@wildwinter/app-shell 0.46.5 → 0.47.0

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.
Files changed (56) hide show
  1. package/LICENSES.md +5 -4
  2. package/dist/{chunk-EHR2KBZC.js → chunk-5SQHL4YV.js} +3 -3
  3. package/dist/{chunk-EHR2KBZC.js.map → chunk-5SQHL4YV.js.map} +1 -1
  4. package/dist/{chunk-J6RSONXM.js → chunk-FPXEQKWM.js} +4 -4
  5. package/dist/{chunk-J6RSONXM.js.map → chunk-FPXEQKWM.js.map} +1 -1
  6. package/dist/{chunk-R3NXPHRZ.js → chunk-IFWLNIBR.js} +13 -5
  7. package/dist/chunk-IFWLNIBR.js.map +1 -0
  8. package/dist/{chunk-CUFREPJ5.js → chunk-IK3LWBQL.js} +4 -4
  9. package/dist/{chunk-CUFREPJ5.js.map → chunk-IK3LWBQL.js.map} +1 -1
  10. package/dist/{chunk-WKPKBAXS.js → chunk-NKL6DNBZ.js} +4 -4
  11. package/dist/{chunk-WKPKBAXS.js.map → chunk-NKL6DNBZ.js.map} +1 -1
  12. package/dist/{chunk-UG2P777F.js → chunk-QLVBKME7.js} +34 -6
  13. package/dist/chunk-QLVBKME7.js.map +1 -0
  14. package/dist/{chunk-2ECJUTSX.js → chunk-T25WXWPB.js} +3 -2
  15. package/dist/chunk-T25WXWPB.js.map +1 -0
  16. package/dist/{chunk-YRFJLJUH.js → chunk-XR4DRDMA.js} +3 -3
  17. package/dist/{chunk-YRFJLJUH.js.map → chunk-XR4DRDMA.js.map} +1 -1
  18. package/dist/{chunk-B2TC6Q5J.js → chunk-XXDJCOXN.js} +3 -3
  19. package/dist/{chunk-B2TC6Q5J.js.map → chunk-XXDJCOXN.js.map} +1 -1
  20. package/dist/context-menu.cjs.map +1 -1
  21. package/dist/context-menu.js +2 -2
  22. package/dist/dialog.cjs.map +1 -1
  23. package/dist/dialog.js +2 -2
  24. package/dist/index.cjs +63 -11
  25. package/dist/index.cjs.map +1 -1
  26. package/dist/index.d.cts +78 -11
  27. package/dist/index.d.ts +78 -11
  28. package/dist/index.js +31 -17
  29. package/dist/index.js.map +1 -1
  30. package/dist/kit-gallery.cjs.map +1 -1
  31. package/dist/kit-gallery.js +3 -3
  32. package/dist/link-status.cjs +7 -0
  33. package/dist/link-status.cjs.map +1 -1
  34. package/dist/link-status.js +2 -2
  35. package/dist/menu.cjs +1 -0
  36. package/dist/menu.cjs.map +1 -1
  37. package/dist/menu.d.cts +8 -4
  38. package/dist/menu.d.ts +8 -4
  39. package/dist/menu.js +1 -1
  40. package/dist/{property-list-D3VZCJzi.d.cts → property-list-5mS4J2uy.d.cts} +8 -2
  41. package/dist/{property-list-D3VZCJzi.d.ts → property-list-5mS4J2uy.d.ts} +8 -2
  42. package/dist/property-list.cjs +10 -2
  43. package/dist/property-list.cjs.map +1 -1
  44. package/dist/property-list.d.cts +1 -1
  45. package/dist/property-list.d.ts +1 -1
  46. package/dist/property-list.js +2 -2
  47. package/dist/settings.css +54 -0
  48. package/dist/settings.css.map +1 -1
  49. package/dist/updater-view.cjs.map +1 -1
  50. package/dist/updater-view.js +3 -3
  51. package/dist/welcome.cjs.map +1 -1
  52. package/dist/welcome.js +4 -4
  53. package/package.json +1 -1
  54. package/dist/chunk-2ECJUTSX.js.map +0 -1
  55. package/dist/chunk-R3NXPHRZ.js.map +0 -1
  56. package/dist/chunk-UG2P777F.js.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/tooltip.ts","../src/icons.ts","../src/dom.ts"],"names":["el","tip"],"mappings":"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","file":"chunk-UG2P777F.js","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"]}