@wildwinter/app-shell 0.45.0 → 0.46.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/tooltip.ts","../src/icons.ts","../src/dom.ts","../src/colour.ts","../src/keys.ts","../src/pane-shell.ts","../src/menu.ts","../src/problems.ts","../src/settings.ts","../src/util.ts","../src/tool-window-web.ts","../src/exit.ts","../src/dialog.ts","../src/confirm.ts","../src/floating.ts","../src/context-menu.ts","../src/about.ts","../src/anchored.ts","../src/ids.ts","../src/property-names.ts","../src/property-name-field.ts","../src/id-editor.ts","../src/vc-view.ts","../src/identity.ts","../src/notes-editor.ts","../src/comments.ts","../src/job-view.ts","../src/job.ts","../src/save.ts","../src/save-view.ts","../src/stale.ts","../src/toast.ts","../src/stepper.ts","../src/updater-view.ts","../src/kit-gallery.ts","../src/welcome.ts","../src/link-status.ts","../src/property-list.ts","../src/nav-history.ts"],"names":["el","node","label","chip","tip","active","timer","show","EDGE","current","GAP","thread","place"],"mappings":"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","file":"index.cjs","sourcesContent":["// ---------------------------------------------------------------------------\n// A single themed tooltip the family controls, replacing native `title`\n// rollovers: those are unstyled OS chrome and appear on the platform's slow\n// (~1s) delay, which is exactly the seam design-language section 4 (\"coherent\n// to the edges\") says not to leave showing.\n//\n// ONE floating bubble, document-DELEGATED: any element carrying a `data-tip`\n// attribute gets it, so a caller just sets `data-tip=\"...\"` anywhere and wires\n// nothing. The bubble anchors above the element (flipping below near the top\n// edge), uses our own snappy delay and the shared panel-enter motion.\n// `initTooltips()` is idempotent, so it is safe to call from more than one\n// place in an app that has several entry points.\n//\n// Lifted from Patterpad's patterpad-surface/web/tooltip.ts, which proved it,\n// with the one app-specific rule (suppressed in Writing View) generalised into\n// the `suppressed` option so the shell knows nothing about either app's modes.\n// ---------------------------------------------------------------------------\n\n// Bold markers: a producer wraps a span in these PRIVATE control chars (U+0002 STX / U+0003 ETX,\n// never present in user text) and the renderer turns it into a <strong>. Lets a data-tip bold part\n// of itself (a name, a \"VO:\" prefix) without any HTML, and each segment is still set via\n// textContent, so there is no injection risk from user content.\nconst B_OPEN = \"\\u0002\";\nconst B_CLOSE = \"\\u0003\";\n\n/** Wrap `s` so it renders bold inside a tooltip (see the marker note above). */\nexport function tipBold(s: string): string { return `${B_OPEN}${s}${B_CLOSE}`; }\n\n/** Render `text` into `host`, turning `\\u0002…\\u0003`-marked spans into <strong>; all set as text (safe). */\nfunction renderTip(host: HTMLElement, text: string): void {\n host.textContent = \"\";\n const re = /\\u0002([^\\u0003]*)\\u0003/g;\n let last = 0;\n let m: RegExpExecArray | null;\n while ((m = re.exec(text)) !== null) {\n if (m.index > last) host.append(text.slice(last, m.index));\n const strong = document.createElement(\"strong\");\n strong.textContent = m[1] ?? \"\";\n host.append(strong);\n last = m.index + m[0].length;\n }\n if (last < text.length) host.append(text.slice(last));\n}\n\nexport interface TooltipOptions {\n /** Called before every show: return true to keep the bubble down. For a mode\n * that wants no chrome at all (Patterpad's Writing View). */\n suppressed?: () => boolean;\n}\n\nlet inited = false;\nlet checked = false; // the one-shot no-host warning below has been scheduled\nlet suppressed: (() => boolean) | undefined;\nconst SHOW_DELAY = 350; // ms - snappier than the OS title delay, slow enough not to flicker on pass-through\nconst EDGE = 6; // viewport inset so the bubble never touches the window edge\nconst GAP = 7; // px between the anchor and the bubble\n\nlet tip: HTMLDivElement | null = null;\nlet timer = 0;\nlet active: HTMLElement | null = null;\n/** The subject of a rect-anchored tip (see `tipAt`), when there is one. */\nlet activeKey: string | null = null;\n\nfunction ensureEl(): HTMLDivElement {\n if (tip) return tip;\n const el = document.createElement(\"div\");\n el.className = \"tooltip\";\n el.setAttribute(\"role\", \"tooltip\");\n el.hidden = true;\n document.body.appendChild(el);\n tip = el;\n return el;\n}\n\n/** A rectangle in VIEWPORT coordinates, for anchoring a tip to something that is\n * not a DOM element: a shape on a canvas, a run of text inside one. */\nexport interface TipRect { left: number; top: number; width: number; height: number }\n\nconst rectOf = (anchor: HTMLElement | TipRect): TipRect =>\n (anchor instanceof HTMLElement ? anchor.getBoundingClientRect() : anchor);\n\n/** Anchor the (already-visible, so measurable) bubble above the anchor, flipping below near the top. */\nfunction place(anchor: HTMLElement | TipRect): void {\n const t = ensureEl();\n const r = rectOf(anchor);\n const tr = t.getBoundingClientRect();\n let top = r.top - tr.height - GAP;\n if (top < EDGE) top = r.top + r.height + GAP; // not enough room above -> below\n let left = r.left + r.width / 2 - tr.width / 2;\n left = Math.max(EDGE, Math.min(left, window.innerWidth - tr.width - EDGE));\n t.style.left = `${Math.round(left)}px`;\n t.style.top = `${Math.round(top)}px`;\n}\n\nfunction show(anchor: HTMLElement): void {\n const text = anchor.dataset[\"tip\"];\n if (!text) return;\n paint(anchor, text);\n}\n\n/** Fill, place and reveal the bubble. The one path: both the delegated\n * `data-tip` route and `tipAt` end up here, so a canvas tip and a button tip\n * are the same bubble with the same look and the same motion. */\nfunction paint(anchor: HTMLElement | TipRect, text: string): void {\n if (suppressed?.()) return;\n const t = ensureEl();\n // A modal <dialog> (settings, a confirm) renders in the browser TOP LAYER, above every normal-flow\n // element whatever its z-index. If the anchor is inside one, move the bubble into that dialog so it\n // shares the top layer; otherwise keep it on <body>. Re-parenting per show also moves it back out\n // once the modal closes.\n const host: HTMLElement = (anchor instanceof HTMLElement ? anchor.closest<HTMLElement>(\"dialog[open]\") : null)\n ?? document.body;\n if (t.parentElement !== host) host.appendChild(t);\n active = anchor instanceof HTMLElement ? anchor : null;\n renderTip(t, text);\n t.hidden = false;\n t.classList.remove(\"show\"); void t.offsetWidth; // restart the enter animation\n place(anchor); // measure + position now it has content + is visible\n t.classList.add(\"show\");\n}\n\nfunction hide(): void {\n if (timer) { window.clearTimeout(timer); timer = 0; }\n active = null;\n activeKey = null;\n if (tip) { tip.hidden = true; tip.classList.remove(\"show\"); }\n}\n\nfunction schedule(anchor: HTMLElement): void {\n if (anchor === active) return;\n if (timer) window.clearTimeout(timer);\n timer = window.setTimeout(() => show(anchor), SHOW_DELAY);\n}\n\n/**\n * Show a tip for something that has no DOM node of its own: a card on a canvas,\n * a zone, a pin. The caller says WHERE (a viewport rectangle) and WHAT, and\n * identifies the subject with `key`.\n *\n * The key is what makes this usable from a canvas. Re-calling with the same key\n * re-places the bubble WITHOUT restarting the delay, so a tip can follow its\n * shape while the camera moves; calling with a different key starts the wait\n * again, so sweeping the pointer across a dense board does not strobe.\n *\n * The bubble is ordinary DOM, so it holds its size whatever the canvas is\n * zoomed to. That is the point of it: the label it stands in for is the one\n * thing on a canvas that must not shrink with everything else.\n */\nexport function tipAt(key: string, rect: TipRect, text: string): void {\n if (key === activeKey) {\n // Already up for this subject: move it, do not re-animate it.\n if (tip && !tip.hidden) { renderTip(tip, text); place(rect); }\n return;\n }\n // A different subject: down first, then wait again. Leaving the old bubble up\n // during the wait would put one card's name over another card, which is worse\n // than no name at all - and it matches the delegated route, where leaving an\n // element hides the tip before the next one is scheduled.\n hide();\n activeKey = key;\n timer = window.setTimeout(() => { timer = 0; paint(rect, text); }, SHOW_DELAY);\n}\n\n/** Take any tip down: the pointer has left, or a gesture has started. */\nexport function hideTip(): void { hide(); }\n\n/**\n * Mount the renderer because something is about to speak the grammar.\n *\n * The themed tooltip is not a feature a host turns on; it is the renderer for a grammar the shell's own\n * components already speak, and `data-tip` with nothing listening draws NOTHING - not the themed\n * bubble, not the platform one. That silence cost Patterpad two releases of a pin with no tooltip, and\n * cost it again when a `title` was converted to `data-tip` in a window that had never mounted this.\n *\n * So `el` calls this whenever it sets a tip. Mounting a delegated listener is the same class of act as\n * `confirmDialog` appending to `document.body`, which this package has always done.\n */\nexport function ensureTooltipHost(): void { initTooltips(); }\n\n/**\n * One deferred check that an app writing `data-tip` ITSELF has a host, warning if not.\n *\n * `ensureTooltipHost` covers anything built through `el`. It cannot cover a `data-tip` written straight\n * into markup or set by hand, which is the case that leaves a whole window of dead tips with no shell\n * component involved - so that one gets a warning rather than silence. Scheduled once, after the\n * current task, so it sees a rendered document rather than an empty one.\n */\nexport function checkTooltipHost(): void {\n if (checked) return;\n checked = true;\n setTimeout(() => {\n if (inited || typeof document === \"undefined\") return;\n if (document.querySelector(\"[data-tip]\")) {\n console.warn(\"app-shell: something set `data-tip` but no tooltip host is mounted, so those rollovers will not draw. Call initTooltips() once per window.\");\n }\n }, 0);\n}\n\nconst tipAncestor = (n: EventTarget | null): HTMLElement | null =>\n (n instanceof Element ? n.closest<HTMLElement>(\"[data-tip]\") : null);\n\n/**\n * Wire the one delegated controller. Mounting happens once; OPTIONS do not.\n *\n * An explicit call is always authoritative about its options, even after something else has already\n * mounted the listener. That ordering is not hypothetical, and Storyletter caught it before it shipped:\n * once components self-mount (see `ensureTooltipHost`), a host's own\n * `initTooltips({ suppressed })` could land second and be dropped by an early return, silently taking\n * a rule like \"no tooltips in Writing View\" with it. Nothing would fail and nothing would show.\n *\n * Components therefore call this with NO arguments: they mount the renderer without claiming the\n * options, and the host keeps the last word on behaviour.\n */\nexport function initTooltips(opts: TooltipOptions = {}): void {\n if (opts.suppressed !== undefined) suppressed = opts.suppressed; // an explicit call always wins\n if (inited) return;\n inited = true;\n\n document.addEventListener(\"pointerover\", (e) => {\n const el = tipAncestor(e.target);\n if (el) schedule(el);\n });\n document.addEventListener(\"pointerout\", (e) => {\n const el = tipAncestor(e.target);\n if (!el) return;\n const to = (e as PointerEvent).relatedTarget;\n if (to instanceof Node && el.contains(to)) return; // still inside the same anchor\n hide();\n });\n // Keyboard parity: reveal on focus, dismiss on blur.\n document.addEventListener(\"focusin\", (e) => { const el = tipAncestor(e.target); if (el) schedule(el); });\n document.addEventListener(\"focusout\", () => hide());\n // It's ANCHORED (not cursor-following), so anything that moves the layout or context dismisses it.\n document.addEventListener(\"pointerdown\", () => hide(), true);\n document.addEventListener(\"scroll\", () => { if (active) hide(); }, true);\n document.addEventListener(\"keydown\", (e) => { if (e.key === \"Escape\") hide(); });\n window.addEventListener(\"blur\", () => hide());\n}\n","// ---------------------------------------------------------------------------\n// The family's icon vocabulary.\n//\n// An icon is a WORD. Two apps in one suite spelling \"close\" differently is the\n// same fault as calling one thing a scene here and a chapter there, and it is\n// harder to notice because nobody reads glyphs, they just feel wrong. This\n// module exists so that no app ever types a codepoint again: it asks for\n// `iconNode(\"close\")` and gets whatever the family has agreed that means.\n//\n// The evidence that it was needed, gathered 2026-08-09 across both apps:\n// Patterpad spelled close as a cross twelve times, Storyletter used the same\n// cross once and a multiplication sign twice, in one window, and a comment\n// bubble had just been invented from scratch with nothing to check it against.\n//\n// DRAWN, not typed (design-language.md section 4, \"Icons are drawn, and so are\n// separators\", 2026-09-16). The first cut of this table was Unicode glyphs,\n// which render from whatever symbol font the OS has, so weight, baseline and\n// optical size drifted per character and per platform. The vocabulary is now\n// one drawn set: Lucide, vendored below as inline SVG strings on one 24-unit\n// grid at one stroke weight. The words did not change; what they draw did.\n//\n// Lucide 1.46.0 (lucide-static), ISC licence.\n// https://lucide.dev / https://cdn.jsdelivr.net/npm/lucide-static@1.46.0/icons/<name>.svg\n// Fetched 2026-09-16. The chosen decision record is\n// patterkit/design/ui-review-2026-09/07c-track-c-icon-sets-notes.md.\n//\n// STROKE. The family draws icons at 14px inside its small square buttons and\n// wants a 1.5px rendered stroke against Inter at that size (Inter Regular's\n// stems are about 1.3px there). Lucide's native stroke is 2 on a 24 grid,\n// which is 2 x 14/24 = 1.17px at 14px, a shade light. So the root of every\n// stroke icon carries stroke-width=\"2.571\": 2.571 x 14/24 = 1.5. A caller\n// drawing at another size gets the proportional weight (12px: 1.29px; 16px:\n// 1.71px), which is what one drawn set means. Filled shapes (the discs) carry\n// fill=\"currentColor\" and no stroke at all.\n//\n// Every icon is `currentColor`, so it takes the colour of the button it sits\n// in, and none of the strings carries width/height: the size is the caller's\n// (`iconNode(name, size)`), so an icon can never be the wrong size somewhere\n// because a CSS rule failed to reach it.\n//\n// Adding one: it needs a MEANING, not a picture. \"A downward chevron\" is not an\n// entry; \"expand this\" is. If two callers want the same picture for two\n// meanings, that is two entries, and one of them will be wrong later.\n// ---------------------------------------------------------------------------\n//\n// Lucide licence (the icons vendored in this file):\n//\n// ISC License\n// Copyright (c) 2026 Lucide Icons and Contributors\n//\n// Permission to use, copy, modify, and/or distribute this software for any\n// purpose with or without fee is hereby granted, provided that the above\n// copyright notice and this permission notice appear in all copies.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n//\n// Portions of Lucide (among those used here: arrow-down, arrow-left,\n// arrow-right, arrow-up, check, chevron-down, chevron-left, chevron-right,\n// circle, lock, plus, search, x) derive from Feather, MIT,\n// Copyright (c) 2013-present Cole Bemis. See LICENSES.md.\n// ---------------------------------------------------------------------------\n\n/**\n * The typed glyphs the vocabulary used to draw.\n *\n * @deprecated Since the move to drawn icons (design-language.md, \"Icons are\n * drawn\"). Kept byte-for-byte so a consumer still doing\n * `textContent = icon.close` keeps working while each app moves; a new call\n * site uses `iconNode(name)` (a node to append) or `iconHtml(name)` (for an\n * innerHTML build). The names are the same in all three. Removed once both\n * apps have moved.\n */\nexport const icon = {\n // --- dismissing and revealing ---------------------------------------------\n /** Close a panel, a dialog, a popover. Patterpad's, twelve times over. */\n close: \"✕\",\n /** The overflow menu on a document or a row: \"more about this\". */\n more: \"⋯\",\n /** Collapsed disclosure, pointing at what would open. */\n collapsed: \"▸\",\n /** Expanded disclosure. */\n expanded: \"▾\",\n /** A dropdown's affordance, where it is not a real <select>. */\n dropdown: \"▾\",\n\n // --- moving through things ------------------------------------------------\n /** Back / previous, in a breadcrumb or a stepper. */\n back: \"‹\",\n /** Forward / next. */\n forward: \"›\",\n /** Up one, in a list. */\n up: \"↑\",\n /** Down one. */\n down: \"↓\",\n\n // --- state ----------------------------------------------------------------\n /** Done, applied, agreed. */\n tick: \"✓\",\n /** Somebody else holds this: the version-control lock. */\n locked: \"⊘\",\n /** Read-only on disk with no other holder: the resting state of everything\n * in a lock-based working copy that nobody has checked out yet. */\n readOnly: \"○\",\n /** YOU hold this one: checked out / opened by the current user, still yours to\n * edit. Shares its glyph with `note`, which the table permits: an entry is a\n * MEANING, and two meanings may draw the same shape. */\n checkedOut: \"✎\",\n /** Tracked, with local changes not yet committed. */\n modified: \"●\",\n /** Not in version control yet: new since the last commit. */\n untracked: \"+\",\n /** Something needs attention but is not fatal. */\n warning: \"‼\",\n /** A live thing: the running position, an active marker. */\n dot: \"●\",\n /** Play, in the sense of \"run this\". */\n play: \"▶\",\n /** Start the thing again from the top: a play session, a sweep. Named for the\n * act, not the arrow, which is the table's rule. */\n restart: \"⟲\",\n /** The three ways a collection can be shown. Named by what you get rather than\n * by the glyph, so a second app can pick the same three without copying\n * somebody's taste in symbols. */\n viewCards: \"▦\",\n viewTable: \"☰\",\n viewNode: \"◈\",\n\n // --- handling -------------------------------------------------------------\n /** The drag grip on a reorderable row. */\n grip: \"⠿\",\n /** Add one of whatever this list holds. */\n add: \"+\",\n\n // --- annotation -----------------------------------------------------------\n /** Documentation notes: the pencil. Both apps had chosen it independently,\n * which is the happiest way for a vocabulary entry to arrive. */\n note: \"✎\",\n /** A comment thread. Speech, not a pencil: documentation states the reason,\n * comments are the conversation, and the two must never look alike. */\n comment: \"❝\",\n} as const;\n\n/**\n * Every word in the vocabulary. The 26 the glyph table had, plus the seven the\n * 2026-09 review found the apps drawing by hand with nothing to check against.\n */\nexport type IconName =\n | keyof typeof icon\n /** History back, the topbar's quiet arrow pair (nav-history.ts). An ARROW,\n * not a chevron: a chevron says structure, an arrow says time (the author's\n * ruling, 2026-08-28). Added beside `arrowRight` so the pair share a set. */\n | \"arrowLeft\"\n /** History forward; also the one honest \"go there\" arrow where a link used\n * to carry a typed one. */\n | \"arrowRight\"\n /** Connect to a server, a live link, a running game. */\n | \"connect\"\n /** Search. */\n | \"search\"\n /** Keep this window on top (tool-window-web.ts). */\n | \"pin\"\n /** Settings. */\n | \"settings\"\n /** Record. The icon is the DISC; painting it in the danger colour while\n * recording is the caller's job, through the button's own colour. */\n | \"record\";\n\n// The two roots every drawing shares. Kept as constants so the table below is\n// the inner elements only, which is what a reader compares against lucide.dev.\nconst STROKE = '<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.571\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">';\nconst FILL = '<svg viewBox=\"0 0 24 24\" fill=\"currentColor\" aria-hidden=\"true\">';\nconst stroked = (inner: string): string => `${STROKE}${inner}</svg>`;\nconst filled = (inner: string): string => `${FILL}${inner}</svg>`;\n\n// The three discs are the one drawing in the table that is not Lucide's own\n// element as shipped: Lucide's `circle` is an r=10 outline that fills its box,\n// which at badge size beside a row title is a blot, so the disc is drawn at a\n// smaller radius with the fill forced (the same amount of hand-drawing as the\n// legacy noteFilled below, and the decision record's stated cost). `modified`\n// and `dot` share it, as their glyphs did; `record` is larger because a record\n// button is meant to fill more of its box.\nconst DISC = filled('<circle cx=\"12\" cy=\"12\" r=\"6\"/>');\nconst DISC_LARGE = filled('<circle cx=\"12\" cy=\"12\" r=\"9\"/>');\n\n/**\n * The drawings, by word. Each is a complete `<svg viewBox=\"0 0 24 24\" …>`\n * string with no width/height (see `iconNode` / `iconHtml`, which size it).\n * The Lucide name each derives from is on the entry, so a reviewer can put\n * the two side by side.\n */\nconst DRAWN: Record<IconName, string> = {\n // --- dismissing and revealing ---------------------------------------------\n /** Close a panel, a dialog, a popover. (x) */\n close: stroked('<path d=\"M18 6 6 18\"/><path d=\"m6 6 12 12\"/>'),\n /** The overflow menu on a document or a row: \"more about this\". (ellipsis) */\n more: stroked('<circle cx=\"12\" cy=\"12\" r=\"1\"/><circle cx=\"19\" cy=\"12\" r=\"1\"/><circle cx=\"5\" cy=\"12\" r=\"1\"/>'),\n /** Collapsed disclosure, pointing at what would open. (chevron-right) */\n collapsed: stroked('<path d=\"m9 18 6-6-6-6\"/>'),\n /** Expanded disclosure. (chevron-down) */\n expanded: stroked('<path d=\"m6 9 6 6 6-6\"/>'),\n /** A dropdown's affordance, where it is not a real <select>. (chevron-down) */\n dropdown: stroked('<path d=\"m6 9 6 6 6-6\"/>'),\n\n // --- moving through things ------------------------------------------------\n /** Back / previous, in a breadcrumb or a stepper. (chevron-left) */\n back: stroked('<path d=\"m15 18-6-6 6-6\"/>'),\n /** Forward / next. (chevron-right) */\n forward: stroked('<path d=\"m9 18 6-6-6-6\"/>'),\n /** Up one, in a list. (arrow-up) */\n up: stroked('<path d=\"m5 12 7-7 7 7\"/><path d=\"M12 19V5\"/>'),\n /** Down one. (arrow-down) */\n down: stroked('<path d=\"M12 5v14\"/><path d=\"m19 12-7 7-7-7\"/>'),\n /** History back. (arrow-left) */\n arrowLeft: stroked('<path d=\"m12 19-7-7 7-7\"/><path d=\"M19 12H5\"/>'),\n /** History forward; \"go there\". (arrow-right) */\n arrowRight: stroked('<path d=\"M5 12h14\"/><path d=\"m12 5 7 7-7 7\"/>'),\n\n // --- state ----------------------------------------------------------------\n /** Done, applied, agreed. (check) */\n tick: stroked('<path d=\"M20 6 9 17l-5-5\"/>'),\n /** Somebody else holds this: the version-control lock. (lock) */\n locked: stroked('<rect width=\"18\" height=\"11\" x=\"3\" y=\"11\" rx=\"2\" ry=\"2\"/><path d=\"M7 11V7a5 5 0 0 1 10 0v4\"/>'),\n /** Read-only on disk with no other holder. (lock-open) An open lock rather\n * than a struck-out eye: this state is not a prohibition. Nobody holds the\n * file, saving checks it out, and it is the resting state of everything the\n * author has not touched yet under a lock-based VCS. eye-off would say \"you\n * cannot\", which is false here; the open lock says \"not held\", beside\n * `locked`, which is the shut one, so the two read as a pair. */\n readOnly: stroked('<rect width=\"18\" height=\"11\" x=\"3\" y=\"11\" rx=\"2\" ry=\"2\"/><path d=\"M7 11V7a5 5 0 0 1 9.9-1\"/>'),\n /** YOU hold this one: checked out, still yours to edit. (pencil) */\n checkedOut: stroked('<path d=\"M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z\"/><path d=\"m15 5 4 4\"/>'),\n /** Tracked, with local changes not yet committed. (a disc; see DISC) */\n modified: DISC,\n /** Not in version control yet: new since the last commit. (plus) */\n untracked: stroked('<path d=\"M5 12h14\"/><path d=\"M12 5v14\"/>'),\n /** Something needs attention but is not fatal. (triangle-alert) */\n warning: stroked('<path d=\"m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3\"/><path d=\"M12 9v4\"/><path d=\"M12 17h.01\"/>'),\n /** A live thing: the running position, an active marker. (a disc) */\n dot: DISC,\n /** Play, in the sense of \"run this\". (play) */\n play: stroked('<path d=\"M5 5a2 2 0 0 1 3.008-1.728l11.997 6.998a2 2 0 0 1 .003 3.458l-12 7A2 2 0 0 1 5 19z\"/>'),\n /** Start the thing again from the top: a play session, a sweep. (rotate-ccw) */\n restart: stroked('<path d=\"M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8\"/><path d=\"M3 3v5h5\"/>'),\n /** The three ways a collection can be shown, named by what you get. */\n /** Cards. (layout-grid) */\n viewCards: stroked('<rect width=\"7\" height=\"7\" x=\"3\" y=\"3\" rx=\"1\"/><rect width=\"7\" height=\"7\" x=\"14\" y=\"3\" rx=\"1\"/><rect width=\"7\" height=\"7\" x=\"14\" y=\"14\" rx=\"1\"/><rect width=\"7\" height=\"7\" x=\"3\" y=\"14\" rx=\"1\"/>'),\n /** A table. (rows-3: a ruled box, which is a table. `list` is bullets, and\n * the view is not a list.) */\n viewTable: stroked('<rect width=\"18\" height=\"18\" x=\"3\" y=\"3\" rx=\"2\"/><path d=\"M21 9H3\"/><path d=\"M21 15H3\"/>'),\n /** A node graph. (waypoints: four nodes on edges reads as a graph.\n * `git-fork` reads as version control, which this family also draws, and\n * a picture that means two things is the fault this table exists to\n * prevent.) */\n viewNode: stroked('<path d=\"m10.586 5.414-5.172 5.172\"/><path d=\"m18.586 13.414-5.172 5.172\"/><path d=\"M6 12h12\"/><circle cx=\"12\" cy=\"20\" r=\"2\"/><circle cx=\"12\" cy=\"4\" r=\"2\"/><circle cx=\"20\" cy=\"12\" r=\"2\"/><circle cx=\"4\" cy=\"12\" r=\"2\"/>'),\n /** Record: the disc, in whatever colour the button is. (a disc; see DISC_LARGE) */\n record: DISC_LARGE,\n\n // --- handling -------------------------------------------------------------\n /** The drag grip on a reorderable row. (grip-vertical) */\n grip: stroked('<circle cx=\"9\" cy=\"12\" r=\"1\"/><circle cx=\"9\" cy=\"5\" r=\"1\"/><circle cx=\"9\" cy=\"19\" r=\"1\"/><circle cx=\"15\" cy=\"12\" r=\"1\"/><circle cx=\"15\" cy=\"5\" r=\"1\"/><circle cx=\"15\" cy=\"19\" r=\"1\"/>'),\n /** Add one of whatever this list holds. (plus) */\n add: stroked('<path d=\"M5 12h14\"/><path d=\"M12 5v14\"/>'),\n /** Connect: to a server, a live link, a running game. (plug) */\n connect: stroked('<path d=\"M12 22v-5\"/><path d=\"M15 8V2\"/><path d=\"M17 8a1 1 0 0 1 1 1v4a4 4 0 0 1-4 4h-4a4 4 0 0 1-4-4V9a1 1 0 0 1 1-1z\"/><path d=\"M9 8V2\"/>'),\n /** Search. (search) */\n search: stroked('<path d=\"m21 21-4.34-4.34\"/><circle cx=\"11\" cy=\"11\" r=\"8\"/>'),\n /** Keep this window on top. (pin) */\n pin: stroked('<path d=\"M12 17v5\"/><path d=\"M9 10.76a2 2 0 0 1-1.11 1.79l-1.78.9A2 2 0 0 0 5 15.24V16a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-.76a2 2 0 0 0-1.11-1.79l-1.78-.9A2 2 0 0 1 15 10.76V7a1 1 0 0 1 1-1 2 2 0 0 0 0-4H8a2 2 0 0 0 0 4 1 1 0 0 1 1 1z\"/>'),\n /** Settings. (settings) */\n settings: stroked('<path d=\"M9.671 4.136a2.34 2.34 0 0 1 4.659 0 2.34 2.34 0 0 0 3.319 1.915 2.34 2.34 0 0 1 2.33 4.033 2.34 2.34 0 0 0 0 3.831 2.34 2.34 0 0 1-2.33 4.033 2.34 2.34 0 0 0-3.319 1.915 2.34 2.34 0 0 1-4.659 0 2.34 2.34 0 0 0-3.32-1.915 2.34 2.34 0 0 1-2.33-4.033 2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915\"/><circle cx=\"12\" cy=\"12\" r=\"3\"/>'),\n\n // --- annotation -----------------------------------------------------------\n /** Documentation notes: a document with lines on it. (file-text) The glyph\n * table drew a pencil and shared it with `checkedOut`; the drawn set gives\n * the two meanings two shapes, and notes get the document, which is what\n * the shell's own noteFilled/noteOutline pair had always drawn. */\n note: stroked('<path d=\"M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z\"/><path d=\"M14 2v5a1 1 0 0 0 1 1h5\"/><path d=\"M10 9H8\"/><path d=\"M16 13H8\"/><path d=\"M16 17H8\"/>'),\n /** A comment thread. Speech, not a document: documentation states the\n * reason, comments are the conversation, and the two must never look\n * alike. (message-square) */\n comment: stroked('<path d=\"M22 17a2 2 0 0 1-2 2H6.828a2 2 0 0 0-1.414.586l-2.202 2.202A.71.71 0 0 1 2 21.286V5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2z\"/>'),\n};\n\n/**\n * The drawings as strings, by word, for a caller that builds markup itself.\n * Prefer `iconHtml(name, size)`, which sizes it; these carry no width/height.\n *\n * Two legacy entries ride along unchanged: `noteFilled` and `noteOutline`, the\n * has-notes / no-notes pair Patterpad drew on a 16-unit grid before the set\n * existed. They are sized in the markup (13px) and on their own grid, so they\n * are NOT part of the vocabulary above and `iconNode` does not know them; no\n * app uses them today. They stay until a 24-grid pair replaces them, because\n * their two-state meaning (there are notes / there are none) has no Lucide\n * shape, and re-weighting the 16-grid drawing to the family stroke merges its\n * text lines.\n */\nexport const iconSvg = {\n ...DRAWN,\n /** A document with lines: notes exist on this thing. (legacy, 16 grid) */\n noteFilled: '<svg viewBox=\"0 0 16 16\" width=\"13\" height=\"13\" fill=\"currentColor\" fill-rule=\"evenodd\" aria-hidden=\"true\"><path d=\"M3.4 1.4h5.3L12.6 5.3v8.1a1.2 1.2 0 0 1-1.2 1.2H3.4a1.2 1.2 0 0 1-1.2-1.2V2.6A1.2 1.2 0 0 1 3.4 1.4ZM4.9 6.8h6.2v1.1H4.9Zm0 2.1h6.2v1.1H4.9Zm0 2.1h3.7v1.1H4.9Z\"/></svg>',\n /** The same document, empty: nothing written here yet. (legacy, 16 grid) */\n noteOutline: '<svg viewBox=\"0 0 16 16\" width=\"13\" height=\"13\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.1\" stroke-linejoin=\"round\" stroke-linecap=\"round\" aria-hidden=\"true\"><path d=\"M3.4 2h4.9l3.9 3.9v7.5a1 1 0 0 1-1 1H3.4a1 1 0 0 1-1-1V3a1 1 0 0 1 1-1Z\"/><path d=\"M8.3 2.2v3.8h3.8\"/><path d=\"M4.9 8h6.2M4.9 10h6.2M4.9 12h3.7\" stroke-width=\"0.95\"/></svg>',\n} as const;\n\nexport type IconSvgName = keyof typeof iconSvg;\n\n/** Every word, in table order, for a test or a gallery to walk. */\nexport const ICON_NAMES = Object.keys(DRAWN) as IconName[];\n\n/** The default size: 14px, the family's icon inside its small square button. */\nexport const ICON_SIZE = 14;\n\n/**\n * The drawing as markup with its size set, for a caller building innerHTML.\n * `data-icon` carries the word, so a stylesheet or a test can find it.\n */\nexport function iconHtml(name: IconName, size = ICON_SIZE): string {\n return DRAWN[name].replace(\"<svg \", `<svg width=\"${size}\" height=\"${size}\" data-icon=\"${name}\" `);\n}\n\n// One parsed template per word, filled on first use; every call clones it, so\n// the string is parsed once per window and each caller gets its own node.\nconst templates = new Map<IconName, SVGSVGElement>();\n\n/**\n * The drawing as a fresh SVG node, sized. Append it where the glyph used to be\n * set as text; it is `aria-hidden`, so the button's accessible name stays the\n * button's (`aria-label` / `data-tip`), as it always had to.\n */\nexport function iconNode(name: IconName, size = ICON_SIZE): SVGSVGElement {\n let tpl = templates.get(name);\n if (!tpl) {\n const holder = document.createElement(\"template\");\n holder.innerHTML = DRAWN[name];\n tpl = holder.content.firstElementChild as SVGSVGElement;\n tpl.setAttribute(\"data-icon\", name);\n templates.set(name, tpl);\n }\n const node = tpl.cloneNode(true) as SVGSVGElement;\n node.setAttribute(\"width\", String(size));\n node.setAttribute(\"height\", String(size));\n return node;\n}\n\n// The glyph table, reversed, so a legacy call site that still hands the shell\n// a typed character (\"✕\", \"↑\") draws the word it stood for. Where two words\n// shared a glyph the first in table order wins, which is fine: the picture was\n// the same either way. Goes when `icon` does.\nconst BY_GLYPH = new Map<string, IconName>();\nfor (const [name, glyph] of Object.entries(icon) as [IconName, string][]) {\n if (!BY_GLYPH.has(glyph)) BY_GLYPH.set(glyph, name);\n}\n\n/** The word a deprecated glyph stood for, or undefined for any other string. */\nexport function iconNameOfGlyph(glyph: string): IconName | undefined {\n return BY_GLYPH.get(glyph);\n}\n\n/** Whether a string is a word in the vocabulary. */\nexport function isIconName(s: string): s is IconName {\n return Object.prototype.hasOwnProperty.call(DRAWN, s);\n}\n","// ---------------------------------------------------------------------------\n// `el`: the tiny tag-typed element factory both apps build their imperative,\n// idempotent views with.\n//\n// A SUPERSET of the two apps' prior signatures, so neither rewrites call sites:\n// - Patterpad: el(tag, cls?, text?) (positional)\n// - Storylet Studio: el(tag, { className, text, ... }, ...kids) (options bag)\n// A string second argument is the className; an object is the props bag; string\n// children become text nodes. So `el(\"div\", \"c\", \"t\")` and\n// `el(\"div\", { className: \"c\" }, \"t\")` produce identical DOM.\n// ---------------------------------------------------------------------------\n\nimport { ensureTooltipHost, checkTooltipHost } from \"./tooltip.js\";\nimport { iconNode, iconNameOfGlyph, isIconName, type IconName } from \"./icons.js\";\n\nexport type Child = Node | string | null | undefined;\n\nexport interface ElProps {\n className?: string;\n text?: string;\n /** A NATIVE rollover. Prefer `tip`: `title` is OS chrome on the platform's own\n * slow delay, which is the seam the themed tooltip exists to close. */\n title?: string;\n /** A themed rollover (`data-tip`, picked up by the delegated controller that\n * `initTooltips()` wires). Also the accessible name, since the elements that\n * want one are usually icon buttons with no text of their own. */\n tip?: string;\n onClick?: (event: MouseEvent) => void;\n}\n\nexport function el<K extends keyof HTMLElementTagNameMap>(\n tag: K,\n classNameOrProps?: string | ElProps,\n ...children: Child[]\n): HTMLElementTagNameMap[K] {\n const node = document.createElement(tag);\n const props: ElProps = typeof classNameOrProps === \"string\"\n ? { className: classNameOrProps }\n : classNameOrProps ?? {};\n if (props.className) node.className = props.className;\n if (props.text !== undefined && props.text !== null) node.textContent = props.text;\n if (props.title !== undefined) node.title = props.title;\n if (props.tip !== undefined) {\n node.dataset[\"tip\"] = props.tip;\n node.setAttribute(\"aria-label\", props.tip);\n // Setting a tip mounts the renderer. Without this, `data-tip` draws nothing at all in a window whose\n // host never called `initTooltips()`, which is a silent failure rather than a degraded one. No\n // options passed: the host stays authoritative about behaviour (see tooltip.ts).\n ensureTooltipHost();\n }\n if (props.onClick) node.addEventListener(\"click\", props.onClick as EventListener);\n for (const child of children) {\n if (child === null || child === undefined) continue;\n node.append(child);\n }\n checkTooltipHost(); // one-shot: warns if the APP wrote data-tip and nothing mounted a host\n return node;\n}\n\n/** A small square icon button (the move/delete controls list editors share).\n * Its rollover is the THEMED one (`data-tip`), so an app that has called\n * `initTooltips()` gets our bubble rather than the platform's.\n *\n * `name` is a word from the vocabulary (\"up\", \"close\"), drawn at 14px. A\n * typed glyph from the deprecated `icon` table (\"↑\", \"✕\") is accepted for\n * now and drawn as the word it stood for, so an app that has not moved its\n * call sites yet still gets the drawn set; any other string is set as text,\n * which is the old behaviour and on its way out. */\nexport function iconBtn(name: IconName | (string & {}), title: string, onClick: () => void, disabled = false, danger = false): HTMLButtonElement {\n const b = el(\"button\", `shell-icon${danger ? \" danger\" : \"\"}`);\n b.type = \"button\"; b.dataset[\"tip\"] = title; b.setAttribute(\"aria-label\", title);\n const word = isIconName(name) ? name : iconNameOfGlyph(name);\n if (word) b.append(iconNode(word)); else b.textContent = name;\n b.disabled = disabled;\n b.addEventListener(\"click\", onClick);\n return b;\n}\n\n/**\n * A captioned field: `<label class=\"shell-labelled\"><span class=\"shell-fieldcap\">…</span>control</label>`.\n *\n * The label is pointed at the field it captions, EXPLICITLY, and never at a button. A `<label>` with no\n * `for` forwards a click to its first labelable descendant, and buttons are labelable - so a caption\n * wrapped around a control containing buttons (`tagChips`, whose every chip carries a remove button)\n * turns every click on the row's dead space into a press of the FIRST button in it. That shipped:\n * patterkit/patter#44, where clicking a Game Data list value anywhere but its ✕ deleted the first value\n * in the list. Reported as \"clicking a value removes the wrong one\", which is not a wrong-index bug at\n * all - the click never reached the chip.\n *\n * When the control holds no labelable field (a chips editor with the add input removed, say), this is a\n * plain `<div>`: no caption behaviour is better than a caption that presses something.\n */\nexport function labelled(label: string, control: HTMLElement): HTMLElement {\n const target = control.matches(\"input, select, textarea\")\n ? control\n : control.querySelector<HTMLElement>(\"input:not([type=button]):not([type=submit]), select, textarea\");\n const w = el(target ? \"label\" : \"div\", \"shell-labelled\");\n w.append(el(\"span\", \"shell-fieldcap\", label), control);\n if (target) {\n if (!target.id) target.id = `shell-f-${Math.random().toString(36).slice(2, 9)}`;\n (w as HTMLLabelElement).htmlFor = target.id;\n }\n return w;\n}\n\n/** Swap item `i` with its neighbour `i + delta` IN PLACE (the up/down reorder list editors share);\n * a no-op when the target is out of range. Returns whether anything moved. */\nexport function moveItem<T>(arr: T[], i: number, delta: number): boolean {\n const j = i + delta;\n if (j < 0 || j >= arr.length) return false;\n [arr[i], arr[j]] = [arr[j]!, arr[i]!];\n return true;\n}\n\n/** The icon size inside a chip's remove / move buttons: the chip is set at\n * 0.76rem, so its controls draw smaller than a toolbar button's 14px. */\nconst CHIP_ICON = 10;\n\n/** A tag-style editor for a string-list field (an enum's allowed values / flags): removable chips + an\n * add input (Enter or \",\" commits; blank / duplicate ignored). Mutates `holder.values` in place (read\n * back on save). `onChange` fires after any add / remove so callers can refresh a dependent control. */\nexport function tagChips(holder: { values?: string[] }, onChange?: () => void): HTMLElement {\n const wrap = el(\"div\", \"shell-tags\");\n const input = el(\"input\", \"shell-tag-input\");\n // Sentence-cased like every other hint (the microcopy ruling, 2026-08-28):\n // lowercase fragments read as adrift, and a placeholder is a hint speaking.\n input.type = \"text\"; input.placeholder = \"Add value\"; input.spellcheck = false;\n const makeChip = (v: string): HTMLElement => {\n const chip = el(\"span\", \"shell-tag\", v);\n const x = el(\"button\", \"shell-tag-x\", iconNode(\"close\", CHIP_ICON));\n x.type = \"button\"; x.dataset[\"tip\"] = `Remove ${v}`; x.setAttribute(\"aria-label\", `Remove ${v}`);\n x.addEventListener(\"click\", () => { holder.values = (holder.values ?? []).filter((o) => o !== v); chip.remove(); onChange?.(); });\n chip.append(x);\n return chip;\n };\n const commit = (): void => {\n const v = input.value.trim();\n if (v && !(holder.values ?? []).includes(v)) { (holder.values ??= []).push(v); wrap.insertBefore(makeChip(v), input); onChange?.(); }\n input.value = \"\";\n };\n input.addEventListener(\"keydown\", (e) => { if (e.key === \"Enter\" || e.key === \",\") { e.preventDefault(); commit(); } });\n input.addEventListener(\"blur\", commit);\n for (const v of holder.values ?? []) wrap.append(makeChip(v));\n wrap.append(input);\n return wrap;\n}\n\n/**\n * An ORDERED chips editor for a string-list field whose order means something\n * (a quality's stages: `advance()` walks them, so 2 comes after 1): numbered\n * chips, each with move-earlier / move-later / remove, plus an add input\n * (Enter or \",\" commits; blank / duplicate ignored). Mutates `holder.stages`\n * in place; `onChange` fires after any add / move / remove.\n *\n * Patterpad's, lifted (ui-review-2026-09, finding 3); Storyletter had been\n * faking it with `tagChips` over a `values` holder, which loses the order\n * controls. Same class family as `tagChips` (`.shell-tags`), so it is styled by\n * settings.css already.\n */\nexport function stageChips(holder: { stages?: string[] }, onChange?: () => void): HTMLElement {\n const wrap = el(\"div\", \"shell-tags shell-stages\");\n const input = el(\"input\", \"shell-tag-input\");\n input.type = \"text\"; input.placeholder = \"Add stage\"; input.spellcheck = false;\n const control = (name: IconName, tip: string, disabled: boolean, onClick: () => void): HTMLButtonElement => {\n const b = el(\"button\", \"shell-tag-x shell-tag-move\", iconNode(name, CHIP_ICON));\n b.type = \"button\"; b.dataset[\"tip\"] = tip; b.setAttribute(\"aria-label\", tip);\n b.disabled = disabled;\n b.addEventListener(\"click\", onClick);\n return b;\n };\n const rebuild = (): void => {\n for (const c of Array.from(wrap.children)) if (c !== input) c.remove();\n const stages = holder.stages ?? [];\n stages.forEach((v, i) => {\n const chip = el(\"span\", \"shell-tag\", `${i + 1}. ${v}`);\n chip.dataset[\"stage\"] = v;\n chip.append(\n control(\"back\", `Move ${v} earlier`, i === 0,\n () => { if (moveItem(stages, i, -1)) { rebuild(); onChange?.(); } }),\n control(\"forward\", `Move ${v} later`, i === stages.length - 1,\n () => { if (moveItem(stages, i, 1)) { rebuild(); onChange?.(); } }),\n );\n const x = el(\"button\", \"shell-tag-x\", iconNode(\"close\", CHIP_ICON));\n x.type = \"button\"; x.dataset[\"tip\"] = `Remove ${v}`; x.setAttribute(\"aria-label\", `Remove ${v}`);\n x.addEventListener(\"click\", () => { holder.stages = (holder.stages ?? []).filter((o) => o !== v); rebuild(); onChange?.(); });\n chip.append(x);\n wrap.insertBefore(chip, input);\n });\n };\n const commit = (): void => {\n const v = input.value.trim();\n if (v && !(holder.stages ?? []).includes(v)) { (holder.stages ??= []).push(v); rebuild(); onChange?.(); }\n input.value = \"\";\n };\n input.addEventListener(\"keydown\", (e) => { if (e.key === \"Enter\" || e.key === \",\") { e.preventDefault(); commit(); } });\n input.addEventListener(\"blur\", commit);\n wrap.append(input);\n rebuild();\n return wrap;\n}\n\n// --- drag-to-reorder ---------------------------------------------------------\n// One drag at a time per window, shared across every wired list, so the\n// midpoint test knows what is being carried without a dataTransfer round trip.\nlet reorderDragId: string | null = null;\nconst clearDropMarks = (host: ParentNode): void =>\n host.querySelectorAll(\".drop-before, .drop-after\").forEach((e) => e.classList.remove(\"drop-before\", \"drop-after\"));\n\n/**\n * Make `el` a drag source and a drop target for HTML5 drag-to-reorder among\n * its siblings. While carried it wears `.dragging`; a hovered target wears\n * `.drop-before` or `.drop-after` by the midpoint test on `axis` (\"y\" for\n * rows, \"x\" for a wrapping grid); a drop calls `onMove(draggedId, before,\n * targetId)` and the caller reorders its model and re-renders.\n *\n * Storyletter's `wireCardDrag`, lifted (ui-review-2026-09, finding 30);\n * Patterpad's `wireSceneDrag` is the same idea fixed on \"y\". The marks are\n * classes only: the app draws them (Patterpad's `box-shadow: 0 -2px 0 0\n * var(--accent)` pair is the family's look).\n */\nexport function wireReorder(el: HTMLElement, id: string, axis: \"x\" | \"y\", onMove: (id: string, before: boolean, targetId: string) => void): void {\n el.draggable = true;\n el.dataset[\"reorderId\"] = id;\n const host = (): ParentNode => el.parentElement ?? el;\n el.addEventListener(\"dragstart\", (e) => {\n reorderDragId = id; el.classList.add(\"dragging\");\n if (e.dataTransfer) { e.dataTransfer.effectAllowed = \"move\"; e.dataTransfer.setData(\"text/plain\", id); }\n });\n el.addEventListener(\"dragend\", () => { reorderDragId = null; el.classList.remove(\"dragging\"); clearDropMarks(host()); });\n el.addEventListener(\"dragover\", (e) => {\n if (!reorderDragId || reorderDragId === id) return;\n e.preventDefault();\n if (e.dataTransfer) e.dataTransfer.dropEffect = \"move\";\n const r = el.getBoundingClientRect();\n const before = axis === \"y\" ? e.clientY < r.top + r.height / 2 : e.clientX < r.left + r.width / 2;\n clearDropMarks(host());\n el.classList.add(before ? \"drop-before\" : \"drop-after\");\n });\n el.addEventListener(\"dragleave\", () => el.classList.remove(\"drop-before\", \"drop-after\"));\n el.addEventListener(\"drop\", (e) => {\n e.preventDefault();\n const before = el.classList.contains(\"drop-before\");\n clearDropMarks(host());\n if (reorderDragId && reorderDragId !== id) onMove(reorderDragId, before, id);\n });\n}\n\n// --- metadata and breadcrumbs ---------------------------------------------------\n// \"Icons are drawn, and so are separators\" (design-language.md section 4,\n// 2026-09-16): metadata is never joined with \"·\" and a breadcrumb is never a\n// string with \"›\" in it. Both apps had been building exactly those strings\n// (ui-review-2026-09, marker A); these two helpers make the same lines as DOM,\n// with the separator drawn by CSS (controls.css) or by the icon vocabulary.\n\n/**\n * A metadata line: `parts` as spans in a flex row, separated by a drawn\n * 3px disc (a `::before` on every part after the first, in controls.css),\n * so `metaLine([\"6 runs\", \"200 max steps\", \"seed 4\"])` is what\n * \"6 runs · 200 max steps · seed 4\" used to be, without the typed dot.\n * Empty, null and undefined parts are skipped, so a caller can pass an\n * optional segment without branching.\n */\nexport function metaLine(parts: (string | Node | null | undefined)[]): HTMLElement {\n const row = el(\"span\", \"shell-meta\");\n for (const part of parts) {\n if (part === null || part === undefined || part === \"\") continue;\n const seg = el(\"span\", \"shell-meta-part\");\n seg.append(part);\n row.append(seg);\n }\n return row;\n}\n\nexport interface Crumb {\n label: string;\n /** Makes the crumb a button. Ignored on the last crumb, which is where the\n * reader already is. */\n onClick?: (event: MouseEvent) => void;\n}\n\n/**\n * A breadcrumb trail: each crumb a span, or a button when it carries\n * `onClick` and is not the last, with `iconNode(\"forward\", 12)` drawn between\n * them. `breadcrumb([\"Box\", \"Deck\", \"Card\"])` is what \"Box › Deck › Card\"\n * used to be; the chevrons are the family's own drawing, not a symbol-font\n * character.\n */\nexport function breadcrumb(parts: (string | Crumb)[]): HTMLElement {\n const trail = el(\"nav\", \"shell-crumbs\");\n trail.setAttribute(\"aria-label\", \"Where this is\");\n parts.forEach((part, i) => {\n const crumb: Crumb = typeof part === \"string\" ? { label: part } : part;\n const last = i === parts.length - 1;\n if (i > 0) {\n const sep = iconNode(\"forward\", 12);\n sep.classList.add(\"shell-crumb-sep\");\n trail.append(sep);\n }\n if (crumb.onClick && !last) {\n const b = el(\"button\", { className: \"shell-crumb shell-crumb-link\", text: crumb.label, onClick: crumb.onClick });\n b.type = \"button\";\n trail.append(b);\n } else {\n const s = el(\"span\", \"shell-crumb\", crumb.label);\n if (last) s.setAttribute(\"aria-current\", \"location\");\n trail.append(s);\n }\n });\n return trail;\n}\n","// ---------------------------------------------------------------------------\n// The per-entity colour model (design-language.md section 4): a stable hash of\n// a name selects an INDEX into the curated palette - repeatable, storage-free.\n// The hues live in the token layer as `--char-0 .. --char-(N-1)` per theme, so\n// a colour reference adapts to light/dark with zero JS. Each app defines the\n// `--char-*` values in its own palette; this module only picks the slot.\n//\n// Storylet Studio uses it for dimension-value / zone chips; Patterpad for\n// character cues.\n// ---------------------------------------------------------------------------\n\n/** Curated colour slots; must match the `--char-*` set defined per theme. */\nexport const PALETTE_SIZE = 12;\n\nexport const PALETTE = Array.from({ length: PALETTE_SIZE }, (_, i) => `var(--char-${i})`) as readonly string[];\n\n/** Hash a name to a palette slot: FNV-1a + an fmix32 avalanche, well\n * distributed even for short, similar names. */\nexport function colourIndex(name: string): number {\n let h = 0x811c9dc5;\n for (let i = 0; i < name.length; i++) { h ^= name.charCodeAt(i); h = Math.imul(h, 0x01000193); }\n h ^= h >>> 16; h = Math.imul(h, 0x85ebca6b); h ^= h >>> 13; h = Math.imul(h, 0xc2b2ae35); h ^= h >>> 16;\n return (h >>> 0) % PALETTE_SIZE;\n}\n\n/** The theme-aware CSS variable reference for a name's slot. */\nexport function colourFor(name: string): string {\n return PALETTE[colourIndex(name)]!;\n}\n","// ---------------------------------------------------------------------------\n// Keyboard hints, platform-true, from ONE helper.\n//\n// \"One casing rule, and platform-true key hints\" (design-language.md section\n// 4, 2026-09-16): a hint writes \"⌘\" on macOS and \"Ctrl\" elsewhere, and \"⌘\"\n// never appears in a hard-coded string. Before this module the family had four\n// notations for one idea (ui-review-2026-09, finding 26): a <kbd> here, \"(⌘1)\"\n// in a tooltip there, a platform fork in one label, and \"↑↓ move · ↵ jump ·\n// esc to close\" typed into a hint bar, which on Windows showed a Mac glyph.\n//\n// The input is the portable spelling every caller already knows from the menu\n// spine: \"Mod+1\", \"Mod+Shift+M\", \"Enter\", \"Esc\", \"Up\". The output is what the\n// platform writes: \"⌘1\" / \"⇧⌘M\" / \"↩\" / \"esc\" on a Mac, in Apple's modifier\n// order and with no joiner; \"Ctrl+1\" / \"Ctrl+Shift+M\" / \"Enter\" / \"Esc\"\n// everywhere else. A hint is DOM (`keyHint`, `hintBar`): a keycap element,\n// never a glyph string, and a tooltip gets its bracketed key from\n// `tipWithKey` so it is right on both platforms.\n// ---------------------------------------------------------------------------\n\nexport type KeyPlatform = \"mac\" | \"win\" | \"linux\";\n\nlet override: KeyPlatform | undefined;\n\n/** Pin the platform every helper here renders for (undefined = detect again).\n * A seam for the tests and for a preview harness; an app leaves it unset. */\nexport function setKeyPlatform(platform?: KeyPlatform): void { override = platform; }\n\n/** The platform the hints render for: the override, else the browser's, else\n * the process's, else \"linux\" (which draws the same as \"win\"). */\nexport function keyPlatform(): KeyPlatform {\n if (override) return override;\n if (typeof navigator !== \"undefined\") {\n const s = `${navigator.platform ?? \"\"} ${navigator.userAgent ?? \"\"}`;\n if (/mac|iphone|ipad/i.test(s)) return \"mac\";\n if (/win/i.test(s)) return \"win\";\n if (s.trim()) return \"linux\";\n }\n const p = typeof process !== \"undefined\" ? process.platform : undefined;\n return p === \"darwin\" ? \"mac\" : p === \"win32\" ? \"win\" : \"linux\";\n}\n\n/** Canonical modifier words, in the order each platform writes them. Apple\n * puts them ⌃ ⌥ ⇧ ⌘ before the key; Windows and Linux write Ctrl+Alt+Shift. */\ntype Modifier = \"ctrl\" | \"alt\" | \"shift\" | \"mod\";\nconst MAC_ORDER: Modifier[] = [\"ctrl\", \"alt\", \"shift\", \"mod\"];\nconst OTHER_ORDER: Modifier[] = [\"mod\", \"ctrl\", \"alt\", \"shift\"];\nconst MAC_MOD: Record<Modifier, string> = { ctrl: \"⌃\", alt: \"⌥\", shift: \"⇧\", mod: \"⌘\" };\nconst OTHER_MOD: Record<Modifier, string> = { ctrl: \"Ctrl\", alt: \"Alt\", shift: \"Shift\", mod: \"Ctrl\" };\n\nconst MODIFIER_ALIASES: Record<string, Modifier> = {\n mod: \"mod\", cmd: \"mod\", command: \"mod\", meta: \"mod\", super: \"mod\",\n ctrl: \"ctrl\", control: \"ctrl\",\n alt: \"alt\", option: \"alt\", opt: \"alt\",\n shift: \"shift\",\n};\n\n/** Named keys: the Mac legend and the spelled-out word the others use. */\nconst NAMED: Record<string, { mac: string; other: string }> = {\n enter: { mac: \"↩\", other: \"Enter\" }, return: { mac: \"↩\", other: \"Enter\" },\n esc: { mac: \"esc\", other: \"Esc\" }, escape: { mac: \"esc\", other: \"Esc\" },\n up: { mac: \"↑\", other: \"Up\" }, down: { mac: \"↓\", other: \"Down\" },\n left: { mac: \"←\", other: \"Left\" }, right: { mac: \"→\", other: \"Right\" },\n backspace: { mac: \"⌫\", other: \"Backspace\" }, delete: { mac: \"⌦\", other: \"Del\" }, del: { mac: \"⌦\", other: \"Del\" },\n tab: { mac: \"⇥\", other: \"Tab\" }, space: { mac: \"Space\", other: \"Space\" },\n home: { mac: \"↖\", other: \"Home\" }, end: { mac: \"↘\", other: \"End\" },\n pageup: { mac: \"⇞\", other: \"PgUp\" }, pagedown: { mac: \"⇟\", other: \"PgDn\" },\n};\n\ninterface Parsed { mods: Modifier[]; key: string | undefined }\n\n/** The portable modifier words, exactly: the spelling the menu spine uses. The\n * aliases above (\"Cmd\", \"Option\") are tolerated by `parse` but they are not\n * portable, which is what `isKeyCombo` keys on. */\nconst PORTABLE_MODS = new Set<string>([\"mod\", \"ctrl\", \"alt\", \"shift\"]);\n\n/** Split \"Mod+Shift+M\" into its modifiers and its key. A literal \"+\" key is\n * written \"Mod++\" (the last empty part). Case is ignored on the words. */\nfunction parse(combo: string): Parsed {\n const parts = combo.split(\"+\");\n const mods: Modifier[] = [];\n let key: string | undefined;\n for (let i = 0; i < parts.length; i++) {\n const raw = parts[i] ?? \"\";\n if (raw === \"\" && i > 0) { key = \"+\"; continue; }\n const mod = MODIFIER_ALIASES[raw.toLowerCase()];\n if (mod) { if (!mods.includes(mod)) mods.push(mod); continue; }\n key = raw;\n }\n return { mods, key };\n}\n\n/**\n * Whether `value` is a combo in the portable spelling (\"Mod+1\", \"Ctrl+Shift+M\",\n * \"Enter\", \"Mod++\") rather than a literal hint someone already wrote out\n * (\"Cmd+1\", \"⌘1\", \"F1 twice\"). The test is strict on purpose: only the words\n * `Mod`, `Ctrl`, `Alt` and `Shift` (any case) count as modifiers, and the one\n * key must be a single character or a named key. A place that took a literal\n * string before (the pane shell's `shortcutHint`) can then take a combo as\n * well without changing what any existing literal draws.\n */\nexport function isKeyCombo(value: string): boolean {\n // \"Mod++\" is the plus key, as `parse` reads it: count it, then read the rest.\n const plus = value.length > 2 && value.endsWith(\"++\");\n const parts = (plus ? value.slice(0, -2) : value).split(\"+\");\n let keys = plus ? 1 : 0;\n for (const raw of parts) {\n if (raw === \"\") return false;\n const word = raw.toLowerCase();\n if (PORTABLE_MODS.has(word)) continue;\n if (raw.length === 1 || word in NAMED) { keys++; continue; }\n return false;\n }\n return keys === 1;\n}\n\nfunction keyLegend(key: string, mac: boolean): string {\n const named = NAMED[key.toLowerCase()];\n if (named) return mac ? named.mac : named.other;\n return key.length === 1 ? key.toUpperCase() : key;\n}\n\n/** The platform's spelling of a combo as one string: \"⇧⌘M\" on a Mac,\n * \"Ctrl+Shift+M\" elsewhere. For a tooltip or a menu label; a visible hint in\n * a window is `keyHint` (a keycap), not this. */\nexport function keyLabel(combo: string, platform: KeyPlatform = keyPlatform()): string {\n const mac = platform === \"mac\";\n const { mods, key } = parse(combo);\n const order = mac ? MAC_ORDER : OTHER_ORDER;\n const words = order.filter((m) => mods.includes(m)).map((m) => (mac ? MAC_MOD : OTHER_MOD)[m]);\n // On Windows \"Mod\" and \"Ctrl\" are both Ctrl; say it once.\n const seen = new Set<string>();\n const modWords = words.filter((w) => (seen.has(w) ? false : (seen.add(w), true)));\n const legend = key === undefined ? [] : [keyLegend(key, mac)];\n return mac ? [...modWords, ...legend].join(\"\") : [...modWords, ...legend].join(\"+\");\n}\n\n/** The legends of a combo as the platform would draw them on keycaps: one\n * entry on a Mac (Apple's glyph string is one legend), one per key elsewhere. */\nexport function keyLegends(combo: string, platform: KeyPlatform = keyPlatform()): string[] {\n if (platform === \"mac\") return [keyLabel(combo, platform)];\n const { mods, key } = parse(combo);\n const seen = new Set<string>();\n const words = OTHER_ORDER.filter((m) => mods.includes(m)).map((m) => OTHER_MOD[m])\n .filter((w) => (seen.has(w) ? false : (seen.add(w), true)));\n return key === undefined ? words : [...words, keyLegend(key, false)];\n}\n\nexport interface KeyHintOptions {\n /** Render for this platform rather than the detected one. */\n platform?: KeyPlatform;\n}\n\nfunction chip(legend: string): HTMLElement {\n const k = document.createElement(\"kbd\");\n k.className = \"shell-kbd\";\n k.textContent = legend;\n return k;\n}\n\n/**\n * A keycap for `combo`: `<kbd class=\"shell-kbd\">` (keys.css). On a Mac one\n * chip carrying the glyph string (\"⇧⌘M\"); elsewhere one chip per key\n * (\"Ctrl\" \"Shift\" \"M\") side by side in a `<span class=\"shell-keys\">`, with no\n * typed joiner: keycaps beside each other read as \"together\". `combo` may\n * also list ALTERNATIVES separated by spaces (\"Up Down\" for a move hint),\n * each drawn as its own keycap.\n */\nexport function keyHint(combo: string, opts: KeyHintOptions = {}): HTMLElement {\n const platform = opts.platform ?? keyPlatform();\n const legends = combo.trim().split(/\\s+/).flatMap((c) => keyLegends(c, platform));\n if (legends.length === 1) return chip(legends[0]!);\n const group = document.createElement(\"span\");\n group.className = \"shell-keys\";\n for (const legend of legends) group.append(chip(legend));\n return group;\n}\n\nexport interface HintBarItem {\n /** A combo, or space-separated alternatives (\"Up Down\"). */\n keys: string;\n /** What the key does, as a sentence-case fragment (\"Move\", \"Jump\"). */\n label: string;\n}\n\n/**\n * The hint bar under a picker or a tool window (\"↑↓ move · ↵ jump · esc\n * close\" as it used to be typed): one `<div class=\"shell-hintbar\">` of\n * `<span class=\"shell-hint\">` items, each a keycap (`keyHint`) and a label,\n * spaced by CSS and separated by nothing typed at all.\n */\nexport function hintBar(items: HintBarItem[], opts: KeyHintOptions = {}): HTMLElement {\n const bar = document.createElement(\"div\");\n bar.className = \"shell-hintbar\";\n for (const item of items) {\n const hint = document.createElement(\"span\");\n hint.className = \"shell-hint\";\n const label = document.createElement(\"span\");\n label.className = \"shell-hint-label\";\n label.textContent = item.label;\n hint.append(keyHint(item.keys, opts), label);\n bar.append(hint);\n }\n return bar;\n}\n\n/** Tooltip text with its key in brackets, platform-true: `tipWithKey(\"Show\n * scenes\", \"Mod+1\")` is \"Show scenes (⌘1)\" on a Mac and \"Show scenes\n * (Ctrl+1)\" elsewhere. For `data-tip`; the pane shell calls it itself when\n * `PaneSideConfig.shortcutHint` is a combo. */\nexport function tipWithKey(text: string, combo: string, platform: KeyPlatform = keyPlatform()): string {\n return `${text} (${keyLabel(combo, platform)})`;\n}\n","// ---------------------------------------------------------------------------\n// mountPaneShell: the app-frame both editors share - a top bar with compact\n// pane toggles, a nav | centre | inspector grid whose side panes collapse and\n// resize, and width/open-state persistence via a host callback. The host fills\n// the pane bodies + top-bar slots and owns its own keyboard accelerators\n// (call togglePane); the frame owns layout, collapse, drag-resize, and state.\n//\n// The frame CSS ships alongside as pane-shell.css (import it once at the app\n// root). It reads the shared token grammar (tokens.css).\n// ---------------------------------------------------------------------------\n\nimport { iconNode } from \"./icons.js\";\nimport { isKeyCombo, tipWithKey } from \"./keys.js\";\nimport { ensureTooltipHost } from \"./tooltip.js\";\n\nexport type PaneSide = \"nav\" | \"inspector\";\n\nexport interface PaneSideConfig {\n /** The open width as a CSS length, e.g. \"14rem\" or \"224px\". */\n defaultWidth: string;\n /** Drag floor in px (default 160). */\n minWidth?: number;\n /** Drag ceiling in px from the window width (default w => min(640, w - 420)). */\n maxWidth?: (innerWidth: number) => number;\n /** Whether a drag seam is offered (default true). */\n resizable?: boolean;\n /** Noun for the toggle's tooltip/aria, e.g. \"navigator\" / \"inspector\". */\n label?: string;\n /** The key that toggles the pane, bracketed after the tooltip. A combo in\n * the portable spelling (\"Mod+1\") is drawn for the platform through\n * `tipWithKey`: \"(⌘1)\" on a Mac, \"(Ctrl+1)\" elsewhere. Anything else is a\n * literal and goes in verbatim, as it always has (\"Cmd+1\" stays \"Cmd+1\"). */\n shortcutHint?: string;\n /** false = the pane is not offered at all: no toggle, togglePane ignored,\n * forced closed whatever the remembered state says. For a slot a host has\n * retired but keeps mounted (Storyletter's inspector) - the shell used to\n * offer a chevron that opened a paneful of nothing. Default true. */\n offered?: boolean;\n}\n\nexport interface PaneShellState {\n open: Record<PaneSide, boolean>;\n /** Dragged widths in px; absent = the config default. */\n width: Partial<Record<PaneSide, number>>;\n}\n\nexport interface PaneShellOptions {\n nav: PaneSideConfig;\n inspector: PaneSideConfig;\n /** Initial open + width state (from the host's store). */\n initial?: Partial<PaneShellState>;\n /** Persist state after any toggle or resize (host wires it to its store). */\n onChange?: (state: PaneShellState) => void;\n /** The toggle's rollover for a side in a given state. Default: \"Show\n * navigator\" / \"Hide navigator\" from the side's `label`, with the\n * `shortcutHint` in brackets (platform-true when it is a combo). Written as\n * `data-tip` (the themed tooltip) and as the accessible name; never as\n * `title`. */\n tipFor?: (side: PaneSide, open: boolean) => string;\n /** An extra class per side, toggled on the `.panes` grid whenever that side\n * is collapsed, beside the shell's own `no-nav` / `no-inspector`. For an\n * app whose stylesheet already keys on its own name for the state\n * (Patterpad's `props-doc-open`), so its rules ride the shell's collapse\n * rather than a second copy of it. */\n collapseAlso?: Partial<Record<PaneSide, string>>;\n}\n\nexport interface PaneShell {\n /** The frame element (top bar + panes); mount it into the app container. */\n readonly root: HTMLElement;\n readonly topbar: HTMLElement;\n /** Top-bar host slots: leading (title) and trailing (status), the host fills. */\n readonly topbarLead: HTMLElement;\n readonly topbarTrail: HTMLElement;\n /** Pane bodies the host fills (the fixed-width inner that clips on collapse). */\n readonly nav: HTMLElement;\n readonly centre: HTMLElement;\n readonly inspector: HTMLElement;\n togglePane(side: PaneSide): void;\n setPaneOpen(side: PaneSide, open: boolean): void;\n /** Whether the pane is showing: open, and not held closed. */\n isOpen(side: PaneSide): boolean;\n /** Fold a side away WITHOUT changing what the person chose: a mode that has\n * no use for the inspector (Patterpad's properties page) holds it closed,\n * and releasing the hold restores whatever was remembered. Not persisted;\n * the toggle keeps reporting the remembered state. */\n holdClosed(side: PaneSide, held: boolean): void;\n /** Clear dragged widths back to the config defaults. */\n resetWidths(): void;\n /** A snapshot of the current state (open + widths). */\n state(): PaneShellState;\n destroy(): void;\n}\n\nconst DEFAULT_MAX = (w: number): number => Math.min(640, w - 420);\nconst openVar: Record<PaneSide, string> = { nav: \"--nav-open-w\", inspector: \"--insp-open-w\" };\nconst collapseClass: Record<PaneSide, string> = { nav: \"no-nav\", inspector: \"no-inspector\" };\n\nexport function mountPaneShell(host: HTMLElement, opts: PaneShellOptions): PaneShell {\n const cfg: Record<PaneSide, PaneSideConfig> = { nav: opts.nav, inspector: opts.inspector };\n const offered = (side: PaneSide): boolean => cfg[side].offered !== false;\n const open: Record<PaneSide, boolean> = {\n nav: offered(\"nav\") && (opts.initial?.open?.nav ?? true),\n inspector: offered(\"inspector\") && (opts.initial?.open?.inspector ?? true),\n };\n const width: Partial<Record<PaneSide, number>> = { ...(opts.initial?.width ?? {}) };\n const held: Record<PaneSide, boolean> = { nav: false, inspector: false };\n const showing = (side: PaneSide): boolean => open[side] && !held[side];\n\n const el = <K extends keyof HTMLElementTagNameMap>(tag: K, cls?: string): HTMLElementTagNameMap[K] => {\n const n = document.createElement(tag);\n if (cls) n.className = cls;\n return n;\n };\n\n // --- top bar ---------------------------------------------------------------\n const navToggle = el(\"button\", \"pane-toggle\");\n navToggle.type = \"button\";\n const inspToggle = el(\"button\", \"pane-toggle\");\n inspToggle.type = \"button\";\n const topbarLead = el(\"div\", \"topbar-lead\");\n const topbarTrail = el(\"div\", \"topbar-trail\");\n const spacer = el(\"span\", \"topbar-spacer\");\n const topbar = el(\"header\", \"topbar\");\n topbar.append(navToggle, topbarLead, spacer, topbarTrail, inspToggle);\n\n // --- panes -----------------------------------------------------------------\n const panes = el(\"main\", \"panes\");\n const navPane = el(\"nav\", \"pane pane-nav\");\n const navInner = el(\"div\", \"pane-inner\");\n navPane.append(navInner);\n const centre = el(\"section\", \"pane-centre\");\n const inspPane = el(\"aside\", \"pane pane-inspector\");\n const inspInner = el(\"div\", \"pane-inner\");\n inspPane.append(inspInner);\n const navResizer = el(\"div\", \"pane-resizer pane-resizer-nav\");\n const inspResizer = el(\"div\", \"pane-resizer pane-resizer-insp\");\n panes.append(navPane, centre, inspPane, navResizer, inspResizer);\n\n const root = el(\"div\", \"pane-shell\");\n root.append(topbar, panes);\n host.append(root);\n // An unoffered pane's toggle is not hidden but ABSENT: nothing to\n // discover, nothing to tab to.\n if (!offered(\"nav\")) navToggle.remove();\n if (!offered(\"inspector\")) inspToggle.remove();\n\n // --- state application -----------------------------------------------------\n const defaultTip = (side: PaneSide, isOpen: boolean): string => {\n const text = `${isOpen ? \"Hide\" : \"Show\"} ${cfg[side].label ?? side}`;\n const hint = cfg[side].shortcutHint;\n if (!hint) return text;\n // A portable combo is spelled for the platform at draw time; a literal\n // is the caller's own words and goes in as written.\n return isKeyCombo(hint) ? tipWithKey(text, hint) : `${text} (${hint})`;\n };\n const tipFor = opts.tipFor ?? defaultTip;\n\n function applyToggleGlyph(side: PaneSide, button: HTMLButtonElement): void {\n const isOpen = open[side];\n // Chevron points toward where the pane collapses to.\n button.replaceChildren(iconNode(side === \"nav\" ? (isOpen ? \"back\" : \"forward\") : (isOpen ? \"forward\" : \"back\")));\n // `data-tip`, not `title`: the themed tooltip, never the OS bubble on the\n // platform's own delay. The tip is also the accessible name, since the\n // button has no text of its own.\n const tip = tipFor(side, isOpen);\n button.dataset[\"tip\"] = tip;\n button.setAttribute(\"aria-label\", tip);\n button.setAttribute(\"aria-pressed\", String(isOpen));\n }\n // Writing data-tip mounts the renderer, as `el` does, so a window whose host\n // never called initTooltips() still draws the rollover.\n ensureTooltipHost();\n\n function apply(): void {\n for (const side of [\"nav\", \"inspector\"] as const) {\n const collapsed = !showing(side);\n panes.classList.toggle(collapseClass[side], collapsed);\n const also = opts.collapseAlso?.[side];\n if (also) panes.classList.toggle(also, collapsed);\n }\n // The open widths live on the grid: the track and each .pane-inner read them.\n panes.style.setProperty(openVar.nav, width.nav !== undefined ? `${width.nav}px` : cfg.nav.defaultWidth);\n panes.style.setProperty(openVar.inspector, width.inspector !== undefined ? `${width.inspector}px` : cfg.inspector.defaultWidth);\n applyToggleGlyph(\"nav\", navToggle);\n applyToggleGlyph(\"inspector\", inspToggle);\n navResizer.style.display = cfg.nav.resizable === false || !offered(\"nav\") ? \"none\" : \"\";\n inspResizer.style.display = cfg.inspector.resizable === false || !offered(\"inspector\") ? \"none\" : \"\";\n }\n\n const snapshot = (): PaneShellState => ({ open: { ...open }, width: { ...width } });\n const persist = (): void => opts.onChange?.(snapshot());\n\n function setPaneOpen(side: PaneSide, next: boolean): void {\n if (open[side] === next) return;\n open[side] = next;\n apply();\n persist();\n }\n function togglePane(side: PaneSide): void { if (offered(side)) setPaneOpen(side, !open[side]); }\n function holdClosed(side: PaneSide, next: boolean): void {\n if (held[side] === next) return;\n held[side] = next;\n apply(); // not persisted: the hold is the mode's, the remembered state is the person's\n }\n function resetWidths(): void { delete width.nav; delete width.inspector; apply(); persist(); }\n\n navToggle.addEventListener(\"click\", () => togglePane(\"nav\"));\n inspToggle.addEventListener(\"click\", () => togglePane(\"inspector\"));\n\n // --- drag resize -----------------------------------------------------------\n function beginResize(side: PaneSide, startEvent: PointerEvent): void {\n if (cfg[side].resizable === false || !showing(side)) return;\n startEvent.preventDefault();\n const pane = side === \"nav\" ? navPane : inspPane;\n const seam = side === \"nav\" ? navResizer : inspResizer;\n seam.classList.add(\"dragging\");\n const min = cfg[side].minWidth ?? 160;\n const max = cfg[side].maxWidth ?? DEFAULT_MAX;\n const startX = startEvent.clientX;\n const startW = pane.getBoundingClientRect().width;\n document.body.classList.add(\"pane-resizing\");\n let latest = startW;\n const onMove = (e: PointerEvent): void => {\n const delta = side === \"nav\" ? e.clientX - startX : startX - e.clientX;\n latest = Math.max(min, Math.min(max(window.innerWidth), startW + delta));\n panes.style.setProperty(openVar[side], `${latest}px`);\n };\n const onUp = (): void => {\n window.removeEventListener(\"pointermove\", onMove);\n window.removeEventListener(\"pointerup\", onUp);\n document.body.classList.remove(\"pane-resizing\");\n seam.classList.remove(\"dragging\");\n width[side] = latest;\n persist();\n };\n window.addEventListener(\"pointermove\", onMove);\n window.addEventListener(\"pointerup\", onUp);\n }\n navResizer.addEventListener(\"pointerdown\", (e) => beginResize(\"nav\", e));\n inspResizer.addEventListener(\"pointerdown\", (e) => beginResize(\"inspector\", e));\n navResizer.addEventListener(\"dblclick\", () => { delete width.nav; apply(); persist(); });\n inspResizer.addEventListener(\"dblclick\", () => { delete width.inspector; apply(); persist(); });\n\n apply();\n\n return {\n root, topbar, topbarLead, topbarTrail,\n nav: navInner, centre, inspector: inspInner,\n togglePane, setPaneOpen, isOpen: showing, holdClosed, resetWidths, state: snapshot,\n destroy: () => { root.remove(); },\n };\n}\n","// ---------------------------------------------------------------------------\n// Shell-owned menu naming: the labels + accelerators for the pane-frame menu\n// items, single-sourced so every app in the family names them identically\n// (and a rename here flows to all of them). Pure data - no electron, no DOM -\n// so a main-process menu builder can import it. Each app builds its own\n// MenuItem from these and wires the click to its shell controller.\n// ---------------------------------------------------------------------------\n\nimport type { RecentProject } from \"./app-store.js\";\n\nexport interface MenuLabel {\n label: string;\n /** Electron accelerator string, when the item has one. */\n accelerator?: string;\n}\n\n/**\n * The Edit menu items the family shares.\n *\n * Undo and Redo are here and the MECHANISM is not, which is the whole finding\n * about undo: Patterpad's is ProseMirror's document history, Storyletter's is a\n * replay of file bytes, and those have nothing in common but this. See\n * `design/shared-shell.md`.\n *\n * The rule both apps discovered separately, and the reason these are spelled\n * out rather than left as Electron's `role: \"undo\"`: the native role runs a DOM\n * text-field undo, which knows nothing about either app's model and will\n * silently undo the wrong thing.\n */\nexport const EDIT_MENU: {\n undo: MenuLabel;\n redo: MenuLabel;\n duplicate: MenuLabel;\n find: MenuLabel;\n /** Replace is Find's second tab, on the platform's key for it. */\n replace: { label: string; acceleratorMac: string; acceleratorOther: string };\n} = {\n undo: { label: \"Undo\", accelerator: \"CmdOrCtrl+Z\" },\n redo: { label: \"Redo\", accelerator: \"Shift+CmdOrCtrl+Z\" },\n duplicate: { label: \"Duplicate\", accelerator: \"CmdOrCtrl+D\" },\n find: { label: \"Find…\", accelerator: \"CmdOrCtrl+F\" },\n replace: { label: \"Replace…\", acceleratorMac: \"Cmd+Alt+F\", acceleratorOther: \"Ctrl+H\" },\n};\n\n/**\n * Back / Forward: navigation HISTORY, the other axis from Up a Level's\n * hierarchy. One string cannot serve both platforms - the mac pair is Xcode's\n * (Cmd+[ is already Up a Level in this family, so the browser pair is taken),\n * and the Alt pair is what every Windows browser and Explorer trained - so the\n * menu builder picks by platform.\n */\nexport const GO_MENU: {\n back: { label: string; acceleratorMac: string; acceleratorOther: string };\n forward: { label: string; acceleratorMac: string; acceleratorOther: string };\n} = {\n back: { label: \"Back\", acceleratorMac: \"Ctrl+Cmd+Left\", acceleratorOther: \"Alt+Left\" },\n forward: { label: \"Forward\", acceleratorMac: \"Ctrl+Cmd+Right\", acceleratorOther: \"Alt+Right\" },\n};\n\n/** The pane-frame menu items (a View menu, conventionally). */\nexport const PANE_MENU: {\n showNav: MenuLabel;\n showInspector: MenuLabel;\n resetView: MenuLabel;\n} = {\n showNav: { label: \"Show Navigator\", accelerator: \"CmdOrCtrl+1\" },\n showInspector: { label: \"Show Inspector\", accelerator: \"CmdOrCtrl+2\" },\n resetView: { label: \"Reset View\" },\n};\n\n/**\n * The Help menu items the family shares, and the one platform rule that goes\n * with them.\n *\n * Lifted from Patterpad, which is the only app that has ever had these: a\n * second app writing its own updater or About is pure waste (`design/\n * shared-shell.md`), and a suite is recognised by finding Check for Updates\n * where you left it. Storyletter will grow both; until it does, these labels\n * are the agreement rather than a description of two implementations.\n *\n * PLACEMENT, which differs by platform and is easy to get wrong:\n * - macOS keeps About in the APP menu (the one named after the product), and\n * Help carries documentation + Check for Updates only.\n * - Windows and Linux have no app menu, so About goes at the foot of Help,\n * after a separator. That is the conventional home there.\n */\nexport const HELP_MENU: {\n checkForUpdates: MenuLabel;\n} = {\n checkForUpdates: { label: \"Check for Updates\\u2026\" },\n};\n\n/** The app-menu items the family shares (macOS; the identity item also belongs in File elsewhere). */\nexport const APP_MENU: {\n userInfo: MenuLabel;\n} = {\n /** Name + optional email, used to sign edits and comments. One label across the suite. */\n userInfo: { label: \"User Information\\u2026\" },\n};\n\n/** What an app must tell the shell to build its named menu items. */\nexport interface MenuNaming {\n /** The product, as it appears in menus: \"Patterpad\", \"Storyletter\". */\n appName: string;\n /** The product's own documentation URL. Omit while an app has no docs yet and\n * the item is rendered disabled rather than opening a broken link. */\n docsUrl?: string;\n /** The suite's documentation home, shared by every app in the family. */\n suiteDocsUrl?: string;\n /** The suite, as it appears in \"<suite> Documentation Home\". Defaults to \"Patter\". */\n suiteName?: string;\n}\n\n/** A named menu item: the label, plus the URL it opens (absent = nothing wired yet). */\nexport interface NamedMenuItem extends MenuLabel {\n url?: string;\n /** False when the app has not supplied a URL, so the builder can render it\n * disabled instead of opening nothing. A placeholder, honestly labelled. */\n ready: boolean;\n}\n\n/**\n * The menu labels that carry a product or suite name, so no app spells its own\n * About or Documentation item differently from the rest of the family.\n *\n * An app with no documentation site yet still gets the ITEM, marked\n * `ready: false`, so the menu has its family shape from day one and wiring the\n * URL later is a one-line change rather than a menu redesign.\n */\nexport function namedMenuItems(naming: MenuNaming): {\n about: NamedMenuItem;\n docs: NamedMenuItem;\n suiteDocs: NamedMenuItem;\n} {\n const suite = naming.suiteName ?? \"Patter\";\n return {\n about: { label: `About ${naming.appName}`, ready: true },\n docs: {\n label: `${naming.appName} Documentation`,\n ...(naming.docsUrl ? { url: naming.docsUrl } : {}),\n ready: naming.docsUrl !== undefined,\n },\n suiteDocs: {\n label: `${suite} Documentation Home`,\n ...(naming.suiteDocsUrl ? { url: naming.suiteDocsUrl } : {}),\n ready: naming.suiteDocsUrl !== undefined,\n },\n };\n}\n\n// --- the rest of the spine (ui-review-2026-09, finding 12) -----------------------\n// Each app used roughly half of what is above and hand-typed the other half,\n// and the copies had already drifted (Review Feedback's accelerator spelled\n// two ways; \"No Recent Projects\" vs \"No recent projects\"). Labels are Title\n// Case, as the platform's menus are; an item that opens something ends in the\n// command ellipsis.\n\n/** The File menu items the family shares. */\nexport const FILE_MENU: {\n newProject: MenuLabel;\n openProject: MenuLabel;\n openRecent: MenuLabel;\n /** The empty Open Recent submenu's one disabled item. */\n noRecents: MenuLabel;\n clearRecents: MenuLabel;\n closeProject: MenuLabel;\n save: MenuLabel;\n saveAs: MenuLabel;\n projectSettings: MenuLabel;\n} = {\n newProject: { label: \"New Project…\", accelerator: \"CmdOrCtrl+N\" },\n openProject: { label: \"Open Project…\", accelerator: \"CmdOrCtrl+O\" },\n openRecent: { label: \"Open Recent\" },\n noRecents: { label: \"No Recent Projects\" },\n clearRecents: { label: \"Clear Recents\" },\n closeProject: { label: \"Close Project\" },\n save: { label: \"Save\", accelerator: \"CmdOrCtrl+S\" },\n saveAs: { label: \"Save As…\", accelerator: \"Shift+CmdOrCtrl+S\" },\n projectSettings: { label: \"Project Settings…\", accelerator: \"CmdOrCtrl+,\" },\n};\n\n/**\n * The Play menu's shared item. The play SURFACE itself (Patterpad's \"Play\n * Scene\" on Cmd+P, Storyletter's \"The Board\" on Cmd+T) is app-named and\n * app-keyed on purpose: the two are not the same act, so the family reserves\n * neither key.\n */\nexport const PLAY_MENU: {\n liveLink: MenuLabel;\n} = {\n liveLink: { label: \"Live Link\" },\n};\n\n/** The Review menu: examining what you have built rather than building or\n * playing it. Review Feedback's accelerator is spelled ONCE, here. */\nexport const REVIEW_MENU: {\n reviewFeedback: MenuLabel;\n nextFeedback: MenuLabel;\n previousFeedback: MenuLabel;\n coverageTest: MenuLabel;\n findPropertyUsage: MenuLabel;\n showResolvedComments: MenuLabel;\n} = {\n reviewFeedback: { label: \"Review Feedback\", accelerator: \"CmdOrCtrl+Shift+R\" },\n nextFeedback: { label: \"Next Feedback\", accelerator: \"F8\" },\n previousFeedback: { label: \"Previous Feedback\", accelerator: \"Shift+F8\" },\n coverageTest: { label: \"Coverage Test…\", accelerator: \"Shift+CmdOrCtrl+C\" },\n findPropertyUsage: { label: \"Find Property Usage…\" },\n showResolvedComments: { label: \"Show Resolved Comments\" },\n};\n\n/** The Publish menu: everything that turns the project into something you\n * hand to others (\"Publish\", never \"Export\"). */\nexport const PUBLISH_MENU: {\n playableHtml: MenuLabel;\n bundle: MenuLabel;\n autoRebuild: MenuLabel;\n} = {\n playableHtml: { label: \"Publish Playable HTML…\" },\n bundle: { label: \"Publish Bundle\", accelerator: \"Shift+CmdOrCtrl+B\" },\n autoRebuild: { label: \"Auto Rebuild\" },\n};\n\n/** The View menu items beyond the pane toggles (PANE_MENU) and history\n * (GO_MENU). Cmd+[ is family-reserved for Up a Level, which is why Back\n * takes Xcode's pair on the mac. */\nexport const VIEW_MENU: {\n projectOverview: MenuLabel;\n upALevel: MenuLabel;\n colourTheme: MenuLabel;\n} = {\n projectOverview: { label: \"Project Overview\" },\n upALevel: { label: \"Up a Level\", accelerator: \"CmdOrCtrl+[\" },\n colourTheme: { label: \"Colour Theme\" },\n};\n\n/** A path with the home directory as `~`, so a recents entry stays readable\n * at menu width. `home` is `app.getPath(\"home\")`; this file stays\n * electron-free. */\nexport function tildePath(path: string, home: string): string {\n if (path === home) return \"~\";\n const sep = home.includes(\"\\\\\") ? \"\\\\\" : \"/\";\n return path.startsWith(home + sep) ? `~${path.slice(home.length)}` : path;\n}\n\n/** As much of Electron's MenuItemConstructorOptions as a recents entry needs;\n * structurally assignable to it. */\nexport interface RecentsMenuItem {\n label?: string;\n sublabel?: string;\n toolTip?: string;\n enabled?: boolean;\n type?: \"separator\";\n click?: () => void;\n}\n\nexport interface RecentsSubmenuOptions {\n onOpen: (path: string) => void;\n /** Offered after a separator when there is anything to clear. */\n onClear?: () => void;\n /** `app.getPath(\"home\")`, for the `~` abbreviation. */\n home: string;\n /** Defaults to process.platform; a seam for the tests. */\n platform?: string;\n}\n\n/**\n * The Open Recent submenu: the fifteen lines both apps had.\n *\n * Shows WHERE each recent lives. macOS renders `sublabel` as a dimmed second\n * line and `toolTip` on hover; native menus elsewhere render neither, so\n * there the path is folded into the label itself. Empty, it is the one\n * disabled \"No Recent Projects\" item.\n */\nexport function recentsSubmenu(recents: RecentProject[], opts: RecentsSubmenuOptions): RecentsMenuItem[] {\n const isMac = (opts.platform ?? process.platform) === \"darwin\";\n if (recents.length === 0) return [{ label: FILE_MENU.noRecents.label, enabled: false }];\n const items: RecentsMenuItem[] = recents.map((r) => {\n const shown = tildePath(r.path, opts.home);\n const name = r.name ?? r.path.split(/[\\\\/]/).filter(Boolean).pop() ?? r.path;\n return {\n label: isMac ? name : `${name} (${shown})`,\n sublabel: shown,\n toolTip: r.path,\n click: () => opts.onOpen(r.path),\n };\n });\n if (opts.onClear) items.push({ type: \"separator\" }, { label: FILE_MENU.clearRecents.label, click: opts.onClear });\n return items;\n}\n","// ---------------------------------------------------------------------------\n// Problem copy: a validator's diagnostic rewritten for the person at the\n// keyboard, through a table the app fills.\n//\n// Patterpad's `humanizeProblem` (its renderer.ts) proved the shape: a dozen\n// validator categories each mapped to a plain sentence with a next step, naming\n// things by their title, and a fallback that softens the technical residue.\n// Storyletter showed the raw compiler string and labelled it `path [where]`\n// (ui-review-2026-09, finding 17), the bracketed id that \"Diagnostics name what\n// the author can see\" (design-language.md) rules out for anything but a\n// DANGLING reference. This module is the translator; the tables are the\n// apps', because the codes are theirs. `defaultProblemCopy` covers the handful\n// of codes both validators raise in some form, as a floor an app spreads into\n// its own table.\n// ---------------------------------------------------------------------------\n\n/** What a translator needs to know about a problem. `code` is the app's own\n * category (Patterpad's `detail`, or a code Storyletter derives from its\n * compiler message); `title` is the author-facing name of the thing the\n * problem is about, when the app can resolve one; `where` is the raw\n * reference (an id) for when it cannot. */\nexport interface ProblemLike {\n code?: string;\n message: string;\n path?: string;\n where?: string;\n title?: string;\n}\n\nexport interface ProblemCopy {\n /** The sentence: what is wrong, in the author's words. */\n text: string;\n /** What to do about it, when there is one thing to do. */\n next?: string;\n /** The reference this problem is about no longer has a name to give, so the\n * raw id may be shown, written `(id ...)` so it cannot be mistaken for a\n * name. Set by the table entry; the translator never guesses it. */\n dangling?: boolean;\n}\n\nexport type ProblemCopyEntry = (problem: ProblemLike) => ProblemCopy;\nexport type ProblemCopyTable = Record<string, ProblemCopyEntry>;\n\n/** The name to call the thing a problem is about: its title in curly quotes,\n * \"(id ...)\" only when the reference dangles and there is nothing else,\n * and \"This\" otherwise, because the bar's \"go to\" shows the reader what\n * \"this\" is and an id is not something they can look for. */\nexport function problemName(p: ProblemLike, dangling = false): string {\n if (p.title) return `“${p.title}”`;\n if (dangling && p.where) return `(id ${p.where})`;\n return \"This\";\n}\n\n/**\n * Translate `problem` through `table`. A matching entry decides the copy; with\n * no entry the raw message is kept and prefixed by the title when there is one\n * (\"Burner Rig: duplicate id\"). Nothing here ever writes `[where]`; an id\n * appears only as `(id ...)`, only when the entry says the reference dangles,\n * and only when there is no title to say instead.\n */\nexport function describeProblem(problem: ProblemLike, table: ProblemCopyTable = {}): ProblemCopy {\n const entry = problem.code ? table[problem.code] : undefined;\n if (entry) {\n const copy = entry(problem);\n const text = copy.dangling && !problem.title && problem.where && !copy.text.includes(`(id ${problem.where})`)\n ? `${copy.text} (id ${problem.where})`\n : copy.text;\n return copy.next ? { text, next: copy.next } : { text };\n }\n const message = problem.message.replace(/\\s*\\[[^\\]]*\\]\\s*$/, \"\").trim();\n return { text: problem.title ? `${problem.title}: ${message}` : message };\n}\n\n/** `describeProblem` as one line for a bar that has room for one: the sentence,\n * then the next step after a space. */\nexport function problemLine(problem: ProblemLike, table?: ProblemCopyTable): string {\n const { text, next } = describeProblem(problem, table);\n return next ? `${text} ${next}` : text;\n}\n\n/**\n * The codes both validators raise in some form, in the family's voice. An app\n * spreads this into its own table and adds its own codes over it; a code an\n * app does not raise costs nothing.\n *\n * duplicate-gameid two things share one Game ID\n * invalid-gameid a Game ID that breaks the address rule\n * dangling-reference a jump / tag / property points at something gone\n * unknown-property a condition or effect names an undeclared property\n * missing-name a thing that needs a name has none\n * empty a container with nothing in it\n * stale-build the playable build is older than the source\n * merge-conflict a file still carries conflict markers\n */\nexport const defaultProblemCopy: ProblemCopyTable = {\n \"duplicate-gameid\": (p) => ({\n text: `The Game ID on ${problemName(p)} is already used elsewhere.`,\n next: \"Each one must be unique; change one of them.\",\n }),\n \"invalid-gameid\": (p) => ({\n text: `The Game ID on ${problemName(p)} isn't valid.`,\n next: \"Use lowercase letters, digits and hyphens.\",\n }),\n \"dangling-reference\": (p) => ({\n text: `${problemName(p, true)} points at something that no longer exists.`,\n next: \"Choose where it goes.\",\n dangling: true,\n }),\n \"unknown-property\": (p) => ({\n text: `${problemName(p)} uses a property that isn't set up yet.`,\n next: \"Declare it in the project settings, or fix the name.\",\n }),\n \"missing-name\": (p) => ({ text: `${problemName(p)} needs a name.` }),\n \"empty\": (p) => ({\n text: `${problemName(p)} is empty.`,\n next: \"Add something inside it, or remove it.\",\n }),\n \"stale-build\": (p) => ({\n text: `Your playable build${p.path ? ` (${p.path})` : \"\"} is out of date.`,\n next: \"It refreshes the next time you publish.\",\n }),\n \"merge-conflict\": (p) => ({\n text: `${p.path ?? \"This file\"} still has an unresolved merge conflict in it.`,\n next: \"Resolve it in your version control tool, then reopen the project.\",\n }),\n};\n","// ---------------------------------------------------------------------------\n// The shared settings surface: a native <dialog> with a left-rail of grouped\n// tabs and one panel per section (mountSettingsDialog), plus the list-editing\n// core those sections lean on (expandableRow, focusNewRow, dupGuard). The app\n// supplies the sections; each holds its own state and reports the first invalid\n// control so the Save gate can block + jump. Framework here, content in the app.\n//\n// Lifted from Patterpad's Project Settings (settings-list.ts + the inlined\n// dialog logic in its renderer), with neutral class names. Styling ships as\n// settings.css.\n// ---------------------------------------------------------------------------\n\nimport { el } from \"./dom.js\";\n\n// --- list-editing core --------------------------------------------------------\n\n/** A compact list row: a single `.set-rowline` (inline controls) plus, when\n * `details` are given, a disclosure that reveals a `.set-details` panel below,\n * so a list scans like a table with secondary fields tucked away. `name` is\n * what the row declares (a property's name, a field's), stamped on it as\n * `data-name` so `revealRow` can land on it. */\nexport function expandableRow(opts: { line: HTMLElement[]; details?: HTMLElement[]; name?: string }): HTMLElement {\n const row = el(\"div\", \"set-row\");\n if (opts.name !== undefined) row.dataset.name = opts.name;\n const line = el(\"div\", \"set-rowline\");\n if (opts.details && opts.details.length) {\n const details = el(\"div\", \"set-details\"); details.hidden = true;\n for (const d of opts.details) details.append(d);\n // The triangle is drawn by CSS off `.open` (a text glyph stays hairline-thin).\n const toggle = el(\"button\", \"set-expand\"); toggle.type = \"button\";\n // `data-tip`, not `title`: this package ships a themed tooltip and nothing\n // else in it raises an OS rollover. A lone `title` here would be the one\n // place a host's chrome broke character, and on the platform's own delay.\n toggle.dataset.tip = \"More\"; toggle.setAttribute(\"aria-label\", \"More\");\n toggle.setAttribute(\"aria-expanded\", \"false\");\n toggle.addEventListener(\"click\", () => {\n const open = details.hidden;\n details.hidden = !open;\n toggle.setAttribute(\"aria-expanded\", String(open));\n toggle.classList.toggle(\"open\", open);\n });\n line.append(toggle);\n opts.line.forEach((c) => line.append(c));\n row.append(line, details);\n } else {\n opts.line.forEach((c) => line.append(c));\n row.append(line);\n }\n return row;\n}\n\n/**\n * Land on one row of a list by the `name` it was built with: open its details\n * (an enum's values sit behind the disclosure, and they are usually what the\n * jump was for), bring it to the middle of its scroller, and light it for a\n * moment (`.set-row.landed` in settings.css). \"Go to definition\" in both apps\n * used to open the page a property is declared on and stop there, with the\n * declaration below the fold and nothing marking it (Storyletter, 2026-09-14).\n *\n * Returns false when no row carries the name, so a host whose page fills in\n * asynchronously can ask again on a later frame; asking again is the host's,\n * since only the host knows what opens on its own time. The row is matched by\n * reading the stamp rather than by an attribute selector, so a name needs no\n * escaping.\n */\nexport function revealRow(within: ParentNode, name: string): boolean {\n const row = [...within.querySelectorAll<HTMLElement>(\".set-row\")].find((r) => r.dataset.name === name);\n if (!row) return false;\n const toggle = row.querySelector<HTMLButtonElement>(\".set-rowline > .set-expand\");\n if (toggle && toggle.getAttribute(\"aria-expanded\") !== \"true\") toggle.click();\n const still = typeof matchMedia === \"function\" && matchMedia(\"(prefers-reduced-motion: reduce)\").matches;\n row.scrollIntoView({ block: \"center\", behavior: still ? \"auto\" : \"smooth\" });\n // Restarted, so landing on the same row twice lights it twice.\n row.classList.remove(\"landed\");\n void row.offsetWidth;\n row.classList.add(\"landed\");\n row.addEventListener(\"animationend\", () => row.classList.remove(\"landed\"), { once: true });\n return true;\n}\n\n/**\n * `revealRow`, retried over the next frames until the row exists or the tries\n * run out: for a page that fills in on its own time after a navigation. Both\n * apps hand-rolled this as `landOn` with the same twelve tries\n * (ui-review-2026-09, finding 29). Resolves true when it landed, false when it\n * gave up, and giving up is quiet: a name no page shows as a row is not a fault.\n */\nexport function revealRowWhenReady(within: ParentNode, name: string, tries = 12): Promise<boolean> {\n return new Promise((resolve) => {\n const attempt = (left: number): void => {\n if (revealRow(within, name)) { resolve(true); return; }\n if (left <= 0) { resolve(false); return; }\n requestAnimationFrame(() => attempt(left - 1));\n };\n attempt(tries);\n });\n}\n\n/** After a \"+ Add\" re-renders a list, bring the new (last) row into view and\n * focus its name input (`.set-name`, else the first input). */\nexport function focusNewRow(listEl: HTMLElement | null | undefined): void {\n const last = listEl?.lastElementChild;\n if (!(last instanceof HTMLElement)) return;\n last.scrollIntoView({ block: \"nearest\" });\n const name = last.querySelector<HTMLInputElement>(\"input.set-name\") ?? last.querySelector<HTMLInputElement>(\"input\");\n name?.focus();\n}\n\nexport interface DupGuard {\n /** Forget the previous render's inputs (call at the top of render). */\n reset(): void;\n /** Register a name input; `key` returns the comparison string (default the\n * input's value). Re-checks live on input. `also` = extra inputs that change the key. */\n track(input: HTMLInputElement, key?: () => string, also?: HTMLInputElement[]): void;\n /** Re-paint duplicates; true if any two non-blank keys collide. */\n check(): boolean;\n /** The first input currently flagged (after a fresh check), or null. */\n firstDuplicate(): HTMLInputElement | null;\n}\n\nconst DUP_MESSAGE = \"Another row already has this name.\";\n\n/** Case-insensitive duplicate-name detection: paints clashing inputs `.invalid`\n * and lets a Save gate block + jump via `firstDuplicate()`. */\nexport function dupGuard(): DupGuard {\n const items: Array<{ input: HTMLInputElement; key: () => string }> = [];\n const check = (): boolean => {\n const counts = new Map<string, number>();\n for (const it of items) { const k = it.key().trim().toLowerCase(); if (k) counts.set(k, (counts.get(k) ?? 0) + 1); }\n let any = false;\n for (const it of items) {\n const k = it.key().trim().toLowerCase();\n const dup = !!k && (counts.get(k) ?? 0) > 1;\n it.input.classList.toggle(\"invalid\", dup);\n // The reason rides `data-tip` (the themed rollover, and what the Save\n // gate's message channel reads), never `title`.\n if (dup) { it.input.dataset[\"tip\"] = DUP_MESSAGE; any = true; }\n else if (it.input.dataset[\"tip\"] === DUP_MESSAGE) delete it.input.dataset[\"tip\"];\n }\n return any;\n };\n return {\n reset() { items.length = 0; },\n track(input, key = () => input.value, also) {\n items.push({ input, key });\n input.addEventListener(\"input\", check);\n for (const a of also ?? []) a.addEventListener(\"input\", check);\n },\n check,\n firstDuplicate() { check(); return items.find((it) => it.input.classList.contains(\"invalid\"))?.input ?? null; },\n };\n}\n\n// --- the settings dialog ------------------------------------------------------\n\nexport interface SettingsSectionHandle {\n /** The first invalid control to jump to, blocking Save (e.g. a duplicate\n * name). Return `{ el, message }` to say WHICH fault in the error line;\n * a bare element says it through its own `data-tip` (the dup guard's, a\n * property-name field's), and the line falls back to a generic sentence\n * when it has neither. */\n firstInvalid?(): HTMLElement | { el: HTMLElement; message?: string } | null;\n}\n\nexport interface SettingsSection {\n id: string;\n label: string;\n /** Optional left-rail group heading above this tab. */\n group?: string;\n /** Build the section body into `host`; called fresh on each open so it reads\n * the current data. Return a handle (for the Save gate). */\n mount(host: HTMLElement): SettingsSectionHandle;\n /** Why this tab cannot be used right now, or null when it can. A reason\n * renders the tab dimmed and inert with the reason as its rollover\n * (Patterpad's Audio tab while the project is not voiced). Read on open\n * and on `refreshTabs()`, so a control inside the dialog can flip it. */\n disabled?: () => string | null;\n}\n\nexport interface SettingsDialogOptions {\n title: string;\n sections: SettingsSection[];\n /** Fired when Save is clicked and every section validates. The app reads its\n * own section state and persists. May be async; the dialog stays open until\n * it resolves, then closes. */\n onSave: () => void | Promise<void>;\n}\n\nexport interface SettingsDialog {\n /** Open (optionally on a given tab id). Sections re-mount from current data. */\n open(tabId?: string): void;\n /** Re-read every section's `disabled()`; a tab that has just become\n * disabled while showing hands over to the first usable one. */\n refreshTabs(): void;\n destroy(): void;\n}\n\n/** Build a settings dialog. The frame owns the modal, the tab rail, save-on-Save\n * (with a validation gate), and Cancel; the sections own their content + state. */\nexport function mountSettingsDialog(opts: SettingsDialogOptions): SettingsDialog {\n const dialog = el(\"dialog\", \"settings-dialog\");\n const form = el(\"form\", \"settings-form\"); form.method = \"dialog\";\n const tabs = el(\"nav\", \"settings-tabs\");\n const panels = el(\"div\", \"settings-panels\");\n const error = el(\"p\", \"settings-error\"); error.hidden = true;\n const cancel = el(\"button\", \"settings-cancel\", \"Cancel\"); cancel.type = \"button\"; cancel.value = \"cancel\";\n const save = el(\"button\", \"settings-save primary\", \"Save\"); save.value = \"save\";\n\n const panelFor = new Map<string, HTMLElement>();\n const tabFor = new Map<string, HTMLButtonElement>();\n const handles = new Map<string, SettingsSectionHandle>();\n let active = opts.sections[0]?.id ?? \"\";\n\n let lastGroup: string | undefined;\n for (const s of opts.sections) {\n if (s.group && s.group !== lastGroup) { tabs.append(el(\"div\", \"settings-group\", s.group)); lastGroup = s.group; }\n const tab = el(\"button\", \"settings-tab\", s.label); tab.type = \"button\"; tab.dataset[\"tab\"] = s.id;\n // A disabled tab is inert by class, not by the `disabled` attribute: a\n // disabled button swallows the pointer, and the reason has to be readable\n // on hover.\n tab.addEventListener(\"click\", () => { if (!tab.classList.contains(\"is-disabled\")) showTab(s.id); });\n tabs.append(tab); tabFor.set(s.id, tab);\n const panel = el(\"section\", \"settings-panel\"); panel.dataset[\"panel\"] = s.id; panel.hidden = true;\n panels.append(panel); panelFor.set(s.id, panel);\n }\n\n function showTab(id: string): void {\n active = id;\n for (const [sid, t] of tabFor) t.classList.toggle(\"active\", sid === id);\n for (const [sid, p] of panelFor) p.hidden = sid !== id;\n }\n\n const usable = (s: SettingsSection): boolean => !tabFor.get(s.id)?.classList.contains(\"is-disabled\");\n function refreshTabs(): void {\n for (const s of opts.sections) {\n const tab = tabFor.get(s.id)!;\n const reason = s.disabled?.() ?? null;\n tab.classList.toggle(\"is-disabled\", reason !== null);\n if (reason !== null) { tab.dataset[\"tip\"] = reason; tab.setAttribute(\"aria-disabled\", \"true\"); }\n else { delete tab.dataset[\"tip\"]; tab.removeAttribute(\"aria-disabled\"); }\n }\n if (!opts.sections.some((s) => s.id === active && usable(s))) {\n const first = opts.sections.find(usable);\n if (first) showTab(first.id);\n }\n }\n\n form.append(\n el(\"h2\", \"settings-title\", opts.title),\n el(\"div\", \"settings-body\", tabs, panels),\n el(\"div\", \"settings-actions\", error, cancel, save),\n );\n dialog.append(form);\n document.body.append(dialog);\n\n // Enter should not submit while editing a field; only the Save button does.\n form.addEventListener(\"keydown\", (e) => {\n if (e.key === \"Enter\" && (e.target as HTMLElement)?.tagName === \"INPUT\") e.preventDefault();\n });\n\n cancel.addEventListener(\"click\", () => dialog.close(\"cancel\"));\n save.addEventListener(\"click\", (e) => {\n e.preventDefault();\n error.hidden = true;\n for (const s of opts.sections) {\n const found = handles.get(s.id)?.firstInvalid?.();\n if (!found) continue;\n const bad = found instanceof HTMLElement ? found : found.el;\n const message = (found instanceof HTMLElement ? undefined : found.message) ?? bad.dataset[\"tip\"];\n showTab(s.id);\n bad.focus();\n // The field's own rollover says which fault it is, so the line repeats it\n // rather than inventing a summary; the generic sentence is the fallback.\n error.textContent = message || \"Fix the highlighted fields first.\";\n error.hidden = false;\n return;\n }\n void (async () => { await opts.onSave(); dialog.close(\"save\"); })();\n });\n\n return {\n open(tabId) {\n handles.clear();\n for (const s of opts.sections) {\n const panel = panelFor.get(s.id)!;\n panel.replaceChildren();\n handles.set(s.id, s.mount(panel));\n }\n error.hidden = true;\n showTab(tabId ?? active ?? opts.sections[0]?.id ?? \"\");\n refreshTabs(); // a disabled tab asked for by id hands over to the first usable one\n dialog.showModal();\n },\n refreshTabs,\n destroy() { dialog.remove(); },\n };\n}\n","// ---------------------------------------------------------------------------\n// The small idioms both apps wrote by hand and never gave a name: the plural\n// suffix (about forty sites), the debounce (eight copies), \"is the focus in a\n// field\" (four copies that disagreed about <select>), the count with grouping\n// separators, clipboard copy with the `.copied` revert (three timings), and\n// relative time (two wordings). One answer each, here.\n//\n// DOM-free except where the idiom is about the DOM (isEditableTarget,\n// copyWithFeedback), so main-process code can import the rest.\n// ---------------------------------------------------------------------------\n\n/** \"1 link\" / \"3 links\". The plural form defaults to `noun + \"s\"`; pass the\n * irregular one (\"entry\", \"entries\") when that is wrong. */\nexport function plural(n: number, noun: string, pluralForm = `${noun}s`): string {\n return `${n} ${n === 1 ? noun : pluralForm}`;\n}\n\nexport interface Debounced<A extends unknown[]> {\n (...args: A): void;\n /** Drop the pending call. */\n cancel(): void;\n /** Run the pending call now, if there is one. */\n flush(): void;\n}\n\n/** Trailing-edge debounce: the call runs `ms` after the LAST call. */\nexport function debounce<A extends unknown[]>(fn: (...args: A) => void, ms: number): Debounced<A> {\n let timer: ReturnType<typeof setTimeout> | undefined;\n let pending: A | undefined;\n const run = (): void => {\n timer = undefined;\n if (pending === undefined) return;\n const args = pending;\n pending = undefined;\n fn(...args);\n };\n const debounced = ((...args: A): void => {\n pending = args;\n if (timer !== undefined) clearTimeout(timer);\n timer = setTimeout(run, ms);\n }) as Debounced<A>;\n debounced.cancel = () => { if (timer !== undefined) clearTimeout(timer); timer = undefined; pending = undefined; };\n debounced.flush = () => { if (timer !== undefined) clearTimeout(timer); run(); };\n return debounced;\n}\n\n/**\n * Is the keyboard's focus in a field? The one agreed answer: an input, a\n * textarea, a select, or anything contenteditable (the attribute is read as\n * well as `isContentEditable`, which jsdom does not implement). A window-level\n * shortcut checks this before acting, so a bare letter typed into a field\n * stays a letter.\n */\nexport function isEditableTarget(t: EventTarget | null | undefined): boolean {\n if (!(t instanceof Element)) return false;\n if (t instanceof HTMLInputElement || t instanceof HTMLTextAreaElement || t instanceof HTMLSelectElement) return true;\n if (t instanceof HTMLElement && t.isContentEditable === true) return true;\n const attr = t.getAttribute(\"contenteditable\");\n return attr !== null && attr !== \"false\";\n}\n\n/** A count for reading: grouping separators in the user's locale. */\nexport function formatCount(n: number): string {\n return n.toLocaleString();\n}\n\nconst copyTimers = new WeakMap<Element, ReturnType<typeof setTimeout>>();\n\n/**\n * Copy `text` to the clipboard and light `el` with `.copied` for `ms` (the\n * family's 1000). A second click restarts the timer rather than stacking a\n * second revert under the first. Resolves when the clipboard write has.\n */\nexport function copyWithFeedback(el: Element, text: string, ms = 1000): Promise<void> {\n const write = typeof navigator !== \"undefined\" && navigator.clipboard\n ? navigator.clipboard.writeText(text).catch(() => {})\n : Promise.resolve();\n el.classList.add(\"copied\");\n const prior = copyTimers.get(el);\n if (prior !== undefined) clearTimeout(prior);\n copyTimers.set(el, setTimeout(() => { el.classList.remove(\"copied\"); copyTimers.delete(el); }, ms));\n return write;\n}\n\n/**\n * How long ago, in one wording: \"just now\", \"4 minutes ago\", \"an hour ago\",\n * \"3 hours ago\", \"yesterday\", \"5 days ago\", and past a week the date itself.\n * Coarse on purpose: the question a reader has is whether the thing is from\n * this sitting, not how many seconds ago it was. A future date is \"just now\".\n */\nexport function relativeTime(date: Date | number | string, now: number = Date.now()): string {\n const then = date instanceof Date ? date.getTime() : new Date(date).getTime();\n if (!Number.isFinite(then)) return \"\";\n const mins = Math.floor((now - then) / 60000);\n if (mins < 1) return \"just now\";\n if (mins < 60) return `${plural(mins, \"minute\")} ago`;\n const hours = Math.floor(mins / 60);\n if (hours === 1) return \"an hour ago\";\n if (hours < 24) return `${hours} hours ago`;\n const days = Math.floor(hours / 24);\n if (days === 1) return \"yesterday\";\n if (days < 7) return `${days} days ago`;\n return new Date(then).toLocaleDateString(undefined, { day: \"numeric\", month: \"short\", year: \"numeric\" });\n}\n","// ---------------------------------------------------------------------------\n// The tool-window kit, RENDERER half: the always-on-top pin button every\n// helper window carries (previously pasted verbatim in five places across\n// the two apps). The matching chrome CSS - .swin-head drag bar, .swin-pin,\n// .swin-close - ships as tool-window.css.\n//\n// The head bar (toolWindowHead) and the follow toggle (followButton) live here\n// too since 0.39. The frameless drag bar itself needs no JS at all: it is markup + the\n// -webkit-app-region rules in tool-window.css.\n// ---------------------------------------------------------------------------\n\nimport { el } from \"./dom.js\";\nimport { iconNode } from \"./icons.js\";\nimport { isEditableTarget } from \"./util.js\";\n\nexport interface PinButtonOptions {\n pinned: boolean;\n /** Persist the choice. The button reflects the click itself. */\n onToggle: (on: boolean) => void;\n}\n\n/** A pin and the handle to drive it, the same shape `saveIndicator` returns. */\nexport interface PinButton {\n el: HTMLButtonElement;\n /**\n * Reflect a pin state decided ELSEWHERE, without calling `onToggle`.\n *\n * The state is not always the button's to choose: main re-pins a helper window\n * on Reset View, and the window is told after the fact. Before this existed a\n * host had to reach in and set the class, the aria and the title by hand,\n * which is three chances to disagree with the button about what it is showing.\n */\n set: (pinned: boolean) => void;\n}\n\n/** The always-on-top pin: `.swin-pin`, aria-pressed, and a tooltip that says\n * what a click will do (the richest of the family's variants, kept). */\nexport function pinButton(opts: PinButtonOptions): PinButton {\n const b = el(\"button\", \"swin-pin\");\n b.type = \"button\";\n // The vocabulary's pin (it used to be a hand-drawn copy of the same shape,\n // pasted in five places across the two apps before it came here).\n b.append(iconNode(\"pin\"));\n let pinned = opts.pinned;\n const reflect = (): void => {\n b.classList.toggle(\"on\", pinned);\n b.setAttribute(\"aria-pressed\", String(pinned));\n // The THEMED rollover, not the platform's. 0.21.0 swept `title` out of this\n // package and missed this one, so every helper window in the family had a\n // single control waiting on the OS delay and then drawing the OS bubble,\n // sitting beside controls that did not. `title` was also the button's only\n // accessible name (the glyph is an aria-hidden SVG), so the label has to go\n // to `aria-label` as it moves, or dropping `title` would take the name too.\n const label = pinned ? \"Pinned on top. Click to unpin.\" : \"Keep on top\";\n b.dataset[\"tip\"] = label;\n b.setAttribute(\"aria-label\", label);\n };\n reflect();\n b.addEventListener(\"click\", () => { pinned = !pinned; reflect(); opts.onToggle(pinned); });\n return { el: b, set: (next: boolean) => { pinned = next; reflect(); } };\n}\n\n// --- the head ------------------------------------------------------------------\n\nexport interface ToolWindowHeadOptions {\n /** The window's own name. Constant: it says which window this is, so it must\n * not change as projects open and close. Omitted by a window whose mode\n * tabs stand where the title would be (Find): pass them as `tabs`. */\n title?: string;\n /** Mode tabs in the title's place (Find's bar: modes left, pin and close right). */\n tabs?: HTMLElement;\n /** A pin BUILT ALREADY, for a window that mounts its chrome once and drives\n * the button with `pin.set(on)` rather than rebuilding the bar. That is the\n * better shape (no re-entrancy question, survives a partial repaint), so the\n * helper takes either. */\n pin?: { el: HTMLElement };\n pinned?: boolean;\n onPin?: (on: boolean) => void;\n onClose: () => void;\n /** Between the title and the spacer: a subtitle, the project name. */\n lead?: (Node | string | null)[];\n /** Between the spacer and the pin: this window's own controls. */\n trail?: (Node | string | null)[];\n /** An extra class beside `swin-head`, for a window that styles its own bar. */\n className?: string;\n /**\n * Escape closes the window (default true): the family's rule, written once\n * here rather than per window.\n *\n * The listener stands aside on its own for a field's Escape (an input,\n * textarea, select or contenteditable target: clearing, cancelling an edit)\n * and for an Escape a deeper handler has already `preventDefault()`ed.\n * `\"always\"` drops the first of those: a window whose focus LIVES in a\n * field (Find, whose query box is where the typing is) still closes on\n * Escape from it. `false` turns the listener off for a window that owns\n * Escape entirely; it calls `onClose` itself when nothing smaller is left.\n */\n esc?: boolean | \"always\";\n /**\n * A window that layers Escape (a selection to clear, a pending outcome to\n * drop, a sweep that must not be closed out from under) says so here:\n * return true when the key was consumed and the window stays open, false\n * to let it close. Innermost first; the window is last.\n */\n onEscape?: () => boolean;\n}\n\ninterface EscSlot {\n onClose: () => void;\n onEscape?: (() => boolean) | undefined;\n fromFields: boolean;\n}\n\n/** The one Escape listener per window. The head may be rebuilt on every render\n * (a play surface does), so the listener is installed once and reads the\n * latest close through this slot. */\nlet escSlot: EscSlot | undefined;\nlet escWired = false;\nfunction wireEsc(): void {\n if (escWired) return;\n escWired = true;\n window.addEventListener(\"keydown\", (e) => {\n if (e.key !== \"Escape\" || !escSlot) return;\n // A deeper handler that claimed the key (a popover closing, a picker\n // dismissing) has said so already.\n if (e.defaultPrevented) return;\n // A field's own Escape (clearing, cancelling an edit) comes first, unless\n // the window asked to close from its fields too.\n if (!escSlot.fromFields && isEditableTarget(e.target)) return;\n // The window's own layers, innermost first; true means one of them took it.\n if (escSlot.onEscape?.() === true) return;\n escSlot.onClose();\n });\n}\n\n/** The `.swin-head` bar every tool window wears: title (or tabs), lead, spacer,\n * trail, pin, close. The close button says \"Close (Esc)\" once, here, rather\n * than in every window. */\nexport function toolWindowHead(opts: ToolWindowHeadOptions): HTMLElement {\n const keep = (parts: (Node | string | null)[] | undefined): (Node | string)[] =>\n (parts ?? []).filter((p): p is Node | string => p !== null);\n const pin = opts.pin\n ?? pinButton({ pinned: opts.pinned ?? true, onToggle: opts.onPin ?? (() => {}) });\n if (opts.esc !== false) {\n escSlot = { onClose: opts.onClose, onEscape: opts.onEscape, fromFields: opts.esc === \"always\" };\n wireEsc();\n }\n return el(\"header\", { className: `swin-head${opts.className ? ` ${opts.className}` : \"\"}` },\n ...(opts.title !== undefined ? [el(\"span\", { className: \"swin-title\", text: opts.title })] : []),\n ...(opts.tabs ? [opts.tabs] : []),\n ...keep(opts.lead),\n el(\"span\", { className: \"swin-spacer\" }),\n ...keep(opts.trail),\n pin.el,\n el(\"button\", { className: \"swin-close\", tip: \"Close (Esc)\", onClick: opts.onClose }, iconNode(\"close\")),\n );\n}\n\n// --- follow in the editor -------------------------------------------------------\n\nexport interface FollowButtonOptions {\n on: boolean;\n /** Persist the choice. The button reflects the click itself. */\n onToggle: (on: boolean) => void;\n /** What the editor opens as the run goes: \"line\" (Patterpad), \"card\"\n * (Storyletter). Default \"line\". */\n what?: string;\n}\n\n/** A toggle and the handle to drive it, the same shape `pinButton` returns. */\nexport interface FollowButton {\n el: HTMLButtonElement;\n /** Reflect a state decided elsewhere, without calling `onToggle`. */\n set: (on: boolean) => void;\n}\n\n/**\n * \"Follow in the editor\": the play surface's toggle that makes the EDITOR\n * follow the run, opening each line / card as it plays. Both play surfaces\n * built one (patterpad play.ts, studio table.ts) with the same label and\n * paraphrased tips; this is the one wording.\n *\n * The LABEL is the careful part. \"Follow\" alone would match the vocabulary of\n * a window that follows the editor; this is the other direction, the editor\n * following the run. Off by default and remembered by the host: following is\n * the author asking for it.\n */\nexport function followButton(opts: FollowButtonOptions): FollowButton {\n const what = opts.what ?? \"line\";\n const b = el(\"button\", \"btn swin-follow\", \"Follow in the editor\");\n b.type = \"button\";\n let on = opts.on;\n const reflect = (): void => {\n b.classList.toggle(\"on\", on);\n b.setAttribute(\"aria-pressed\", String(on));\n const label = on\n ? `The editor opens each ${what} as it plays. Click to stop.`\n : `Open each ${what} in the editor as it plays`;\n b.dataset[\"tip\"] = label;\n };\n reflect();\n b.addEventListener(\"click\", () => { on = !on; reflect(); opts.onToggle(on); });\n return { el: b, set: (next: boolean) => { on = next; reflect(); } };\n}\n","// ---------------------------------------------------------------------------\n// The exit half of the panel motion vocabulary.\n//\n// Enters are pure CSS: they run on insertion. Exits cannot be, because the node\n// has to OUTLIVE the close for the animation to play and then be torn down. So\n// every closing surface routes its teardown through here instead of removing\n// itself directly.\n//\n// Patterpad's `closeWithExit`, lifted. It was already app-agnostic, and the\n// shell had grown a second copy of the same twelve lines inside `confirm.ts`,\n// which is the drift this package exists to stop: one motion vocabulary, drawn\n// one way. `tokens.css` already carried the keyframes and the durations; this\n// is the missing half that plays them.\n// ---------------------------------------------------------------------------\n\n/**\n * Play the close animation on `element`, then run `done` exactly once.\n *\n * `done` does the real teardown: remove the node, drop listeners, unmount\n * whatever was inside it. Under `prefers-reduced-motion` the duration reads 0\n * and `done` runs synchronously, so reduced motion means instant rather than\n * an invisible wait.\n */\nexport function closeWithExit(element: HTMLElement, done: () => void): void {\n element.classList.add(\"closing\");\n // getComputedStyle flushes pending style, so this reflects the `.closing`\n // rule we just added rather than the state before it.\n const seconds = parseFloat(getComputedStyle(element).animationDuration) || 0;\n if (seconds === 0) { done(); return; }\n\n let fired = false;\n const finish = (): void => {\n if (fired) return;\n fired = true;\n element.removeEventListener(\"animationend\", onEnd);\n clearTimeout(timer);\n done();\n };\n // Only OUR animation ending counts. Content inside the panel (rows, pills,\n // spinners) raises its own animationend, and an inner one firing first would\n // tear the panel down mid-fade.\n const onEnd = (e: AnimationEvent): void => { if (e.target === element) finish(); };\n element.addEventListener(\"animationend\", onEnd);\n // Fallback: animationend is missed if the element is hidden or the animation\n // is interrupted, and a panel that never tears down is worse than an abrupt one.\n const timer = setTimeout(finish, seconds * 1000 + 120);\n}\n","// ---------------------------------------------------------------------------\n// dialogFrame: the one modal skeleton every dialog in the family sits on.\n//\n// Title, an optional sub line, a body the caller fills, an actions row the\n// caller fills, on a native <dialog> so the focus trap and Escape come from the\n// platform. Four scrims and three panel drawings had grown across five shell\n// files and a dozen app dialogs (ui-review-2026-09, findings 9 and 30); this is\n// the frame they all sit on now, and the shell's own dialogs (confirm, identity,\n// about, notes) were moved onto it first, which is how it is proven.\n//\n// What the frame owns: the backdrop, the panel, the enter and exit motion\n// (closeWithExit), Escape, and giving focus back to whatever had it when the\n// dialog opened. What it does not own: the content classes, the buttons'\n// meaning, and when to close. The caller keeps those.\n//\n// Styles ship as dialog.css. The action buttons are expected to wear `.btn`\n// from controls.css; the frame does not draw buttons of its own.\n// ---------------------------------------------------------------------------\n\nimport { el } from \"./dom.js\";\nimport { closeWithExit } from \"./exit.js\";\n\nexport interface DialogFrameOptions {\n /** The heading. Also the dialog's accessible name. */\n title: string;\n /** One plain sentence under the heading, if the title needs one. */\n sub?: string;\n /** Extra class(es) on the <dialog>, for the caller's own content rules and\n * width (`--dialog-width` on the class; see dialog.css). */\n className?: string;\n /** Runs once, after the dialog has left the document, however it closed. */\n onClose?: () => void;\n}\n\nexport interface DialogFrame {\n readonly dialog: HTMLDialogElement;\n /** Fill this with the content. */\n readonly body: HTMLElement;\n /** Fill this with the buttons, right-aligned; empty, it draws nothing. */\n readonly actions: HTMLElement;\n /** Show modally. Records what had focus so `close()` can give it back. */\n open(): void;\n /** Play the exit, tear down, restore focus. Idempotent. */\n close(): void;\n isOpen(): boolean;\n}\n\n/** Build a dialog on the family's frame. Appended to <body> at once (so an\n * `open()` on the next line has nothing to wait for); shown only on `open()`. */\nexport function dialogFrame(opts: DialogFrameOptions): DialogFrame {\n const dialog = el(\"dialog\", `shell-dialog ${opts.className ?? \"\"}`.trim());\n const body = el(\"div\", \"shell-dialog-body\");\n const actions = el(\"div\", \"shell-dialog-actions\");\n dialog.append(el(\"h2\", \"shell-dialog-title\", opts.title));\n if (opts.sub !== undefined) dialog.append(el(\"p\", \"shell-dialog-sub\", opts.sub));\n dialog.append(body, actions);\n dialog.setAttribute(\"aria-label\", opts.title);\n document.body.append(dialog);\n\n let state: \"closed\" | \"open\" | \"closing\" = \"closed\";\n let opener: Element | null = null;\n\n const teardown = (): void => {\n dialog.remove();\n // Back to the control that opened this. The platform does it for a plain\n // dialog.close(), but the exit motion ends in a remove(), and a removed\n // dialog restores nothing.\n if (opener instanceof HTMLElement && opener.isConnected) opener.focus();\n opener = null;\n state = \"closed\";\n opts.onClose?.();\n };\n\n const close = (): void => {\n if (state !== \"open\") return;\n state = \"closing\";\n closeWithExit(dialog, () => { if (dialog.open) dialog.close(); teardown(); });\n };\n\n // Escape arrives as the cancel event; route it through the exit motion.\n dialog.addEventListener(\"cancel\", (e) => { e.preventDefault(); close(); });\n // Closed by someone else (a form with method=\"dialog\", or a direct\n // dialog.close()): no motion to play, tear down at once.\n dialog.addEventListener(\"close\", () => { if (state === \"open\") teardown(); });\n\n return {\n dialog, body, actions,\n open() {\n if (state !== \"closed\") return;\n opener = document.activeElement;\n state = \"open\";\n dialog.showModal();\n },\n close,\n isOpen: () => state === \"open\",\n };\n}\n","// ---------------------------------------------------------------------------\n// A themed in-app confirmation modal (design-language \"coherent to the\n// edges\": never a stock OS dialog). The promise API is Patterpad's surface\n// confirm; the build sits on the family's dialog frame (dialog.ts), so the\n// focus trap, Esc, the scrim and the exit motion are the frame's. Two\n// deliberate corrections over that original, kept when Patterpad migrates\n// here: the destructive button wears --danger (a required host token; the\n// surface one mistakenly used --accent), and initial focus lands on Cancel so\n// a stray Enter cannot destroy anything.\n//\n// Styles: dialog.css + controls.css for the frame and the buttons, confirm.css\n// for what is confirm's own (its width, its body copy). Callers keep the\n// elide-the-dialog rule: when nothing is at stake, don't ask.\n// ---------------------------------------------------------------------------\n\nimport { el } from \"./dom.js\";\nimport { dialogFrame } from \"./dialog.js\";\n\nexport interface ConfirmOptions {\n title: string;\n /** One plain sentence, ending with what undo does. */\n body?: string;\n /**\n * Content that is evidence rather than a sentence: a list of the scenes that\n * refer to the thing, a warning line. Rendered after `body` when both are\n * given. The caller styles it; the frame's body is a column with a gap.\n */\n bodyNode?: HTMLElement;\n /** The destructive button's label, which names its object (\"Delete scene\",\n * \"Remove language\"). */\n confirmLabel: string;\n}\n\n/** Resolves true on confirm; false on Cancel / Esc / backdrop. */\nexport function confirmDialog(opts: ConfirmOptions): Promise<boolean> {\n return new Promise((resolve) => {\n let done = false;\n // Resolve on the gesture, not after the exit motion: the caller acts on the\n // answer at once, and the fade plays over whatever it does.\n const finish = (ok: boolean): void => {\n if (done) return;\n done = true;\n resolve(ok);\n frame.close();\n };\n const frame = dialogFrame({\n title: opts.title, className: \"confirm-dialog\",\n onClose: () => finish(false), // Esc, or closed by someone else\n });\n const cancel = el(\"button\", \"btn confirm-btn cancel\", \"Cancel\");\n const danger = el(\"button\", \"btn danger confirm-btn\", opts.confirmLabel);\n cancel.type = \"button\";\n danger.type = \"button\";\n if (opts.body !== undefined) frame.body.append(el(\"div\", \"confirm-body\", opts.body));\n if (opts.bodyNode) frame.body.append(opts.bodyNode);\n frame.actions.append(cancel, danger);\n\n cancel.addEventListener(\"click\", () => finish(false));\n danger.addEventListener(\"click\", () => finish(true));\n // Esc arrives as the dialog's cancel event; the frame routes it through the\n // exit motion and onClose. A mousedown that lands on the dialog element\n // itself is the backdrop.\n frame.dialog.addEventListener(\"mousedown\", (e) => { if (e.target === frame.dialog) finish(false); });\n\n frame.open();\n cancel.focus();\n });\n}\n","// ---------------------------------------------------------------------------\n// The floating-layer lifecycle every popup and menu shares: a body-appended\n// element, display toggling, a scroll / resize follower that keeps it glued to\n// its anchor, a click-away dismiss, and the family's exit motion on close.\n//\n// Patterpad's surface had it (four popups: the cue picker, the slash menu, the\n// action menu, the jump picker) and Storyletter's context menu had the same\n// idea in eleven lines without the follower (ui-review-2026-09, finding 5).\n// This is the surface's, lifted whole. Positioning stays the caller's, because\n// it differs per popup: pass a `reposition` closure to `show()` and the\n// follower re-runs it on scroll and resize until `close()`.\n//\n// The element is REUSED across opens (a popup that re-renders on every\n// keystroke must not tear itself down each time), which is why a stale exit\n// teardown has a token to lose against a reopen.\n// ---------------------------------------------------------------------------\n\nimport { closeWithExit } from \"./exit.js\";\n\nexport interface Floating {\n /** The floating element. Build content into it; it is appended to <body>\n * (or the `host` given), hidden until `show()`. */\n readonly el: HTMLElement;\n /** Show `el` and keep `reposition` glued to the anchor on scroll / resize.\n * Safe to call repeatedly (on every re-render): the follower attaches once. */\n show(reposition: () => void): void;\n /** While open, call `onOutside` on a pointer-down outside `el`, and outside\n * anything `isInside` accepts (a second flyout, the anchor button).\n * Idempotent: arms once. */\n dismissOnOutside(onOutside: () => void, isInside?: (target: Node) => boolean): void;\n /** Play the exit, then hide `el`, clear its children, and drop the follower\n * and any outside listener. */\n close(): void;\n isOpen(): boolean;\n}\n\n/** Re-run `reposition` on any scroll or resize until the returned disposer runs. */\nfunction followOnScroll(reposition: () => void): () => void {\n const onMove = (): void => reposition();\n window.addEventListener(\"scroll\", onMove, true);\n window.addEventListener(\"resize\", onMove);\n return () => { window.removeEventListener(\"scroll\", onMove, true); window.removeEventListener(\"resize\", onMove); };\n}\n\nexport interface FloatingOptions {\n /** Where the element is appended. Default <body>. Under a modal <dialog> a\n * body-level node sits behind the scrim, inert, so a popup opened from\n * inside one passes the dialog here and paints in its top layer. */\n host?: HTMLElement;\n}\n\nexport function createFloating(className: string, opts: FloatingOptions = {}): Floating {\n const el = document.createElement(\"div\"); el.className = className; el.style.display = \"none\";\n (opts.host ?? document.body).appendChild(el);\n let open = false;\n let detach: (() => void) | null = null;\n let outside: ((e: MouseEvent) => void) | null = null;\n let closeToken = 0; // bumped on every show / close so a stale exit teardown cannot clobber a reopen\n\n const close = (): void => {\n if (!open) return;\n open = false;\n detach?.(); detach = null; // stop following + dismissing immediately; it is on its way out\n if (outside) { document.removeEventListener(\"mousedown\", outside, true); outside = null; }\n const myToken = ++closeToken;\n // Play the exit, THEN hide + clear. A reopen during the fade must win:\n // show() bumps closeToken, and this guard abandons the stale teardown.\n closeWithExit(el, () => {\n if (myToken !== closeToken) return;\n el.style.display = \"none\"; el.replaceChildren(); el.classList.remove(\"closing\");\n });\n };\n\n const show = (reposition: () => void): void => {\n closeToken++; el.classList.remove(\"closing\"); // cancel any in-flight exit, undo its class\n open = true; el.style.display = \"block\"; reposition();\n detach ??= followOnScroll(reposition);\n };\n\n const dismissOnOutside = (onOutside: () => void, isInside?: (target: Node) => boolean): void => {\n if (outside) return; // already armed\n outside = (e: MouseEvent): void => {\n const t = e.target as Node;\n if (!el.contains(t) && !(isInside?.(t) ?? false)) onOutside();\n };\n document.addEventListener(\"mousedown\", outside, true);\n };\n\n return { el, show, dismissOnOutside, close, isOpen: () => open };\n}\n","// ---------------------------------------------------------------------------\n// A right-click context menu and a small anchored popover: a floating list of\n// actions at the cursor (or a panel under a control), dismissed on outside\n// click or Escape, clamped to the viewport, closed with the family's exit\n// motion.\n//\n// Storyletter's, lifted (ui-review-2026-09, finding 11): its own header had\n// named itself an extraction candidate, and it had the two things Patterpad's\n// inline `sceneContextMenu` lacked, a `disabled` item and the clamp. A DOM\n// popover, not a native menu, so it is themed like everything else.\n//\n// Styles ship as context-menu.css; import it wherever the module is used,\n// including tool windows, which is the bug that made Storyletter give the\n// menu its own stylesheet in the first place.\n// ---------------------------------------------------------------------------\n\nimport { el } from \"./dom.js\";\nimport { closeWithExit } from \"./exit.js\";\n\nexport interface ContextItem {\n label: string;\n /** Drawn in --danger: a destructive action, which names its object. */\n danger?: boolean;\n /** Shown greyed and unclickable. For an action that belongs on this menu\n * but cannot apply right now (Move up on the first row), so the menu keeps\n * the same shape and the same item stays in the same place every time. */\n disabled?: boolean;\n onClick: () => void;\n}\n\nconst EDGE = 6;\n\n/** The one open menu or popover. Only ever one, so a fresh open replaces it\n * and a re-render that removed the anchor cannot leave one hanging in the air. */\nlet current: (() => void) | null = null;\n\n/** Outside-click / Escape wiring shared by the menu and the popover. The\n * returned `dismiss` plays the exit and removes the node; `onDismiss` fires\n * for every way out so a caller can flush on all of them. */\nfunction floating(node: HTMLElement, onDismiss?: () => void): { dismiss: () => void } {\n let gone = false;\n const dismiss = (): void => {\n if (gone) return;\n gone = true;\n if (current === dismiss) current = null;\n window.removeEventListener(\"pointerdown\", onAway, true);\n window.removeEventListener(\"keydown\", onKey, true);\n // A node mid-fade must not take a second click.\n closeWithExit(node, () => node.remove());\n onDismiss?.();\n };\n const onAway = (e: PointerEvent): void => { if (!node.contains(e.target as Node)) dismiss(); };\n const onKey = (e: KeyboardEvent): void => { if (e.key === \"Escape\") { e.preventDefault(); dismiss(); } };\n window.addEventListener(\"pointerdown\", onAway, true);\n window.addEventListener(\"keydown\", onKey, true);\n current?.();\n current = dismiss;\n return { dismiss };\n}\n\n/** Clamp a floating node into the viewport, preferring below `anchor` and\n * flipping above it when there is no room. */\nfunction placeBelow(node: HTMLElement, anchor: DOMRect): void {\n node.style.left = `${anchor.left}px`;\n node.style.top = `${anchor.bottom + 4}px`;\n const r = node.getBoundingClientRect();\n if (r.right > window.innerWidth) node.style.left = `${Math.max(EDGE, window.innerWidth - r.width - EDGE)}px`;\n if (r.bottom > window.innerHeight) node.style.top = `${Math.max(EDGE, anchor.top - r.height - 4)}px`;\n}\n\nexport interface PopoverOptions {\n /** Where the popover is appended. Default <body>. A popover opened from\n * inside a modal <dialog> passes the dialog: a body-level node sits behind\n * the scrim, inert, while one inside the dialog paints in its top layer\n * (Patterpad's colour swatch popover in Project settings). */\n host?: HTMLElement;\n}\n\n/** Open a small panel anchored to an element; `build` gets a close callback.\n * `onClose` runs however it closes (Escape, outside click, or `close`), the\n * place to flush an edit the panel was collecting. Only one is ever open. */\nexport function openPopover(\n anchor: HTMLElement, build: (close: () => void) => HTMLElement, onClose?: () => void, opts: PopoverOptions = {},\n): void {\n const pop = el(\"div\", \"popover\");\n let closed = false;\n const finish = (): void => { if (closed) return; closed = true; onClose?.(); };\n const { dismiss } = floating(pop, finish);\n pop.append(build(dismiss));\n (opts.host ?? document.body).append(pop);\n placeBelow(pop, anchor.getBoundingClientRect());\n}\n\n/** Open a context menu at (x, y). Only one is ever open. */\nexport function openContextMenu(x: number, y: number, items: ContextItem[]): void {\n const menu = el(\"div\", \"ctxmenu\");\n menu.setAttribute(\"role\", \"menu\");\n const { dismiss } = floating(menu);\n\n for (const item of items) {\n const button = el(\"button\", {\n className: `ctxmenu-item${item.danger ? \" danger\" : \"\"}`, text: item.label,\n onClick: () => { if (item.disabled === true) return; dismiss(); item.onClick(); },\n });\n button.type = \"button\";\n button.setAttribute(\"role\", \"menuitem\");\n if (item.disabled === true) button.disabled = true;\n menu.append(button);\n }\n\n menu.style.left = `${x}px`;\n menu.style.top = `${y}px`;\n document.body.append(menu);\n // Keep it on-screen.\n const r = menu.getBoundingClientRect();\n if (r.right > window.innerWidth) menu.style.left = `${Math.max(EDGE, window.innerWidth - r.width - EDGE)}px`;\n if (r.bottom > window.innerHeight) menu.style.top = `${Math.max(EDGE, window.innerHeight - r.height - EDGE)}px`;\n}\n","// ---------------------------------------------------------------------------\n// The About surface: every app in the family has one, and it should never be\n// the grey OS panel (design-language, \"coherent to the edges\").\n//\n// Patterpad's, generalised. Theirs reuses its updater-dialog chrome and hard\n// codes the PatterKit wordmark; the shell takes the wordmark as markup from the\n// app, because that is the one part that is genuinely per-product. Everything\n// else - the layout, the type, the link handling, the single Close - is the\n// family's, so two apps' About boxes are recognisably siblings.\n//\n// The host opens links, because a renderer cannot: `onOpenLink` goes through\n// the app's own IPC to `shell.openExternal`. Without it the links are shown as\n// plain text rather than as buttons that do nothing.\n// ---------------------------------------------------------------------------\n\nimport { el } from \"./dom.js\";\nimport { dialogFrame } from \"./dialog.js\";\n\nexport interface AboutOptions {\n /** The product's name, large. */\n appName: string;\n /** \"1.4.2\" - shown as \"Version 1.4.2\". */\n version: string;\n /** One or two sentences: what this app is for. */\n blurb?: string;\n /** Licence, authorship, the suite it belongs to. Newlines are respected. */\n credits?: string;\n links?: { label: string; url: string }[];\n /** Inline SVG for the product wordmark, if it has one. */\n wordmark?: string;\n /** Open a URL in the real browser. Omit and the links render as text. */\n onOpenLink?: (url: string) => void;\n}\n\n/** Show the About dialog. Resolves when it closes. */\nexport function showAbout(opts: AboutOptions): Promise<void> {\n return new Promise((resolve) => {\n // On the family's frame: the product name is the frame's title, centred by\n // about.css, and the wordmark sits above it.\n const frame = dialogFrame({ title: opts.appName, className: \"shell-about\", onClose: () => resolve() });\n frame.dialog.setAttribute(\"aria-label\", `About ${opts.appName}`);\n if (opts.wordmark !== undefined) {\n const mark = el(\"div\", \"shell-about-mark\");\n mark.innerHTML = opts.wordmark;\n frame.dialog.prepend(mark);\n }\n frame.body.append(el(\"div\", \"shell-about-version\", `Version ${opts.version}`));\n if (opts.blurb !== undefined) frame.body.append(el(\"p\", \"shell-about-blurb\", opts.blurb));\n if (opts.credits !== undefined) frame.body.append(el(\"p\", \"shell-about-credits\", opts.credits));\n\n if (opts.links?.length) {\n const row = el(\"div\", \"shell-about-links\");\n for (const link of opts.links) {\n if (!opts.onOpenLink) { row.append(el(\"span\", \"shell-about-link\", link.label)); continue; }\n const a = el(\"button\", \"shell-about-link\", link.label);\n a.type = \"button\";\n a.addEventListener(\"click\", () => opts.onOpenLink?.(link.url));\n row.append(a);\n }\n frame.body.append(row);\n }\n\n const close = el(\"button\", \"btn shell-about-close\", \"Close\");\n close.type = \"button\";\n close.addEventListener(\"click\", () => frame.close());\n frame.actions.append(close);\n frame.open();\n close.focus();\n });\n}\n","// ---------------------------------------------------------------------------\n// A floating panel anchored to the thing it is about: Patterpad's\n// `openAnchoredPanel`, lifted and generalised.\n//\n// Patterpad's condition, effects, jump and gameId editors all use one, and so do\n// Storyletter's comment threads. Two implementations of one idea existed for\n// about a day, which is exactly the drift the shell is for - and Patterpad's was\n// the mature one, so this is that, not the one written second.\n//\n// The behaviours are all learnt from use, and each is a bug somebody hit:\n//\n// - Re-clicking the SAME anchor toggles the panel off and returns null,\n// rather than closing and reopening with a flicker. Callers must handle the\n// null.\n// - A DIFFERENT anchor swaps rather than stacking: only one is ever open.\n// - The outside-click listener is armed a tick late, or the very click that\n// opened the panel would close it again.\n// - `ignoreDown` spares body-level inner popovers, which are outside the\n// panel in the DOM but inside it as far as the author is concerned.\n// - `deferEscape` leaves Escape to an inner popover when one is open, so one\n// key does not close two things.\n//\n// Placement is the part worth reading. It flips to whichever side of the anchor\n// has MORE room, keeps clear of any bottom bars the app names, caps at 70% of\n// the window and scrolls its body. A panel that opens cramped against a status\n// bar with empty space above it is the failure this avoids.\n// ---------------------------------------------------------------------------\n\nimport { el } from \"./dom.js\";\nimport { iconNode } from \"./icons.js\";\nimport { closeWithExit } from \"./exit.js\";\n\nexport interface AnchoredPanel {\n panel: HTMLElement;\n /** The content area to populate: the header is built for you. */\n body: HTMLElement;\n /** Idempotent; fires the caller's `onClose` exactly once. */\n close: () => void;\n}\n\nexport interface AnchoredPanelOptions {\n anchor: HTMLElement;\n /** Extra class(es) on the panel, for app-specific sizing or colour. */\n className?: string;\n title: string;\n width: number;\n /**\n * Which side to try first.\n *\n * `\"left\"` suits a panel hung off a row in a right-hand pane (Patterpad's\n * inspector); `\"below\"` suits one hung off a button in a document's header\n * (Storyletter's topline). Either way it flips when the room is not there.\n */\n prefer?: \"left\" | \"below\" | \"centre\";\n /** Selectors for chrome the panel must not cover - a problems bar, a review\n * bar - so those stay usable while it is open. */\n keepClear?: string[];\n /** A pointerdown inside something matching this does NOT close the panel. */\n ignoreDown?: string;\n /** While something matching this exists, Escape belongs to it, not to us. */\n deferEscape?: string;\n /** Where the panel is appended. Default <body>. A panel opened from inside a\n * modal <dialog> passes the dialog: a body-level node sits behind the scrim,\n * inert, while one inside the dialog paints in its top layer. Placement is\n * viewport-relative either way (`position: fixed`). */\n host?: HTMLElement;\n onClose?: () => void;\n}\n\n/** The one open panel. Only ever one, which is what makes toggling meaningful. */\nlet current: { anchor: HTMLElement; panel: HTMLElement; close: () => void } | null = null;\n\nexport function openAnchoredPanel(opts: AnchoredPanelOptions): AnchoredPanel | null {\n if (current) {\n const prev = current;\n current = null;\n prev.close();\n if (prev.anchor === opts.anchor) return null; // a toggle, not a reopen\n }\n\n const panel = el(\"div\", `shell-anchored ${opts.className ?? \"\"}`.trim());\n const closeBtn = el(\"button\", \"shell-anchored-close\", iconNode(\"close\", 12));\n closeBtn.type = \"button\";\n closeBtn.setAttribute(\"aria-label\", \"Close\");\n const body = el(\"div\", \"shell-anchored-body\");\n panel.append(\n el(\"div\", \"shell-anchored-head\", el(\"span\", \"shell-anchored-title\", opts.title), closeBtn),\n body,\n );\n (opts.host ?? document.body).append(panel);\n placeAnchored(panel, opts.anchor, opts.width, opts.prefer ?? \"below\", opts.keepClear ?? []);\n\n let closed = false;\n const close = (): void => {\n if (closed) return;\n closed = true;\n if (current?.panel === panel) current = null;\n document.removeEventListener(\"pointerdown\", onDown, true);\n document.removeEventListener(\"keydown\", onKey, true);\n // Play the exit, THEN tear down. The order matters: `onClose` is where a\n // caller unmounts whatever it put in the body, so running it first would\n // leave an empty panel fading out. Listeners come off above rather than\n // here, because a panel mid-fade must not still be taking clicks.\n closeWithExit(panel, () => { opts.onClose?.(); panel.remove(); });\n };\n closeBtn.addEventListener(\"click\", close);\n\n const onDown = (e: PointerEvent): void => {\n const target = e.target as Node;\n if (panel.contains(target) || opts.anchor.contains(target)) return;\n if (opts.ignoreDown !== undefined && target instanceof Element && target.closest(opts.ignoreDown)) return;\n close();\n };\n const onKey = (e: KeyboardEvent): void => {\n if (e.key !== \"Escape\") return;\n if (opts.deferEscape !== undefined && document.querySelector(opts.deferEscape)) return;\n close();\n };\n // Next tick: the click that opened this is still travelling.\n setTimeout(() => {\n document.addEventListener(\"pointerdown\", onDown, true);\n document.addEventListener(\"keydown\", onKey, true);\n }, 0);\n\n current = { anchor: opts.anchor, panel, close };\n return { panel, body, close };\n}\n\n/** Close whatever is open. For a navigation or a re-render: a panel anchored to\n * an element that no longer exists would hang in the air. */\nexport function closeAnchoredPanel(): void {\n const open = current;\n current = null;\n open?.close();\n}\n\n/** Patterpad's placement, with the side as a parameter. */\nexport function placeAnchored(\n panel: HTMLElement, anchor: HTMLElement, width: number,\n prefer: \"left\" | \"below\" | \"centre\", keepClear: string[],\n): void {\n const a = anchor.getBoundingClientRect();\n const GAP = 10;\n const CAP = window.innerHeight * 0.7;\n const MIN_H = 140;\n panel.style.width = `${width}px`;\n\n // \"centre\" is for an anchor that is a POINT rather than a control: a zero-size\n // proxy dropped where somebody clicked on a canvas. Aligning a panel's edge to\n // a point puts the whole panel up and to one side of the spot the person just\n // chose, which reads as the panel having appeared somewhere else. Centred on\n // the point, it appears where they pointed.\n if (prefer === \"centre\") {\n const centred = a.left + a.width / 2 - width / 2;\n panel.style.left = `${Math.round(Math.min(Math.max(8, centred), window.innerWidth - width - 8))}px`;\n } else {\n // Horizontally: left of the anchor when asked and there is room, otherwise\n // aligned to it and nudged back inside the window.\n const leftOf = a.left - width - GAP;\n const alignedRight = Math.min(a.right - width, window.innerWidth - width - 8);\n panel.style.left = `${Math.round(prefer === \"left\" && leftOf >= 8\n ? leftOf\n : Math.max(8, prefer === \"left\" ? a.left : alignedRight))}px`;\n }\n\n // Vertically: whichever side has more room, staying off the app's bottom bars.\n let bottomLimit = window.innerHeight - 8;\n for (const selector of keepClear) {\n const bar = document.querySelector(selector);\n if (!bar) continue;\n const r = bar.getBoundingClientRect();\n if (r.height > 0) bottomLimit = Math.min(bottomLimit, r.top - 6);\n }\n // Centred on a point vertically as well, for the same reason, but only while\n // the panel actually fits: past that it falls back to the more-room-wins rule\n // below rather than hanging off the top of the window.\n if (prefer === \"centre\") {\n const height = Math.min(CAP, Math.max(MIN_H, panel.offsetHeight));\n const mid = a.top + a.height / 2 - height / 2;\n if (mid >= 8 && mid + height <= bottomLimit) {\n panel.style.top = `${Math.round(mid)}px`;\n panel.style.bottom = \"auto\";\n panel.style.maxHeight = `${Math.round(CAP)}px`;\n return;\n }\n }\n const roomBelow = bottomLimit - (a.bottom + GAP);\n const roomAbove = (a.top - GAP) - 8;\n if (roomAbove > roomBelow) {\n panel.style.top = \"auto\";\n panel.style.bottom = `${Math.round(window.innerHeight - (a.top - GAP))}px`;\n panel.style.maxHeight = `${Math.round(Math.max(MIN_H, Math.min(CAP, roomAbove)))}px`;\n } else {\n panel.style.bottom = \"auto\";\n panel.style.top = `${Math.round(Math.max(8, a.bottom + GAP))}px`;\n panel.style.maxHeight = `${Math.round(Math.max(MIN_H, Math.min(CAP, roomBelow)))}px`;\n }\n}\n","// ---------------------------------------------------------------------------\n// Game IDs: the host-facing ADDRESS of a thing.\n//\n// This belongs to the shell because it follows from the SHAPE these apps share\n// rather than from any one subject: a project of data files that compiles to\n// artefacts for something else to consume. \"Something else consumes it\" is the\n// whole reason content needs a stable name a program can call it by. Nothing\n// here needs the words card, beat, hand or scene to describe.\n//\n// It arrived here as two byte-identical copies, in Storyletter's model and\n// Patterpad's, each with its own editor popover on top - and the two editors had\n// grown DIFFERENT manners for the same job, which is how the duplication was\n// noticed at all.\n//\n// DEPENDENCY-FREE on purpose. The apps' domain layers (compilers, CLIs, engine\n// runtimes) need these rules far from any UI, and they keep their own copies\n// rather than taking a dependency on a UI kit; each asserts parity with these in\n// a test, so the copies cannot drift in silence. A NEW app starts from these.\n// ---------------------------------------------------------------------------\n\n/**\n * Slugify a name into hyphen form: lower case, apostrophes dropped, runs of\n * anything else to a single hyphen, no leading or trailing hyphen.\n *\n * May return \"\", when there was nothing usable in the input. Callers treat that\n * as \"no pinned address\" rather than as an address.\n */\nexport function gameIdify(text: string): string {\n return text.toLowerCase().replace(/['’]/g, \"\")\n .replace(/[^a-z0-9-]+/g, \"-\").replace(/-+/g, \"-\").replace(/^-+|-+$/g, \"\");\n}\n\n/** Is this a legal address? Lower case, digits and hyphens, starting and ending\n * with a letter or a digit. Note \"\" is NOT legal: an empty pinned address means\n * \"derive one\", which is a different thing from an address. */\nexport function isValidGameId(gameId: string): boolean {\n return /^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/.test(gameId);\n}\n","// ---------------------------------------------------------------------------\n// Property names: what an author may call a value the story reads and writes.\n//\n// This belongs to the shell for the same reason gameIds do (see ids.ts): it\n// follows from the SHAPE these apps share - a project of data files, authored in\n// an editor, compiled for something else to run - rather than from any one\n// subject. Nothing here needs the words card, beat, hand or scene.\n//\n// UNLIKE gameIds, the rule is not a house style. It is dictated by the\n// expression language both families embed (`@wildwinter/expr`), and every clause\n// below is a failure observed by compiling one:\n//\n// parser.ts tokenises an identifier as /[a-zA-Z_][a-zA-Z0-9_]*/ and then\n// FOLDS it: `name: propTok.value.toLowerCase()`.\n//\n// @patter.is_night -> [\"sv\",\"patter\",\"is_night\"] reachable\n// @patter.isNight -> [\"sv\",\"patter\",\"isnight\"] folded: a declaration\n// spelled `isNight` is\n// one nothing can reach\n// @patter.is-night -> [\"bin\",\"-\",[\"sv\",\"patter\",\"is\"], NOT an error: it is\n// [\"s\",\"night\"]] SUBTRACTION. A hyphen\n// silently compiles to\n// a different meaning\n// @patter.is night -> parse error\n// @patter.9lives -> parse error (a name cannot start with a digit)\n// @patter.not -> parse error (`true false and or not` are keywords)\n//\n// The hyphen line is why this is worth a shared rule rather than a per-app\n// check: every other violation is loud, and that one quietly means something\n// else. It is also why a property name is NOT a gameId with different spelling -\n// a gameId is built out of hyphens, and here a hyphen is an operator.\n//\n// DEPENDENCY-FREE on purpose, ids.ts's reasoning verbatim: the apps' compilers,\n// CLIs and embedded runtimes need these rules far from any UI, so they keep\n// their own copies and assert parity with these in a test.\n// ---------------------------------------------------------------------------\n\n/** The five words `@wildwinter/expr` lexes as keywords, so a property may not be\n * called any of them: the reference does not resolve, it fails to parse. Kept\n * here as a copy for the same reason the rules are (no dependency), and each\n * app probes the real parser to prove the list is still true. */\nexport const RESERVED_PROPERTY_NAMES: readonly string[] = [\"true\", \"false\", \"and\", \"or\", \"not\"];\n\n/** What an editor should tell an author, in one line. */\nexport const PROPERTY_NAME_HINT =\n \"Lower case letters, digits, and underscores. It can't start with a digit. No hyphens or spaces.\";\n\n/**\n * Coerce a label into a legal property name: lower case, apostrophes dropped,\n * runs of anything else to a single underscore, no trailing underscore, an\n * underscore in front if it would otherwise start with a digit, and one behind\n * if it would otherwise be a keyword.\n *\n * A LEADING underscore is kept where the author typed one, because `_private` is\n * a legal name and a meaningful choice; only the ends that would be illegal are\n * touched.\n *\n * May return \"\", when there was nothing usable in the input. Callers treat that\n * as \"no name yet\" rather than as a name.\n */\nexport function propertyNameify(text: string): string {\n const trimmed = text.trim();\n // An underscore the author actually typed is kept; one that is only the ghost of\n // leading punctuation is not. That is the difference between `_private` and `!gold`.\n const deliberateLeading = trimmed.startsWith(\"_\");\n let out = trimmed.toLowerCase().replace(/['’]/g, \"\")\n .replace(/[^a-z0-9_]+/g, \"_\").replace(/_+/g, \"_\").replace(/^_+|_+$/g, \"\");\n if (out === \"\") return \"\";\n if (deliberateLeading || /^[0-9]/.test(out)) out = `_${out}`;\n if (RESERVED_PROPERTY_NAMES.includes(out)) out = `${out}_`;\n return out;\n}\n\n/**\n * Is this a name the expression language can actually reach? Lower case letters,\n * digits and underscores, not starting with a digit, and not a keyword.\n *\n * \"\" is NOT legal: an unnamed declaration is an unfinished row, which is a\n * different thing from an illegal one, and callers distinguish them.\n */\nexport function isValidPropertyName(name: string): boolean {\n return /^[a-z_][a-z0-9_]*$/.test(name) && !RESERVED_PROPERTY_NAMES.includes(name);\n}\n\n/**\n * The one thing that is only a case difference, e.g. `isNight` -> `isnight`.\n *\n * Worth its own question because it is the only violation that can be repaired\n * without guessing at intent: the language already folds every REFERENCE, so\n * folding the declaration to match changes nothing observable, where inventing\n * an underscore for a space is a decision about what the author meant. Loaders\n * fold this class silently and report the rest.\n */\nexport function isCaseOnlyPropertyName(name: string): boolean {\n return !isValidPropertyName(name) && isValidPropertyName(name.toLowerCase());\n}\n","// ---------------------------------------------------------------------------\n// The manners for a field that names a declared property.\n//\n// The RULE is property-names.ts, which is dependency-free because each app's\n// domain layer keeps its own copy of it. This is the other half: how a field\n// BEHAVES while somebody types a name into it, which only UI touches, so the\n// shell owns it outright.\n//\n// The manners are the gameId editor's, adopted rather than re-argued (see\n// id-editor.ts): an illegal name is marked and blocks Save, and Tab coerces it,\n// in the field, where it can be seen and undone. Nothing is rewritten as it is\n// typed. Patterpad's first pass at this folded every keystroke to lower case;\n// that is the manner the id editor had already rejected, on the grounds that an\n// app which silently renames a thing has made a decision that was not its to\n// make, and a property name is exactly that kind of thing: the author is naming\n// something their own conditions will call.\n//\n// It arrived here as two copies, one per app, written in one session and already\n// carrying the same forty lines of fault wording. Lifting them before they could\n// drift is the whole reason this file exists.\n// ---------------------------------------------------------------------------\n\nimport { isValidPropertyName, propertyNameify, RESERVED_PROPERTY_NAMES } from \"./property-names.js\";\n\n/** Re-check callbacks for bound REFERENCE fields, so a host can say \"the declarations\n * changed\" without holding a handle per row. */\nconst refSyncs = new WeakMap<HTMLInputElement, () => void>();\n\n/**\n * One line saying what is wrong with this name, or undefined when nothing is.\n *\n * Each branch names what actually HAPPENS rather than reciting the rule, because\n * the person reading it is usually somebody wondering why a condition does\n * nothing. Kept to one line: it lands in a rollover on the field, and hosts\n * repeat it in the Save error rather than inventing a summary of their own.\n */\nexport function propertyNameProblem(name: string): string | undefined {\n if (isValidPropertyName(name)) return undefined;\n const suggestion = propertyNameify(name);\n const tail = suggestion ? ` Try \"${suggestion}\", or press Tab.` : \"\";\n if (RESERVED_PROPERTY_NAMES.includes(name.toLowerCase())) {\n return `Can't be used. \"${name.toLowerCase()}\" is a keyword in expressions.${tail}`;\n }\n // The one that is not an error anywhere else: `@scope.a-b` compiles to a-minus-b.\n if (name.includes(\"-\")) return `Can't be used. A hyphen reads as subtraction in an expression.${tail}`;\n if (/^[0-9]/.test(name)) return `Can't be used. A name can't start with a digit.${tail}`;\n if (name !== name.toLowerCase()) {\n return `Can't be used. Expressions fold names, so this would look for \"${name.toLowerCase()}\".${tail}`;\n }\n return `Can't be used. Only lower case letters, digits, and underscores.${tail}`;\n}\n\n/**\n * Wire a name field: mark it live, explain the fault in its rollover, and coerce\n * on Tab. `onCommit` receives what the author typed, VERBATIM, on every input.\n *\n * `.illegal` rather than dupGuard's `.invalid`, because both can be true of one\n * field and `dupGuard.check()` owns that class: it would clear this marking every\n * time it ran, including at the moment of a blocked Save.\n *\n * An empty field is not marked. An unfinished row is a different thing from an\n * illegal one, and hosts prune blank names on save.\n */\nexport function bindPropertyName(\n input: HTMLInputElement,\n onCommit: (value: string) => void,\n opts: { hint?: string } = {},\n): void {\n const hint = opts.hint;\n const sync = (): void => {\n const v = input.value.trim();\n const problem = v === \"\" ? undefined : propertyNameProblem(v);\n input.classList.toggle(\"illegal\", !!problem);\n if (problem) input.title = problem;\n else if (input.title.startsWith(\"Can't be used\")) {\n if (hint) input.title = hint;\n else input.removeAttribute(\"title\");\n }\n };\n input.addEventListener(\"input\", () => { onCommit(input.value); sync(); });\n input.addEventListener(\"keydown\", (e) => {\n // The opt-in coercion, the id editor's gesture. Shift+Tab is left alone: it is\n // how somebody leaves a field they have not finished with.\n if (e.key !== \"Tab\" || e.shiftKey) return;\n const typed = input.value.trim();\n if (typed === \"\" || isValidPropertyName(typed)) return;\n const coerced = propertyNameify(typed);\n if (!coerced || coerced === input.value) return;\n e.preventDefault();\n input.value = coerced;\n onCommit(coerced);\n sync();\n });\n sync();\n}\n\n/**\n * The first field in `host` holding a name no expression could reach, for a Save\n * gate. Hosts hand this back beside `dupGuard.firstDuplicate()`: two faults, two\n * sets of words, one gate.\n */\nexport function firstIllegalPropertyName(host: ParentNode): HTMLInputElement | null {\n return host.querySelector<HTMLInputElement>(\"input.illegal\");\n}\n\n// ---------------------------------------------------------------------------\n// Reference fields, which are a different job from declaration fields.\n//\n// A declaration NAMES a property; a reference POINTS at one. The expression\n// parser folds every reference, so `@world.isNight` reaches `isnight` perfectly\n// well and complaining about the capital would be inventing a rule the language\n// does not have. Everything else still bites, and harder: no declaration may\n// contain a hyphen, so `is-night` in a reference can never match anything that\n// exists.\n//\n// And a reference has a fault a declaration cannot have: naming something that\n// was never declared. That is not a grammar question, so the host supplies the\n// list. The cost of getting it wrong is quiet - a coverage driver pointed at a\n// property nobody declared feeds a value nobody reads, the branches it was meant\n// to exercise stay unexercised, and the report shows them as never hit, which\n// reads as \"this content is unreachable\" rather than \"that name is a typo\".\n// ---------------------------------------------------------------------------\n\nexport interface PropertyRefOptions {\n /** The names that exist, read fresh on every check so a declaration added in the\n * same dialog clears the complaint. Compared case-insensitively, since the\n * parser folds. */\n known: () => string[];\n /** The scope token this field addresses, for the wording (\"no @world property...\"). */\n scope?: string;\n /** Shown on the field when there is nothing to complain about. */\n hint?: string;\n}\n\n/** The closest known name, when one is close enough to be worth naming. Deliberately\n * narrow: a wrong suggestion is worse than none, so it wants a shared prefix or a\n * single-character slip, not the least-bad match in the list. */\nfunction nearest(name: string, known: string[]): string | undefined {\n const n = name.toLowerCase();\n const byPrefix = known.filter((k) => k.toLowerCase().startsWith(n) || n.startsWith(k.toLowerCase()));\n if (byPrefix.length === 1) return byPrefix[0];\n let best: string | undefined;\n let bestScore = 3; // strictly better than \"three edits away\"\n for (const k of known) {\n const a = k.toLowerCase();\n if (Math.abs(a.length - n.length) > 2) continue;\n // Levenshtein, small strings, no need for a matrix beyond two rows.\n let prev = Array.from({ length: n.length + 1 }, (_, i) => i);\n for (let i = 1; i <= a.length; i++) {\n const row = [i];\n for (let j = 1; j <= n.length; j++) {\n row[j] = Math.min(prev[j]! + 1, row[j - 1]! + 1, prev[j - 1]! + (a[i - 1] === n[j - 1] ? 0 : 1));\n }\n prev = row;\n }\n const d = prev[n.length]!;\n if (d < bestScore) { bestScore = d; best = k; }\n }\n return best;\n}\n\n/** Why this reference cannot be used, or undefined when it can. */\nexport function propertyRefProblem(name: string, opts: PropertyRefOptions): string | undefined {\n const scope = opts.scope ? `@${opts.scope}` : \"that scope\";\n // Case is NOT a fault here: the parser folds references.\n const folded = name.toLowerCase();\n if (!isValidPropertyName(folded)) {\n const suggestion = propertyNameify(name);\n const tail = suggestion ? ` Try \"${suggestion}\", or press Tab.` : \"\";\n if (RESERVED_PROPERTY_NAMES.includes(folded)) return `Can't be used. \"${folded}\" is a keyword in expressions.${tail}`;\n if (name.includes(\"-\")) return `Can't be used. A hyphen reads as subtraction in an expression.${tail}`;\n if (/^[0-9]/.test(name)) return `Can't be used. A name can't start with a digit.${tail}`;\n return `Can't be used. Only lower case letters, digits, and underscores.${tail}`;\n }\n const known = opts.known();\n if (known.some((k) => k.toLowerCase() === folded)) return undefined;\n const near = nearest(folded, known);\n if (near) return `No ${scope} property is called \"${name}\". Did you mean \"${near}\"?`;\n if (known.length === 0) return `No ${scope} properties are declared yet. Declare one above first.`;\n const shown = known.slice(0, 3).map((k) => `\"${k}\"`).join(\", \");\n const more = known.length > 3 ? `, and ${known.length - 3} more` : \"\";\n return `No ${scope} property is called \"${name}\". Pick one of ${shown}${more}.`;\n}\n\n/**\n * Wire a field that POINTS at a declared property: same manners as a declaration\n * field (mark, do not rewrite, Tab coerces), plus the declared names offered as a\n * datalist, because the rule is declare-then-reference and a picker makes that\n * painless rather than pedantic.\n *\n * Marks `.illegal` for an undeclared name too, which gates Save wherever the host\n * already asks `firstIllegalPropertyName`.\n */\nexport function bindPropertyRef(\n input: HTMLInputElement,\n onCommit: (value: string) => void,\n opts: PropertyRefOptions,\n): void {\n const list = document.createElement(\"datalist\");\n list.id = `shell-propref-${Math.random().toString(36).slice(2, 9)}`;\n input.setAttribute(\"list\", list.id);\n\n // Attached lazily, not once at bind. A datalist has to be IN the document to do anything, and it is\n // attached as a sibling of the input - so binding a field that has not been appended yet (which is\n // the ordinary order for a builder that makes its nodes and then mounts them) silently produced no\n // autocomplete at all: no error, nothing to see. This re-tries on every sync, so it heals as soon as\n // the field reaches the tree.\n const attach = (): void => {\n if (!list.isConnected && input.parentNode) input.after(list);\n };\n\n const sync = (): void => {\n attach();\n const known = opts.known();\n list.replaceChildren(...known.map((k) => { const o = document.createElement(\"option\"); o.value = k; return o; }));\n const v = input.value.trim();\n const problem = v === \"\" ? undefined : propertyRefProblem(v, opts);\n input.classList.toggle(\"illegal\", !!problem);\n if (problem) input.title = problem;\n else if (input.title.startsWith(\"Can't be used\") || input.title.startsWith(\"No \")) {\n if (opts.hint) input.title = opts.hint;\n else input.removeAttribute(\"title\");\n }\n };\n refSyncs.set(input, sync);\n\n input.addEventListener(\"input\", () => { onCommit(input.value); sync(); });\n input.addEventListener(\"keydown\", (e) => {\n if (e.key !== \"Tab\" || e.shiftKey) return;\n const typed = input.value.trim();\n // Only a GRAMMAR fault is coercible. An undeclared name is not something Tab can\n // fix, and a legal reference in the wrong case is not a fault at all.\n if (typed === \"\" || isValidPropertyName(typed.toLowerCase())) return;\n const coerced = propertyNameify(typed);\n if (!coerced || coerced === input.value) return;\n e.preventDefault();\n input.value = coerced;\n onCommit(coerced);\n sync();\n });\n sync();\n}\n\n/**\n * Re-check every bound reference field inside `host`. Hosts call this when the\n * DECLARATIONS change, since a reference's validity depends on a list it does not\n * own: rename a property and the driver pointing at it is wrong from that moment,\n * with nothing typed into it.\n */\nexport function revalidatePropertyRefs(host: ParentNode): void {\n for (const input of host.querySelectorAll(\"input\")) refSyncs.get(input)?.();\n}\n","// ---------------------------------------------------------------------------\n// The gameId editor: a small anchored popover for setting a thing's address.\n//\n// Patterpad's `id-editor.ts`, lifted into the shell so both apps have the same\n// manners. They did not: Storyletter's accepted anything and let the save\n// quietly rewrite it, Patterpad's refused an illegal address and offered Tab as\n// an opt-in slugify. Patterpad's is the right half of that argument and is what\n// this is - the address is what a host will call the content by, and an app that\n// silently renames it has made a decision that was not its to make.\n//\n// THE SEAM: this knows nothing about what it is addressing. It takes the pinned\n// value, the name-derived fallback to show as a placeholder, and hands back a\n// string to persist (\"\" = go back to deriving one).\n// ---------------------------------------------------------------------------\n\nimport { el } from \"./dom.js\";\nimport { openAnchoredPanel } from \"./anchored.js\";\nimport { gameIdify as defaultSlugify, isValidGameId as defaultValid } from \"./ids.js\";\n\nexport interface GameIdEditorOptions {\n anchor: HTMLElement;\n /** The pinned address, or \"\" when it is being derived. */\n value: string;\n /** What it derives to, shown as the placeholder. */\n derived: string;\n /** Persist. \"\" means \"stop pinning, go back to deriving\". */\n onCommit: (gameId: string) => void;\n /** The panel's title. Both apps say \"Game ID\"; a third may not. */\n title?: string;\n /** Override the rules. Defaults are the shell's, which is what a new app\n * should use; an app whose domain layer owns them can pass its own. */\n slugify?: (text: string) => string;\n validate?: (gameId: string) => boolean;\n /** Where the panel goes, for hosts that anchor it somewhere tight. */\n prefer?: \"left\" | \"below\" | \"centre\";\n /** Chrome the panel must not cover, passed through to the anchored panel: an\n * app with a problems bar along the bottom wants it usable while an address\n * is being edited. Without this the editor is the one panel in a host that\n * can land on top of its own bars. */\n keepClear?: string[];\n}\n\n/**\n * Open it. Returns false when that click TOGGLED the panel shut, which is the\n * anchored panel's contract and worth passing on: a caller that repaints on open\n * needs to know it did not.\n */\nexport function openGameIdEditor(opts: GameIdEditorOptions): boolean {\n const slugify = opts.slugify ?? defaultSlugify;\n const valid = opts.validate ?? defaultValid;\n\n const panel = openAnchoredPanel({\n anchor: opts.anchor, className: \"shell-id-editor\", title: opts.title ?? \"Game ID\", width: 260,\n ...(opts.prefer !== undefined ? { prefer: opts.prefer } : {}),\n ...(opts.keepClear !== undefined ? { keepClear: opts.keepClear } : {}),\n });\n if (!panel) return false;\n\n const input = el(\"input\", \"shell-id-input\");\n input.type = \"text\";\n input.value = opts.value;\n input.placeholder = opts.derived || \"game-id\";\n input.spellcheck = false;\n\n const hint = el(\"div\", \"shell-id-hint\", \"Lower case letters, digits, and hyphens. Leave it empty to derive one from the name.\");\n const actions = el(\"div\", \"shell-id-actions\");\n const reset = el(\"button\", \"shell-id-reset\", \"Reset to auto\");\n const set = el(\"button\", \"shell-id-set\", \"Set\");\n reset.type = \"button\";\n set.type = \"button\";\n actions.append(reset, set);\n panel.body.append(input, hint, actions);\n\n // \"\" is allowed and means reset; anything else has to be a legal address.\n const legal = (): boolean => { const v = input.value.trim(); return v === \"\" || valid(v); };\n const sync = (): void => {\n set.disabled = !legal();\n hint.classList.toggle(\"bad\", !legal());\n };\n const commit = (): void => {\n if (!legal()) return;\n opts.onCommit(input.value.trim());\n panel.close();\n };\n\n input.addEventListener(\"input\", sync);\n input.addEventListener(\"keydown\", (e) => {\n // Stop keys reaching the app underneath: a canvas listening for Delete must\n // not act on one typed into an address.\n e.stopPropagation();\n if (e.key === \"Enter\") { e.preventDefault(); commit(); }\n // The opt-in coercion. Nothing is rewritten unless it is asked for, and when\n // it is, it happens in the field where it can be seen and undone.\n if (e.key === \"Tab\" && input.value.trim() !== \"\") {\n e.preventDefault();\n input.value = slugify(input.value);\n sync();\n }\n });\n set.addEventListener(\"click\", commit);\n reset.addEventListener(\"click\", () => { opts.onCommit(\"\"); panel.close(); });\n\n sync();\n setTimeout(() => input.focus(), 0);\n return true;\n}\n","// ---------------------------------------------------------------------------\n// The version-control surface's pure DOM half: folding a snapshot over the\n// shard key(s) an item stands for, the one badge that item flies, painting\n// those badges onto rows that already exist, and turning a document's editing\n// controls off when somebody else holds its shard.\n//\n// The family's, for the same reason the main half is: it follows from the app\n// SHAPE. Patterpad's #145 grammar, by way of Storyletter's port.\n//\n// Render-FREE by design, and that is load-bearing: a poll repaints badges\n// without rebuilding anything, so a mid-edit document is never disturbed.\n//\n// The one thing an app must supply is WHAT STAYS LIVE in a locked document\n// (`staysLive`): reading a shard somebody else holds must remain fully\n// possible, so navigation, disclosure and view switches keep working while the\n// writing stops - and only the app knows what those look like in its own\n// markup.\n// ---------------------------------------------------------------------------\n\nimport { icon, iconNode, type IconName } from \"./icons.js\";\nimport { el } from \"./dom.js\";\n\n/** One shard's state as the renderer sees it. The app's own DTO will be this\n * shape (it crosses its own bridge); this is what the view needs. */\nexport interface ShardVc {\n key: string;\n writable: boolean;\n lockedBy?: string[];\n outOfDate?: boolean;\n /** WE hold it: still ours to edit. */\n checkedOutByMe?: boolean;\n /** Tracked, with uncommitted local changes. */\n dirty?: boolean;\n /** Not in version control yet. */\n untracked?: boolean;\n}\n\n/** A snapshot, keyed by shard key. Absent = clean, writable, up to date. */\nexport type VcMap = ReadonlyMap<string, ShardVc>;\n\n/** Fold the state of the shard key(s) an item stands for (a box row spans its\n * box + tags + hands shards), most actionable winning: any holder locks it,\n * any stale shard makes it stale, any read-only shard makes it read-only. */\nexport function foldVc(shards: VcMap, keys: string | undefined): ShardVc | undefined {\n if (!keys) return undefined;\n let out: ShardVc | undefined;\n for (const key of keys.split(\" \")) {\n const s = shards.get(key);\n if (!s) continue;\n out ??= { key, writable: true };\n if (!s.writable) out.writable = false;\n if (s.lockedBy?.length) out.lockedBy = [...new Set([...(out.lockedBy ?? []), ...s.lockedBy])];\n if (s.outOfDate) out.outOfDate = true;\n if (s.checkedOutByMe) out.checkedOutByMe = true;\n if (s.dirty) out.dirty = true;\n if (s.untracked) out.untracked = true;\n }\n return out;\n}\n\n/** What a row flies: the word to draw (`name`), the class that colours it,\n * and the rollover. `glyph` is the deprecated typed character for a caller\n * still setting text; it goes when `icon` does. */\nexport interface VcBadge {\n name: IconName;\n /** @deprecated Draw `name` with `iconNode` instead. */\n glyph: string;\n cls: string;\n title: string;\n}\n\n/** The one badge an item flies, by priority, or null when there is nothing to\n * say. Drawn monochrome (never colour emoji), so each inherits its themed\n * colour and reads the same in Linen and Baize. */\nexport function vcBadgeFor(s: ShardVc | undefined): VcBadge | null {\n const badge = (name: IconName, cls: string, title: string): VcBadge => ({ name, glyph: icon[name as keyof typeof icon] ?? \"\", cls, title });\n if (s?.lockedBy?.length) return badge(\"locked\", \"vc-locked\", `Locked by ${s.lockedBy.join(\", \")}`);\n if (s?.outOfDate) return badge(\"down\", \"vc-stale\", \"Out of date. A newer version is on the server.\");\n // The three states of a file that is YOURS, most actionable first. Ordered so\n // the badge answers \"what would I do about this?\" rather than describing the\n // file: a checkout you are holding matters more than the edits inside it, and\n // both matter more than a file the VCS has never seen.\n if (s?.checkedOutByMe) return badge(\"checkedOut\", \"vc-mine\", \"Checked out by you\");\n if (s?.dirty) return badge(\"modified\", \"vc-dirty\", \"Modified. Local changes aren't committed yet.\");\n if (s?.untracked) return badge(\"untracked\", \"vc-new\", \"New. Not in version control yet.\");\n // Read-only on disk with NO other holder is still editable: the save checks\n // it out. Muted, and last, because under a lock-based VCS this is the\n // resting state of everything the author has not touched yet.\n if (s && !s.writable) return badge(\"readOnly\", \"vc-frozen\", \"Read-only on disk. Saving checks it out.\");\n return null;\n}\n\n/** Repaint the badge on every item under `root` that names a shard (its\n * `data-vc`). In place: no re-render, so nothing loses focus or scroll. */\nexport function paintVcBadges(root: ParentNode, shards: VcMap): void {\n root.querySelectorAll<HTMLElement>(\"[data-vc]\").forEach((host) => {\n host.querySelector(\":scope > .vc-badge\")?.remove();\n const badge = vcBadgeFor(foldVc(shards, host.dataset[\"vc\"]));\n if (!badge) return;\n // `tip` carries the accessible name too, so no separate aria-label. 12px:\n // the badge sits beside a row title at 0.78rem and must not outweigh it.\n const span = el(\"span\", { className: `vc-badge ${badge.cls}`, tip: badge.title }, iconNode(badge.name, 12));\n host.append(span);\n });\n}\n\ntype Disableable = HTMLButtonElement | HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement;\n\n/** Turn a region's editing controls off - or back on, but only the ones WE\n * turned off, so a control disabled for its own reasons (the first card's\n * \"previous\", a redraw-turns box on \"always\") stays disabled. */\nexport function lockControls(host: HTMLElement, off: boolean, staysLive: string): void {\n host.classList.toggle(\"vc-readonly\", off);\n if (off) {\n host.querySelectorAll<Disableable>(\"input, textarea, select, button\").forEach((c) => {\n if (c.disabled || (staysLive !== \"\" && c.matches(staysLive))) return;\n c.disabled = true;\n c.classList.add(\"vc-off\");\n });\n } else {\n host.querySelectorAll<Disableable>(\".vc-off\").forEach((c) => { c.disabled = false; c.classList.remove(\"vc-off\"); });\n }\n}\n\n/** The notice a locked document opens with: who holds it, and why nothing types. */\nexport function lockNotice(holders: string[]): HTMLElement {\n return el(\"div\", { className: \"vc-lock\" },\n el(\"span\", { className: \"vc-lock-glyph\" }, iconNode(\"locked\")),\n el(\"span\", { text: `Locked by ${holders.join(\", \")}. Read-only until they release it.` }));\n}\n","// ---------------------------------------------------------------------------\n// \"Who is working here?\" - Patterpad's first-run identity, as the family's.\n//\n// `{ name, email? }`, asked ONCE at first startup and skippable, editable later\n// from User Information… in the menu. It belongs to the person at the keyboard,\n// never to the project, which is why the app stores it in ITS OWN state and not\n// in a shard: a project carrying a name would hand it to whoever opened the file\n// next.\n//\n// The shell asks and returns; PERSISTING is the app's, because each app has its\n// own state file. `suggested` is there for the day simple-vc-lib can say who the\n// version control thinks you are (see patterkit from-storylets/vc-current-user),\n// so the box opens with a sensible answer rather than empty.\n//\n// Two occasions, one dialog (ui-review-2026-09, Patterpad adoption step 5): the\n// first run is a welcome, the menu item is an edit, and the title and the\n// primary button say which. Without a `mode` it is the plain ask it always was.\n// ---------------------------------------------------------------------------\n\nimport { el, labelled } from \"./dom.js\";\nimport { dialogFrame } from \"./dialog.js\";\n\nexport interface Identity { name: string; email?: string }\n\nexport interface IdentityOptions {\n /** What it already says, if anything. */\n current?: Identity;\n /** A name to offer when there is none: the VCS's, one day. */\n suggested?: Identity;\n /**\n * `\"welcome\"` is the first run (\"Welcome to <appName>\", Continue); `\"edit\"`\n * is the menu item (\"User information\", Save). Absent, the title is the\n * shell's \"Who is working here?\" and the button is Save.\n */\n mode?: \"welcome\" | \"edit\";\n /** Names the app in the welcome title. Without it the title is \"Welcome\". */\n appName?: string;\n /**\n * By default a skip resolves `undefined` and the app asks again next launch.\n * With this on, a skip resolves `{ name: \"\" }`: the app stores the blank and\n * never asks again (Patterpad's first run, where main fills in a default).\n * A Save with an empty name counts as a skip either way.\n */\n neverAskAgainOnSkip?: boolean;\n}\n\n/** Ask, and record the answer. Resolves when the dialog closes, either way. */\nexport function askIdentity(opts: IdentityOptions = {}): Promise<Identity | undefined> {\n return new Promise<Identity | undefined>((resolve) => {\n const seed = opts.current ?? opts.suggested;\n const name = el(\"input\", \"field shell-ident-input\") as HTMLInputElement;\n name.placeholder = \"Your name\";\n name.value = seed?.name ?? \"\";\n const email = el(\"input\", \"field shell-ident-input\") as HTMLInputElement;\n email.placeholder = \"Optional\";\n email.type = \"email\";\n email.value = seed?.email ?? \"\";\n\n const skip = el(\"button\", \"btn shell-ident-btn\", \"Skip\");\n const save = el(\"button\", \"btn primary shell-ident-btn\", opts.mode === \"welcome\" ? \"Continue\" : \"Save\");\n skip.type = \"button\"; save.type = \"button\";\n\n let done = false;\n const finish = (keep: boolean): void => {\n if (done) return;\n done = true;\n const typed = name.value.trim();\n const value = email.value.trim();\n const answer: Identity | undefined = keep && typed !== \"\"\n ? (value === \"\" ? { name: typed } : { name: typed, email: value })\n : (opts.neverAskAgainOnSkip === true ? { name: \"\" } : undefined);\n resolve(answer);\n frame.close();\n };\n\n // The frame owns the panel, the scrim, Escape and the exit motion; this\n // owns the two fields and the two answers.\n const frame = dialogFrame({\n title: titleFor(opts),\n sub: subFor(opts),\n className: \"shell-ident\",\n onClose: () => finish(false), // Escape, or closed by someone else: a skip\n });\n // Captions above the fields, not placeholders alone: a placeholder is gone\n // the moment there is a value in the box, and the VCS's suggestion is one.\n frame.body.append(el(\"div\", \"shell-ident-fields\", labelled(\"Name\", name), labelled(\"Email\", email)));\n frame.actions.append(skip, save);\n\n skip.addEventListener(\"click\", () => finish(false));\n save.addEventListener(\"click\", () => finish(true));\n // Enter saves, Escape skips: the two answers the dialog has.\n name.addEventListener(\"keydown\", (e) => { if (e.key === \"Enter\") finish(true); });\n email.addEventListener(\"keydown\", (e) => { if (e.key === \"Enter\") finish(true); });\n\n frame.open();\n name.focus();\n });\n}\n\nfunction titleFor(opts: IdentityOptions): string {\n if (opts.mode === \"welcome\") return opts.appName ? `Welcome to ${opts.appName}` : \"Welcome\";\n if (opts.mode === \"edit\") return \"User information\";\n return \"Who is working here?\";\n}\n\n/** The one sub line, minus its last sentence when this IS the later change. */\nfunction subFor(opts: IdentityOptions): string {\n const why = \"Your name goes on the comments you write. It's kept in this app, not in the project.\";\n return opts.mode === \"edit\" ? why : `${why} You can change it later.`;\n}\n","// ---------------------------------------------------------------------------\n// The documentation-notes editor: Patterpad's, as the family's (Patter spec 18).\n//\n// Documentation states the reason; comments are the conversation. A note says\n// why a card is here, who it is for, what a translator needs to know. It has no\n// author, no timestamp, and nobody replies to it.\n//\n// A MODAL, and that is a decision somebody already paid for: Patterpad tried an\n// anchored popover first and removed it as too cramped. Notes are prose, and\n// prose needs room.\n//\n// One text area PER CLASS, each non-blank line becoming a note of that class.\n// The alternative - a list of lines each with its own class dropdown - is more\n// granular and, as their proposal puts it, fiddlier: you would fill in a form to\n// write a sentence.\n//\n// THE SEAM: this knows nothing about what a note is attached to. The app hands\n// it the notes that apply, the ancestors they came from and the classes on\n// offer, and takes back a list. Whether the levels are box -> deck -> card or\n// scene -> block -> line never reaches here.\n//\n// Showing INHERITED notes read-only is Storyletter's addition, and it belongs in\n// the family: Patterpad deferred it because its stacked inspector already shows\n// each ancestor's Notes row, but an app whose editor has no such stack must show\n// them somewhere or an author will write the box's note again on the card.\n// ---------------------------------------------------------------------------\n\nimport { el } from \"./dom.js\";\nimport { dialogFrame } from \"./dialog.js\";\n\n/** One line of documentation. `type` names its class; absent = editor-only. */\nexport interface DocLine { type?: string; text: string }\n\n/** What applies to one thing: its own notes, and the ancestors' that reach it.\n * Inherited notes are READ-ONLY - they are edited where they live, which is\n * what stops a note being copied down and then disagreeing with itself. */\nexport interface Notes {\n own: DocLine[];\n inherited: { id: string; label: string; lines: DocLine[] }[];\n /** The classes this app offers, in the order they should appear. */\n classes: string[];\n}\n\nconst EDITOR_ONLY = \"\";\nconst UNTYPED_KEY = \"__untyped\";\n\n/** The classes the family already has words for; anything else is Title Cased,\n * so a studio can add one without touching this. Patterpad's labels. */\nconst CLASS_LABEL: Record<string, string> = {\n everyone: \"Everyone\", writing: \"Writing\", vo: \"Voice (VO)\", loc: \"Localisers\",\n};\nconst label = (cls: string): string =>\n cls === EDITOR_ONLY ? \"Note (editor-only)\"\n : CLASS_LABEL[cls] ?? (cls[0]!.toUpperCase() + cls.slice(1));\n\nconst PLACEHOLDER: Record<string, string> = {\n vo: \"Direction for the voice actor or director\",\n loc: \"Context for translators\",\n};\nconst placeholder = (cls: string): string =>\n cls === EDITOR_ONLY ? \"An internal note, never exported\"\n : PLACEHOLDER[cls] ?? \"Why this is here\";\n\nexport interface NotesEditorOptions {\n /** What this is about, for the dialog's title (\"Notes: Arrive at the gate\"). */\n subject: string;\n notes: Notes;\n /** Commit. Called once, on close, and only when something changed. */\n save: (lines: DocLine[]) => void;\n}\n\n/** Open the notes modal. Resolves when it closes. */\nexport function openNotesEditor(opts: NotesEditorOptions): void {\n const { notes } = opts;\n\n // Seed one text area per class that already has notes; a fresh thing gets the\n // first class in the vocabulary, so the commonest act (write a note) is typing\n // rather than choosing.\n const seed = new Map<string, string>();\n for (const line of notes.own) {\n const key = line.type ?? EDITOR_ONLY;\n seed.set(key, seed.has(key) ? `${seed.get(key)!}\\n${line.text}` : line.text);\n }\n const shown: string[] = [...seed.keys()];\n if (shown.length === 0) shown.push(notes.classes[0] ?? EDITOR_ONLY);\n const areas = new Map<string, HTMLTextAreaElement>();\n\n const value = (): DocLine[] => {\n const out: DocLine[] = [];\n for (const cls of shown) {\n const area = areas.get(cls);\n if (!area) continue;\n for (const raw of area.value.split(\"\\n\")) {\n const text = raw.trim();\n if (text !== \"\") out.push(cls === EDITOR_ONLY ? { text } : { type: cls, text });\n }\n }\n return out;\n };\n\n const body = el(\"div\", \"shell-notes-body\");\n\n const render = (): void => {\n body.replaceChildren();\n\n // The inherited context first, because it is what an author needs BEFORE\n // deciding whether to write anything: outermost first, muted, and labelled\n // with where it lives so the answer to \"why can I not edit this\" is on\n // screen.\n if (notes.inherited.length > 0) {\n const from = el(\"div\", { className: \"shell-notes-inherited\" },\n el(\"div\", \"shell-notes-caption\", \"Inherited\"));\n for (const level of notes.inherited) {\n from.append(el(\"div\", { className: \"shell-notes-level\" },\n el(\"span\", \"shell-notes-level-label\", level.label),\n ...level.lines.map((line) => el(\"div\", { className: \"shell-notes-line\" },\n ...(line.type !== undefined && line.type !== \"everyone\"\n ? [el(\"span\", \"shell-notes-cls\", label(line.type))] : []),\n el(\"span\", \"\", line.text))),\n ));\n }\n body.append(from);\n }\n\n for (const cls of shown) {\n const block = el(\"div\", { className: \"shell-notes-class\" },\n el(\"label\", \"shell-notes-caption\", label(cls)));\n const area = el(\"textarea\", \"field shell-notes-text\");\n area.value = areas.get(cls)?.value ?? seed.get(cls) ?? \"\";\n area.rows = 4;\n area.placeholder = placeholder(cls);\n area.spellcheck = true;\n areas.set(cls, area);\n block.append(area);\n body.append(block);\n }\n\n // One line per note, said once where somebody is about to type.\n body.append(el(\"p\", \"shell-notes-hint\", \"One note per line.\"));\n\n const remaining = [...notes.classes, EDITOR_ONLY].filter((c) => !shown.includes(c));\n if (remaining.length > 0) {\n const add = el(\"select\", \"shell-notes-add\");\n add.append(new Option(\"Add a note for…\", \"\"));\n for (const cls of remaining) add.append(new Option(label(cls), cls === EDITOR_ONLY ? UNTYPED_KEY : cls));\n add.addEventListener(\"change\", () => {\n if (add.value === \"\") return;\n const cls = add.value === UNTYPED_KEY ? EDITOR_ONLY : add.value;\n shown.push(cls);\n render();\n areas.get(cls)?.focus();\n });\n body.append(add);\n }\n };\n render();\n\n const done = el(\"button\", \"btn primary shell-notes-btn\", \"Done\");\n done.type = \"button\";\n\n const before = JSON.stringify(notes.own);\n // Done and Escape both end up here (the frame's onClose runs for every way\n // out), so the guard is what stops one gesture saving twice.\n let closed = false;\n const commit = (): void => {\n if (closed) return;\n closed = true;\n const next = value();\n // Only when something changed: opening a note to read it must not cost an\n // undo step, and must not touch the file (or the version control status).\n if (JSON.stringify(next) !== before) opts.save(next);\n };\n // Escape closes the dialog by itself, and commits: this editor has no Cancel,\n // because a note is prose and losing a paragraph to a stray key is worse than\n // an unwanted note somebody can delete.\n const frame = dialogFrame({ title: `Notes: ${opts.subject}`, className: \"shell-notes\", onClose: commit });\n frame.body.append(body);\n frame.actions.append(done);\n done.addEventListener(\"click\", () => { commit(); frame.close(); });\n\n frame.open();\n areas.get(shown[0] ?? EDITOR_ONLY)?.focus();\n}\n","// ---------------------------------------------------------------------------\n// The comment thread popover: Patterpad's (#148), as the family's.\n//\n// Comments are the conversation; documentation states the reason. Anchored\n// rather than modal, which is the deliberate contrast with the notes editor: a\n// comment is had BESIDE the thing, and a modal covering the card would hide\n// what is being discussed.\n//\n// Everything here that looks like a small decision is one somebody already\n// made: author and timestamp on every message (a comment without a \"who\" is an\n// anonymous complaint); Enter posts and closes while Shift+Enter is a newline;\n// the button reads Comment on a new thread and Reply on an old one; focus goes\n// to the composer ONLY for a new thread, because opening an existing one to\n// read must not yank the cursor out of the work; and a thread does not exist\n// until its first message is posted, so a composer somebody thought better of\n// leaves nothing behind.\n//\n// THE SEAM: an anchor is an opaque id. What it points at - a card, a beat, a\n// span of characters - is the app's, and so is where the threads are stored.\n// This takes a list and gives back \"post this\" and \"resolve that\".\n// ---------------------------------------------------------------------------\n\nimport { el } from \"./dom.js\";\nimport { iconNode } from \"./icons.js\";\nimport { openAnchoredPanel } from \"./anchored.js\";\n\n/** One message. The author is a NAME stamped at posting time, not a reference:\n * people leave projects and their words stay. */\nexport interface CommentMessage {\n author: string; ts: string; body: string;\n /** A TOMBSTONE: the words are gone, the turn in the conversation is not.\n * Deleting a reply out of a thread would renumber the argument around it, so\n * what is left says who spoke and when and that they withdrew it. The body is\n * emptied on the way out, so \"deleted\" means deleted from the file too. */\n deleted?: boolean;\n}\n\n/** A thread, anchored to the id of whatever it is about. */\nexport interface Comment {\n id: string;\n anchor: string;\n resolved?: boolean;\n messages: CommentMessage[];\n}\n\nconst stamp = (ts: string): string => {\n const when = new Date(ts);\n if (Number.isNaN(when.getTime())) return ts;\n return when.toLocaleString(undefined, { dateStyle: \"medium\", timeStyle: \"short\" });\n};\n\n/** A preview of a thread, for the list: its first message, shortened. The first\n * message that still SAYS something - a thread whose opener was withdrawn is\n * previewed by whatever carried on, not by its tombstone. */\nconst gist = (thread: Comment): string => {\n const first = thread.messages.find((m) => m.deleted !== true)?.body ?? \"\";\n return first.length > 60 ? `${first.slice(0, 57)}…` : first;\n};\n\nexport interface CommentsOptions {\n anchor: HTMLElement;\n /** What is being discussed, for the panel's title. */\n subject: string;\n /** Every thread on this thing, resolved ones included. */\n threads: Comment[];\n /** Review ▸ Show Resolved Comments. */\n showResolved: boolean;\n /** A fresh thread id, minted by the caller so main never has to. */\n newThreadId: () => string;\n post: (threadId: string, body: string) => void;\n setResolved: (threadId: string, resolved: boolean) => void;\n /**\n * Withdraw one message. Absent = the host does not offer deletion.\n *\n * By INDEX, because a message has no id of its own and giving every message\n * one would be a format change to every stored thread for the sake of one\n * verb. The index is read off the list the reader is looking at, and these\n * files are edited by one person at a time with a VCS underneath.\n *\n * The host decides what deleting MEANS: the agreed rule is that the message\n * becomes a tombstone, and the whole thread goes when nothing readable would\n * be left (which covers the common case of withdrawing a comment nobody had\n * replied to).\n */\n deleteMessage?: (threadId: string, index: number) => void;\n /** Where the panel sits: \"centre\" for a point on a canvas (see anchored.ts). */\n prefer?: \"left\" | \"below\" | \"centre\";\n /**\n * Chrome the panel must not cover. Defaults to `[\".problembar\"]`, which was\n * hardcoded here and should not have been: one app's class name in shared\n * code, and it misses any OTHER bar a host has. A second app arrived with two.\n */\n keepClear?: string[];\n /**\n * The text a thread is pinned to, shown above it as a quotation.\n *\n * A callback rather than a field on `Comment`, because resolving an anchor is\n * the APP's half of the seam and this is only that resolution rendered: an app\n * that pins threads to a span of prose can quote it, one that pins them to a\n * whole card has nothing to quote and passes nothing. Keeping it out of the\n * thread type also means no change to what is written to disk, which matters\n * for files living in version control.\n *\n * Return undefined (or \"\") for a thread with no quotable anchor.\n */\n quoteFor?: (thread: Comment) => string | undefined;\n}\n\nexport function openComments(opts: CommentsOptions): void {\n const visible = opts.threads.filter((t) => opts.showResolved || t.resolved !== true);\n const panel = openAnchoredPanel({\n anchor: opts.anchor, className: \"comments\", title: \"Comments\", width: 320,\n // Below its button (the topline), unlike Patterpad's inspector rows which\n // want it to the left; and never over the problems bar, which an author may\n // be stepping through while reading the thread.\n prefer: opts.prefer ?? \"below\",\n keepClear: opts.keepClear ?? [\".problembar\"],\n });\n if (!panel) return; // the same anchor again: that click closed it\n const { body, close } = panel;\n\n // Which thread is on screen. A brand-new one until it is posted: it exists\n // only here, which is why nothing is written when the panel closes unposted.\n let open: Comment | undefined = visible.length === 1 ? visible[0] : undefined;\n let composing = visible.length === 0;\n\n const render = (): void => {\n body.replaceChildren();\n\n if (!composing && open === undefined) {\n // More than one: pick.\n for (const thread of visible) {\n const row = el(\"button\", { className: `shell-cmt-row${thread.resolved === true ? \" resolved\" : \"\"}` },\n el(\"span\", { className: \"shell-cmt-row-author\", text: thread.messages[0]?.author ?? \"Someone\" }),\n el(\"span\", { className: \"shell-cmt-row-gist\", text: gist(thread) }),\n ...(thread.messages.length > 1\n ? [el(\"span\", { className: \"shell-cmt-row-count\", text: `${thread.messages.length}` })] : []),\n );\n row.addEventListener(\"click\", () => { open = thread; render(); });\n body.append(row);\n }\n const fresh = el(\"button\", { className: \"shell-cmt-new\", text: \"New comment\" });\n fresh.addEventListener(\"click\", () => { open = undefined; composing = true; render(); });\n body.append(fresh);\n return;\n }\n\n const thread = open;\n if (thread) {\n // The span this thread is pinned to, quoted above it. Without it a comment\n // on a phrase reads as a comment on the whole thing, and the reader has to\n // remember what was selected.\n const quote = opts.quoteFor?.(thread);\n if (quote !== undefined && quote !== \"\") {\n body.append(el(\"blockquote\", { className: \"shell-cmt-quote\", text: quote }));\n }\n const list = el(\"div\", { className: `shell-cmt-list${thread.resolved === true ? \" resolved\" : \"\"}` });\n thread.messages.forEach((message, index) => {\n const head = el(\"div\", { className: \"shell-cmt-msg-head\" },\n el(\"span\", { className: \"shell-cmt-author\", text: message.author === \"\" ? \"Someone\" : message.author }),\n el(\"span\", { className: \"shell-cmt-ts\", text: stamp(message.ts) }));\n // Rollover-revealed, at the end of the head: the family's grip grammar,\n // and a delete that is always visible invites the accident it is.\n // Nothing is offered on a tombstone: there is nothing left to withdraw.\n if (opts.deleteMessage && message.deleted !== true) {\n const bin = el(\"button\", { className: \"shell-cmt-del\" }, iconNode(\"close\", 12));\n bin.dataset.tip = \"Delete this comment\";\n bin.setAttribute(\"aria-label\", \"Delete this comment\");\n bin.addEventListener(\"click\", () => opts.deleteMessage?.(thread.id, index));\n head.append(bin);\n }\n list.append(el(\"div\", { className: `shell-cmt-msg${message.deleted === true ? \" gone\" : \"\"}` },\n head,\n el(\"div\", { className: \"shell-cmt-body\", text: message.deleted === true ? \"Comment deleted\" : message.body })));\n });\n body.append(list);\n }\n\n const input = el(\"textarea\", { className: \"shell-cmt-input\" });\n input.rows = 2;\n input.placeholder = thread ? \"Reply…\" : \"Comment…\";\n input.addEventListener(\"keydown\", (e) => {\n e.stopPropagation();\n if (e.key !== \"Enter\" || e.shiftKey) return;\n e.preventDefault();\n submit(true);\n });\n body.append(input);\n\n const submit = (andClose: boolean): void => {\n const text = input.value.trim();\n if (text === \"\") return;\n const id = thread?.id ?? opts.newThreadId();\n opts.post(id, text);\n if (andClose) close(); else { input.value = \"\"; }\n };\n\n const actions = el(\"div\", { className: \"shell-cmt-actions\" });\n const post = el(\"button\", { className: \"shell-cmt-btn primary\", text: thread ? \"Reply\" : \"Comment\" });\n post.addEventListener(\"click\", () => submit(false));\n actions.append(post);\n\n if (thread) {\n const resolved = thread.resolved === true;\n const toggle = el(\"button\", { className: \"shell-cmt-btn\", text: resolved ? \"Reopen\" : \"Mark complete\" });\n toggle.addEventListener(\"click\", () => {\n opts.setResolved(thread.id, !resolved);\n // A resolved thread hides, so there is nothing left to look at.\n if (!resolved) close(); else render();\n });\n actions.append(toggle);\n }\n body.append(actions);\n\n // Only for a new thread: reading an old one must not steal the cursor.\n if (!thread) input.focus();\n };\n render();\n}\n","// ---------------------------------------------------------------------------\n// The long-job kit (renderer): the progress strip the main-side JobHost feeds.\n// A determinate bar, a count, elapsed and estimated remaining, and Cancel.\n//\n// A STRIP, NOT A MODAL. The window that started the job is the one that shows\n// it, and the rest of the app stays usable: these are tool windows, and taking\n// the whole editor hostage while a sweep runs was the old system's mistake.\n// The strip is hidden until a job starts and hides itself when one ends.\n//\n// TWO MODES, ONE STRIP. A job that knows its size (a coverage sweep: N runs)\n// gets the determinate bar, the count and the time readout. A job that does\n// not (a publish, a pull, a pack: one write of unknown length) gets an\n// INDETERMINATE band that sweeps the bar, no count, and the elapsed time\n// alone. The host's progress message already says which: `total` 0 is \"no\n// idea yet\" (job.ts), so the strip follows the data and flips to the\n// determinate bar the moment a total arrives. A host that knows its jobs\n// never count pins the mode with `indeterminate: true`; a host whose jobs\n// cannot be stopped mid-write drops Cancel with `cancellable: false` (or by\n// passing no `onCancel` at all).\n//\n// The time readout only appears once there is enough evidence for it. An ETA\n// that swings wildly for the first second reads as a broken app, so the\n// estimate waits until a second of work and a tenth of the job are behind it.\n// ---------------------------------------------------------------------------\n\nimport { el } from \"./dom.js\";\n\n/** Per-run overrides for a strip that serves several kinds of job (the main\n * window's: a countable export beside an uncountable pull). Each begin()\n * starts from the mount options and applies these on top. */\nexport interface JobBeginOptions {\n /** Pin the band regardless of what the job reports. */\n indeterminate?: boolean;\n /** Show Cancel for this run. */\n cancellable?: boolean;\n}\n\nexport interface JobProgressView {\n /** The strip; mount it where the job belongs. */\n readonly element: HTMLElement;\n /** Show the strip, reset to zero, and (optionally) name what is running. */\n begin(label?: string, run?: JobBeginOptions): void;\n /** Feed it a progress message from the main-side host. A `total` of 0\n * (the host's \"no idea yet\") draws the indeterminate band; the first\n * positive total flips the strip to the determinate bar. */\n update(done: number, total: number, elapsedMs: number): void;\n /** Hide the strip (the job finished, failed, or was cancelled). */\n end(): void;\n readonly visible: boolean;\n /** True while the strip is drawing the band rather than the bar. */\n readonly indeterminate: boolean;\n}\n\nexport interface JobProgressOptions {\n /** Called when Cancel is clicked. The button disables itself and says so;\n * the job stops at its next yield, and the host then calls end(). Omit it\n * for a strip whose jobs cannot be stopped: Cancel is then not drawn. */\n onCancel?: () => void;\n /** The word for the units, for the count readout (default \"runs\"). */\n units?: string;\n /** Always draw the band and never the count, whatever the job reports.\n * Default: follow the data (band until a total arrives). */\n indeterminate?: boolean;\n /** Draw Cancel. Default: only when `onCancel` was given. */\n cancellable?: boolean;\n}\n\nconst clock = (ms: number): string => {\n const total = Math.round(ms / 1000);\n const m = Math.floor(total / 60);\n const s = total % 60;\n return m > 0 ? `${m}m ${String(s).padStart(2, \"0\")}s` : `${s}s`;\n};\n\n/** Enough of the job done, and enough time passed, for a remaining-time\n * estimate to be worth showing rather than misleading. */\nconst estimable = (done: number, total: number, elapsedMs: number): boolean =>\n done > 0 && total > 0 && elapsedMs > 1000 && done / total > 0.1;\n\nexport function mountJobProgress(host: HTMLElement, opts: JobProgressOptions): JobProgressView {\n const units = opts.units ?? \"runs\";\n const pinned = opts.indeterminate === true;\n const cancellableByDefault = opts.cancellable ?? (opts.onCancel !== undefined);\n\n const fill = el(\"i\", { className: \"job-fill\" });\n const bar = el(\"div\", { className: \"job-bar\" }, fill);\n bar.setAttribute(\"role\", \"progressbar\");\n bar.setAttribute(\"aria-valuemin\", \"0\");\n bar.setAttribute(\"aria-valuemax\", \"100\");\n const what = el(\"span\", { className: \"job-label\" });\n const count = el(\"span\", { className: \"job-count\" });\n const time = el(\"span\", { className: \"job-time\" });\n const cancel = el(\"button\", { className: \"job-cancel\", text: \"Cancel\" });\n cancel.type = \"button\";\n\n const strip = el(\"div\", { className: \"job-strip\" }, what, bar, count, time, cancel);\n strip.hidden = true;\n host.append(strip);\n\n // The run's settings: reset by begin(), read by update().\n let runPinned = pinned;\n let indeterminate = false;\n\n /** Draw the band (no count, no value) or the bar (both). Every write is\n * idempotent, so update() may call it each time and only a flip shows. */\n const setMode = (band: boolean): void => {\n indeterminate = band;\n strip.classList.toggle(\"indeterminate\", band);\n count.hidden = band;\n if (band) {\n // The band's width and motion are the stylesheet's: clear the inline\n // width the bar set, or it wins over the class.\n fill.style.width = \"\";\n bar.removeAttribute(\"aria-valuenow\");\n }\n };\n\n const view: JobProgressView = {\n element: strip,\n get visible() { return !strip.hidden; },\n get indeterminate() { return indeterminate; },\n\n begin(label?: string, run?: JobBeginOptions) {\n runPinned = run?.indeterminate ?? pinned;\n const cancellable = run?.cancellable ?? cancellableByDefault;\n what.textContent = label ?? \"Running…\";\n count.textContent = \"\";\n time.textContent = \"\";\n cancel.hidden = !cancellable;\n cancel.disabled = false;\n cancel.textContent = \"Cancel\";\n // Every run opens on the band: nothing is known until the first report.\n setMode(true);\n strip.hidden = false;\n },\n\n update(done: number, total: number, elapsedMs: number) {\n if (strip.hidden) strip.hidden = false;\n const band = runPinned || !(total > 0);\n setMode(band);\n if (!band) {\n const pct = Math.min(100, (done / total) * 100);\n fill.style.width = `${pct}%`;\n bar.setAttribute(\"aria-valuenow\", String(Math.round(pct)));\n count.textContent = `${done} / ${total} ${units}`.trimEnd();\n }\n if (!band && estimable(done, total, elapsedMs)) {\n const remaining = (elapsedMs / done) * (total - done);\n time.textContent = `${clock(elapsedMs)} elapsed, about ${clock(remaining)} left`;\n } else {\n time.textContent = clock(elapsedMs);\n }\n },\n\n end() {\n strip.hidden = true;\n },\n };\n\n cancel.addEventListener(\"click\", () => {\n // Cancellation lands at the job's next yield, which may be a moment away:\n // say so, rather than leaving a dead-looking button.\n cancel.disabled = true;\n cancel.textContent = \"Stopping…\";\n opts.onCancel?.();\n });\n\n // Before the first begin(): the band, and Cancel per the mount options, so\n // a host that only ever calls update() (the strip appearing on the first\n // progress message) still gets a coherent strip.\n cancel.hidden = !cancellableByDefault;\n setMode(true);\n\n return view;\n}\n","// ---------------------------------------------------------------------------\n// The long-job kit (main process): run a piece of work that takes long enough\n// to need a progress bar and a Cancel button, without freezing the app.\n//\n// The shape every editor in the family needs: coverage sweeps, big exports,\n// corpus runs. One kind of job at a time, progress reported to the windows\n// that asked for it, cancellation honoured at the next yield point, and a\n// partial result when the work can offer one.\n//\n// COOPERATIVE, NOT PARALLEL. The work still runs in the main process; it just\n// stops hogging it. `ctx.step()` is both the progress report and the yield:\n// the work hands the event loop back every few milliseconds, so IPC keeps\n// flowing, the renderer keeps painting, and Cancel is heard. The alternative\n// (a utilityProcess or a worker) buys true parallelism at the cost of\n// serialising the job's inputs and outputs across a process boundary, and a\n// second entry point per app. Reach for that only when the work is heavy\n// enough that a responsive main process is not enough.\n//\n// Electron is an OPTIONAL peer here: nothing in this file imports it. The host\n// supplies `send`, so the kit is testable headlessly and usable from any\n// message transport.\n// ---------------------------------------------------------------------------\n\n/** The channel a host should send progress on, and the shape it carries. */\nexport const JOB_PROGRESS = \"job:progress\";\n\nexport interface JobProgress {\n /** Which job this is about (\"coverage\"), so one listener can serve many. */\n kind: string;\n /** Units finished and expected. `total` 0 means \"no idea yet\". */\n done: number;\n total: number;\n /** Milliseconds since the job started, for elapsed + estimated remaining. */\n elapsedMs: number;\n}\n\n/** What the work is given: a cancellation flag and the one call that both\n * reports progress and yields. */\nexport interface JobContext {\n /** True once someone has cancelled. Check it to bail out early, or to\n * return a partial result rather than nothing. */\n readonly cancelled: boolean;\n /** Report progress and, when enough time has passed, hand the event loop\n * back. Await it: that await IS the yield. */\n step(done: number, total: number): Promise<void>;\n}\n\nexport type JobResult<T> =\n | { ok: true; value: T }\n | { cancelled: true; value?: T }\n | { error: string };\n\nexport interface JobHost {\n /** Run `work` as the job of this kind. Rejects a second start of the same\n * kind while one is in flight (the caller should have disabled the button;\n * this is the backstop). */\n start<T>(kind: string, work: (ctx: JobContext) => Promise<T>): Promise<JobResult<T>>;\n /** Ask the running job of this kind to stop. It stops at its next step(). */\n cancel(kind: string): void;\n running(kind: string): boolean;\n}\n\nexport interface JobHostOptions {\n /** Deliver a progress message to whoever is watching (typically\n * `window.webContents.send(JOB_PROGRESS, payload)` for each live window). */\n send: (channel: string, payload: JobProgress) => void;\n /** How long the work may hold the event loop between yields (default 16ms,\n * about one frame). Smaller is smoother and slower. */\n sliceMs?: number;\n /** How often a progress message may be sent (default 100ms). Progress is\n * for a human to read; flooding the channel just costs IPC. */\n reportMs?: number;\n /** Injectable clock + yield, for tests. */\n now?: () => number;\n yieldToLoop?: () => Promise<void>;\n}\n\nconst defaultYield = (): Promise<void> =>\n new Promise((resolve) => { setTimeout(resolve, 0); });\n\nexport function createJobHost(opts: JobHostOptions): JobHost {\n const now = opts.now ?? (() => Date.now());\n const handOver = opts.yieldToLoop ?? defaultYield;\n const sliceMs = opts.sliceMs ?? 16;\n const reportMs = opts.reportMs ?? 100;\n const live = new Map<string, { cancelled: boolean }>();\n\n return {\n running: (kind) => live.has(kind),\n\n cancel(kind) {\n const job = live.get(kind);\n if (job) job.cancelled = true;\n },\n\n async start<T>(kind: string, work: (ctx: JobContext) => Promise<T>): Promise<JobResult<T>> {\n if (live.has(kind)) return { error: `a ${kind} job is already running` };\n const job = { cancelled: false };\n live.set(kind, job);\n\n const started = now();\n let lastYield = started;\n // A flag, not a timestamp sentinel: on a clock that can legitimately\n // read 0, \"never reported yet\" and \"reported at 0\" must not be the\n // same state. The first step always reports, so the bar moves at once.\n let reported = false;\n let lastReport = 0;\n\n const ctx: JobContext = {\n get cancelled() { return job.cancelled; },\n async step(done: number, total: number): Promise<void> {\n const at = now();\n if (!reported || at - lastReport >= reportMs || done >= total) {\n reported = true;\n lastReport = at;\n opts.send(JOB_PROGRESS, { kind, done, total, elapsedMs: at - started });\n }\n if (at - lastYield >= sliceMs) {\n lastYield = at;\n await handOver();\n }\n },\n };\n\n try {\n const value = await work(ctx);\n return job.cancelled ? { cancelled: true, value } : { ok: true, value };\n } catch (e) {\n // A cancelled job that threw on the way out is still a cancellation:\n // the author asked it to stop, and an error report would be noise.\n if (job.cancelled) return { cancelled: true };\n return { error: e instanceof Error ? e.message : String(e) };\n } finally {\n live.delete(kind);\n }\n },\n };\n}\n","// ---------------------------------------------------------------------------\n// The save/dirty controller: the little machine that turns \"the author typed\n// something\" into \"the bytes are on disk\", and says so on screen.\n//\n// Both apps wrote one. Neither is complete, and the two are incomplete in\n// OPPOSITE directions, which is the clearest argument for a shared one that\n// this review has produced:\n//\n// - Patterpad runs an INTERVAL (one timer for the app's life, saving any\n// dirty scene every N seconds). Continuous typing is saved throughout, but\n// a single edit can sit unwritten for the whole period.\n// - Storyletter DEBOUNCES (write 700ms after edits settle). A single edit is\n// written promptly, but an author typing steadily is never written at all\n// until they pause - which on a long paragraph is a long time.\n//\n// So this does both: debounce for promptness, with a MAXIMUM AGE so a run of\n// edits cannot outrun the writer. Neither app had the pair; each had half.\n//\n// The other thing neither had is re-entrancy. Storyletter's flush cleared its\n// pending queue and then awaited the write, so a flush arriving mid-write saw\n// nothing pending and reported \"saved\" while bytes were still in the air. Here\n// a write in flight is a thing you can await, and the status is only \"saved\"\n// when nothing arrived while it was running.\n//\n// WHAT THIS DOES NOT OWN is what a save IS. The controller never touches the\n// document: it calls the app's `write` and reads its boolean. What is pending,\n// how it coalesces, what to repaint afterwards - all of that stays in the app,\n// because all of it is about the app's model.\n//\n// DOM-free, so a test can drive it with fake timers and no window.\n// ---------------------------------------------------------------------------\n\n/**\n * Three states, not a boolean.\n *\n * \"saving\" earns its place: on a slow disk or a slow VC hook a save takes long\n * enough to see, and a status that flips straight from unsaved to saved leaves\n * the author wondering whether the click did anything.\n */\nexport type SaveStatus = \"saved\" | \"unsaved\" | \"saving\";\n\nexport interface SaveControllerOptions {\n /**\n * Write whatever is pending. Return false if it failed: the controller stays\n * \"unsaved\" and will try again on the next touch or flush, rather than\n * quietly reporting success over a write that did not happen.\n *\n * Called only when something is pending, and never twice at once.\n */\n write: () => Promise<boolean> | boolean;\n /** Told every time the status changes, and only when it changes. */\n onStatus?: (status: SaveStatus) => void;\n /** How long after the last edit to write. Storyletter's 700ms by default. */\n delayMs?: number;\n /**\n * The longest an edit may go unwritten while more keep arriving.\n *\n * This is the interval half of the two apps put back in: without it, steady\n * typing defers the write for as long as the typing lasts.\n */\n maxWaitMs?: number;\n}\n\nexport interface SaveController {\n /** What the indicator should say. */\n readonly status: SaveStatus;\n /** Is anything unwritten? For a close guard, or an updater asking whether it\n * may restart. True while a write is in flight, too: it is not on disk yet. */\n readonly pending: boolean;\n /** Something changed. Starts (or extends) the countdown. */\n touch(): void;\n /**\n * Write now, and wait for it.\n *\n * Call on every transition that must see current bytes: switching what is\n * being edited, opening a tool window that reads the disk, closing the\n * window, Cmd+S. Safe to call when nothing is pending (it does nothing) and\n * safe to call during a write (it waits for it, then writes again if more\n * arrived while it ran).\n */\n flush(): Promise<void>;\n /** Give up on what is pending without writing it. For a project close after\n * the author has said to discard, and for teardown. */\n cancel(): void;\n /**\n * Autosave on or off (Patterpad's per-project setting).\n *\n * Off does not mean \"never write\": touch() still marks the work unsaved, and\n * flush() still writes on transitions and on Cmd+S. It only stops the clock.\n */\n setAuto(on: boolean): void;\n}\n\nexport function createSaveController(opts: SaveControllerOptions): SaveController {\n const delayMs = opts.delayMs ?? 700;\n const maxWaitMs = opts.maxWaitMs ?? 5000;\n\n let status: SaveStatus = \"saved\";\n let auto = true;\n let dirty = false;\n /** When the oldest unwritten edit arrived, for the maximum age. */\n let dirtySince = 0;\n let timer: ReturnType<typeof setTimeout> | undefined;\n /** The write in flight, so a second flush awaits it instead of racing it. */\n let inFlight: Promise<void> | undefined;\n\n const setStatus = (next: SaveStatus): void => {\n if (next === status) return;\n status = next;\n opts.onStatus?.(status);\n };\n\n const clearTimer = (): void => {\n if (timer === undefined) return;\n clearTimeout(timer);\n timer = undefined;\n };\n\n const arm = (): void => {\n clearTimer();\n if (!auto) return;\n // Never later than maxWaitMs after the first unwritten edit, however much\n // longer the author keeps typing.\n const deadline = dirtySince + maxWaitMs;\n const wait = Math.max(0, Math.min(delayMs, deadline - Date.now()));\n timer = setTimeout(() => { timer = undefined; void run(); }, wait);\n };\n\n const run = async (): Promise<void> => {\n if (inFlight) return inFlight; // one writer at a time\n if (!dirty) { setStatus(\"saved\"); return; }\n clearTimer();\n dirty = false;\n setStatus(\"saving\");\n inFlight = (async () => {\n let ok = false;\n try {\n ok = await opts.write();\n } catch {\n // A thrown write is a failed write. The app has already said whatever\n // it wants to say about it; here it only means \"still unsaved\".\n ok = false;\n }\n if (!ok) {\n // Put the dirt back so the next touch or flush retries, and keep the\n // oldest timestamp: a failing save must not reset the maximum age.\n if (!dirty) { dirty = true; dirtySince = dirtySince || Date.now(); }\n }\n setStatus(dirty ? \"unsaved\" : \"saved\");\n if (dirty) arm(); // more arrived while we wrote, or it failed\n })();\n try {\n await inFlight;\n } finally {\n inFlight = undefined;\n }\n };\n\n return {\n get status() { return status; },\n get pending() { return dirty || inFlight !== undefined; },\n touch() {\n if (!dirty) dirtySince = Date.now();\n dirty = true;\n // An edit arriving mid-write leaves the status alone: a write really is\n // running, and it will settle to \"unsaved\" on its own when it lands.\n if (!inFlight) setStatus(\"unsaved\");\n arm();\n },\n async flush() {\n // Await a write already running, then write again if this call's work (or\n // anything that arrived mid-write) is still outstanding.\n if (inFlight) await inFlight;\n if (dirty) await run();\n else setStatus(\"saved\");\n },\n cancel() {\n clearTimer();\n dirty = false;\n setStatus(inFlight ? \"saving\" : \"saved\");\n },\n setAuto(on) {\n auto = on;\n if (on) { if (dirty) arm(); } else clearTimer();\n },\n };\n}\n","// ---------------------------------------------------------------------------\n// The save indicator: the six lines that draw what `createSaveController`\n// already computes.\n//\n// The controller has been shared since 0.14.0 and its three states with it, but\n// the DRAWING stayed in each app - so both apps hand-rendered the output of one\n// machine and promptly drifted. Patterpad's was `<span id=\"dirty\" hidden>●\n// unsaved</span>`: present only when there was something to worry about.\n// Storyletter's always paints one of Saved / Saving… / Unsaved. (Design review\n// 2026-08, A4.)\n//\n// STORYLETTER'S WON, and the reasoning is worth keeping because it is not\n// \"newer is better\". Three states are what the shared controller models, and an\n// app that autosaves without being asked owes the author the reassurance as\n// well as the warning: a dot that only ever appears to worry you leaves \"did\n// that get written?\" unanswered at exactly the moment it is asked. \"Saving…\"\n// earns its place separately - on a slow disk or a slow version-control hook a\n// write takes long enough to see.\n//\n// It cannot drift again, which is the actual point of putting it here.\n// ---------------------------------------------------------------------------\n\nimport { el } from \"./dom.js\";\nimport type { SaveStatus } from \"./save.js\";\n\nexport interface SaveIndicator {\n /** Put it in the topbar. */\n readonly el: HTMLElement;\n /** Wire straight to the controller's `onStatus`. */\n set(status: SaveStatus): void;\n}\n\n/** What each state says. Not an option: two apps saying it differently is the\n * drift this exists to end. */\nconst WORDS: Record<SaveStatus, string> = {\n saved: \"Saved\",\n saving: \"Saving…\",\n unsaved: \"Unsaved\",\n};\n\nexport function saveIndicator(initial: SaveStatus = \"saved\"): SaveIndicator {\n const node = el(\"span\");\n const set = (status: SaveStatus): void => {\n node.className = `savestat ${status}`;\n node.textContent = WORDS[status];\n };\n set(initial);\n return { el: node, set };\n}\n","// ---------------------------------------------------------------------------\n// The stale-session bar: \"what you are playing is older than the project\".\n//\n// Both apps grew one without copying the other, and landed within a word of the\n// same sentence - Patterpad's \"Scene changed in the editor: restart to play the\n// new version\", Storyletter's \"The project changed in the editor. Restart to\n// play the new version.\" That is the strongest evidence a thing is shape-level\n// rather than a taste: any app that compiles a document into something you then\n// PLAY has a running session that can fall behind its source, and the only two\n// things it can say are what went out of date and how to start again.\n//\n// So the app supplies the NOUN and the callback, and nothing else. Everything\n// left over - the warn-toned banner, the sentence, the restart glyph - is the\n// shape, and having it in one place is what stops the two apps drifting to two\n// wordings for one situation.\n//\n// WHOSE DRAWING WON, since the two differed here where the words did not.\n// Patterpad's was a line of centred grey text in the choice tray; Storyletter's\n// is a bordered warn-toned bar with the button in it. The bar, because this is\n// a condition rather than a remark: the session is frozen until you act, and a\n// note that reads like the end of a passage does not say so.\n// ---------------------------------------------------------------------------\n\nimport { el } from \"./dom.js\";\nimport { iconNode } from \"./icons.js\";\n\nexport interface StaleBarOptions {\n /**\n * What went out of date, as a capitalised noun phrase: \"The project\", \"The\n * scene\". Written into \"<subject> changed in the editor.\"\n */\n subject: string;\n /** Start again from the current source. */\n onRestart: () => void;\n /** The button, when \"Restart\" is not the app's word for it. */\n restartLabel?: string;\n /**\n * The rest of the sentence, for an app whose session is not a PLAY: the\n * default is \"Restart to play the new version.\"\n */\n advice?: string;\n}\n\nexport function staleBar(opts: StaleBarOptions): HTMLElement {\n const label = opts.restartLabel ?? \"Restart\";\n return el(\"div\", { className: \"stale-bar\" },\n el(\"span\", { className: \"stale-bar-msg\",\n text: `${opts.subject} changed in the editor. ${opts.advice ?? \"Restart to play the new version.\"}` }),\n // The icon is a node beside the word, not a character inside it; the\n // button's flex gap sets the space (stale.css).\n el(\"button\", { className: \"stale-bar-go\", onClick: () => opts.onRestart() },\n iconNode(\"restart\", 12), label),\n );\n}\n","// ---------------------------------------------------------------------------\n// The toast: a transient remark from the app - \"Bundle published\", \"Save\n// refused: ...\", \"Spell-check is off\" - that shows itself, waits, and leaves.\n//\n// Both apps grew one without copying the other, and drifted on everything a\n// toast can drift on. Patterpad's sat bottom-right, an outlined card on the\n// surface colour, entered and left on the shared panel motion, lingered longer\n// for an error, and announced itself to a screen reader. Storyletter's sat\n// bottom-centre, a solid --danger or --ok block with surface-coloured text, had\n// no motion, one duration, and no ARIA. Same three sentences either side.\n//\n// WHOSE DRAWING WON, and why, since the two differed here in every particular:\n//\n// PLACE: bottom-right. A toast is a REMARK, not a condition (that is the stale\n// bar's job), and a remark must not sit over what the author is reading or\n// typing. Bottom-centre lands on the centre column in the editor and on the\n// choice tray in Play; the corner is out of the reading measure, and it is\n// where the platforms put their own notifications, so the eye already knows\n// to glance there and back.\n//\n// COLOUR: an outlined card on --surface, with the KIND carried by the border\n// and the text colour. A solid block of --danger shouts, and the design\n// language asks for restraint at the seams; the card also keeps its text as\n// --ink, which reads on every palette without each one having to tune a\n// contrast pair for white-on-red.\n//\n// TIME: 4s, 7s for an error. Something went wrong is worth an extra glance.\n//\n// MOTION: the shared panel vocabulary in tokens.css, in and out, so a toast\n// moves the way every other transient surface in the family moves.\n//\n// One toast at a time: a new one replaces the old, never stacks. Rapid events\n// (a burst of saves) would otherwise pile up a column of remarks about one\n// moment. The dismiss checks it is still dismissing the CURRENT toast, so a\n// replacement is never hidden by its predecessor's timer.\n//\n// Mounted by the module, not by host markup: it appends its own node to\n// document.body on first use, so a second window gets the whole thing by\n// importing it (multi-window-rules.md section 1). Its CSS travels beside it.\n// ---------------------------------------------------------------------------\n\nimport { el } from \"./dom.js\";\nimport { closeWithExit } from \"./exit.js\";\n\n/** What the remark is about. `info` is the plain case; `ok` says a thing you\n * asked for happened; `error` says it did not. */\nexport type ToastKind = \"info\" | \"ok\" | \"error\";\n\nexport interface ToastOptions {\n /** How long it stays, in ms, before the exit plays. Defaults to 4000, or\n * 7000 for an error. */\n duration?: number;\n}\n\nconst DURATION: Record<ToastKind, number> = { info: 4000, ok: 4000, error: 7000 };\n\nlet node: HTMLElement | undefined;\nlet timer = 0;\nlet seq = 0;\n\nfunction mount(): HTMLElement {\n if (node && node.isConnected) return node;\n // role=status + aria-live=polite: announced without interrupting, which is\n // exactly a toast's manners.\n node = el(\"div\", { className: \"shell-toast\" });\n node.setAttribute(\"role\", \"status\");\n node.setAttribute(\"aria-live\", \"polite\");\n node.hidden = true;\n document.body.append(node);\n return node;\n}\n\n/**\n * Show a toast. Replaces any toast already showing.\n *\n * `message` is shown as written; a newline breaks the line (\"Bundle\n * published\\n<path>\"), and a long unbroken token such as a path wraps inside\n * the card rather than spilling past it.\n */\nexport function toast(message: string, kind: ToastKind = \"info\", opts: ToastOptions = {}): void {\n const t = mount();\n const id = ++seq;\n t.textContent = message;\n t.className = `shell-toast ${kind}`; // also clears a `.closing` left by a prior dismiss\n t.hidden = false;\n window.clearTimeout(timer);\n timer = window.setTimeout(() => {\n // Only hide if this is still the toast that set the timer: a replacement\n // that arrived meanwhile has its own.\n closeWithExit(t, () => { if (seq === id) t.hidden = true; });\n }, opts.duration ?? DURATION[kind]);\n}\n\n/** Dismiss the current toast now, if any. Plays the exit. */\nexport function dismissToast(): void {\n if (!node || node.hidden) return;\n window.clearTimeout(timer);\n const id = seq;\n const t = node;\n closeWithExit(t, () => { if (seq === id) t.hidden = true; });\n}\n","// ---------------------------------------------------------------------------\n// The stepper bar: a bottom bar that walks you through a list of things to\n// attend to, one at a time.\n//\n// Count, previous, position, next, the current thing as a button, and a slot at\n// the right for whatever acts on it. That is the whole shape, and it is already\n// four bars across two apps: Patterpad's problems bar and its review walk,\n// Storyletter's problems bar and its Review Feedback walk. Patterpad drew its\n// two with parallel class sets (`.problembar-*` and `.reviewbar-*`) for one\n// idea; Storyletter drew its second as the first plus one modifier, which is\n// the better rule and the reason this ended up here (design review 2026-08,\n// section 5 items 2 and 3).\n//\n// NO DOMAIN WORD anywhere in it, which is the test that says it belongs in the\n// shell rather than in either app. It knows about a list, an index, and three\n// pieces of text per entry; it does not know what a problem or a comment is.\n// Severity, resolvedness and quick fixes all arrive as strings and elements the\n// app made.\n//\n// TWO THINGS PATTERPAD'S BARS LACK and gain by adopting this: the position\n// readout (`3/11`, so the walk has a length and an end rather than just a next),\n// and the `where` segment naming what the entry is about before you go there.\n//\n// STEPPING NAVIGATES, or does not: that is the CALLER's decision and this bar\n// takes no view. It reports `onStep` and `onGo` and nothing more. The rule that\n// settles it lives in design-language.md - an ambient surface moves the view and\n// never the focus; a mode you entered may take you somewhere - and the guard for\n// an uncommitted edit belongs to the app, because only the app knows what is\n// unsaved.\n// ---------------------------------------------------------------------------\n\nimport { el } from \"./dom.js\";\nimport { iconNode } from \"./icons.js\";\n\nexport interface StepperItem {\n /**\n * One word for what kind of thing this is: \"error\", \"comment\", \"resolved\".\n * Absent when the bar carries one kind of thing only.\n */\n kind?: string;\n /** An extra class on the kind chip, so an app can colour its own kinds\n * (Storyletter's `sev-error`, and `done` for a resolved thread). */\n kindClass?: string;\n /** Where it is. A string is the app's own address, set in the mono face; a\n * Node is a made element, a `breadcrumb([\"Box\", \"Deck\", \"Card\"])` say,\n * drawn as it is. Give the bar plain crumbs: the whole entry is already\n * the button that goes there, so a crumb with its own click has nowhere\n * else to take you. */\n where?: string | Node;\n /** The entry itself, in one line. Overflow is clipped, not wrapped: the bar\n * is one row high and stays that way however long the sentence is. */\n text: string;\n}\n\n/** How loud the count is. The app picks; the palette supplies the value. */\nexport type StepperTone = \"danger\" | \"warn\" | \"accent\" | \"muted\";\n\nexport interface StepperBarOptions {\n items: StepperItem[];\n /** Which one is current. Clamped, so a shrinking list cannot point off the end. */\n at: number;\n tone?: StepperTone;\n /** Go to another index. The bar wraps, so this is always in range. */\n onStep: (next: number) => void;\n /** Take me to what the current entry is about. */\n onGo: (index: number) => void;\n /** What the three controls say they do. Keyboard shortcuts belong in here. */\n tips?: { prev?: string; next?: string; go?: string };\n /**\n * What to say when the list is empty.\n *\n * Absent hides the bar, which is right for an AMBIENT bar: no problems, no\n * problems bar. Present keeps it up, which is right for a MODE: entering the\n * walk and seeing nothing at all reads as a broken command rather than as\n * \"there is no feedback\".\n */\n empty?: string;\n /** Leave the mode. Drawn as the last control, hard right. */\n onClose?: () => void;\n closeTip?: string;\n /** The right-hand end before the close: a quick fix, say. Nulls are skipped,\n * so a caller can pass a conditional straight in. */\n actions?: (HTMLElement | null | undefined)[];\n}\n\nconst STEP_ICON = 12;\n\n/** Draw (or hide) the bar in `host`. Idempotent: call it again with new state. */\nexport function renderStepperBar(host: HTMLElement, opts: StepperBarOptions): void {\n const { items } = opts;\n // 12px inside the bar's 20px control: the bar is set at 0.8rem.\n const close = opts.onClose === undefined ? null : el(\"button\", {\n className: \"stepbar-nav stepbar-close\",\n tip: opts.closeTip ?? \"Close\", onClick: opts.onClose,\n }, iconNode(\"close\", STEP_ICON));\n const actions = (opts.actions ?? []).filter((a): a is HTMLElement => a !== null && a !== undefined);\n\n if (items.length === 0) {\n if (opts.empty === undefined) { host.hidden = true; host.replaceChildren(); return; }\n host.hidden = false;\n host.replaceChildren(\n el(\"span\", { className: \"stepbar-count muted\", text: \"0\" }),\n el(\"span\", { className: \"stepbar-empty\", text: opts.empty }),\n ...actions, ...(close ? [close] : []),\n );\n return;\n }\n\n host.hidden = false;\n const index = Math.min(Math.max(opts.at, 0), items.length - 1);\n const item = items[index]!;\n const step = (delta: number): void => opts.onStep((index + delta + items.length) % items.length);\n\n // The steppers are absent for a list of one: two arrows that both come back\n // to where you are is furniture pretending to be a control.\n const nav = items.length > 1\n ? [\n el(\"button\", { className: \"stepbar-nav\",\n tip: opts.tips?.prev ?? \"Previous\", onClick: () => step(-1) }, iconNode(\"back\", STEP_ICON)),\n el(\"span\", { className: \"stepbar-of\", text: `${index + 1}/${items.length}` }),\n el(\"button\", { className: \"stepbar-nav\",\n tip: opts.tips?.next ?? \"Next\", onClick: () => step(1) }, iconNode(\"forward\", STEP_ICON)),\n ]\n : [];\n\n host.replaceChildren(\n el(\"span\", { className: `stepbar-count ${opts.tone ?? \"muted\"}`, text: String(items.length) }),\n ...nav,\n el(\"button\", { className: \"stepbar-cur\", tip: opts.tips?.go ?? \"Go to this\", onClick: () => opts.onGo(index) },\n item.kind === undefined ? null\n : el(\"span\", { className: `stepbar-cat${item.kindClass ? ` ${item.kindClass}` : \"\"}`, text: item.kind }),\n item.where === undefined ? null\n : typeof item.where === \"string\" ? el(\"span\", { className: \"stepbar-where\", text: item.where })\n : el(\"span\", \"stepbar-where\", item.where),\n el(\"span\", { className: \"stepbar-msg\", text: item.text }),\n ),\n ...actions, ...(close ? [close] : []),\n );\n}\n","// ---------------------------------------------------------------------------\n// The updater's VIEW: the themed prompt main summons over `updater:prompt`\n// (updater.ts) and reads the chosen button index back from, the same contract\n// as dialog.showMessageBox's `response`. The renderer half of the updater is\n// not optional: an unanswered prompt does not fall back to a native dialog,\n// the shell waits 300 seconds and resolves its own fallback index. Both apps\n// had written this view by hand (55 of 60 lines identical); this is the one\n// they share, on the family's dialog frame, the way save.ts has save-view.ts.\n//\n// Storyletter's copy, plus Patterpad's `links` row as an option (an About box\n// used to share this dialog there). Styles ship as updater.css.\n// ---------------------------------------------------------------------------\n\nimport { el } from \"./dom.js\";\nimport { dialogFrame } from \"./dialog.js\";\nimport type { UpdaterDownloadProgress, UpdaterPromptOptions } from \"./updater.js\";\n\nexport interface UpdaterLink { label: string; url: string }\n\nexport interface UpdaterViewOptions extends UpdaterPromptOptions {\n /** Web links under the detail. Opened through `openExternal`, never by\n * navigating the window. */\n links?: UpdaterLink[];\n /** How a link opens (the app's allow-listed shell.openExternal bridge).\n * Required for `links` to do anything. */\n openExternal?: (url: string) => void;\n}\n\n// The progress row of the open `progress: true` dialog, if any. These are\n// modal, so one at a time, so one slot is enough. Closing clears it.\nlet liveProgress: { bar: HTMLElement; label: HTMLElement } | null = null;\n\nconst mb = (n: number): string => (n / (1024 * 1024)).toFixed(1);\n\n/** Route a download-progress tick into the open dialog's bar. No-op when none\n * is showing. Registered once at boot on the app's progress channel. */\nexport function feedUpdaterDownloadProgress(p: UpdaterDownloadProgress): void {\n if (!liveProgress) return;\n const pct = Math.max(0, Math.min(100, p.percent));\n liveProgress.bar.style.width = `${pct}%`;\n liveProgress.label.textContent =\n `${pct.toFixed(0)}%, ${mb(p.transferred)} of ${mb(p.total)} MB (${mb(p.bytesPerSecond)} MB/s)`;\n}\n\n/** Show the prompt as a modal themed dialog; resolve the index of the clicked\n * button (Esc resolves `cancelId`, which defaults to the last button). */\nexport function showUpdaterDialog(opts: UpdaterViewOptions): Promise<number> {\n return new Promise((resolve) => {\n const defaultId = opts.defaultId ?? 0;\n const cancelId = opts.cancelId ?? opts.buttons.length - 1;\n\n let done = false;\n const finish = (idx: number): void => {\n if (done) return;\n done = true;\n liveProgress = null; // stop feeding a dialog that is gone\n resolve(idx);\n frame.close();\n };\n const frame = dialogFrame({\n title: opts.message, className: \"updater-dialog\",\n // Esc is the cancel button, not a further answer: main is waiting on an index.\n onClose: () => finish(cancelId),\n });\n if (opts.detail) frame.body.append(el(\"p\", \"updater-detail\", opts.detail));\n\n if (opts.progress) {\n const track = el(\"div\", \"updater-progress-track\");\n const bar = el(\"div\", \"updater-progress-bar\");\n track.append(bar);\n const label = el(\"p\", \"updater-progress-label\", \"Starting download…\");\n frame.body.append(track, label);\n liveProgress = { bar, label };\n }\n\n if (opts.links?.length) {\n const row = el(\"p\", \"updater-links\");\n for (const link of opts.links) {\n const a = el(\"a\", undefined, link.label);\n a.href = link.url;\n a.addEventListener(\"click\", (e) => { e.preventDefault(); opts.openExternal?.(link.url); });\n row.append(a);\n }\n frame.body.append(row);\n }\n\n opts.buttons.forEach((label, i) => {\n // The default is the affirmative and wears the accent; every other\n // button, the way out included, is the plain one.\n const b = el(\"button\", i === defaultId ? \"btn primary\" : \"btn\", label);\n b.type = \"button\";\n b.addEventListener(\"click\", () => finish(i));\n frame.actions.append(b);\n if (i === defaultId) queueMicrotask(() => b.focus());\n });\n\n frame.open();\n });\n}\n","// ---------------------------------------------------------------------------\n// The kit gallery: pick a starting point by what you want to make.\n//\n// The new-thing moment for the family (New Project, New Box, New Scene), drawn\n// once. Adobe's New Document is the shape: tiles on the left, a details panel\n// on the right, one screen. Not a wizard: a wizard asks for settings before\n// anything has been chosen, and the choice is the part that teaches.\n//\n// Storyletter grew this as `kit-picker.ts` (one component at two scales on\n// <dialog>, \"a shell candidate, held back until it had been used in earnest\")\n// and the kit gallery brief moved it here, 2026-09-27\n// (storylet-studio/design/kit-gallery.md). What a kit IS made of stays in\n// each app: this file knows names, words and pictures, never boxes or scenes.\n//\n// Sections are shelves (\"Start from a kit\", \"Learn from a finished project\"),\n// and each says what its button does, because opening a copy of an example\n// and creating from a kit are different acts behind the same kind of tile.\n// The app's own fields (a project name, version control, a build path) sit in\n// the details panel, shown only for the sections that use them.\n// ---------------------------------------------------------------------------\n\nimport { el } from \"./dom.js\";\nimport { dialogFrame } from \"./dialog.js\";\n\nexport interface KitGalleryItem<T extends string> {\n id: T;\n /** What you are making, in the author's terms, not the model's. */\n name: string;\n /** What it is FOR: the panel's first line, and the tile's unless `tile` says otherwise. */\n blurb: string;\n /** The tile's line, when the blurb is longer than a tile holds (three\n * lines). A whole short sentence reads better than a long one cut off. */\n tile?: string;\n /** More, for the panel only. */\n detail?: string;\n /** What pressing Play (or Run) shows, said as a promise. */\n play?: string;\n /** The model's parts it puts to work, second and quieter (\"Shows: ...\"). */\n shows?: string;\n /** What lands, in the concrete, as a short list in the panel. */\n lands?: string[];\n /** A word or two on the tile (\"Start here\"). */\n badge?: string;\n /** An illustration: a transparent image whose opaque pixels are the ink.\n * Drawn as a mask in `--kit-art-ink` on `--kit-art-plate`, so one file\n * serves both themes and the app chooses the colours. */\n image?: string;\n}\n\nexport interface KitGallerySection<T extends string> {\n /** Sentence-case label text (\"Start from a kit\"). Absent: no caption. */\n caption?: string;\n /** The consequence of a click, said before the click. */\n note?: string;\n items: KitGalleryItem<T>[];\n /** The primary button's label while an item here is chosen. Default \"Create\". */\n action?: string;\n /** Show the app's detail fields (and ask for the name) for this section.\n * Default true. An example is opened, not named, so its shelf says false. */\n usesDetails?: boolean;\n}\n\nexport interface KitGalleryChoice {\n /** Present when a name was asked for and the chosen section uses details. */\n name?: string;\n}\n\nexport interface KitGalleryOptions<T extends string> {\n /** The dialog's heading: \"New project\", \"New box\", \"New scene\". */\n title: string;\n /** What the thing being made IS, in concrete terms. */\n what?: string;\n sections: KitGallerySection<T>[];\n /** Ask for a name in the details panel, with this placeholder. Required\n * when asked: making a thing without one would have to invent a folder. */\n namePlaceholder?: string;\n /** The name field's label. Default \"Name\". */\n nameLabel?: string;\n /** The app's own fields, below the name (version control, a build path). */\n details?: HTMLElement;\n /** Runs whenever an item is chosen, the opening one included, so the app can show or hide its\n * own fields for it (New Scene's Speaker, for a kit with lines). */\n onChoose?: (id: T) => void;\n /** Checked before `onPick`, after the name: return the app's field that still needs filling (it\n * is focused and marked, and nothing is made), or null when all is well. */\n validate?: (id: T) => HTMLElement | null;\n /** Runs as the name is typed (and once on open, with \"\"), so the app's own\n * fields can follow it: Patterpad's folder preview and default publish path. */\n onNameInput?: (name: string) => void;\n /** The item chosen when the gallery opens. Default: the first. */\n initial?: T;\n onPick: (id: T, choice: KitGalleryChoice) => void;\n /** Runs once the gallery has closed, whichever way. */\n onClose?: () => void;\n}\n\nexport interface KitGallery {\n readonly dialog: HTMLDialogElement;\n close(): void;\n}\n\n/** Draw `image` into an art box as a mask (see kit-gallery.css), or hide the box. */\nfunction setArt(host: HTMLElement, image: string | undefined): void {\n host.replaceChildren();\n host.hidden = image === undefined;\n if (image === undefined) return;\n const ink = el(\"span\", \"kit-gallery-ink\");\n ink.style.setProperty(\"--kit-art\", `url(\"${image.replace(/\"/g, \"%22\")}\")`);\n host.append(ink);\n}\n\n/** One tile: the picture, the name with its badge, the blurb. The gallery's\n * own, and the welcome screen's, so a kit looks the same wherever it is met\n * (welcome.ts draws a tiled group with it; import kit-gallery.css there too). */\nexport function kitTile(item: { name: string; blurb: string; badge?: string; image?: string }, onClick: () => void): HTMLButtonElement {\n const art = el(\"div\", \"kit-gallery-art\");\n setArt(art, item.image);\n const tile = el(\"button\", { className: \"kit-gallery-tile\", onClick },\n art,\n el(\"span\", \"kit-gallery-tile-head\",\n el(\"span\", \"kit-gallery-tile-name\", item.name),\n item.badge !== undefined ? el(\"span\", \"kit-gallery-badge\", item.badge) : null),\n el(\"span\", \"kit-gallery-tile-blurb\", item.blurb)) as HTMLButtonElement;\n tile.type = \"button\";\n return tile;\n}\n\n/** Open the gallery as a modal dialog on the family's frame. */\nexport function openKitGallery<T extends string>(opts: KitGalleryOptions<T>): KitGallery {\n const frame = dialogFrame({ title: opts.title, ...(opts.what !== undefined ? { sub: opts.what } : {}), className: \"kit-gallery\", ...(opts.onClose ? { onClose: opts.onClose } : {}) });\n const { dialog } = frame;\n\n const entries = opts.sections.flatMap((section, s) => section.items.map((item) => ({ item, section, s })));\n if (entries.length === 0) throw new Error(\"openKitGallery: no items to choose from\");\n let chosen = entries.find((e) => e.item.id === opts.initial) ?? entries[0]!;\n\n // --- the details panel ----------------------------------------------------\n const nameInput = opts.namePlaceholder === undefined ? undefined : el(\"input\", { className: \"field kit-gallery-name\" }) as HTMLInputElement;\n if (nameInput) {\n nameInput.placeholder = opts.namePlaceholder!;\n nameInput.setAttribute(\"aria-label\", opts.nameLabel ?? \"Name\");\n }\n const fields = el(\"div\", \"kit-gallery-fields\",\n ...(nameInput ? [el(\"label\", \"kit-gallery-label\", opts.nameLabel ?? \"Name\"), nameInput] : []),\n ...(opts.details ? [opts.details] : []));\n\n const panelArt = el(\"div\", \"kit-gallery-art kit-gallery-panel-art\");\n const panelName = el(\"h3\", \"kit-gallery-panel-name\");\n const panelBlurb = el(\"p\", \"kit-gallery-panel-blurb\");\n const panelDetail = el(\"p\", \"kit-gallery-panel-detail\");\n const panelPlay = el(\"p\", \"kit-gallery-play\");\n const panelShows = el(\"p\", \"kit-gallery-shows\");\n const panelLands = el(\"ul\", \"kit-gallery-lands\");\n const panelLandsCaption = el(\"p\", \"kit-gallery-lands-caption\", \"What you get\");\n const panelNote = el(\"p\", \"kit-gallery-note\");\n const panel = el(\"div\", \"kit-gallery-panel\",\n panelArt, panelName, panelBlurb, panelDetail, panelPlay, panelShows, panelLandsCaption, panelLands, panelNote, fields);\n\n const primary = el(\"button\", { className: \"btn primary\", onClick: () => commit() }) as HTMLButtonElement;\n primary.type = \"button\";\n const cancel = el(\"button\", { className: \"btn\", text: \"Cancel\", onClick: () => frame.close() }) as HTMLButtonElement;\n cancel.type = \"button\";\n\n const setText = (node: HTMLElement, text: string | undefined): void => {\n node.textContent = text ?? \"\";\n node.hidden = text === undefined || text === \"\";\n };\n\n // --- the tiles --------------------------------------------------------------\n const tiles = new Map<T, HTMLButtonElement>();\n const shelves = opts.sections.map((section) => {\n const grid = el(\"div\", \"kit-gallery-grid\", ...section.items.map((item) => {\n const tile = kitTile({ ...item, blurb: item.tile ?? item.blurb }, () => choose(item.id));\n tile.dataset.kit = item.id;\n // Double-click is the desktop's \"choose and go\"; a single click only chooses,\n // so a tile can be read in the panel before anything is made.\n tile.addEventListener(\"dblclick\", () => { choose(item.id); commit(); });\n tiles.set(item.id, tile);\n return tile;\n }));\n return el(\"section\", \"kit-gallery-shelf\",\n section.caption !== undefined ? el(\"h3\", \"kit-gallery-caption\", section.caption) : null,\n section.note !== undefined ? el(\"p\", \"kit-gallery-shelf-note\", section.note) : null,\n grid);\n });\n\n const choose = (id: T): void => {\n const next = entries.find((e) => e.item.id === id);\n if (!next) return;\n chosen = next;\n for (const [tid, tile] of tiles) tile.setAttribute(\"aria-pressed\", String(tid === id));\n const { item, section } = chosen;\n setArt(panelArt, item.image);\n panelName.textContent = item.name;\n setText(panelBlurb, item.blurb);\n setText(panelDetail, item.detail);\n setText(panelPlay, item.play);\n setText(panelShows, item.shows !== undefined ? `Shows: ${item.shows}` : undefined);\n panelLands.replaceChildren(...(item.lands ?? []).map((l) => el(\"li\", undefined, l)));\n panelLands.hidden = (item.lands ?? []).length === 0;\n panelLandsCaption.hidden = panelLands.hidden;\n const details = section.usesDetails !== false;\n fields.hidden = !details || (nameInput === undefined && opts.details === undefined);\n // Without the fields, the shelf's note is what the click will do next\n // (\"a folder you choose\"), so the panel repeats it beside the button.\n setText(panelNote, details ? undefined : section.note);\n primary.textContent = section.action ?? \"Create\";\n opts.onChoose?.(item.id);\n };\n\n const commit = (): void => {\n const { item, section } = chosen;\n const details = section.usesDetails !== false;\n let name: string | undefined;\n if (details && nameInput) {\n name = nameInput.value.trim();\n if (name === \"\") { nameInput.focus(); nameInput.classList.add(\"kit-gallery-missing\"); return; }\n }\n const missing = opts.validate?.(item.id) ?? null;\n if (missing) {\n missing.classList.add(\"kit-gallery-missing\");\n missing.addEventListener(\"input\", () => missing.classList.remove(\"kit-gallery-missing\"), { once: true });\n missing.focus();\n return;\n }\n frame.close();\n opts.onPick(item.id, name !== undefined ? { name } : {});\n };\n\n if (nameInput) {\n nameInput.addEventListener(\"input\", () => {\n nameInput.classList.remove(\"kit-gallery-missing\");\n opts.onNameInput?.(nameInput.value);\n });\n opts.onNameInput?.(\"\");\n // Enter creates with what is chosen: the author has said what it should be\n // called, and the tile they are looking at is the one they meant.\n nameInput.addEventListener(\"keydown\", (e) => {\n e.stopPropagation();\n if (e.key !== \"Enter\") return;\n e.preventDefault();\n commit();\n });\n }\n\n frame.body.append(el(\"div\", \"kit-gallery-layout\", el(\"div\", \"kit-gallery-shelves\", ...shelves), panel));\n frame.actions.append(cancel, primary);\n dialog.addEventListener(\"click\", (e) => { if (e.target === dialog) frame.close(); });\n\n choose(chosen.item.id);\n frame.open();\n // Focus where the next keystroke is wanted: the name when one is asked for\n // and the opening shelf uses it, otherwise the chosen tile.\n if (nameInput && chosen.section.usesDetails !== false) nameInput.focus();\n else tiles.get(chosen.item.id)?.focus();\n\n return { dialog, close: () => frame.close() };\n}\n","// ---------------------------------------------------------------------------\n// The welcome screen: what an app shows with no project open. Title, one line\n// under it, the actions (Open, New), an optional teaching line, optional\n// captioned groups (Storyletter's shipped examples), and the recents.\n//\n// Both apps drew this with the same twelve CSS rules under two class prefixes\n// (`.recent-name` / `.wel-recent-name`), four of them byte-identical. The CSS\n// here is Patterpad's; the captioned groups are Storyletter's, as an optional\n// slot, drawn as a plain list of rows (name + hint) rather than cards.\n//\n// The whole screen is a drag region (the window has no title bar to grab\n// here) and every control opts out. Styles ship as welcome.css.\n// ---------------------------------------------------------------------------\n\nimport { el } from \"./dom.js\";\nimport { kitTile } from \"./kit-gallery.js\";\n\nexport interface WelcomeAction {\n label: string;\n onClick: () => void;\n /** The one accent button (Open a project…). */\n primary?: boolean;\n}\n\nexport interface WelcomeRecent {\n /** What the project calls itself, with the folder stem as the fallback. */\n name: string;\n /** Beside the name, because two projects may share a name and the folder\n * is how you tell them apart. */\n path: string;\n onOpen: () => void;\n}\n\nexport interface WelcomeGroupItem {\n name: string;\n /** What choosing it gets you, said before the click. */\n hint?: string;\n /** Tiled groups only: a word or two beside the name (\"Start here\"). */\n badge?: string;\n /** Tiled groups only: the picture, as the kit gallery draws it. */\n image?: string;\n onOpen: () => void;\n}\n\nexport interface WelcomeGroup {\n /** Sentence-case label text (\"Learn from a finished project\"); never an overline. */\n caption: string;\n /** The consequence of a click, said before the click (\"Each opens as your\n * own copy, in a folder you choose.\"). */\n note?: string;\n items: WelcomeGroupItem[];\n /** Draw the items as the kit gallery's tiles rather than rows (the kit\n * gallery brief, section 6: the welcome shows the kits and the examples as\n * the gallery shows them). Needs kit-gallery.css beside welcome.css. */\n tiles?: boolean;\n}\n\nexport interface WelcomeOptions {\n title: string;\n sub: string;\n actions: WelcomeAction[];\n recents: WelcomeRecent[];\n groups?: WelcomeGroup[];\n /** The teaching door: a line under the actions, quieter than a button\n * (\"New to Patter? Take the interactive tour\"). The app builds and styles\n * it; a text action in it is a link, not bare muted text. */\n tourLine?: HTMLElement;\n /** The recents caption. Default \"Recent\". */\n recentsCaption?: string;\n /** How many recents to show. Default 5. */\n maxRecents?: number;\n /** A sentence about why the last open failed, under everything. */\n error?: string;\n}\n\nexport interface Welcome {\n el: HTMLElement;\n /** Redraw the recents (the list changes as projects open and close). */\n setRecents(recents: WelcomeRecent[]): void;\n setError(error: string | undefined): void;\n}\n\n/** Mount the welcome into `host` (replacing its children). */\nexport function mountWelcome(host: HTMLElement, opts: WelcomeOptions): Welcome {\n const caption = (text: string): HTMLElement => el(\"h2\", \"welcome-caption\", text);\n const group = (label: string, ...body: (Node | null)[]): HTMLElement =>\n el(\"section\", \"welcome-group\", caption(label), ...body);\n\n const actions = el(\"div\", \"welcome-actions\");\n for (const a of opts.actions) {\n const b = el(\"button\", { className: `btn${a.primary ? \" primary\" : \"\"}`, text: a.label, onClick: a.onClick });\n b.type = \"button\";\n actions.append(b);\n }\n\n const groups = (opts.groups ?? []).map((g) => group(g.caption,\n g.note !== undefined ? el(\"p\", \"welcome-note\", g.note) : null,\n g.tiles\n ? el(\"div\", \"kit-gallery-grid welcome-tiles\", ...g.items.map((item) => kitTile({\n name: item.name, blurb: item.hint ?? \"\",\n ...(item.badge !== undefined ? { badge: item.badge } : {}),\n ...(item.image !== undefined ? { image: item.image } : {}),\n }, item.onOpen)))\n : el(\"div\", \"welcome-list\", ...g.items.map((item) => {\n const b = el(\"button\", { className: \"welcome-item\", onClick: item.onOpen },\n el(\"span\", \"welcome-item-name\", item.name),\n item.hint !== undefined ? el(\"span\", \"welcome-item-hint\", item.hint) : null);\n b.type = \"button\";\n return b;\n })),\n ));\n\n const recentsHost = el(\"div\", \"welcome-recents-slot\");\n const drawRecents = (recents: WelcomeRecent[]): void => {\n const shown = recents.slice(0, opts.maxRecents ?? 5);\n recentsHost.replaceChildren();\n if (shown.length === 0) return;\n recentsHost.append(group(opts.recentsCaption ?? \"Recent\",\n el(\"div\", \"welcome-recents\", ...shown.map((r) => {\n const b = el(\"button\", { className: \"welcome-recent\", onClick: r.onOpen },\n el(\"span\", \"welcome-recent-name\", r.name),\n el(\"span\", \"welcome-recent-path\", r.path));\n b.type = \"button\";\n return b;\n })),\n ));\n };\n drawRecents(opts.recents);\n\n const error = el(\"p\", \"welcome-error\");\n const setError = (text: string | undefined): void => {\n error.textContent = text ?? \"\";\n error.hidden = text === undefined || text === \"\";\n };\n setError(opts.error);\n\n const root = el(\"div\", \"welcome\", el(\"div\", \"welcome-card\",\n el(\"h1\", \"welcome-title\", opts.title),\n el(\"p\", \"welcome-sub\", opts.sub),\n actions,\n opts.tourLine ? el(\"div\", \"welcome-line\", opts.tourLine) : null,\n ...groups,\n recentsHost,\n error,\n ));\n host.replaceChildren(root);\n return { el: root, setRecents: drawRecents, setError };\n}\n","// ---------------------------------------------------------------------------\n// The live-link status chip: a compact control in the bottom-right corner for\n// the loopback server a running game connects to. All the state collapses to\n// one coloured \"connect\" icon (grey off, amber listening, green connected and\n// in sync, red connected on a different build); click it to toggle the link\n// (off -> listening -> stop), and while the link is up the copiable ws://\n// address sits beside it. Patterpad's debug-panel.ts and Storyletter's\n// live-link.ts were this file twice, character for character down to the\n// 1000ms `.copied` revert. Styles ship as link-status.css.\n//\n// What the game sends is the app's business; this is the control and the\n// status only.\n// ---------------------------------------------------------------------------\n\nimport { el } from \"./dom.js\";\nimport { iconNode } from \"./icons.js\";\nimport { copyWithFeedback } from \"./util.js\";\n\nexport type LinkStatus =\n | { state: \"off\" }\n | { state: \"error\"; message: string }\n | { state: \"listening\"; port: number; address?: string }\n | {\n state: \"connected\"; port: number; address?: string;\n /** What connected, if it said. */\n project?: string;\n /** Whether the game's build matches the editor's. */\n build?: \"match\" | \"stale\" | \"unknown\";\n /** One extra sentence for the tip (Storyletter names the live boxes). */\n note?: string;\n };\n\n/** The chip's colour class for a state: the four. */\nexport type LinkStatusClass = \"off\" | \"listening\" | \"live\" | \"stale\";\n\nexport interface LinkStatusOptions {\n /** A word beside the chip (\"Live link\"), so a bottom-corner plug is not a\n * mystery. Omitted draws none. */\n label?: string;\n /** Start when off or failed, stop otherwise. A returned status is applied;\n * a status pushed later through `apply` works as well. */\n onToggle: (current: LinkStatus) => LinkStatus | void | Promise<LinkStatus | void>;\n /** Runs after the address is copied. The copy itself is the chip's. */\n onCopy?: (address: string) => void;\n /** Controls before the address (Patterpad's flow picker). */\n lead?: HTMLElement[];\n}\n\nexport interface LinkStatusChip {\n el: HTMLElement;\n apply(status: LinkStatus): void;\n status(): LinkStatus;\n /** Show / hide the control (shown when a project is open). */\n setVisible(on: boolean): void;\n /** Toggle the link (a menu item routes here). */\n toggle(): void;\n}\n\nexport function linkStatusClass(s: LinkStatus): LinkStatusClass {\n if (s.state === \"off\" || s.state === \"error\") return \"off\";\n if (s.state === \"listening\") return \"listening\";\n return s.build === \"stale\" ? \"stale\" : \"live\";\n}\n\n/** The tooltip, spelling the state out. One wording for the family. */\nexport function linkStatusTip(s: LinkStatus): string {\n switch (s.state) {\n case \"off\": return \"Live link is off. Click to start listening.\";\n case \"error\": return `Live link failed (${s.message}). Click to retry.`;\n case \"listening\": return \"Live link is listening for a game. Click to stop.\";\n case \"connected\": {\n const who = s.project !== undefined ? ` to ${s.project}` : \"\";\n const build = s.build === \"stale\" ? \" on a different build, so save or rebuild to re-sync\"\n : s.build === \"match\" ? \" and in sync\" : \"\";\n const note = s.note ? ` ${s.note}` : \"\";\n return `Live link is connected${who}${build}.${note} Click to stop.`;\n }\n }\n}\n\n/** The address a game connects to. */\nexport function linkAddress(s: LinkStatus): string | undefined {\n if (s.state !== \"listening\" && s.state !== \"connected\") return undefined;\n return s.address ?? `ws://127.0.0.1:${s.port}`;\n}\n\n/** Where the chip sits, which link-status.css says too: its right inset, and the\n * breathing room anything beside it keeps. Kept beside the reserve that uses\n * them, since the reserve is a promise about the CSS. */\nconst CORNER_INSET = 14.5;\nconst CORNER_GAP = 12;\n\n/** Mount the chip into `host` (document.body in both apps: it is fixed to the\n * window's corner). Hidden until `setVisible(true)`. */\nexport function mountLinkStatus(host: HTMLElement, opts: LinkStatusOptions): LinkStatusChip {\n const wrap = el(\"div\", \"linkstatus\"); wrap.hidden = true;\n const url = el(\"button\", \"linkstatus-url\"); url.type = \"button\"; url.hidden = true;\n const toggle = el(\"button\", \"linkstatus-toggle off\"); toggle.type = \"button\"; toggle.append(iconNode(\"connect\"));\n if (opts.label !== undefined) wrap.append(el(\"span\", \"linkstatus-word\", opts.label));\n wrap.append(...(opts.lead ?? []), url, toggle);\n host.append(wrap);\n\n let status: LinkStatus = { state: \"off\" };\n\n // The corner the chip floats over belongs to whatever the host put there: a\n // problems bar's error link and its buttons, a canvas strip's last control.\n // Both apps had it drawn under the chip (2026-09-17). So the chip publishes\n // how much of the corner it takes, as --linkstatus-reserve on the document,\n // and the things that can sit there leave that much room (the stepper bar\n // does, in stepper.css; a host's own strips opt in). 0px while hidden.\n // Re-measured on every render, because the address comes and goes, and on a\n // resize where the platform offers one, because a web font landing moves it.\n const root = host.ownerDocument.documentElement;\n const publishReserve = (): void => {\n const width = wrap.hidden ? 0 : wrap.getBoundingClientRect().width;\n root.style.setProperty(\"--linkstatus-reserve\",\n width > 0 ? `${Math.ceil(width + CORNER_INSET + CORNER_GAP)}px` : \"0px\");\n };\n if (typeof ResizeObserver !== \"undefined\") new ResizeObserver(publishReserve).observe(wrap);\n\n const render = (): void => {\n toggle.className = `linkstatus-toggle ${linkStatusClass(status)}`;\n const tip = linkStatusTip(status);\n toggle.dataset[\"tip\"] = tip;\n toggle.setAttribute(\"aria-label\", tip);\n // The copiable address means something once the server is up.\n const addr = linkAddress(status);\n if (addr !== undefined) {\n url.textContent = addr;\n url.dataset[\"tip\"] = \"Click to copy the live link address\";\n url.hidden = false;\n } else url.hidden = true;\n publishReserve();\n };\n const apply = (s: LinkStatus): void => { status = s; render(); };\n render();\n\n toggle.addEventListener(\"click\", () => {\n const out = opts.onToggle(status);\n void Promise.resolve(out).then((next) => { if (next) apply(next); });\n });\n url.addEventListener(\"click\", () => {\n const addr = url.textContent ?? \"\";\n if (!addr) return;\n void copyWithFeedback(url, addr);\n opts.onCopy?.(addr);\n });\n\n return {\n el: wrap, apply,\n status: () => status,\n setVisible(on: boolean): void { wrap.hidden = !on; publishReserve(); },\n toggle(): void { toggle.click(); },\n };\n}\n","// ---------------------------------------------------------------------------\n// THE property declaration list: name, type, default, values or stages,\n// purpose, in a row per declaration, with reorder, remove, add-then-focus and\n// the duplicate / illegal-name gates. Patterpad's settings-properties.ts and\n// Storyletter's prop-list.ts were built from the same shell primitives in the\n// same order (dupGuard, bindPropertyName, a type select over the same six\n// types, defaultControl, three iconBtns on moveItem, labelled tagChips and\n// stageChips, expandableRow, focusNewRow); this is the one list, and each\n// app's extras (Shared, Temporary, Read-only, Durable) arrive through\n// `extraLine` / `extraDetails`.\n//\n// `defaultControl` was four copies (three inside Patterpad), and the two apps'\n// option labels had already parted (\"(unset)\" vs \"(none)\"). One label set now.\n//\n// Storage of the default differs by app: Patterpad's model holds a typed\n// value (true, 3), Storyletter's DTO holds the string the field showed. The\n// list mutates `decls` in place either way; `typed` picks the encoding.\n// ---------------------------------------------------------------------------\n\nimport { el } from \"./dom.js\";\nimport { iconBtn, labelled, moveItem, stageChips, tagChips } from \"./dom.js\";\nimport { dupGuard, expandableRow, focusNewRow } from \"./settings.js\";\nimport type { SettingsSectionHandle } from \"./settings.js\";\nimport { bindPropertyName, firstIllegalPropertyName } from \"./property-name-field.js\";\nimport { PROPERTY_NAME_HINT } from \"./property-names.js\";\n\n/** The six types both apps declare. */\nexport type PropertyListType = \"number\" | \"boolean\" | \"string\" | \"enum\" | \"flags\" | \"quality\";\n\n/** The shape a row edits. Apps' DTOs carry more (shared, writable, durable);\n * those ride through untouched. */\nexport interface PropertyDeclLike {\n name: string;\n type: string;\n default?: unknown;\n /** enum / flags */\n values?: string[];\n /** quality: the ladder, in order */\n stages?: string[];\n purpose?: string;\n}\n\n/** The type list, in the family's order, with the words the select shows. */\nexport const PROPERTY_TYPES: ReadonlyArray<readonly [PropertyListType, string]> = [\n [\"number\", \"Number\"], [\"boolean\", \"True / False\"], [\"string\", \"Text\"],\n [\"enum\", \"List\"], [\"flags\", \"Flags\"], [\"quality\", \"Quality\"],\n];\n\nexport interface DefaultControlOptions {\n /**\n * How the default is stored. `false` (default): the string the field shows,\n * \"\" for none (Storyletter's DTO). `true`: a typed value (boolean, number,\n * string), and none DELETES the key (Patterpad's model).\n */\n typed?: boolean;\n}\n\nconst option = (value: string, label: string, selected: boolean): HTMLOptionElement => {\n const o = el(\"option\", undefined, label);\n o.value = value; o.selected = selected;\n return o;\n};\n\nconst NONE = \"(none)\";\n\n/**\n * The type-appropriate control for a declaration's DEFAULT: a true / false\n * picker for a boolean, the value list for an enum, the stage list for a\n * quality (blank = the first rung), a note for flags (a set starts empty), a\n * number or text field otherwise. The one label for \"no default\" is \"(none)\".\n */\nexport function defaultControl(p: PropertyDeclLike, onChange?: () => void, opts: DefaultControlOptions = {}): HTMLElement {\n const typed = opts.typed === true;\n const write = (raw: string): void => {\n if (raw === \"\") { if (typed) delete p.default; else p.default = \"\"; }\n else if (typed && p.type === \"boolean\") p.default = raw === \"true\";\n else if (typed && p.type === \"number\") p.default = Number(raw);\n else p.default = raw;\n onChange?.();\n };\n const current = p.default === undefined || p.default === null ? \"\" : String(p.default);\n if (p.type === \"boolean\") {\n const sel = el(\"select\", \"field set-default\");\n sel.append(option(\"\", NONE, current === \"\"), option(\"true\", \"True\", current === \"true\"), option(\"false\", \"False\", current === \"false\"));\n sel.addEventListener(\"change\", () => write(sel.value));\n return sel;\n }\n if (p.type === \"enum\") {\n const sel = el(\"select\", \"field set-default\");\n sel.append(option(\"\", NONE, current === \"\"));\n for (const v of p.values ?? []) sel.append(option(v, v, current === v));\n sel.addEventListener(\"change\", () => write(sel.value));\n return sel;\n }\n if (p.type === \"quality\") {\n // The default is a STAGE; blank means the first rung, so say so rather\n // than \"(none)\".\n const sel = el(\"select\", \"field set-default\");\n sel.append(option(\"\", \"(first stage)\", current === \"\"));\n for (const v of p.stages ?? []) sel.append(option(v, v, current === v));\n sel.addEventListener(\"change\", () => write(sel.value));\n return sel;\n }\n if (p.type === \"flags\") {\n // Flags hold a SET of values, so there is no single default: it starts empty.\n const s = el(\"span\", \"set-flagnote\", \"Starts empty\");\n s.dataset[\"tip\"] = \"A flags property starts with none set.\";\n return s;\n }\n const input = el(\"input\", \"field set-default\");\n input.type = p.type === \"number\" ? \"number\" : \"text\";\n input.placeholder = \"Default\";\n input.value = current;\n input.addEventListener(\"input\", () => write(input.value));\n return input;\n}\n\nexport interface PropertyListOptions<T extends PropertyDeclLike> extends DefaultControlOptions {\n /** Called after every mutation; a centre editor feeds its autosave here. */\n onChange?: () => void;\n /** The add button's label. Default \"+ Add property\". */\n addLabel?: string;\n /** The empty sentence. Default \"No properties yet.\" */\n emptyText?: string;\n /** The type select's entries; default `PROPERTY_TYPES`. */\n types?: ReadonlyArray<readonly [string, string]>;\n /** A fresh declaration for the add button. Default: a blank of the first type. */\n newDecl?: () => T;\n /** Controls on the row's line, between the default and the movers\n * (Storyletter's \"uses\" affordance). */\n extraLine?: (decl: T, index: number) => (HTMLElement | null)[];\n /** Fields behind the disclosure, before Values / Stages / Purpose\n * (Shared, Temporary, Read-only, Durable). */\n extraDetails?: (decl: T, index: number) => (HTMLElement | null)[];\n /** Offer the Purpose field. Default true. */\n purpose?: boolean;\n}\n\nexport interface PropertyListHandle extends SettingsSectionHandle {\n /** Both faults, for the Save gate: a duplicate first, then an illegal name. */\n firstInvalid(): HTMLInputElement | null;\n /** The first name that clashes with another, or null. */\n firstDuplicate(): HTMLInputElement | null;\n /** The first name no expression could reach, or null. */\n firstIllegalName(): HTMLInputElement | null;\n /** Redraw from `decls` (after an outside change). */\n render(): void;\n}\n\n/** Mount the list into `host`. Mutates `decls` in place; the caller reads\n * them back on save (pruning blank names is the caller's, since only it\n * knows its DTO). */\nexport function mountPropertyList<T extends PropertyDeclLike>(host: HTMLElement, decls: T[], opts: PropertyListOptions<T> = {}): PropertyListHandle {\n const changed = (): void => opts.onChange?.();\n const guard = dupGuard();\n const types = opts.types ?? PROPERTY_TYPES;\n const list = el(\"div\", \"set-list\");\n const keep = (parts: (HTMLElement | null)[] | undefined): HTMLElement[] =>\n (parts ?? []).filter((p): p is HTMLElement => p !== null);\n\n const row = (p: T, i: number): HTMLElement => {\n const name = el(\"input\", \"field set-name\");\n name.type = \"text\"; name.placeholder = \"Property name\"; name.value = p.name; name.spellcheck = false;\n name.dataset[\"tip\"] = PROPERTY_NAME_HINT;\n bindPropertyName(name, (v) => { p.name = v; changed(); }, { hint: PROPERTY_NAME_HINT });\n guard.track(name);\n\n const type = el(\"select\", \"field set-type\");\n for (const [v, label] of types) type.append(option(v, label, v === p.type));\n type.addEventListener(\"change\", () => {\n p.type = type.value;\n if (opts.typed) delete p.default; else p.default = \"\";\n if (p.type === \"enum\" || p.type === \"flags\") p.values ??= []; else delete p.values;\n if (p.type === \"quality\") p.stages ??= []; else delete p.stages;\n render(); changed();\n });\n\n // The default control is rebuilt in place when the values change, so a\n // new value becomes selectable as the default.\n let def = defaultControl(p, changed, opts);\n const refreshDefault = (): void => { const fresh = defaultControl(p, changed, opts); def.replaceWith(fresh); def = fresh; changed(); };\n\n const up = iconBtn(\"up\", \"Move up\", () => { if (moveItem(decls, i, -1)) { render(); changed(); } }, i === 0);\n const down = iconBtn(\"down\", \"Move down\", () => { if (moveItem(decls, i, 1)) { render(); changed(); } }, i === decls.length - 1);\n const del = iconBtn(\"close\", \"Delete property\", () => { decls.splice(i, 1); render(); changed(); }, false, true);\n\n const details: HTMLElement[] = keep(opts.extraDetails?.(p, i));\n if (p.type === \"enum\" || p.type === \"flags\") details.push(labelled(\"Values\", tagChips(p, refreshDefault)));\n // A quality's ladder, IN ORDER: the chips carry movers because position is the meaning.\n if (p.type === \"quality\") details.push(labelled(\"Stages (in order)\", stageChips(p, refreshDefault)));\n if (opts.purpose !== false) {\n const purpose = el(\"input\", \"field set-purpose\");\n purpose.type = \"text\"; purpose.placeholder = \"What this property is for\"; purpose.value = p.purpose ?? \"\";\n purpose.addEventListener(\"input\", () => {\n if (purpose.value.trim()) p.purpose = purpose.value; else delete p.purpose;\n changed();\n });\n details.push(labelled(\"Purpose\", purpose));\n }\n // Stamped with the declared name so \"Go to definition\" lands on the row (revealRow).\n return expandableRow({ line: [name, type, def, ...keep(opts.extraLine?.(p, i)), up, down, del], details, name: p.name });\n };\n\n const render = (): void => {\n guard.reset();\n list.replaceChildren();\n if (decls.length === 0) list.append(el(\"p\", \"empty\", opts.emptyText ?? \"No properties yet.\"));\n else decls.forEach((p, i) => list.append(row(p, i)));\n guard.check();\n };\n render();\n\n const add = el(\"button\", \"btn set-add\", opts.addLabel ?? \"+ Add property\");\n add.type = \"button\";\n add.addEventListener(\"click\", () => {\n decls.push(opts.newDecl ? opts.newDecl() : ({ name: \"\", type: types[0]?.[0] ?? \"string\", ...(opts.typed ? {} : { default: \"\" }) } as unknown as T));\n render(); changed(); focusNewRow(list);\n });\n host.append(list, add);\n\n return {\n firstDuplicate: () => guard.firstDuplicate(),\n firstIllegalName: () => firstIllegalPropertyName(host),\n // The Save gate takes both faults; the field's own rollover says which.\n firstInvalid: () => guard.firstDuplicate() ?? firstIllegalPropertyName(host),\n render,\n };\n}\n","// ---------------------------------------------------------------------------\n// Navigation history - the VS Code back/forward pair, family-wide.\n//\n// The shell owns the STACK and the ARROWS; each app owns what a place is.\n// `Place` is opaque here for the same reason the app-store's `places` is:\n// \"where you are\" means a focus + document + tab in Storyletter and a scene +\n// position in Patterpad, and the shell has no business knowing either. The app\n// supplies two judgements - `same` (two places that are the same DOCUMENT, so\n// tab and selection twitches coalesce instead of filling the stack) and\n// `usable` (a place can still be restored: the card it names may have been\n// deleted since) - and the mechanics cannot drift between the apps.\n//\n// The model is the browser's: `visit` records the place being LEFT on an\n// ordinary navigation and clears the forward list (navigating anew after\n// going back branches history, and the abandoned branch is gone); `back` and\n// `forward` exchange the current place for the adjacent one. Entries that\n// fail `usable` are DISCARDED on the way past, never restored and never moved\n// to the other side.\n//\n// One duty stays with the app, documented rather than latched: restoring a\n// place re-dispatches the app's own navigation actions, and those call\n// `visit`. The app must not `visit` while it is travelling (Storyletter's\n// `arriving` flag is the local idiom), or every Back would push what it just\n// left and Forward would never reach anything.\n// ---------------------------------------------------------------------------\n\nimport { iconNode, type IconName } from \"./icons.js\";\n\nexport interface NavHistoryOptions<Place> {\n /** Same DOCUMENT: a visit whose place is `same` as the newest entry\n * REPLACES it (keeping the freshest tab) instead of stacking. */\n same(a: Place, b: Place): boolean;\n /** Still restorable? Checked as an entry is stepped onto; a stale one is\n * dropped and the step continues past it. Default: everything is. */\n usable?(p: Place): boolean;\n /** Entries beyond this age off the far end (default 100). */\n cap?: number;\n}\n\nexport interface NavHistory<Place> {\n /** Record the place being left, before an ordinary navigation. */\n visit(place: Place): void;\n /** Step back: hands over the current place (it becomes the forward entry)\n * and returns the place to restore, or undefined at the far end. */\n back(current: Place): Place | undefined;\n forward(current: Place): Place | undefined;\n /** Whether the arrows light. Optimistic: a side holding only stale entries\n * still reports true, and the press quietly discards them (the alternative\n * is validating the whole stack on every paint). */\n canBack(): boolean;\n canForward(): boolean;\n}\n\nexport function createNavHistory<Place>(opts: NavHistoryOptions<Place>): NavHistory<Place> {\n const cap = opts.cap ?? 100;\n const usable = opts.usable ?? ((): boolean => true);\n let past: Place[] = [];\n let ahead: Place[] = [];\n\n const step = (from: Place[], to: Place[], current: Place): Place | undefined => {\n for (;;) {\n const p = from.pop();\n if (p === undefined) return undefined;\n if (!usable(p)) continue; // its document is gone: drop, keep walking\n if (opts.same(p, current)) continue; // a step must MOVE: a self-visit (a\n // tab click routed through a navigation action) is not a journey, and\n // restoring it reads as a dead button\n to.push(current);\n return p;\n }\n };\n\n return {\n visit(place) {\n ahead = [];\n const top = past[past.length - 1];\n if (top !== undefined && opts.same(top, place)) past[past.length - 1] = place;\n else past.push(place);\n if (past.length > cap) past = past.slice(past.length - cap);\n },\n back(current) { return step(past, ahead, current); },\n forward(current) { return step(ahead, past, current); },\n canBack() { return past.length > 0; },\n canForward() { return ahead.length > 0; },\n };\n}\n\n/**\n * The quiet arrow pair, VS Code's shape: greyed where there is nowhere to\n * go, one component so it looks and sits the same in every app of the\n * family; the caller re-`set`s it whenever a navigation may have changed\n * what the arrows can do.\n *\n * ARROWS, not chevrons, and the distinction is the family's glyph grammar\n * (the author's ruling, 2026-08-28): a chevron says STRUCTURE - the pane\n * toggles, a labelled up-crumb, a tree row's disclosure - and an arrow says\n * TIME. The first cut used chevrons, and sitting on the topbar two seats\n * from the pane toggle's chevron the pair read as more of the same thing;\n * it is how every browser, editor and file manager already split the two.\n *\n * The pair's HOME is the topbar's lead, immediately after the nav toggle\n * (Patterpad placed it there first, and the ruling ratified it).\n */\nexport function historyNav(onBack: () => void, onForward: () => void): {\n el: HTMLElement;\n set(canBack: boolean, canForward: boolean): void;\n} {\n const btn = (name: IconName, tip: string, onClick: () => void): HTMLButtonElement => {\n const b = document.createElement(\"button\");\n b.type = \"button\";\n b.className = \"shell-histnav-btn\";\n b.append(iconNode(name));\n b.dataset[\"tip\"] = tip;\n b.setAttribute(\"aria-label\", tip);\n b.addEventListener(\"click\", onClick);\n return b;\n };\n const back = btn(\"arrowLeft\", \"Back\", onBack);\n const forward = btn(\"arrowRight\", \"Forward\", onForward);\n const el = document.createElement(\"span\");\n el.className = \"shell-histnav\";\n el.append(back, forward);\n return {\n el,\n set(canBack, canForward) { back.disabled = !canBack; forward.disabled = !canForward; },\n };\n}\n"]}
1
+ {"version":3,"sources":["../src/tooltip.ts","../src/icons.ts","../src/dom.ts","../src/colour.ts","../src/keys.ts","../src/pane-shell.ts","../src/menu.ts","../src/problems.ts","../src/settings.ts","../src/util.ts","../src/tool-window-web.ts","../src/exit.ts","../src/dialog.ts","../src/confirm.ts","../src/floating.ts","../src/context-menu.ts","../src/about.ts","../src/anchored.ts","../src/ids.ts","../src/property-names.ts","../src/property-name-field.ts","../src/id-editor.ts","../src/vc-view.ts","../src/identity.ts","../src/notes-editor.ts","../src/comments.ts","../src/job-view.ts","../src/job.ts","../src/save.ts","../src/save-view.ts","../src/stale.ts","../src/toast.ts","../src/stepper.ts","../src/updater-view.ts","../src/kit-gallery.ts","../src/welcome.ts","../src/link-status.ts","../src/property-list.ts","../src/nav-history.ts"],"names":["el","node","label","chip","tip","active","timer","show","EDGE","current","GAP","thread","place"],"mappings":"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","file":"index.cjs","sourcesContent":["// ---------------------------------------------------------------------------\n// A single themed tooltip the family controls, replacing native `title`\n// rollovers: those are unstyled OS chrome and appear on the platform's slow\n// (~1s) delay, which is exactly the seam design-language section 4 (\"coherent\n// to the edges\") says not to leave showing.\n//\n// ONE floating bubble, document-DELEGATED: any element carrying a `data-tip`\n// attribute gets it, so a caller just sets `data-tip=\"...\"` anywhere and wires\n// nothing. The bubble anchors above the element (flipping below near the top\n// edge), uses our own snappy delay and the shared panel-enter motion.\n// `initTooltips()` is idempotent, so it is safe to call from more than one\n// place in an app that has several entry points.\n//\n// Lifted from Patterpad's patterpad-surface/web/tooltip.ts, which proved it,\n// with the one app-specific rule (suppressed in Writing View) generalised into\n// the `suppressed` option so the shell knows nothing about either app's modes.\n// ---------------------------------------------------------------------------\n\n// Bold markers: a producer wraps a span in these PRIVATE control chars (U+0002 STX / U+0003 ETX,\n// never present in user text) and the renderer turns it into a <strong>. Lets a data-tip bold part\n// of itself (a name, a \"VO:\" prefix) without any HTML, and each segment is still set via\n// textContent, so there is no injection risk from user content.\nconst B_OPEN = \"\\u0002\";\nconst B_CLOSE = \"\\u0003\";\n\n/** Wrap `s` so it renders bold inside a tooltip (see the marker note above). */\nexport function tipBold(s: string): string { return `${B_OPEN}${s}${B_CLOSE}`; }\n\n/** Render `text` into `host`, turning `\\u0002…\\u0003`-marked spans into <strong>; all set as text (safe). */\nfunction renderTip(host: HTMLElement, text: string): void {\n host.textContent = \"\";\n const re = /\\u0002([^\\u0003]*)\\u0003/g;\n let last = 0;\n let m: RegExpExecArray | null;\n while ((m = re.exec(text)) !== null) {\n if (m.index > last) host.append(text.slice(last, m.index));\n const strong = document.createElement(\"strong\");\n strong.textContent = m[1] ?? \"\";\n host.append(strong);\n last = m.index + m[0].length;\n }\n if (last < text.length) host.append(text.slice(last));\n}\n\nexport interface TooltipOptions {\n /** Called before every show: return true to keep the bubble down. For a mode\n * that wants no chrome at all (Patterpad's Writing View). */\n suppressed?: () => boolean;\n}\n\nlet inited = false;\nlet checked = false; // the one-shot no-host warning below has been scheduled\nlet suppressed: (() => boolean) | undefined;\nconst SHOW_DELAY = 350; // ms - snappier than the OS title delay, slow enough not to flicker on pass-through\nconst EDGE = 6; // viewport inset so the bubble never touches the window edge\nconst GAP = 7; // px between the anchor and the bubble\n\nlet tip: HTMLDivElement | null = null;\nlet timer = 0;\nlet active: HTMLElement | null = null;\n/** The subject of a rect-anchored tip (see `tipAt`), when there is one. */\nlet activeKey: string | null = null;\n\nfunction ensureEl(): HTMLDivElement {\n if (tip) return tip;\n const el = document.createElement(\"div\");\n el.className = \"tooltip\";\n el.setAttribute(\"role\", \"tooltip\");\n el.hidden = true;\n document.body.appendChild(el);\n tip = el;\n return el;\n}\n\n/** A rectangle in VIEWPORT coordinates, for anchoring a tip to something that is\n * not a DOM element: a shape on a canvas, a run of text inside one. */\nexport interface TipRect { left: number; top: number; width: number; height: number }\n\nconst rectOf = (anchor: HTMLElement | TipRect): TipRect =>\n (anchor instanceof HTMLElement ? anchor.getBoundingClientRect() : anchor);\n\n/** Anchor the (already-visible, so measurable) bubble above the anchor, flipping below near the top. */\nfunction place(anchor: HTMLElement | TipRect): void {\n const t = ensureEl();\n const r = rectOf(anchor);\n const tr = t.getBoundingClientRect();\n let top = r.top - tr.height - GAP;\n if (top < EDGE) top = r.top + r.height + GAP; // not enough room above -> below\n let left = r.left + r.width / 2 - tr.width / 2;\n left = Math.max(EDGE, Math.min(left, window.innerWidth - tr.width - EDGE));\n t.style.left = `${Math.round(left)}px`;\n t.style.top = `${Math.round(top)}px`;\n}\n\nfunction show(anchor: HTMLElement): void {\n const text = anchor.dataset[\"tip\"];\n if (!text) return;\n paint(anchor, text);\n}\n\n/** Fill, place and reveal the bubble. The one path: both the delegated\n * `data-tip` route and `tipAt` end up here, so a canvas tip and a button tip\n * are the same bubble with the same look and the same motion. */\nfunction paint(anchor: HTMLElement | TipRect, text: string): void {\n if (suppressed?.()) return;\n const t = ensureEl();\n // A modal <dialog> (settings, a confirm) renders in the browser TOP LAYER, above every normal-flow\n // element whatever its z-index. If the anchor is inside one, move the bubble into that dialog so it\n // shares the top layer; otherwise keep it on <body>. Re-parenting per show also moves it back out\n // once the modal closes.\n const host: HTMLElement = (anchor instanceof HTMLElement ? anchor.closest<HTMLElement>(\"dialog[open]\") : null)\n ?? document.body;\n if (t.parentElement !== host) host.appendChild(t);\n active = anchor instanceof HTMLElement ? anchor : null;\n renderTip(t, text);\n t.hidden = false;\n t.classList.remove(\"show\"); void t.offsetWidth; // restart the enter animation\n place(anchor); // measure + position now it has content + is visible\n t.classList.add(\"show\");\n}\n\nfunction hide(): void {\n if (timer) { window.clearTimeout(timer); timer = 0; }\n active = null;\n activeKey = null;\n if (tip) { tip.hidden = true; tip.classList.remove(\"show\"); }\n}\n\nfunction schedule(anchor: HTMLElement): void {\n if (anchor === active) return;\n if (timer) window.clearTimeout(timer);\n timer = window.setTimeout(() => show(anchor), SHOW_DELAY);\n}\n\n/**\n * Show a tip for something that has no DOM node of its own: a card on a canvas,\n * a zone, a pin. The caller says WHERE (a viewport rectangle) and WHAT, and\n * identifies the subject with `key`.\n *\n * The key is what makes this usable from a canvas. Re-calling with the same key\n * re-places the bubble WITHOUT restarting the delay, so a tip can follow its\n * shape while the camera moves; calling with a different key starts the wait\n * again, so sweeping the pointer across a dense board does not strobe.\n *\n * The bubble is ordinary DOM, so it holds its size whatever the canvas is\n * zoomed to. That is the point of it: the label it stands in for is the one\n * thing on a canvas that must not shrink with everything else.\n */\nexport function tipAt(key: string, rect: TipRect, text: string): void {\n if (key === activeKey) {\n // Already up for this subject: move it, do not re-animate it.\n if (tip && !tip.hidden) { renderTip(tip, text); place(rect); }\n return;\n }\n // A different subject: down first, then wait again. Leaving the old bubble up\n // during the wait would put one card's name over another card, which is worse\n // than no name at all - and it matches the delegated route, where leaving an\n // element hides the tip before the next one is scheduled.\n hide();\n activeKey = key;\n timer = window.setTimeout(() => { timer = 0; paint(rect, text); }, SHOW_DELAY);\n}\n\n/** Take any tip down: the pointer has left, or a gesture has started. */\nexport function hideTip(): void { hide(); }\n\n/**\n * Mount the renderer because something is about to speak the grammar.\n *\n * The themed tooltip is not a feature a host turns on; it is the renderer for a grammar the shell's own\n * components already speak, and `data-tip` with nothing listening draws NOTHING - not the themed\n * bubble, not the platform one. That silence cost Patterpad two releases of a pin with no tooltip, and\n * cost it again when a `title` was converted to `data-tip` in a window that had never mounted this.\n *\n * So `el` calls this whenever it sets a tip. Mounting a delegated listener is the same class of act as\n * `confirmDialog` appending to `document.body`, which this package has always done.\n */\nexport function ensureTooltipHost(): void { initTooltips(); }\n\n/**\n * One deferred check that an app writing `data-tip` ITSELF has a host, warning if not.\n *\n * `ensureTooltipHost` covers anything built through `el`. It cannot cover a `data-tip` written straight\n * into markup or set by hand, which is the case that leaves a whole window of dead tips with no shell\n * component involved - so that one gets a warning rather than silence. Scheduled once, after the\n * current task, so it sees a rendered document rather than an empty one.\n */\nexport function checkTooltipHost(): void {\n if (checked) return;\n checked = true;\n setTimeout(() => {\n if (inited || typeof document === \"undefined\") return;\n if (document.querySelector(\"[data-tip]\")) {\n console.warn(\"app-shell: something set `data-tip` but no tooltip host is mounted, so those rollovers will not draw. Call initTooltips() once per window.\");\n }\n }, 0);\n}\n\nconst tipAncestor = (n: EventTarget | null): HTMLElement | null =>\n (n instanceof Element ? n.closest<HTMLElement>(\"[data-tip]\") : null);\n\n/**\n * Wire the one delegated controller. Mounting happens once; OPTIONS do not.\n *\n * An explicit call is always authoritative about its options, even after something else has already\n * mounted the listener. That ordering is not hypothetical, and Storyletter caught it before it shipped:\n * once components self-mount (see `ensureTooltipHost`), a host's own\n * `initTooltips({ suppressed })` could land second and be dropped by an early return, silently taking\n * a rule like \"no tooltips in Writing View\" with it. Nothing would fail and nothing would show.\n *\n * Components therefore call this with NO arguments: they mount the renderer without claiming the\n * options, and the host keeps the last word on behaviour.\n */\nexport function initTooltips(opts: TooltipOptions = {}): void {\n if (opts.suppressed !== undefined) suppressed = opts.suppressed; // an explicit call always wins\n if (inited) return;\n inited = true;\n\n document.addEventListener(\"pointerover\", (e) => {\n const el = tipAncestor(e.target);\n if (el) schedule(el);\n });\n document.addEventListener(\"pointerout\", (e) => {\n const el = tipAncestor(e.target);\n if (!el) return;\n const to = (e as PointerEvent).relatedTarget;\n if (to instanceof Node && el.contains(to)) return; // still inside the same anchor\n hide();\n });\n // Keyboard parity: reveal on focus, dismiss on blur.\n document.addEventListener(\"focusin\", (e) => { const el = tipAncestor(e.target); if (el) schedule(el); });\n document.addEventListener(\"focusout\", () => hide());\n // It's ANCHORED (not cursor-following), so anything that moves the layout or context dismisses it.\n document.addEventListener(\"pointerdown\", () => hide(), true);\n document.addEventListener(\"scroll\", () => { if (active) hide(); }, true);\n document.addEventListener(\"keydown\", (e) => { if (e.key === \"Escape\") hide(); });\n window.addEventListener(\"blur\", () => hide());\n}\n","// ---------------------------------------------------------------------------\n// The family's icon vocabulary.\n//\n// An icon is a WORD. Two apps in one suite spelling \"close\" differently is the\n// same fault as calling one thing a scene here and a chapter there, and it is\n// harder to notice because nobody reads glyphs, they just feel wrong. This\n// module exists so that no app ever types a codepoint again: it asks for\n// `iconNode(\"close\")` and gets whatever the family has agreed that means.\n//\n// The evidence that it was needed, gathered 2026-08-09 across both apps:\n// Patterpad spelled close as a cross twelve times, Storyletter used the same\n// cross once and a multiplication sign twice, in one window, and a comment\n// bubble had just been invented from scratch with nothing to check it against.\n//\n// DRAWN, not typed (design-language.md section 4, \"Icons are drawn, and so are\n// separators\", 2026-09-16). The first cut of this table was Unicode glyphs,\n// which render from whatever symbol font the OS has, so weight, baseline and\n// optical size drifted per character and per platform. The vocabulary is now\n// one drawn set: Lucide, vendored below as inline SVG strings on one 24-unit\n// grid at one stroke weight. The words did not change; what they draw did.\n//\n// Lucide 1.46.0 (lucide-static), ISC licence.\n// https://lucide.dev / https://cdn.jsdelivr.net/npm/lucide-static@1.46.0/icons/<name>.svg\n// Fetched 2026-09-16. The chosen decision record is\n// patterkit/design/ui-review-2026-09/07c-track-c-icon-sets-notes.md.\n//\n// STROKE. The family draws icons at 14px inside its small square buttons and\n// wants a 1.5px rendered stroke against Inter at that size (Inter Regular's\n// stems are about 1.3px there). Lucide's native stroke is 2 on a 24 grid,\n// which is 2 x 14/24 = 1.17px at 14px, a shade light. So the root of every\n// stroke icon carries stroke-width=\"2.571\": 2.571 x 14/24 = 1.5. A caller\n// drawing at another size gets the proportional weight (12px: 1.29px; 16px:\n// 1.71px), which is what one drawn set means. Filled shapes (the discs) carry\n// fill=\"currentColor\" and no stroke at all.\n//\n// Every icon is `currentColor`, so it takes the colour of the button it sits\n// in, and none of the strings carries width/height: the size is the caller's\n// (`iconNode(name, size)`), so an icon can never be the wrong size somewhere\n// because a CSS rule failed to reach it.\n//\n// Adding one: it needs a MEANING, not a picture. \"A downward chevron\" is not an\n// entry; \"expand this\" is. If two callers want the same picture for two\n// meanings, that is two entries, and one of them will be wrong later.\n// ---------------------------------------------------------------------------\n//\n// Lucide licence (the icons vendored in this file):\n//\n// ISC License\n// Copyright (c) 2026 Lucide Icons and Contributors\n//\n// Permission to use, copy, modify, and/or distribute this software for any\n// purpose with or without fee is hereby granted, provided that the above\n// copyright notice and this permission notice appear in all copies.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n//\n// Portions of Lucide (among those used here: arrow-down, arrow-left,\n// arrow-right, arrow-up, check, chevron-down, chevron-left, chevron-right,\n// circle, lock, plus, search, x) derive from Feather, MIT,\n// Copyright (c) 2013-present Cole Bemis. See LICENSES.md.\n// ---------------------------------------------------------------------------\n\n/**\n * The typed glyphs the vocabulary used to draw.\n *\n * @deprecated Since the move to drawn icons (design-language.md, \"Icons are\n * drawn\"). Kept byte-for-byte so a consumer still doing\n * `textContent = icon.close` keeps working while each app moves; a new call\n * site uses `iconNode(name)` (a node to append) or `iconHtml(name)` (for an\n * innerHTML build). The names are the same in all three. Removed once both\n * apps have moved.\n */\nexport const icon = {\n // --- dismissing and revealing ---------------------------------------------\n /** Close a panel, a dialog, a popover. Patterpad's, twelve times over. */\n close: \"✕\",\n /** The overflow menu on a document or a row: \"more about this\". */\n more: \"⋯\",\n /** Collapsed disclosure, pointing at what would open. */\n collapsed: \"▸\",\n /** Expanded disclosure. */\n expanded: \"▾\",\n /** A dropdown's affordance, where it is not a real <select>. */\n dropdown: \"▾\",\n\n // --- moving through things ------------------------------------------------\n /** Back / previous, in a breadcrumb or a stepper. */\n back: \"‹\",\n /** Forward / next. */\n forward: \"›\",\n /** Up one, in a list. */\n up: \"↑\",\n /** Down one. */\n down: \"↓\",\n\n // --- state ----------------------------------------------------------------\n /** Done, applied, agreed. */\n tick: \"✓\",\n /** Somebody else holds this: the version-control lock. */\n locked: \"⊘\",\n /** Read-only on disk with no other holder: the resting state of everything\n * in a lock-based working copy that nobody has checked out yet. */\n readOnly: \"○\",\n /** YOU hold this one: checked out / opened by the current user, still yours to\n * edit. Shares its glyph with `note`, which the table permits: an entry is a\n * MEANING, and two meanings may draw the same shape. */\n checkedOut: \"✎\",\n /** Tracked, with local changes not yet committed. */\n modified: \"●\",\n /** Not in version control yet: new since the last commit. */\n untracked: \"+\",\n /** Something needs attention but is not fatal. */\n warning: \"‼\",\n /** A live thing: the running position, an active marker. */\n dot: \"●\",\n /** Play, in the sense of \"run this\". */\n play: \"▶\",\n /** Start the thing again from the top: a play session, a sweep. Named for the\n * act, not the arrow, which is the table's rule. */\n restart: \"⟲\",\n /** The three ways a collection can be shown. Named by what you get rather than\n * by the glyph, so a second app can pick the same three without copying\n * somebody's taste in symbols. */\n viewCards: \"▦\",\n viewTable: \"☰\",\n viewNode: \"◈\",\n\n // --- handling -------------------------------------------------------------\n /** The drag grip on a reorderable row. */\n grip: \"⠿\",\n /** Add one of whatever this list holds. */\n add: \"+\",\n\n // --- annotation -----------------------------------------------------------\n /** Documentation notes: the pencil. Both apps had chosen it independently,\n * which is the happiest way for a vocabulary entry to arrive. */\n note: \"✎\",\n /** A comment thread. Speech, not a pencil: documentation states the reason,\n * comments are the conversation, and the two must never look alike. */\n comment: \"❝\",\n} as const;\n\n/**\n * Every word in the vocabulary. The 26 the glyph table had, plus the seven the\n * 2026-09 review found the apps drawing by hand with nothing to check against.\n */\nexport type IconName =\n | keyof typeof icon\n /** History back, the topbar's quiet arrow pair (nav-history.ts). An ARROW,\n * not a chevron: a chevron says structure, an arrow says time (the author's\n * ruling, 2026-08-28). Added beside `arrowRight` so the pair share a set. */\n | \"arrowLeft\"\n /** History forward; also the one honest \"go there\" arrow where a link used\n * to carry a typed one. */\n | \"arrowRight\"\n /** Connect to a server, a live link, a running game. */\n | \"connect\"\n /** Search. */\n | \"search\"\n /** Keep this window on top (tool-window-web.ts). */\n | \"pin\"\n /** Settings. */\n | \"settings\"\n /** Record. The icon is the DISC; painting it in the danger colour while\n * recording is the caller's job, through the button's own colour. */\n | \"record\";\n\n// The two roots every drawing shares. Kept as constants so the table below is\n// the inner elements only, which is what a reader compares against lucide.dev.\nconst STROKE = '<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.571\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">';\nconst FILL = '<svg viewBox=\"0 0 24 24\" fill=\"currentColor\" aria-hidden=\"true\">';\nconst stroked = (inner: string): string => `${STROKE}${inner}</svg>`;\nconst filled = (inner: string): string => `${FILL}${inner}</svg>`;\n\n// The three discs are the one drawing in the table that is not Lucide's own\n// element as shipped: Lucide's `circle` is an r=10 outline that fills its box,\n// which at badge size beside a row title is a blot, so the disc is drawn at a\n// smaller radius with the fill forced (the same amount of hand-drawing as the\n// legacy noteFilled below, and the decision record's stated cost). `modified`\n// and `dot` share it, as their glyphs did; `record` is larger because a record\n// button is meant to fill more of its box.\nconst DISC = filled('<circle cx=\"12\" cy=\"12\" r=\"6\"/>');\nconst DISC_LARGE = filled('<circle cx=\"12\" cy=\"12\" r=\"9\"/>');\n\n/**\n * The drawings, by word. Each is a complete `<svg viewBox=\"0 0 24 24\" …>`\n * string with no width/height (see `iconNode` / `iconHtml`, which size it).\n * The Lucide name each derives from is on the entry, so a reviewer can put\n * the two side by side.\n */\nconst DRAWN: Record<IconName, string> = {\n // --- dismissing and revealing ---------------------------------------------\n /** Close a panel, a dialog, a popover. (x) */\n close: stroked('<path d=\"M18 6 6 18\"/><path d=\"m6 6 12 12\"/>'),\n /** The overflow menu on a document or a row: \"more about this\". (ellipsis) */\n more: stroked('<circle cx=\"12\" cy=\"12\" r=\"1\"/><circle cx=\"19\" cy=\"12\" r=\"1\"/><circle cx=\"5\" cy=\"12\" r=\"1\"/>'),\n /** Collapsed disclosure, pointing at what would open. (chevron-right) */\n collapsed: stroked('<path d=\"m9 18 6-6-6-6\"/>'),\n /** Expanded disclosure. (chevron-down) */\n expanded: stroked('<path d=\"m6 9 6 6 6-6\"/>'),\n /** A dropdown's affordance, where it is not a real <select>. (chevron-down) */\n dropdown: stroked('<path d=\"m6 9 6 6 6-6\"/>'),\n\n // --- moving through things ------------------------------------------------\n /** Back / previous, in a breadcrumb or a stepper. (chevron-left) */\n back: stroked('<path d=\"m15 18-6-6 6-6\"/>'),\n /** Forward / next. (chevron-right) */\n forward: stroked('<path d=\"m9 18 6-6-6-6\"/>'),\n /** Up one, in a list. (arrow-up) */\n up: stroked('<path d=\"m5 12 7-7 7 7\"/><path d=\"M12 19V5\"/>'),\n /** Down one. (arrow-down) */\n down: stroked('<path d=\"M12 5v14\"/><path d=\"m19 12-7 7-7-7\"/>'),\n /** History back. (arrow-left) */\n arrowLeft: stroked('<path d=\"m12 19-7-7 7-7\"/><path d=\"M19 12H5\"/>'),\n /** History forward; \"go there\". (arrow-right) */\n arrowRight: stroked('<path d=\"M5 12h14\"/><path d=\"m12 5 7 7-7 7\"/>'),\n\n // --- state ----------------------------------------------------------------\n /** Done, applied, agreed. (check) */\n tick: stroked('<path d=\"M20 6 9 17l-5-5\"/>'),\n /** Somebody else holds this: the version-control lock. (lock) */\n locked: stroked('<rect width=\"18\" height=\"11\" x=\"3\" y=\"11\" rx=\"2\" ry=\"2\"/><path d=\"M7 11V7a5 5 0 0 1 10 0v4\"/>'),\n /** Read-only on disk with no other holder. (lock-open) An open lock rather\n * than a struck-out eye: this state is not a prohibition. Nobody holds the\n * file, saving checks it out, and it is the resting state of everything the\n * author has not touched yet under a lock-based VCS. eye-off would say \"you\n * cannot\", which is false here; the open lock says \"not held\", beside\n * `locked`, which is the shut one, so the two read as a pair. */\n readOnly: stroked('<rect width=\"18\" height=\"11\" x=\"3\" y=\"11\" rx=\"2\" ry=\"2\"/><path d=\"M7 11V7a5 5 0 0 1 9.9-1\"/>'),\n /** YOU hold this one: checked out, still yours to edit. (pencil) */\n checkedOut: stroked('<path d=\"M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z\"/><path d=\"m15 5 4 4\"/>'),\n /** Tracked, with local changes not yet committed. (a disc; see DISC) */\n modified: DISC,\n /** Not in version control yet: new since the last commit. (plus) */\n untracked: stroked('<path d=\"M5 12h14\"/><path d=\"M12 5v14\"/>'),\n /** Something needs attention but is not fatal. (triangle-alert) */\n warning: stroked('<path d=\"m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3\"/><path d=\"M12 9v4\"/><path d=\"M12 17h.01\"/>'),\n /** A live thing: the running position, an active marker. (a disc) */\n dot: DISC,\n /** Play, in the sense of \"run this\". (play) */\n play: stroked('<path d=\"M5 5a2 2 0 0 1 3.008-1.728l11.997 6.998a2 2 0 0 1 .003 3.458l-12 7A2 2 0 0 1 5 19z\"/>'),\n /** Start the thing again from the top: a play session, a sweep. (rotate-ccw) */\n restart: stroked('<path d=\"M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8\"/><path d=\"M3 3v5h5\"/>'),\n /** The three ways a collection can be shown, named by what you get. */\n /** Cards. (layout-grid) */\n viewCards: stroked('<rect width=\"7\" height=\"7\" x=\"3\" y=\"3\" rx=\"1\"/><rect width=\"7\" height=\"7\" x=\"14\" y=\"3\" rx=\"1\"/><rect width=\"7\" height=\"7\" x=\"14\" y=\"14\" rx=\"1\"/><rect width=\"7\" height=\"7\" x=\"3\" y=\"14\" rx=\"1\"/>'),\n /** A table. (rows-3: a ruled box, which is a table. `list` is bullets, and\n * the view is not a list.) */\n viewTable: stroked('<rect width=\"18\" height=\"18\" x=\"3\" y=\"3\" rx=\"2\"/><path d=\"M21 9H3\"/><path d=\"M21 15H3\"/>'),\n /** A node graph. (waypoints: four nodes on edges reads as a graph.\n * `git-fork` reads as version control, which this family also draws, and\n * a picture that means two things is the fault this table exists to\n * prevent.) */\n viewNode: stroked('<path d=\"m10.586 5.414-5.172 5.172\"/><path d=\"m18.586 13.414-5.172 5.172\"/><path d=\"M6 12h12\"/><circle cx=\"12\" cy=\"20\" r=\"2\"/><circle cx=\"12\" cy=\"4\" r=\"2\"/><circle cx=\"20\" cy=\"12\" r=\"2\"/><circle cx=\"4\" cy=\"12\" r=\"2\"/>'),\n /** Record: the disc, in whatever colour the button is. (a disc; see DISC_LARGE) */\n record: DISC_LARGE,\n\n // --- handling -------------------------------------------------------------\n /** The drag grip on a reorderable row. (grip-vertical) */\n grip: stroked('<circle cx=\"9\" cy=\"12\" r=\"1\"/><circle cx=\"9\" cy=\"5\" r=\"1\"/><circle cx=\"9\" cy=\"19\" r=\"1\"/><circle cx=\"15\" cy=\"12\" r=\"1\"/><circle cx=\"15\" cy=\"5\" r=\"1\"/><circle cx=\"15\" cy=\"19\" r=\"1\"/>'),\n /** Add one of whatever this list holds. (plus) */\n add: stroked('<path d=\"M5 12h14\"/><path d=\"M12 5v14\"/>'),\n /** Connect: to a server, a live link, a running game. (plug) */\n connect: stroked('<path d=\"M12 22v-5\"/><path d=\"M15 8V2\"/><path d=\"M17 8a1 1 0 0 1 1 1v4a4 4 0 0 1-4 4h-4a4 4 0 0 1-4-4V9a1 1 0 0 1 1-1z\"/><path d=\"M9 8V2\"/>'),\n /** Search. (search) */\n search: stroked('<path d=\"m21 21-4.34-4.34\"/><circle cx=\"11\" cy=\"11\" r=\"8\"/>'),\n /** Keep this window on top. (pin) */\n pin: stroked('<path d=\"M12 17v5\"/><path d=\"M9 10.76a2 2 0 0 1-1.11 1.79l-1.78.9A2 2 0 0 0 5 15.24V16a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-.76a2 2 0 0 0-1.11-1.79l-1.78-.9A2 2 0 0 1 15 10.76V7a1 1 0 0 1 1-1 2 2 0 0 0 0-4H8a2 2 0 0 0 0 4 1 1 0 0 1 1 1z\"/>'),\n /** Settings. (settings) */\n settings: stroked('<path d=\"M9.671 4.136a2.34 2.34 0 0 1 4.659 0 2.34 2.34 0 0 0 3.319 1.915 2.34 2.34 0 0 1 2.33 4.033 2.34 2.34 0 0 0 0 3.831 2.34 2.34 0 0 1-2.33 4.033 2.34 2.34 0 0 0-3.319 1.915 2.34 2.34 0 0 1-4.659 0 2.34 2.34 0 0 0-3.32-1.915 2.34 2.34 0 0 1-2.33-4.033 2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915\"/><circle cx=\"12\" cy=\"12\" r=\"3\"/>'),\n\n // --- annotation -----------------------------------------------------------\n /** Documentation notes: a document with lines on it. (file-text) The glyph\n * table drew a pencil and shared it with `checkedOut`; the drawn set gives\n * the two meanings two shapes, and notes get the document, which is what\n * the shell's own noteFilled/noteOutline pair had always drawn. */\n note: stroked('<path d=\"M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z\"/><path d=\"M14 2v5a1 1 0 0 0 1 1h5\"/><path d=\"M10 9H8\"/><path d=\"M16 13H8\"/><path d=\"M16 17H8\"/>'),\n /** A comment thread. Speech, not a document: documentation states the\n * reason, comments are the conversation, and the two must never look\n * alike. (message-square) */\n comment: stroked('<path d=\"M22 17a2 2 0 0 1-2 2H6.828a2 2 0 0 0-1.414.586l-2.202 2.202A.71.71 0 0 1 2 21.286V5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2z\"/>'),\n};\n\n/**\n * The drawings as strings, by word, for a caller that builds markup itself.\n * Prefer `iconHtml(name, size)`, which sizes it; these carry no width/height.\n *\n * Two legacy entries ride along unchanged: `noteFilled` and `noteOutline`, the\n * has-notes / no-notes pair Patterpad drew on a 16-unit grid before the set\n * existed. They are sized in the markup (13px) and on their own grid, so they\n * are NOT part of the vocabulary above and `iconNode` does not know them; no\n * app uses them today. They stay until a 24-grid pair replaces them, because\n * their two-state meaning (there are notes / there are none) has no Lucide\n * shape, and re-weighting the 16-grid drawing to the family stroke merges its\n * text lines.\n */\nexport const iconSvg = {\n ...DRAWN,\n /** A document with lines: notes exist on this thing. (legacy, 16 grid) */\n noteFilled: '<svg viewBox=\"0 0 16 16\" width=\"13\" height=\"13\" fill=\"currentColor\" fill-rule=\"evenodd\" aria-hidden=\"true\"><path d=\"M3.4 1.4h5.3L12.6 5.3v8.1a1.2 1.2 0 0 1-1.2 1.2H3.4a1.2 1.2 0 0 1-1.2-1.2V2.6A1.2 1.2 0 0 1 3.4 1.4ZM4.9 6.8h6.2v1.1H4.9Zm0 2.1h6.2v1.1H4.9Zm0 2.1h3.7v1.1H4.9Z\"/></svg>',\n /** The same document, empty: nothing written here yet. (legacy, 16 grid) */\n noteOutline: '<svg viewBox=\"0 0 16 16\" width=\"13\" height=\"13\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.1\" stroke-linejoin=\"round\" stroke-linecap=\"round\" aria-hidden=\"true\"><path d=\"M3.4 2h4.9l3.9 3.9v7.5a1 1 0 0 1-1 1H3.4a1 1 0 0 1-1-1V3a1 1 0 0 1 1-1Z\"/><path d=\"M8.3 2.2v3.8h3.8\"/><path d=\"M4.9 8h6.2M4.9 10h6.2M4.9 12h3.7\" stroke-width=\"0.95\"/></svg>',\n} as const;\n\nexport type IconSvgName = keyof typeof iconSvg;\n\n/** Every word, in table order, for a test or a gallery to walk. */\nexport const ICON_NAMES = Object.keys(DRAWN) as IconName[];\n\n/** The default size: 14px, the family's icon inside its small square button. */\nexport const ICON_SIZE = 14;\n\n/**\n * The drawing as markup with its size set, for a caller building innerHTML.\n * `data-icon` carries the word, so a stylesheet or a test can find it.\n */\nexport function iconHtml(name: IconName, size = ICON_SIZE): string {\n return DRAWN[name].replace(\"<svg \", `<svg width=\"${size}\" height=\"${size}\" data-icon=\"${name}\" `);\n}\n\n// One parsed template per word, filled on first use; every call clones it, so\n// the string is parsed once per window and each caller gets its own node.\nconst templates = new Map<IconName, SVGSVGElement>();\n\n/**\n * The drawing as a fresh SVG node, sized. Append it where the glyph used to be\n * set as text; it is `aria-hidden`, so the button's accessible name stays the\n * button's (`aria-label` / `data-tip`), as it always had to.\n */\nexport function iconNode(name: IconName, size = ICON_SIZE): SVGSVGElement {\n let tpl = templates.get(name);\n if (!tpl) {\n const holder = document.createElement(\"template\");\n holder.innerHTML = DRAWN[name];\n tpl = holder.content.firstElementChild as SVGSVGElement;\n tpl.setAttribute(\"data-icon\", name);\n templates.set(name, tpl);\n }\n const node = tpl.cloneNode(true) as SVGSVGElement;\n node.setAttribute(\"width\", String(size));\n node.setAttribute(\"height\", String(size));\n return node;\n}\n\n// The glyph table, reversed, so a legacy call site that still hands the shell\n// a typed character (\"✕\", \"↑\") draws the word it stood for. Where two words\n// shared a glyph the first in table order wins, which is fine: the picture was\n// the same either way. Goes when `icon` does.\nconst BY_GLYPH = new Map<string, IconName>();\nfor (const [name, glyph] of Object.entries(icon) as [IconName, string][]) {\n if (!BY_GLYPH.has(glyph)) BY_GLYPH.set(glyph, name);\n}\n\n/** The word a deprecated glyph stood for, or undefined for any other string. */\nexport function iconNameOfGlyph(glyph: string): IconName | undefined {\n return BY_GLYPH.get(glyph);\n}\n\n/** Whether a string is a word in the vocabulary. */\nexport function isIconName(s: string): s is IconName {\n return Object.prototype.hasOwnProperty.call(DRAWN, s);\n}\n","// ---------------------------------------------------------------------------\n// `el`: the tiny tag-typed element factory both apps build their imperative,\n// idempotent views with.\n//\n// A SUPERSET of the two apps' prior signatures, so neither rewrites call sites:\n// - Patterpad: el(tag, cls?, text?) (positional)\n// - Storylet Studio: el(tag, { className, text, ... }, ...kids) (options bag)\n// A string second argument is the className; an object is the props bag; string\n// children become text nodes. So `el(\"div\", \"c\", \"t\")` and\n// `el(\"div\", { className: \"c\" }, \"t\")` produce identical DOM.\n// ---------------------------------------------------------------------------\n\nimport { ensureTooltipHost, checkTooltipHost } from \"./tooltip.js\";\nimport { iconNode, iconNameOfGlyph, isIconName, type IconName } from \"./icons.js\";\n\nexport type Child = Node | string | null | undefined;\n\nexport interface ElProps {\n className?: string;\n text?: string;\n /** A NATIVE rollover. Prefer `tip`: `title` is OS chrome on the platform's own\n * slow delay, which is the seam the themed tooltip exists to close. */\n title?: string;\n /** A themed rollover (`data-tip`, picked up by the delegated controller that\n * `initTooltips()` wires). Also the accessible name, since the elements that\n * want one are usually icon buttons with no text of their own. */\n tip?: string;\n onClick?: (event: MouseEvent) => void;\n}\n\nexport function el<K extends keyof HTMLElementTagNameMap>(\n tag: K,\n classNameOrProps?: string | ElProps,\n ...children: Child[]\n): HTMLElementTagNameMap[K] {\n const node = document.createElement(tag);\n const props: ElProps = typeof classNameOrProps === \"string\"\n ? { className: classNameOrProps }\n : classNameOrProps ?? {};\n if (props.className) node.className = props.className;\n if (props.text !== undefined && props.text !== null) node.textContent = props.text;\n if (props.title !== undefined) node.title = props.title;\n if (props.tip !== undefined) {\n node.dataset[\"tip\"] = props.tip;\n node.setAttribute(\"aria-label\", props.tip);\n // Setting a tip mounts the renderer. Without this, `data-tip` draws nothing at all in a window whose\n // host never called `initTooltips()`, which is a silent failure rather than a degraded one. No\n // options passed: the host stays authoritative about behaviour (see tooltip.ts).\n ensureTooltipHost();\n }\n if (props.onClick) node.addEventListener(\"click\", props.onClick as EventListener);\n for (const child of children) {\n if (child === null || child === undefined) continue;\n node.append(child);\n }\n checkTooltipHost(); // one-shot: warns if the APP wrote data-tip and nothing mounted a host\n return node;\n}\n\n/** A small square icon button (the move/delete controls list editors share).\n * Its rollover is the THEMED one (`data-tip`), so an app that has called\n * `initTooltips()` gets our bubble rather than the platform's.\n *\n * `name` is a word from the vocabulary (\"up\", \"close\"), drawn at 14px. A\n * typed glyph from the deprecated `icon` table (\"↑\", \"✕\") is accepted for\n * now and drawn as the word it stood for, so an app that has not moved its\n * call sites yet still gets the drawn set; any other string is set as text,\n * which is the old behaviour and on its way out. */\nexport function iconBtn(name: IconName | (string & {}), title: string, onClick: () => void, disabled = false, danger = false): HTMLButtonElement {\n const b = el(\"button\", `shell-icon${danger ? \" danger\" : \"\"}`);\n b.type = \"button\"; b.dataset[\"tip\"] = title; b.setAttribute(\"aria-label\", title);\n const word = isIconName(name) ? name : iconNameOfGlyph(name);\n if (word) b.append(iconNode(word)); else b.textContent = name;\n b.disabled = disabled;\n b.addEventListener(\"click\", onClick);\n return b;\n}\n\n/**\n * A captioned field: `<label class=\"shell-labelled\"><span class=\"shell-fieldcap\">…</span>control</label>`.\n *\n * The label is pointed at the field it captions, EXPLICITLY, and never at a button. A `<label>` with no\n * `for` forwards a click to its first labelable descendant, and buttons are labelable - so a caption\n * wrapped around a control containing buttons (`tagChips`, whose every chip carries a remove button)\n * turns every click on the row's dead space into a press of the FIRST button in it. That shipped:\n * patterkit/patter#44, where clicking a Game Data list value anywhere but its ✕ deleted the first value\n * in the list. Reported as \"clicking a value removes the wrong one\", which is not a wrong-index bug at\n * all - the click never reached the chip.\n *\n * When the control holds no labelable field (a chips editor with the add input removed, say), this is a\n * plain `<div>`: no caption behaviour is better than a caption that presses something.\n */\nexport function labelled(label: string, control: HTMLElement): HTMLElement {\n const target = control.matches(\"input, select, textarea\")\n ? control\n : control.querySelector<HTMLElement>(\"input:not([type=button]):not([type=submit]), select, textarea\");\n const w = el(target ? \"label\" : \"div\", \"shell-labelled\");\n w.append(el(\"span\", \"shell-fieldcap\", label), control);\n if (target) {\n if (!target.id) target.id = `shell-f-${Math.random().toString(36).slice(2, 9)}`;\n (w as HTMLLabelElement).htmlFor = target.id;\n }\n return w;\n}\n\n/** Swap item `i` with its neighbour `i + delta` IN PLACE (the up/down reorder list editors share);\n * a no-op when the target is out of range. Returns whether anything moved. */\nexport function moveItem<T>(arr: T[], i: number, delta: number): boolean {\n const j = i + delta;\n if (j < 0 || j >= arr.length) return false;\n [arr[i], arr[j]] = [arr[j]!, arr[i]!];\n return true;\n}\n\n/** The icon size inside a chip's remove / move buttons: the chip is set at\n * 0.76rem, so its controls draw smaller than a toolbar button's 14px. */\nconst CHIP_ICON = 10;\n\n/** A tag-style editor for a string-list field (an enum's allowed values / flags): removable chips + an\n * add input (Enter or \",\" commits; blank / duplicate ignored). Mutates `holder.values` in place (read\n * back on save). `onChange` fires after any add / remove so callers can refresh a dependent control. */\nexport function tagChips(holder: { values?: string[] }, onChange?: () => void): HTMLElement {\n const wrap = el(\"div\", \"shell-tags\");\n const input = el(\"input\", \"shell-tag-input\");\n // Sentence-cased like every other hint (the microcopy ruling, 2026-08-28):\n // lowercase fragments read as adrift, and a placeholder is a hint speaking.\n input.type = \"text\"; input.placeholder = \"Add value\"; input.spellcheck = false;\n const makeChip = (v: string): HTMLElement => {\n const chip = el(\"span\", \"shell-tag\", v);\n const x = el(\"button\", \"shell-tag-x\", iconNode(\"close\", CHIP_ICON));\n x.type = \"button\"; x.dataset[\"tip\"] = `Remove ${v}`; x.setAttribute(\"aria-label\", `Remove ${v}`);\n x.addEventListener(\"click\", () => { holder.values = (holder.values ?? []).filter((o) => o !== v); chip.remove(); onChange?.(); });\n chip.append(x);\n return chip;\n };\n const commit = (): void => {\n const v = input.value.trim();\n if (v && !(holder.values ?? []).includes(v)) { (holder.values ??= []).push(v); wrap.insertBefore(makeChip(v), input); onChange?.(); }\n input.value = \"\";\n };\n input.addEventListener(\"keydown\", (e) => { if (e.key === \"Enter\" || e.key === \",\") { e.preventDefault(); commit(); } });\n input.addEventListener(\"blur\", commit);\n for (const v of holder.values ?? []) wrap.append(makeChip(v));\n wrap.append(input);\n return wrap;\n}\n\n/**\n * An ORDERED chips editor for a string-list field whose order means something\n * (a quality's stages: `advance()` walks them, so 2 comes after 1): numbered\n * chips, each with move-earlier / move-later / remove, plus an add input\n * (Enter or \",\" commits; blank / duplicate ignored). Mutates `holder.stages`\n * in place; `onChange` fires after any add / move / remove.\n *\n * Patterpad's, lifted (ui-review-2026-09, finding 3); Storyletter had been\n * faking it with `tagChips` over a `values` holder, which loses the order\n * controls. Same class family as `tagChips` (`.shell-tags`), so it is styled by\n * settings.css already.\n */\nexport function stageChips(holder: { stages?: string[] }, onChange?: () => void): HTMLElement {\n const wrap = el(\"div\", \"shell-tags shell-stages\");\n const input = el(\"input\", \"shell-tag-input\");\n input.type = \"text\"; input.placeholder = \"Add stage\"; input.spellcheck = false;\n const control = (name: IconName, tip: string, disabled: boolean, onClick: () => void): HTMLButtonElement => {\n const b = el(\"button\", \"shell-tag-x shell-tag-move\", iconNode(name, CHIP_ICON));\n b.type = \"button\"; b.dataset[\"tip\"] = tip; b.setAttribute(\"aria-label\", tip);\n b.disabled = disabled;\n b.addEventListener(\"click\", onClick);\n return b;\n };\n const rebuild = (): void => {\n for (const c of Array.from(wrap.children)) if (c !== input) c.remove();\n const stages = holder.stages ?? [];\n stages.forEach((v, i) => {\n const chip = el(\"span\", \"shell-tag\", `${i + 1}. ${v}`);\n chip.dataset[\"stage\"] = v;\n chip.append(\n control(\"back\", `Move ${v} earlier`, i === 0,\n () => { if (moveItem(stages, i, -1)) { rebuild(); onChange?.(); } }),\n control(\"forward\", `Move ${v} later`, i === stages.length - 1,\n () => { if (moveItem(stages, i, 1)) { rebuild(); onChange?.(); } }),\n );\n const x = el(\"button\", \"shell-tag-x\", iconNode(\"close\", CHIP_ICON));\n x.type = \"button\"; x.dataset[\"tip\"] = `Remove ${v}`; x.setAttribute(\"aria-label\", `Remove ${v}`);\n x.addEventListener(\"click\", () => { holder.stages = (holder.stages ?? []).filter((o) => o !== v); rebuild(); onChange?.(); });\n chip.append(x);\n wrap.insertBefore(chip, input);\n });\n };\n const commit = (): void => {\n const v = input.value.trim();\n if (v && !(holder.stages ?? []).includes(v)) { (holder.stages ??= []).push(v); rebuild(); onChange?.(); }\n input.value = \"\";\n };\n input.addEventListener(\"keydown\", (e) => { if (e.key === \"Enter\" || e.key === \",\") { e.preventDefault(); commit(); } });\n input.addEventListener(\"blur\", commit);\n wrap.append(input);\n rebuild();\n return wrap;\n}\n\n// --- drag-to-reorder ---------------------------------------------------------\n// One drag at a time per window, shared across every wired list, so the\n// midpoint test knows what is being carried without a dataTransfer round trip.\nlet reorderDragId: string | null = null;\nconst clearDropMarks = (host: ParentNode): void =>\n host.querySelectorAll(\".drop-before, .drop-after\").forEach((e) => e.classList.remove(\"drop-before\", \"drop-after\"));\n\n/**\n * Make `el` a drag source and a drop target for HTML5 drag-to-reorder among\n * its siblings. While carried it wears `.dragging`; a hovered target wears\n * `.drop-before` or `.drop-after` by the midpoint test on `axis` (\"y\" for\n * rows, \"x\" for a wrapping grid); a drop calls `onMove(draggedId, before,\n * targetId)` and the caller reorders its model and re-renders.\n *\n * Storyletter's `wireCardDrag`, lifted (ui-review-2026-09, finding 30);\n * Patterpad's `wireSceneDrag` is the same idea fixed on \"y\". The marks are\n * classes only: the app draws them (Patterpad's `box-shadow: 0 -2px 0 0\n * var(--accent)` pair is the family's look).\n */\nexport function wireReorder(el: HTMLElement, id: string, axis: \"x\" | \"y\", onMove: (id: string, before: boolean, targetId: string) => void): void {\n el.draggable = true;\n el.dataset[\"reorderId\"] = id;\n const host = (): ParentNode => el.parentElement ?? el;\n el.addEventListener(\"dragstart\", (e) => {\n reorderDragId = id; el.classList.add(\"dragging\");\n if (e.dataTransfer) { e.dataTransfer.effectAllowed = \"move\"; e.dataTransfer.setData(\"text/plain\", id); }\n });\n el.addEventListener(\"dragend\", () => { reorderDragId = null; el.classList.remove(\"dragging\"); clearDropMarks(host()); });\n el.addEventListener(\"dragover\", (e) => {\n if (!reorderDragId || reorderDragId === id) return;\n e.preventDefault();\n if (e.dataTransfer) e.dataTransfer.dropEffect = \"move\";\n const r = el.getBoundingClientRect();\n const before = axis === \"y\" ? e.clientY < r.top + r.height / 2 : e.clientX < r.left + r.width / 2;\n clearDropMarks(host());\n el.classList.add(before ? \"drop-before\" : \"drop-after\");\n });\n el.addEventListener(\"dragleave\", () => el.classList.remove(\"drop-before\", \"drop-after\"));\n el.addEventListener(\"drop\", (e) => {\n e.preventDefault();\n const before = el.classList.contains(\"drop-before\");\n clearDropMarks(host());\n if (reorderDragId && reorderDragId !== id) onMove(reorderDragId, before, id);\n });\n}\n\n// --- metadata and breadcrumbs ---------------------------------------------------\n// \"Icons are drawn, and so are separators\" (design-language.md section 4,\n// 2026-09-16): metadata is never joined with \"·\" and a breadcrumb is never a\n// string with \"›\" in it. Both apps had been building exactly those strings\n// (ui-review-2026-09, marker A); these two helpers make the same lines as DOM,\n// with the separator drawn by CSS (controls.css) or by the icon vocabulary.\n\n/**\n * A metadata line: `parts` as spans in a flex row, separated by a drawn\n * 3px disc (a `::before` on every part after the first, in controls.css),\n * so `metaLine([\"6 runs\", \"200 max steps\", \"seed 4\"])` is what\n * \"6 runs · 200 max steps · seed 4\" used to be, without the typed dot.\n * Empty, null and undefined parts are skipped, so a caller can pass an\n * optional segment without branching.\n */\nexport function metaLine(parts: (string | Node | null | undefined)[]): HTMLElement {\n const row = el(\"span\", \"shell-meta\");\n for (const part of parts) {\n if (part === null || part === undefined || part === \"\") continue;\n const seg = el(\"span\", \"shell-meta-part\");\n seg.append(part);\n row.append(seg);\n }\n return row;\n}\n\nexport interface Crumb {\n label: string;\n /** Makes the crumb a button. Ignored on the last crumb, which is where the\n * reader already is. */\n onClick?: (event: MouseEvent) => void;\n}\n\n/**\n * A breadcrumb trail: each crumb a span, or a button when it carries\n * `onClick` and is not the last, with `iconNode(\"forward\", 12)` drawn between\n * them. `breadcrumb([\"Box\", \"Deck\", \"Card\"])` is what \"Box › Deck › Card\"\n * used to be; the chevrons are the family's own drawing, not a symbol-font\n * character.\n */\nexport function breadcrumb(parts: (string | Crumb)[]): HTMLElement {\n const trail = el(\"nav\", \"shell-crumbs\");\n trail.setAttribute(\"aria-label\", \"Where this is\");\n parts.forEach((part, i) => {\n const crumb: Crumb = typeof part === \"string\" ? { label: part } : part;\n const last = i === parts.length - 1;\n if (i > 0) {\n const sep = iconNode(\"forward\", 12);\n sep.classList.add(\"shell-crumb-sep\");\n trail.append(sep);\n }\n if (crumb.onClick && !last) {\n const b = el(\"button\", { className: \"shell-crumb shell-crumb-link\", text: crumb.label, onClick: crumb.onClick });\n b.type = \"button\";\n trail.append(b);\n } else {\n const s = el(\"span\", \"shell-crumb\", crumb.label);\n if (last) s.setAttribute(\"aria-current\", \"location\");\n trail.append(s);\n }\n });\n return trail;\n}\n","// ---------------------------------------------------------------------------\n// The per-entity colour model (design-language.md section 4): a stable hash of\n// a name selects an INDEX into the curated palette - repeatable, storage-free.\n// The hues live in the token layer as `--char-0 .. --char-(N-1)` per theme, so\n// a colour reference adapts to light/dark with zero JS. Each app defines the\n// `--char-*` values in its own palette; this module only picks the slot.\n//\n// Storylet Studio uses it for dimension-value / zone chips; Patterpad for\n// character cues.\n// ---------------------------------------------------------------------------\n\n/** Curated colour slots; must match the `--char-*` set defined per theme. */\nexport const PALETTE_SIZE = 12;\n\nexport const PALETTE = Array.from({ length: PALETTE_SIZE }, (_, i) => `var(--char-${i})`) as readonly string[];\n\n/** Hash a name to a palette slot: FNV-1a + an fmix32 avalanche, well\n * distributed even for short, similar names. */\nexport function colourIndex(name: string): number {\n let h = 0x811c9dc5;\n for (let i = 0; i < name.length; i++) { h ^= name.charCodeAt(i); h = Math.imul(h, 0x01000193); }\n h ^= h >>> 16; h = Math.imul(h, 0x85ebca6b); h ^= h >>> 13; h = Math.imul(h, 0xc2b2ae35); h ^= h >>> 16;\n return (h >>> 0) % PALETTE_SIZE;\n}\n\n/** The theme-aware CSS variable reference for a name's slot. */\nexport function colourFor(name: string): string {\n return PALETTE[colourIndex(name)]!;\n}\n","// ---------------------------------------------------------------------------\n// Keyboard hints, platform-true, from ONE helper.\n//\n// \"One casing rule, and platform-true key hints\" (design-language.md section\n// 4, 2026-09-16): a hint writes \"⌘\" on macOS and \"Ctrl\" elsewhere, and \"⌘\"\n// never appears in a hard-coded string. Before this module the family had four\n// notations for one idea (ui-review-2026-09, finding 26): a <kbd> here, \"(⌘1)\"\n// in a tooltip there, a platform fork in one label, and \"↑↓ move · ↵ jump ·\n// esc to close\" typed into a hint bar, which on Windows showed a Mac glyph.\n//\n// The input is the portable spelling every caller already knows from the menu\n// spine: \"Mod+1\", \"Mod+Shift+M\", \"Enter\", \"Esc\", \"Up\". The output is what the\n// platform writes: \"⌘1\" / \"⇧⌘M\" / \"↩\" / \"esc\" on a Mac, in Apple's modifier\n// order and with no joiner; \"Ctrl+1\" / \"Ctrl+Shift+M\" / \"Enter\" / \"Esc\"\n// everywhere else. A hint is DOM (`keyHint`, `hintBar`): a keycap element,\n// never a glyph string, and a tooltip gets its bracketed key from\n// `tipWithKey` so it is right on both platforms.\n// ---------------------------------------------------------------------------\n\nexport type KeyPlatform = \"mac\" | \"win\" | \"linux\";\n\nlet override: KeyPlatform | undefined;\n\n/** Pin the platform every helper here renders for (undefined = detect again).\n * A seam for the tests and for a preview harness; an app leaves it unset. */\nexport function setKeyPlatform(platform?: KeyPlatform): void { override = platform; }\n\n/** The platform the hints render for: the override, else the browser's, else\n * the process's, else \"linux\" (which draws the same as \"win\"). */\nexport function keyPlatform(): KeyPlatform {\n if (override) return override;\n if (typeof navigator !== \"undefined\") {\n const s = `${navigator.platform ?? \"\"} ${navigator.userAgent ?? \"\"}`;\n if (/mac|iphone|ipad/i.test(s)) return \"mac\";\n if (/win/i.test(s)) return \"win\";\n if (s.trim()) return \"linux\";\n }\n const p = typeof process !== \"undefined\" ? process.platform : undefined;\n return p === \"darwin\" ? \"mac\" : p === \"win32\" ? \"win\" : \"linux\";\n}\n\n/** Canonical modifier words, in the order each platform writes them. Apple\n * puts them ⌃ ⌥ ⇧ ⌘ before the key; Windows and Linux write Ctrl+Alt+Shift. */\ntype Modifier = \"ctrl\" | \"alt\" | \"shift\" | \"mod\";\nconst MAC_ORDER: Modifier[] = [\"ctrl\", \"alt\", \"shift\", \"mod\"];\nconst OTHER_ORDER: Modifier[] = [\"mod\", \"ctrl\", \"alt\", \"shift\"];\nconst MAC_MOD: Record<Modifier, string> = { ctrl: \"⌃\", alt: \"⌥\", shift: \"⇧\", mod: \"⌘\" };\nconst OTHER_MOD: Record<Modifier, string> = { ctrl: \"Ctrl\", alt: \"Alt\", shift: \"Shift\", mod: \"Ctrl\" };\n\nconst MODIFIER_ALIASES: Record<string, Modifier> = {\n mod: \"mod\", cmd: \"mod\", command: \"mod\", meta: \"mod\", super: \"mod\",\n ctrl: \"ctrl\", control: \"ctrl\",\n alt: \"alt\", option: \"alt\", opt: \"alt\",\n shift: \"shift\",\n};\n\n/** Named keys: the Mac legend and the spelled-out word the others use. */\nconst NAMED: Record<string, { mac: string; other: string }> = {\n enter: { mac: \"↩\", other: \"Enter\" }, return: { mac: \"↩\", other: \"Enter\" },\n esc: { mac: \"esc\", other: \"Esc\" }, escape: { mac: \"esc\", other: \"Esc\" },\n up: { mac: \"↑\", other: \"Up\" }, down: { mac: \"↓\", other: \"Down\" },\n left: { mac: \"←\", other: \"Left\" }, right: { mac: \"→\", other: \"Right\" },\n backspace: { mac: \"⌫\", other: \"Backspace\" }, delete: { mac: \"⌦\", other: \"Del\" }, del: { mac: \"⌦\", other: \"Del\" },\n tab: { mac: \"⇥\", other: \"Tab\" }, space: { mac: \"Space\", other: \"Space\" },\n home: { mac: \"↖\", other: \"Home\" }, end: { mac: \"↘\", other: \"End\" },\n pageup: { mac: \"⇞\", other: \"PgUp\" }, pagedown: { mac: \"⇟\", other: \"PgDn\" },\n};\n\ninterface Parsed { mods: Modifier[]; key: string | undefined }\n\n/** The portable modifier words, exactly: the spelling the menu spine uses. The\n * aliases above (\"Cmd\", \"Option\") are tolerated by `parse` but they are not\n * portable, which is what `isKeyCombo` keys on. */\nconst PORTABLE_MODS = new Set<string>([\"mod\", \"ctrl\", \"alt\", \"shift\"]);\n\n/** Split \"Mod+Shift+M\" into its modifiers and its key. A literal \"+\" key is\n * written \"Mod++\" (the last empty part). Case is ignored on the words. */\nfunction parse(combo: string): Parsed {\n const parts = combo.split(\"+\");\n const mods: Modifier[] = [];\n let key: string | undefined;\n for (let i = 0; i < parts.length; i++) {\n const raw = parts[i] ?? \"\";\n if (raw === \"\" && i > 0) { key = \"+\"; continue; }\n const mod = MODIFIER_ALIASES[raw.toLowerCase()];\n if (mod) { if (!mods.includes(mod)) mods.push(mod); continue; }\n key = raw;\n }\n return { mods, key };\n}\n\n/**\n * Whether `value` is a combo in the portable spelling (\"Mod+1\", \"Ctrl+Shift+M\",\n * \"Enter\", \"Mod++\") rather than a literal hint someone already wrote out\n * (\"Cmd+1\", \"⌘1\", \"F1 twice\"). The test is strict on purpose: only the words\n * `Mod`, `Ctrl`, `Alt` and `Shift` (any case) count as modifiers, and the one\n * key must be a single character or a named key. A place that took a literal\n * string before (the pane shell's `shortcutHint`) can then take a combo as\n * well without changing what any existing literal draws.\n */\nexport function isKeyCombo(value: string): boolean {\n // \"Mod++\" is the plus key, as `parse` reads it: count it, then read the rest.\n const plus = value.length > 2 && value.endsWith(\"++\");\n const parts = (plus ? value.slice(0, -2) : value).split(\"+\");\n let keys = plus ? 1 : 0;\n for (const raw of parts) {\n if (raw === \"\") return false;\n const word = raw.toLowerCase();\n if (PORTABLE_MODS.has(word)) continue;\n if (raw.length === 1 || word in NAMED) { keys++; continue; }\n return false;\n }\n return keys === 1;\n}\n\nfunction keyLegend(key: string, mac: boolean): string {\n const named = NAMED[key.toLowerCase()];\n if (named) return mac ? named.mac : named.other;\n return key.length === 1 ? key.toUpperCase() : key;\n}\n\n/** The platform's spelling of a combo as one string: \"⇧⌘M\" on a Mac,\n * \"Ctrl+Shift+M\" elsewhere. For a tooltip or a menu label; a visible hint in\n * a window is `keyHint` (a keycap), not this. */\nexport function keyLabel(combo: string, platform: KeyPlatform = keyPlatform()): string {\n const mac = platform === \"mac\";\n const { mods, key } = parse(combo);\n const order = mac ? MAC_ORDER : OTHER_ORDER;\n const words = order.filter((m) => mods.includes(m)).map((m) => (mac ? MAC_MOD : OTHER_MOD)[m]);\n // On Windows \"Mod\" and \"Ctrl\" are both Ctrl; say it once.\n const seen = new Set<string>();\n const modWords = words.filter((w) => (seen.has(w) ? false : (seen.add(w), true)));\n const legend = key === undefined ? [] : [keyLegend(key, mac)];\n return mac ? [...modWords, ...legend].join(\"\") : [...modWords, ...legend].join(\"+\");\n}\n\n/** The legends of a combo as the platform would draw them on keycaps: one\n * entry on a Mac (Apple's glyph string is one legend), one per key elsewhere. */\nexport function keyLegends(combo: string, platform: KeyPlatform = keyPlatform()): string[] {\n if (platform === \"mac\") return [keyLabel(combo, platform)];\n const { mods, key } = parse(combo);\n const seen = new Set<string>();\n const words = OTHER_ORDER.filter((m) => mods.includes(m)).map((m) => OTHER_MOD[m])\n .filter((w) => (seen.has(w) ? false : (seen.add(w), true)));\n return key === undefined ? words : [...words, keyLegend(key, false)];\n}\n\nexport interface KeyHintOptions {\n /** Render for this platform rather than the detected one. */\n platform?: KeyPlatform;\n}\n\nfunction chip(legend: string): HTMLElement {\n const k = document.createElement(\"kbd\");\n k.className = \"shell-kbd\";\n k.textContent = legend;\n return k;\n}\n\n/**\n * A keycap for `combo`: `<kbd class=\"shell-kbd\">` (keys.css). On a Mac one\n * chip carrying the glyph string (\"⇧⌘M\"); elsewhere one chip per key\n * (\"Ctrl\" \"Shift\" \"M\") side by side in a `<span class=\"shell-keys\">`, with no\n * typed joiner: keycaps beside each other read as \"together\". `combo` may\n * also list ALTERNATIVES separated by spaces (\"Up Down\" for a move hint),\n * each drawn as its own keycap.\n */\nexport function keyHint(combo: string, opts: KeyHintOptions = {}): HTMLElement {\n const platform = opts.platform ?? keyPlatform();\n const legends = combo.trim().split(/\\s+/).flatMap((c) => keyLegends(c, platform));\n if (legends.length === 1) return chip(legends[0]!);\n const group = document.createElement(\"span\");\n group.className = \"shell-keys\";\n for (const legend of legends) group.append(chip(legend));\n return group;\n}\n\nexport interface HintBarItem {\n /** A combo, or space-separated alternatives (\"Up Down\"). */\n keys: string;\n /** What the key does, as a sentence-case fragment (\"Move\", \"Jump\"). */\n label: string;\n}\n\n/**\n * The hint bar under a picker or a tool window (\"↑↓ move · ↵ jump · esc\n * close\" as it used to be typed): one `<div class=\"shell-hintbar\">` of\n * `<span class=\"shell-hint\">` items, each a keycap (`keyHint`) and a label,\n * spaced by CSS and separated by nothing typed at all.\n */\nexport function hintBar(items: HintBarItem[], opts: KeyHintOptions = {}): HTMLElement {\n const bar = document.createElement(\"div\");\n bar.className = \"shell-hintbar\";\n for (const item of items) {\n const hint = document.createElement(\"span\");\n hint.className = \"shell-hint\";\n const label = document.createElement(\"span\");\n label.className = \"shell-hint-label\";\n label.textContent = item.label;\n hint.append(keyHint(item.keys, opts), label);\n bar.append(hint);\n }\n return bar;\n}\n\n/** Tooltip text with its key in brackets, platform-true: `tipWithKey(\"Show\n * scenes\", \"Mod+1\")` is \"Show scenes (⌘1)\" on a Mac and \"Show scenes\n * (Ctrl+1)\" elsewhere. For `data-tip`; the pane shell calls it itself when\n * `PaneSideConfig.shortcutHint` is a combo. */\nexport function tipWithKey(text: string, combo: string, platform: KeyPlatform = keyPlatform()): string {\n return `${text} (${keyLabel(combo, platform)})`;\n}\n","// ---------------------------------------------------------------------------\n// mountPaneShell: the app-frame both editors share - a top bar with compact\n// pane toggles, a nav | centre | inspector grid whose side panes collapse and\n// resize, and width/open-state persistence via a host callback. The host fills\n// the pane bodies + top-bar slots and owns its own keyboard accelerators\n// (call togglePane); the frame owns layout, collapse, drag-resize, and state.\n//\n// The frame CSS ships alongside as pane-shell.css (import it once at the app\n// root). It reads the shared token grammar (tokens.css).\n// ---------------------------------------------------------------------------\n\nimport { iconNode } from \"./icons.js\";\nimport { isKeyCombo, tipWithKey } from \"./keys.js\";\nimport { ensureTooltipHost } from \"./tooltip.js\";\n\nexport type PaneSide = \"nav\" | \"inspector\";\n\nexport interface PaneSideConfig {\n /** The open width as a CSS length, e.g. \"14rem\" or \"224px\". */\n defaultWidth: string;\n /** Drag floor in px (default 160). */\n minWidth?: number;\n /** Drag ceiling in px from the window width (default w => min(640, w - 420)). */\n maxWidth?: (innerWidth: number) => number;\n /** Whether a drag seam is offered (default true). */\n resizable?: boolean;\n /** Noun for the toggle's tooltip/aria, e.g. \"navigator\" / \"inspector\". */\n label?: string;\n /** The key that toggles the pane, bracketed after the tooltip. A combo in\n * the portable spelling (\"Mod+1\") is drawn for the platform through\n * `tipWithKey`: \"(⌘1)\" on a Mac, \"(Ctrl+1)\" elsewhere. Anything else is a\n * literal and goes in verbatim, as it always has (\"Cmd+1\" stays \"Cmd+1\"). */\n shortcutHint?: string;\n /** false = the pane is not offered at all: no toggle, togglePane ignored,\n * forced closed whatever the remembered state says. For a slot a host has\n * retired but keeps mounted (Storyletter's inspector) - the shell used to\n * offer a chevron that opened a paneful of nothing. Default true. */\n offered?: boolean;\n}\n\nexport interface PaneShellState {\n open: Record<PaneSide, boolean>;\n /** Dragged widths in px; absent = the config default. */\n width: Partial<Record<PaneSide, number>>;\n}\n\nexport interface PaneShellOptions {\n nav: PaneSideConfig;\n inspector: PaneSideConfig;\n /** Initial open + width state (from the host's store). */\n initial?: Partial<PaneShellState>;\n /** Persist state after any toggle or resize (host wires it to its store). */\n onChange?: (state: PaneShellState) => void;\n /** The toggle's rollover for a side in a given state. Default: \"Show\n * navigator\" / \"Hide navigator\" from the side's `label`, with the\n * `shortcutHint` in brackets (platform-true when it is a combo). Written as\n * `data-tip` (the themed tooltip) and as the accessible name; never as\n * `title`. */\n tipFor?: (side: PaneSide, open: boolean) => string;\n /** An extra class per side, toggled on the `.panes` grid whenever that side\n * is collapsed, beside the shell's own `no-nav` / `no-inspector`. For an\n * app whose stylesheet already keys on its own name for the state\n * (Patterpad's `props-doc-open`), so its rules ride the shell's collapse\n * rather than a second copy of it. */\n collapseAlso?: Partial<Record<PaneSide, string>>;\n}\n\nexport interface PaneShell {\n /** The frame element (top bar + panes); mount it into the app container. */\n readonly root: HTMLElement;\n readonly topbar: HTMLElement;\n /** Top-bar host slots: leading (title) and trailing (status), the host fills. */\n readonly topbarLead: HTMLElement;\n readonly topbarTrail: HTMLElement;\n /** Pane bodies the host fills (the fixed-width inner that clips on collapse). */\n readonly nav: HTMLElement;\n readonly centre: HTMLElement;\n readonly inspector: HTMLElement;\n togglePane(side: PaneSide): void;\n setPaneOpen(side: PaneSide, open: boolean): void;\n /** Whether the pane is showing: open, and not held closed. */\n isOpen(side: PaneSide): boolean;\n /** Fold a side away WITHOUT changing what the person chose: a mode that has\n * no use for the inspector (Patterpad's properties page) holds it closed,\n * and releasing the hold restores whatever was remembered. Not persisted;\n * the toggle keeps reporting the remembered state. */\n holdClosed(side: PaneSide, held: boolean): void;\n /** Clear dragged widths back to the config defaults. */\n resetWidths(): void;\n /** A snapshot of the current state (open + widths). */\n state(): PaneShellState;\n destroy(): void;\n}\n\nconst DEFAULT_MAX = (w: number): number => Math.min(640, w - 420);\nconst openVar: Record<PaneSide, string> = { nav: \"--nav-open-w\", inspector: \"--insp-open-w\" };\nconst collapseClass: Record<PaneSide, string> = { nav: \"no-nav\", inspector: \"no-inspector\" };\n\nexport function mountPaneShell(host: HTMLElement, opts: PaneShellOptions): PaneShell {\n const cfg: Record<PaneSide, PaneSideConfig> = { nav: opts.nav, inspector: opts.inspector };\n const offered = (side: PaneSide): boolean => cfg[side].offered !== false;\n const open: Record<PaneSide, boolean> = {\n nav: offered(\"nav\") && (opts.initial?.open?.nav ?? true),\n inspector: offered(\"inspector\") && (opts.initial?.open?.inspector ?? true),\n };\n const width: Partial<Record<PaneSide, number>> = { ...(opts.initial?.width ?? {}) };\n const held: Record<PaneSide, boolean> = { nav: false, inspector: false };\n const showing = (side: PaneSide): boolean => open[side] && !held[side];\n\n const el = <K extends keyof HTMLElementTagNameMap>(tag: K, cls?: string): HTMLElementTagNameMap[K] => {\n const n = document.createElement(tag);\n if (cls) n.className = cls;\n return n;\n };\n\n // --- top bar ---------------------------------------------------------------\n const navToggle = el(\"button\", \"pane-toggle\");\n navToggle.type = \"button\";\n const inspToggle = el(\"button\", \"pane-toggle\");\n inspToggle.type = \"button\";\n const topbarLead = el(\"div\", \"topbar-lead\");\n const topbarTrail = el(\"div\", \"topbar-trail\");\n const spacer = el(\"span\", \"topbar-spacer\");\n const topbar = el(\"header\", \"topbar\");\n topbar.append(navToggle, topbarLead, spacer, topbarTrail, inspToggle);\n\n // --- panes -----------------------------------------------------------------\n const panes = el(\"main\", \"panes\");\n const navPane = el(\"nav\", \"pane pane-nav\");\n const navInner = el(\"div\", \"pane-inner\");\n navPane.append(navInner);\n const centre = el(\"section\", \"pane-centre\");\n const inspPane = el(\"aside\", \"pane pane-inspector\");\n const inspInner = el(\"div\", \"pane-inner\");\n inspPane.append(inspInner);\n const navResizer = el(\"div\", \"pane-resizer pane-resizer-nav\");\n const inspResizer = el(\"div\", \"pane-resizer pane-resizer-insp\");\n panes.append(navPane, centre, inspPane, navResizer, inspResizer);\n\n const root = el(\"div\", \"pane-shell\");\n root.append(topbar, panes);\n host.append(root);\n // An unoffered pane's toggle is not hidden but ABSENT: nothing to\n // discover, nothing to tab to.\n if (!offered(\"nav\")) navToggle.remove();\n if (!offered(\"inspector\")) inspToggle.remove();\n\n // --- state application -----------------------------------------------------\n const defaultTip = (side: PaneSide, isOpen: boolean): string => {\n const text = `${isOpen ? \"Hide\" : \"Show\"} ${cfg[side].label ?? side}`;\n const hint = cfg[side].shortcutHint;\n if (!hint) return text;\n // A portable combo is spelled for the platform at draw time; a literal\n // is the caller's own words and goes in as written.\n return isKeyCombo(hint) ? tipWithKey(text, hint) : `${text} (${hint})`;\n };\n const tipFor = opts.tipFor ?? defaultTip;\n\n function applyToggleGlyph(side: PaneSide, button: HTMLButtonElement): void {\n const isOpen = open[side];\n // Chevron points toward where the pane collapses to.\n button.replaceChildren(iconNode(side === \"nav\" ? (isOpen ? \"back\" : \"forward\") : (isOpen ? \"forward\" : \"back\")));\n // `data-tip`, not `title`: the themed tooltip, never the OS bubble on the\n // platform's own delay. The tip is also the accessible name, since the\n // button has no text of its own.\n const tip = tipFor(side, isOpen);\n button.dataset[\"tip\"] = tip;\n button.setAttribute(\"aria-label\", tip);\n button.setAttribute(\"aria-pressed\", String(isOpen));\n }\n // Writing data-tip mounts the renderer, as `el` does, so a window whose host\n // never called initTooltips() still draws the rollover.\n ensureTooltipHost();\n\n function apply(): void {\n for (const side of [\"nav\", \"inspector\"] as const) {\n const collapsed = !showing(side);\n panes.classList.toggle(collapseClass[side], collapsed);\n const also = opts.collapseAlso?.[side];\n if (also) panes.classList.toggle(also, collapsed);\n }\n // The open widths live on the grid: the track and each .pane-inner read them.\n panes.style.setProperty(openVar.nav, width.nav !== undefined ? `${width.nav}px` : cfg.nav.defaultWidth);\n panes.style.setProperty(openVar.inspector, width.inspector !== undefined ? `${width.inspector}px` : cfg.inspector.defaultWidth);\n applyToggleGlyph(\"nav\", navToggle);\n applyToggleGlyph(\"inspector\", inspToggle);\n navResizer.style.display = cfg.nav.resizable === false || !offered(\"nav\") ? \"none\" : \"\";\n inspResizer.style.display = cfg.inspector.resizable === false || !offered(\"inspector\") ? \"none\" : \"\";\n }\n\n const snapshot = (): PaneShellState => ({ open: { ...open }, width: { ...width } });\n const persist = (): void => opts.onChange?.(snapshot());\n\n function setPaneOpen(side: PaneSide, next: boolean): void {\n if (open[side] === next) return;\n open[side] = next;\n apply();\n persist();\n }\n function togglePane(side: PaneSide): void { if (offered(side)) setPaneOpen(side, !open[side]); }\n function holdClosed(side: PaneSide, next: boolean): void {\n if (held[side] === next) return;\n held[side] = next;\n apply(); // not persisted: the hold is the mode's, the remembered state is the person's\n }\n function resetWidths(): void { delete width.nav; delete width.inspector; apply(); persist(); }\n\n navToggle.addEventListener(\"click\", () => togglePane(\"nav\"));\n inspToggle.addEventListener(\"click\", () => togglePane(\"inspector\"));\n\n // --- drag resize -----------------------------------------------------------\n function beginResize(side: PaneSide, startEvent: PointerEvent): void {\n if (cfg[side].resizable === false || !showing(side)) return;\n startEvent.preventDefault();\n const pane = side === \"nav\" ? navPane : inspPane;\n const seam = side === \"nav\" ? navResizer : inspResizer;\n seam.classList.add(\"dragging\");\n const min = cfg[side].minWidth ?? 160;\n const max = cfg[side].maxWidth ?? DEFAULT_MAX;\n const startX = startEvent.clientX;\n const startW = pane.getBoundingClientRect().width;\n document.body.classList.add(\"pane-resizing\");\n let latest = startW;\n const onMove = (e: PointerEvent): void => {\n const delta = side === \"nav\" ? e.clientX - startX : startX - e.clientX;\n latest = Math.max(min, Math.min(max(window.innerWidth), startW + delta));\n panes.style.setProperty(openVar[side], `${latest}px`);\n };\n const onUp = (): void => {\n window.removeEventListener(\"pointermove\", onMove);\n window.removeEventListener(\"pointerup\", onUp);\n document.body.classList.remove(\"pane-resizing\");\n seam.classList.remove(\"dragging\");\n width[side] = latest;\n persist();\n };\n window.addEventListener(\"pointermove\", onMove);\n window.addEventListener(\"pointerup\", onUp);\n }\n navResizer.addEventListener(\"pointerdown\", (e) => beginResize(\"nav\", e));\n inspResizer.addEventListener(\"pointerdown\", (e) => beginResize(\"inspector\", e));\n navResizer.addEventListener(\"dblclick\", () => { delete width.nav; apply(); persist(); });\n inspResizer.addEventListener(\"dblclick\", () => { delete width.inspector; apply(); persist(); });\n\n apply();\n\n return {\n root, topbar, topbarLead, topbarTrail,\n nav: navInner, centre, inspector: inspInner,\n togglePane, setPaneOpen, isOpen: showing, holdClosed, resetWidths, state: snapshot,\n destroy: () => { root.remove(); },\n };\n}\n","// ---------------------------------------------------------------------------\n// Shell-owned menu naming: the labels + accelerators for the pane-frame menu\n// items, single-sourced so every app in the family names them identically\n// (and a rename here flows to all of them). Pure data - no electron, no DOM -\n// so a main-process menu builder can import it. Each app builds its own\n// MenuItem from these and wires the click to its shell controller.\n// ---------------------------------------------------------------------------\n\nimport type { RecentProject } from \"./app-store.js\";\n\nexport interface MenuLabel {\n label: string;\n /** Electron accelerator string, when the item has one. */\n accelerator?: string;\n}\n\n/**\n * The Edit menu items the family shares.\n *\n * Undo and Redo are here and the MECHANISM is not, which is the whole finding\n * about undo: Patterpad's is ProseMirror's document history, Storyletter's is a\n * replay of file bytes, and those have nothing in common but this. See\n * `design/shared-shell.md`.\n *\n * The rule both apps discovered separately, and the reason these are spelled\n * out rather than left as Electron's `role: \"undo\"`: the native role runs a DOM\n * text-field undo, which knows nothing about either app's model and will\n * silently undo the wrong thing.\n */\nexport const EDIT_MENU: {\n undo: MenuLabel;\n redo: MenuLabel;\n duplicate: MenuLabel;\n find: MenuLabel;\n /** Replace is Find's second tab, on the platform's key for it. */\n replace: { label: string; acceleratorMac: string; acceleratorOther: string };\n} = {\n undo: { label: \"Undo\", accelerator: \"CmdOrCtrl+Z\" },\n redo: { label: \"Redo\", accelerator: \"Shift+CmdOrCtrl+Z\" },\n duplicate: { label: \"Duplicate\", accelerator: \"CmdOrCtrl+D\" },\n find: { label: \"Find…\", accelerator: \"CmdOrCtrl+F\" },\n replace: { label: \"Replace…\", acceleratorMac: \"Cmd+Alt+F\", acceleratorOther: \"Ctrl+H\" },\n};\n\n/**\n * Back / Forward: navigation HISTORY, the other axis from Up a Level's\n * hierarchy. One string cannot serve both platforms - the mac pair is Xcode's\n * (Cmd+[ is already Up a Level in this family, so the browser pair is taken),\n * and the Alt pair is what every Windows browser and Explorer trained - so the\n * menu builder picks by platform.\n */\nexport const GO_MENU: {\n back: { label: string; acceleratorMac: string; acceleratorOther: string };\n forward: { label: string; acceleratorMac: string; acceleratorOther: string };\n} = {\n back: { label: \"Back\", acceleratorMac: \"Ctrl+Cmd+Left\", acceleratorOther: \"Alt+Left\" },\n forward: { label: \"Forward\", acceleratorMac: \"Ctrl+Cmd+Right\", acceleratorOther: \"Alt+Right\" },\n};\n\n/** The pane-frame menu items (a View menu, conventionally). */\nexport const PANE_MENU: {\n showNav: MenuLabel;\n showInspector: MenuLabel;\n resetView: MenuLabel;\n} = {\n showNav: { label: \"Show Navigator\", accelerator: \"CmdOrCtrl+1\" },\n showInspector: { label: \"Show Inspector\", accelerator: \"CmdOrCtrl+2\" },\n resetView: { label: \"Reset View\" },\n};\n\n/**\n * The Help menu items the family shares, and the one platform rule that goes\n * with them.\n *\n * Lifted from Patterpad, which is the only app that has ever had these: a\n * second app writing its own updater or About is pure waste (`design/\n * shared-shell.md`), and a suite is recognised by finding Check for Updates\n * where you left it. Storyletter will grow both; until it does, these labels\n * are the agreement rather than a description of two implementations.\n *\n * PLACEMENT, which differs by platform and is easy to get wrong:\n * - macOS keeps About in the APP menu (the one named after the product), and\n * Help carries documentation + Check for Updates only.\n * - Windows and Linux have no app menu, so About goes at the foot of Help,\n * after a separator. That is the conventional home there.\n */\nexport const HELP_MENU: {\n checkForUpdates: MenuLabel;\n} = {\n checkForUpdates: { label: \"Check for Updates\\u2026\" },\n};\n\n/** The app-menu items the family shares (macOS; the identity item also belongs in File elsewhere). */\nexport const APP_MENU: {\n userInfo: MenuLabel;\n} = {\n /** Name + optional email, used to sign edits and comments. One label across the suite. */\n userInfo: { label: \"User Information\\u2026\" },\n};\n\n/** What an app must tell the shell to build its named menu items. */\nexport interface MenuNaming {\n /** The product, as it appears in menus: \"Patterpad\", \"Storyletter\". */\n appName: string;\n /** The product's own documentation URL. Omit while an app has no docs yet and\n * the item is rendered disabled rather than opening a broken link. */\n docsUrl?: string;\n /** The suite's documentation home, shared by every app in the family. */\n suiteDocsUrl?: string;\n /** The suite, as it appears in \"<suite> Documentation Home\". Defaults to \"Patter\". */\n suiteName?: string;\n}\n\n/** A named menu item: the label, plus the URL it opens (absent = nothing wired yet). */\nexport interface NamedMenuItem extends MenuLabel {\n url?: string;\n /** False when the app has not supplied a URL, so the builder can render it\n * disabled instead of opening nothing. A placeholder, honestly labelled. */\n ready: boolean;\n}\n\n/**\n * The menu labels that carry a product or suite name, so no app spells its own\n * About or Documentation item differently from the rest of the family.\n *\n * An app with no documentation site yet still gets the ITEM, marked\n * `ready: false`, so the menu has its family shape from day one and wiring the\n * URL later is a one-line change rather than a menu redesign.\n */\nexport function namedMenuItems(naming: MenuNaming): {\n about: NamedMenuItem;\n docs: NamedMenuItem;\n suiteDocs: NamedMenuItem;\n} {\n const suite = naming.suiteName ?? \"Patter\";\n return {\n about: { label: `About ${naming.appName}`, ready: true },\n docs: {\n label: `${naming.appName} Documentation`,\n ...(naming.docsUrl ? { url: naming.docsUrl } : {}),\n ready: naming.docsUrl !== undefined,\n },\n suiteDocs: {\n label: `${suite} Documentation Home`,\n ...(naming.suiteDocsUrl ? { url: naming.suiteDocsUrl } : {}),\n ready: naming.suiteDocsUrl !== undefined,\n },\n };\n}\n\n// --- the rest of the spine (ui-review-2026-09, finding 12) -----------------------\n// Each app used roughly half of what is above and hand-typed the other half,\n// and the copies had already drifted (Review Feedback's accelerator spelled\n// two ways; \"No Recent Projects\" vs \"No recent projects\"). Labels are Title\n// Case, as the platform's menus are; an item that opens something ends in the\n// command ellipsis.\n\n/** The File menu items the family shares. */\nexport const FILE_MENU: {\n newProject: MenuLabel;\n openProject: MenuLabel;\n openRecent: MenuLabel;\n /** The empty Open Recent submenu's one disabled item. */\n noRecents: MenuLabel;\n clearRecents: MenuLabel;\n closeProject: MenuLabel;\n save: MenuLabel;\n saveAs: MenuLabel;\n projectSettings: MenuLabel;\n} = {\n newProject: { label: \"New Project…\", accelerator: \"CmdOrCtrl+N\" },\n openProject: { label: \"Open Project…\", accelerator: \"CmdOrCtrl+O\" },\n openRecent: { label: \"Open Recent\" },\n noRecents: { label: \"No Recent Projects\" },\n clearRecents: { label: \"Clear Recents\" },\n closeProject: { label: \"Close Project\" },\n save: { label: \"Save\", accelerator: \"CmdOrCtrl+S\" },\n saveAs: { label: \"Save As…\", accelerator: \"Shift+CmdOrCtrl+S\" },\n projectSettings: { label: \"Project Settings…\", accelerator: \"CmdOrCtrl+,\" },\n};\n\n/**\n * The Play menu's shared item. The play SURFACE itself (Patterpad's \"Play\n * Scene\" on Cmd+P, Storyletter's \"The Board\" on Cmd+T) is app-named and\n * app-keyed on purpose: the two are not the same act, so the family reserves\n * neither key.\n */\nexport const PLAY_MENU: {\n liveLink: MenuLabel;\n} = {\n liveLink: { label: \"Live Link\" },\n};\n\n/** The Review menu: examining what you have built rather than building or\n * playing it. Review Feedback's accelerator is spelled ONCE, here. */\nexport const REVIEW_MENU: {\n reviewFeedback: MenuLabel;\n nextFeedback: MenuLabel;\n previousFeedback: MenuLabel;\n coverageTest: MenuLabel;\n findPropertyUsage: MenuLabel;\n showResolvedComments: MenuLabel;\n} = {\n reviewFeedback: { label: \"Review Feedback\", accelerator: \"CmdOrCtrl+Shift+R\" },\n nextFeedback: { label: \"Next Feedback\", accelerator: \"F8\" },\n previousFeedback: { label: \"Previous Feedback\", accelerator: \"Shift+F8\" },\n coverageTest: { label: \"Coverage Test…\", accelerator: \"Shift+CmdOrCtrl+C\" },\n findPropertyUsage: { label: \"Find Property Usage…\" },\n showResolvedComments: { label: \"Show Resolved Comments\" },\n};\n\n/** The Publish menu: everything that turns the project into something you\n * hand to others (\"Publish\", never \"Export\"). */\nexport const PUBLISH_MENU: {\n playableHtml: MenuLabel;\n bundle: MenuLabel;\n autoRebuild: MenuLabel;\n} = {\n playableHtml: { label: \"Publish Playable HTML…\" },\n bundle: { label: \"Publish Bundle\", accelerator: \"Shift+CmdOrCtrl+B\" },\n autoRebuild: { label: \"Auto Rebuild\" },\n};\n\n/** The View menu items beyond the pane toggles (PANE_MENU) and history\n * (GO_MENU). Cmd+[ is family-reserved for Up a Level, which is why Back\n * takes Xcode's pair on the mac. */\nexport const VIEW_MENU: {\n projectOverview: MenuLabel;\n upALevel: MenuLabel;\n colourTheme: MenuLabel;\n} = {\n projectOverview: { label: \"Project Overview\" },\n upALevel: { label: \"Up a Level\", accelerator: \"CmdOrCtrl+[\" },\n colourTheme: { label: \"Colour Theme\" },\n};\n\n/** A path with the home directory as `~`, so a recents entry stays readable\n * at menu width. `home` is `app.getPath(\"home\")`; this file stays\n * electron-free. */\nexport function tildePath(path: string, home: string): string {\n if (path === home) return \"~\";\n const sep = home.includes(\"\\\\\") ? \"\\\\\" : \"/\";\n return path.startsWith(home + sep) ? `~${path.slice(home.length)}` : path;\n}\n\n/** As much of Electron's MenuItemConstructorOptions as a recents entry needs;\n * structurally assignable to it. */\nexport interface RecentsMenuItem {\n label?: string;\n sublabel?: string;\n toolTip?: string;\n enabled?: boolean;\n type?: \"separator\";\n click?: () => void;\n}\n\nexport interface RecentsSubmenuOptions {\n onOpen: (path: string) => void;\n /** Offered after a separator when there is anything to clear. */\n onClear?: () => void;\n /** `app.getPath(\"home\")`, for the `~` abbreviation. */\n home: string;\n /** Defaults to process.platform; a seam for the tests. */\n platform?: string;\n}\n\n/**\n * The Open Recent submenu: the fifteen lines both apps had.\n *\n * Shows WHERE each recent lives. macOS renders `sublabel` as a dimmed second\n * line and `toolTip` on hover; native menus elsewhere render neither, so\n * there the path is folded into the label itself. Empty, it is the one\n * disabled \"No Recent Projects\" item.\n */\nexport function recentsSubmenu(recents: RecentProject[], opts: RecentsSubmenuOptions): RecentsMenuItem[] {\n const isMac = (opts.platform ?? process.platform) === \"darwin\";\n if (recents.length === 0) return [{ label: FILE_MENU.noRecents.label, enabled: false }];\n const items: RecentsMenuItem[] = recents.map((r) => {\n const shown = tildePath(r.path, opts.home);\n const name = r.name ?? r.path.split(/[\\\\/]/).filter(Boolean).pop() ?? r.path;\n return {\n label: isMac ? name : `${name} (${shown})`,\n sublabel: shown,\n toolTip: r.path,\n click: () => opts.onOpen(r.path),\n };\n });\n if (opts.onClear) items.push({ type: \"separator\" }, { label: FILE_MENU.clearRecents.label, click: opts.onClear });\n return items;\n}\n","// ---------------------------------------------------------------------------\n// Problem copy: a validator's diagnostic rewritten for the person at the\n// keyboard, through a table the app fills.\n//\n// Patterpad's `humanizeProblem` (its renderer.ts) proved the shape: a dozen\n// validator categories each mapped to a plain sentence with a next step, naming\n// things by their title, and a fallback that softens the technical residue.\n// Storyletter showed the raw compiler string and labelled it `path [where]`\n// (ui-review-2026-09, finding 17), the bracketed id that \"Diagnostics name what\n// the author can see\" (design-language.md) rules out for anything but a\n// DANGLING reference. This module is the translator; the tables are the\n// apps', because the codes are theirs. `defaultProblemCopy` covers the handful\n// of codes both validators raise in some form, as a floor an app spreads into\n// its own table.\n// ---------------------------------------------------------------------------\n\n/** What a translator needs to know about a problem. `code` is the app's own\n * category (Patterpad's `detail`, or a code Storyletter derives from its\n * compiler message); `title` is the author-facing name of the thing the\n * problem is about, when the app can resolve one; `where` is the raw\n * reference (an id) for when it cannot. */\nexport interface ProblemLike {\n code?: string;\n message: string;\n path?: string;\n where?: string;\n title?: string;\n}\n\nexport interface ProblemCopy {\n /** The sentence: what is wrong, in the author's words. */\n text: string;\n /** What to do about it, when there is one thing to do. */\n next?: string;\n /** The reference this problem is about no longer has a name to give, so the\n * raw id may be shown, written `(id ...)` so it cannot be mistaken for a\n * name. Set by the table entry; the translator never guesses it. */\n dangling?: boolean;\n}\n\nexport type ProblemCopyEntry = (problem: ProblemLike) => ProblemCopy;\nexport type ProblemCopyTable = Record<string, ProblemCopyEntry>;\n\n/** The name to call the thing a problem is about: its title in curly quotes,\n * \"(id ...)\" only when the reference dangles and there is nothing else,\n * and \"This\" otherwise, because the bar's \"go to\" shows the reader what\n * \"this\" is and an id is not something they can look for. */\nexport function problemName(p: ProblemLike, dangling = false): string {\n if (p.title) return `“${p.title}”`;\n if (dangling && p.where) return `(id ${p.where})`;\n return \"This\";\n}\n\n/**\n * Translate `problem` through `table`. A matching entry decides the copy; with\n * no entry the raw message is kept and prefixed by the title when there is one\n * (\"Burner Rig: duplicate id\"). Nothing here ever writes `[where]`; an id\n * appears only as `(id ...)`, only when the entry says the reference dangles,\n * and only when there is no title to say instead.\n */\nexport function describeProblem(problem: ProblemLike, table: ProblemCopyTable = {}): ProblemCopy {\n const entry = problem.code ? table[problem.code] : undefined;\n if (entry) {\n const copy = entry(problem);\n const text = copy.dangling && !problem.title && problem.where && !copy.text.includes(`(id ${problem.where})`)\n ? `${copy.text} (id ${problem.where})`\n : copy.text;\n return copy.next ? { text, next: copy.next } : { text };\n }\n const message = problem.message.replace(/\\s*\\[[^\\]]*\\]\\s*$/, \"\").trim();\n return { text: problem.title ? `${problem.title}: ${message}` : message };\n}\n\n/** `describeProblem` as one line for a bar that has room for one: the sentence,\n * then the next step after a space. */\nexport function problemLine(problem: ProblemLike, table?: ProblemCopyTable): string {\n const { text, next } = describeProblem(problem, table);\n return next ? `${text} ${next}` : text;\n}\n\n/**\n * The codes both validators raise in some form, in the family's voice. An app\n * spreads this into its own table and adds its own codes over it; a code an\n * app does not raise costs nothing.\n *\n * duplicate-gameid two things share one Game ID\n * invalid-gameid a Game ID that breaks the address rule\n * dangling-reference a jump / tag / property points at something gone\n * unknown-property a condition or effect names an undeclared property\n * missing-name a thing that needs a name has none\n * empty a container with nothing in it\n * stale-build the playable build is older than the source\n * merge-conflict a file still carries conflict markers\n */\nexport const defaultProblemCopy: ProblemCopyTable = {\n \"duplicate-gameid\": (p) => ({\n text: `The Game ID on ${problemName(p)} is already used elsewhere.`,\n next: \"Each one must be unique; change one of them.\",\n }),\n \"invalid-gameid\": (p) => ({\n text: `The Game ID on ${problemName(p)} isn't valid.`,\n next: \"Use lowercase letters, digits and hyphens.\",\n }),\n \"dangling-reference\": (p) => ({\n text: `${problemName(p, true)} points at something that no longer exists.`,\n next: \"Choose where it goes.\",\n dangling: true,\n }),\n \"unknown-property\": (p) => ({\n text: `${problemName(p)} uses a property that isn't set up yet.`,\n next: \"Declare it in the project settings, or fix the name.\",\n }),\n \"missing-name\": (p) => ({ text: `${problemName(p)} needs a name.` }),\n \"empty\": (p) => ({\n text: `${problemName(p)} is empty.`,\n next: \"Add something inside it, or remove it.\",\n }),\n \"stale-build\": (p) => ({\n text: `Your playable build${p.path ? ` (${p.path})` : \"\"} is out of date.`,\n next: \"It refreshes the next time you publish.\",\n }),\n \"merge-conflict\": (p) => ({\n text: `${p.path ?? \"This file\"} still has an unresolved merge conflict in it.`,\n next: \"Resolve it in your version control tool, then reopen the project.\",\n }),\n};\n","// ---------------------------------------------------------------------------\n// The shared settings surface: a native <dialog> with a left-rail of grouped\n// tabs and one panel per section (mountSettingsDialog), plus the list-editing\n// core those sections lean on (expandableRow, focusNewRow, dupGuard). The app\n// supplies the sections; each holds its own state and reports the first invalid\n// control so the Save gate can block + jump. Framework here, content in the app.\n//\n// Lifted from Patterpad's Project Settings (settings-list.ts + the inlined\n// dialog logic in its renderer), with neutral class names. Styling ships as\n// settings.css.\n// ---------------------------------------------------------------------------\n\nimport { el } from \"./dom.js\";\n\n// --- list-editing core --------------------------------------------------------\n\n/** A compact list row: a single `.set-rowline` (inline controls) plus, when\n * `details` are given, a disclosure that reveals a `.set-details` panel below,\n * so a list scans like a table with secondary fields tucked away. `name` is\n * what the row declares (a property's name, a field's), stamped on it as\n * `data-name` so `revealRow` can land on it. */\nexport function expandableRow(opts: { line: HTMLElement[]; details?: HTMLElement[]; name?: string }): HTMLElement {\n const row = el(\"div\", \"set-row\");\n if (opts.name !== undefined) row.dataset.name = opts.name;\n const line = el(\"div\", \"set-rowline\");\n if (opts.details && opts.details.length) {\n const details = el(\"div\", \"set-details\"); details.hidden = true;\n for (const d of opts.details) details.append(d);\n // The triangle is drawn by CSS off `.open` (a text glyph stays hairline-thin).\n const toggle = el(\"button\", \"set-expand\"); toggle.type = \"button\";\n // `data-tip`, not `title`: this package ships a themed tooltip and nothing\n // else in it raises an OS rollover. A lone `title` here would be the one\n // place a host's chrome broke character, and on the platform's own delay.\n toggle.dataset.tip = \"More\"; toggle.setAttribute(\"aria-label\", \"More\");\n toggle.setAttribute(\"aria-expanded\", \"false\");\n toggle.addEventListener(\"click\", () => {\n const open = details.hidden;\n details.hidden = !open;\n toggle.setAttribute(\"aria-expanded\", String(open));\n toggle.classList.toggle(\"open\", open);\n });\n line.append(toggle);\n opts.line.forEach((c) => line.append(c));\n row.append(line, details);\n } else {\n opts.line.forEach((c) => line.append(c));\n row.append(line);\n }\n return row;\n}\n\n/**\n * Land on one row of a list by the `name` it was built with: open its details\n * (an enum's values sit behind the disclosure, and they are usually what the\n * jump was for), bring it to the middle of its scroller, and light it for a\n * moment (`.set-row.landed` in settings.css). \"Go to definition\" in both apps\n * used to open the page a property is declared on and stop there, with the\n * declaration below the fold and nothing marking it (Storyletter, 2026-09-14).\n *\n * Returns false when no row carries the name, so a host whose page fills in\n * asynchronously can ask again on a later frame; asking again is the host's,\n * since only the host knows what opens on its own time. The row is matched by\n * reading the stamp rather than by an attribute selector, so a name needs no\n * escaping.\n */\nexport function revealRow(within: ParentNode, name: string): boolean {\n const row = [...within.querySelectorAll<HTMLElement>(\".set-row\")].find((r) => r.dataset.name === name);\n if (!row) return false;\n const toggle = row.querySelector<HTMLButtonElement>(\".set-rowline > .set-expand\");\n if (toggle && toggle.getAttribute(\"aria-expanded\") !== \"true\") toggle.click();\n const still = typeof matchMedia === \"function\" && matchMedia(\"(prefers-reduced-motion: reduce)\").matches;\n row.scrollIntoView({ block: \"center\", behavior: still ? \"auto\" : \"smooth\" });\n // Restarted, so landing on the same row twice lights it twice.\n row.classList.remove(\"landed\");\n void row.offsetWidth;\n row.classList.add(\"landed\");\n row.addEventListener(\"animationend\", () => row.classList.remove(\"landed\"), { once: true });\n return true;\n}\n\n/**\n * `revealRow`, retried over the next frames until the row exists or the tries\n * run out: for a page that fills in on its own time after a navigation. Both\n * apps hand-rolled this as `landOn` with the same twelve tries\n * (ui-review-2026-09, finding 29). Resolves true when it landed, false when it\n * gave up, and giving up is quiet: a name no page shows as a row is not a fault.\n */\nexport function revealRowWhenReady(within: ParentNode, name: string, tries = 12): Promise<boolean> {\n return new Promise((resolve) => {\n const attempt = (left: number): void => {\n if (revealRow(within, name)) { resolve(true); return; }\n if (left <= 0) { resolve(false); return; }\n requestAnimationFrame(() => attempt(left - 1));\n };\n attempt(tries);\n });\n}\n\n/** After a \"+ Add\" re-renders a list, bring the new (last) row into view and\n * focus its name input (`.set-name`, else the first input). */\nexport function focusNewRow(listEl: HTMLElement | null | undefined): void {\n const last = listEl?.lastElementChild;\n if (!(last instanceof HTMLElement)) return;\n last.scrollIntoView({ block: \"nearest\" });\n const name = last.querySelector<HTMLInputElement>(\"input.set-name\") ?? last.querySelector<HTMLInputElement>(\"input\");\n name?.focus();\n}\n\nexport interface DupGuard {\n /** Forget the previous render's inputs (call at the top of render). */\n reset(): void;\n /** Register a name input; `key` returns the comparison string (default the\n * input's value). Re-checks live on input. `also` = extra inputs that change the key. */\n track(input: HTMLInputElement, key?: () => string, also?: HTMLInputElement[]): void;\n /** Re-paint duplicates; true if any two non-blank keys collide. */\n check(): boolean;\n /** The first input currently flagged (after a fresh check), or null. */\n firstDuplicate(): HTMLInputElement | null;\n}\n\nconst DUP_MESSAGE = \"Another row already has this name.\";\n\n/** Case-insensitive duplicate-name detection: paints clashing inputs `.invalid`\n * and lets a Save gate block + jump via `firstDuplicate()`. */\nexport function dupGuard(): DupGuard {\n const items: Array<{ input: HTMLInputElement; key: () => string }> = [];\n const check = (): boolean => {\n const counts = new Map<string, number>();\n for (const it of items) { const k = it.key().trim().toLowerCase(); if (k) counts.set(k, (counts.get(k) ?? 0) + 1); }\n let any = false;\n for (const it of items) {\n const k = it.key().trim().toLowerCase();\n const dup = !!k && (counts.get(k) ?? 0) > 1;\n it.input.classList.toggle(\"invalid\", dup);\n // The reason rides `data-tip` (the themed rollover, and what the Save\n // gate's message channel reads), never `title`.\n if (dup) { it.input.dataset[\"tip\"] = DUP_MESSAGE; any = true; }\n else if (it.input.dataset[\"tip\"] === DUP_MESSAGE) delete it.input.dataset[\"tip\"];\n }\n return any;\n };\n return {\n reset() { items.length = 0; },\n track(input, key = () => input.value, also) {\n items.push({ input, key });\n input.addEventListener(\"input\", check);\n for (const a of also ?? []) a.addEventListener(\"input\", check);\n },\n check,\n firstDuplicate() { check(); return items.find((it) => it.input.classList.contains(\"invalid\"))?.input ?? null; },\n };\n}\n\n// --- the settings dialog ------------------------------------------------------\n\nexport interface SettingsSectionHandle {\n /** The first invalid control to jump to, blocking Save (e.g. a duplicate\n * name). Return `{ el, message }` to say WHICH fault in the error line;\n * a bare element says it through its own `data-tip` (the dup guard's, a\n * property-name field's), and the line falls back to a generic sentence\n * when it has neither. */\n firstInvalid?(): HTMLElement | { el: HTMLElement; message?: string } | null;\n}\n\nexport interface SettingsSection {\n id: string;\n label: string;\n /** Optional left-rail group heading above this tab. */\n group?: string;\n /** Build the section body into `host`; called fresh on each open so it reads\n * the current data. Return a handle (for the Save gate). */\n mount(host: HTMLElement): SettingsSectionHandle;\n /** Why this tab cannot be used right now, or null when it can. A reason\n * renders the tab dimmed and inert with the reason as its rollover\n * (Patterpad's Audio tab while the project is not voiced). Read on open\n * and on `refreshTabs()`, so a control inside the dialog can flip it. */\n disabled?: () => string | null;\n}\n\nexport interface SettingsDialogOptions {\n title: string;\n sections: SettingsSection[];\n /** Fired when Save is clicked and every section validates. The app reads its\n * own section state and persists. May be async; the dialog stays open until\n * it resolves, then closes. */\n onSave: () => void | Promise<void>;\n}\n\nexport interface SettingsDialog {\n /** Open (optionally on a given tab id). Sections re-mount from current data. */\n open(tabId?: string): void;\n /** Re-read every section's `disabled()`; a tab that has just become\n * disabled while showing hands over to the first usable one. */\n refreshTabs(): void;\n destroy(): void;\n}\n\n/** Build a settings dialog. The frame owns the modal, the tab rail, save-on-Save\n * (with a validation gate), and Cancel; the sections own their content + state. */\nexport function mountSettingsDialog(opts: SettingsDialogOptions): SettingsDialog {\n const dialog = el(\"dialog\", \"settings-dialog\");\n const form = el(\"form\", \"settings-form\"); form.method = \"dialog\";\n const tabs = el(\"nav\", \"settings-tabs\");\n const panels = el(\"div\", \"settings-panels\");\n const error = el(\"p\", \"settings-error\"); error.hidden = true;\n const cancel = el(\"button\", \"settings-cancel\", \"Cancel\"); cancel.type = \"button\"; cancel.value = \"cancel\";\n const save = el(\"button\", \"settings-save primary\", \"Save\"); save.value = \"save\";\n\n const panelFor = new Map<string, HTMLElement>();\n const tabFor = new Map<string, HTMLButtonElement>();\n const handles = new Map<string, SettingsSectionHandle>();\n let active = opts.sections[0]?.id ?? \"\";\n\n let lastGroup: string | undefined;\n for (const s of opts.sections) {\n if (s.group && s.group !== lastGroup) { tabs.append(el(\"div\", \"settings-group\", s.group)); lastGroup = s.group; }\n const tab = el(\"button\", \"settings-tab\", s.label); tab.type = \"button\"; tab.dataset[\"tab\"] = s.id;\n // A disabled tab is inert by class, not by the `disabled` attribute: a\n // disabled button swallows the pointer, and the reason has to be readable\n // on hover.\n tab.addEventListener(\"click\", () => { if (!tab.classList.contains(\"is-disabled\")) showTab(s.id); });\n tabs.append(tab); tabFor.set(s.id, tab);\n const panel = el(\"section\", \"settings-panel\"); panel.dataset[\"panel\"] = s.id; panel.hidden = true;\n panels.append(panel); panelFor.set(s.id, panel);\n }\n\n function showTab(id: string): void {\n active = id;\n for (const [sid, t] of tabFor) t.classList.toggle(\"active\", sid === id);\n for (const [sid, p] of panelFor) p.hidden = sid !== id;\n }\n\n const usable = (s: SettingsSection): boolean => !tabFor.get(s.id)?.classList.contains(\"is-disabled\");\n function refreshTabs(): void {\n for (const s of opts.sections) {\n const tab = tabFor.get(s.id)!;\n const reason = s.disabled?.() ?? null;\n tab.classList.toggle(\"is-disabled\", reason !== null);\n if (reason !== null) { tab.dataset[\"tip\"] = reason; tab.setAttribute(\"aria-disabled\", \"true\"); }\n else { delete tab.dataset[\"tip\"]; tab.removeAttribute(\"aria-disabled\"); }\n }\n if (!opts.sections.some((s) => s.id === active && usable(s))) {\n const first = opts.sections.find(usable);\n if (first) showTab(first.id);\n }\n }\n\n form.append(\n el(\"h2\", \"settings-title\", opts.title),\n el(\"div\", \"settings-body\", tabs, panels),\n el(\"div\", \"settings-actions\", error, cancel, save),\n );\n dialog.append(form);\n document.body.append(dialog);\n\n // Enter should not submit while editing a field; only the Save button does.\n form.addEventListener(\"keydown\", (e) => {\n if (e.key === \"Enter\" && (e.target as HTMLElement)?.tagName === \"INPUT\") e.preventDefault();\n });\n\n cancel.addEventListener(\"click\", () => dialog.close(\"cancel\"));\n save.addEventListener(\"click\", (e) => {\n e.preventDefault();\n error.hidden = true;\n for (const s of opts.sections) {\n const found = handles.get(s.id)?.firstInvalid?.();\n if (!found) continue;\n const bad = found instanceof HTMLElement ? found : found.el;\n const message = (found instanceof HTMLElement ? undefined : found.message) ?? bad.dataset[\"tip\"];\n showTab(s.id);\n bad.focus();\n // The field's own rollover says which fault it is, so the line repeats it\n // rather than inventing a summary; the generic sentence is the fallback.\n error.textContent = message || \"Fix the highlighted fields first.\";\n error.hidden = false;\n return;\n }\n void (async () => { await opts.onSave(); dialog.close(\"save\"); })();\n });\n\n return {\n open(tabId) {\n handles.clear();\n for (const s of opts.sections) {\n const panel = panelFor.get(s.id)!;\n panel.replaceChildren();\n handles.set(s.id, s.mount(panel));\n }\n error.hidden = true;\n showTab(tabId ?? active ?? opts.sections[0]?.id ?? \"\");\n refreshTabs(); // a disabled tab asked for by id hands over to the first usable one\n dialog.showModal();\n },\n refreshTabs,\n destroy() { dialog.remove(); },\n };\n}\n","// ---------------------------------------------------------------------------\n// The small idioms both apps wrote by hand and never gave a name: the plural\n// suffix (about forty sites), the debounce (eight copies), \"is the focus in a\n// field\" (four copies that disagreed about <select>), the count with grouping\n// separators, clipboard copy with the `.copied` revert (three timings), and\n// relative time (two wordings). One answer each, here.\n//\n// DOM-free except where the idiom is about the DOM (isEditableTarget,\n// copyWithFeedback), so main-process code can import the rest.\n// ---------------------------------------------------------------------------\n\n/** \"1 link\" / \"3 links\". The plural form defaults to `noun + \"s\"`; pass the\n * irregular one (\"entry\", \"entries\") when that is wrong. */\nexport function plural(n: number, noun: string, pluralForm = `${noun}s`): string {\n return `${n} ${n === 1 ? noun : pluralForm}`;\n}\n\nexport interface Debounced<A extends unknown[]> {\n (...args: A): void;\n /** Drop the pending call. */\n cancel(): void;\n /** Run the pending call now, if there is one. */\n flush(): void;\n}\n\n/** Trailing-edge debounce: the call runs `ms` after the LAST call. */\nexport function debounce<A extends unknown[]>(fn: (...args: A) => void, ms: number): Debounced<A> {\n let timer: ReturnType<typeof setTimeout> | undefined;\n let pending: A | undefined;\n const run = (): void => {\n timer = undefined;\n if (pending === undefined) return;\n const args = pending;\n pending = undefined;\n fn(...args);\n };\n const debounced = ((...args: A): void => {\n pending = args;\n if (timer !== undefined) clearTimeout(timer);\n timer = setTimeout(run, ms);\n }) as Debounced<A>;\n debounced.cancel = () => { if (timer !== undefined) clearTimeout(timer); timer = undefined; pending = undefined; };\n debounced.flush = () => { if (timer !== undefined) clearTimeout(timer); run(); };\n return debounced;\n}\n\n/**\n * Is the keyboard's focus in a field? The one agreed answer: an input, a\n * textarea, a select, or anything contenteditable (the attribute is read as\n * well as `isContentEditable`, which jsdom does not implement). A window-level\n * shortcut checks this before acting, so a bare letter typed into a field\n * stays a letter.\n */\nexport function isEditableTarget(t: EventTarget | null | undefined): boolean {\n if (!(t instanceof Element)) return false;\n if (t instanceof HTMLInputElement || t instanceof HTMLTextAreaElement || t instanceof HTMLSelectElement) return true;\n if (t instanceof HTMLElement && t.isContentEditable === true) return true;\n const attr = t.getAttribute(\"contenteditable\");\n return attr !== null && attr !== \"false\";\n}\n\n/** A count for reading: grouping separators in the user's locale. */\nexport function formatCount(n: number): string {\n return n.toLocaleString();\n}\n\nconst copyTimers = new WeakMap<Element, ReturnType<typeof setTimeout>>();\n\n/**\n * Copy `text` to the clipboard and light `el` with `.copied` for `ms` (the\n * family's 1000). A second click restarts the timer rather than stacking a\n * second revert under the first. Resolves when the clipboard write has.\n */\nexport function copyWithFeedback(el: Element, text: string, ms = 1000): Promise<void> {\n const write = typeof navigator !== \"undefined\" && navigator.clipboard\n ? navigator.clipboard.writeText(text).catch(() => {})\n : Promise.resolve();\n el.classList.add(\"copied\");\n const prior = copyTimers.get(el);\n if (prior !== undefined) clearTimeout(prior);\n copyTimers.set(el, setTimeout(() => { el.classList.remove(\"copied\"); copyTimers.delete(el); }, ms));\n return write;\n}\n\n/**\n * How long ago, in one wording: \"just now\", \"4 minutes ago\", \"an hour ago\",\n * \"3 hours ago\", \"yesterday\", \"5 days ago\", and past a week the date itself.\n * Coarse on purpose: the question a reader has is whether the thing is from\n * this sitting, not how many seconds ago it was. A future date is \"just now\".\n */\nexport function relativeTime(date: Date | number | string, now: number = Date.now()): string {\n const then = date instanceof Date ? date.getTime() : new Date(date).getTime();\n if (!Number.isFinite(then)) return \"\";\n const mins = Math.floor((now - then) / 60000);\n if (mins < 1) return \"just now\";\n if (mins < 60) return `${plural(mins, \"minute\")} ago`;\n const hours = Math.floor(mins / 60);\n if (hours === 1) return \"an hour ago\";\n if (hours < 24) return `${hours} hours ago`;\n const days = Math.floor(hours / 24);\n if (days === 1) return \"yesterday\";\n if (days < 7) return `${days} days ago`;\n return new Date(then).toLocaleDateString(undefined, { day: \"numeric\", month: \"short\", year: \"numeric\" });\n}\n","// ---------------------------------------------------------------------------\n// The tool-window kit, RENDERER half: the always-on-top pin button every\n// helper window carries (previously pasted verbatim in five places across\n// the two apps). The matching chrome CSS - .swin-head drag bar, .swin-pin,\n// .swin-close - ships as tool-window.css.\n//\n// The head bar (toolWindowHead) and the follow toggle (followButton) live here\n// too since 0.39. The frameless drag bar itself needs no JS at all: it is markup + the\n// -webkit-app-region rules in tool-window.css.\n// ---------------------------------------------------------------------------\n\nimport { el } from \"./dom.js\";\nimport { iconNode } from \"./icons.js\";\nimport { isEditableTarget } from \"./util.js\";\n\nexport interface PinButtonOptions {\n pinned: boolean;\n /** Persist the choice. The button reflects the click itself. */\n onToggle: (on: boolean) => void;\n}\n\n/** A pin and the handle to drive it, the same shape `saveIndicator` returns. */\nexport interface PinButton {\n el: HTMLButtonElement;\n /**\n * Reflect a pin state decided ELSEWHERE, without calling `onToggle`.\n *\n * The state is not always the button's to choose: main re-pins a helper window\n * on Reset View, and the window is told after the fact. Before this existed a\n * host had to reach in and set the class, the aria and the title by hand,\n * which is three chances to disagree with the button about what it is showing.\n */\n set: (pinned: boolean) => void;\n}\n\n/** The always-on-top pin: `.swin-pin`, aria-pressed, and a tooltip that says\n * what a click will do (the richest of the family's variants, kept). */\nexport function pinButton(opts: PinButtonOptions): PinButton {\n const b = el(\"button\", \"swin-pin\");\n b.type = \"button\";\n // The vocabulary's pin (it used to be a hand-drawn copy of the same shape,\n // pasted in five places across the two apps before it came here).\n b.append(iconNode(\"pin\"));\n let pinned = opts.pinned;\n const reflect = (): void => {\n b.classList.toggle(\"on\", pinned);\n b.setAttribute(\"aria-pressed\", String(pinned));\n // The THEMED rollover, not the platform's. 0.21.0 swept `title` out of this\n // package and missed this one, so every helper window in the family had a\n // single control waiting on the OS delay and then drawing the OS bubble,\n // sitting beside controls that did not. `title` was also the button's only\n // accessible name (the glyph is an aria-hidden SVG), so the label has to go\n // to `aria-label` as it moves, or dropping `title` would take the name too.\n const label = pinned ? \"Pinned on top. Click to unpin.\" : \"Keep on top\";\n b.dataset[\"tip\"] = label;\n b.setAttribute(\"aria-label\", label);\n };\n reflect();\n b.addEventListener(\"click\", () => { pinned = !pinned; reflect(); opts.onToggle(pinned); });\n return { el: b, set: (next: boolean) => { pinned = next; reflect(); } };\n}\n\n// --- the head ------------------------------------------------------------------\n\nexport interface ToolWindowHeadOptions {\n /** The window's own name. Constant: it says which window this is, so it must\n * not change as projects open and close. Omitted by a window whose mode\n * tabs stand where the title would be (Find): pass them as `tabs`. */\n title?: string;\n /** Mode tabs in the title's place (Find's bar: modes left, pin and close right). */\n tabs?: HTMLElement;\n /** A pin BUILT ALREADY, for a window that mounts its chrome once and drives\n * the button with `pin.set(on)` rather than rebuilding the bar. That is the\n * better shape (no re-entrancy question, survives a partial repaint), so the\n * helper takes either. */\n pin?: { el: HTMLElement };\n pinned?: boolean;\n onPin?: (on: boolean) => void;\n onClose: () => void;\n /** Between the title and the spacer: a subtitle, the project name. */\n lead?: (Node | string | null)[];\n /** Between the spacer and the pin: this window's own controls. */\n trail?: (Node | string | null)[];\n /** An extra class beside `swin-head`, for a window that styles its own bar. */\n className?: string;\n /**\n * Escape closes the window (default true): the family's rule, written once\n * here rather than per window.\n *\n * The listener stands aside on its own for a field's Escape (an input,\n * textarea, select or contenteditable target: clearing, cancelling an edit)\n * and for an Escape a deeper handler has already `preventDefault()`ed.\n * `\"always\"` drops the first of those: a window whose focus LIVES in a\n * field (Find, whose query box is where the typing is) still closes on\n * Escape from it. `false` turns the listener off for a window that owns\n * Escape entirely; it calls `onClose` itself when nothing smaller is left.\n */\n esc?: boolean | \"always\";\n /**\n * A window that layers Escape (a selection to clear, a pending outcome to\n * drop, a sweep that must not be closed out from under) says so here:\n * return true when the key was consumed and the window stays open, false\n * to let it close. Innermost first; the window is last.\n */\n onEscape?: () => boolean;\n}\n\ninterface EscSlot {\n onClose: () => void;\n onEscape?: (() => boolean) | undefined;\n fromFields: boolean;\n}\n\n/** The one Escape listener per window. The head may be rebuilt on every render\n * (a play surface does), so the listener is installed once and reads the\n * latest close through this slot. */\nlet escSlot: EscSlot | undefined;\nlet escWired = false;\nfunction wireEsc(): void {\n if (escWired) return;\n escWired = true;\n window.addEventListener(\"keydown\", (e) => {\n if (e.key !== \"Escape\" || !escSlot) return;\n // A deeper handler that claimed the key (a popover closing, a picker\n // dismissing) has said so already.\n if (e.defaultPrevented) return;\n // A field's own Escape (clearing, cancelling an edit) comes first, unless\n // the window asked to close from its fields too.\n if (!escSlot.fromFields && isEditableTarget(e.target)) return;\n // The window's own layers, innermost first; true means one of them took it.\n if (escSlot.onEscape?.() === true) return;\n escSlot.onClose();\n });\n}\n\n/** The `.swin-head` bar every tool window wears: title (or tabs), lead, spacer,\n * trail, pin, close. The close button says \"Close (Esc)\" once, here, rather\n * than in every window. */\nexport function toolWindowHead(opts: ToolWindowHeadOptions): HTMLElement {\n const keep = (parts: (Node | string | null)[] | undefined): (Node | string)[] =>\n (parts ?? []).filter((p): p is Node | string => p !== null);\n const pin = opts.pin\n ?? pinButton({ pinned: opts.pinned ?? true, onToggle: opts.onPin ?? (() => {}) });\n if (opts.esc !== false) {\n escSlot = { onClose: opts.onClose, onEscape: opts.onEscape, fromFields: opts.esc === \"always\" };\n wireEsc();\n }\n return el(\"header\", { className: `swin-head${opts.className ? ` ${opts.className}` : \"\"}` },\n ...(opts.title !== undefined ? [el(\"span\", { className: \"swin-title\", text: opts.title })] : []),\n ...(opts.tabs ? [opts.tabs] : []),\n ...keep(opts.lead),\n el(\"span\", { className: \"swin-spacer\" }),\n ...keep(opts.trail),\n pin.el,\n el(\"button\", { className: \"swin-close\", tip: \"Close (Esc)\", onClick: opts.onClose }, iconNode(\"close\")),\n );\n}\n\n// --- follow in the editor -------------------------------------------------------\n\nexport interface FollowButtonOptions {\n on: boolean;\n /** Persist the choice. The button reflects the click itself. */\n onToggle: (on: boolean) => void;\n /** What the editor opens as the run goes: \"line\" (Patterpad), \"card\"\n * (Storyletter). Default \"line\". */\n what?: string;\n}\n\n/** A toggle and the handle to drive it, the same shape `pinButton` returns. */\nexport interface FollowButton {\n el: HTMLButtonElement;\n /** Reflect a state decided elsewhere, without calling `onToggle`. */\n set: (on: boolean) => void;\n}\n\n/**\n * \"Follow in the editor\": the play surface's toggle that makes the EDITOR\n * follow the run, opening each line / card as it plays. Both play surfaces\n * built one (patterpad play.ts, studio table.ts) with the same label and\n * paraphrased tips; this is the one wording.\n *\n * The LABEL is the careful part. \"Follow\" alone would match the vocabulary of\n * a window that follows the editor; this is the other direction, the editor\n * following the run. Off by default and remembered by the host: following is\n * the author asking for it.\n */\nexport function followButton(opts: FollowButtonOptions): FollowButton {\n const what = opts.what ?? \"line\";\n const b = el(\"button\", \"btn swin-follow\", \"Follow in the editor\");\n b.type = \"button\";\n let on = opts.on;\n const reflect = (): void => {\n b.classList.toggle(\"on\", on);\n b.setAttribute(\"aria-pressed\", String(on));\n const label = on\n ? `The editor opens each ${what} as it plays. Click to stop.`\n : `Open each ${what} in the editor as it plays`;\n b.dataset[\"tip\"] = label;\n };\n reflect();\n b.addEventListener(\"click\", () => { on = !on; reflect(); opts.onToggle(on); });\n return { el: b, set: (next: boolean) => { on = next; reflect(); } };\n}\n","// ---------------------------------------------------------------------------\n// The exit half of the panel motion vocabulary.\n//\n// Enters are pure CSS: they run on insertion. Exits cannot be, because the node\n// has to OUTLIVE the close for the animation to play and then be torn down. So\n// every closing surface routes its teardown through here instead of removing\n// itself directly.\n//\n// Patterpad's `closeWithExit`, lifted. It was already app-agnostic, and the\n// shell had grown a second copy of the same twelve lines inside `confirm.ts`,\n// which is the drift this package exists to stop: one motion vocabulary, drawn\n// one way. `tokens.css` already carried the keyframes and the durations; this\n// is the missing half that plays them.\n// ---------------------------------------------------------------------------\n\n/**\n * Play the close animation on `element`, then run `done` exactly once.\n *\n * `done` does the real teardown: remove the node, drop listeners, unmount\n * whatever was inside it. Under `prefers-reduced-motion` the duration reads 0\n * and `done` runs synchronously, so reduced motion means instant rather than\n * an invisible wait.\n */\nexport function closeWithExit(element: HTMLElement, done: () => void): void {\n element.classList.add(\"closing\");\n // getComputedStyle flushes pending style, so this reflects the `.closing`\n // rule we just added rather than the state before it.\n const seconds = parseFloat(getComputedStyle(element).animationDuration) || 0;\n if (seconds === 0) { done(); return; }\n\n let fired = false;\n const finish = (): void => {\n if (fired) return;\n fired = true;\n element.removeEventListener(\"animationend\", onEnd);\n clearTimeout(timer);\n done();\n };\n // Only OUR animation ending counts. Content inside the panel (rows, pills,\n // spinners) raises its own animationend, and an inner one firing first would\n // tear the panel down mid-fade.\n const onEnd = (e: AnimationEvent): void => { if (e.target === element) finish(); };\n element.addEventListener(\"animationend\", onEnd);\n // Fallback: animationend is missed if the element is hidden or the animation\n // is interrupted, and a panel that never tears down is worse than an abrupt one.\n const timer = setTimeout(finish, seconds * 1000 + 120);\n}\n","// ---------------------------------------------------------------------------\n// dialogFrame: the one modal skeleton every dialog in the family sits on.\n//\n// Title, an optional sub line, a body the caller fills, an actions row the\n// caller fills, on a native <dialog> so the focus trap and Escape come from the\n// platform. Four scrims and three panel drawings had grown across five shell\n// files and a dozen app dialogs (ui-review-2026-09, findings 9 and 30); this is\n// the frame they all sit on now, and the shell's own dialogs (confirm, identity,\n// about, notes) were moved onto it first, which is how it is proven.\n//\n// What the frame owns: the backdrop, the panel, the enter and exit motion\n// (closeWithExit), Escape, and giving focus back to whatever had it when the\n// dialog opened. What it does not own: the content classes, the buttons'\n// meaning, and when to close. The caller keeps those.\n//\n// Styles ship as dialog.css. The action buttons are expected to wear `.btn`\n// from controls.css; the frame does not draw buttons of its own.\n// ---------------------------------------------------------------------------\n\nimport { el } from \"./dom.js\";\nimport { closeWithExit } from \"./exit.js\";\n\nexport interface DialogFrameOptions {\n /** The heading. Also the dialog's accessible name. */\n title: string;\n /** One plain sentence under the heading, if the title needs one. */\n sub?: string;\n /** Extra class(es) on the <dialog>, for the caller's own content rules and\n * width (`--dialog-width` on the class; see dialog.css). */\n className?: string;\n /** Runs once, after the dialog has left the document, however it closed. */\n onClose?: () => void;\n}\n\nexport interface DialogFrame {\n readonly dialog: HTMLDialogElement;\n /** Fill this with the content. */\n readonly body: HTMLElement;\n /** Fill this with the buttons, right-aligned; empty, it draws nothing. */\n readonly actions: HTMLElement;\n /** Show modally. Records what had focus so `close()` can give it back. */\n open(): void;\n /** Play the exit, tear down, restore focus. Idempotent. */\n close(): void;\n isOpen(): boolean;\n}\n\n/** Build a dialog on the family's frame. Appended to <body> at once (so an\n * `open()` on the next line has nothing to wait for); shown only on `open()`. */\nexport function dialogFrame(opts: DialogFrameOptions): DialogFrame {\n const dialog = el(\"dialog\", `shell-dialog ${opts.className ?? \"\"}`.trim());\n const body = el(\"div\", \"shell-dialog-body\");\n const actions = el(\"div\", \"shell-dialog-actions\");\n dialog.append(el(\"h2\", \"shell-dialog-title\", opts.title));\n if (opts.sub !== undefined) dialog.append(el(\"p\", \"shell-dialog-sub\", opts.sub));\n dialog.append(body, actions);\n dialog.setAttribute(\"aria-label\", opts.title);\n document.body.append(dialog);\n\n let state: \"closed\" | \"open\" | \"closing\" = \"closed\";\n let opener: Element | null = null;\n\n const teardown = (): void => {\n dialog.remove();\n // Back to the control that opened this. The platform does it for a plain\n // dialog.close(), but the exit motion ends in a remove(), and a removed\n // dialog restores nothing.\n if (opener instanceof HTMLElement && opener.isConnected) opener.focus();\n opener = null;\n state = \"closed\";\n opts.onClose?.();\n };\n\n const close = (): void => {\n if (state !== \"open\") return;\n state = \"closing\";\n closeWithExit(dialog, () => { if (dialog.open) dialog.close(); teardown(); });\n };\n\n // Escape arrives as the cancel event; route it through the exit motion.\n dialog.addEventListener(\"cancel\", (e) => { e.preventDefault(); close(); });\n // Closed by someone else (a form with method=\"dialog\", or a direct\n // dialog.close()): no motion to play, tear down at once.\n dialog.addEventListener(\"close\", () => { if (state === \"open\") teardown(); });\n\n return {\n dialog, body, actions,\n open() {\n if (state !== \"closed\") return;\n opener = document.activeElement;\n state = \"open\";\n dialog.showModal();\n },\n close,\n isOpen: () => state === \"open\",\n };\n}\n","// ---------------------------------------------------------------------------\n// A themed in-app confirmation modal (design-language \"coherent to the\n// edges\": never a stock OS dialog). The promise API is Patterpad's surface\n// confirm; the build sits on the family's dialog frame (dialog.ts), so the\n// focus trap, Esc, the scrim and the exit motion are the frame's. Two\n// deliberate corrections over that original, kept when Patterpad migrates\n// here: the destructive button wears --danger (a required host token; the\n// surface one mistakenly used --accent), and initial focus lands on Cancel so\n// a stray Enter cannot destroy anything.\n//\n// Styles: dialog.css + controls.css for the frame and the buttons, confirm.css\n// for what is confirm's own (its width, its body copy). Callers keep the\n// elide-the-dialog rule: when nothing is at stake, don't ask.\n// ---------------------------------------------------------------------------\n\nimport { el } from \"./dom.js\";\nimport { dialogFrame } from \"./dialog.js\";\n\nexport interface ConfirmOptions {\n title: string;\n /** One plain sentence, ending with what undo does. */\n body?: string;\n /**\n * Content that is evidence rather than a sentence: a list of the scenes that\n * refer to the thing, a warning line. Rendered after `body` when both are\n * given. The caller styles it; the frame's body is a column with a gap.\n */\n bodyNode?: HTMLElement;\n /** The destructive button's label, which names its object (\"Delete scene\",\n * \"Remove language\"). */\n confirmLabel: string;\n}\n\n/** Resolves true on confirm; false on Cancel / Esc / backdrop. */\nexport function confirmDialog(opts: ConfirmOptions): Promise<boolean> {\n return new Promise((resolve) => {\n let done = false;\n // Resolve on the gesture, not after the exit motion: the caller acts on the\n // answer at once, and the fade plays over whatever it does.\n const finish = (ok: boolean): void => {\n if (done) return;\n done = true;\n resolve(ok);\n frame.close();\n };\n const frame = dialogFrame({\n title: opts.title, className: \"confirm-dialog\",\n onClose: () => finish(false), // Esc, or closed by someone else\n });\n const cancel = el(\"button\", \"btn confirm-btn cancel\", \"Cancel\");\n const danger = el(\"button\", \"btn danger confirm-btn\", opts.confirmLabel);\n cancel.type = \"button\";\n danger.type = \"button\";\n if (opts.body !== undefined) frame.body.append(el(\"div\", \"confirm-body\", opts.body));\n if (opts.bodyNode) frame.body.append(opts.bodyNode);\n frame.actions.append(cancel, danger);\n\n cancel.addEventListener(\"click\", () => finish(false));\n danger.addEventListener(\"click\", () => finish(true));\n // Esc arrives as the dialog's cancel event; the frame routes it through the\n // exit motion and onClose. A mousedown that lands on the dialog element\n // itself is the backdrop.\n frame.dialog.addEventListener(\"mousedown\", (e) => { if (e.target === frame.dialog) finish(false); });\n\n frame.open();\n cancel.focus();\n });\n}\n","// ---------------------------------------------------------------------------\n// The floating-layer lifecycle every popup and menu shares: a body-appended\n// element, display toggling, a scroll / resize follower that keeps it glued to\n// its anchor, a click-away dismiss, and the family's exit motion on close.\n//\n// Patterpad's surface had it (four popups: the cue picker, the slash menu, the\n// action menu, the jump picker) and Storyletter's context menu had the same\n// idea in eleven lines without the follower (ui-review-2026-09, finding 5).\n// This is the surface's, lifted whole. Positioning stays the caller's, because\n// it differs per popup: pass a `reposition` closure to `show()` and the\n// follower re-runs it on scroll and resize until `close()`.\n//\n// The element is REUSED across opens (a popup that re-renders on every\n// keystroke must not tear itself down each time), which is why a stale exit\n// teardown has a token to lose against a reopen.\n// ---------------------------------------------------------------------------\n\nimport { closeWithExit } from \"./exit.js\";\n\nexport interface Floating {\n /** The floating element. Build content into it; it is appended to <body>\n * (or the `host` given), hidden until `show()`. */\n readonly el: HTMLElement;\n /** Show `el` and keep `reposition` glued to the anchor on scroll / resize.\n * Safe to call repeatedly (on every re-render): the follower attaches once. */\n show(reposition: () => void): void;\n /** While open, call `onOutside` on a pointer-down outside `el`, and outside\n * anything `isInside` accepts (a second flyout, the anchor button).\n * Idempotent: arms once. */\n dismissOnOutside(onOutside: () => void, isInside?: (target: Node) => boolean): void;\n /** Play the exit, then hide `el`, clear its children, and drop the follower\n * and any outside listener. */\n close(): void;\n isOpen(): boolean;\n}\n\n/** Re-run `reposition` on any scroll or resize until the returned disposer runs. */\nfunction followOnScroll(reposition: () => void): () => void {\n const onMove = (): void => reposition();\n window.addEventListener(\"scroll\", onMove, true);\n window.addEventListener(\"resize\", onMove);\n return () => { window.removeEventListener(\"scroll\", onMove, true); window.removeEventListener(\"resize\", onMove); };\n}\n\nexport interface FloatingOptions {\n /** Where the element is appended. Default <body>. Under a modal <dialog> a\n * body-level node sits behind the scrim, inert, so a popup opened from\n * inside one passes the dialog here and paints in its top layer. */\n host?: HTMLElement;\n}\n\nexport function createFloating(className: string, opts: FloatingOptions = {}): Floating {\n const el = document.createElement(\"div\"); el.className = className; el.style.display = \"none\";\n (opts.host ?? document.body).appendChild(el);\n let open = false;\n let detach: (() => void) | null = null;\n let outside: ((e: MouseEvent) => void) | null = null;\n let closeToken = 0; // bumped on every show / close so a stale exit teardown cannot clobber a reopen\n\n const close = (): void => {\n if (!open) return;\n open = false;\n detach?.(); detach = null; // stop following + dismissing immediately; it is on its way out\n if (outside) { document.removeEventListener(\"mousedown\", outside, true); outside = null; }\n const myToken = ++closeToken;\n // Play the exit, THEN hide + clear. A reopen during the fade must win:\n // show() bumps closeToken, and this guard abandons the stale teardown.\n closeWithExit(el, () => {\n if (myToken !== closeToken) return;\n el.style.display = \"none\"; el.replaceChildren(); el.classList.remove(\"closing\");\n });\n };\n\n const show = (reposition: () => void): void => {\n closeToken++; el.classList.remove(\"closing\"); // cancel any in-flight exit, undo its class\n open = true; el.style.display = \"block\"; reposition();\n detach ??= followOnScroll(reposition);\n };\n\n const dismissOnOutside = (onOutside: () => void, isInside?: (target: Node) => boolean): void => {\n if (outside) return; // already armed\n outside = (e: MouseEvent): void => {\n const t = e.target as Node;\n if (!el.contains(t) && !(isInside?.(t) ?? false)) onOutside();\n };\n document.addEventListener(\"mousedown\", outside, true);\n };\n\n return { el, show, dismissOnOutside, close, isOpen: () => open };\n}\n","// ---------------------------------------------------------------------------\n// A right-click context menu and a small anchored popover: a floating list of\n// actions at the cursor (or a panel under a control), dismissed on outside\n// click or Escape, clamped to the viewport, closed with the family's exit\n// motion.\n//\n// Storyletter's, lifted (ui-review-2026-09, finding 11): its own header had\n// named itself an extraction candidate, and it had the two things Patterpad's\n// inline `sceneContextMenu` lacked, a `disabled` item and the clamp. A DOM\n// popover, not a native menu, so it is themed like everything else.\n//\n// Styles ship as context-menu.css; import it wherever the module is used,\n// including tool windows, which is the bug that made Storyletter give the\n// menu its own stylesheet in the first place.\n// ---------------------------------------------------------------------------\n\nimport { el } from \"./dom.js\";\nimport { closeWithExit } from \"./exit.js\";\n\nexport interface ContextItem {\n label: string;\n /** Drawn in --danger: a destructive action, which names its object. */\n danger?: boolean;\n /** Shown greyed and unclickable. For an action that belongs on this menu\n * but cannot apply right now (Move up on the first row), so the menu keeps\n * the same shape and the same item stays in the same place every time. */\n disabled?: boolean;\n onClick: () => void;\n}\n\nconst EDGE = 6;\n\n/** The one open menu or popover. Only ever one, so a fresh open replaces it\n * and a re-render that removed the anchor cannot leave one hanging in the air. */\nlet current: (() => void) | null = null;\n\n/** Outside-click / Escape wiring shared by the menu and the popover. The\n * returned `dismiss` plays the exit and removes the node; `onDismiss` fires\n * for every way out so a caller can flush on all of them. */\nfunction floating(node: HTMLElement, onDismiss?: () => void): { dismiss: () => void } {\n let gone = false;\n const dismiss = (): void => {\n if (gone) return;\n gone = true;\n if (current === dismiss) current = null;\n window.removeEventListener(\"pointerdown\", onAway, true);\n window.removeEventListener(\"keydown\", onKey, true);\n // A node mid-fade must not take a second click.\n closeWithExit(node, () => node.remove());\n onDismiss?.();\n };\n const onAway = (e: PointerEvent): void => { if (!node.contains(e.target as Node)) dismiss(); };\n const onKey = (e: KeyboardEvent): void => { if (e.key === \"Escape\") { e.preventDefault(); dismiss(); } };\n window.addEventListener(\"pointerdown\", onAway, true);\n window.addEventListener(\"keydown\", onKey, true);\n current?.();\n current = dismiss;\n return { dismiss };\n}\n\n/** Clamp a floating node into the viewport, preferring below `anchor` and\n * flipping above it when there is no room. */\nfunction placeBelow(node: HTMLElement, anchor: DOMRect): void {\n node.style.left = `${anchor.left}px`;\n node.style.top = `${anchor.bottom + 4}px`;\n const r = node.getBoundingClientRect();\n if (r.right > window.innerWidth) node.style.left = `${Math.max(EDGE, window.innerWidth - r.width - EDGE)}px`;\n if (r.bottom > window.innerHeight) node.style.top = `${Math.max(EDGE, anchor.top - r.height - 4)}px`;\n}\n\nexport interface PopoverOptions {\n /** Where the popover is appended. Default <body>. A popover opened from\n * inside a modal <dialog> passes the dialog: a body-level node sits behind\n * the scrim, inert, while one inside the dialog paints in its top layer\n * (Patterpad's colour swatch popover in Project settings). */\n host?: HTMLElement;\n}\n\n/** Open a small panel anchored to an element; `build` gets a close callback.\n * `onClose` runs however it closes (Escape, outside click, or `close`), the\n * place to flush an edit the panel was collecting. Only one is ever open. */\nexport function openPopover(\n anchor: HTMLElement, build: (close: () => void) => HTMLElement, onClose?: () => void, opts: PopoverOptions = {},\n): void {\n const pop = el(\"div\", \"popover\");\n let closed = false;\n const finish = (): void => { if (closed) return; closed = true; onClose?.(); };\n const { dismiss } = floating(pop, finish);\n pop.append(build(dismiss));\n (opts.host ?? document.body).append(pop);\n placeBelow(pop, anchor.getBoundingClientRect());\n}\n\n/** Open a context menu at (x, y). Only one is ever open. */\nexport function openContextMenu(x: number, y: number, items: ContextItem[]): void {\n const menu = el(\"div\", \"ctxmenu\");\n menu.setAttribute(\"role\", \"menu\");\n const { dismiss } = floating(menu);\n\n for (const item of items) {\n const button = el(\"button\", {\n className: `ctxmenu-item${item.danger ? \" danger\" : \"\"}`, text: item.label,\n onClick: () => { if (item.disabled === true) return; dismiss(); item.onClick(); },\n });\n button.type = \"button\";\n button.setAttribute(\"role\", \"menuitem\");\n if (item.disabled === true) button.disabled = true;\n menu.append(button);\n }\n\n menu.style.left = `${x}px`;\n menu.style.top = `${y}px`;\n document.body.append(menu);\n // Keep it on-screen.\n const r = menu.getBoundingClientRect();\n if (r.right > window.innerWidth) menu.style.left = `${Math.max(EDGE, window.innerWidth - r.width - EDGE)}px`;\n if (r.bottom > window.innerHeight) menu.style.top = `${Math.max(EDGE, window.innerHeight - r.height - EDGE)}px`;\n}\n","// ---------------------------------------------------------------------------\n// The About surface: every app in the family has one, and it should never be\n// the grey OS panel (design-language, \"coherent to the edges\").\n//\n// Patterpad's, generalised. Theirs reuses its updater-dialog chrome and hard\n// codes the PatterKit wordmark; the shell takes the wordmark as markup from the\n// app, because that is the one part that is genuinely per-product. Everything\n// else - the layout, the type, the link handling, the single Close - is the\n// family's, so two apps' About boxes are recognisably siblings.\n//\n// The host opens links, because a renderer cannot: `onOpenLink` goes through\n// the app's own IPC to `shell.openExternal`. Without it the links are shown as\n// plain text rather than as buttons that do nothing.\n// ---------------------------------------------------------------------------\n\nimport { el } from \"./dom.js\";\nimport { dialogFrame } from \"./dialog.js\";\n\nexport interface AboutOptions {\n /** The product's name, large. */\n appName: string;\n /** \"1.4.2\" - shown as \"Version 1.4.2\". */\n version: string;\n /** One or two sentences: what this app is for. */\n blurb?: string;\n /** Licence, authorship, the suite it belongs to. Newlines are respected. */\n credits?: string;\n links?: { label: string; url: string }[];\n /** Inline SVG for the product wordmark, if it has one. */\n wordmark?: string;\n /** Open a URL in the real browser. Omit and the links render as text. */\n onOpenLink?: (url: string) => void;\n}\n\n/** Show the About dialog. Resolves when it closes. */\nexport function showAbout(opts: AboutOptions): Promise<void> {\n return new Promise((resolve) => {\n // On the family's frame: the product name is the frame's title, centred by\n // about.css, and the wordmark sits above it.\n const frame = dialogFrame({ title: opts.appName, className: \"shell-about\", onClose: () => resolve() });\n frame.dialog.setAttribute(\"aria-label\", `About ${opts.appName}`);\n if (opts.wordmark !== undefined) {\n const mark = el(\"div\", \"shell-about-mark\");\n mark.innerHTML = opts.wordmark;\n frame.dialog.prepend(mark);\n }\n frame.body.append(el(\"div\", \"shell-about-version\", `Version ${opts.version}`));\n if (opts.blurb !== undefined) frame.body.append(el(\"p\", \"shell-about-blurb\", opts.blurb));\n if (opts.credits !== undefined) frame.body.append(el(\"p\", \"shell-about-credits\", opts.credits));\n\n if (opts.links?.length) {\n const row = el(\"div\", \"shell-about-links\");\n for (const link of opts.links) {\n if (!opts.onOpenLink) { row.append(el(\"span\", \"shell-about-link\", link.label)); continue; }\n const a = el(\"button\", \"shell-about-link\", link.label);\n a.type = \"button\";\n a.addEventListener(\"click\", () => opts.onOpenLink?.(link.url));\n row.append(a);\n }\n frame.body.append(row);\n }\n\n const close = el(\"button\", \"btn shell-about-close\", \"Close\");\n close.type = \"button\";\n close.addEventListener(\"click\", () => frame.close());\n frame.actions.append(close);\n frame.open();\n close.focus();\n });\n}\n","// ---------------------------------------------------------------------------\n// A floating panel anchored to the thing it is about: Patterpad's\n// `openAnchoredPanel`, lifted and generalised.\n//\n// Patterpad's condition, effects, jump and gameId editors all use one, and so do\n// Storyletter's comment threads. Two implementations of one idea existed for\n// about a day, which is exactly the drift the shell is for - and Patterpad's was\n// the mature one, so this is that, not the one written second.\n//\n// The behaviours are all learnt from use, and each is a bug somebody hit:\n//\n// - Re-clicking the SAME anchor toggles the panel off and returns null,\n// rather than closing and reopening with a flicker. Callers must handle the\n// null.\n// - A DIFFERENT anchor swaps rather than stacking: only one is ever open.\n// - The outside-click listener is armed a tick late, or the very click that\n// opened the panel would close it again.\n// - `ignoreDown` spares body-level inner popovers, which are outside the\n// panel in the DOM but inside it as far as the author is concerned.\n// - `deferEscape` leaves Escape to an inner popover when one is open, so one\n// key does not close two things.\n//\n// Placement is the part worth reading. It flips to whichever side of the anchor\n// has MORE room, keeps clear of any bottom bars the app names, caps at 70% of\n// the window and scrolls its body. A panel that opens cramped against a status\n// bar with empty space above it is the failure this avoids.\n// ---------------------------------------------------------------------------\n\nimport { el } from \"./dom.js\";\nimport { iconNode } from \"./icons.js\";\nimport { closeWithExit } from \"./exit.js\";\n\nexport interface AnchoredPanel {\n panel: HTMLElement;\n /** The content area to populate: the header is built for you. */\n body: HTMLElement;\n /** Idempotent; fires the caller's `onClose` exactly once. */\n close: () => void;\n}\n\nexport interface AnchoredPanelOptions {\n anchor: HTMLElement;\n /** Extra class(es) on the panel, for app-specific sizing or colour. */\n className?: string;\n title: string;\n width: number;\n /**\n * Which side to try first.\n *\n * `\"left\"` suits a panel hung off a row in a right-hand pane (Patterpad's\n * inspector); `\"below\"` suits one hung off a button in a document's header\n * (Storyletter's topline). Either way it flips when the room is not there.\n */\n prefer?: \"left\" | \"below\" | \"centre\";\n /** Selectors for chrome the panel must not cover - a problems bar, a review\n * bar - so those stay usable while it is open. */\n keepClear?: string[];\n /** A pointerdown inside something matching this does NOT close the panel. */\n ignoreDown?: string;\n /** While something matching this exists, Escape belongs to it, not to us. */\n deferEscape?: string;\n /** Where the panel is appended. Default <body>. A panel opened from inside a\n * modal <dialog> passes the dialog: a body-level node sits behind the scrim,\n * inert, while one inside the dialog paints in its top layer. Placement is\n * viewport-relative either way (`position: fixed`). */\n host?: HTMLElement;\n onClose?: () => void;\n}\n\n/** The one open panel. Only ever one, which is what makes toggling meaningful. */\nlet current: { anchor: HTMLElement; panel: HTMLElement; close: () => void } | null = null;\n\nexport function openAnchoredPanel(opts: AnchoredPanelOptions): AnchoredPanel | null {\n if (current) {\n const prev = current;\n current = null;\n prev.close();\n if (prev.anchor === opts.anchor) return null; // a toggle, not a reopen\n }\n\n const panel = el(\"div\", `shell-anchored ${opts.className ?? \"\"}`.trim());\n const closeBtn = el(\"button\", \"shell-anchored-close\", iconNode(\"close\", 12));\n closeBtn.type = \"button\";\n closeBtn.setAttribute(\"aria-label\", \"Close\");\n const body = el(\"div\", \"shell-anchored-body\");\n panel.append(\n el(\"div\", \"shell-anchored-head\", el(\"span\", \"shell-anchored-title\", opts.title), closeBtn),\n body,\n );\n (opts.host ?? document.body).append(panel);\n placeAnchored(panel, opts.anchor, opts.width, opts.prefer ?? \"below\", opts.keepClear ?? []);\n\n let closed = false;\n const close = (): void => {\n if (closed) return;\n closed = true;\n if (current?.panel === panel) current = null;\n document.removeEventListener(\"pointerdown\", onDown, true);\n document.removeEventListener(\"keydown\", onKey, true);\n // Play the exit, THEN tear down. The order matters: `onClose` is where a\n // caller unmounts whatever it put in the body, so running it first would\n // leave an empty panel fading out. Listeners come off above rather than\n // here, because a panel mid-fade must not still be taking clicks.\n closeWithExit(panel, () => { opts.onClose?.(); panel.remove(); });\n };\n closeBtn.addEventListener(\"click\", close);\n\n const onDown = (e: PointerEvent): void => {\n const target = e.target as Node;\n if (panel.contains(target) || opts.anchor.contains(target)) return;\n if (opts.ignoreDown !== undefined && target instanceof Element && target.closest(opts.ignoreDown)) return;\n close();\n };\n const onKey = (e: KeyboardEvent): void => {\n if (e.key !== \"Escape\") return;\n if (opts.deferEscape !== undefined && document.querySelector(opts.deferEscape)) return;\n close();\n };\n // Next tick: the click that opened this is still travelling.\n setTimeout(() => {\n document.addEventListener(\"pointerdown\", onDown, true);\n document.addEventListener(\"keydown\", onKey, true);\n }, 0);\n\n current = { anchor: opts.anchor, panel, close };\n return { panel, body, close };\n}\n\n/** Close whatever is open. For a navigation or a re-render: a panel anchored to\n * an element that no longer exists would hang in the air. */\nexport function closeAnchoredPanel(): void {\n const open = current;\n current = null;\n open?.close();\n}\n\n/** Patterpad's placement, with the side as a parameter. */\nexport function placeAnchored(\n panel: HTMLElement, anchor: HTMLElement, width: number,\n prefer: \"left\" | \"below\" | \"centre\", keepClear: string[],\n): void {\n const a = anchor.getBoundingClientRect();\n const GAP = 10;\n const CAP = window.innerHeight * 0.7;\n const MIN_H = 140;\n panel.style.width = `${width}px`;\n\n // \"centre\" is for an anchor that is a POINT rather than a control: a zero-size\n // proxy dropped where somebody clicked on a canvas. Aligning a panel's edge to\n // a point puts the whole panel up and to one side of the spot the person just\n // chose, which reads as the panel having appeared somewhere else. Centred on\n // the point, it appears where they pointed.\n if (prefer === \"centre\") {\n const centred = a.left + a.width / 2 - width / 2;\n panel.style.left = `${Math.round(Math.min(Math.max(8, centred), window.innerWidth - width - 8))}px`;\n } else {\n // Horizontally: left of the anchor when asked and there is room, otherwise\n // aligned to it and nudged back inside the window.\n const leftOf = a.left - width - GAP;\n const alignedRight = Math.min(a.right - width, window.innerWidth - width - 8);\n panel.style.left = `${Math.round(prefer === \"left\" && leftOf >= 8\n ? leftOf\n : Math.max(8, prefer === \"left\" ? a.left : alignedRight))}px`;\n }\n\n // Vertically: whichever side has more room, staying off the app's bottom bars.\n let bottomLimit = window.innerHeight - 8;\n for (const selector of keepClear) {\n const bar = document.querySelector(selector);\n if (!bar) continue;\n const r = bar.getBoundingClientRect();\n if (r.height > 0) bottomLimit = Math.min(bottomLimit, r.top - 6);\n }\n // Centred on a point vertically as well, for the same reason, but only while\n // the panel actually fits: past that it falls back to the more-room-wins rule\n // below rather than hanging off the top of the window.\n if (prefer === \"centre\") {\n const height = Math.min(CAP, Math.max(MIN_H, panel.offsetHeight));\n const mid = a.top + a.height / 2 - height / 2;\n if (mid >= 8 && mid + height <= bottomLimit) {\n panel.style.top = `${Math.round(mid)}px`;\n panel.style.bottom = \"auto\";\n panel.style.maxHeight = `${Math.round(CAP)}px`;\n return;\n }\n }\n const roomBelow = bottomLimit - (a.bottom + GAP);\n const roomAbove = (a.top - GAP) - 8;\n if (roomAbove > roomBelow) {\n panel.style.top = \"auto\";\n panel.style.bottom = `${Math.round(window.innerHeight - (a.top - GAP))}px`;\n panel.style.maxHeight = `${Math.round(Math.max(MIN_H, Math.min(CAP, roomAbove)))}px`;\n } else {\n panel.style.bottom = \"auto\";\n panel.style.top = `${Math.round(Math.max(8, a.bottom + GAP))}px`;\n panel.style.maxHeight = `${Math.round(Math.max(MIN_H, Math.min(CAP, roomBelow)))}px`;\n }\n}\n","// ---------------------------------------------------------------------------\n// Game IDs: the host-facing ADDRESS of a thing.\n//\n// This belongs to the shell because it follows from the SHAPE these apps share\n// rather than from any one subject: a project of data files that compiles to\n// artefacts for something else to consume. \"Something else consumes it\" is the\n// whole reason content needs a stable name a program can call it by. Nothing\n// here needs the words card, beat, hand or scene to describe.\n//\n// It arrived here as two byte-identical copies, in Storyletter's model and\n// Patterpad's, each with its own editor popover on top - and the two editors had\n// grown DIFFERENT manners for the same job, which is how the duplication was\n// noticed at all.\n//\n// DEPENDENCY-FREE on purpose. The apps' domain layers (compilers, CLIs, engine\n// runtimes) need these rules far from any UI, and they keep their own copies\n// rather than taking a dependency on a UI kit; each asserts parity with these in\n// a test, so the copies cannot drift in silence. A NEW app starts from these.\n// ---------------------------------------------------------------------------\n\n/**\n * Slugify a name into hyphen form: lower case, apostrophes dropped, runs of\n * anything else to a single hyphen, no leading or trailing hyphen.\n *\n * May return \"\", when there was nothing usable in the input. Callers treat that\n * as \"no pinned address\" rather than as an address.\n */\nexport function gameIdify(text: string): string {\n return text.toLowerCase().replace(/['’]/g, \"\")\n .replace(/[^a-z0-9-]+/g, \"-\").replace(/-+/g, \"-\").replace(/^-+|-+$/g, \"\");\n}\n\n/** Is this a legal address? Lower case, digits and hyphens, starting and ending\n * with a letter or a digit. Note \"\" is NOT legal: an empty pinned address means\n * \"derive one\", which is a different thing from an address. */\nexport function isValidGameId(gameId: string): boolean {\n return /^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/.test(gameId);\n}\n","// ---------------------------------------------------------------------------\n// Property names: what an author may call a value the story reads and writes.\n//\n// This belongs to the shell for the same reason gameIds do (see ids.ts): it\n// follows from the SHAPE these apps share - a project of data files, authored in\n// an editor, compiled for something else to run - rather than from any one\n// subject. Nothing here needs the words card, beat, hand or scene.\n//\n// UNLIKE gameIds, the rule is not a house style. It is dictated by the\n// expression language both families embed (`@wildwinter/expr`), and every clause\n// below is a failure observed by compiling one:\n//\n// parser.ts tokenises an identifier as /[a-zA-Z_][a-zA-Z0-9_]*/ and then\n// FOLDS it: `name: propTok.value.toLowerCase()`.\n//\n// @patter.is_night -> [\"sv\",\"patter\",\"is_night\"] reachable\n// @patter.isNight -> [\"sv\",\"patter\",\"isnight\"] folded: a declaration\n// spelled `isNight` is\n// one nothing can reach\n// @patter.is-night -> [\"bin\",\"-\",[\"sv\",\"patter\",\"is\"], NOT an error: it is\n// [\"s\",\"night\"]] SUBTRACTION. A hyphen\n// silently compiles to\n// a different meaning\n// @patter.is night -> parse error\n// @patter.9lives -> parse error (a name cannot start with a digit)\n// @patter.not -> parse error (`true false and or not` are keywords)\n//\n// The hyphen line is why this is worth a shared rule rather than a per-app\n// check: every other violation is loud, and that one quietly means something\n// else. It is also why a property name is NOT a gameId with different spelling -\n// a gameId is built out of hyphens, and here a hyphen is an operator.\n//\n// DEPENDENCY-FREE on purpose, ids.ts's reasoning verbatim: the apps' compilers,\n// CLIs and embedded runtimes need these rules far from any UI, so they keep\n// their own copies and assert parity with these in a test.\n// ---------------------------------------------------------------------------\n\n/** The five words `@wildwinter/expr` lexes as keywords, so a property may not be\n * called any of them: the reference does not resolve, it fails to parse. Kept\n * here as a copy for the same reason the rules are (no dependency), and each\n * app probes the real parser to prove the list is still true. */\nexport const RESERVED_PROPERTY_NAMES: readonly string[] = [\"true\", \"false\", \"and\", \"or\", \"not\"];\n\n/** What an editor should tell an author, in one line. */\nexport const PROPERTY_NAME_HINT =\n \"Lower case letters, digits, and underscores. It can't start with a digit. No hyphens or spaces.\";\n\n/**\n * Coerce a label into a legal property name: lower case, apostrophes dropped,\n * runs of anything else to a single underscore, no trailing underscore, an\n * underscore in front if it would otherwise start with a digit, and one behind\n * if it would otherwise be a keyword.\n *\n * A LEADING underscore is kept where the author typed one, because `_private` is\n * a legal name and a meaningful choice; only the ends that would be illegal are\n * touched.\n *\n * May return \"\", when there was nothing usable in the input. Callers treat that\n * as \"no name yet\" rather than as a name.\n */\nexport function propertyNameify(text: string): string {\n const trimmed = text.trim();\n // An underscore the author actually typed is kept; one that is only the ghost of\n // leading punctuation is not. That is the difference between `_private` and `!gold`.\n const deliberateLeading = trimmed.startsWith(\"_\");\n let out = trimmed.toLowerCase().replace(/['’]/g, \"\")\n .replace(/[^a-z0-9_]+/g, \"_\").replace(/_+/g, \"_\").replace(/^_+|_+$/g, \"\");\n if (out === \"\") return \"\";\n if (deliberateLeading || /^[0-9]/.test(out)) out = `_${out}`;\n if (RESERVED_PROPERTY_NAMES.includes(out)) out = `${out}_`;\n return out;\n}\n\n/**\n * Is this a name the expression language can actually reach? Lower case letters,\n * digits and underscores, not starting with a digit, and not a keyword.\n *\n * \"\" is NOT legal: an unnamed declaration is an unfinished row, which is a\n * different thing from an illegal one, and callers distinguish them.\n */\nexport function isValidPropertyName(name: string): boolean {\n return /^[a-z_][a-z0-9_]*$/.test(name) && !RESERVED_PROPERTY_NAMES.includes(name);\n}\n\n/**\n * The one thing that is only a case difference, e.g. `isNight` -> `isnight`.\n *\n * Worth its own question because it is the only violation that can be repaired\n * without guessing at intent: the language already folds every REFERENCE, so\n * folding the declaration to match changes nothing observable, where inventing\n * an underscore for a space is a decision about what the author meant. Loaders\n * fold this class silently and report the rest.\n */\nexport function isCaseOnlyPropertyName(name: string): boolean {\n return !isValidPropertyName(name) && isValidPropertyName(name.toLowerCase());\n}\n","// ---------------------------------------------------------------------------\n// The manners for a field that names a declared property.\n//\n// The RULE is property-names.ts, which is dependency-free because each app's\n// domain layer keeps its own copy of it. This is the other half: how a field\n// BEHAVES while somebody types a name into it, which only UI touches, so the\n// shell owns it outright.\n//\n// The manners are the gameId editor's, adopted rather than re-argued (see\n// id-editor.ts): an illegal name is marked and blocks Save, and Tab coerces it,\n// in the field, where it can be seen and undone. Nothing is rewritten as it is\n// typed. Patterpad's first pass at this folded every keystroke to lower case;\n// that is the manner the id editor had already rejected, on the grounds that an\n// app which silently renames a thing has made a decision that was not its to\n// make, and a property name is exactly that kind of thing: the author is naming\n// something their own conditions will call.\n//\n// It arrived here as two copies, one per app, written in one session and already\n// carrying the same forty lines of fault wording. Lifting them before they could\n// drift is the whole reason this file exists.\n// ---------------------------------------------------------------------------\n\nimport { isValidPropertyName, propertyNameify, RESERVED_PROPERTY_NAMES } from \"./property-names.js\";\n\n/** Re-check callbacks for bound REFERENCE fields, so a host can say \"the declarations\n * changed\" without holding a handle per row. */\nconst refSyncs = new WeakMap<HTMLInputElement, () => void>();\n\n/**\n * One line saying what is wrong with this name, or undefined when nothing is.\n *\n * Each branch names what actually HAPPENS rather than reciting the rule, because\n * the person reading it is usually somebody wondering why a condition does\n * nothing. Kept to one line: it lands in a rollover on the field, and hosts\n * repeat it in the Save error rather than inventing a summary of their own.\n */\nexport function propertyNameProblem(name: string): string | undefined {\n if (isValidPropertyName(name)) return undefined;\n const suggestion = propertyNameify(name);\n const tail = suggestion ? ` Try \"${suggestion}\", or press Tab.` : \"\";\n if (RESERVED_PROPERTY_NAMES.includes(name.toLowerCase())) {\n return `Can't be used. \"${name.toLowerCase()}\" is a keyword in expressions.${tail}`;\n }\n // The one that is not an error anywhere else: `@scope.a-b` compiles to a-minus-b.\n if (name.includes(\"-\")) return `Can't be used. A hyphen reads as subtraction in an expression.${tail}`;\n if (/^[0-9]/.test(name)) return `Can't be used. A name can't start with a digit.${tail}`;\n if (name !== name.toLowerCase()) {\n return `Can't be used. Expressions fold names, so this would look for \"${name.toLowerCase()}\".${tail}`;\n }\n return `Can't be used. Only lower case letters, digits, and underscores.${tail}`;\n}\n\n/**\n * Wire a name field: mark it live, explain the fault in its rollover, and coerce\n * on Tab. `onCommit` receives what the author typed, VERBATIM, on every input.\n *\n * `.illegal` rather than dupGuard's `.invalid`, because both can be true of one\n * field and `dupGuard.check()` owns that class: it would clear this marking every\n * time it ran, including at the moment of a blocked Save.\n *\n * An empty field is not marked. An unfinished row is a different thing from an\n * illegal one, and hosts prune blank names on save.\n */\nexport function bindPropertyName(\n input: HTMLInputElement,\n onCommit: (value: string) => void,\n opts: { hint?: string } = {},\n): void {\n const hint = opts.hint;\n const sync = (): void => {\n const v = input.value.trim();\n const problem = v === \"\" ? undefined : propertyNameProblem(v);\n input.classList.toggle(\"illegal\", !!problem);\n if (problem) input.title = problem;\n else if (input.title.startsWith(\"Can't be used\")) {\n if (hint) input.title = hint;\n else input.removeAttribute(\"title\");\n }\n };\n input.addEventListener(\"input\", () => { onCommit(input.value); sync(); });\n input.addEventListener(\"keydown\", (e) => {\n // The opt-in coercion, the id editor's gesture. Shift+Tab is left alone: it is\n // how somebody leaves a field they have not finished with.\n if (e.key !== \"Tab\" || e.shiftKey) return;\n const typed = input.value.trim();\n if (typed === \"\" || isValidPropertyName(typed)) return;\n const coerced = propertyNameify(typed);\n if (!coerced || coerced === input.value) return;\n e.preventDefault();\n input.value = coerced;\n onCommit(coerced);\n sync();\n });\n sync();\n}\n\n/**\n * The first field in `host` holding a name no expression could reach, for a Save\n * gate. Hosts hand this back beside `dupGuard.firstDuplicate()`: two faults, two\n * sets of words, one gate.\n */\nexport function firstIllegalPropertyName(host: ParentNode): HTMLInputElement | null {\n return host.querySelector<HTMLInputElement>(\"input.illegal\");\n}\n\n// ---------------------------------------------------------------------------\n// Reference fields, which are a different job from declaration fields.\n//\n// A declaration NAMES a property; a reference POINTS at one. The expression\n// parser folds every reference, so `@world.isNight` reaches `isnight` perfectly\n// well and complaining about the capital would be inventing a rule the language\n// does not have. Everything else still bites, and harder: no declaration may\n// contain a hyphen, so `is-night` in a reference can never match anything that\n// exists.\n//\n// And a reference has a fault a declaration cannot have: naming something that\n// was never declared. That is not a grammar question, so the host supplies the\n// list. The cost of getting it wrong is quiet - a coverage driver pointed at a\n// property nobody declared feeds a value nobody reads, the branches it was meant\n// to exercise stay unexercised, and the report shows them as never hit, which\n// reads as \"this content is unreachable\" rather than \"that name is a typo\".\n// ---------------------------------------------------------------------------\n\nexport interface PropertyRefOptions {\n /** The names that exist, read fresh on every check so a declaration added in the\n * same dialog clears the complaint. Compared case-insensitively, since the\n * parser folds. */\n known: () => string[];\n /** The scope token this field addresses, for the wording (\"no @world property...\"). */\n scope?: string;\n /** Shown on the field when there is nothing to complain about. */\n hint?: string;\n}\n\n/** The closest known name, when one is close enough to be worth naming. Deliberately\n * narrow: a wrong suggestion is worse than none, so it wants a shared prefix or a\n * single-character slip, not the least-bad match in the list. */\nfunction nearest(name: string, known: string[]): string | undefined {\n const n = name.toLowerCase();\n const byPrefix = known.filter((k) => k.toLowerCase().startsWith(n) || n.startsWith(k.toLowerCase()));\n if (byPrefix.length === 1) return byPrefix[0];\n let best: string | undefined;\n let bestScore = 3; // strictly better than \"three edits away\"\n for (const k of known) {\n const a = k.toLowerCase();\n if (Math.abs(a.length - n.length) > 2) continue;\n // Levenshtein, small strings, no need for a matrix beyond two rows.\n let prev = Array.from({ length: n.length + 1 }, (_, i) => i);\n for (let i = 1; i <= a.length; i++) {\n const row = [i];\n for (let j = 1; j <= n.length; j++) {\n row[j] = Math.min(prev[j]! + 1, row[j - 1]! + 1, prev[j - 1]! + (a[i - 1] === n[j - 1] ? 0 : 1));\n }\n prev = row;\n }\n const d = prev[n.length]!;\n if (d < bestScore) { bestScore = d; best = k; }\n }\n return best;\n}\n\n/** Why this reference cannot be used, or undefined when it can. */\nexport function propertyRefProblem(name: string, opts: PropertyRefOptions): string | undefined {\n const scope = opts.scope ? `@${opts.scope}` : \"that scope\";\n // Case is NOT a fault here: the parser folds references.\n const folded = name.toLowerCase();\n if (!isValidPropertyName(folded)) {\n const suggestion = propertyNameify(name);\n const tail = suggestion ? ` Try \"${suggestion}\", or press Tab.` : \"\";\n if (RESERVED_PROPERTY_NAMES.includes(folded)) return `Can't be used. \"${folded}\" is a keyword in expressions.${tail}`;\n if (name.includes(\"-\")) return `Can't be used. A hyphen reads as subtraction in an expression.${tail}`;\n if (/^[0-9]/.test(name)) return `Can't be used. A name can't start with a digit.${tail}`;\n return `Can't be used. Only lower case letters, digits, and underscores.${tail}`;\n }\n const known = opts.known();\n if (known.some((k) => k.toLowerCase() === folded)) return undefined;\n const near = nearest(folded, known);\n if (near) return `No ${scope} property is called \"${name}\". Did you mean \"${near}\"?`;\n if (known.length === 0) return `No ${scope} properties are declared yet. Declare one above first.`;\n const shown = known.slice(0, 3).map((k) => `\"${k}\"`).join(\", \");\n const more = known.length > 3 ? `, and ${known.length - 3} more` : \"\";\n return `No ${scope} property is called \"${name}\". Pick one of ${shown}${more}.`;\n}\n\n/**\n * Wire a field that POINTS at a declared property: same manners as a declaration\n * field (mark, do not rewrite, Tab coerces), plus the declared names offered as a\n * datalist, because the rule is declare-then-reference and a picker makes that\n * painless rather than pedantic.\n *\n * Marks `.illegal` for an undeclared name too, which gates Save wherever the host\n * already asks `firstIllegalPropertyName`.\n */\nexport function bindPropertyRef(\n input: HTMLInputElement,\n onCommit: (value: string) => void,\n opts: PropertyRefOptions,\n): void {\n const list = document.createElement(\"datalist\");\n list.id = `shell-propref-${Math.random().toString(36).slice(2, 9)}`;\n input.setAttribute(\"list\", list.id);\n\n // Attached lazily, not once at bind. A datalist has to be IN the document to do anything, and it is\n // attached as a sibling of the input - so binding a field that has not been appended yet (which is\n // the ordinary order for a builder that makes its nodes and then mounts them) silently produced no\n // autocomplete at all: no error, nothing to see. This re-tries on every sync, so it heals as soon as\n // the field reaches the tree.\n const attach = (): void => {\n if (!list.isConnected && input.parentNode) input.after(list);\n };\n\n const sync = (): void => {\n attach();\n const known = opts.known();\n list.replaceChildren(...known.map((k) => { const o = document.createElement(\"option\"); o.value = k; return o; }));\n const v = input.value.trim();\n const problem = v === \"\" ? undefined : propertyRefProblem(v, opts);\n input.classList.toggle(\"illegal\", !!problem);\n if (problem) input.title = problem;\n else if (input.title.startsWith(\"Can't be used\") || input.title.startsWith(\"No \")) {\n if (opts.hint) input.title = opts.hint;\n else input.removeAttribute(\"title\");\n }\n };\n refSyncs.set(input, sync);\n\n input.addEventListener(\"input\", () => { onCommit(input.value); sync(); });\n input.addEventListener(\"keydown\", (e) => {\n if (e.key !== \"Tab\" || e.shiftKey) return;\n const typed = input.value.trim();\n // Only a GRAMMAR fault is coercible. An undeclared name is not something Tab can\n // fix, and a legal reference in the wrong case is not a fault at all.\n if (typed === \"\" || isValidPropertyName(typed.toLowerCase())) return;\n const coerced = propertyNameify(typed);\n if (!coerced || coerced === input.value) return;\n e.preventDefault();\n input.value = coerced;\n onCommit(coerced);\n sync();\n });\n sync();\n}\n\n/**\n * Re-check every bound reference field inside `host`. Hosts call this when the\n * DECLARATIONS change, since a reference's validity depends on a list it does not\n * own: rename a property and the driver pointing at it is wrong from that moment,\n * with nothing typed into it.\n */\nexport function revalidatePropertyRefs(host: ParentNode): void {\n for (const input of host.querySelectorAll(\"input\")) refSyncs.get(input)?.();\n}\n","// ---------------------------------------------------------------------------\n// The gameId editor: a small anchored popover for setting a thing's address.\n//\n// Patterpad's `id-editor.ts`, lifted into the shell so both apps have the same\n// manners. They did not: Storyletter's accepted anything and let the save\n// quietly rewrite it, Patterpad's refused an illegal address and offered Tab as\n// an opt-in slugify. Patterpad's is the right half of that argument and is what\n// this is - the address is what a host will call the content by, and an app that\n// silently renames it has made a decision that was not its to make.\n//\n// THE SEAM: this knows nothing about what it is addressing. It takes the pinned\n// value, the name-derived fallback to show as a placeholder, and hands back a\n// string to persist (\"\" = go back to deriving one).\n// ---------------------------------------------------------------------------\n\nimport { el } from \"./dom.js\";\nimport { openAnchoredPanel } from \"./anchored.js\";\nimport { gameIdify as defaultSlugify, isValidGameId as defaultValid } from \"./ids.js\";\n\nexport interface GameIdEditorOptions {\n anchor: HTMLElement;\n /** The pinned address, or \"\" when it is being derived. */\n value: string;\n /** What it derives to, shown as the placeholder. */\n derived: string;\n /** Persist. \"\" means \"stop pinning, go back to deriving\". */\n onCommit: (gameId: string) => void;\n /** The panel's title. Both apps say \"Game ID\"; a third may not. */\n title?: string;\n /** Override the rules. Defaults are the shell's, which is what a new app\n * should use; an app whose domain layer owns them can pass its own. */\n slugify?: (text: string) => string;\n validate?: (gameId: string) => boolean;\n /** Where the panel goes, for hosts that anchor it somewhere tight. */\n prefer?: \"left\" | \"below\" | \"centre\";\n /** Chrome the panel must not cover, passed through to the anchored panel: an\n * app with a problems bar along the bottom wants it usable while an address\n * is being edited. Without this the editor is the one panel in a host that\n * can land on top of its own bars. */\n keepClear?: string[];\n}\n\n/**\n * Open it. Returns false when that click TOGGLED the panel shut, which is the\n * anchored panel's contract and worth passing on: a caller that repaints on open\n * needs to know it did not.\n */\nexport function openGameIdEditor(opts: GameIdEditorOptions): boolean {\n const slugify = opts.slugify ?? defaultSlugify;\n const valid = opts.validate ?? defaultValid;\n\n const panel = openAnchoredPanel({\n anchor: opts.anchor, className: \"shell-id-editor\", title: opts.title ?? \"Game ID\", width: 260,\n ...(opts.prefer !== undefined ? { prefer: opts.prefer } : {}),\n ...(opts.keepClear !== undefined ? { keepClear: opts.keepClear } : {}),\n });\n if (!panel) return false;\n\n const input = el(\"input\", \"shell-id-input\");\n input.type = \"text\";\n input.value = opts.value;\n input.placeholder = opts.derived || \"game-id\";\n input.spellcheck = false;\n\n const hint = el(\"div\", \"shell-id-hint\", \"Lower case letters, digits, and hyphens. Leave it empty to derive one from the name.\");\n const actions = el(\"div\", \"shell-id-actions\");\n const reset = el(\"button\", \"shell-id-reset\", \"Reset to auto\");\n const set = el(\"button\", \"shell-id-set\", \"Set\");\n reset.type = \"button\";\n set.type = \"button\";\n actions.append(reset, set);\n panel.body.append(input, hint, actions);\n\n // \"\" is allowed and means reset; anything else has to be a legal address.\n const legal = (): boolean => { const v = input.value.trim(); return v === \"\" || valid(v); };\n const sync = (): void => {\n set.disabled = !legal();\n hint.classList.toggle(\"bad\", !legal());\n };\n const commit = (): void => {\n if (!legal()) return;\n opts.onCommit(input.value.trim());\n panel.close();\n };\n\n input.addEventListener(\"input\", sync);\n input.addEventListener(\"keydown\", (e) => {\n // Stop keys reaching the app underneath: a canvas listening for Delete must\n // not act on one typed into an address.\n e.stopPropagation();\n if (e.key === \"Enter\") { e.preventDefault(); commit(); }\n // The opt-in coercion. Nothing is rewritten unless it is asked for, and when\n // it is, it happens in the field where it can be seen and undone.\n if (e.key === \"Tab\" && input.value.trim() !== \"\") {\n e.preventDefault();\n input.value = slugify(input.value);\n sync();\n }\n });\n set.addEventListener(\"click\", commit);\n reset.addEventListener(\"click\", () => { opts.onCommit(\"\"); panel.close(); });\n\n sync();\n setTimeout(() => input.focus(), 0);\n return true;\n}\n","// ---------------------------------------------------------------------------\n// The version-control surface's pure DOM half: folding a snapshot over the\n// shard key(s) an item stands for, the one badge that item flies, painting\n// those badges onto rows that already exist, and turning a document's editing\n// controls off when somebody else holds its shard.\n//\n// The family's, for the same reason the main half is: it follows from the app\n// SHAPE. Patterpad's #145 grammar, by way of Storyletter's port.\n//\n// Render-FREE by design, and that is load-bearing: a poll repaints badges\n// without rebuilding anything, so a mid-edit document is never disturbed.\n//\n// The one thing an app must supply is WHAT STAYS LIVE in a locked document\n// (`staysLive`): reading a shard somebody else holds must remain fully\n// possible, so navigation, disclosure and view switches keep working while the\n// writing stops - and only the app knows what those look like in its own\n// markup.\n// ---------------------------------------------------------------------------\n\nimport { icon, iconNode, type IconName } from \"./icons.js\";\nimport { el } from \"./dom.js\";\n\n/** One shard's state as the renderer sees it. The app's own DTO will be this\n * shape (it crosses its own bridge); this is what the view needs. */\nexport interface ShardVc {\n key: string;\n writable: boolean;\n lockedBy?: string[];\n outOfDate?: boolean;\n /** WE hold it: still ours to edit. */\n checkedOutByMe?: boolean;\n /** Tracked, with uncommitted local changes. */\n dirty?: boolean;\n /** Not in version control yet. */\n untracked?: boolean;\n}\n\n/** A snapshot, keyed by shard key. Absent = clean, writable, up to date. */\nexport type VcMap = ReadonlyMap<string, ShardVc>;\n\n/** Fold the state of the shard key(s) an item stands for (a box row spans its\n * box + tags + hands shards), most actionable winning: any holder locks it,\n * any stale shard makes it stale, any read-only shard makes it read-only. */\nexport function foldVc(shards: VcMap, keys: string | undefined): ShardVc | undefined {\n if (!keys) return undefined;\n let out: ShardVc | undefined;\n for (const key of keys.split(\" \")) {\n const s = shards.get(key);\n if (!s) continue;\n out ??= { key, writable: true };\n if (!s.writable) out.writable = false;\n if (s.lockedBy?.length) out.lockedBy = [...new Set([...(out.lockedBy ?? []), ...s.lockedBy])];\n if (s.outOfDate) out.outOfDate = true;\n if (s.checkedOutByMe) out.checkedOutByMe = true;\n if (s.dirty) out.dirty = true;\n if (s.untracked) out.untracked = true;\n }\n return out;\n}\n\n/** What a row flies: the word to draw (`name`), the class that colours it,\n * and the rollover. `glyph` is the deprecated typed character for a caller\n * still setting text; it goes when `icon` does. */\nexport interface VcBadge {\n name: IconName;\n /** @deprecated Draw `name` with `iconNode` instead. */\n glyph: string;\n cls: string;\n title: string;\n}\n\n/** The one badge an item flies, by priority, or null when there is nothing to\n * say. Drawn monochrome (never colour emoji), so each inherits its themed\n * colour and reads the same in Linen and Baize. */\nexport function vcBadgeFor(s: ShardVc | undefined): VcBadge | null {\n const badge = (name: IconName, cls: string, title: string): VcBadge => ({ name, glyph: icon[name as keyof typeof icon] ?? \"\", cls, title });\n if (s?.lockedBy?.length) return badge(\"locked\", \"vc-locked\", `Locked by ${s.lockedBy.join(\", \")}`);\n if (s?.outOfDate) return badge(\"down\", \"vc-stale\", \"Out of date. A newer version is on the server.\");\n // The three states of a file that is YOURS, most actionable first. Ordered so\n // the badge answers \"what would I do about this?\" rather than describing the\n // file: a checkout you are holding matters more than the edits inside it, and\n // both matter more than a file the VCS has never seen.\n if (s?.checkedOutByMe) return badge(\"checkedOut\", \"vc-mine\", \"Checked out by you\");\n if (s?.dirty) return badge(\"modified\", \"vc-dirty\", \"Modified. Local changes aren't committed yet.\");\n if (s?.untracked) return badge(\"untracked\", \"vc-new\", \"New. Not in version control yet.\");\n // Read-only on disk with NO other holder is still editable: the save checks\n // it out. Muted, and last, because under a lock-based VCS this is the\n // resting state of everything the author has not touched yet.\n if (s && !s.writable) return badge(\"readOnly\", \"vc-frozen\", \"Read-only on disk. Saving checks it out.\");\n return null;\n}\n\n/** Repaint the badge on every item under `root` that names a shard (its\n * `data-vc`). In place: no re-render, so nothing loses focus or scroll. */\nexport function paintVcBadges(root: ParentNode, shards: VcMap): void {\n root.querySelectorAll<HTMLElement>(\"[data-vc]\").forEach((host) => {\n host.querySelector(\":scope > .vc-badge\")?.remove();\n const badge = vcBadgeFor(foldVc(shards, host.dataset[\"vc\"]));\n if (!badge) return;\n // `tip` carries the accessible name too, so no separate aria-label. 12px:\n // the badge sits beside a row title at 0.78rem and must not outweigh it.\n const span = el(\"span\", { className: `vc-badge ${badge.cls}`, tip: badge.title }, iconNode(badge.name, 12));\n host.append(span);\n });\n}\n\ntype Disableable = HTMLButtonElement | HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement;\n\n/** Turn a region's editing controls off - or back on, but only the ones WE\n * turned off, so a control disabled for its own reasons (the first card's\n * \"previous\", a redraw-turns box on \"always\") stays disabled. */\nexport function lockControls(host: HTMLElement, off: boolean, staysLive: string): void {\n host.classList.toggle(\"vc-readonly\", off);\n if (off) {\n host.querySelectorAll<Disableable>(\"input, textarea, select, button\").forEach((c) => {\n if (c.disabled || (staysLive !== \"\" && c.matches(staysLive))) return;\n c.disabled = true;\n c.classList.add(\"vc-off\");\n });\n } else {\n host.querySelectorAll<Disableable>(\".vc-off\").forEach((c) => { c.disabled = false; c.classList.remove(\"vc-off\"); });\n }\n}\n\n/** The notice a locked document opens with: who holds it, and why nothing types. */\nexport function lockNotice(holders: string[]): HTMLElement {\n return el(\"div\", { className: \"vc-lock\" },\n el(\"span\", { className: \"vc-lock-glyph\" }, iconNode(\"locked\")),\n el(\"span\", { text: `Locked by ${holders.join(\", \")}. Read-only until they release it.` }));\n}\n","// ---------------------------------------------------------------------------\n// \"Who is working here?\" - Patterpad's first-run identity, as the family's.\n//\n// `{ name, email? }`, asked ONCE at first startup and skippable, editable later\n// from User Information… in the menu. It belongs to the person at the keyboard,\n// never to the project, which is why the app stores it in ITS OWN state and not\n// in a shard: a project carrying a name would hand it to whoever opened the file\n// next.\n//\n// The shell asks and returns; PERSISTING is the app's, because each app has its\n// own state file. `suggested` is there for the day simple-vc-lib can say who the\n// version control thinks you are (see patterkit from-storylets/vc-current-user),\n// so the box opens with a sensible answer rather than empty.\n//\n// Two occasions, one dialog (ui-review-2026-09, Patterpad adoption step 5): the\n// first run is a welcome, the menu item is an edit, and the title and the\n// primary button say which. Without a `mode` it is the plain ask it always was.\n// ---------------------------------------------------------------------------\n\nimport { el, labelled } from \"./dom.js\";\nimport { dialogFrame } from \"./dialog.js\";\n\nexport interface Identity { name: string; email?: string }\n\nexport interface IdentityOptions {\n /** What it already says, if anything. */\n current?: Identity;\n /** A name to offer when there is none: the VCS's, one day. */\n suggested?: Identity;\n /**\n * `\"welcome\"` is the first run (\"Welcome to <appName>\", Continue); `\"edit\"`\n * is the menu item (\"User information\", Save). Absent, the title is the\n * shell's \"Who is working here?\" and the button is Save.\n */\n mode?: \"welcome\" | \"edit\";\n /** Names the app in the welcome title. Without it the title is \"Welcome\". */\n appName?: string;\n /**\n * By default a skip resolves `undefined` and the app asks again next launch.\n * With this on, a skip resolves `{ name: \"\" }`: the app stores the blank and\n * never asks again (Patterpad's first run, where main fills in a default).\n * A Save with an empty name counts as a skip either way.\n */\n neverAskAgainOnSkip?: boolean;\n}\n\n/** Ask, and record the answer. Resolves when the dialog closes, either way. */\nexport function askIdentity(opts: IdentityOptions = {}): Promise<Identity | undefined> {\n return new Promise<Identity | undefined>((resolve) => {\n const seed = opts.current ?? opts.suggested;\n const name = el(\"input\", \"field shell-ident-input\") as HTMLInputElement;\n name.placeholder = \"Your name\";\n name.value = seed?.name ?? \"\";\n const email = el(\"input\", \"field shell-ident-input\") as HTMLInputElement;\n email.placeholder = \"Optional\";\n email.type = \"email\";\n email.value = seed?.email ?? \"\";\n\n const skip = el(\"button\", \"btn shell-ident-btn\", \"Skip\");\n const save = el(\"button\", \"btn primary shell-ident-btn\", opts.mode === \"welcome\" ? \"Continue\" : \"Save\");\n skip.type = \"button\"; save.type = \"button\";\n\n let done = false;\n const finish = (keep: boolean): void => {\n if (done) return;\n done = true;\n const typed = name.value.trim();\n const value = email.value.trim();\n const answer: Identity | undefined = keep && typed !== \"\"\n ? (value === \"\" ? { name: typed } : { name: typed, email: value })\n : (opts.neverAskAgainOnSkip === true ? { name: \"\" } : undefined);\n resolve(answer);\n frame.close();\n };\n\n // The frame owns the panel, the scrim, Escape and the exit motion; this\n // owns the two fields and the two answers.\n const frame = dialogFrame({\n title: titleFor(opts),\n sub: subFor(opts),\n className: \"shell-ident\",\n onClose: () => finish(false), // Escape, or closed by someone else: a skip\n });\n // Captions above the fields, not placeholders alone: a placeholder is gone\n // the moment there is a value in the box, and the VCS's suggestion is one.\n frame.body.append(el(\"div\", \"shell-ident-fields\", labelled(\"Name\", name), labelled(\"Email\", email)));\n frame.actions.append(skip, save);\n\n skip.addEventListener(\"click\", () => finish(false));\n save.addEventListener(\"click\", () => finish(true));\n // Enter saves, Escape skips: the two answers the dialog has.\n name.addEventListener(\"keydown\", (e) => { if (e.key === \"Enter\") finish(true); });\n email.addEventListener(\"keydown\", (e) => { if (e.key === \"Enter\") finish(true); });\n\n frame.open();\n name.focus();\n });\n}\n\nfunction titleFor(opts: IdentityOptions): string {\n if (opts.mode === \"welcome\") return opts.appName ? `Welcome to ${opts.appName}` : \"Welcome\";\n if (opts.mode === \"edit\") return \"User information\";\n return \"Who is working here?\";\n}\n\n/** The one sub line, minus its last sentence when this IS the later change. */\nfunction subFor(opts: IdentityOptions): string {\n const why = \"Your name goes on the comments you write. It's kept in this app, not in the project.\";\n return opts.mode === \"edit\" ? why : `${why} You can change it later.`;\n}\n","// ---------------------------------------------------------------------------\n// The documentation-notes editor: Patterpad's, as the family's (Patter spec 18).\n//\n// Documentation states the reason; comments are the conversation. A note says\n// why a card is here, who it is for, what a translator needs to know. It has no\n// author, no timestamp, and nobody replies to it.\n//\n// A MODAL, and that is a decision somebody already paid for: Patterpad tried an\n// anchored popover first and removed it as too cramped. Notes are prose, and\n// prose needs room.\n//\n// One text area PER CLASS, each non-blank line becoming a note of that class.\n// The alternative - a list of lines each with its own class dropdown - is more\n// granular and, as their proposal puts it, fiddlier: you would fill in a form to\n// write a sentence.\n//\n// THE SEAM: this knows nothing about what a note is attached to. The app hands\n// it the notes that apply, the ancestors they came from and the classes on\n// offer, and takes back a list. Whether the levels are box -> deck -> card or\n// scene -> block -> line never reaches here.\n//\n// Showing INHERITED notes read-only is Storyletter's addition, and it belongs in\n// the family: Patterpad deferred it because its stacked inspector already shows\n// each ancestor's Notes row, but an app whose editor has no such stack must show\n// them somewhere or an author will write the box's note again on the card.\n// ---------------------------------------------------------------------------\n\nimport { el } from \"./dom.js\";\nimport { dialogFrame } from \"./dialog.js\";\n\n/** One line of documentation. `type` names its class; absent = editor-only. */\nexport interface DocLine { type?: string; text: string }\n\n/** What applies to one thing: its own notes, and the ancestors' that reach it.\n * Inherited notes are READ-ONLY - they are edited where they live, which is\n * what stops a note being copied down and then disagreeing with itself. */\nexport interface Notes {\n own: DocLine[];\n inherited: { id: string; label: string; lines: DocLine[] }[];\n /** The classes this app offers, in the order they should appear. */\n classes: string[];\n}\n\nconst EDITOR_ONLY = \"\";\nconst UNTYPED_KEY = \"__untyped\";\n\n/** The classes the family already has words for; anything else is Title Cased,\n * so a studio can add one without touching this. Patterpad's labels. */\nconst CLASS_LABEL: Record<string, string> = {\n everyone: \"Everyone\", writing: \"Writing\", vo: \"Voice (VO)\", loc: \"Localisers\",\n};\nconst label = (cls: string): string =>\n cls === EDITOR_ONLY ? \"Note (editor-only)\"\n : CLASS_LABEL[cls] ?? (cls[0]!.toUpperCase() + cls.slice(1));\n\nconst PLACEHOLDER: Record<string, string> = {\n vo: \"Direction for the voice actor or director\",\n loc: \"Context for translators\",\n};\nconst placeholder = (cls: string): string =>\n cls === EDITOR_ONLY ? \"An internal note, never exported\"\n : PLACEHOLDER[cls] ?? \"Why this is here\";\n\nexport interface NotesEditorOptions {\n /** What this is about, for the dialog's title (\"Notes: Arrive at the gate\"). */\n subject: string;\n notes: Notes;\n /** Commit. Called once, on close, and only when something changed. */\n save: (lines: DocLine[]) => void;\n}\n\n/** Open the notes modal. Resolves when it closes. */\nexport function openNotesEditor(opts: NotesEditorOptions): void {\n const { notes } = opts;\n\n // Seed one text area per class that already has notes; a fresh thing gets the\n // first class in the vocabulary, so the commonest act (write a note) is typing\n // rather than choosing.\n const seed = new Map<string, string>();\n for (const line of notes.own) {\n const key = line.type ?? EDITOR_ONLY;\n seed.set(key, seed.has(key) ? `${seed.get(key)!}\\n${line.text}` : line.text);\n }\n const shown: string[] = [...seed.keys()];\n if (shown.length === 0) shown.push(notes.classes[0] ?? EDITOR_ONLY);\n const areas = new Map<string, HTMLTextAreaElement>();\n\n const value = (): DocLine[] => {\n const out: DocLine[] = [];\n for (const cls of shown) {\n const area = areas.get(cls);\n if (!area) continue;\n for (const raw of area.value.split(\"\\n\")) {\n const text = raw.trim();\n if (text !== \"\") out.push(cls === EDITOR_ONLY ? { text } : { type: cls, text });\n }\n }\n return out;\n };\n\n const body = el(\"div\", \"shell-notes-body\");\n\n const render = (): void => {\n body.replaceChildren();\n\n // The inherited context first, because it is what an author needs BEFORE\n // deciding whether to write anything: outermost first, muted, and labelled\n // with where it lives so the answer to \"why can I not edit this\" is on\n // screen.\n if (notes.inherited.length > 0) {\n const from = el(\"div\", { className: \"shell-notes-inherited\" },\n el(\"div\", \"shell-notes-caption\", \"Inherited\"));\n for (const level of notes.inherited) {\n from.append(el(\"div\", { className: \"shell-notes-level\" },\n el(\"span\", \"shell-notes-level-label\", level.label),\n ...level.lines.map((line) => el(\"div\", { className: \"shell-notes-line\" },\n ...(line.type !== undefined && line.type !== \"everyone\"\n ? [el(\"span\", \"shell-notes-cls\", label(line.type))] : []),\n el(\"span\", \"\", line.text))),\n ));\n }\n body.append(from);\n }\n\n for (const cls of shown) {\n const block = el(\"div\", { className: \"shell-notes-class\" },\n el(\"label\", \"shell-notes-caption\", label(cls)));\n const area = el(\"textarea\", \"field shell-notes-text\");\n area.value = areas.get(cls)?.value ?? seed.get(cls) ?? \"\";\n area.rows = 4;\n area.placeholder = placeholder(cls);\n area.spellcheck = true;\n areas.set(cls, area);\n block.append(area);\n body.append(block);\n }\n\n // One line per note, said once where somebody is about to type.\n body.append(el(\"p\", \"shell-notes-hint\", \"One note per line.\"));\n\n const remaining = [...notes.classes, EDITOR_ONLY].filter((c) => !shown.includes(c));\n if (remaining.length > 0) {\n const add = el(\"select\", \"shell-notes-add\");\n add.append(new Option(\"Add a note for…\", \"\"));\n for (const cls of remaining) add.append(new Option(label(cls), cls === EDITOR_ONLY ? UNTYPED_KEY : cls));\n add.addEventListener(\"change\", () => {\n if (add.value === \"\") return;\n const cls = add.value === UNTYPED_KEY ? EDITOR_ONLY : add.value;\n shown.push(cls);\n render();\n areas.get(cls)?.focus();\n });\n body.append(add);\n }\n };\n render();\n\n const done = el(\"button\", \"btn primary shell-notes-btn\", \"Done\");\n done.type = \"button\";\n\n const before = JSON.stringify(notes.own);\n // Done and Escape both end up here (the frame's onClose runs for every way\n // out), so the guard is what stops one gesture saving twice.\n let closed = false;\n const commit = (): void => {\n if (closed) return;\n closed = true;\n const next = value();\n // Only when something changed: opening a note to read it must not cost an\n // undo step, and must not touch the file (or the version control status).\n if (JSON.stringify(next) !== before) opts.save(next);\n };\n // Escape closes the dialog by itself, and commits: this editor has no Cancel,\n // because a note is prose and losing a paragraph to a stray key is worse than\n // an unwanted note somebody can delete.\n const frame = dialogFrame({ title: `Notes: ${opts.subject}`, className: \"shell-notes\", onClose: commit });\n frame.body.append(body);\n frame.actions.append(done);\n done.addEventListener(\"click\", () => { commit(); frame.close(); });\n\n frame.open();\n areas.get(shown[0] ?? EDITOR_ONLY)?.focus();\n}\n","// ---------------------------------------------------------------------------\n// The comment thread popover: Patterpad's (#148), as the family's.\n//\n// Comments are the conversation; documentation states the reason. Anchored\n// rather than modal, which is the deliberate contrast with the notes editor: a\n// comment is had BESIDE the thing, and a modal covering the card would hide\n// what is being discussed.\n//\n// Everything here that looks like a small decision is one somebody already\n// made: author and timestamp on every message (a comment without a \"who\" is an\n// anonymous complaint); Enter posts and closes while Shift+Enter is a newline;\n// the button reads Comment on a new thread and Reply on an old one; focus goes\n// to the composer ONLY for a new thread, because opening an existing one to\n// read must not yank the cursor out of the work; and a thread does not exist\n// until its first message is posted, so a composer somebody thought better of\n// leaves nothing behind.\n//\n// THE SEAM: an anchor is an opaque id. What it points at - a card, a beat, a\n// span of characters - is the app's, and so is where the threads are stored.\n// This takes a list and gives back \"post this\" and \"resolve that\".\n// ---------------------------------------------------------------------------\n\nimport { el } from \"./dom.js\";\nimport { iconNode } from \"./icons.js\";\nimport { openAnchoredPanel } from \"./anchored.js\";\n\n/** One message. The author is a NAME stamped at posting time, not a reference:\n * people leave projects and their words stay. */\nexport interface CommentMessage {\n author: string; ts: string; body: string;\n /** A TOMBSTONE: the words are gone, the turn in the conversation is not.\n * Deleting a reply out of a thread would renumber the argument around it, so\n * what is left says who spoke and when and that they withdrew it. The body is\n * emptied on the way out, so \"deleted\" means deleted from the file too. */\n deleted?: boolean;\n}\n\n/** A thread, anchored to the id of whatever it is about. */\nexport interface Comment {\n id: string;\n anchor: string;\n resolved?: boolean;\n messages: CommentMessage[];\n}\n\nconst stamp = (ts: string): string => {\n const when = new Date(ts);\n if (Number.isNaN(when.getTime())) return ts;\n return when.toLocaleString(undefined, { dateStyle: \"medium\", timeStyle: \"short\" });\n};\n\n/** A preview of a thread, for the list: its first message, shortened. The first\n * message that still SAYS something - a thread whose opener was withdrawn is\n * previewed by whatever carried on, not by its tombstone. */\nconst gist = (thread: Comment): string => {\n const first = thread.messages.find((m) => m.deleted !== true)?.body ?? \"\";\n return first.length > 60 ? `${first.slice(0, 57)}…` : first;\n};\n\nexport interface CommentsOptions {\n anchor: HTMLElement;\n /** What is being discussed, for the panel's title. */\n subject: string;\n /** Every thread on this thing, resolved ones included. */\n threads: Comment[];\n /** Review ▸ Show Resolved Comments. */\n showResolved: boolean;\n /** A fresh thread id, minted by the caller so main never has to. */\n newThreadId: () => string;\n post: (threadId: string, body: string) => void;\n setResolved: (threadId: string, resolved: boolean) => void;\n /**\n * Withdraw one message. Absent = the host does not offer deletion.\n *\n * By INDEX, because a message has no id of its own and giving every message\n * one would be a format change to every stored thread for the sake of one\n * verb. The index is read off the list the reader is looking at, and these\n * files are edited by one person at a time with a VCS underneath.\n *\n * The host decides what deleting MEANS: the agreed rule is that the message\n * becomes a tombstone, and the whole thread goes when nothing readable would\n * be left (which covers the common case of withdrawing a comment nobody had\n * replied to).\n */\n deleteMessage?: (threadId: string, index: number) => void;\n /** Where the panel sits: \"centre\" for a point on a canvas (see anchored.ts). */\n prefer?: \"left\" | \"below\" | \"centre\";\n /**\n * Chrome the panel must not cover. Defaults to `[\".problembar\"]`, which was\n * hardcoded here and should not have been: one app's class name in shared\n * code, and it misses any OTHER bar a host has. A second app arrived with two.\n */\n keepClear?: string[];\n /**\n * The text a thread is pinned to, shown above it as a quotation.\n *\n * A callback rather than a field on `Comment`, because resolving an anchor is\n * the APP's half of the seam and this is only that resolution rendered: an app\n * that pins threads to a span of prose can quote it, one that pins them to a\n * whole card has nothing to quote and passes nothing. Keeping it out of the\n * thread type also means no change to what is written to disk, which matters\n * for files living in version control.\n *\n * Return undefined (or \"\") for a thread with no quotable anchor.\n */\n quoteFor?: (thread: Comment) => string | undefined;\n}\n\nexport function openComments(opts: CommentsOptions): void {\n const visible = opts.threads.filter((t) => opts.showResolved || t.resolved !== true);\n const panel = openAnchoredPanel({\n anchor: opts.anchor, className: \"comments\", title: \"Comments\", width: 320,\n // Below its button (the topline), unlike Patterpad's inspector rows which\n // want it to the left; and never over the problems bar, which an author may\n // be stepping through while reading the thread.\n prefer: opts.prefer ?? \"below\",\n keepClear: opts.keepClear ?? [\".problembar\"],\n });\n if (!panel) return; // the same anchor again: that click closed it\n const { body, close } = panel;\n\n // Which thread is on screen. A brand-new one until it is posted: it exists\n // only here, which is why nothing is written when the panel closes unposted.\n let open: Comment | undefined = visible.length === 1 ? visible[0] : undefined;\n let composing = visible.length === 0;\n\n const render = (): void => {\n body.replaceChildren();\n\n if (!composing && open === undefined) {\n // More than one: pick.\n for (const thread of visible) {\n const row = el(\"button\", { className: `shell-cmt-row${thread.resolved === true ? \" resolved\" : \"\"}` },\n el(\"span\", { className: \"shell-cmt-row-author\", text: thread.messages[0]?.author ?? \"Someone\" }),\n el(\"span\", { className: \"shell-cmt-row-gist\", text: gist(thread) }),\n ...(thread.messages.length > 1\n ? [el(\"span\", { className: \"shell-cmt-row-count\", text: `${thread.messages.length}` })] : []),\n );\n row.addEventListener(\"click\", () => { open = thread; render(); });\n body.append(row);\n }\n const fresh = el(\"button\", { className: \"shell-cmt-new\", text: \"New comment\" });\n fresh.addEventListener(\"click\", () => { open = undefined; composing = true; render(); });\n body.append(fresh);\n return;\n }\n\n const thread = open;\n if (thread) {\n // The span this thread is pinned to, quoted above it. Without it a comment\n // on a phrase reads as a comment on the whole thing, and the reader has to\n // remember what was selected.\n const quote = opts.quoteFor?.(thread);\n if (quote !== undefined && quote !== \"\") {\n body.append(el(\"blockquote\", { className: \"shell-cmt-quote\", text: quote }));\n }\n const list = el(\"div\", { className: `shell-cmt-list${thread.resolved === true ? \" resolved\" : \"\"}` });\n thread.messages.forEach((message, index) => {\n const head = el(\"div\", { className: \"shell-cmt-msg-head\" },\n el(\"span\", { className: \"shell-cmt-author\", text: message.author === \"\" ? \"Someone\" : message.author }),\n el(\"span\", { className: \"shell-cmt-ts\", text: stamp(message.ts) }));\n // Rollover-revealed, at the end of the head: the family's grip grammar,\n // and a delete that is always visible invites the accident it is.\n // Nothing is offered on a tombstone: there is nothing left to withdraw.\n if (opts.deleteMessage && message.deleted !== true) {\n const bin = el(\"button\", { className: \"shell-cmt-del\" }, iconNode(\"close\", 12));\n bin.dataset.tip = \"Delete this comment\";\n bin.setAttribute(\"aria-label\", \"Delete this comment\");\n bin.addEventListener(\"click\", () => opts.deleteMessage?.(thread.id, index));\n head.append(bin);\n }\n list.append(el(\"div\", { className: `shell-cmt-msg${message.deleted === true ? \" gone\" : \"\"}` },\n head,\n el(\"div\", { className: \"shell-cmt-body\", text: message.deleted === true ? \"Comment deleted\" : message.body })));\n });\n body.append(list);\n }\n\n const input = el(\"textarea\", { className: \"shell-cmt-input\" });\n input.rows = 2;\n input.placeholder = thread ? \"Reply…\" : \"Comment…\";\n input.addEventListener(\"keydown\", (e) => {\n e.stopPropagation();\n if (e.key !== \"Enter\" || e.shiftKey) return;\n e.preventDefault();\n submit(true);\n });\n body.append(input);\n\n const submit = (andClose: boolean): void => {\n const text = input.value.trim();\n if (text === \"\") return;\n const id = thread?.id ?? opts.newThreadId();\n opts.post(id, text);\n if (andClose) close(); else { input.value = \"\"; }\n };\n\n const actions = el(\"div\", { className: \"shell-cmt-actions\" });\n const post = el(\"button\", { className: \"shell-cmt-btn primary\", text: thread ? \"Reply\" : \"Comment\" });\n post.addEventListener(\"click\", () => submit(false));\n actions.append(post);\n\n if (thread) {\n const resolved = thread.resolved === true;\n const toggle = el(\"button\", { className: \"shell-cmt-btn\", text: resolved ? \"Reopen\" : \"Mark complete\" });\n toggle.addEventListener(\"click\", () => {\n opts.setResolved(thread.id, !resolved);\n // A resolved thread hides, so there is nothing left to look at.\n if (!resolved) close(); else render();\n });\n actions.append(toggle);\n }\n body.append(actions);\n\n // Only for a new thread: reading an old one must not steal the cursor.\n if (!thread) input.focus();\n };\n render();\n}\n","// ---------------------------------------------------------------------------\n// The long-job kit (renderer): the progress strip the main-side JobHost feeds.\n// A determinate bar, a count, elapsed and estimated remaining, and Cancel.\n//\n// A STRIP, NOT A MODAL. The window that started the job is the one that shows\n// it, and the rest of the app stays usable: these are tool windows, and taking\n// the whole editor hostage while a sweep runs was the old system's mistake.\n// The strip is hidden until a job starts and hides itself when one ends.\n//\n// TWO MODES, ONE STRIP. A job that knows its size (a coverage sweep: N runs)\n// gets the determinate bar, the count and the time readout. A job that does\n// not (a publish, a pull, a pack: one write of unknown length) gets an\n// INDETERMINATE band that sweeps the bar, no count, and the elapsed time\n// alone. The host's progress message already says which: `total` 0 is \"no\n// idea yet\" (job.ts), so the strip follows the data and flips to the\n// determinate bar the moment a total arrives. A host that knows its jobs\n// never count pins the mode with `indeterminate: true`; a host whose jobs\n// cannot be stopped mid-write drops Cancel with `cancellable: false` (or by\n// passing no `onCancel` at all).\n//\n// The time readout only appears once there is enough evidence for it. An ETA\n// that swings wildly for the first second reads as a broken app, so the\n// estimate waits until a second of work and a tenth of the job are behind it.\n// ---------------------------------------------------------------------------\n\nimport { el } from \"./dom.js\";\n\n/** Per-run overrides for a strip that serves several kinds of job (the main\n * window's: a countable export beside an uncountable pull). Each begin()\n * starts from the mount options and applies these on top. */\nexport interface JobBeginOptions {\n /** Pin the band regardless of what the job reports. */\n indeterminate?: boolean;\n /** Show Cancel for this run. */\n cancellable?: boolean;\n}\n\nexport interface JobProgressView {\n /** The strip; mount it where the job belongs. */\n readonly element: HTMLElement;\n /** Show the strip, reset to zero, and (optionally) name what is running. */\n begin(label?: string, run?: JobBeginOptions): void;\n /** Feed it a progress message from the main-side host. A `total` of 0\n * (the host's \"no idea yet\") draws the indeterminate band; the first\n * positive total flips the strip to the determinate bar. */\n update(done: number, total: number, elapsedMs: number): void;\n /** Hide the strip (the job finished, failed, or was cancelled). */\n end(): void;\n readonly visible: boolean;\n /** True while the strip is drawing the band rather than the bar. */\n readonly indeterminate: boolean;\n}\n\nexport interface JobProgressOptions {\n /** Called when Cancel is clicked. The button disables itself and says so;\n * the job stops at its next yield, and the host then calls end(). Omit it\n * for a strip whose jobs cannot be stopped: Cancel is then not drawn. */\n onCancel?: () => void;\n /** The word for the units, for the count readout (default \"runs\"). */\n units?: string;\n /** Always draw the band and never the count, whatever the job reports.\n * Default: follow the data (band until a total arrives). */\n indeterminate?: boolean;\n /** Draw Cancel. Default: only when `onCancel` was given. */\n cancellable?: boolean;\n}\n\nconst clock = (ms: number): string => {\n const total = Math.round(ms / 1000);\n const m = Math.floor(total / 60);\n const s = total % 60;\n return m > 0 ? `${m}m ${String(s).padStart(2, \"0\")}s` : `${s}s`;\n};\n\n/** Enough of the job done, and enough time passed, for a remaining-time\n * estimate to be worth showing rather than misleading. */\nconst estimable = (done: number, total: number, elapsedMs: number): boolean =>\n done > 0 && total > 0 && elapsedMs > 1000 && done / total > 0.1;\n\nexport function mountJobProgress(host: HTMLElement, opts: JobProgressOptions): JobProgressView {\n const units = opts.units ?? \"runs\";\n const pinned = opts.indeterminate === true;\n const cancellableByDefault = opts.cancellable ?? (opts.onCancel !== undefined);\n\n const fill = el(\"i\", { className: \"job-fill\" });\n const bar = el(\"div\", { className: \"job-bar\" }, fill);\n bar.setAttribute(\"role\", \"progressbar\");\n bar.setAttribute(\"aria-valuemin\", \"0\");\n bar.setAttribute(\"aria-valuemax\", \"100\");\n const what = el(\"span\", { className: \"job-label\" });\n const count = el(\"span\", { className: \"job-count\" });\n const time = el(\"span\", { className: \"job-time\" });\n const cancel = el(\"button\", { className: \"job-cancel\", text: \"Cancel\" });\n cancel.type = \"button\";\n\n const strip = el(\"div\", { className: \"job-strip\" }, what, bar, count, time, cancel);\n strip.hidden = true;\n host.append(strip);\n\n // The run's settings: reset by begin(), read by update().\n let runPinned = pinned;\n let indeterminate = false;\n\n /** Draw the band (no count, no value) or the bar (both). Every write is\n * idempotent, so update() may call it each time and only a flip shows. */\n const setMode = (band: boolean): void => {\n indeterminate = band;\n strip.classList.toggle(\"indeterminate\", band);\n count.hidden = band;\n if (band) {\n // The band's width and motion are the stylesheet's: clear the inline\n // width the bar set, or it wins over the class.\n fill.style.width = \"\";\n bar.removeAttribute(\"aria-valuenow\");\n }\n };\n\n const view: JobProgressView = {\n element: strip,\n get visible() { return !strip.hidden; },\n get indeterminate() { return indeterminate; },\n\n begin(label?: string, run?: JobBeginOptions) {\n runPinned = run?.indeterminate ?? pinned;\n const cancellable = run?.cancellable ?? cancellableByDefault;\n what.textContent = label ?? \"Running…\";\n count.textContent = \"\";\n time.textContent = \"\";\n cancel.hidden = !cancellable;\n cancel.disabled = false;\n cancel.textContent = \"Cancel\";\n // Every run opens on the band: nothing is known until the first report.\n setMode(true);\n strip.hidden = false;\n },\n\n update(done: number, total: number, elapsedMs: number) {\n if (strip.hidden) strip.hidden = false;\n const band = runPinned || !(total > 0);\n setMode(band);\n if (!band) {\n const pct = Math.min(100, (done / total) * 100);\n fill.style.width = `${pct}%`;\n bar.setAttribute(\"aria-valuenow\", String(Math.round(pct)));\n count.textContent = `${done} / ${total} ${units}`.trimEnd();\n }\n if (!band && estimable(done, total, elapsedMs)) {\n const remaining = (elapsedMs / done) * (total - done);\n time.textContent = `${clock(elapsedMs)} elapsed, about ${clock(remaining)} left`;\n } else {\n time.textContent = clock(elapsedMs);\n }\n },\n\n end() {\n strip.hidden = true;\n },\n };\n\n cancel.addEventListener(\"click\", () => {\n // Cancellation lands at the job's next yield, which may be a moment away:\n // say so, rather than leaving a dead-looking button.\n cancel.disabled = true;\n cancel.textContent = \"Stopping…\";\n opts.onCancel?.();\n });\n\n // Before the first begin(): the band, and Cancel per the mount options, so\n // a host that only ever calls update() (the strip appearing on the first\n // progress message) still gets a coherent strip.\n cancel.hidden = !cancellableByDefault;\n setMode(true);\n\n return view;\n}\n","// ---------------------------------------------------------------------------\n// The long-job kit (main process): run a piece of work that takes long enough\n// to need a progress bar and a Cancel button, without freezing the app.\n//\n// The shape every editor in the family needs: coverage sweeps, big exports,\n// corpus runs. One kind of job at a time, progress reported to the windows\n// that asked for it, cancellation honoured at the next yield point, and a\n// partial result when the work can offer one.\n//\n// COOPERATIVE, NOT PARALLEL. The work still runs in the main process; it just\n// stops hogging it. `ctx.step()` is both the progress report and the yield:\n// the work hands the event loop back every few milliseconds, so IPC keeps\n// flowing, the renderer keeps painting, and Cancel is heard. The alternative\n// (a utilityProcess or a worker) buys true parallelism at the cost of\n// serialising the job's inputs and outputs across a process boundary, and a\n// second entry point per app. Reach for that only when the work is heavy\n// enough that a responsive main process is not enough.\n//\n// Electron is an OPTIONAL peer here: nothing in this file imports it. The host\n// supplies `send`, so the kit is testable headlessly and usable from any\n// message transport.\n// ---------------------------------------------------------------------------\n\n/** The channel a host should send progress on, and the shape it carries. */\nexport const JOB_PROGRESS = \"job:progress\";\n\nexport interface JobProgress {\n /** Which job this is about (\"coverage\"), so one listener can serve many. */\n kind: string;\n /** Units finished and expected. `total` 0 means \"no idea yet\". */\n done: number;\n total: number;\n /** Milliseconds since the job started, for elapsed + estimated remaining. */\n elapsedMs: number;\n}\n\n/** What the work is given: a cancellation flag and the one call that both\n * reports progress and yields. */\nexport interface JobContext {\n /** True once someone has cancelled. Check it to bail out early, or to\n * return a partial result rather than nothing. */\n readonly cancelled: boolean;\n /** Report progress and, when enough time has passed, hand the event loop\n * back. Await it: that await IS the yield. */\n step(done: number, total: number): Promise<void>;\n}\n\nexport type JobResult<T> =\n | { ok: true; value: T }\n | { cancelled: true; value?: T }\n | { error: string };\n\nexport interface JobHost {\n /** Run `work` as the job of this kind. Rejects a second start of the same\n * kind while one is in flight (the caller should have disabled the button;\n * this is the backstop). */\n start<T>(kind: string, work: (ctx: JobContext) => Promise<T>): Promise<JobResult<T>>;\n /** Ask the running job of this kind to stop. It stops at its next step(). */\n cancel(kind: string): void;\n running(kind: string): boolean;\n}\n\nexport interface JobHostOptions {\n /** Deliver a progress message to whoever is watching (typically\n * `window.webContents.send(JOB_PROGRESS, payload)` for each live window). */\n send: (channel: string, payload: JobProgress) => void;\n /** How long the work may hold the event loop between yields (default 16ms,\n * about one frame). Smaller is smoother and slower. */\n sliceMs?: number;\n /** How often a progress message may be sent (default 100ms). Progress is\n * for a human to read; flooding the channel just costs IPC. */\n reportMs?: number;\n /** Injectable clock + yield, for tests. */\n now?: () => number;\n yieldToLoop?: () => Promise<void>;\n}\n\nconst defaultYield = (): Promise<void> =>\n new Promise((resolve) => { setTimeout(resolve, 0); });\n\nexport function createJobHost(opts: JobHostOptions): JobHost {\n const now = opts.now ?? (() => Date.now());\n const handOver = opts.yieldToLoop ?? defaultYield;\n const sliceMs = opts.sliceMs ?? 16;\n const reportMs = opts.reportMs ?? 100;\n const live = new Map<string, { cancelled: boolean }>();\n\n return {\n running: (kind) => live.has(kind),\n\n cancel(kind) {\n const job = live.get(kind);\n if (job) job.cancelled = true;\n },\n\n async start<T>(kind: string, work: (ctx: JobContext) => Promise<T>): Promise<JobResult<T>> {\n if (live.has(kind)) return { error: `a ${kind} job is already running` };\n const job = { cancelled: false };\n live.set(kind, job);\n\n const started = now();\n let lastYield = started;\n // A flag, not a timestamp sentinel: on a clock that can legitimately\n // read 0, \"never reported yet\" and \"reported at 0\" must not be the\n // same state. The first step always reports, so the bar moves at once.\n let reported = false;\n let lastReport = 0;\n\n const ctx: JobContext = {\n get cancelled() { return job.cancelled; },\n async step(done: number, total: number): Promise<void> {\n const at = now();\n if (!reported || at - lastReport >= reportMs || done >= total) {\n reported = true;\n lastReport = at;\n opts.send(JOB_PROGRESS, { kind, done, total, elapsedMs: at - started });\n }\n if (at - lastYield >= sliceMs) {\n lastYield = at;\n await handOver();\n }\n },\n };\n\n try {\n const value = await work(ctx);\n return job.cancelled ? { cancelled: true, value } : { ok: true, value };\n } catch (e) {\n // A cancelled job that threw on the way out is still a cancellation:\n // the author asked it to stop, and an error report would be noise.\n if (job.cancelled) return { cancelled: true };\n return { error: e instanceof Error ? e.message : String(e) };\n } finally {\n live.delete(kind);\n }\n },\n };\n}\n","// ---------------------------------------------------------------------------\n// The save/dirty controller: the little machine that turns \"the author typed\n// something\" into \"the bytes are on disk\", and says so on screen.\n//\n// Both apps wrote one. Neither is complete, and the two are incomplete in\n// OPPOSITE directions, which is the clearest argument for a shared one that\n// this review has produced:\n//\n// - Patterpad runs an INTERVAL (one timer for the app's life, saving any\n// dirty scene every N seconds). Continuous typing is saved throughout, but\n// a single edit can sit unwritten for the whole period.\n// - Storyletter DEBOUNCES (write 700ms after edits settle). A single edit is\n// written promptly, but an author typing steadily is never written at all\n// until they pause - which on a long paragraph is a long time.\n//\n// So this does both: debounce for promptness, with a MAXIMUM AGE so a run of\n// edits cannot outrun the writer. Neither app had the pair; each had half.\n//\n// The other thing neither had is re-entrancy. Storyletter's flush cleared its\n// pending queue and then awaited the write, so a flush arriving mid-write saw\n// nothing pending and reported \"saved\" while bytes were still in the air. Here\n// a write in flight is a thing you can await, and the status is only \"saved\"\n// when nothing arrived while it was running.\n//\n// WHAT THIS DOES NOT OWN is what a save IS. The controller never touches the\n// document: it calls the app's `write` and reads its boolean. What is pending,\n// how it coalesces, what to repaint afterwards - all of that stays in the app,\n// because all of it is about the app's model.\n//\n// DOM-free, so a test can drive it with fake timers and no window.\n// ---------------------------------------------------------------------------\n\n/**\n * Three states, not a boolean.\n *\n * \"saving\" earns its place: on a slow disk or a slow VC hook a save takes long\n * enough to see, and a status that flips straight from unsaved to saved leaves\n * the author wondering whether the click did anything.\n */\nexport type SaveStatus = \"saved\" | \"unsaved\" | \"saving\";\n\nexport interface SaveControllerOptions {\n /**\n * Write whatever is pending. Return false if it failed: the controller stays\n * \"unsaved\" and will try again on the next touch or flush, rather than\n * quietly reporting success over a write that did not happen.\n *\n * Called only when something is pending, and never twice at once.\n */\n write: () => Promise<boolean> | boolean;\n /** Told every time the status changes, and only when it changes. */\n onStatus?: (status: SaveStatus) => void;\n /** How long after the last edit to write. Storyletter's 700ms by default. */\n delayMs?: number;\n /**\n * The longest an edit may go unwritten while more keep arriving.\n *\n * This is the interval half of the two apps put back in: without it, steady\n * typing defers the write for as long as the typing lasts.\n */\n maxWaitMs?: number;\n}\n\nexport interface SaveController {\n /** What the indicator should say. */\n readonly status: SaveStatus;\n /** Is anything unwritten? For a close guard, or an updater asking whether it\n * may restart. True while a write is in flight, too: it is not on disk yet. */\n readonly pending: boolean;\n /** Something changed. Starts (or extends) the countdown. */\n touch(): void;\n /**\n * Write now, and wait for it.\n *\n * Call on every transition that must see current bytes: switching what is\n * being edited, opening a tool window that reads the disk, closing the\n * window, Cmd+S. Safe to call when nothing is pending (it does nothing) and\n * safe to call during a write (it waits for it, then writes again if more\n * arrived while it ran).\n */\n flush(): Promise<void>;\n /** Give up on what is pending without writing it. For a project close after\n * the author has said to discard, and for teardown. */\n cancel(): void;\n /**\n * Autosave on or off (Patterpad's per-project setting).\n *\n * Off does not mean \"never write\": touch() still marks the work unsaved, and\n * flush() still writes on transitions and on Cmd+S. It only stops the clock.\n */\n setAuto(on: boolean): void;\n}\n\nexport function createSaveController(opts: SaveControllerOptions): SaveController {\n const delayMs = opts.delayMs ?? 700;\n const maxWaitMs = opts.maxWaitMs ?? 5000;\n\n let status: SaveStatus = \"saved\";\n let auto = true;\n let dirty = false;\n /** When the oldest unwritten edit arrived, for the maximum age. */\n let dirtySince = 0;\n let timer: ReturnType<typeof setTimeout> | undefined;\n /** The write in flight, so a second flush awaits it instead of racing it. */\n let inFlight: Promise<void> | undefined;\n\n const setStatus = (next: SaveStatus): void => {\n if (next === status) return;\n status = next;\n opts.onStatus?.(status);\n };\n\n const clearTimer = (): void => {\n if (timer === undefined) return;\n clearTimeout(timer);\n timer = undefined;\n };\n\n const arm = (): void => {\n clearTimer();\n if (!auto) return;\n // Never later than maxWaitMs after the first unwritten edit, however much\n // longer the author keeps typing.\n const deadline = dirtySince + maxWaitMs;\n const wait = Math.max(0, Math.min(delayMs, deadline - Date.now()));\n timer = setTimeout(() => { timer = undefined; void run(); }, wait);\n };\n\n const run = async (): Promise<void> => {\n if (inFlight) return inFlight; // one writer at a time\n if (!dirty) { setStatus(\"saved\"); return; }\n clearTimer();\n dirty = false;\n setStatus(\"saving\");\n inFlight = (async () => {\n let ok = false;\n try {\n ok = await opts.write();\n } catch {\n // A thrown write is a failed write. The app has already said whatever\n // it wants to say about it; here it only means \"still unsaved\".\n ok = false;\n }\n if (!ok) {\n // Put the dirt back so the next touch or flush retries, and keep the\n // oldest timestamp: a failing save must not reset the maximum age.\n if (!dirty) { dirty = true; dirtySince = dirtySince || Date.now(); }\n }\n setStatus(dirty ? \"unsaved\" : \"saved\");\n if (dirty) arm(); // more arrived while we wrote, or it failed\n })();\n try {\n await inFlight;\n } finally {\n inFlight = undefined;\n }\n };\n\n return {\n get status() { return status; },\n get pending() { return dirty || inFlight !== undefined; },\n touch() {\n if (!dirty) dirtySince = Date.now();\n dirty = true;\n // An edit arriving mid-write leaves the status alone: a write really is\n // running, and it will settle to \"unsaved\" on its own when it lands.\n if (!inFlight) setStatus(\"unsaved\");\n arm();\n },\n async flush() {\n // Await a write already running, then write again if this call's work (or\n // anything that arrived mid-write) is still outstanding.\n if (inFlight) await inFlight;\n if (dirty) await run();\n else setStatus(\"saved\");\n },\n cancel() {\n clearTimer();\n dirty = false;\n setStatus(inFlight ? \"saving\" : \"saved\");\n },\n setAuto(on) {\n auto = on;\n if (on) { if (dirty) arm(); } else clearTimer();\n },\n };\n}\n","// ---------------------------------------------------------------------------\n// The save indicator: the six lines that draw what `createSaveController`\n// already computes.\n//\n// The controller has been shared since 0.14.0 and its three states with it, but\n// the DRAWING stayed in each app - so both apps hand-rendered the output of one\n// machine and promptly drifted. Patterpad's was `<span id=\"dirty\" hidden>●\n// unsaved</span>`: present only when there was something to worry about.\n// Storyletter's always paints one of Saved / Saving… / Unsaved. (Design review\n// 2026-08, A4.)\n//\n// STORYLETTER'S WON, and the reasoning is worth keeping because it is not\n// \"newer is better\". Three states are what the shared controller models, and an\n// app that autosaves without being asked owes the author the reassurance as\n// well as the warning: a dot that only ever appears to worry you leaves \"did\n// that get written?\" unanswered at exactly the moment it is asked. \"Saving…\"\n// earns its place separately - on a slow disk or a slow version-control hook a\n// write takes long enough to see.\n//\n// It cannot drift again, which is the actual point of putting it here.\n// ---------------------------------------------------------------------------\n\nimport { el } from \"./dom.js\";\nimport type { SaveStatus } from \"./save.js\";\n\nexport interface SaveIndicator {\n /** Put it in the topbar. */\n readonly el: HTMLElement;\n /** Wire straight to the controller's `onStatus`. */\n set(status: SaveStatus): void;\n}\n\n/** What each state says. Not an option: two apps saying it differently is the\n * drift this exists to end. */\nconst WORDS: Record<SaveStatus, string> = {\n saved: \"Saved\",\n saving: \"Saving…\",\n unsaved: \"Unsaved\",\n};\n\nexport function saveIndicator(initial: SaveStatus = \"saved\"): SaveIndicator {\n const node = el(\"span\");\n const set = (status: SaveStatus): void => {\n node.className = `savestat ${status}`;\n node.textContent = WORDS[status];\n };\n set(initial);\n return { el: node, set };\n}\n","// ---------------------------------------------------------------------------\n// The stale-session bar: \"what you are playing is older than the project\".\n//\n// Both apps grew one without copying the other, and landed within a word of the\n// same sentence - Patterpad's \"Scene changed in the editor: restart to play the\n// new version\", Storyletter's \"The project changed in the editor. Restart to\n// play the new version.\" That is the strongest evidence a thing is shape-level\n// rather than a taste: any app that compiles a document into something you then\n// PLAY has a running session that can fall behind its source, and the only two\n// things it can say are what went out of date and how to start again.\n//\n// So the app supplies the NOUN and the callback, and nothing else. Everything\n// left over - the warn-toned banner, the sentence, the restart glyph - is the\n// shape, and having it in one place is what stops the two apps drifting to two\n// wordings for one situation.\n//\n// WHOSE DRAWING WON, since the two differed here where the words did not.\n// Patterpad's was a line of centred grey text in the choice tray; Storyletter's\n// is a bordered warn-toned bar with the button in it. The bar, because this is\n// a condition rather than a remark: the session is frozen until you act, and a\n// note that reads like the end of a passage does not say so.\n// ---------------------------------------------------------------------------\n\nimport { el } from \"./dom.js\";\nimport { iconNode } from \"./icons.js\";\n\nexport interface StaleBarOptions {\n /**\n * What went out of date, as a capitalised noun phrase: \"The project\", \"The\n * scene\". Written into \"<subject> changed in the editor.\"\n */\n subject: string;\n /** Start again from the current source. */\n onRestart: () => void;\n /** The button, when \"Restart\" is not the app's word for it. */\n restartLabel?: string;\n /**\n * The rest of the sentence, for an app whose session is not a PLAY: the\n * default is \"Restart to play the new version.\"\n */\n advice?: string;\n}\n\nexport function staleBar(opts: StaleBarOptions): HTMLElement {\n const label = opts.restartLabel ?? \"Restart\";\n return el(\"div\", { className: \"stale-bar\" },\n el(\"span\", { className: \"stale-bar-msg\",\n text: `${opts.subject} changed in the editor. ${opts.advice ?? \"Restart to play the new version.\"}` }),\n // The icon is a node beside the word, not a character inside it; the\n // button's flex gap sets the space (stale.css).\n el(\"button\", { className: \"stale-bar-go\", onClick: () => opts.onRestart() },\n iconNode(\"restart\", 12), label),\n );\n}\n","// ---------------------------------------------------------------------------\n// The toast: a transient remark from the app - \"Bundle published\", \"Save\n// refused: ...\", \"Spell-check is off\" - that shows itself, waits, and leaves.\n//\n// Both apps grew one without copying the other, and drifted on everything a\n// toast can drift on. Patterpad's sat bottom-right, an outlined card on the\n// surface colour, entered and left on the shared panel motion, lingered longer\n// for an error, and announced itself to a screen reader. Storyletter's sat\n// bottom-centre, a solid --danger or --ok block with surface-coloured text, had\n// no motion, one duration, and no ARIA. Same three sentences either side.\n//\n// WHOSE DRAWING WON, and why, since the two differed here in every particular:\n//\n// PLACE: bottom-right. A toast is a REMARK, not a condition (that is the stale\n// bar's job), and a remark must not sit over what the author is reading or\n// typing. Bottom-centre lands on the centre column in the editor and on the\n// choice tray in Play; the corner is out of the reading measure, and it is\n// where the platforms put their own notifications, so the eye already knows\n// to glance there and back.\n//\n// COLOUR: an outlined card on --surface, with the KIND carried by the border\n// and the text colour. A solid block of --danger shouts, and the design\n// language asks for restraint at the seams; the card also keeps its text as\n// --ink, which reads on every palette without each one having to tune a\n// contrast pair for white-on-red.\n//\n// TIME: 4s, 7s for an error. Something went wrong is worth an extra glance.\n//\n// MOTION: the shared panel vocabulary in tokens.css, in and out, so a toast\n// moves the way every other transient surface in the family moves.\n//\n// One toast at a time: a new one replaces the old, never stacks. Rapid events\n// (a burst of saves) would otherwise pile up a column of remarks about one\n// moment. The dismiss checks it is still dismissing the CURRENT toast, so a\n// replacement is never hidden by its predecessor's timer.\n//\n// Mounted by the module, not by host markup: it appends its own node to\n// document.body on first use, so a second window gets the whole thing by\n// importing it (multi-window-rules.md section 1). Its CSS travels beside it.\n// ---------------------------------------------------------------------------\n\nimport { el } from \"./dom.js\";\nimport { closeWithExit } from \"./exit.js\";\n\n/** What the remark is about. `info` is the plain case; `ok` says a thing you\n * asked for happened; `error` says it did not. */\nexport type ToastKind = \"info\" | \"ok\" | \"error\";\n\nexport interface ToastOptions {\n /** How long it stays, in ms, before the exit plays. Defaults to 4000, or\n * 7000 for an error. */\n duration?: number;\n}\n\nconst DURATION: Record<ToastKind, number> = { info: 4000, ok: 4000, error: 7000 };\n\nlet node: HTMLElement | undefined;\nlet timer = 0;\nlet seq = 0;\n\nfunction mount(): HTMLElement {\n if (node && node.isConnected) return node;\n // role=status + aria-live=polite: announced without interrupting, which is\n // exactly a toast's manners.\n node = el(\"div\", { className: \"shell-toast\" });\n node.setAttribute(\"role\", \"status\");\n node.setAttribute(\"aria-live\", \"polite\");\n node.hidden = true;\n document.body.append(node);\n return node;\n}\n\n/**\n * Show a toast. Replaces any toast already showing.\n *\n * `message` is shown as written; a newline breaks the line (\"Bundle\n * published\\n<path>\"), and a long unbroken token such as a path wraps inside\n * the card rather than spilling past it.\n */\nexport function toast(message: string, kind: ToastKind = \"info\", opts: ToastOptions = {}): void {\n const t = mount();\n const id = ++seq;\n t.textContent = message;\n t.className = `shell-toast ${kind}`; // also clears a `.closing` left by a prior dismiss\n t.hidden = false;\n window.clearTimeout(timer);\n timer = window.setTimeout(() => {\n // Only hide if this is still the toast that set the timer: a replacement\n // that arrived meanwhile has its own.\n closeWithExit(t, () => { if (seq === id) t.hidden = true; });\n }, opts.duration ?? DURATION[kind]);\n}\n\n/** Dismiss the current toast now, if any. Plays the exit. */\nexport function dismissToast(): void {\n if (!node || node.hidden) return;\n window.clearTimeout(timer);\n const id = seq;\n const t = node;\n closeWithExit(t, () => { if (seq === id) t.hidden = true; });\n}\n","// ---------------------------------------------------------------------------\n// The stepper bar: a bottom bar that walks you through a list of things to\n// attend to, one at a time.\n//\n// Count, previous, position, next, the current thing as a button, and a slot at\n// the right for whatever acts on it. That is the whole shape, and it is already\n// four bars across two apps: Patterpad's problems bar and its review walk,\n// Storyletter's problems bar and its Review Feedback walk. Patterpad drew its\n// two with parallel class sets (`.problembar-*` and `.reviewbar-*`) for one\n// idea; Storyletter drew its second as the first plus one modifier, which is\n// the better rule and the reason this ended up here (design review 2026-08,\n// section 5 items 2 and 3).\n//\n// NO DOMAIN WORD anywhere in it, which is the test that says it belongs in the\n// shell rather than in either app. It knows about a list, an index, and three\n// pieces of text per entry; it does not know what a problem or a comment is.\n// Severity, resolvedness and quick fixes all arrive as strings and elements the\n// app made.\n//\n// TWO THINGS PATTERPAD'S BARS LACK and gain by adopting this: the position\n// readout (`3/11`, so the walk has a length and an end rather than just a next),\n// and the `where` segment naming what the entry is about before you go there.\n//\n// STEPPING NAVIGATES, or does not: that is the CALLER's decision and this bar\n// takes no view. It reports `onStep` and `onGo` and nothing more. The rule that\n// settles it lives in design-language.md - an ambient surface moves the view and\n// never the focus; a mode you entered may take you somewhere - and the guard for\n// an uncommitted edit belongs to the app, because only the app knows what is\n// unsaved.\n// ---------------------------------------------------------------------------\n\nimport { el } from \"./dom.js\";\nimport { iconNode } from \"./icons.js\";\n\nexport interface StepperItem {\n /**\n * One word for what kind of thing this is: \"error\", \"comment\", \"resolved\".\n * Absent when the bar carries one kind of thing only.\n */\n kind?: string;\n /** An extra class on the kind chip, so an app can colour its own kinds\n * (Storyletter's `sev-error`, and `done` for a resolved thread). */\n kindClass?: string;\n /** Where it is. A string is the app's own address, set in the mono face; a\n * Node is a made element, a `breadcrumb([\"Box\", \"Deck\", \"Card\"])` say,\n * drawn as it is. Give the bar plain crumbs: the whole entry is already\n * the button that goes there, so a crumb with its own click has nowhere\n * else to take you. */\n where?: string | Node;\n /** The entry itself, in one line. Overflow is clipped, not wrapped: the bar\n * is one row high and stays that way however long the sentence is. */\n text: string;\n}\n\n/** How loud the count is. The app picks; the palette supplies the value. */\nexport type StepperTone = \"danger\" | \"warn\" | \"accent\" | \"muted\";\n\nexport interface StepperBarOptions {\n items: StepperItem[];\n /** Which one is current. Clamped, so a shrinking list cannot point off the end. */\n at: number;\n tone?: StepperTone;\n /** Go to another index. The bar wraps, so this is always in range. */\n onStep: (next: number) => void;\n /** Take me to what the current entry is about. */\n onGo: (index: number) => void;\n /** What the three controls say they do. Keyboard shortcuts belong in here. */\n tips?: { prev?: string; next?: string; go?: string };\n /**\n * What to say when the list is empty.\n *\n * Absent hides the bar, which is right for an AMBIENT bar: no problems, no\n * problems bar. Present keeps it up, which is right for a MODE: entering the\n * walk and seeing nothing at all reads as a broken command rather than as\n * \"there is no feedback\".\n */\n empty?: string;\n /** Leave the mode. Drawn as the last control, hard right. */\n onClose?: () => void;\n closeTip?: string;\n /** The right-hand end before the close: a quick fix, say. Nulls are skipped,\n * so a caller can pass a conditional straight in. */\n actions?: (HTMLElement | null | undefined)[];\n}\n\nconst STEP_ICON = 12;\n\n/** Draw (or hide) the bar in `host`. Idempotent: call it again with new state. */\nexport function renderStepperBar(host: HTMLElement, opts: StepperBarOptions): void {\n const { items } = opts;\n // 12px inside the bar's 20px control: the bar is set at 0.8rem.\n const close = opts.onClose === undefined ? null : el(\"button\", {\n className: \"stepbar-nav stepbar-close\",\n tip: opts.closeTip ?? \"Close\", onClick: opts.onClose,\n }, iconNode(\"close\", STEP_ICON));\n const actions = (opts.actions ?? []).filter((a): a is HTMLElement => a !== null && a !== undefined);\n\n if (items.length === 0) {\n if (opts.empty === undefined) { host.hidden = true; host.replaceChildren(); return; }\n host.hidden = false;\n host.replaceChildren(\n el(\"span\", { className: \"stepbar-count muted\", text: \"0\" }),\n el(\"span\", { className: \"stepbar-empty\", text: opts.empty }),\n ...actions, ...(close ? [close] : []),\n );\n return;\n }\n\n host.hidden = false;\n const index = Math.min(Math.max(opts.at, 0), items.length - 1);\n const item = items[index]!;\n const step = (delta: number): void => opts.onStep((index + delta + items.length) % items.length);\n\n // The steppers are absent for a list of one: two arrows that both come back\n // to where you are is furniture pretending to be a control.\n const nav = items.length > 1\n ? [\n el(\"button\", { className: \"stepbar-nav\",\n tip: opts.tips?.prev ?? \"Previous\", onClick: () => step(-1) }, iconNode(\"back\", STEP_ICON)),\n el(\"span\", { className: \"stepbar-of\", text: `${index + 1}/${items.length}` }),\n el(\"button\", { className: \"stepbar-nav\",\n tip: opts.tips?.next ?? \"Next\", onClick: () => step(1) }, iconNode(\"forward\", STEP_ICON)),\n ]\n : [];\n\n host.replaceChildren(\n el(\"span\", { className: `stepbar-count ${opts.tone ?? \"muted\"}`, text: String(items.length) }),\n ...nav,\n el(\"button\", { className: \"stepbar-cur\", tip: opts.tips?.go ?? \"Go to this\", onClick: () => opts.onGo(index) },\n item.kind === undefined ? null\n : el(\"span\", { className: `stepbar-cat${item.kindClass ? ` ${item.kindClass}` : \"\"}`, text: item.kind }),\n item.where === undefined ? null\n : typeof item.where === \"string\" ? el(\"span\", { className: \"stepbar-where\", text: item.where })\n : el(\"span\", \"stepbar-where\", item.where),\n el(\"span\", { className: \"stepbar-msg\", text: item.text }),\n ),\n ...actions, ...(close ? [close] : []),\n );\n}\n","// ---------------------------------------------------------------------------\n// The updater's VIEW: the themed prompt main summons over `updater:prompt`\n// (updater.ts) and reads the chosen button index back from, the same contract\n// as dialog.showMessageBox's `response`. The renderer half of the updater is\n// not optional: an unanswered prompt does not fall back to a native dialog,\n// the shell waits 300 seconds and resolves its own fallback index. Both apps\n// had written this view by hand (55 of 60 lines identical); this is the one\n// they share, on the family's dialog frame, the way save.ts has save-view.ts.\n//\n// Storyletter's copy, plus Patterpad's `links` row as an option (an About box\n// used to share this dialog there). Styles ship as updater.css.\n// ---------------------------------------------------------------------------\n\nimport { el } from \"./dom.js\";\nimport { dialogFrame } from \"./dialog.js\";\nimport type { UpdaterDownloadProgress, UpdaterPromptOptions } from \"./updater.js\";\n\nexport interface UpdaterLink { label: string; url: string }\n\nexport interface UpdaterViewOptions extends UpdaterPromptOptions {\n /** Web links under the detail. Opened through `openExternal`, never by\n * navigating the window. */\n links?: UpdaterLink[];\n /** How a link opens (the app's allow-listed shell.openExternal bridge).\n * Required for `links` to do anything. */\n openExternal?: (url: string) => void;\n}\n\n// The progress row of the open `progress: true` dialog, if any. These are\n// modal, so one at a time, so one slot is enough. Closing clears it.\nlet liveProgress: { bar: HTMLElement; label: HTMLElement } | null = null;\n\nconst mb = (n: number): string => (n / (1024 * 1024)).toFixed(1);\n\n/** Route a download-progress tick into the open dialog's bar. No-op when none\n * is showing. Registered once at boot on the app's progress channel. */\nexport function feedUpdaterDownloadProgress(p: UpdaterDownloadProgress): void {\n if (!liveProgress) return;\n const pct = Math.max(0, Math.min(100, p.percent));\n liveProgress.bar.style.width = `${pct}%`;\n liveProgress.label.textContent =\n `${pct.toFixed(0)}%, ${mb(p.transferred)} of ${mb(p.total)} MB (${mb(p.bytesPerSecond)} MB/s)`;\n}\n\n/** Show the prompt as a modal themed dialog; resolve the index of the clicked\n * button (Esc resolves `cancelId`, which defaults to the last button). */\nexport function showUpdaterDialog(opts: UpdaterViewOptions): Promise<number> {\n return new Promise((resolve) => {\n const defaultId = opts.defaultId ?? 0;\n const cancelId = opts.cancelId ?? opts.buttons.length - 1;\n\n let done = false;\n const finish = (idx: number): void => {\n if (done) return;\n done = true;\n liveProgress = null; // stop feeding a dialog that is gone\n resolve(idx);\n frame.close();\n };\n const frame = dialogFrame({\n title: opts.message, className: \"updater-dialog\",\n // Esc is the cancel button, not a further answer: main is waiting on an index.\n onClose: () => finish(cancelId),\n });\n if (opts.detail) frame.body.append(el(\"p\", \"updater-detail\", opts.detail));\n\n if (opts.progress) {\n const track = el(\"div\", \"updater-progress-track\");\n const bar = el(\"div\", \"updater-progress-bar\");\n track.append(bar);\n const label = el(\"p\", \"updater-progress-label\", \"Starting download…\");\n frame.body.append(track, label);\n liveProgress = { bar, label };\n }\n\n if (opts.links?.length) {\n const row = el(\"p\", \"updater-links\");\n for (const link of opts.links) {\n const a = el(\"a\", undefined, link.label);\n a.href = link.url;\n a.addEventListener(\"click\", (e) => { e.preventDefault(); opts.openExternal?.(link.url); });\n row.append(a);\n }\n frame.body.append(row);\n }\n\n opts.buttons.forEach((label, i) => {\n // The default is the affirmative and wears the accent; every other\n // button, the way out included, is the plain one.\n const b = el(\"button\", i === defaultId ? \"btn primary\" : \"btn\", label);\n b.type = \"button\";\n b.addEventListener(\"click\", () => finish(i));\n frame.actions.append(b);\n if (i === defaultId) queueMicrotask(() => b.focus());\n });\n\n frame.open();\n });\n}\n","// ---------------------------------------------------------------------------\n// The kit gallery: pick a starting point by what you want to make.\n//\n// The new-thing moment for the family (New Project, New Box, New Scene), drawn\n// once. Adobe's New Document is the shape: tiles on the left, a details panel\n// on the right, one screen. Not a wizard: a wizard asks for settings before\n// anything has been chosen, and the choice is the part that teaches.\n//\n// Storyletter grew this as `kit-picker.ts` (one component at two scales on\n// <dialog>, \"a shell candidate, held back until it had been used in earnest\")\n// and the kit gallery brief moved it here, 2026-09-27\n// (storylet-studio/design/kit-gallery.md). What a kit IS made of stays in\n// each app: this file knows names, words and pictures, never boxes or scenes.\n//\n// Sections are shelves (\"Start from a kit\", \"Learn from a finished project\"),\n// and each says what its button does, because opening a copy of an example\n// and creating from a kit are different acts behind the same kind of tile.\n// The app's own fields (a project name, version control, a build path) sit in\n// the details panel, shown only for the sections that use them.\n// ---------------------------------------------------------------------------\n\nimport { el } from \"./dom.js\";\nimport { dialogFrame } from \"./dialog.js\";\n\nexport interface KitGalleryItem<T extends string> {\n id: T;\n /** What you are making, in the author's terms, not the model's. */\n name: string;\n /** What it is FOR: the panel's first line, and the tile's unless `tile` says otherwise. */\n blurb: string;\n /** The tile's line, when the blurb is longer than a tile holds (three\n * lines). A whole short sentence reads better than a long one cut off. */\n tile?: string;\n /** More, for the panel only. */\n detail?: string;\n /** What pressing Play (or Run) shows, said as a promise. */\n play?: string;\n /** What it has, in a word or two each (\"Drawn map\", \"Copies\"): pills on the tile and in the\n * panel, so kits compare at a glance before any is chosen. The author's ask, 2026-09-27, in\n * place of pictures, which were ruled out the same day. */\n features?: string[];\n /** What lands, in the concrete, as a short list in the panel. */\n lands?: string[];\n /** A word or two on the tile (\"Start here\"). */\n badge?: string;\n}\n\nexport interface KitGallerySection<T extends string> {\n /** Sentence-case label text (\"Start from a kit\"). Absent: no caption. */\n caption?: string;\n /** The consequence of a click, said before the click. */\n note?: string;\n items: KitGalleryItem<T>[];\n /** The primary button's label while an item here is chosen. Default \"Create\". */\n action?: string;\n /** Show the app's detail fields (and ask for the name) for this section.\n * Default true. An example is opened, not named, so its shelf says false. */\n usesDetails?: boolean;\n}\n\nexport interface KitGalleryChoice {\n /** Present when a name was asked for and the chosen section uses details. */\n name?: string;\n}\n\nexport interface KitGalleryOptions<T extends string> {\n /** The dialog's heading: \"New project\", \"New box\", \"New scene\". */\n title: string;\n /** What the thing being made IS, in concrete terms. */\n what?: string;\n sections: KitGallerySection<T>[];\n /** Ask for a name in the details panel, with this placeholder. Required\n * when asked: making a thing without one would have to invent a folder. */\n namePlaceholder?: string;\n /** The name field's label. Default \"Name\". */\n nameLabel?: string;\n /** The app's own fields, below the name (version control, a build path). */\n details?: HTMLElement;\n /** Runs whenever an item is chosen, the opening one included, so the app can show or hide its\n * own fields for it (New Scene's Speaker, for a kit with lines). */\n onChoose?: (id: T) => void;\n /** Checked before `onPick`, after the name: return the app's field that still needs filling (it\n * is focused and marked, and nothing is made), or null when all is well. */\n validate?: (id: T) => HTMLElement | null;\n /** Runs as the name is typed (and once on open, with \"\"), so the app's own\n * fields can follow it: Patterpad's folder preview and default publish path. */\n onNameInput?: (name: string) => void;\n /** The item chosen when the gallery opens. Default: the first. */\n initial?: T;\n onPick: (id: T, choice: KitGalleryChoice) => void;\n /** Runs once the gallery has closed, whichever way. */\n onClose?: () => void;\n}\n\nexport interface KitGallery {\n readonly dialog: HTMLDialogElement;\n close(): void;\n}\n\n/** A kit's features as pills, or null when it lists none. */\nfunction featurePills(features: string[] | undefined): HTMLElement | null {\n if (!features || features.length === 0) return null;\n return el(\"span\", \"kit-gallery-features\", ...features.map((f) => el(\"span\", \"kit-gallery-feature\", f)));\n}\n\n/** One tile: the name with its badge, the blurb, the feature pills. The gallery's\n * own, and the welcome screen's, so a kit looks the same wherever it is met\n * (welcome.ts draws a tiled group with it; import kit-gallery.css there too). */\nexport function kitTile(item: { name: string; blurb: string; badge?: string; features?: string[] }, onClick: () => void): HTMLButtonElement {\n const tile = el(\"button\", { className: \"kit-gallery-tile\", onClick },\n el(\"span\", \"kit-gallery-tile-head\",\n el(\"span\", \"kit-gallery-tile-name\", item.name),\n item.badge !== undefined ? el(\"span\", \"kit-gallery-badge\", item.badge) : null),\n el(\"span\", \"kit-gallery-tile-blurb\", item.blurb),\n featurePills(item.features)) as HTMLButtonElement;\n tile.type = \"button\";\n return tile;\n}\n\n/** Open the gallery as a modal dialog on the family's frame. */\nexport function openKitGallery<T extends string>(opts: KitGalleryOptions<T>): KitGallery {\n const frame = dialogFrame({ title: opts.title, ...(opts.what !== undefined ? { sub: opts.what } : {}), className: \"kit-gallery\", ...(opts.onClose ? { onClose: opts.onClose } : {}) });\n const { dialog } = frame;\n\n const entries = opts.sections.flatMap((section, s) => section.items.map((item) => ({ item, section, s })));\n if (entries.length === 0) throw new Error(\"openKitGallery: no items to choose from\");\n let chosen = entries.find((e) => e.item.id === opts.initial) ?? entries[0]!;\n\n // --- the details panel ----------------------------------------------------\n const nameInput = opts.namePlaceholder === undefined ? undefined : el(\"input\", { className: \"field kit-gallery-name\" }) as HTMLInputElement;\n if (nameInput) {\n nameInput.placeholder = opts.namePlaceholder!;\n nameInput.setAttribute(\"aria-label\", opts.nameLabel ?? \"Name\");\n }\n const fields = el(\"div\", \"kit-gallery-fields\",\n ...(nameInput ? [el(\"label\", \"kit-gallery-label\", opts.nameLabel ?? \"Name\"), nameInput] : []),\n ...(opts.details ? [opts.details] : []));\n\n const panelName = el(\"h3\", \"kit-gallery-panel-name\");\n const panelBlurb = el(\"p\", \"kit-gallery-panel-blurb\");\n const panelDetail = el(\"p\", \"kit-gallery-panel-detail\");\n const panelPlay = el(\"p\", \"kit-gallery-play\");\n const panelFeatures = el(\"div\", \"kit-gallery-panel-features\");\n const panelLands = el(\"ul\", \"kit-gallery-lands\");\n const panelLandsCaption = el(\"p\", \"kit-gallery-lands-caption\", \"What you get\");\n const panelNote = el(\"p\", \"kit-gallery-note\");\n const panel = el(\"div\", \"kit-gallery-panel\",\n panelName, panelFeatures, panelBlurb, panelDetail, panelPlay, panelLandsCaption, panelLands, panelNote, fields);\n\n const primary = el(\"button\", { className: \"btn primary\", onClick: () => commit() }) as HTMLButtonElement;\n primary.type = \"button\";\n const cancel = el(\"button\", { className: \"btn\", text: \"Cancel\", onClick: () => frame.close() }) as HTMLButtonElement;\n cancel.type = \"button\";\n\n const setText = (node: HTMLElement, text: string | undefined): void => {\n node.textContent = text ?? \"\";\n node.hidden = text === undefined || text === \"\";\n };\n\n // --- the tiles --------------------------------------------------------------\n const tiles = new Map<T, HTMLButtonElement>();\n const shelves = opts.sections.map((section) => {\n const grid = el(\"div\", \"kit-gallery-grid\", ...section.items.map((item) => {\n const tile = kitTile({ ...item, blurb: item.tile ?? item.blurb }, () => choose(item.id));\n tile.dataset.kit = item.id;\n // Double-click is the desktop's \"choose and go\"; a single click only chooses,\n // so a tile can be read in the panel before anything is made.\n tile.addEventListener(\"dblclick\", () => { choose(item.id); commit(); });\n tiles.set(item.id, tile);\n return tile;\n }));\n return el(\"section\", \"kit-gallery-shelf\",\n section.caption !== undefined ? el(\"h3\", \"kit-gallery-caption\", section.caption) : null,\n section.note !== undefined ? el(\"p\", \"kit-gallery-shelf-note\", section.note) : null,\n grid);\n });\n\n const choose = (id: T): void => {\n const next = entries.find((e) => e.item.id === id);\n if (!next) return;\n chosen = next;\n for (const [tid, tile] of tiles) tile.setAttribute(\"aria-pressed\", String(tid === id));\n const { item, section } = chosen;\n panelName.textContent = item.name;\n setText(panelBlurb, item.blurb);\n setText(panelDetail, item.detail);\n setText(panelPlay, item.play);\n const pills = featurePills(item.features);\n panelFeatures.replaceChildren(...(pills ? [pills] : []));\n panelFeatures.hidden = pills === null;\n panelLands.replaceChildren(...(item.lands ?? []).map((l) => el(\"li\", undefined, l)));\n panelLands.hidden = (item.lands ?? []).length === 0;\n panelLandsCaption.hidden = panelLands.hidden;\n const details = section.usesDetails !== false;\n fields.hidden = !details || (nameInput === undefined && opts.details === undefined);\n // Without the fields, the shelf's note is what the click will do next\n // (\"a folder you choose\"), so the panel repeats it beside the button.\n setText(panelNote, details ? undefined : section.note);\n primary.textContent = section.action ?? \"Create\";\n opts.onChoose?.(item.id);\n };\n\n const commit = (): void => {\n const { item, section } = chosen;\n const details = section.usesDetails !== false;\n let name: string | undefined;\n if (details && nameInput) {\n name = nameInput.value.trim();\n if (name === \"\") { nameInput.focus(); nameInput.classList.add(\"kit-gallery-missing\"); return; }\n }\n const missing = opts.validate?.(item.id) ?? null;\n if (missing) {\n missing.classList.add(\"kit-gallery-missing\");\n missing.addEventListener(\"input\", () => missing.classList.remove(\"kit-gallery-missing\"), { once: true });\n missing.focus();\n return;\n }\n frame.close();\n opts.onPick(item.id, name !== undefined ? { name } : {});\n };\n\n if (nameInput) {\n nameInput.addEventListener(\"input\", () => {\n nameInput.classList.remove(\"kit-gallery-missing\");\n opts.onNameInput?.(nameInput.value);\n });\n opts.onNameInput?.(\"\");\n // Enter creates with what is chosen: the author has said what it should be\n // called, and the tile they are looking at is the one they meant.\n nameInput.addEventListener(\"keydown\", (e) => {\n e.stopPropagation();\n if (e.key !== \"Enter\") return;\n e.preventDefault();\n commit();\n });\n }\n\n frame.body.append(el(\"div\", \"kit-gallery-layout\", el(\"div\", \"kit-gallery-shelves\", ...shelves), panel));\n frame.actions.append(cancel, primary);\n dialog.addEventListener(\"click\", (e) => { if (e.target === dialog) frame.close(); });\n\n choose(chosen.item.id);\n frame.open();\n // Focus where the next keystroke is wanted: the name when one is asked for\n // and the opening shelf uses it, otherwise the chosen tile.\n if (nameInput && chosen.section.usesDetails !== false) nameInput.focus();\n else tiles.get(chosen.item.id)?.focus();\n\n return { dialog, close: () => frame.close() };\n}\n","// ---------------------------------------------------------------------------\n// The welcome screen: what an app shows with no project open. Title, one line\n// under it, the actions (Open, New), an optional teaching line, optional\n// captioned groups (Storyletter's shipped examples), and the recents.\n//\n// Both apps drew this with the same twelve CSS rules under two class prefixes\n// (`.recent-name` / `.wel-recent-name`), four of them byte-identical. The CSS\n// here is Patterpad's; the captioned groups are Storyletter's, as an optional\n// slot, drawn as a plain list of rows (name + hint) rather than cards.\n//\n// The whole screen is a drag region (the window has no title bar to grab\n// here) and every control opts out. Styles ship as welcome.css.\n// ---------------------------------------------------------------------------\n\nimport { el } from \"./dom.js\";\nimport { kitTile } from \"./kit-gallery.js\";\n\nexport interface WelcomeAction {\n label: string;\n onClick: () => void;\n /** The one accent button (Open a project…). */\n primary?: boolean;\n}\n\nexport interface WelcomeRecent {\n /** What the project calls itself, with the folder stem as the fallback. */\n name: string;\n /** Beside the name, because two projects may share a name and the folder\n * is how you tell them apart. */\n path: string;\n onOpen: () => void;\n}\n\nexport interface WelcomeGroupItem {\n name: string;\n /** What choosing it gets you, said before the click. */\n hint?: string;\n /** Tiled groups only: a word or two beside the name (\"Start here\"). */\n badge?: string;\n /** Tiled groups only: the kit's feature pills, as the gallery draws them. */\n features?: string[];\n onOpen: () => void;\n}\n\nexport interface WelcomeGroup {\n /** Sentence-case label text (\"Learn from a finished project\"); never an overline. */\n caption: string;\n /** The consequence of a click, said before the click (\"Each opens as your\n * own copy, in a folder you choose.\"). */\n note?: string;\n items: WelcomeGroupItem[];\n /** Draw the items as the kit gallery's tiles rather than rows (the kit\n * gallery brief, section 6: the welcome shows the kits and the examples as\n * the gallery shows them). Needs kit-gallery.css beside welcome.css. */\n tiles?: boolean;\n}\n\nexport interface WelcomeOptions {\n title: string;\n sub: string;\n actions: WelcomeAction[];\n recents: WelcomeRecent[];\n groups?: WelcomeGroup[];\n /** The teaching door: a line under the actions, quieter than a button\n * (\"New to Patter? Take the interactive tour\"). The app builds and styles\n * it; a text action in it is a link, not bare muted text. */\n tourLine?: HTMLElement;\n /** The recents caption. Default \"Recent\". */\n recentsCaption?: string;\n /** How many recents to show. Default 5. */\n maxRecents?: number;\n /** A sentence about why the last open failed, under everything. */\n error?: string;\n}\n\nexport interface Welcome {\n el: HTMLElement;\n /** Redraw the recents (the list changes as projects open and close). */\n setRecents(recents: WelcomeRecent[]): void;\n setError(error: string | undefined): void;\n}\n\n/** Mount the welcome into `host` (replacing its children). */\nexport function mountWelcome(host: HTMLElement, opts: WelcomeOptions): Welcome {\n const caption = (text: string): HTMLElement => el(\"h2\", \"welcome-caption\", text);\n const group = (label: string, ...body: (Node | null)[]): HTMLElement =>\n el(\"section\", \"welcome-group\", caption(label), ...body);\n\n const actions = el(\"div\", \"welcome-actions\");\n for (const a of opts.actions) {\n const b = el(\"button\", { className: `btn${a.primary ? \" primary\" : \"\"}`, text: a.label, onClick: a.onClick });\n b.type = \"button\";\n actions.append(b);\n }\n\n const groups = (opts.groups ?? []).map((g) => group(g.caption,\n g.note !== undefined ? el(\"p\", \"welcome-note\", g.note) : null,\n g.tiles\n ? el(\"div\", \"kit-gallery-grid welcome-tiles\", ...g.items.map((item) => kitTile({\n name: item.name, blurb: item.hint ?? \"\",\n ...(item.badge !== undefined ? { badge: item.badge } : {}),\n ...(item.features !== undefined ? { features: item.features } : {}),\n }, item.onOpen)))\n : el(\"div\", \"welcome-list\", ...g.items.map((item) => {\n const b = el(\"button\", { className: \"welcome-item\", onClick: item.onOpen },\n el(\"span\", \"welcome-item-name\", item.name),\n item.hint !== undefined ? el(\"span\", \"welcome-item-hint\", item.hint) : null);\n b.type = \"button\";\n return b;\n })),\n ));\n\n const recentsHost = el(\"div\", \"welcome-recents-slot\");\n const drawRecents = (recents: WelcomeRecent[]): void => {\n const shown = recents.slice(0, opts.maxRecents ?? 5);\n recentsHost.replaceChildren();\n if (shown.length === 0) return;\n recentsHost.append(group(opts.recentsCaption ?? \"Recent\",\n el(\"div\", \"welcome-recents\", ...shown.map((r) => {\n const b = el(\"button\", { className: \"welcome-recent\", onClick: r.onOpen },\n el(\"span\", \"welcome-recent-name\", r.name),\n el(\"span\", \"welcome-recent-path\", r.path));\n b.type = \"button\";\n return b;\n })),\n ));\n };\n drawRecents(opts.recents);\n\n const error = el(\"p\", \"welcome-error\");\n const setError = (text: string | undefined): void => {\n error.textContent = text ?? \"\";\n error.hidden = text === undefined || text === \"\";\n };\n setError(opts.error);\n\n const root = el(\"div\", \"welcome\", el(\"div\", \"welcome-card\",\n el(\"h1\", \"welcome-title\", opts.title),\n el(\"p\", \"welcome-sub\", opts.sub),\n actions,\n opts.tourLine ? el(\"div\", \"welcome-line\", opts.tourLine) : null,\n ...groups,\n recentsHost,\n error,\n ));\n host.replaceChildren(root);\n return { el: root, setRecents: drawRecents, setError };\n}\n","// ---------------------------------------------------------------------------\n// The live-link status chip: a compact control in the bottom-right corner for\n// the loopback server a running game connects to. All the state collapses to\n// one coloured \"connect\" icon (grey off, amber listening, green connected and\n// in sync, red connected on a different build); click it to toggle the link\n// (off -> listening -> stop), and while the link is up the copiable ws://\n// address sits beside it. Patterpad's debug-panel.ts and Storyletter's\n// live-link.ts were this file twice, character for character down to the\n// 1000ms `.copied` revert. Styles ship as link-status.css.\n//\n// What the game sends is the app's business; this is the control and the\n// status only.\n// ---------------------------------------------------------------------------\n\nimport { el } from \"./dom.js\";\nimport { iconNode } from \"./icons.js\";\nimport { copyWithFeedback } from \"./util.js\";\n\nexport type LinkStatus =\n | { state: \"off\" }\n | { state: \"error\"; message: string }\n | { state: \"listening\"; port: number; address?: string }\n | {\n state: \"connected\"; port: number; address?: string;\n /** What connected, if it said. */\n project?: string;\n /** Whether the game's build matches the editor's. */\n build?: \"match\" | \"stale\" | \"unknown\";\n /** One extra sentence for the tip (Storyletter names the live boxes). */\n note?: string;\n };\n\n/** The chip's colour class for a state: the four. */\nexport type LinkStatusClass = \"off\" | \"listening\" | \"live\" | \"stale\";\n\nexport interface LinkStatusOptions {\n /** A word beside the chip (\"Live link\"), so a bottom-corner plug is not a\n * mystery. Omitted draws none. */\n label?: string;\n /** Start when off or failed, stop otherwise. A returned status is applied;\n * a status pushed later through `apply` works as well. */\n onToggle: (current: LinkStatus) => LinkStatus | void | Promise<LinkStatus | void>;\n /** Runs after the address is copied. The copy itself is the chip's. */\n onCopy?: (address: string) => void;\n /** Controls before the address (Patterpad's flow picker). */\n lead?: HTMLElement[];\n}\n\nexport interface LinkStatusChip {\n el: HTMLElement;\n apply(status: LinkStatus): void;\n status(): LinkStatus;\n /** Show / hide the control (shown when a project is open). */\n setVisible(on: boolean): void;\n /** Toggle the link (a menu item routes here). */\n toggle(): void;\n}\n\nexport function linkStatusClass(s: LinkStatus): LinkStatusClass {\n if (s.state === \"off\" || s.state === \"error\") return \"off\";\n if (s.state === \"listening\") return \"listening\";\n return s.build === \"stale\" ? \"stale\" : \"live\";\n}\n\n/** The tooltip, spelling the state out. One wording for the family. */\nexport function linkStatusTip(s: LinkStatus): string {\n switch (s.state) {\n case \"off\": return \"Live link is off. Click to start listening.\";\n case \"error\": return `Live link failed (${s.message}). Click to retry.`;\n case \"listening\": return \"Live link is listening for a game. Click to stop.\";\n case \"connected\": {\n const who = s.project !== undefined ? ` to ${s.project}` : \"\";\n const build = s.build === \"stale\" ? \" on a different build, so save or rebuild to re-sync\"\n : s.build === \"match\" ? \" and in sync\" : \"\";\n const note = s.note ? ` ${s.note}` : \"\";\n return `Live link is connected${who}${build}.${note} Click to stop.`;\n }\n }\n}\n\n/** The address a game connects to. */\nexport function linkAddress(s: LinkStatus): string | undefined {\n if (s.state !== \"listening\" && s.state !== \"connected\") return undefined;\n return s.address ?? `ws://127.0.0.1:${s.port}`;\n}\n\n/** Where the chip sits, which link-status.css says too: its right inset, and the\n * breathing room anything beside it keeps. Kept beside the reserve that uses\n * them, since the reserve is a promise about the CSS. */\nconst CORNER_INSET = 14.5;\nconst CORNER_GAP = 12;\n\n/** Mount the chip into `host` (document.body in both apps: it is fixed to the\n * window's corner). Hidden until `setVisible(true)`. */\nexport function mountLinkStatus(host: HTMLElement, opts: LinkStatusOptions): LinkStatusChip {\n const wrap = el(\"div\", \"linkstatus\"); wrap.hidden = true;\n const url = el(\"button\", \"linkstatus-url\"); url.type = \"button\"; url.hidden = true;\n const toggle = el(\"button\", \"linkstatus-toggle off\"); toggle.type = \"button\"; toggle.append(iconNode(\"connect\"));\n if (opts.label !== undefined) wrap.append(el(\"span\", \"linkstatus-word\", opts.label));\n wrap.append(...(opts.lead ?? []), url, toggle);\n host.append(wrap);\n\n let status: LinkStatus = { state: \"off\" };\n\n // The corner the chip floats over belongs to whatever the host put there: a\n // problems bar's error link and its buttons, a canvas strip's last control.\n // Both apps had it drawn under the chip (2026-09-17). So the chip publishes\n // how much of the corner it takes, as --linkstatus-reserve on the document,\n // and the things that can sit there leave that much room (the stepper bar\n // does, in stepper.css; a host's own strips opt in). 0px while hidden.\n // Re-measured on every render, because the address comes and goes, and on a\n // resize where the platform offers one, because a web font landing moves it.\n const root = host.ownerDocument.documentElement;\n const publishReserve = (): void => {\n const width = wrap.hidden ? 0 : wrap.getBoundingClientRect().width;\n root.style.setProperty(\"--linkstatus-reserve\",\n width > 0 ? `${Math.ceil(width + CORNER_INSET + CORNER_GAP)}px` : \"0px\");\n };\n if (typeof ResizeObserver !== \"undefined\") new ResizeObserver(publishReserve).observe(wrap);\n\n const render = (): void => {\n toggle.className = `linkstatus-toggle ${linkStatusClass(status)}`;\n const tip = linkStatusTip(status);\n toggle.dataset[\"tip\"] = tip;\n toggle.setAttribute(\"aria-label\", tip);\n // The copiable address means something once the server is up.\n const addr = linkAddress(status);\n if (addr !== undefined) {\n url.textContent = addr;\n url.dataset[\"tip\"] = \"Click to copy the live link address\";\n url.hidden = false;\n } else url.hidden = true;\n publishReserve();\n };\n const apply = (s: LinkStatus): void => { status = s; render(); };\n render();\n\n toggle.addEventListener(\"click\", () => {\n const out = opts.onToggle(status);\n void Promise.resolve(out).then((next) => { if (next) apply(next); });\n });\n url.addEventListener(\"click\", () => {\n const addr = url.textContent ?? \"\";\n if (!addr) return;\n void copyWithFeedback(url, addr);\n opts.onCopy?.(addr);\n });\n\n return {\n el: wrap, apply,\n status: () => status,\n setVisible(on: boolean): void { wrap.hidden = !on; publishReserve(); },\n toggle(): void { toggle.click(); },\n };\n}\n","// ---------------------------------------------------------------------------\n// THE property declaration list: name, type, default, values or stages,\n// purpose, in a row per declaration, with reorder, remove, add-then-focus and\n// the duplicate / illegal-name gates. Patterpad's settings-properties.ts and\n// Storyletter's prop-list.ts were built from the same shell primitives in the\n// same order (dupGuard, bindPropertyName, a type select over the same six\n// types, defaultControl, three iconBtns on moveItem, labelled tagChips and\n// stageChips, expandableRow, focusNewRow); this is the one list, and each\n// app's extras (Shared, Temporary, Read-only, Durable) arrive through\n// `extraLine` / `extraDetails`.\n//\n// `defaultControl` was four copies (three inside Patterpad), and the two apps'\n// option labels had already parted (\"(unset)\" vs \"(none)\"). One label set now.\n//\n// Storage of the default differs by app: Patterpad's model holds a typed\n// value (true, 3), Storyletter's DTO holds the string the field showed. The\n// list mutates `decls` in place either way; `typed` picks the encoding.\n// ---------------------------------------------------------------------------\n\nimport { el } from \"./dom.js\";\nimport { iconBtn, labelled, moveItem, stageChips, tagChips } from \"./dom.js\";\nimport { dupGuard, expandableRow, focusNewRow } from \"./settings.js\";\nimport type { SettingsSectionHandle } from \"./settings.js\";\nimport { bindPropertyName, firstIllegalPropertyName } from \"./property-name-field.js\";\nimport { PROPERTY_NAME_HINT } from \"./property-names.js\";\n\n/** The six types both apps declare. */\nexport type PropertyListType = \"number\" | \"boolean\" | \"string\" | \"enum\" | \"flags\" | \"quality\";\n\n/** The shape a row edits. Apps' DTOs carry more (shared, writable, durable);\n * those ride through untouched. */\nexport interface PropertyDeclLike {\n name: string;\n type: string;\n default?: unknown;\n /** enum / flags */\n values?: string[];\n /** quality: the ladder, in order */\n stages?: string[];\n purpose?: string;\n}\n\n/** The type list, in the family's order, with the words the select shows. */\nexport const PROPERTY_TYPES: ReadonlyArray<readonly [PropertyListType, string]> = [\n [\"number\", \"Number\"], [\"boolean\", \"True / False\"], [\"string\", \"Text\"],\n [\"enum\", \"List\"], [\"flags\", \"Flags\"], [\"quality\", \"Quality\"],\n];\n\nexport interface DefaultControlOptions {\n /**\n * How the default is stored. `false` (default): the string the field shows,\n * \"\" for none (Storyletter's DTO). `true`: a typed value (boolean, number,\n * string), and none DELETES the key (Patterpad's model).\n */\n typed?: boolean;\n}\n\nconst option = (value: string, label: string, selected: boolean): HTMLOptionElement => {\n const o = el(\"option\", undefined, label);\n o.value = value; o.selected = selected;\n return o;\n};\n\nconst NONE = \"(none)\";\n\n/**\n * The type-appropriate control for a declaration's DEFAULT: a true / false\n * picker for a boolean, the value list for an enum, the stage list for a\n * quality (blank = the first rung), a note for flags (a set starts empty), a\n * number or text field otherwise. The one label for \"no default\" is \"(none)\".\n */\nexport function defaultControl(p: PropertyDeclLike, onChange?: () => void, opts: DefaultControlOptions = {}): HTMLElement {\n const typed = opts.typed === true;\n const write = (raw: string): void => {\n if (raw === \"\") { if (typed) delete p.default; else p.default = \"\"; }\n else if (typed && p.type === \"boolean\") p.default = raw === \"true\";\n else if (typed && p.type === \"number\") p.default = Number(raw);\n else p.default = raw;\n onChange?.();\n };\n const current = p.default === undefined || p.default === null ? \"\" : String(p.default);\n if (p.type === \"boolean\") {\n const sel = el(\"select\", \"field set-default\");\n sel.append(option(\"\", NONE, current === \"\"), option(\"true\", \"True\", current === \"true\"), option(\"false\", \"False\", current === \"false\"));\n sel.addEventListener(\"change\", () => write(sel.value));\n return sel;\n }\n if (p.type === \"enum\") {\n const sel = el(\"select\", \"field set-default\");\n sel.append(option(\"\", NONE, current === \"\"));\n for (const v of p.values ?? []) sel.append(option(v, v, current === v));\n sel.addEventListener(\"change\", () => write(sel.value));\n return sel;\n }\n if (p.type === \"quality\") {\n // The default is a STAGE; blank means the first rung, so say so rather\n // than \"(none)\".\n const sel = el(\"select\", \"field set-default\");\n sel.append(option(\"\", \"(first stage)\", current === \"\"));\n for (const v of p.stages ?? []) sel.append(option(v, v, current === v));\n sel.addEventListener(\"change\", () => write(sel.value));\n return sel;\n }\n if (p.type === \"flags\") {\n // Flags hold a SET of values, so there is no single default: it starts empty.\n const s = el(\"span\", \"set-flagnote\", \"Starts empty\");\n s.dataset[\"tip\"] = \"A flags property starts with none set.\";\n return s;\n }\n const input = el(\"input\", \"field set-default\");\n input.type = p.type === \"number\" ? \"number\" : \"text\";\n input.placeholder = \"Default\";\n input.value = current;\n input.addEventListener(\"input\", () => write(input.value));\n return input;\n}\n\nexport interface PropertyListOptions<T extends PropertyDeclLike> extends DefaultControlOptions {\n /** Called after every mutation; a centre editor feeds its autosave here. */\n onChange?: () => void;\n /** The add button's label. Default \"+ Add property\". */\n addLabel?: string;\n /** The empty sentence. Default \"No properties yet.\" */\n emptyText?: string;\n /** The type select's entries; default `PROPERTY_TYPES`. */\n types?: ReadonlyArray<readonly [string, string]>;\n /** A fresh declaration for the add button. Default: a blank of the first type. */\n newDecl?: () => T;\n /** Controls on the row's line, between the default and the movers\n * (Storyletter's \"uses\" affordance). */\n extraLine?: (decl: T, index: number) => (HTMLElement | null)[];\n /** Fields behind the disclosure, before Values / Stages / Purpose\n * (Shared, Temporary, Read-only, Durable). */\n extraDetails?: (decl: T, index: number) => (HTMLElement | null)[];\n /** Offer the Purpose field. Default true. */\n purpose?: boolean;\n}\n\nexport interface PropertyListHandle extends SettingsSectionHandle {\n /** Both faults, for the Save gate: a duplicate first, then an illegal name. */\n firstInvalid(): HTMLInputElement | null;\n /** The first name that clashes with another, or null. */\n firstDuplicate(): HTMLInputElement | null;\n /** The first name no expression could reach, or null. */\n firstIllegalName(): HTMLInputElement | null;\n /** Redraw from `decls` (after an outside change). */\n render(): void;\n}\n\n/** Mount the list into `host`. Mutates `decls` in place; the caller reads\n * them back on save (pruning blank names is the caller's, since only it\n * knows its DTO). */\nexport function mountPropertyList<T extends PropertyDeclLike>(host: HTMLElement, decls: T[], opts: PropertyListOptions<T> = {}): PropertyListHandle {\n const changed = (): void => opts.onChange?.();\n const guard = dupGuard();\n const types = opts.types ?? PROPERTY_TYPES;\n const list = el(\"div\", \"set-list\");\n const keep = (parts: (HTMLElement | null)[] | undefined): HTMLElement[] =>\n (parts ?? []).filter((p): p is HTMLElement => p !== null);\n\n const row = (p: T, i: number): HTMLElement => {\n const name = el(\"input\", \"field set-name\");\n name.type = \"text\"; name.placeholder = \"Property name\"; name.value = p.name; name.spellcheck = false;\n name.dataset[\"tip\"] = PROPERTY_NAME_HINT;\n bindPropertyName(name, (v) => { p.name = v; changed(); }, { hint: PROPERTY_NAME_HINT });\n guard.track(name);\n\n const type = el(\"select\", \"field set-type\");\n for (const [v, label] of types) type.append(option(v, label, v === p.type));\n type.addEventListener(\"change\", () => {\n p.type = type.value;\n if (opts.typed) delete p.default; else p.default = \"\";\n if (p.type === \"enum\" || p.type === \"flags\") p.values ??= []; else delete p.values;\n if (p.type === \"quality\") p.stages ??= []; else delete p.stages;\n render(); changed();\n });\n\n // The default control is rebuilt in place when the values change, so a\n // new value becomes selectable as the default.\n let def = defaultControl(p, changed, opts);\n const refreshDefault = (): void => { const fresh = defaultControl(p, changed, opts); def.replaceWith(fresh); def = fresh; changed(); };\n\n const up = iconBtn(\"up\", \"Move up\", () => { if (moveItem(decls, i, -1)) { render(); changed(); } }, i === 0);\n const down = iconBtn(\"down\", \"Move down\", () => { if (moveItem(decls, i, 1)) { render(); changed(); } }, i === decls.length - 1);\n const del = iconBtn(\"close\", \"Delete property\", () => { decls.splice(i, 1); render(); changed(); }, false, true);\n\n const details: HTMLElement[] = keep(opts.extraDetails?.(p, i));\n if (p.type === \"enum\" || p.type === \"flags\") details.push(labelled(\"Values\", tagChips(p, refreshDefault)));\n // A quality's ladder, IN ORDER: the chips carry movers because position is the meaning.\n if (p.type === \"quality\") details.push(labelled(\"Stages (in order)\", stageChips(p, refreshDefault)));\n if (opts.purpose !== false) {\n const purpose = el(\"input\", \"field set-purpose\");\n purpose.type = \"text\"; purpose.placeholder = \"What this property is for\"; purpose.value = p.purpose ?? \"\";\n purpose.addEventListener(\"input\", () => {\n if (purpose.value.trim()) p.purpose = purpose.value; else delete p.purpose;\n changed();\n });\n details.push(labelled(\"Purpose\", purpose));\n }\n // Stamped with the declared name so \"Go to definition\" lands on the row (revealRow).\n return expandableRow({ line: [name, type, def, ...keep(opts.extraLine?.(p, i)), up, down, del], details, name: p.name });\n };\n\n const render = (): void => {\n guard.reset();\n list.replaceChildren();\n if (decls.length === 0) list.append(el(\"p\", \"empty\", opts.emptyText ?? \"No properties yet.\"));\n else decls.forEach((p, i) => list.append(row(p, i)));\n guard.check();\n };\n render();\n\n const add = el(\"button\", \"btn set-add\", opts.addLabel ?? \"+ Add property\");\n add.type = \"button\";\n add.addEventListener(\"click\", () => {\n decls.push(opts.newDecl ? opts.newDecl() : ({ name: \"\", type: types[0]?.[0] ?? \"string\", ...(opts.typed ? {} : { default: \"\" }) } as unknown as T));\n render(); changed(); focusNewRow(list);\n });\n host.append(list, add);\n\n return {\n firstDuplicate: () => guard.firstDuplicate(),\n firstIllegalName: () => firstIllegalPropertyName(host),\n // The Save gate takes both faults; the field's own rollover says which.\n firstInvalid: () => guard.firstDuplicate() ?? firstIllegalPropertyName(host),\n render,\n };\n}\n","// ---------------------------------------------------------------------------\n// Navigation history - the VS Code back/forward pair, family-wide.\n//\n// The shell owns the STACK and the ARROWS; each app owns what a place is.\n// `Place` is opaque here for the same reason the app-store's `places` is:\n// \"where you are\" means a focus + document + tab in Storyletter and a scene +\n// position in Patterpad, and the shell has no business knowing either. The app\n// supplies two judgements - `same` (two places that are the same DOCUMENT, so\n// tab and selection twitches coalesce instead of filling the stack) and\n// `usable` (a place can still be restored: the card it names may have been\n// deleted since) - and the mechanics cannot drift between the apps.\n//\n// The model is the browser's: `visit` records the place being LEFT on an\n// ordinary navigation and clears the forward list (navigating anew after\n// going back branches history, and the abandoned branch is gone); `back` and\n// `forward` exchange the current place for the adjacent one. Entries that\n// fail `usable` are DISCARDED on the way past, never restored and never moved\n// to the other side.\n//\n// One duty stays with the app, documented rather than latched: restoring a\n// place re-dispatches the app's own navigation actions, and those call\n// `visit`. The app must not `visit` while it is travelling (Storyletter's\n// `arriving` flag is the local idiom), or every Back would push what it just\n// left and Forward would never reach anything.\n// ---------------------------------------------------------------------------\n\nimport { iconNode, type IconName } from \"./icons.js\";\n\nexport interface NavHistoryOptions<Place> {\n /** Same DOCUMENT: a visit whose place is `same` as the newest entry\n * REPLACES it (keeping the freshest tab) instead of stacking. */\n same(a: Place, b: Place): boolean;\n /** Still restorable? Checked as an entry is stepped onto; a stale one is\n * dropped and the step continues past it. Default: everything is. */\n usable?(p: Place): boolean;\n /** Entries beyond this age off the far end (default 100). */\n cap?: number;\n}\n\nexport interface NavHistory<Place> {\n /** Record the place being left, before an ordinary navigation. */\n visit(place: Place): void;\n /** Step back: hands over the current place (it becomes the forward entry)\n * and returns the place to restore, or undefined at the far end. */\n back(current: Place): Place | undefined;\n forward(current: Place): Place | undefined;\n /** Whether the arrows light. Optimistic: a side holding only stale entries\n * still reports true, and the press quietly discards them (the alternative\n * is validating the whole stack on every paint). */\n canBack(): boolean;\n canForward(): boolean;\n}\n\nexport function createNavHistory<Place>(opts: NavHistoryOptions<Place>): NavHistory<Place> {\n const cap = opts.cap ?? 100;\n const usable = opts.usable ?? ((): boolean => true);\n let past: Place[] = [];\n let ahead: Place[] = [];\n\n const step = (from: Place[], to: Place[], current: Place): Place | undefined => {\n for (;;) {\n const p = from.pop();\n if (p === undefined) return undefined;\n if (!usable(p)) continue; // its document is gone: drop, keep walking\n if (opts.same(p, current)) continue; // a step must MOVE: a self-visit (a\n // tab click routed through a navigation action) is not a journey, and\n // restoring it reads as a dead button\n to.push(current);\n return p;\n }\n };\n\n return {\n visit(place) {\n ahead = [];\n const top = past[past.length - 1];\n if (top !== undefined && opts.same(top, place)) past[past.length - 1] = place;\n else past.push(place);\n if (past.length > cap) past = past.slice(past.length - cap);\n },\n back(current) { return step(past, ahead, current); },\n forward(current) { return step(ahead, past, current); },\n canBack() { return past.length > 0; },\n canForward() { return ahead.length > 0; },\n };\n}\n\n/**\n * The quiet arrow pair, VS Code's shape: greyed where there is nowhere to\n * go, one component so it looks and sits the same in every app of the\n * family; the caller re-`set`s it whenever a navigation may have changed\n * what the arrows can do.\n *\n * ARROWS, not chevrons, and the distinction is the family's glyph grammar\n * (the author's ruling, 2026-08-28): a chevron says STRUCTURE - the pane\n * toggles, a labelled up-crumb, a tree row's disclosure - and an arrow says\n * TIME. The first cut used chevrons, and sitting on the topbar two seats\n * from the pane toggle's chevron the pair read as more of the same thing;\n * it is how every browser, editor and file manager already split the two.\n *\n * The pair's HOME is the topbar's lead, immediately after the nav toggle\n * (Patterpad placed it there first, and the ruling ratified it).\n */\nexport function historyNav(onBack: () => void, onForward: () => void): {\n el: HTMLElement;\n set(canBack: boolean, canForward: boolean): void;\n} {\n const btn = (name: IconName, tip: string, onClick: () => void): HTMLButtonElement => {\n const b = document.createElement(\"button\");\n b.type = \"button\";\n b.className = \"shell-histnav-btn\";\n b.append(iconNode(name));\n b.dataset[\"tip\"] = tip;\n b.setAttribute(\"aria-label\", tip);\n b.addEventListener(\"click\", onClick);\n return b;\n };\n const back = btn(\"arrowLeft\", \"Back\", onBack);\n const forward = btn(\"arrowRight\", \"Forward\", onForward);\n const el = document.createElement(\"span\");\n el.className = \"shell-histnav\";\n el.append(back, forward);\n return {\n el,\n set(canBack, canForward) { back.disabled = !canBack; forward.disabled = !canForward; },\n };\n}\n"]}