panelset 1.2.0 → 1.2.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.
- package/README.md +24 -20
- package/dist/panelset-core.js +2 -1
- package/dist/panelset-core.js.map +1 -1
- package/dist/panelset.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
# PanelSet
|
|
2
2
|
|
|
3
|
+
[]() []()
|
|
4
|
+
|
|
3
5
|
**Flexible panel management with smooth transitions.**
|
|
4
6
|
|
|
5
|
-
A
|
|
7
|
+
A small library for animating elements between sizes. Three classes share one animation core (a lock / measure / animate / unlock cycle): transitions are CSS only, JavaScript only measures and sets pixel values. Accessible by default (managed ARIA and focus), interrupt-safe, and it respects `prefers-reduced-motion`.
|
|
8
|
+
|
|
9
|
+
**Documentation:** the full guides, every option, and live examples are at <https://martinomagnifico.github.io/panelset/>. This README is a quick reference.
|
|
10
|
+
|
|
6
11
|
|
|
7
|
-
> **Documentation:** this README is a quick reference. The full guides, every option, and live examples live in the HTML docs. Source and issues: <https://github.com/martinomagnifico/panelset>.
|
|
8
12
|
|
|
9
13
|
## The three classes
|
|
10
14
|
|
|
@@ -12,7 +16,7 @@ A TypeScript + SCSS library for animating elements between sizes. Three classes
|
|
|
12
16
|
|---|---|
|
|
13
17
|
| **`Panel`** | A single element that opens and closes (accordions, show-more, sidebars, drawers). Animates `height` or `width`. |
|
|
14
18
|
| **`PanelSet`** | A container that switches between mutually exclusive panels (tabs, wizards, steppers). Animates its own height to fit the incoming panel. |
|
|
15
|
-
| **`PanelControl`** | Optional. Makes a tab strip or sidebar drive a `PanelSet`: keyboard navigation, roving `tabindex`, `aria-selected
|
|
19
|
+
| **`PanelControl`** | Optional. Makes a tab strip or sidebar drive a `PanelSet`: keyboard navigation, roving `tabindex`, selection state (`aria-selected` on real tabs, `aria-current` otherwise), and tab locking through `setTabState()`. |
|
|
16
20
|
|
|
17
21
|
`PanelControl` is side-effect-free, so it tree-shakes out of the ESM build when you don’t import it.
|
|
18
22
|
|
|
@@ -73,19 +77,19 @@ Any `[aria-controls]` element is a trigger. As a shortcut, a `[data-panel-trigge
|
|
|
73
77
|
|
|
74
78
|
| Option | Type | Default | Description |
|
|
75
79
|
|---|---|---|---|
|
|
76
|
-
| `axis` | `'vertical' \| 'horizontal'` | `'vertical'` | Which dimension animates (height or width) |
|
|
77
80
|
| `align` | `'start' \| 'center' \| 'end'` | `'start'` | Content alignment within the clipped container |
|
|
78
|
-
| `transitions` | `boolean` | `true` | Enable/disable CSS transitions |
|
|
79
81
|
| `autoFocus` | `false \| true \| 'heading' \| 'first' \| 'input'` | `false` | Move focus into the panel on open |
|
|
80
|
-
| `
|
|
81
|
-
| `closeSiblings` | `boolean` | `false` | Close other open panels in the same group |
|
|
82
|
+
| `axis` | `'vertical' \| 'horizontal'` | `'vertical'` | Which dimension animates (height or width) |
|
|
82
83
|
| `closeOnResize` | `boolean` | `false` | Close the panel when the window is resized |
|
|
83
|
-
| `
|
|
84
|
-
| `
|
|
84
|
+
| `closeSiblings` | `boolean` | `false` | Close other open panels in the same group |
|
|
85
|
+
| `debug` | `boolean` | `false` | Log events to the console |
|
|
85
86
|
| `deepLink` | `boolean` | `false` | Reflect open state in the `?panel=` URL |
|
|
87
|
+
| `interruptible` | `boolean` | `true` | Allow a new open/close to interrupt one in progress |
|
|
86
88
|
| `loadingDelay` | `number` | `320` | ms before the spinner appears during async loading |
|
|
87
89
|
| `loadingHeight` | `number` | `150` | px reserved while async content loads |
|
|
88
|
-
| `
|
|
90
|
+
| `persist` | `boolean` | `false` | Save open/closed state to `localStorage` |
|
|
91
|
+
| `returnFocus` | `boolean` | `true` | Return focus to the trigger on close |
|
|
92
|
+
| `transitions` | `boolean` | `true` | Enable/disable CSS transitions |
|
|
89
93
|
|
|
90
94
|
### Async content
|
|
91
95
|
|
|
@@ -130,22 +134,22 @@ Mark the starting panel with `class="active"` and every other panel `hidden`.
|
|
|
130
134
|
| Option | Type | Default | Description |
|
|
131
135
|
|---|---|---|---|
|
|
132
136
|
| `align` | `'start' \| 'center' \| 'end'` | `'start'` | Alignment while opening/closing |
|
|
133
|
-
| `
|
|
134
|
-
| `levels` | `boolean` | `false` | Give panels a depth order from DOM position; forward/back slide opposite ways |
|
|
135
|
-
| `loop` | `boolean` | `false` | `next()` / `prev()` wrap around the ends |
|
|
137
|
+
| `autoFocus` | `false \| true \| 'heading' \| 'first' \| 'input'` | `false` | Move focus into the panel on activation |
|
|
136
138
|
| `closable` | `boolean` | `false` | Allow the whole container to open and close |
|
|
137
139
|
| `closeOnTab` | `boolean` | `false` | Clicking the active tab closes the container (needs `closable`) |
|
|
140
|
+
| `debug` | `boolean` | `false` | Log events to the console |
|
|
141
|
+
| `deepLink` | `boolean` | `false` | Reflect the active panel in the `?panel=` URL |
|
|
138
142
|
| `disabledMode` | `'aria' \| 'native'` | `'aria'` | How `data-ps-next` / `-prev` buttons are disabled at the ends |
|
|
139
|
-
| `autoFocus` | `false \| true \| 'heading' \| 'first' \| 'input'` | `false` | Move focus into the panel on activation |
|
|
140
|
-
| `returnFocus` | `boolean` | `false` | Return focus to the trigger on close |
|
|
141
143
|
| `interruptible` | `boolean` | `true` | Allow a new activation to interrupt one in progress |
|
|
142
|
-
| `
|
|
143
|
-
| `manageLabels` | `boolean` | `true` | Link each panel to its tab via `aria-labelledby` (auto-generates a tab id if needed) |
|
|
144
|
-
| `persist` | `boolean` | `false` | Save the active panel id to `localStorage` |
|
|
145
|
-
| `deepLink` | `boolean` | `false` | Reflect the active panel in the `?panel=` URL |
|
|
144
|
+
| `levels` | `boolean` | `false` | Give panels a depth order from DOM position; forward/back slide opposite ways |
|
|
146
145
|
| `loadingDelay` | `number` | `320` | ms before the spinner appears during async loading |
|
|
147
146
|
| `loadingHeight` | `number` | `150` | px reserved while async content loads |
|
|
148
|
-
| `
|
|
147
|
+
| `loop` | `boolean` | `false` | `next()` / `prev()` wrap around the ends |
|
|
148
|
+
| `manageLabels` | `boolean` | `true` | Link each panel to its tab via `aria-labelledby` (auto-generates a tab id if needed) |
|
|
149
|
+
| `manageTriggers` | `boolean` | `true` | Reflect selection (`aria-selected` on real tabs, `aria-current` otherwise) / activating state onto `[aria-controls]` triggers |
|
|
150
|
+
| `persist` | `boolean` | `false` | Save the active panel id to `localStorage` |
|
|
151
|
+
| `returnFocus` | `boolean` | `false` | Return focus to the trigger on close |
|
|
152
|
+
| `transitions` | `boolean \| { panels?: boolean, height?: boolean }` | `true` | Enable/disable transitions (or per axis) |
|
|
149
153
|
|
|
150
154
|
### Async content
|
|
151
155
|
|
package/dist/panelset-core.js
CHANGED
|
@@ -257,7 +257,8 @@ var g, _ = class i {
|
|
|
257
257
|
_updateTabTriggers(e) {
|
|
258
258
|
this.panels.forEach((t) => {
|
|
259
259
|
t.id && document.querySelectorAll(`[aria-controls="${t.id}"]`).forEach((n) => {
|
|
260
|
-
|
|
260
|
+
let r = t === e;
|
|
261
|
+
n.getAttribute("role") === "tab" && n.closest("[role=\"tablist\"]") ? (n.setAttribute("aria-selected", String(r)), n.removeAttribute("aria-current")) : (r ? n.setAttribute("aria-current", "true") : n.removeAttribute("aria-current"), n.removeAttribute("aria-selected"));
|
|
261
262
|
});
|
|
262
263
|
});
|
|
263
264
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"panelset-core.js","names":[],"sources":["../src/js/functions/core.ts","../src/js/functions/focus.ts","../src/js/functions/persist.ts","../src/js/functions/config.ts","../src/js/functions/utils.ts","../src/js/panelset.ts","../src/js/functions/pinning.ts","../src/js/panel.ts","../src/js/panelcontrol.ts","../src/js/panel.element.ts","../src/js/panelset.element.ts","../src/js/panelcontrol.element.ts","../src/js/index.ts"],"sourcesContent":["/**\n * Animation engine for dimension transitions. One instance per element.\n * start() aborts the previous cycle and returns a fresh AbortSignal.\n * Pass it to fetch() and cancelling the animation cancels the request too.\n */\n\nexport class Core {\n\tprivate _controller = new AbortController();\n\n\tget signal(): AbortSignal {\n\t\treturn this._controller.signal;\n\t}\n\n\tstart(): AbortSignal {\n\t\tthis._controller.abort();\n\t\tthis._controller = new AbortController();\n\t\treturn this._controller.signal;\n\t}\n\n\t// Always resolves. Falls back to setTimeout if transitionend never fires —\n\t// e.g. an interrupted zero-delta transition where nothing actually moves.\n\tstatic waitForTransition(el: HTMLElement, propertyName?: string): Promise<void> {\n\t\treturn new Promise(resolve => {\n\t\t\tconst s = getComputedStyle(el);\n\t\t\tconst total = (parseFloat(s.transitionDuration) || 0)\n\t\t\t + (parseFloat(s.transitionDelay) || 0);\n\t\t\tif (total === 0) return resolve();\n\n\t\t\tlet settled = false;\n\t\t\tconst finish = () => {\n\t\t\t\tif (settled) return;\n\t\t\t\tsettled = true;\n\t\t\t\tel.removeEventListener('transitionend', handler);\n\t\t\t\tresolve();\n\t\t\t};\n\t\t\tconst handler = (e: TransitionEvent) => {\n\t\t\t\tif (e.target !== el) return;\n\t\t\t\tif (propertyName && e.propertyName !== propertyName) return;\n\t\t\t\tfinish();\n\t\t\t};\n\t\t\tel.addEventListener('transitionend', handler);\n\t\t\tsetTimeout(finish, (total + 0.05) * 1000);\n\t\t});\n\t}\n}\n","/**\n * The autoFocus mode. Pass to autoFocus() after opening a panel.\n * - true : focus the panel element itself\n * - 'heading' : focus the first heading (h1–h6)\n * - 'first' : focus the first focusable element\n * - 'input' : focus the first form field (bypasses keyboard-only check)\n * - function : custom handler, called with the panel element\n */\nexport type AutoFocusMode =\n\t| boolean\n\t| 'heading'\n\t| 'first'\n\t| 'input'\n\t| ((el: HTMLElement) => void);\n\n/**\n * Move focus into a panel after it opens.\n *\n * Skips focus when the triggering event is a mouse/touch click (not\n * keyboard), except for 'input' mode which always focuses.\n */\nexport function autoFocus(el: HTMLElement, mode: AutoFocusMode, event?: Event): void {\n\tif (!mode) return;\n\n\tif (mode !== 'input' && event) {\n\t\tconst isKeyboard =\n\t\t\tevent.type.startsWith('key') ||\n\t\t\t(event instanceof MouseEvent && event.detail === 0);\n\t\tif (!isKeyboard) return;\n\t}\n\n\tconst focus = (target: HTMLElement) => {\n\t\tsetTimeout(() => target.focus(), 100);\n\t};\n\n\tif (mode === true) {\n\t\tif (!el.hasAttribute('tabindex')) el.setAttribute('tabindex', '-1');\n\t\tfocus(el);\n\t} else if (mode === 'heading') {\n\t\tconst heading = el.querySelector<HTMLElement>('h1, h2, h3, h4, h5, h6');\n\t\tif (heading) {\n\t\t\tif (!heading.hasAttribute('tabindex')) heading.setAttribute('tabindex', '-1');\n\t\t\tfocus(heading);\n\t\t}\n\t} else if (mode === 'first') {\n\t\tconst focusable = el.querySelector<HTMLElement>(\n\t\t\t'a,button,input,select,textarea,[tabindex]:not([tabindex=\"-1\"])'\n\t\t);\n\t\tif (focusable) focus(focusable);\n\t} else if (mode === 'input') {\n\t\tconst input = el.querySelector<HTMLElement>(\n\t\t\t'input:not([type=hidden]):not([disabled]),select:not([disabled]),textarea:not([disabled])'\n\t\t);\n\t\tif (input) focus(input);\n\t} else if (typeof mode === 'function') {\n\t\tsetTimeout(() => (mode as (el: HTMLElement) => void)(el), 100);\n\t}\n}\n","/**\n * URL param + localStorage.\n */\n\n\n// URL param\n\nexport const readPanelParam = (): string[] => {\n\tconst value = new URLSearchParams(location.search).get('panel');\n\treturn value ? value.split(',').filter(Boolean) : [];\n};\n\nexport const writePanelParam = (ids: string[]): void => {\n\tconst url = new URL(location.href);\n\turl.searchParams.delete('panel');\n\n\tif (ids.length) {\n\t\tconst sep = url.search ? '&' : '?';\n\t\thistory.replaceState(null, '', `${url}${sep}panel=${ids.join(',')}`);\n\t} else {\n\t\thistory.replaceState(null, '', url);\n\t}\n};\n\n\n// localStorage\n//\n// Keys are scoped to the current page path so that auto-assigned ids\n// (panel-1, panel-2, …) on different pages don't collide in shared storage.\n// A panel persisted on /accordion stays distinct from a panel-1 on /intro.\n\nconst pageScope = (key: string): string => `${location.pathname}::${key}`;\n\nexport const readStored = (key: string): string | null =>\n\tlocalStorage.getItem(pageScope(key));\n\nexport const writeStored = (key: string, value: string): void =>\n\tlocalStorage.setItem(pageScope(key), value);","type AttrType = 'string' | 'boolean' | 'number' | 'json';\n\n/** Maps each config key to its [dataset key, value type]. */\nexport type AttrMap<T> = {\n\t[K in keyof T]?: [datasetKey: string, type: AttrType];\n};\n\nfunction _coerce(value: string, type: AttrType): unknown {\n\tswitch (type) {\n\t\tcase 'string': return value;\n\t\tcase 'boolean': return value !== 'false';\n\t\tcase 'number': return parseInt(value, 10);\n\t\tcase 'json':\n\t\t\ttry { return JSON.parse(value); }\n\t\t\tcatch { return value !== 'false'; }\n\t}\n}\n\n/**\n * Parse data attributes from a DOMStringMap into a partial config object.\n * Each entry maps a config key to a [datasetKey, type] pair.\n */\nexport function parseDataAttrs<T>(dataset: DOMStringMap, attrMap: AttrMap<T>): Partial<T> {\n\tconst config: Partial<T> = {};\n\tfor (const [configKey, entry] of Object.entries(attrMap) as [keyof T & string, [string, AttrType]][]) {\n\t\tconst [datasetKey, type] = entry;\n\t\tconst value = dataset[datasetKey];\n\t\tif (value === undefined) continue;\n\t\t(config as Record<string, unknown>)[configKey] = _coerce(value, type);\n\t}\n\treturn config;\n}\n\n/**\n * Parse plain element attributes into a partial config object.\n * Uses the same AttrMap as parseDataAttrs but reads from element.getAttribute()\n * instead of dataset. The datasetKey is converted from camelCase to kebab-case\n * to form the attribute name (e.g. \"panelAxis\" > \"panel-axis\").\n */\nexport function parseAttrs<T>(element: Element, attrMap: AttrMap<T>): Partial<T> {\n\tconst config: Partial<T> = {};\n\tfor (const [configKey, entry] of Object.entries(attrMap) as [keyof T & string, [string, AttrType]][]) {\n\t\tconst [datasetKey, type] = entry;\n\t\tconst attrName = datasetKey.replace(/([A-Z])/g, '-$1').toLowerCase();\n\t\tconst value = element.getAttribute(attrName);\n\t\tif (value === null) continue;\n\t\t(config as Record<string, unknown>)[configKey] = _coerce(value, type);\n\t}\n\treturn config;\n}\n","/**\n * Shared debug logger. Both Panel and PanelSet use this pattern.\n */\nexport function log(prefix: string, element: HTMLElement, debug: boolean, message: string): void {\n\tif (!debug) return;\n\tconsole.log(`[${prefix}] \"${element.id || 'no id'}\" -`, message);\n}\n\n\n/**\n * Add or remove id token(s) on an element's aria-describedby, leaving any other\n * tokens (author-set descriptions) intact. `ids` may be a single id or a\n * space-separated list. Used to attach a \"why is this disabled\" hint only while\n * a control is disabled, so it is not announced when the control is enabled.\n */\nexport function setDescribedBy(el: HTMLElement, ids: string, present: boolean): void {\n\tconst want = ids.split(/\\s+/).filter(Boolean);\n\tif (!want.length) return;\n\tconst cur = (el.getAttribute('aria-describedby') || '').split(/\\s+/).filter(Boolean);\n\tlet changed = false;\n\tfor (const id of want) {\n\t\tconst has = cur.includes(id);\n\t\tif (present && !has) { cur.push(id); changed = true; }\n\t\telse if (!present && has) { cur.splice(cur.indexOf(id), 1); changed = true; }\n\t}\n\tif (!changed) return;\n\tif (cur.length) el.setAttribute('aria-describedby', cur.join(' '));\n\telse el.removeAttribute('aria-describedby');\n}\n\n\nlet _interpolateSizeLogged = false;\n\n/**\n * Logs browser interpolate-size support once across all Panel and PanelSet instances.\n * No-ops if debug is false or the message has already been logged.\n */\nexport function logInterpolateSizeOnce(debug: boolean): void {\n\tif (!debug || _interpolateSizeLogged) return;\n\t_interpolateSizeLogged = true;\n\tconsole.log(\"[Panel/PanelSet] Browser supports 'interpolate-size', which will be used for opening and closing.\");\n}\n\n\n/** A before-open event detail that carries an awaitable promise for async content. */\nexport interface Awaitable {\n\t/** Underlying mechanism the open awaits; prefer waitUntil(). */\n\tpromise: Promise<unknown> | null;\n\t/** Delay the open until p resolves. Safe to call more than once (the open awaits\n\t * all of them), and safe to destructure (it closes over the detail, not `this`). */\n\twaitUntil(p: Promise<unknown>): void;\n}\n\n/**\n * Wire detail.waitUntil() so it sets detail.promise, combining via Promise.all when\n * called more than once. Direct `detail.promise = …` keeps working alongside it.\n */\nexport function attachWaitUntil(detail: Awaitable): void {\n\tdetail.waitUntil = (p) => {\n\t\tdetail.promise = detail.promise ? Promise.all([detail.promise, p]) : p;\n\t};\n}\n\n/**\n * Register an async content handler on a CustomEvent.\n * The handler receives the target element and an AbortSignal.\n * If it returns a Promise, it is handed to event.detail.waitUntil() so the\n * consuming code awaits it (combining with any other waitUntil calls).\n * Pass once:true to skip the handler after the first successful load\n * (tracked via target.dataset.loaded).\n */\nexport function registerBeforeOpenHandler<D extends Awaitable & { signal: AbortSignal }>(\n\telement: HTMLElement,\n\teventName: string,\n\tgetTarget: (detail: D) => HTMLElement,\n\thandler: (target: HTMLElement, signal: AbortSignal) => Promise<void> | void,\n\toptions: { once?: boolean } = {}\n): void {\n\tconst once = options.once === true;\n\telement.addEventListener(eventName, (e) => {\n\t\tconst event = e as CustomEvent<D>;\n\t\tconst target = getTarget(event.detail);\n\t\tconst { signal } = event.detail;\n\t\tif (once && target.dataset.loaded === 'true') return;\n\t\tconst result = handler(target, signal);\n\t\tif (result && typeof result.then === 'function') {\n\t\t\tevent.detail.waitUntil(result.then(() => {\n\t\t\t\tif (once) target.dataset.loaded = 'true';\n\t\t\t}));\n\t\t}\n\t});\n}\n","import '../style/panelset.scss';\nimport { Core } from './functions/core.js';\nimport { autoFocus } from './functions/focus.js';\nimport type { AutoFocusMode } from './functions/focus.js';\nimport { readPanelParam, writePanelParam, readStored, writeStored } from './functions/persist.js';\n\n\nimport type { PanelSetConfig, ReadyEventDetail, BeforeActivateEventDetail, BeforeOpenEventDetail, ActivationEventDetail, ActivationAbortedEventDetail, HandlerOptions, ShowOptions, AsyncContentHandler } from './panelset.types.js';\nimport { parseDataAttrs, type AttrMap } from './functions/config.js';\nimport { log, logInterpolateSizeOnce, registerBeforeOpenHandler, attachWaitUntil, setDescribedBy } from './functions/utils.js';\n\ndeclare global {\n\tinterface HTMLElement {\n\t\tpanelSet?: PanelSet;\n\t}\n}\n\nexport class PanelSet {\n\t// Default configuration\n\tstatic defaults: Required<Omit<PanelSetConfig, 'selector'>> = {\n\t\talign: 'start',\n\t\ttransitions: true,\n\t\tlevels: false,\n\t\tloop: false,\n\t\tclosable: false,\n\t\tcloseOnTab: false,\n\t\tdisabledMode: 'aria',\n\t\tloadingHeight: 150,\n\t\tloadingDelay: 320,\n\t\treturnFocus: false,\n\t\tautoFocus: false,\n\t\tpersist: false,\n\t\tdeepLink: false,\n\t\tinterruptible: true,\n\t\tmanageTriggers: true,\n\t\tmanageLabels: true,\n\t\tdebug: false\n\t};\n\n\t// Instance properties\n\telement!: HTMLElement;\n\tconfig!: Required<Omit<PanelSetConfig, 'selector'>>;\n\tpanels!: HTMLElement[];\n\tactivePanel!: HTMLElement;\n\tpanelWrapper!: HTMLElement;\n\tpendingPanel!: HTMLElement;\n\t/** True once an async content handler has been registered via onBeforeOpen(). */\n\thasAsyncContent: boolean = false;\n\n\tprivate _animShow = new Core(); // panel switching + async content\n\tprivate _animOpenClose = new Core(); // container open/close\n\tprivate _isLoadingAsync: boolean = false;\n\tprivate _activating: boolean = false;\n\tprivate _switchDirection: 'levelup' | 'leveldown' | null = null;\n\tprivate _returnFocusTarget: HTMLElement | null = null;\n\tprivate _heightObserver: ResizeObserver | null = null;\n\t// Listeners for end-of-range reflection on this set's verb buttons; aborted on\n\t// destroy so a torn-down instance stops reflecting.\n\tprivate _verbController = new AbortController();\n\n\tprivate static readonly _nativeInterpolateSize =\n\t\ttypeof CSS !== 'undefined' && CSS.supports('interpolate-size: allow-keywords');\n\n\t// One document-level click listener, shared across all PanelSet instances,\n\t// handles the verb buttons (data-ps-next / -prev / -close). Delegation (not\n\t// per-instance binding) is required because verb buttons commonly live inside\n\t// async-loaded panel content that does not exist at init. Installed lazily on\n\t// first construction — same spirit as logInterpolateSizeOnce.\n\tprivate static _verbDelegationInstalled = false;\n\n\tstatic readonly attrs: AttrMap<PanelSetConfig> = {\n\t\talign: ['panelsetAlign', 'string'],\n\t\ttransitions: ['transitions', 'json'],\n\t\tlevels: ['psLevels', 'boolean'],\n\t\tloop: ['psLoop', 'boolean'],\n\t\tclosable: ['closable', 'boolean'],\n\t\tcloseOnTab: ['closeOnTab', 'boolean'],\n\t\tdisabledMode: ['psDisabledMode', 'string'],\n\t\tloadingHeight: ['loadingHeight', 'number'],\n\t\tloadingDelay: ['loadingDelay', 'number'],\n\t\tautoFocus: ['autoFocus', 'string'],\n\t\treturnFocus: ['returnFocus', 'boolean'],\n\t\tpersist: ['panelPersist', 'boolean'],\n\t\tdeepLink: ['panelDeeplink', 'boolean'],\n\t\tinterruptible: ['interruptible', 'boolean'],\n\t\tmanageTriggers: ['manageTriggers', 'boolean'],\n\t\tmanageLabels: ['manageLabels', 'boolean'],\n\t\tdebug: ['debug', 'boolean'],\n\t};\n\n\t/**\n\t * Initialize PanelSet instances\n\t * @param selectorOrOptions - CSS selector string or config object\n\t * @param options - Additional config options (when first param is selector)\n\t * @returns Array of PanelSet instances\n\t */\n\tstatic init(selectorOrOptions: string | PanelSetConfig = {}, options: PanelSetConfig = {}): PanelSet[] {\n\t\t// Handle different call signatures\n\t\tlet selector: string;\n\t\tlet config: PanelSetConfig;\n\n\t\tif (typeof selectorOrOptions === 'string') {\n\t\t\t// init('#demo') or init('#demo', {debug: true})\n\t\t\tselector = selectorOrOptions;\n\t\t\tconfig = options;\n\t\t} else {\n\t\t\t// init() or init({selector: '#demo', debug: true})\n\t\t\tconfig = selectorOrOptions;\n\t\t\tselector = config.selector || '[data-panelset]';\n\t\t}\n\n\t\tconst elements = document.querySelectorAll<HTMLElement>(selector);\n\t\tconst instances: PanelSet[] = [];\n\n\t\telements.forEach(el => {\n\n\t\t\ttry {\n\t\t\t\tPanelSet._validateElement(el);\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error((error as Error).message);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Skip if already initialized\n\t\t\tif (el.panelSet) {\n\t\t\t\tinstances.push(el.panelSet);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst instance = new PanelSet(el, config);\n\t\t\tinstances.push(instance);\n\t\t});\n\n\t\treturn instances;\n\t}\n\n\tconstructor(elementOrSelector: HTMLElement | string, options: PanelSetConfig = {}) {\n\t\t// Handle both element and selector\n\t\tlet element: HTMLElement | null;\n\t\tif (typeof elementOrSelector === 'string') {\n\t\t\telement = document.querySelector<HTMLElement>(elementOrSelector);\n\t\t\tif (!element) {\n\t\t\t\tthrow new Error(`PanelSet: No element found for selector \"${elementOrSelector}\"`);\n\t\t\t}\n\t\t} else {\n\t\t\telement = elementOrSelector;\n\t\t}\n\n\t\tthis.element = element;\n\n\t\t// Validate element\n\t\tPanelSet._validateElement(element);\n\n\t\t// Check if already initialized\n\t\tif (element.panelSet) {\n\t\t\tconsole.warn('PanelSet: already initialized');\n\t\t\treturn element.panelSet!;\n\t\t}\n\n\t\t// Store instance on element\n\t\telement.panelSet = this;\n\n\t\t// Install the shared verb-button click delegation once (self-guards).\n\t\tPanelSet._installVerbDelegation();\n\n\t\t// Precedence: defaults < init() options < per-element data-attributes.\n\t\t// The attribute is the most specific signal, so it wins — this lets an\n\t\t// element opt out of a global flag, e.g. data-panel-persist=\"false\"\n\t\t// overriding PanelSet.init({ persist: true }).\n\t\t\n\t\tconst dataConfig = parseDataAttrs<PanelSetConfig>(element.dataset, PanelSet.attrs);\n\t\tthis.config = { ...PanelSet.defaults, ...options, ...dataConfig } as Required<Omit<PanelSetConfig, 'selector'>>;\n\n\t\t// Only this set's own panels (a nested PanelSet/Panel would otherwise have\n\t\t// its panels claimed by the outer instance). See _collectPanels.\n\t\tthis.panels = this._collectPanels();\n\n\t\tif (this.panels.length === 0) {\n\t\t\t// An empty set is valid for dynamic / windowed flows that addPanel() their\n\t\t\t// panels later. Establish the wrapper so addPanel() has somewhere to insert;\n\t\t\t// activePanel / pendingPanel are assigned on the first add (via refresh()).\n\t\t\tthis.panelWrapper =\n\t\t\t\tthis.element.querySelector<HTMLElement>(':scope > .panel-wrapper') || this._autoWrapPanels();\n\t\t\tthis._log('Initialized empty (0 panels) — ready for addPanel()');\n\t\t\tthis._dispatch<ReadyEventDetail>('ps:ready', { container: this.element, instance: this });\n\t\t\tthis._initVerbButtons();\n\t\t\tthis._observeTrackHeight();\n\t\t\treturn;\n\t\t}\n\n\n\t\tconst resolvedId = this._resolveInitialPanel();\n\t\tthis.activePanel =\n\t\t\t(resolvedId ? this.panels.find(p => p.id === resolvedId) : null)\n\t\t\t?? this.panels.find(p => p.classList.contains('active'))\n\t\t\t?? this.panels[0];\n\t\t// Direct-child wrapper only — a descendant query could return a nested\n\t\t// component's wrapper.\n\t\tthis.panelWrapper =\n\t\t\tthis.element.querySelector<HTMLElement>(':scope > .panel-wrapper') || this._autoWrapPanels();\n\n\t\tthis.pendingPanel = this.activePanel;\n\n\n\n\n\t\t// 'start' is the default (no CSS targets it), so only stamp the attribute\n\t\t// for non-default alignments — mirrors Panel and keeps the DOM clean.\n\t\tif (this.config.align !== 'start') this.element.dataset.panelsetAlign = this.config.align;\n\n\t\t// this.element.setAttribute('data-panelset-ready', ''); // For styling (turning this off for now)\n\n\t\t// Closable sets are closed by default; only an explicit .is-open opens them.\n\t\t// A closed set is inert until opened.\n\t\tif (this.config.closable && !this.element.classList.contains('is-open')) {\n\t\t\tthis.element.setAttribute('inert', '');\n\t\t}\n\n\t\tif (PanelSet._nativeInterpolateSize) logInterpolateSizeOnce(this.config.debug);\n\t\tthis._log(`Initialized (${this.panels.length} panels)`);\n\t\tthis._dispatch<ReadyEventDetail>('ps:ready', { container: this.element, instance: this });\n\n\t\tthis._internalInit();\n\n\t\tthis._initVerbButtons();\n\n\t\tthis._observeTrackHeight();\n\n\t}\n\n\t// Re-measure the tallest panel whenever the tracking parent's WIDTH changes.\n\t// A ResizeObserver reacts to any layout change (window, flex, container\n\t// queries), not just window resize, and updates promptly instead of after a\n\t// debounce — so --ps-max-height stays in step with the current width. We\n\t// guard on width because our own height writes would otherwise re-trigger it.\n\tprivate _observeTrackHeight(): void {\n\t\tconst trackingParent = this.element.closest<HTMLElement>('[data-panelset-trackheight]');\n\t\tif (!trackingParent || typeof ResizeObserver === 'undefined') return;\n\n\t\tlet lastWidth = trackingParent.clientWidth;\n\t\tlet rafId = 0;\n\t\tthis._heightObserver = new ResizeObserver(() => {\n\t\t\tconst width = trackingParent.clientWidth;\n\t\t\tif (width === lastWidth) return;\n\t\t\tlastWidth = width;\n\t\t\tcancelAnimationFrame(rafId);\n\t\t\trafId = requestAnimationFrame(() => this._updateHighestPanel());\n\t\t});\n\t\tthis._heightObserver.observe(trackingParent);\n\t}\n\n\t// Debug logging helper\n\tprivate _log(message: string): void { log('PanelSet', this.element, this.config.debug, message); }\n\n\t// Closed = a closable set without the .is-open class (and not mid-open).\n\t// Non-closable tabsets are conceptually always open, so never \"closed\".\n\tprivate get _isClosed(): boolean {\n\t\treturn this.config.closable\n\t\t\t&& !this.element.classList.contains('is-open')\n\t\t\t&& !this.element.classList.contains('is-opening');\n\t}\n\n\t// URL param + localStorage helpers\n\n\tprivate _parsePanelParam = (): string | null => {\n\t\tconst ids = readPanelParam();\n\t\treturn this.panels.find(p => p.id && ids.includes(p.id))?.id ?? null;\n\t};\n\n\tprivate _persistState = (panelId: string): void => {\n\t\tif (this.config.persist && this.element.id) writeStored(`ps:${this.element.id}`, panelId);\n\t\tif (this.config.deepLink) {\n\t\t\tthis._updatePanelParam(panelId);\n\t\t} else {\n\t\t\t// No deepLink: clean up any stale ?panel= IDs left by a snap-open.\n\t\t\tconst myIds = new Set(this.panels.map(p => p.id).filter(Boolean));\n\t\t\tconst current = readPanelParam();\n\t\t\tif (current.some(id => myIds.has(id))) writePanelParam(current.filter(id => !myIds.has(id)));\n\t\t}\n\t};\n\n\tprivate _updatePanelParam = (panelId: string): void => {\n\t\tconst myIds = new Set(this.panels.map(p => p.id).filter(Boolean));\n\t\tconst next = [...readPanelParam().filter(id => !myIds.has(id)), panelId].filter(Boolean);\n\t\twritePanelParam(next);\n\t};\n\n\tprivate _resolveInitialPanel = (): string | null => {\n\t\t// URL param is always honoured: a ?panel=id link is explicit and\n\t\t// page-specific, so shareable deep links work with no config.\n\t\tconst fromUrl = this._parsePanelParam();\n\t\tif (fromUrl) return fromUrl;\n\t\t// localStorage is opt-in only, so a stale entry can't override the markup\n\t\t// .active panel unless this set actually persists.\n\t\tif (this.config.persist) {\n\t\t\tconst { id } = this.element;\n\t\t\tif (!id) return null;\n\t\t\tconst saved = readStored(`ps:${id}`);\n\t\t\treturn saved && this.panels.some(p => p.id === saved) ? saved : null;\n\t\t}\n\t\treturn null;\n\t};\n\n\tprivate static _validateElement(element: HTMLElement): void {\n\t\tif (!element.hasAttribute('data-panelset') && !element.tagName.includes('-')) {\n\t\t\tthrow new Error('PanelSet: element must have [data-panelset] or be a custom element');\n\t\t}\n\t}\n\n\tprivate _autoWrapPanels(): HTMLElement {\n\t\tconst wrapper = document.createElement('div');\n\t\twrapper.className = 'panel-wrapper';\n\t\tthis.panels.forEach(panel => wrapper.appendChild(panel));\n\t\tthis.element.appendChild(wrapper);\n\t\treturn wrapper;\n\t}\n\n\t// Collect this set's own [role=\"tabpanel\"] panels. querySelectorAll is\n\t// unscoped, so a nested PanelSet/Panel could otherwise have its panels claimed\n\t// by an outer instance; closest() keeps only panels whose nearest panelset/\n\t// panel container is this element.\n\tprivate _collectPanels(): HTMLElement[] {\n\t\tconst ownContainer = (el: HTMLElement): boolean =>\n\t\t\tel.closest('[data-panelset], ps-panelset, [data-panel], ps-panel') === this.element;\n\t\treturn Array.from(this.element.querySelectorAll<HTMLElement>('[role=\"tabpanel\"]')).filter(ownContainer);\n\t}\n\n\tprivate _internalInit(): void {\n\t\tthis.panels.forEach(panel => {\n\t\t\tpanel.classList.remove('fade', 'incoming', 'outgoing', 'levelup', 'leveldown');\n\t\t\tif (panel !== this.activePanel) {\n\t\t\t\tpanel.hidden = true;\n\t\t\t\tpanel.classList.remove('active');\n\t\t\t} else {\n\t\t\t\tpanel.hidden = false;\n\t\t\t\tpanel.classList.add('active');\n\t\t\t}\n\t\t});\n\t\tthis.element.style.height = '';\n\t\tthis._updateHighestPanel();\n\t\tif (this.config.manageTriggers) this._updateTabTriggers(this.activePanel);\n\t\tif (this.config.manageLabels) this._reflectLabels();\n\t}\n\t\n\n\t// Dispatch custom event helper\n\tprivate _dispatch<T = unknown>(eventName: string, detail: T): void {\n\t\tthis.element.dispatchEvent(\n\t\t\tnew CustomEvent(eventName, {\n\t\t\t\tdetail,\n\t\t\t\tbubbles: true,\n\t\t\t\tcancelable: false\n\t\t\t})\n\t\t);\n\t}\n\n\t/* --- Modular helpers --- */\n\n\tprivate _getVerticalMetrics(el: HTMLElement | null): number {\n\t\tif (!el) return 0;\n\t\tconst s = getComputedStyle(el);\n\t\treturn (parseFloat(s.paddingTop) || 0) + (parseFloat(s.paddingBottom) || 0)\n\t\t + (parseFloat(s.borderTopWidth) || 0) + (parseFloat(s.borderBottomWidth) || 0);\n\t}\n\n\tprivate _measureHeight(panel: HTMLElement): number {\n\t\tlet total = panel.offsetHeight;\n\t\ttotal += this._getVerticalMetrics(this.panelWrapper);\n\t\ttotal += this._getVerticalMetrics(this.element);\n\t\treturn total;\n\t}\n\n\tprivate _updateHighestPanel(): void {\n\t\tif (this.element.hasAttribute('data-panelset-trackheight')) {\n\t\t\tconsole.warn('PanelSet: data-panelset-trackheight on parent only');\n\t\t\treturn;\n\t\t}\n\t\tconst trackingParent = this.element.closest<HTMLElement>('[data-panelset-trackheight]');\n\t\tif (!trackingParent) return;\n\n\t\t// Hide all panels before measuring each one individually.\n\t\tthis.panels.forEach(p => { p.hidden = true; p.classList.remove('active'); });\n\n\t\tlet max = 0;\n\t\tthis.panels.forEach(panel => {\n\t\t\tpanel.hidden = false;\n\t\t\tpanel.classList.add('active');\n\t\t\tpanel.style.visibility = 'hidden';\n\t\t\tconst h = this.element.offsetHeight;\n\t\t\tif (h > max) max = h;\n\t\t\tpanel.hidden = true;\n\t\t\tpanel.classList.remove('active');\n\t\t\tpanel.style.visibility = '';\n\t\t});\n\n\t\t// Restore the active panel.\n\t\tif (this.activePanel) {\n\t\t\tthis.activePanel.hidden = false;\n\t\t\tthis.activePanel.classList.add('active');\n\t\t}\n\n\t\ttrackingParent.style.setProperty('--ps-max-height', `${max}px`);\n\t\tthis._log(`Max container height: ${max}px`);\n\t}\n\n\tprivate _updateTabTriggers(activePanel: HTMLElement): void {\n\t\tthis.panels.forEach(panel => {\n\t\t\tif (!panel.id) return;\n\t\t\tdocument.querySelectorAll<HTMLElement>(`[aria-controls=\"${panel.id}\"]`).forEach(trigger => {\n\t\t\t\ttrigger.setAttribute('aria-selected', String(panel === activePanel));\n\t\t\t});\n\t\t});\n\t}\n\n\t// Auto-label each panel from the trigger that controls it (the reverse of the\n\t// [aria-controls] link). This is static structure, so it runs at init / refresh\n\t// only, never on activation. Conservative: it never overrides an existing\n\t// accessible name, and only acts when one trigger unambiguously controls the panel.\n\tprivate _reflectLabels(): void {\n\t\tthis.panels.forEach(panel => {\n\t\t\tif (!panel.id) return;\n\t\t\tif (panel.hasAttribute('aria-labelledby') || panel.hasAttribute('aria-label')) return;\n\n\t\t\tconst triggers = Array.from(\n\t\t\t\tdocument.querySelectorAll<HTMLElement>(`[aria-controls=\"${panel.id}\"]`)\n\t\t\t);\n\t\t\tif (triggers.length === 0) return;\n\n\t\t\t// Prefer a single role=\"tab\" when several controls point at this panel\n\t\t\t// (e.g. a tab plus a remote control); otherwise require exactly one trigger.\n\t\t\tconst tabs = triggers.filter(t => t.getAttribute('role') === 'tab');\n\t\t\tconst labelling = tabs.length === 1 ? tabs[0]\n\t\t\t\t: triggers.length === 1 ? triggers[0]\n\t\t\t\t: null;\n\t\t\tif (!labelling) return; // ambiguous — leave naming to the author\n\n\t\t\tif (!labelling.id) labelling.id = this._uniqueId(`${panel.id}-tab`);\n\t\t\tpanel.setAttribute('aria-labelledby', labelling.id);\n\t\t});\n\t}\n\n\t// A document-unique id derived from a base, for a generated trigger id.\n\tprivate _uniqueId(base: string): string {\n\t\tlet id = base, n = 2;\n\t\twhile (document.getElementById(id)) id = `${base}-${n++}`;\n\t\treturn id;\n\t}\n\n\tprivate _setTriggersActivating(active: boolean): void {\n\t\tthis.panels.forEach(panel => {\n\t\t\tif (!panel.id) return;\n\t\t\tdocument.querySelectorAll<HTMLElement>(`[aria-controls=\"${panel.id}\"]`).forEach(trigger => {\n\t\t\t\ttrigger.classList.toggle('is-activating', active);\n\t\t\t});\n\t\t});\n\t}\n\n\tprivate _cleanupPanels(newPanel: HTMLElement): void {\n\t\tthis.panels.forEach(panel => {\n\t\t\tpanel.classList.remove('fade', 'incoming', 'outgoing', 'levelup', 'leveldown');\n\t\t\tif (panel !== newPanel) {\n\t\t\t\tpanel.classList.remove('active');\n\t\t\t\tpanel.hidden = true;\n\t\t\t} else {\n\t\t\t\tpanel.classList.add('active');\n\t\t\t\tpanel.hidden = false;\n\t\t\t\tpanel.removeAttribute('inert');\n\t\t\t}\n\t\t});\n\t\tthis.element.style.height = '';\n\t\tthis.element.classList.remove('is-transitioning');\n\t\tthis.activePanel = newPanel;\n\t\tif (this.config.manageTriggers) this._updateTabTriggers(newPanel);\n\t}\n\n\tprivate _resolveAutoFocus(resolvedTrigger: HTMLElement | null, autoFocus?: AutoFocusMode): AutoFocusMode | undefined {\n\t\tif (this.config.manageTriggers) {\n\t\t\tconst attrValue = resolvedTrigger?.getAttribute('data-auto-focus');\n\t\t\tif (attrValue != null) {\n\t\t\t\tif (attrValue === 'true') return true;\n\t\t\t\tif (attrValue === 'false') return false;\n\t\t\t\tif (attrValue === 'heading' || attrValue === 'first' || attrValue === 'input') return attrValue as AutoFocusMode;\n\t\t\t}\n\t\t}\n\t\tif (autoFocus !== undefined) return autoFocus;\n\t\treturn this.config.autoFocus;\n\t}\n\n\tprivate _handleAutoFocus(panel: HTMLElement, mode: AutoFocusMode, event?: Event): void {\n\t\tautoFocus(panel, mode, event);\n\t}\n\n\t// Shared helper for open/close\n\tprivate _animateOpenClose(isOpening: boolean, withTransition: boolean, event?: Event): void {\n\t\tconst action = isOpening ? 'opening' : 'closing';\n\t\tconst oppositeClass = `is-${isOpening ? 'closing' : 'opening'}`;\n\t\tconst actionClass = `is-${action}`;\n\n\t\tthis._log(isOpening ? 'Opening' : 'Closing');\n\n\t\tconst signal = this._animOpenClose.start();\n\n\t\t// Capture position before removing the opposite class — needed to resume\n\t\t// from where it is, not from the start, when reversing mid-animation.\n\t\tconst isReversing = this.element.classList.contains(oppositeClass);\n\t\tconst reverseStartHeight = isReversing ? this.element.offsetHeight : null;\n\n\t\t// Capture the open height BEFORE removing is-open. Since closable sets are\n\t\t// closed-by-default (height:0 when not .is-open), removing is-open collapses\n\t\t// the resting height immediately — so a later offsetHeight read would return 0\n\t\t// and the close would animate 0 → 0 (no transition). This is the real \"from\".\n\t\tconst closeStartHeight = !isOpening ? this.element.offsetHeight : null;\n\n\t\tthis.element.classList.remove(oppositeClass);\n\t\tif (!isOpening) this.element.classList.remove('is-open');\n\n\t\tif (isOpening) this.element.removeAttribute('inert');\n\n\t\t// Settle into the closed resting state (no is-open class) and restore focus.\n\t\tconst settleClosed = () => {\n\t\t\tthis.element.setAttribute('inert', '');\n\t\t\tconst byPointer = event instanceof PointerEvent && event.pointerType !== '';\n\t\t\tif (this.config.returnFocus && this._returnFocusTarget && !byPointer) {\n\t\t\t\tthis._returnFocusTarget.focus();\n\t\t\t}\n\t\t};\n\n\t\tif (withTransition && this.config.transitions) {\n\t\t\t// Mirror Panel exactly: animate under the .is-opening / .is-closing class\n\t\t\t// only, never pinning the wrapper. The wrapper reveal lives entirely in CSS\n\t\t\t// (.is-opening / .is-closing .panel-wrapper) and animates from whatever value\n\t\t\t// is currently committed — so a reclick mid-transition just swaps the class\n\t\t\t// and the browser interpolates from the live position. .is-open is added only\n\t\t\t// once the animation settles. height:auto during opening comes from the\n\t\t\t// @supports .is-opening rule, so is-open is not needed mid-animation.\n\t\t\tthis.element.classList.add(actionClass);\n\n\t\t\tif (PanelSet._nativeInterpolateSize) {\n\t\t\t\tif (isOpening) {\n\t\t\t\t\tthis.element.style.height = reverseStartHeight !== null ? `${reverseStartHeight}px` : '0px';\n\t\t\t\t\trequestAnimationFrame(() => {\n\t\t\t\t\t\tthis.element.style.height = ''; // .is-opening's height: auto takes over\n\t\t\t\t\t\tCore.waitForTransition(this.element, 'height').then(() => {\n\t\t\t\t\t\t\tif (signal.aborted) return;\n\t\t\t\t\t\t\t// Wait for the wrapper transition too — its GPU layer keeps the\n\t\t\t\t\t\t\t// clip alive in WebKit until it finishes.\n\t\t\t\t\t\t\tconst wrapperDone = this.panelWrapper\n\t\t\t\t\t\t\t\t? Core.waitForTransition(this.panelWrapper)\n\t\t\t\t\t\t\t\t: Promise.resolve();\n\t\t\t\t\t\t\twrapperDone.then(() => {\n\t\t\t\t\t\t\t\tif (signal.aborted) return;\n\t\t\t\t\t\t\t\tthis.element.classList.remove(actionClass);\n\t\t\t\t\t\t\t\tthis.element.classList.add('is-open');\n\t\t\t\t\t\t\t\tvoid this.element.offsetHeight;\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t});\n\t\t\t\t\t});\n\t\t\t\t} else {\n\t\t\t\t\t// Lock at px — interpolate-size alone can't animate auto → 0 in Firefox.\n\t\t\t\t\t// Use the height captured before is-open was removed (resting height\n\t\t\t\t\t// is already 0 now that the class is gone).\n\t\t\t\t\tthis.element.style.height = reverseStartHeight !== null\n\t\t\t\t\t\t? `${reverseStartHeight}px`\n\t\t\t\t\t\t: `${closeStartHeight}px`;\n\t\t\t\t\trequestAnimationFrame(() => {\n\t\t\t\t\t\tthis.element.style.height = ''; // closed resting height: 0 takes over\n\t\t\t\t\t\tCore.waitForTransition(this.element, 'height').then(() => {\n\t\t\t\t\t\t\tif (signal.aborted) return;\n\t\t\t\t\t\t\tthis.element.classList.remove(actionClass);\n\t\t\t\t\t\t\tvoid this.element.offsetHeight;\n\t\t\t\t\t\t\tsettleClosed();\n\t\t\t\t\t\t});\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// JS fallback: measure > lock > animate > unlock\n\t\t\t\tconst targetHeight = isOpening ? this._measureHeight(this.pendingPanel) : 0;\n\t\t\t\t// On open the current height is the (closed) start, unless reversing a\n\t\t\t\t// close mid-flight; on close use the height captured before is-open was\n\t\t\t\t// removed (resting height is already 0).\n\t\t\t\tconst currentHeight = reverseStartHeight !== null\n\t\t\t\t\t? reverseStartHeight\n\t\t\t\t\t: (isOpening ? this.element.offsetHeight : (closeStartHeight ?? 0));\n\t\t\t\tthis.element.style.height = `${currentHeight}px`;\n\t\t\t\t// Force a flush so the Npx lock is committed before the rAF changes it.\n\t\t\t\t// Without it the lock is overwritten and Firefox sees auto → 0px in one\n\t\t\t\t// step — non-animatable, so it jumps.\n\t\t\t\tvoid getComputedStyle(this.element).height;\n\n\t\t\t\trequestAnimationFrame(() => {\n\t\t\t\t\tthis.element.style.height = `${targetHeight}px`;\n\n\t\t\t\t\tCore.waitForTransition(this.element).then(() => {\n\t\t\t\t\t\tif (signal.aborted) return;\n\t\t\t\t\t\tthis.element.style.height = '';\n\t\t\t\t\t\tthis.element.classList.remove(actionClass);\n\t\t\t\t\t\tif (isOpening) this.element.classList.add('is-open');\n\t\t\t\t\t\tvoid this.element.offsetHeight;\n\t\t\t\t\t\tif (!isOpening) settleClosed();\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t}\n\t\t} else {\n\t\t\tif (isOpening) {\n\t\t\t\tthis.element.classList.add('is-open');\n\t\t\t} else {\n\t\t\t\tthis.element.classList.remove('is-open');\n\t\t\t\tsettleClosed();\n\t\t\t}\n\t\t\tthis.element.style.height = '';\n\t\t}\n\t}\n\n\t/**\n\t * Get the ID of the currently active panel\n\t * @returns Panel ID or null if no panel is active\n\t */\n\tgetActive(): string | null {\n\t\treturn this.pendingPanel?.id || null;\n\t}\n\n\t/**\n\t * Re-scan the DOM for this set's panels and reconcile internal state — the\n\t * active panel, trigger state, and the Prev/Next end-of-range disabling. Call\n\t * after adding, removing, or reordering [role=\"tabpanel\"] elements at runtime\n\t * (e.g. lazy or windowed wizards). The active panel is preserved when it is\n\t * still present; otherwise it falls back to the marked .active panel, then the\n\t * first panel. Newly added panels are initialised to the hidden state.\n\t * Call when idle (not mid-transition).\n\t */\n\trefresh(): void {\n\t\tconst previousActive = this.activePanel;\n\t\tthis.panels = this._collectPanels();\n\t\tif (this.panels.length === 0) return;\n\n\t\tthis.activePanel = (previousActive && this.panels.includes(previousActive))\n\t\t\t? previousActive\n\t\t\t: (this.panels.find(p => p.classList.contains('active')) ?? this.panels[0]);\n\t\tthis.pendingPanel = this.activePanel;\n\t\t// A runtime-added wrapper (or first wrap) may differ from the cached one.\n\t\tthis.panelWrapper = this.element.querySelector<HTMLElement>(':scope > .panel-wrapper') || this.panelWrapper;\n\n\t\tthis._internalInit();\n\t\tthis._reflectEnds(); // add/remove/reorder may change first/last → re-sync verb buttons\n\t\tthis._log(`Refreshed (${this.panels.length} panels)`);\n\t}\n\n\t/**\n\t * Insert a panel at runtime and refresh. The node is appended to the wrapper\n\t * unless a position is given. Ensures the element carries role=\"tabpanel\".\n\t * @param panel - The [role=\"tabpanel\"] element to add.\n\t * @param position - { before } / { after } an existing panel id, or { index }.\n\t * @returns The inserted panel.\n\t */\n\taddPanel(panel: HTMLElement, position?: { before?: string; after?: string; index?: number }): HTMLElement {\n\t\tif (!panel.hasAttribute('role')) panel.setAttribute('role', 'tabpanel');\n\n\t\tlet ref: HTMLElement | null = null;\n\t\tif (position?.before) {\n\t\t\tref = this.panels.find(p => p.id === position.before) ?? null;\n\t\t} else if (position?.after) {\n\t\t\tconst after = this.panels.find(p => p.id === position.after);\n\t\t\tref = (after?.nextElementSibling as HTMLElement | null) ?? null;\n\t\t} else if (typeof position?.index === 'number') {\n\t\t\tref = this.panels[position.index] ?? null;\n\t\t}\n\n\t\t(this.panelWrapper || this._autoWrapPanels()).insertBefore(panel, ref);\n\t\tthis.refresh();\n\t\treturn panel;\n\t}\n\n\t/**\n\t * Remove a panel by id and refresh.\n\t * @param panelId - ID of the panel to remove.\n\t */\n\tremovePanel(panelId: string): void {\n\t\tconst panel = this.panels.find(p => p.id === panelId);\n\t\tif (!panel) return;\n\t\tpanel.remove();\n\t\tthis.refresh();\n\t}\n\n\t/**\n\t * Destroy this instance\n\t */\n\tdestroy(): void {\n\t\tthis._animShow.start(); // abort pending .then() callbacks (they check signal.aborted)\n\t\tthis._animOpenClose.start();\n\t\tthis._heightObserver?.disconnect();\n\t\tthis._heightObserver = null;\n\t\tthis._verbController.abort(); // stop end-state reflection; the static click\n\t\t // delegation no-ops once .panelSet is gone\n\t\tdelete this.element.panelSet;\n\t\tthis._log('Destroyed');\n\t}\n\n\t// Edge info for the currently targeted panel (pendingPanel), for event detail.\n\tprivate _edgeInfo(panel: HTMLElement | undefined): { index: number; total: number; atStart: boolean; atEnd: boolean } {\n\t\tconst total = this.panels.length;\n\t\tconst index = panel ? this.panels.indexOf(panel) : -1;\n\t\treturn { index, total, atStart: index <= 0, atEnd: index === total - 1 };\n\t}\n\n\t/* --- Verb buttons (data-ps-next / -prev / -close) --- */\n\n\t// Markup sugar over next() / prev() / close(): one document-level click\n\t// listener drives every set's verb buttons. Delegation is required (not a\n\t// nicety) — verb buttons commonly live inside async-loaded panel content that\n\t// does not exist at init. Installed once, shared by all instances.\n\tprivate static _installVerbDelegation(): void {\n\t\tif (PanelSet._verbDelegationInstalled) return;\n\t\tPanelSet._verbDelegationInstalled = true;\n\t\tdocument.addEventListener('click', PanelSet._onVerbClick);\n\t}\n\n\t// Resolve the set element a verb button drives. An explicit selector value —\n\t// data-ps-next=\"#wizard\" — always wins; otherwise the nearest enclosing set.\n\tprivate static _resolveVerbSet(btn: HTMLElement, verb: 'next' | 'prev' | 'close'): HTMLElement | null {\n\t\tconst sel = btn.getAttribute(`data-ps-${verb}`);\n\t\tif (sel) return document.querySelector<HTMLElement>(sel);\n\t\treturn btn.closest<HTMLElement>('[data-panelset], ps-panelset');\n\t}\n\n\tprivate static _onVerbClick = (event: Event): void => {\n\t\tconst start = event.target;\n\t\tif (!(start instanceof Element)) return;\n\t\tconst btn = start.closest<HTMLElement>('[data-ps-next], [data-ps-prev], [data-ps-close]');\n\t\t// aria-disabled is our end-of-range guard; a native disabled button never\n\t\t// fires click, so there is nothing extra to check for that.\n\t\tif (!btn || btn.getAttribute('aria-disabled') === 'true') return;\n\n\t\tconst verb: 'next' | 'prev' | 'close' =\n\t\t\tbtn.hasAttribute('data-ps-next') ? 'next' :\n\t\t\tbtn.hasAttribute('data-ps-prev') ? 'prev' : 'close';\n\n\t\tconst setEl = PanelSet._resolveVerbSet(btn, verb);\n\t\tconst instance = setEl?.panelSet;\n\t\tif (!instance) {\n\t\t\t// Same tone as PanelControl's \"not initialised\" notice. No instance means\n\t\t\t// no merged config, so gate the log on the set element's data-debug.\n\t\t\tif (setEl) log('PanelSet', setEl, setEl.dataset.debug != null && setEl.dataset.debug !== 'false',\n\t\t\t\t`data-ps-${verb}: PanelSet is not initialised. Add a PanelSet.init().`);\n\t\t\treturn;\n\t\t}\n\t\tinstance[verb]({ event });\n\t};\n\n\t// Wire end-of-range reflection for this set's verb buttons and stamp the\n\t// initial state. Clicks are handled globally (see _installVerbDelegation); here\n\t// we only keep aria-disabled in step with the ends.\n\tprivate _initVerbButtons(): void {\n\t\tconst { signal } = this._verbController;\n\t\tthis.element.addEventListener('ps:activationstart', this._onActivationEdge, { signal });\n\t\tthis.element.addEventListener('ps:activationcomplete', this._onActivationEdge, { signal });\n\t\tthis._reflectEnds();\n\t}\n\n\t// Recompute first/last from the current panels and re-apply the verb buttons'\n\t// end-of-range state. Run at init and on refresh() — so adding / removing /\n\t// reordering panels keeps Prev/Next correct (otherwise an appended panel leaves\n\t// the old last step's Next stuck disabled until the next activation). Activation\n\t// uses the event's own edge flags instead (see _onActivationEdge).\n\tprivate _reflectEnds(): void {\n\t\tconst { atStart, atEnd } = this._edgeInfo(this.pendingPanel);\n\t\tthis._reflectVerbEndState(atStart, atEnd);\n\t}\n\n\t// Reflect on both activationstart and activationcomplete. The edge flags ride\n\t// on the event detail and describe the *targeted* panel — i.e. pendingPanel,\n\t// which is what _step() steps from. Tracking pendingPanel (not activePanel)\n\t// keeps the button state agreeing with the guard during rapid interruptible\n\t// switches and reversals.\n\tprivate _onActivationEdge = (e: Event): void => {\n\t\tconst { atStart, atEnd } = (e as CustomEvent<ActivationEventDetail>).detail;\n\t\tthis._reflectVerbEndState(atStart, atEnd);\n\t};\n\n\t// End-of-range reflection on this set's prev/next buttons: prev is disabled at\n\t// the first panel, next at the last. With loop on, the ends wrap around, so the\n\t// buttons are never disabled — leave them alone in either mode.\n\t//\n\t// 'aria' (default): toggle aria-disabled, never the native disabled (the\n\t// author's). The button stays focusable, so no focus dance is needed.\n\t//\n\t// 'native': PanelSet owns the native disabled attribute on these buttons (it\n\t// must re-enable when stepping away from an end); aria-disabled is the author's\n\t// and untouched. Disabling the focused element drops focus to <body>, so the\n\t// focus dance moves focus off a button before disabling it.\n\tprivate _reflectVerbEndState(atStart: boolean, atEnd: boolean): void {\n\t\tif (this.config.loop) return;\n\t\tconst prev = this._verbButtonsFor('prev');\n\t\tconst next = this._verbButtonsFor('next');\n\n\t\tif (this.config.disabledMode !== 'native') {\n\t\t\tprev.forEach(b => this._applyVerbDisabled(b, atStart));\n\t\t\tnext.forEach(b => this._applyVerbDisabled(b, atEnd));\n\t\t\treturn;\n\t\t}\n\n\t\t// Re-enable first (never moves focus), so the counterpart is ready to\n\t\t// receive focus before we disable an end button.\n\t\tif (!atStart) prev.forEach(b => this._applyVerbDisabled(b, false));\n\t\tif (!atEnd) next.forEach(b => this._applyVerbDisabled(b, false));\n\t\t// Then disable the end button(s). The counterpart is the opposite-direction\n\t\t// button, but only when it stays enabled (i.e. not also at its end).\n\t\tif (atStart) this._disableVerbNative(prev, atEnd ? [] : next);\n\t\tif (atEnd) this._disableVerbNative(next, atStart ? [] : prev);\n\t}\n\n\t// Apply the disabled state to one verb button per the configured mode, and keep\n\t// its aria-describedby hint (data-ps-disabled-hint) in step — the hint id is\n\t// attached only while the button is disabled, so it is not announced when the\n\t// button is usable. Native disabling that needs the focus dance routes through\n\t// _disableVerbNative, which calls this after moving focus.\n\tprivate _applyVerbDisabled(btn: HTMLElement, disabled: boolean): void {\n\t\tif (this.config.disabledMode === 'native') {\n\t\t\tif (disabled) btn.setAttribute('disabled', ''); else btn.removeAttribute('disabled');\n\t\t} else {\n\t\t\tbtn.setAttribute('aria-disabled', String(disabled));\n\t\t}\n\t\tconst hint = btn.getAttribute('data-ps-disabled-hint');\n\t\tif (hint) setDescribedBy(btn, hint, disabled);\n\t}\n\n\t// Disable verb `buttons` (native mode). Before disabling one that holds focus,\n\t// move focus to the first enabled counterpart, else to the active panel — so\n\t// focus never lands on <body>.\n\tprivate _disableVerbNative(buttons: HTMLElement[], counterparts: HTMLElement[]): void {\n\t\tbuttons.forEach(btn => {\n\t\t\tif (!btn.hasAttribute('disabled') && document.activeElement === btn) {\n\t\t\t\tconst target = counterparts.find(c => !c.hasAttribute('disabled')) ?? this._verbFocusFallback();\n\t\t\t\ttarget?.focus();\n\t\t\t}\n\t\t\tthis._applyVerbDisabled(btn, true);\n\t\t});\n\t}\n\n\t// Fallback focus target when no enabled counterpart exists: the panel the user\n\t// is on (pendingPanel during a switch, else activePanel). Make it focusable the\n\t// same way autoFocus: true does.\n\tprivate _verbFocusFallback(): HTMLElement | null {\n\t\tconst panel = this.pendingPanel ?? this.activePanel;\n\t\tif (!panel) return null;\n\t\tif (!panel.hasAttribute('tabindex')) panel.setAttribute('tabindex', '-1');\n\t\treturn panel;\n\t}\n\n\t// All data-ps-prev / data-ps-next buttons that resolve to this set — interior\n\t// (closest) and explicit-target (data-ps-next=\"#sel\") alike.\n\tprivate _verbButtonsFor(verb: 'prev' | 'next'): HTMLElement[] {\n\t\treturn Array.from(document.querySelectorAll<HTMLElement>(`[data-ps-${verb}]`))\n\t\t\t.filter(btn => PanelSet._resolveVerbSet(btn, verb) === this.element);\n\t}\n\n\t/**\n\t * Activate the next panel in DOM order. Stops at the last panel unless the\n\t * `loop` option is set, in which case it wraps to the first.\n\t * @param options - Configuration options for the activation\n\t */\n\tnext(options?: ShowOptions): void {\n\t\tthis._step(1, options);\n\t}\n\n\t/**\n\t * Activate the previous panel in DOM order. Stops at the first panel unless\n\t * the `loop` option is set, in which case it wraps to the last.\n\t * @param options - Configuration options for the activation\n\t */\n\tprev(options?: ShowOptions): void {\n\t\tthis._step(-1, options);\n\t}\n\n\tprivate _step(dir: 1 | -1, options?: ShowOptions): void {\n\t\tconst total = this.panels.length;\n\t\tif (total === 0) return;\n\t\t// Step from the panel being targeted, so rapid clicks queue correctly.\n\t\tconst from = this.panels.indexOf(this.pendingPanel);\n\t\tconst current = from === -1 ? 0 : from;\n\t\tlet target = current + dir;\n\t\tlet wrapped = false;\n\t\tif (target < 0 || target >= total) {\n\t\t\tif (!this.config.loop) return; // clamp at the ends\n\t\t\ttarget = (target + total) % total; // wrap\n\t\t\twrapped = true;\n\t\t}\n\t\tconst next = this.panels[target];\n\t\t// Only a loop wrap needs the direction hint: its DOM-order delta points the\n\t\t// wrong way (last->first looks backward), so honour the step's direction. A\n\t\t// normal step's DOM order already matches the action, so leave it alone.\n\t\tif (next && next !== this.pendingPanel)\n\t\t\tthis.show(next.id, wrapped ? { ...options, direction: dir > 0 ? 'forward' : 'backward' } : options);\n\t}\n\n\n\t/**\n\t * Open a closable panelset\n\t * @param options - Configuration options\n\t */\n\topen(options?: ShowOptions): void {\n\t\tconst {\n\t\t\tevent,\n\t\t\ttransition = true,\n\t\t\tautoFocus\n\t\t} = options || {};\n\n\t\tif (!this.config.closable) {\n\t\t\tthis._log('Not closable');\n\t\t\treturn;\n\t\t}\n\n\t\tconst isClosed = this._isClosed;\n\t\tconst isClosing = this.element.classList.contains('is-closing');\n\t\tconst isLoading = this.element.classList.contains('is-loading');\n\n\t\tif (!isClosed && !isClosing) return;\n\t\tif (this.element.classList.contains('is-transitioning') && !isLoading) return;\n\n\t\t// Derive trigger for data-attribute check\n\t\tconst resolvedTrigger = event?.target instanceof HTMLElement \n\t\t\t? (event.target.closest('button, a, [role=\"tab\"]') as HTMLElement) ?? event.target\n\t\t\t: null;\n\n\t\tconst finalAutoFocus = this._resolveAutoFocus(resolvedTrigger, autoFocus);\n\t\tif (resolvedTrigger) this._returnFocusTarget = resolvedTrigger;\n\n\t\tthis._animateOpenClose(true, transition);\n\t\t\n\t\t// Handle autofocus after opening\n\t\tif (finalAutoFocus !== false && finalAutoFocus !== undefined && this.pendingPanel) {\n\t\t\tif (transition && this.config.transitions) {\n\t\t\t\tCore.waitForTransition(this.element).then(() => {\n\t\t\t\t\tthis._handleAutoFocus(this.pendingPanel, finalAutoFocus, event);\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tthis._handleAutoFocus(this.pendingPanel, finalAutoFocus, event);\n\t\t\t}\n\t\t}\n\t}\n\n\n\t/**\n\t * Close a closable panelset\n\t * @param options - Configuration options\n\t */\n\tclose(options?: ShowOptions): void {\n\t\tconst {\n\t\t\ttransition = true,\n\t\t\tevent\n\t\t} = options || {};\n\n\t\tif (!this.config.closable) {\n\t\t\tthis._log('Not closable');\n\t\t\treturn;\n\t\t}\n\n\t\tconst isClosed = this._isClosed;\n\t\tconst isClosing = this.element.classList.contains('is-closing');\n\t\tconst isOpening = this.element.classList.contains('is-opening');\n\t\tconst isLoading = this.element.classList.contains('is-loading');\n\n\t\tif ((isClosed || isClosing) && !isOpening) return;\n\t\tif (this.element.classList.contains('is-transitioning') && !isLoading) return;\n\n\t\tthis._animateOpenClose(false, transition, event);\n\t}\n\n\n\t/**\n\t * Toggle a closable panelset between open and closed\n\t * @param options - Configuration options\n\t */\n\ttoggle(options?: ShowOptions): void {\n\t\tconst {\n\t\t\tevent,\n\t\t\ttransition = true,\n\t\t\tautoFocus\n\t\t} = options || {};\n\n\t\tconst isClosed = this._isClosed;\n\t\tconst isClosing = this.element.classList.contains('is-closing');\n\n\t\t// If closed or closing, open it\n\t\tif (isClosed || isClosing) {\n\t\t\t// Just pass through to open() - it handles priority cascade\n\t\t\tthis.open({ event, transition, autoFocus });\n\t\t} else {\n\t\t\tthis.close({ transition, event });\n\t\t}\n\t}\n\n\t/**\n\t * Register a handler for async content loading\n\t * @param handler - Async content handler function\n\t * @param options - Handler options (once: whether to load only once)\n\t */\n\tonBeforeOpen(handler: AsyncContentHandler, options: HandlerOptions = {}): void {\n\t\tthis.hasAsyncContent = true;\n\t\tregisterBeforeOpenHandler<BeforeOpenEventDetail>(\n\t\t\tthis.element,\n\t\t\t'ps:beforeopen',\n\t\t\t(detail) => detail.targetPanel,\n\t\t\thandler,\n\t\t\toptions\n\t\t);\n\t}\n\n\t/* --- Main logic --- */\n\n\n\t/**\n\t * Show a panel by ID\n\t * @param panelId - ID of the panel to show\n\t * @param options - Configuration options for this activation\n\t */\n\tasync show(panelId: string, options?: ShowOptions): Promise<void> {\n\t\tif (this.config.interruptible === false && this._activating) return;\n\n\t\tconst {\n\t\t\tevent,\n\t\t\ttransition = true,\n\t\t\tautoFocus,\n\t\t\tdirection: stepDirection\n\t\t} = options || {};\n\n\t\t// Always derive trigger from event\n\t\tconst resolvedTrigger = event?.target instanceof HTMLElement \n\t\t\t? (event.target.closest('button, a, [role=\"tab\"]') as HTMLElement) ?? event.target\n\t\t\t: null;\n\n\t\tconst finalAutoFocus = this._resolveAutoFocus(resolvedTrigger, autoFocus);\n\n\t\tconst newPanel = this.panels.find(p => p.id === panelId);\n\n\t\tif (!newPanel) {\n\t\t\tthis._log(`Panel not found: ${panelId}`);\n\t\t\treturn;\n\t\t}\n\n\t\t// Cancelable gate, fired before any state changes. A listener can call\n\t\t// preventDefault() to veto the activation — e.g. a wizard that only allows\n\t\t// a step once required fields are filled. Covers every path (tab click,\n\t\t// next()/prev(), deep link) since they all funnel through show().\n\t\tconst beforeActivate = new CustomEvent<BeforeActivateEventDetail>('ps:beforeactivate', {\n\t\t\tdetail: {\n\t\t\t\tpanelId,\n\t\t\t\ttargetPanel: newPanel,\n\t\t\t\toutgoingPanel: this.activePanel ?? null,\n\t\t\t\ttrigger: resolvedTrigger\n\t\t\t},\n\t\t\tbubbles: true,\n\t\t\tcancelable: true\n\t\t});\n\t\tif (!this.element.dispatchEvent(beforeActivate)) {\n\t\t\tthis._log(`Vetoed by ps:beforeactivate: ${panelId}`);\n\t\t\treturn;\n\t\t}\n\n\t\tconst isClosed = this._isClosed;\n\t\tconst isClosing = this.element.classList.contains('is-closing');\n\t\tconst isLoading = this.element.classList.contains('is-loading');\n\n\t\tif (newPanel === this.pendingPanel) {\n\t\t\tif (isClosed || isClosing) {\n\t\t\t\t// Same panel, but closed or closing: open it\n\t\t\t\tthis.open({ event, transition, autoFocus: finalAutoFocus });\n\t\t\t} else if (this.config.closable && this.config.closeOnTab) {\n\t\t\t\t// Clicking the active tab while open: close if closeOnTab is enabled\n\t\t\t\tthis.close({ transition, event });\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\t// Block tab switches during open/close animations (but not during async loading)\n\t\tif ((this.element.classList.contains('is-opening') || isClosing) && !isLoading) return;\n\n\t\t// When closed: silently swap to the target panel, then open\n\t\tif (isClosed) {\n\t\t\tthis.pendingPanel = newPanel;\n\t\t\tthis._cleanupPanels(newPanel);\n\t\t\tthis.open({ event, transition, autoFocus: finalAutoFocus });\n\t\t\treturn;\n\t\t}\n\n\t\tconst switchInFlight = this._activating;\n\t\tthis._activating = true;\n\t\tif (this.config.manageTriggers && this.config.interruptible === false) this._setTriggersActivating(true);\n\n\t\tconst prevPanel = this.pendingPanel;\n\t\tconst prevPanelId = prevPanel?.id;\n\t\tthis.pendingPanel = newPanel;\n\n\t\t// Reversal: a switch is mid-flight and the user re-requested the panel that\n\t\t// is still animating out (the current activePanel). Treat the in-flight\n\t\t// incoming panel (prevPanel) as the new outgoing one and apply the opposite\n\t\t// direction, so the CSS transition rolls back from the live positions.\n\t\tconst isReversal = switchInFlight && newPanel === this.activePanel && prevPanel !== newPanel;\n\t\tif (this.config.manageTriggers) this._updateTabTriggers(newPanel);\n\n\t\tthis._persistState(panelId);\n\n\t\tthis.element.classList.remove('is-loading');\n\n\t\tif (!isReversal && prevPanel && prevPanel !== this.activePanel && prevPanel !== newPanel) {\n\t\t\tprevPanel.classList.remove('incoming', 'outgoing', 'levelup', 'leveldown');\n\t\t\tif (prevPanel.hidden) {\n\t\t\t\t// Was never visible, keep hidden\n\t\t\t} else {\n\t\t\t\tprevPanel.classList.remove('active');\n\t\t\t}\n\t\t}\n\n\t\tconst wasLoadingAsync = this._isLoadingAsync;\n\n\t\t// start() aborts the previous signal — cancels in-flight animation AND\n\t\t// any fetch() that received the previous signal via ps:beforeopen.\n\t\tconst prevSignalAborted = this._animShow.signal.aborted;\n\t\tconst signal = this._animShow.start();\n\n\t\tif (!prevSignalAborted && wasLoadingAsync && prevPanelId && prevPanelId !== panelId) {\n\t\t\tthis._dispatch<ActivationAbortedEventDetail>('ps:activationaborted', {\n\t\t\t\tpanelId: prevPanelId,\n\t\t\t\ttrigger: resolvedTrigger\n\t\t\t});\n\t\t}\n\n\t\tthis._isLoadingAsync = false;\n\n\t\tthis._log(`${prevPanel?.id || 'none'} > ${panelId}`);\n\n\t\tconst beforeOpenDetail: BeforeOpenEventDetail = {\n\t\t\tpanelId,\n\t\t\ttargetPanel: newPanel,\n\t\t\toutgoingPanel: prevPanel,\n\t\t\tsignal,\n\t\t\tpromise: null,\n\t\t\twaitUntil() {} // wired below; closes over the detail so it is safe to destructure\n\t\t};\n\t\tattachWaitUntil(beforeOpenDetail);\n\n\t\tconst beforeOpenEvent = new CustomEvent('ps:beforeopen', {\n\t\t\tdetail: beforeOpenDetail,\n\t\t\tbubbles: true,\n\t\t\tcancelable: false\n\t\t});\n\n\t\tthis.element.dispatchEvent(beforeOpenEvent);\n\n\t\tconst userPromise = beforeOpenDetail.promise;\n\n\t\tif (userPromise) {\n\t\t\tthis._isLoadingAsync = true;\n\t\t\tthis._log('Waiting for content...');\n\n\t\t\t\t// Add is-loading immediately so the wrapper dims without flash.\n\t\t\t// The spinner's appearance is delayed via CSS transition-delay\n\t\t\t// (--ps-loading-delay) so it only shows for slow loads, without a JS timer.\n\t\t\tthis.element.style.setProperty('--ps-loading-delay', `${this.config.loadingDelay}ms`);\n\t\t\tthis.element.classList.add('is-loading');\n\n\t\t\tlet openTransition: Promise<void> | null = null;\n\n\t\t\tconst shouldTransition = transition !== false && this.config.transitions !== false;\n\t\t\tlet heightTransition = shouldTransition;\n\t\t\tif (typeof this.config.transitions === 'object') {\n\t\t\t\theightTransition = shouldTransition && this.config.transitions.height !== false;\n\t\t\t}\n\n\t\t\tif (heightTransition) {\n\t\t\t\tif (isClosed) {\n\t\t\t\t\tthis.element.classList.add('is-open', 'is-opening');\n\t\t\t\t\tthis.element.style.height = '0px';\n\t\t\t\t\trequestAnimationFrame(() => {\n\t\t\t\t\t\tthis.element.style.height = `${this.config.loadingHeight}px`;\n\t\t\t\t\t});\n\t\t\t\t\topenTransition = Core.waitForTransition(this.element, 'height');\n\t\t\t\t} else {\n\t\t\t\t\t// loadingHeight is a minimum: only expand if the current height is shorter.\n\t\t\t\t\tconst currentHeight = this.element.offsetHeight;\n\t\t\t\t\tconst targetHeight = Math.max(currentHeight, this.config.loadingHeight);\n\t\t\t\t\tif (targetHeight > currentHeight) {\n\t\t\t\t\t\tthis.element.style.height = `${currentHeight}px`;\n\t\t\t\t\t\trequestAnimationFrame(() => {\n\t\t\t\t\t\t\tthis.element.style.height = `${targetHeight}px`;\n\t\t\t\t\t\t});\n\t\t\t\t\t\topenTransition = Core.waitForTransition(this.element, 'height');\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tawait Promise.all([userPromise, openTransition].filter(Boolean) as Promise<void>[]);\n\n\t\t\t\tif (signal.aborted) {\n\t\t\t\t\tthis._log(`Aborted during load: ${panelId}`);\n\t\t\t\t\tthis.element.classList.remove('is-loading');\n\t\t\t\t\tthis.element.style.removeProperty('--ps-loading-delay');\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tthis._log('Content loaded');\n\n\t\t\t\tif (newPanel.dataset.loaded === 'true') {\n\t\t\t\t\tthis._updateHighestPanel();\n\t\t\t\t}\n\n\t\t\t} catch (error) {\n\t\t\t\tconst err = error as Error;\n\t\t\t\tthis._log(`Load failed: ${err.message}`);\n\t\t\t\tthis.element.classList.remove('is-loading');\n\t\t\t\tthis.element.style.removeProperty('--ps-loading-delay');\n\n\t\t\t\tif (err.name !== 'AbortError') {\n\t\t\t\t\tconsole.error('Panel load error:', error);\n\t\t\t\t}\n\n\t\t\t\tthis._activating = false;\n\t\t\t\tif (this.config.manageTriggers && this.config.interruptible === false) this._setTriggersActivating(false);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis.element.classList.remove('is-loading');\n\t\t\tthis.element.style.removeProperty('--ps-loading-delay');\n\t\t\tthis.element.classList.remove('is-opening');\n\t\t}\n\n\t\tif (signal.aborted) {\n\t\t\tthis._log(`Aborted: ${panelId}`);\n\t\t\treturn;\n\t\t}\n\n\t\tconst outgoingPanel = isReversal ? prevPanel : this.activePanel;\n\n\t\tthis._dispatch<ActivationEventDetail>('ps:activationstart', {\n\t\t\tpanelId,\n\t\t\ttrigger: resolvedTrigger,\n\t\t\toutgoingPanel,\n\t\t\t...this._edgeInfo(newPanel)\n\t\t});\n\n\t\tconst shouldTransition = transition !== false && this.config.transitions !== false;\n\n\t\tlet panelTransition = shouldTransition;\n\t\tlet heightTransition = shouldTransition;\n\n\t\tif (typeof this.config.transitions === 'object') {\n\t\t\tpanelTransition = shouldTransition && this.config.transitions.panels !== false;\n\t\t\theightTransition = shouldTransition && this.config.transitions.height !== false;\n\t\t}\n\n\t\tthis.panels.forEach(panel => panel.classList.toggle('fade', panelTransition));\n\n\t\t// Direction (levels feature). DOM order is the implicit level: a later\n\t\t// panel is \"higher\". Going to a higher panel is levelup, lower is leveldown.\n\t\t// When levels is off, no direction class is set and the default\n\t\t// (--ps-panel-in-transform-from / --ps-panel-out-transform-to) direction is always used.\n\t\tlet direction: 'levelup' | 'leveldown' | null = null;\n\t\tif (isReversal) {\n\t\t\t// Opposite of the in-flight direction. A plain (no-levels) slide always\n\t\t\t// runs in the default (levelup) direction, so its reverse is leveldown.\n\t\t\tdirection = this._switchDirection === 'leveldown' ? 'levelup' : 'leveldown';\n\t\t} else if (this.config.levels && outgoingPanel && outgoingPanel !== newPanel) {\n\t\t\t// next()/prev() pass their step direction so a loop wrap slides in the\n\t\t\t// action's direction ('forward' = like Next), not the DOM-order delta —\n\t\t\t// which would slide a last->first wrap backwards. A direct jump (e.g. a tab\n\t\t\t// click) carries no intent, so it falls back to DOM order.\n\t\t\tif (stepDirection) {\n\t\t\t\tdirection = stepDirection === 'forward' ? 'levelup' : 'leveldown';\n\t\t\t} else {\n\t\t\t\tconst fromIdx = this.panels.indexOf(outgoingPanel);\n\t\t\t\tconst toIdx = this.panels.indexOf(newPanel);\n\t\t\t\tif (fromIdx !== -1 && toIdx !== -1 && fromIdx !== toIdx) {\n\t\t\t\t\tdirection = toIdx > fromIdx ? 'levelup' : 'leveldown';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tthis._switchDirection = direction;\n\n\t\t// Clear any stale state from an interrupted switch synchronously, so CSS\n\t\t// transitions interpolate from the current position rather than snapping.\n\t\tthis.panels.forEach(p => p.classList.remove('outgoing', 'levelup', 'leveldown'));\n\n\t\tconst startHeight = this.element.offsetHeight;\n\t\tif (heightTransition) {\n\t\t\tthis.element.style.height = `${startHeight}px`;\n\t\t}\n\n\t\tnewPanel.hidden = false;\n\t\tnewPanel.setAttribute('inert', '');\n\t\tnewPanel.classList.add('incoming');\n\t\tif (direction) newPanel.classList.add(direction);\n\t\tif (panelTransition) {\n\t\t\tthis.element.classList.add('is-transitioning');\n\t\t}\n\t\tif (outgoingPanel && outgoingPanel !== newPanel) {\n\t\t\toutgoingPanel.classList.remove('active', 'incoming');\n\t\t\toutgoingPanel.classList.add('outgoing');\n\t\t\tif (direction) outgoingPanel.classList.add(direction);\n\t\t\toutgoingPanel.hidden = false;\n\t\t\toutgoingPanel.setAttribute('inert', '');\n\t\t}\n\n\t\t// Double rAF: first frame commits incoming (opacity:0) state to the\n\t\t// rendering pipeline; second frame adds active (opacity:1) so the\n\t\t// fade-in transition fires. Single rAF causes Firefox to skip the\n\t\t// transition and show the new panel at full opacity immediately.\n\t\trequestAnimationFrame(() => requestAnimationFrame(() => {\n\t\t\tnewPanel.classList.add('active');\n\t\t\tif (outgoingPanel && outgoingPanel !== newPanel) {\n\t\t\t\toutgoingPanel.classList.remove('incoming');\n\t\t\t}\n\n\t\t\tconst targetHeight = this._measureHeight(newPanel);\n\t\t\tconst heightChanged = startHeight !== targetHeight;\n\n\t\t\tif (heightTransition) {\n\t\t\t\tthis.element.style.height = `${targetHeight}px`;\n\t\t\t}\n\n\t\t\tconst promises: Promise<void>[] = [];\n\t\t\tif (panelTransition) {\n\t\t\t\tpromises.push(Core.waitForTransition(newPanel));\n\t\t\t}\n\t\t\tif (heightTransition && heightChanged) {\n\t\t\t\tpromises.push(Core.waitForTransition(this.element));\n\t\t\t}\n\t\t\tif (!promises.length) promises.push(Promise.resolve());\n\n\t\t\tPromise.all(promises).then(() => {\n\t\t\t\tif (signal.aborted) {\n\t\t\t\t\tthis._log(`Interrupted: ${panelId}`);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tthis._cleanupPanels(newPanel);\n\t\t\t\tthis._log(`✓ ${panelId}`);\n\n\t\t\t\tif (finalAutoFocus !== false && finalAutoFocus !== undefined) {\n\t\t\t\t\tthis._handleAutoFocus(newPanel, finalAutoFocus, event);\n\t\t\t\t}\n\n\t\t\t\tthis._activating = false;\n\t\t\t\tif (this.config.manageTriggers && this.config.interruptible === false) this._setTriggersActivating(false);\n\t\t\t\tthis._dispatch<ActivationEventDetail>('ps:activationcomplete', {\n\t\t\t\t\tpanelId,\n\t\t\t\t\ttrigger: resolvedTrigger,\n\t\t\t\t\toutgoingPanel,\n\t\t\t\t\t...this._edgeInfo(newPanel)\n\t\t\t\t});\n\t\t\t});\n\t\t}));\n\t}\n\n}\n\nexport default PanelSet;","/**\n * Pinning elements (for 'push' panels)\n */\n\n\nexport const findBody = (element: HTMLElement): HTMLElement | null => {\n\tconst parent = element.parentElement;\n\tif (!parent?.querySelector('[data-panel-body]')) return null;\n\n\treturn Array.from(parent.children).find(\n\t\t(el): el is HTMLElement =>\n\t\t\tel instanceof HTMLElement && el.hasAttribute('data-panel-body')\n\t) ?? null;\n};\n\n\nexport const lockBody = (body: HTMLElement): void => {\n\tconst pins = Array.from(body.querySelectorAll<HTMLElement>('[data-panel-pin]'));\n\tif (!pins.length) return;\n\n\t// Measure everything before touching any styles — avoids layout thrashing.\n\tconst snapshots = pins.map(el => ({\n\t\tel,\n\t\tpin: el.dataset.panelPin as 'start' | 'end',\n\t\tw: el.offsetWidth,\n\t}));\n\n\tsnapshots.forEach(({ el, pin, w }) => {\n\t\tel.style.boxSizing = 'border-box';\n\t\tel.style.width = `${w}px`;\n\t\tif (pin === 'end') {\n\t\t\tel.style.marginLeft = `calc(100% - ${w}px)`;\n\t\t}\n\t});\n};\n\n\nexport const unlockBody = (body: HTMLElement): void => {\n\tbody.querySelectorAll<HTMLElement>('[data-panel-pin]').forEach(el => {\n\t\tel.style.boxSizing = '';\n\t\tel.style.width = '';\n\t\tel.style.marginLeft = '';\n\t});\n};","import '../style/panelset.scss';\nimport { Core } from './functions/core.js';\nimport { autoFocus } from './functions/focus.js';\nimport { readPanelParam, writePanelParam, readStored, writeStored } from './functions/persist.js';\nimport { findBody, lockBody, unlockBody } from './functions/pinning.js';\n\nimport type { PanelConfig, BeforeOpenEventDetail, PanelEventDetail, AsyncOpenHandler } from './panel.types.js';\nimport { parseDataAttrs, type AttrMap } from './functions/config.js';\nimport { log, logInterpolateSizeOnce, registerBeforeOpenHandler, attachWaitUntil } from './functions/utils.js';\n\ndeclare global {\n\tinterface HTMLElement {\n\t\tpanel?: Panel;\n\t}\n}\n\nfunction trueSiblings(\n\titem: HTMLElement,\n\topts: {\n\t\tgroupSelector: string;\n\t\tscopeSelector?: string;\n\t\titemSelector: string;\n\t\tfilter?: (el: HTMLElement) => boolean;\n\t}\n): HTMLElement[] {\n\tconst { groupSelector, scopeSelector = groupSelector, itemSelector, filter } = opts;\n\n\tconst belongsToGroup = (el: HTMLElement, group: HTMLElement): boolean => {\n\t\tif (el.closest(scopeSelector) !== group) return false;\n\t\tconst parentItem = el.parentElement?.closest<HTMLElement>(itemSelector);\n\t\treturn !parentItem || !group.contains(parentItem);\n\t};\n\n\tconst group = item.closest<HTMLElement>(groupSelector);\n\tif (!group || !belongsToGroup(item, group)) return [];\n\n\treturn [...group.querySelectorAll<HTMLElement>(itemSelector)].filter(sibling =>\n\t\tsibling !== item &&\n\t\tbelongsToGroup(sibling, group) &&\n\t\t(filter ? filter(sibling) : true)\n\t);\n}\n\nexport class Panel {\n\telement: HTMLElement;\n\tconfig: Required<PanelConfig>;\n\n\tprivate _returnFocusTarget: HTMLElement | null = null;\n\tprivate _tempCloseGroup: HTMLElement | null = null;\n\tprivate _anim = new Core();\n\tprivate _listenerController = new AbortController();\n\tprivate _activating = false;\n\n\tstatic defaults: Required<PanelConfig> = {\n\t\taxis: 'vertical',\n\t\talign: 'start',\n\t\tcloseOnResize: false,\n\t\ttransitions: true,\n\t\tautoFocus: false,\n\t\treturnFocus: true,\n\t\tcloseSiblings: false,\n\t\tloadingDelay: 320,\n\t\tloadingHeight: 150,\n\t\tinterruptible: true,\n\t\tpersist: false,\n\t\tdeepLink: false,\n\t\tdebug: false,\n\t};\n\n\tstatic readonly attrs: AttrMap<PanelConfig> = {\n\t\taxis: ['panelAxis', 'string'],\n\t\talign: ['panelAlign', 'string'],\n\t\tautoFocus: ['panelAutoFocus', 'string'],\n\t\tcloseOnResize: ['panelCloseOnResize', 'boolean'],\n\t\ttransitions: ['panelTransitions', 'boolean'],\n\t\treturnFocus: ['panelReturnFocus', 'boolean'],\n\t\tcloseSiblings: ['panelCloseSiblings', 'boolean'],\n\t\tloadingDelay: ['panelLoadingDelay', 'number'],\n\t\tloadingHeight: ['panelLoadingHeight', 'number'],\n\t\tinterruptible: ['panelInterruptible', 'boolean'],\n\t\tpersist: ['panelPersist', 'boolean'],\n\t\tdeepLink: ['panelDeeplink', 'boolean'],\n\t\tdebug: ['debug', 'boolean'],\n\t};\n\n\t// True when the browser supports interpolate-size: allow-keywords.\n\t// When set, CSS animates height/width 0 to/from auto natively and the JS\n\t// measure-animate cycle is skipped (open/close just toggle state classes).\n\tprivate static readonly _nativeInterpolateSize =\n\t\ttypeof CSS !== 'undefined' && CSS.supports('interpolate-size: allow-keywords');\n\n\tprivate static _autoIdCounter = 0;\n\n\tstatic init(selectorOrOptions: string | PanelConfig = '[data-panel]', options: PanelConfig = {}): Panel[] {\n\t\tlet selector: string;\n\t\tlet config: PanelConfig;\n\t\tif (typeof selectorOrOptions === 'string') {\n\t\t\tselector = selectorOrOptions;\n\t\t\tconfig = options;\n\t\t} else {\n\t\t\tconfig = selectorOrOptions;\n\t\t\tselector = '[data-panel]';\n\t\t}\n\n\t\t// Implicit trigger wiring (a [data-panel-trigger] button next to its panel)\n\t\t// is handled per-instance in the constructor — see _wireImplicitTriggers —\n\t\t// so it works for Panel.init(), the <ps-panel> web component, and any\n\t\t// panel constructed directly, not just [data-panel] in this one pass.\n\n\t\treturn Array.from(document.querySelectorAll<HTMLElement>(selector))\n\t\t\t.filter(el => !el.panel)\n\t\t\t.filter(el => !el.dataset.panel || el.dataset.panel === 'data-panel') // skip data-panel=\"id\" trigger buttons; Panel containers have no value (or Pug's boolean \"data-panel\")\n\t\t\t.map(el => new Panel(el, config));\n\t}\n\n\tconstructor(elementOrSelector: HTMLElement | string, options: PanelConfig = {}) {\n\t\tconst element = typeof elementOrSelector === 'string'\n\t\t\t? document.querySelector<HTMLElement>(elementOrSelector)\n\t\t\t: elementOrSelector;\n\t\tif (!element) throw new Error(`Panel: No element found for selector \"${elementOrSelector}\"`);\n\t\tthis.element = element;\n\t\telement.panel = this;\n\n\t\tif (!element.querySelector(':scope > .panel-wrapper')) {\n\t\t\tconst wrapper = document.createElement('div');\n\t\t\twrapper.className = 'panel-wrapper';\n\t\t\twrapper.append(...Array.from(element.childNodes));\n\t\t\telement.appendChild(wrapper);\n\t\t}\n\n\t\t// Precedence: defaults < init() options < per-element data-attributes.\n\t\t// The attribute is the most specific signal, so it wins — this lets an\n\t\t// element opt out of a global flag, e.g. data-panel-persist=\"false\"\n\t\t// overriding Panel.init({ persist: true }).\n\t\tconst dataConfig = parseDataAttrs<PanelConfig>(element.dataset, Panel.attrs);\n\t\tthis.config = { ...Panel.defaults, ...options, ...dataConfig };\n\n\t\tif (this.config.axis === 'horizontal') element.dataset.panelAxis = 'horizontal';\n\t\tif (this.config.align !== 'start') element.dataset.panelAlign = this.config.align;\n\n\t\tthis._wireImplicitTriggers();\n\t\tthis._bindTriggers();\n\n\t\t// Start open if persisted/deep-linked state says so, OR if the markup was\n\t\t// authored with .is-open. Either way snap open without animation and sync\n\t\t// the trigger's aria-expanded, so hand-authored markup needs no extra ARIA.\n\t\tif (this._resolveInitialState() || this.element.classList.contains('is-open')) {\n\t\t\tthis.element.classList.add('is-open');\n\t\t\tthis.element.removeAttribute('inert');\n\t\t\tthis._setTriggerState(true);\n\t\t\t// is-restored is present for exactly one paint so CSS can suppress\n\t\t\t// transitions on parent/sibling elements. Double rAF ensures the class\n\t\t\t// survives the first paint before being removed.\n\t\t\tthis.element.classList.add('is-restored');\n\t\t\trequestAnimationFrame(() => requestAnimationFrame(() => this.element.classList.remove('is-restored')));\n\t\t\tthis._dispatch('panel:opened');\n\t\t} else {\n\t\t\tthis.element.setAttribute('inert', '');\n\t\t}\n\n\t\tif (Panel._nativeInterpolateSize) logInterpolateSizeOnce(this.config.debug);\n\t\tthis._log('Initialized');\n\t}\n\n\tprivate _log(msg: string) { log('Panel', this.element, this.config.debug, msg); }\n\n\t// URL param + localStorage helpers \n\n\tprivate _parsePanelParam = (): boolean => {\n\t\tconst { id } = this.element;\n\t\tif (!id) return false;\n\t\treturn readPanelParam().includes(id);\n\t};\n\n\tprivate _updatePanelParam = (open: boolean): void => {\n\t\tconst { id } = this.element;\n\t\tif (!id) return;\n\t\tconst current = readPanelParam();\n\t\tconst next = open\n\t\t\t? [...new Set([...current, id])]\n\t\t\t: current.filter(i => i !== id);\n\t\twritePanelParam(next);\n\t};\n\n\t// Resolve persist/deepLink with precedence: element attribute > group attribute\n\t// > init option / default. The element's own attribute is the most specific\n\t// signal, so an explicit data-panel-persist=\"false\" opts the element out even\n\t// inside a persisting [data-panel-group]. An attribute is \"set\" only when\n\t// present; presence with any value except \"false\" means true.\n\tprivate _resolveStateConfig = (): { persist: boolean; deepLink: boolean } => {\n\t\t// undefined = attribute not present on this element.\n\t\tconst ownAttr = (name: string): boolean | undefined =>\n\t\t\tthis.element.hasAttribute(name)\n\t\t\t\t? this.element.getAttribute(name) !== 'false'\n\t\t\t\t: undefined;\n\n\t\tconst ownPersist = ownAttr('data-panel-persist');\n\t\tconst ownDeepLink = ownAttr('data-panel-deeplink');\n\n\t\t// Nearest enclosing group (stop at any parent [data-panel]).\n\t\tlet groupPersist: boolean | undefined;\n\t\tlet groupDeepLink: boolean | undefined;\n\t\tlet el = this.element.parentElement;\n\t\twhile (el) {\n\t\t\tif (el.hasAttribute('data-panel')) break;\n\t\t\tif (el.hasAttribute('data-panel-group')) {\n\t\t\t\tif (el.hasAttribute('data-panel-persist')) groupPersist = el.getAttribute('data-panel-persist') !== 'false';\n\t\t\t\tif (el.hasAttribute('data-panel-deeplink')) groupDeepLink = el.getAttribute('data-panel-deeplink') !== 'false';\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tel = el.parentElement;\n\t\t}\n\n\t\treturn {\n\t\t\tpersist: ownPersist ?? groupPersist ?? this.config.persist,\n\t\t\tdeepLink: ownDeepLink ?? groupDeepLink ?? this.config.deepLink,\n\t\t};\n\t};\n\n\tprivate _persistState = (open: boolean): void => {\n\t\tif (!this.element.id) return;\n\n\t\tconst { persist: hasPersist, deepLink: hasDeepLink } = this._resolveStateConfig();\n\n\t\tif (hasPersist) {\n\t\t\twriteStored(`panel:${this.element.id}`, open ? 'open' : 'closed');\n\t\t}\n\n\t\tif (hasDeepLink) {\n\t\t\tthis._updatePanelParam(open);\n\t\t} else if (!open && this._parsePanelParam()) {\n\t\t\t// No deepLink configured: on close, still clean up a stale ?panel= ID\n\t\t\t// left by a snap-open so the URL doesn't keep reopening the panel.\n\t\t\tthis._updatePanelParam(false);\n\t\t}\n\t};\n\n\tprivate _resolveInitialState = (): boolean => {\n\t\tconst { id } = this.element;\n\t\tif (!id) return false;\n\t\t// URL param is always honoured: a ?panel=id link is explicit and\n\t\t// page-specific, so shareable deep links work with no config.\n\t\tif (this._parsePanelParam()) return true;\n\t\t// localStorage is opt-in only. Without persist, a stale entry — e.g. an\n\t\t// auto-assigned id (panel-1, …) left by another page — must not reopen this.\n\t\tconst { persist } = this._resolveStateConfig();\n\t\tif (persist && readStored(`panel:${id}`) === 'open') return true;\n\t\treturn false;\n\t};\n\n\tprivate _cssProp = (): 'height' | 'width' =>\n\t\tthis.config.axis === 'horizontal' ? 'width' : 'height';\n\n\n\t// Turn an adjacent [data-panel-trigger] button into a wired aria-controls\n\t// trigger for THIS panel. Searching outward from the panel (rather than from\n\t// the trigger to a [data-panel] sibling) means it matches however the panel\n\t// is authored — a [data-panel] div or a <ps-panel> custom element — and runs\n\t// for every construction path, so it no longer depends on calling init().\n\t// The panel gets a stable auto-ID only when a trigger actually needs one.\n\tprivate _wireImplicitTriggers() {\n\t\tconst isPanel = (el: HTMLElement): boolean => el.hasAttribute('data-panel') || !!el.panel;\n\t\tconst wire = (trigger: HTMLElement): void => {\n\t\t\tif (!this.element.id) this.element.id = `panel-${++Panel._autoIdCounter}`;\n\t\t\ttrigger.setAttribute('aria-controls', this.element.id);\n\t\t\tif (!trigger.hasAttribute('aria-expanded')) trigger.setAttribute('aria-expanded', 'false');\n\t\t\ttrigger.removeAttribute('data-panel-trigger');\n\t\t};\n\t\t// The trigger can be the sibling itself, or a direct child of a heading\n\t\t// sibling (e.g. <h2><button data-panel-trigger>…</button></h2>).\n\t\tconst triggerIn = (el: HTMLElement): HTMLElement | null =>\n\t\t\tel.hasAttribute('data-panel-trigger') ? el\n\t\t\t: /^H[1-6]$/.test(el.tagName) ? el.querySelector<HTMLElement>(':scope > [data-panel-trigger]')\n\t\t\t: null;\n\t\t// Nearest trigger on each side, without crossing into another panel.\n\t\tfor (const dir of ['previousElementSibling', 'nextElementSibling'] as const) {\n\t\t\tlet el = this.element[dir] as HTMLElement | null;\n\t\t\twhile (el && !isPanel(el)) {\n\t\t\t\tconst trigger = triggerIn(el);\n\t\t\t\tif (trigger) { wire(trigger); break; }\n\t\t\t\tel = el[dir] as HTMLElement | null;\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate _bindTriggers() {\n\t\tconst id = this.element.id;\n\t\tif (!id) return;\n\t\tconst { signal } = this._listenerController;\n\n\t\tdocument.querySelectorAll<HTMLElement>(`[aria-controls=\"${id}\"]`).forEach(trigger => {\n\t\t\ttrigger.addEventListener('click', e => {\n\t\t\t\tthis._returnFocusTarget = trigger;\n\t\t\t\tthis.toggle(e);\n\t\t\t}, { signal });\n\t\t});\n\n\t\tthis.element.querySelectorAll<HTMLElement>('[data-panel-close]')\n\t\t\t.forEach(btn => {\n\t\t\t\tif (btn.closest('[data-panel]') !== this.element) return;\n\t\t\t\tbtn.addEventListener('click', () => this.close(), { signal });\n\t\t\t});\n\n\t\tif (this.config.closeOnResize) {\n\t\t\twindow.addEventListener('resize', () => {\n\t\t\t\tif (!this.isOpen || this.element.classList.contains('is-closing')) return;\n\t\t\t\tconst body = findBody(this.element);\n\t\t\t\tif (body) unlockBody(body);\n\t\t\t\tthis.close();\n\t\t\t}, { signal });\n\t\t}\n\t}\n\n\tprivate _setTriggerState(open: boolean) {\n\t\tconst id = this.element.id;\n\t\tif (!id) return;\n\t\tdocument.querySelectorAll(`[aria-controls=\"${id}\"]`).forEach(t =>\n\t\t\tt.setAttribute('aria-expanded', String(open))\n\t\t);\n\t}\n\n\tprivate _cleanupTempClose() {\n\t\tif (!this._tempCloseGroup) return;\n\t\tthis._tempCloseGroup.style.removeProperty('--ps-tempclose-speed');\n\t\tthis._tempCloseGroup.style.removeProperty('--ps-tempclose-timing');\n\t\tthis._tempCloseGroup = null;\n\t}\n\n\tprivate _closeGroupSiblings() {\n\t\tconst group = this.element.closest<HTMLElement>('[data-panel-group]');\n\t\tconst groupClose = group?.hasAttribute('data-panel-close-siblings') ?? false;\n\t\tif (!this.config.closeSiblings && !groupClose) return;\n\n\t\tconst toClose: HTMLElement[] = group\n\t\t\t? trueSiblings(this.element, {\n\t\t\t\tgroupSelector: '[data-panel-group]',\n\t\t\t\titemSelector: '[data-panel]',\n\t\t\t\tfilter: el => !!el.panel?.isOpen,\n\t\t\t})\n\t\t\t: Array.from(this.element.parentElement?.children ?? [])\n\t\t\t\t.filter((el): el is HTMLElement =>\n\t\t\t\t\tel instanceof HTMLElement && el !== this.element && !!el.panel?.isOpen\n\t\t\t\t);\n\n\t\tif (toClose.length && group) {\n\t\t\tgroup.style.setProperty('--ps-tempclose-speed', 'var(--ps-open-speed)');\n\t\t\tgroup.style.setProperty('--ps-tempclose-timing', 'var(--ps-open-timing)');\n\t\t\tthis._tempCloseGroup = group;\n\t\t}\n\n\t\ttoClose.forEach(el => {\n\t\t\tel.panel!._returnFocusTarget = null;\n\t\t\tel.panel!.close();\n\t\t});\n\t}\n\n\tprivate _handleAutoFocus(event?: Event) {\n\t\tif (!this.config.autoFocus) return;\n\t\tautoFocus(this.element, this.config.autoFocus, event);\n\t}\n\n\tprivate _dispatch(name: string) {\n\t\tif (name === 'panel:opened' || name === 'panel:closed') this._activating = false;\n\t\tconst detail: PanelEventDetail = { trigger: this._returnFocusTarget };\n\t\tthis.element.dispatchEvent(new CustomEvent(name, { detail, bubbles: true }));\n\t}\n\n\t// Public API\n\n\tget isOpen(): boolean {\n\t\treturn this.element.classList.contains('is-open') || this.element.classList.contains('is-opening');\n\t}\n\n\n\n\t// open\n\n\tasync open(event?: Event) {\n\t\tif (this.isOpen && !this.element.classList.contains('is-closing')) return;\n\t\tif (this.config.interruptible === false && this._activating) return;\n\n\t\tthis._activating = true;\n\t\tconst signal = this._anim.start();\n\t\tconst cssProp = this._cssProp();\n\n\t\tconst beforeOpenDetail: BeforeOpenEventDetail = {\n\t\t\tsignal,\n\t\t\tpromise: null,\n\t\t\twaitUntil() {}, // wired below; closes over the detail so it is safe to destructure\n\t\t\ttrigger: this._returnFocusTarget\n\t\t};\n\t\tattachWaitUntil(beforeOpenDetail);\n\n\t\tthis.element.dispatchEvent(\n\t\t\tnew CustomEvent('panel:beforeopen', { detail: beforeOpenDetail, bubbles: true })\n\t\t);\n\n\t\tif (beforeOpenDetail.promise) {\n\t\t\tawait this._openAsync(signal, cssProp, beforeOpenDetail.promise, event);\n\t\t} else {\n\t\t\tthis._openSync(signal, cssProp, event);\n\t\t}\n\t}\n\n\n\t// async content path\n\n\tprivate async _openAsync(\n\t\tsignal: AbortSignal,\n\t\tcssProp: 'height' | 'width',\n\t\tcontentPromise: Promise<unknown>,\n\t\tevent?: Event\n\t) {\n\t\t// Race content arrival against loadingDelay.\n\t\t// If content arrives first, skip Phase 1 entirely — no spinner, no loadingHeight.\n\t\tconst contentFirst = await Promise.race([\n\t\t\tcontentPromise.then(() => true as const),\n\t\t\tnew Promise<false>(res => {\n\t\t\t\tconst t = setTimeout(() => res(false), this.config.loadingDelay);\n\t\t\t\tsignal.addEventListener('abort', () => clearTimeout(t));\n\t\t\t}),\n\t\t]).catch(() => false as const);\n\n\t\tif (signal.aborted) return;\n\n\t\tif (contentFirst) {\n\t\t\t// Fast path: content ready before loadingDelay — open like a normal panel.\n\t\t\tthis._openSync(signal, cssProp, event);\n\t\t\treturn;\n\t\t}\n\n\t\t// Slow path: loadingDelay elapsed, content not yet ready.\n\t\t// Add is-loading BEFORE any forced style flush. If the wrapper is committed\n\t\t// at opacity 1 (e.g. panel was previously open) before is-loading is added,\n\t\t// then adding is-opening creates a 1→0 opacity transition on the wrapper\n\t\t// that makes content visible throughout Phase 1. Adding is-loading first\n\t\t// ensures the wrapper is committed at opacity 0, so no transition fires.\n\t\tthis.element.classList.remove('is-closing');\n\t\tthis.element.removeAttribute('inert');\n\t\tthis.element.classList.add('is-loading');\n\n\t\t// Clear stale content so old content doesn't reappear when is-loading is removed.\n\t\tthis.element.querySelector(':scope > .panel-wrapper')?.replaceChildren();\n\n\t\t// JS already waited loadingDelay, so the spinner should appear immediately.\n\t\tthis.element.style.setProperty('--ps-loading-delay', '0ms');\n\n\t\tthis._setTriggerState(true);\n\t\tthis._persistState(true);\n\t\tthis._dispatch('panel:opening');\n\n\t\tconst body = findBody(this.element);\n\t\tif (body) lockBody(body);\n\n\t\tlet openTransition: Promise<void> | undefined;\n\n\t\tif (this.config.transitions) {\n\t\t\tthis.element.classList.add('is-opening');\n\t\t\tthis.element.style[cssProp] = '0px';\n\t\t\tvoid getComputedStyle(this.element)[cssProp]; // commit 0px before rAF\n\n\t\t\trequestAnimationFrame(() => {\n\t\t\t\tthis.element.style[cssProp] = `${this.config.loadingHeight}px`;\n\t\t\t});\n\n\t\t\topenTransition = Core.waitForTransition(this.element, cssProp);\n\t\t} else {\n\t\t\tthis.element.style[cssProp] = `${this.config.loadingHeight}px`;\n\t\t}\n\n\t\ttry {\n\t\t\tawait Promise.all([contentPromise, openTransition].filter(Boolean) as Promise<void>[]);\n\t\t} catch {\n\t\t\t// AbortError or content error — fall through to signal check below\n\t\t} finally {\n\t\t\tthis.element.classList.remove('is-loading');\n\t\t\tthis.element.style.removeProperty('--ps-loading-delay');\n\t\t}\n\n\t\tif (signal.aborted) return;\n\n\t\t// Phase 2: animate from loadingHeight to content height.\n\t\tconst currentRect = this.element.getBoundingClientRect();\n\t\tconst current = cssProp === 'height' ? currentRect.height : currentRect.width;\n\t\tthis.element.style[cssProp] = '';\n\n\t\tif (this.config.transitions) {\n\t\t\tif (Panel._nativeInterpolateSize) {\n\t\t\t\t// Inline cleared; @supports block now applies height:auto.\n\t\t\t\t// Browser transitions from loadingHeight to natural auto size.\n\t\t\t\tCore.waitForTransition(this.element, cssProp).then(() => {\n\t\t\t\t\tif (signal.aborted) return;\n\t\t\t\t\tthis.element.classList.remove('is-opening');\n\t\t\t\t\tthis.element.classList.add('is-open');\n\t\t\t\t\tthis._dispatch('panel:opened');\n\t\t\t\t\tthis._log('Opened');\n\t\t\t\t\tthis._handleAutoFocus(event);\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\t// JS fallback: measure natural size, re-lock at loadingHeight, animate.\n\t\t\t\t// Set to 'auto' before measuring — base CSS gives height:0 so the cleared\n\t\t\t\t// inline style would return 0 from getBoundingClientRect.\n\t\t\t\tthis.element.style[cssProp] = 'auto';\n\t\t\t\tconst targetRect = this.element.getBoundingClientRect();\n\t\t\t\tconst target = cssProp === 'height' ? targetRect.height : targetRect.width;\n\t\t\t\tthis.element.style[cssProp] = `${current}px`;\n\t\t\t\tvoid getComputedStyle(this.element)[cssProp];\n\n\t\t\t\trequestAnimationFrame(() => {\n\t\t\t\t\tthis.element.style[cssProp] = `${target}px`;\n\n\t\t\t\t\tCore.waitForTransition(this.element, cssProp).then(() => {\n\t\t\t\t\t\tif (signal.aborted) return;\n\t\t\t\t\t\tthis.element.style[cssProp] = '';\n\t\t\t\t\t\tthis.element.classList.remove('is-opening');\n\t\t\t\t\t\tthis.element.classList.add('is-open');\n\t\t\t\t\t\tthis._dispatch('panel:opened');\n\t\t\t\t\t\tthis._log('Opened');\n\t\t\t\t\t\tthis._handleAutoFocus(event);\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t}\n\t\t} else {\n\t\t\tthis.element.classList.remove('is-opening');\n\t\t\tthis.element.classList.add('is-open');\n\t\t\tthis._dispatch('panel:opened');\n\t\t\tthis._log('Opened');\n\t\t\tthis._handleAutoFocus(event);\n\t\t}\n\t}\n\n\n\t// sync path\n\n\tprivate _openSync(\n\t\tsignal: AbortSignal,\n\t\tcssProp: 'height' | 'width',\n\t\tevent?: Event\n\t) {\n\t\tconst isReversingClose = this.element.classList.contains('is-closing');\n\t\tconst reverseStartSize = isReversingClose\n\t\t\t? this.element.getBoundingClientRect()[cssProp === 'height' ? 'height' : 'width']\n\t\t\t: null;\n\n\t\tthis.element.classList.remove('is-closing');\n\t\tthis.element.removeAttribute('inert');\n\n\t\tconst body = findBody(this.element);\n\n\t\tif (this.config.transitions) {\n\t\t\tif (Panel._nativeInterpolateSize) {\n\t\t\t\t// Native path: lock BEFORE closeGroupSiblings so the layout flush inside\n\t\t\t\t// sibling close() sees this panel already committed at 0px, not at its\n\t\t\t\t// natural open height. Without this, the flush overwrites the 0px lock\n\t\t\t\t// and the 0→auto transition has no delta to animate.\n\t\t\t\tthis.element.classList.add('is-opening');\n\t\t\t\tthis.element.style[cssProp] = reverseStartSize !== null ? `${reverseStartSize}px` : '0px';\n\t\t\t\tif (body) lockBody(body);\n\t\t\t\tvoid getComputedStyle(this.element)[cssProp]; // commit 0px before sibling flush\n\n\t\t\t\tthis._setTriggerState(true);\n\t\t\t\tthis._persistState(true);\n\t\t\t\tthis._closeGroupSiblings();\n\t\t\t\tthis._dispatch('panel:opening');\n\n\t\t\t\trequestAnimationFrame(() => {\n\t\t\t\t\tthis.element.style[cssProp] = '';\n\t\t\t\t\tCore.waitForTransition(this.element, cssProp).then(() => {\n\t\t\t\t\t\tif (signal.aborted) return;\n\t\t\t\t\t\tthis.element.classList.remove('is-opening');\n\t\t\t\t\t\tthis.element.classList.add('is-open');\n\t\t\t\t\t\tthis._dispatch('panel:opened');\n\t\t\t\t\t\tthis._cleanupTempClose();\n\t\t\t\t\t\tthis._log('Opened');\n\t\t\t\t\t\tthis._handleAutoFocus(event);\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tthis._setTriggerState(true);\n\t\t\t\tthis._persistState(true);\n\t\t\t\tthis._closeGroupSiblings();\n\t\t\t\tthis._dispatch('panel:opening');\n\t\t\t\t// JS fallback: measure natural size, lock at 0 (or reverse start), animate\n\t\t\t\t// to target px, then clear inline on complete.\n\t\t\t\t// Set to 'auto' so getBoundingClientRect returns the natural content size.\n\t\t\t\t// The base CSS gives height:0, so without this the measured target would be 0.\n\t\t\t\tthis.element.style[cssProp] = 'auto';\n\n\t\t\t\tconst rect = this.element.getBoundingClientRect();\n\t\t\t\tconst target = cssProp === 'height' ? rect.height : rect.width;\n\n\t\t\t\tthis.element.style[cssProp] = reverseStartSize !== null ? `${reverseStartSize}px` : '0px';\n\t\t\t\tthis.element.classList.add('is-opening');\n\t\t\t\tif (body) lockBody(body);\n\t\t\t\t// Force a flush so Firefox commits the locked state before the rAF.\n\t\t\t\tvoid getComputedStyle(this.element)[cssProp];\n\n\t\t\t\trequestAnimationFrame(() => {\n\t\t\t\t\tthis.element.style[cssProp] = `${target}px`;\n\t\t\t\t\tCore.waitForTransition(this.element, cssProp).then(() => {\n\t\t\t\t\t\tif (signal.aborted) return;\n\t\t\t\t\t\tthis.element.style[cssProp] = '';\n\t\t\t\t\t\tthis.element.classList.remove('is-opening');\n\t\t\t\t\t\tthis.element.classList.add('is-open');\n\t\t\t\t\t\tthis._dispatch('panel:opened');\n\t\t\t\t\t\tthis._cleanupTempClose();\n\t\t\t\t\t\tthis._log('Opened');\n\t\t\t\t\t\tthis._handleAutoFocus(event);\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t}\n\t\t} else {\n\t\t\tthis._setTriggerState(true);\n\t\t\tthis._persistState(true);\n\t\t\tthis._closeGroupSiblings();\n\t\t\tthis._dispatch('panel:opening');\n\t\t\tthis.element.classList.add('is-open');\n\t\t\tthis._dispatch('panel:opened');\n\t\t\tthis._cleanupTempClose();\n\t\t\tthis._log('Opened');\n\t\t\tthis._handleAutoFocus(event);\n\t\t}\n\t}\n\n\n\t/**\n\t * Register a handler for async content loading before the panel opens.\n\t * The handler receives the panel element and an AbortSignal.\n\t * If it returns a Promise, the panel waits for it before animating open.\n\t */\n\tonBeforeOpen(handler: AsyncOpenHandler, options: { once?: boolean } = {}): void {\n\t\tregisterBeforeOpenHandler<BeforeOpenEventDetail>(\n\t\t\tthis.element,\n\t\t\t'panel:beforeopen',\n\t\t\t() => this.element,\n\t\t\thandler,\n\t\t\toptions\n\t\t);\n\t}\n\n\tclose(event?: Event) {\n\t\tif (!this.isOpen) return;\n\t\tif (this.config.interruptible === false && this._activating) return;\n\n\t\tthis._activating = true;\n\t\tthis.element.setAttribute('inert', '');\n\t\tthis._setTriggerState(false);\n\n\t\tconst prop = this._cssProp();\n\t\tconst body = findBody(this.element);\n\t\tconst signal = this._anim.start();\n\n\t\tthis._dispatch('panel:closing');\n\n\t\tconst finish = () => {\n\t\t\tthis.element.classList.remove('is-closing', 'is-open', 'is-opening');\n\t\t\tthis.element.style[prop] = '';\n\t\t\tif (body) unlockBody(body);\n\t\t\tthis._persistState(false);\n\t\t\tthis._dispatch('panel:closed');\n\t\t\tthis._log('Closed');\n\t\t\tconst byPointer = event instanceof PointerEvent && event.pointerType !== '';\n\t\t\tif (this.config.returnFocus && this._returnFocusTarget && !byPointer) {\n\t\t\t\tthis._returnFocusTarget.focus();\n\t\t\t}\n\t\t};\n\n\t\tif (!this.config.transitions) {\n\t\t\tfinish();\n\t\t\treturn;\n\t\t}\n\n\t\tconst rect = this.element.getBoundingClientRect();\n\t\tconst current = prop === 'height' ? rect.height : rect.width;\n\t\tthis.element.style[prop] = `${current}px`;\n\t\tthis.element.classList.remove('is-opening', 'is-open');\n\t\tthis.element.classList.add('is-closing');\n\t\t// Force a flush so Firefox sees { is-closing, height: Npx } as a committed\n\t\t// state. Without it the lock is overwritten in the rAF and Firefox sees\n\t\t// auto → 0px in one step — non-animatable, so it jumps.\n\t\tvoid getComputedStyle(this.element)[prop];\n\t\trequestAnimationFrame(() => {\n\t\t\tthis.element.style[prop] = '0px';\n\t\t\tCore.waitForTransition(this.element, prop).then(() => {\n\t\t\t\tif (signal.aborted) return;\n\t\t\t\tfinish();\n\t\t\t});\n\t\t});\n\t}\n\n\ttoggle(event?: Event) {\n\t\tif (this.element.classList.contains('is-closing')) {\n\t\t\tthis.open(event); // reverse: re-open from mid-close\n\t\t} else if (this.isOpen) {\n\t\t\tthis.close(event);\n\t\t} else {\n\t\t\tif (event?.target) {\n\t\t\t\tthis._returnFocusTarget =\n\t\t\t\t\t(event.target as HTMLElement).closest('button, a') as HTMLElement\n\t\t\t\t\t?? event.target as HTMLElement;\n\t\t\t}\n\t\t\tthis.open(event);\n\t\t}\n\t}\n\n\t/**\n\t * Tear down this instance. Removes listeners, resets element state, and\n\t * clears element.panel so Panel.init() can re-bind it.\n\t */\n\tdestroy() {\n\t\tthis._anim.start(); // pending .then() callbacks check signal.aborted\n\t\tthis._listenerController.abort();\n\n\t\tthis.element.classList.remove('is-opening', 'is-closing', 'is-loading', 'is-open');\n\t\tthis.element.style[this._cssProp()] = '';\n\t\tthis.element.setAttribute('inert', '');\n\n\t\tthis._setTriggerState(false);\n\t\tconst body = findBody(this.element);\n\t\tif (body) unlockBody(body);\n\n\t\tdelete this.element.panel;\n\t\tthis._log('Destroyed');\n\t}\n}\n\nexport default Panel;\n","import type { PanelControlConfig } from './panelcontrol.types.js';\nimport type { ShowOptions } from './panelset.types.js';\nimport { parseDataAttrs, type AttrMap } from './functions/config.js';\nimport { log, setDescribedBy } from './functions/utils.js';\n\ndeclare global {\n\tinterface HTMLElement {\n\t\tpanelControl?: PanelControl;\n\t}\n}\n\nexport class PanelControl {\n\tstatic defaults: Required<Omit<PanelControlConfig, 'selector'>> = {\n\t\tactivation: 'manual',\n\t\tdebug: false,\n\t};\n\n\tstatic readonly attrs: AttrMap<PanelControlConfig> = {\n\t\tactivation: ['activation', 'string'],\n\t\tdebug: ['debug', 'boolean'],\n\t};\n\n\telement!: HTMLElement;\n\tconfig!: Required<Omit<PanelControlConfig, 'selector'>>;\n\tprivate _setEl: HTMLElement | null = null;\n\tprivate _controller = new AbortController();\n\tprivate _isTablist = false;\n\tprivate _activationWired = false;\n\n\t/**\n\t * Initialise all PanelControl containers matching the selector.\n\t * @param selectorOrOptions - CSS selector string or config object.\n\t * @param options - Config (used when the first argument is a selector).\n\t */\n\tstatic init(selectorOrOptions: string | PanelControlConfig = '[data-panelcontrol]', options: PanelControlConfig = {}): PanelControl[] {\n\t\tlet selector: string;\n\t\tlet config: PanelControlConfig;\n\t\tif (typeof selectorOrOptions === 'string') {\n\t\t\tselector = selectorOrOptions;\n\t\t\tconfig = options;\n\t\t} else {\n\t\t\tconfig = selectorOrOptions;\n\t\t\tselector = config.selector || '[data-panelcontrol]';\n\t\t}\n\t\treturn Array.from(document.querySelectorAll<HTMLElement>(selector))\n\t\t\t.filter(el => !el.panelControl)\n\t\t\t.map(el => new PanelControl(el, config));\n\t}\n\n\tconstructor(elementOrSelector: HTMLElement | string, options: PanelControlConfig = {}) {\n\t\tconst element = typeof elementOrSelector === 'string'\n\t\t\t? document.querySelector<HTMLElement>(elementOrSelector)\n\t\t\t: elementOrSelector;\n\t\tif (!element) throw new Error(`PanelControl: No element found for selector \"${elementOrSelector}\"`);\n\t\tthis.element = element;\n\n\t\tif (element.panelControl) {\n\t\t\tconsole.warn('PanelControl: already initialized');\n\t\t\treturn element.panelControl;\n\t\t}\n\t\telement.panelControl = this;\n\n\t\t// Precedence: defaults < init() options < per-element data-attributes.\n\t\tconst dataConfig = parseDataAttrs<PanelControlConfig>(element.dataset, PanelControl.attrs);\n\t\tthis.config = { ...PanelControl.defaults, ...options, ...dataConfig } as Required<Omit<PanelControlConfig, 'selector'>>;\n\n\t\tthis._isTablist = element.getAttribute('role') === 'tablist';\n\t\tthis._bindTriggers();\n\t\tif (this._isTablist) this._setupKeyboard();\n\n\t\t// First resolution attempt now — wires the element-dependent bits (roving\n\t\t// sync, closeable reflection) if the PanelSet is already present. The getter\n\t\t// retries on later access, so a PanelSet added after init is picked up too.\n\t\tconst linked = this.panelSetElement;\n\n\t\tthis._log(`Initialized (${linked ? 'linked to a PanelSet' : 'no PanelSet found yet'}${this._isTablist ? ', tablist keyboard nav' : ''})`);\n\t}\n\n\t/**\n\t * The PanelSet container this control drives. Resolved lazily on first access\n\t * and then cached — so a PanelSet added to the DOM after init is still found.\n\t */\n\tget panelSetElement(): HTMLElement | null {\n\t\tif (!this._setEl) {\n\t\t\tconst el = this._resolvePanelSet();\n\t\t\tif (el) {\n\t\t\t\tthis._setEl = el;\n\t\t\t\tthis._onElementResolved(el);\n\t\t\t}\n\t\t}\n\t\treturn this._setEl;\n\t}\n\n\t/** The live PanelSet instance this control drives, if initialised. */\n\tget panelSet() {\n\t\treturn this.panelSetElement?.panelSet;\n\t}\n\n\t// ---- Public API -------------------------------------------------------\n\n\t/** Activate a tab's panel through the linked PanelSet. */\n\tshow(panelId: string, options?: ShowOptions): void { this.panelSet?.show(panelId, options); }\n\n\t/**\n\t * Lock or unlock a tab. PanelControl only applies the state it is told to\n\t * apply — it does not decide *when* a tab should be locked (that is the\n\t * caller's concern, e.g. a flow controller). 'disabled' sets aria-disabled so\n\t * keyboard nav skips the tab and clicks / Enter no longer activate it;\n\t * 'enabled' clears it. A tab may carry data-pc-disabled-hint=\"hintId\"; that\n\t * hint is attached to aria-describedby only while the tab is disabled, so a\n\t * focusable (aria-disabled) tab can explain why it is locked.\n\t * @param panelId - aria-controls target id of the tab(s) to update.\n\t * @param state - 'enabled' or 'disabled'.\n\t */\n\tsetTabState(panelId: string, state: 'enabled' | 'disabled'): void {\n\t\tconst disabled = state === 'disabled';\n\t\tthis.element.querySelectorAll<HTMLElement>(`[aria-controls=\"${panelId}\"]`).forEach(tab => {\n\t\t\ttab.setAttribute('aria-disabled', String(disabled));\n\t\t\tconst hint = tab.getAttribute('data-pc-disabled-hint');\n\t\t\tif (hint) setDescribedBy(tab, hint, disabled);\n\t\t\tif (this._isTablist && disabled) tab.tabIndex = -1; // can't hold the roving stop\n\t\t});\n\t\t// If the disabled tab held the roving stop, hand it to an enabled tab.\n\t\tif (this._isTablist && disabled) this._ensureRovingStop();\n\t}\n\n\t// ---- Internals --------------------------------------------------------\n\n\tprivate _log(msg: string) { log('PanelControl', this.element, this.config.debug, msg); }\n\n\t// Reflect whether the linked set closes on re-click (closable + closeOnTab)\n\t// onto the control as [data-closeable]. CSS can use it to keep the active\n\t// trigger interactive — an active-tab pointer-events:none would otherwise\n\t// block re-click-to-close. Prefers the merged config (covers JS options and\n\t// data attributes); falls back to the set element's attributes pre-init.\n\tprivate _reflectCloseable = (): void => {\n\t\tconst set = this.panelSet;\n\t\tconst el = this.panelSetElement;\n\t\tlet closeable = false;\n\t\tif (set) {\n\t\t\tcloseable = !!(set.config.closable && set.config.closeOnTab);\n\t\t} else if (el) {\n\t\t\tconst closable = el.dataset.closable != null || el.hasAttribute('closable');\n\t\t\tconst onTab = el.dataset.closeOnTab != null || el.hasAttribute('close-on-tab');\n\t\t\tcloseable = closable && onTab;\n\t\t}\n\t\tthis.element.toggleAttribute('data-closeable', closeable);\n\t};\n\n\t// Resolve the PanelSet element. An explicit target — data-panelcontrol=\"#sel\"\n\t// — wins (handy for remote or late-added sets). Otherwise discover it from the\n\t// first trigger's target panel: [aria-controls] → panel → nearest panelset\n\t// container, which is what lets the control sit anywhere in the DOM. One\n\t// PanelControl is linked to one PanelSet.\n\tprivate _resolvePanelSet(): HTMLElement | null {\n\t\tconst target = this.element.getAttribute('data-panelcontrol');\n\t\tif (target) return document.querySelector<HTMLElement>(target);\n\n\t\tconst trigger = this.element.querySelector<HTMLElement>('[aria-controls]');\n\t\tconst panelId = trigger?.getAttribute('aria-controls');\n\t\tif (!panelId) return null;\n\t\tconst panel = document.getElementById(panelId);\n\t\treturn panel?.closest<HTMLElement>('[data-panelset], ps-panelset') ?? null;\n\t}\n\n\t// Wire the element-dependent bits, once — runs when the PanelSet element is\n\t// first resolved (which may be after init, on the first click).\n\tprivate _onElementResolved(el: HTMLElement): void {\n\t\tconst { signal } = this._controller;\n\t\t// Keep roving in sync when the set activates a panel (click or programmatic).\n\t\tif (this._isTablist && !this._activationWired) {\n\t\t\tel.addEventListener('ps:activationcomplete', this._onActivation as EventListener, { signal });\n\t\t\tthis._activationWired = true;\n\t\t}\n\t\t// Reflect closeable now; re-check once the instance is ready.\n\t\tthis._reflectCloseable();\n\t\tif (!el.panelSet) {\n\t\t\tel.addEventListener('ps:ready', this._reflectCloseable, { once: true, signal });\n\t\t}\n\t}\n\n\tprivate _bindTriggers() {\n\t\tconst { signal } = this._controller;\n\t\tthis.element.querySelectorAll<HTMLElement>('[aria-controls]').forEach(trigger => {\n\t\t\ttrigger.addEventListener('click', event => {\n\t\t\t\tthis._activate(trigger, event);\n\t\t\t}, { signal });\n\t\t});\n\t}\n\n\t// Activate the panel a trigger controls, and keep roving tabindex in step.\n\t// Locked triggers (aria-disabled) never activate.\n\tprivate _activate(trigger: HTMLElement, event: Event) {\n\t\tif (trigger.getAttribute('aria-disabled') === 'true') return;\n\t\tconst panelId = trigger.getAttribute('aria-controls');\n\t\tif (!panelId) return;\n\t\t// The PanelSet does the switching. If its instance isn't there, the most\n\t\t// likely cause is a missing PanelSet.init() — warn rather than no-op silently.\n\t\tif (!this.panelSet) {\n\t\t\tthis._log(`Can’t activate '${panelId}': its PanelSet is not initialised. Add a PanelSet.init().`);\n\t\t\treturn;\n\t\t}\n\t\tthis.panelSet.show(panelId, { event }); // instance resolved lazily\n\t\tif (this._isTablist) this._setRoving(trigger);\n\t}\n\n\t// ---- Tablist keyboard pattern ----------------------------------------\n\n\tprivate _tabs(): HTMLElement[] {\n\t\treturn Array.from(this.element.querySelectorAll<HTMLElement>('[role=\"tab\"]'));\n\t}\n\n\tprivate _enabled = (tab: HTMLElement): boolean =>\n\t\ttab.getAttribute('aria-disabled') !== 'true' && !tab.hidden;\n\n\t// Roving tabindex: only the given tab is in the tab order.\n\tprivate _setRoving(active: HTMLElement) {\n\t\tthis._tabs().forEach(tab => { tab.tabIndex = tab === active ? 0 : -1; });\n\t}\n\n\t// Make sure one enabled tab still holds the tab stop (e.g. after the tab that\n\t// held it was disabled). Prefers the active tab, else the first enabled one.\n\tprivate _ensureRovingStop() {\n\t\tconst tabs = this._tabs();\n\t\tif (tabs.some(t => t.tabIndex === 0 && this._enabled(t))) return;\n\t\tconst stop = tabs.find(t => t.getAttribute('aria-selected') === 'true' && this._enabled(t))\n\t\t\t?? tabs.find(this._enabled);\n\t\tif (stop) this._setRoving(stop);\n\t}\n\n\tprivate _setupKeyboard() {\n\t\tconst tabs = this._tabs();\n\t\tif (!tabs.length) return;\n\t\t// Start with the marked-selected tab (or the first) as the tab stop.\n\t\tconst active = tabs.find(t => t.getAttribute('aria-selected') === 'true') ?? tabs[0];\n\t\tthis._setRoving(active);\n\t\tthis.element.addEventListener('keydown', this._onKeydown, { signal: this._controller.signal });\n\t\t// The ps:activationcomplete roving sync is wired in _onElementResolved,\n\t\t// once the PanelSet element is known (it may resolve after init).\n\t}\n\n\tprivate _onActivation = (e: CustomEvent<{ panelId: string }>) => {\n\t\tconst tab = this._tabs().find(t => t.getAttribute('aria-controls') === e.detail?.panelId);\n\t\tif (tab) this._setRoving(tab);\n\t};\n\n\tprivate _onKeydown = (e: KeyboardEvent) => {\n\t\tconst tabs = this._tabs().filter(this._enabled);\n\t\tif (!tabs.length) return;\n\n\t\tconst vertical = this.element.getAttribute('aria-orientation') === 'vertical';\n\t\tconst nextKey = vertical ? 'ArrowDown' : 'ArrowRight';\n\t\tconst prevKey = vertical ? 'ArrowUp' : 'ArrowLeft';\n\n\t\tconst idx = tabs.indexOf(document.activeElement as HTMLElement);\n\t\tlet target: HTMLElement | undefined;\n\n\t\tswitch (e.key) {\n\t\t\tcase nextKey: target = tabs[(idx + 1) % tabs.length]; break;\n\t\t\tcase prevKey: target = tabs[(idx - 1 + tabs.length) % tabs.length]; break;\n\t\t\tcase 'Home': target = tabs[0]; break;\n\t\t\tcase 'End': target = tabs[tabs.length - 1]; break;\n\t\t\tcase 'Enter':\n\t\t\tcase ' ':\n\t\t\t\t// Activate the focused tab (covers non-<button> tabs; buttons would\n\t\t\t\t// fire click natively, but handling it here is harmless and uniform).\n\t\t\t\tif (idx >= 0) { e.preventDefault(); this._activate(tabs[idx], e); }\n\t\t\t\treturn;\n\t\t\tdefault: return;\n\t\t}\n\n\t\tif (!target) return;\n\t\te.preventDefault();\n\t\tthis._setRoving(target);\n\t\ttarget.focus();\n\t\t// 'auto' activation, but only when it is safe to do so.\n\t\tif (this._autoActivate()) this._activate(target, e);\n\t};\n\n\t// 'auto' self-downgrades to manual when activating-on-arrow would fight the\n\t// user: autoFocus would yank focus into the panel, async content would fire\n\t// loads on every keystroke.\n\tprivate _autoActivate(): boolean {\n\t\treturn this.config.activation === 'auto'\n\t\t\t&& !this._autoFocusInPlay()\n\t\t\t&& !this.panelSet?.hasAsyncContent;\n\t}\n\n\t// autoFocus can live on the PanelSet (config / data-auto-focus / web attr) or\n\t// on an individual trigger (data-auto-focus). Any of them makes auto unsafe.\n\tprivate _autoFocusInPlay(): boolean {\n\t\tconst ps = this.panelSet;\n\t\tif (ps && ps.config.autoFocus !== false) return true;\n\n\t\tconst set = this.panelSetElement;\n\t\tconst setAttr = set && (set.dataset.autoFocus ?? set.getAttribute('auto-focus'));\n\t\tif (setAttr != null && setAttr !== 'false') return true;\n\n\t\treturn this._tabs().some(tab => {\n\t\t\tconst a = tab.getAttribute('data-auto-focus');\n\t\t\treturn a != null && a !== 'false';\n\t\t});\n\t}\n\n\t/** Remove all listeners and drop the reference from the element. */\n\tdestroy() {\n\t\tthis._controller.abort();\n\t\tdelete this.element.panelControl;\n\t\tthis._log('Destroyed');\n\t}\n}\n\nexport default PanelControl;\n","import { Panel } from './panel.js';\nimport type { PanelConfig } from './panel.types.js';\nimport { parseAttrs } from './functions/config.js';\n\nexport class PanelElement extends HTMLElement {\n\tconnectedCallback(): void {\n\t\tif (this.panel) return;\n\t\tconst options = parseAttrs<PanelConfig>(this, Panel.attrs);\n\t\tnew Panel(this, options);\n\t}\n\n\tdisconnectedCallback(): void {}\n}\n","import { PanelSet } from './panelset.js';\nimport type { PanelSetConfig } from './panelset.types.js';\nimport { parseAttrs } from './functions/config.js';\n\nexport class PanelSetElement extends HTMLElement {\n\tconnectedCallback(): void {\n\t\tif (this.panelSet) return;\n\t\tconst options = parseAttrs<PanelSetConfig>(this, PanelSet.attrs);\n\t\tnew PanelSet(this, options);\n\t}\n\n\tdisconnectedCallback(): void {}\n}\n","import { PanelControl } from './panelcontrol.js';\nimport type { PanelControlConfig } from './panelcontrol.types.js';\nimport { parseAttrs } from './functions/config.js';\n\nexport class PanelControlElement extends HTMLElement {\n\tconnectedCallback(): void {\n\t\tif (this.panelControl) return;\n\t\tconst options = parseAttrs<PanelControlConfig>(this, PanelControl.attrs);\n\t\tnew PanelControl(this, options);\n\t}\n\n\tdisconnectedCallback(): void {}\n}\n\n/**\n * Register the <ps-panelcontrol> custom element.\n * @param prefix - Element name prefix. Defaults to 'ps' → <ps-panelcontrol>.\n */\nexport function registerPanelControl(prefix = 'ps'): void {\n\tconst name = `${prefix}-panelcontrol`;\n\tif (!customElements.get(name)) customElements.define(name, PanelControlElement);\n}\n","export { PanelSet } from './panelset.js';\nexport type {\n\tPanelSetConfig,\n\tReadyEventDetail,\n\tBeforeActivateEventDetail,\n\tBeforeOpenEventDetail,\n\tActivationEventDetail,\n\tActivationAbortedEventDetail,\n\tHandlerOptions,\n\tShowOptions,\n\tAsyncContentHandler,\n} from './panelset.types.js';\n\nexport { Panel } from './panel.js';\nexport type {\n\tPanelConfig,\n\t// Aliased: PanelSet also exports a (differently shaped) BeforeOpenEventDetail.\n\tBeforeOpenEventDetail as PanelBeforeOpenEventDetail,\n\tPanelEventDetail,\n\tAsyncOpenHandler,\n} from './panel.types.js';\n\nexport { PanelControl } from './panelcontrol.js';\nexport type { PanelControlConfig } from './panelcontrol.types.js';\n\nimport { PanelElement } from './panel.element.js';\nimport { PanelSetElement } from './panelset.element.js';\nimport { PanelControlElement, registerPanelControl } from './panelcontrol.element.js';\nexport { PanelElement, PanelSetElement, PanelControlElement, registerPanelControl };\n\n\nexport function register(prefix = 'ps'): void {\n\tconst define = (name: string, ctor: CustomElementConstructor) => {\n\t\tif (!customElements.get(name)) customElements.define(name, ctor);\n\t};\n\tdefine(`${prefix}-panel`, PanelElement);\n\tdefine(`${prefix}-panelset`, PanelSetElement);\n\tdefine(`${prefix}-panelcontrol`, PanelControlElement);\n}\n\nexport { PanelSet as default } from './panelset.js';\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"panelset-core.js","names":[],"sources":["../src/js/functions/core.ts","../src/js/functions/focus.ts","../src/js/functions/persist.ts","../src/js/functions/config.ts","../src/js/functions/utils.ts","../src/js/panelset.ts","../src/js/functions/pinning.ts","../src/js/panel.ts","../src/js/panelcontrol.ts","../src/js/panel.element.ts","../src/js/panelset.element.ts","../src/js/panelcontrol.element.ts","../src/js/index.ts"],"sourcesContent":["/**\n * Animation engine for dimension transitions. One instance per element.\n * start() aborts the previous cycle and returns a fresh AbortSignal.\n * Pass it to fetch() and cancelling the animation cancels the request too.\n */\n\nexport class Core {\n\tprivate _controller = new AbortController();\n\n\tget signal(): AbortSignal {\n\t\treturn this._controller.signal;\n\t}\n\n\tstart(): AbortSignal {\n\t\tthis._controller.abort();\n\t\tthis._controller = new AbortController();\n\t\treturn this._controller.signal;\n\t}\n\n\t// Always resolves. Falls back to setTimeout if transitionend never fires —\n\t// e.g. an interrupted zero-delta transition where nothing actually moves.\n\tstatic waitForTransition(el: HTMLElement, propertyName?: string): Promise<void> {\n\t\treturn new Promise(resolve => {\n\t\t\tconst s = getComputedStyle(el);\n\t\t\tconst total = (parseFloat(s.transitionDuration) || 0)\n\t\t\t + (parseFloat(s.transitionDelay) || 0);\n\t\t\tif (total === 0) return resolve();\n\n\t\t\tlet settled = false;\n\t\t\tconst finish = () => {\n\t\t\t\tif (settled) return;\n\t\t\t\tsettled = true;\n\t\t\t\tel.removeEventListener('transitionend', handler);\n\t\t\t\tresolve();\n\t\t\t};\n\t\t\tconst handler = (e: TransitionEvent) => {\n\t\t\t\tif (e.target !== el) return;\n\t\t\t\tif (propertyName && e.propertyName !== propertyName) return;\n\t\t\t\tfinish();\n\t\t\t};\n\t\t\tel.addEventListener('transitionend', handler);\n\t\t\tsetTimeout(finish, (total + 0.05) * 1000);\n\t\t});\n\t}\n}\n","/**\n * The autoFocus mode. Pass to autoFocus() after opening a panel.\n * - true : focus the panel element itself\n * - 'heading' : focus the first heading (h1–h6)\n * - 'first' : focus the first focusable element\n * - 'input' : focus the first form field (bypasses keyboard-only check)\n * - function : custom handler, called with the panel element\n */\nexport type AutoFocusMode =\n\t| boolean\n\t| 'heading'\n\t| 'first'\n\t| 'input'\n\t| ((el: HTMLElement) => void);\n\n/**\n * Move focus into a panel after it opens.\n *\n * Skips focus when the triggering event is a mouse/touch click (not\n * keyboard), except for 'input' mode which always focuses.\n */\nexport function autoFocus(el: HTMLElement, mode: AutoFocusMode, event?: Event): void {\n\tif (!mode) return;\n\n\tif (mode !== 'input' && event) {\n\t\tconst isKeyboard =\n\t\t\tevent.type.startsWith('key') ||\n\t\t\t(event instanceof MouseEvent && event.detail === 0);\n\t\tif (!isKeyboard) return;\n\t}\n\n\tconst focus = (target: HTMLElement) => {\n\t\tsetTimeout(() => target.focus(), 100);\n\t};\n\n\tif (mode === true) {\n\t\tif (!el.hasAttribute('tabindex')) el.setAttribute('tabindex', '-1');\n\t\tfocus(el);\n\t} else if (mode === 'heading') {\n\t\tconst heading = el.querySelector<HTMLElement>('h1, h2, h3, h4, h5, h6');\n\t\tif (heading) {\n\t\t\tif (!heading.hasAttribute('tabindex')) heading.setAttribute('tabindex', '-1');\n\t\t\tfocus(heading);\n\t\t}\n\t} else if (mode === 'first') {\n\t\tconst focusable = el.querySelector<HTMLElement>(\n\t\t\t'a,button,input,select,textarea,[tabindex]:not([tabindex=\"-1\"])'\n\t\t);\n\t\tif (focusable) focus(focusable);\n\t} else if (mode === 'input') {\n\t\tconst input = el.querySelector<HTMLElement>(\n\t\t\t'input:not([type=hidden]):not([disabled]),select:not([disabled]),textarea:not([disabled])'\n\t\t);\n\t\tif (input) focus(input);\n\t} else if (typeof mode === 'function') {\n\t\tsetTimeout(() => (mode as (el: HTMLElement) => void)(el), 100);\n\t}\n}\n","/**\n * URL param + localStorage.\n */\n\n\n// URL param\n\nexport const readPanelParam = (): string[] => {\n\tconst value = new URLSearchParams(location.search).get('panel');\n\treturn value ? value.split(',').filter(Boolean) : [];\n};\n\nexport const writePanelParam = (ids: string[]): void => {\n\tconst url = new URL(location.href);\n\turl.searchParams.delete('panel');\n\n\tif (ids.length) {\n\t\tconst sep = url.search ? '&' : '?';\n\t\thistory.replaceState(null, '', `${url}${sep}panel=${ids.join(',')}`);\n\t} else {\n\t\thistory.replaceState(null, '', url);\n\t}\n};\n\n\n// localStorage\n//\n// Keys are scoped to the current page path so that auto-assigned ids\n// (panel-1, panel-2, …) on different pages don't collide in shared storage.\n// A panel persisted on /accordion stays distinct from a panel-1 on /intro.\n\nconst pageScope = (key: string): string => `${location.pathname}::${key}`;\n\nexport const readStored = (key: string): string | null =>\n\tlocalStorage.getItem(pageScope(key));\n\nexport const writeStored = (key: string, value: string): void =>\n\tlocalStorage.setItem(pageScope(key), value);","type AttrType = 'string' | 'boolean' | 'number' | 'json';\n\n/** Maps each config key to its [dataset key, value type]. */\nexport type AttrMap<T> = {\n\t[K in keyof T]?: [datasetKey: string, type: AttrType];\n};\n\nfunction _coerce(value: string, type: AttrType): unknown {\n\tswitch (type) {\n\t\tcase 'string': return value;\n\t\tcase 'boolean': return value !== 'false';\n\t\tcase 'number': return parseInt(value, 10);\n\t\tcase 'json':\n\t\t\ttry { return JSON.parse(value); }\n\t\t\tcatch { return value !== 'false'; }\n\t}\n}\n\n/**\n * Parse data attributes from a DOMStringMap into a partial config object.\n * Each entry maps a config key to a [datasetKey, type] pair.\n */\nexport function parseDataAttrs<T>(dataset: DOMStringMap, attrMap: AttrMap<T>): Partial<T> {\n\tconst config: Partial<T> = {};\n\tfor (const [configKey, entry] of Object.entries(attrMap) as [keyof T & string, [string, AttrType]][]) {\n\t\tconst [datasetKey, type] = entry;\n\t\tconst value = dataset[datasetKey];\n\t\tif (value === undefined) continue;\n\t\t(config as Record<string, unknown>)[configKey] = _coerce(value, type);\n\t}\n\treturn config;\n}\n\n/**\n * Parse plain element attributes into a partial config object.\n * Uses the same AttrMap as parseDataAttrs but reads from element.getAttribute()\n * instead of dataset. The datasetKey is converted from camelCase to kebab-case\n * to form the attribute name (e.g. \"panelAxis\" > \"panel-axis\").\n */\nexport function parseAttrs<T>(element: Element, attrMap: AttrMap<T>): Partial<T> {\n\tconst config: Partial<T> = {};\n\tfor (const [configKey, entry] of Object.entries(attrMap) as [keyof T & string, [string, AttrType]][]) {\n\t\tconst [datasetKey, type] = entry;\n\t\tconst attrName = datasetKey.replace(/([A-Z])/g, '-$1').toLowerCase();\n\t\tconst value = element.getAttribute(attrName);\n\t\tif (value === null) continue;\n\t\t(config as Record<string, unknown>)[configKey] = _coerce(value, type);\n\t}\n\treturn config;\n}\n","/**\n * Shared debug logger. Both Panel and PanelSet use this pattern.\n */\nexport function log(prefix: string, element: HTMLElement, debug: boolean, message: string): void {\n\tif (!debug) return;\n\tconsole.log(`[${prefix}] \"${element.id || 'no id'}\" -`, message);\n}\n\n\n/**\n * Add or remove id token(s) on an element's aria-describedby, leaving any other\n * tokens (author-set descriptions) intact. `ids` may be a single id or a\n * space-separated list. Used to attach a \"why is this disabled\" hint only while\n * a control is disabled, so it is not announced when the control is enabled.\n */\nexport function setDescribedBy(el: HTMLElement, ids: string, present: boolean): void {\n\tconst want = ids.split(/\\s+/).filter(Boolean);\n\tif (!want.length) return;\n\tconst cur = (el.getAttribute('aria-describedby') || '').split(/\\s+/).filter(Boolean);\n\tlet changed = false;\n\tfor (const id of want) {\n\t\tconst has = cur.includes(id);\n\t\tif (present && !has) { cur.push(id); changed = true; }\n\t\telse if (!present && has) { cur.splice(cur.indexOf(id), 1); changed = true; }\n\t}\n\tif (!changed) return;\n\tif (cur.length) el.setAttribute('aria-describedby', cur.join(' '));\n\telse el.removeAttribute('aria-describedby');\n}\n\n\nlet _interpolateSizeLogged = false;\n\n/**\n * Logs browser interpolate-size support once across all Panel and PanelSet instances.\n * No-ops if debug is false or the message has already been logged.\n */\nexport function logInterpolateSizeOnce(debug: boolean): void {\n\tif (!debug || _interpolateSizeLogged) return;\n\t_interpolateSizeLogged = true;\n\tconsole.log(\"[Panel/PanelSet] Browser supports 'interpolate-size', which will be used for opening and closing.\");\n}\n\n\n/** A before-open event detail that carries an awaitable promise for async content. */\nexport interface Awaitable {\n\t/** Underlying mechanism the open awaits; prefer waitUntil(). */\n\tpromise: Promise<unknown> | null;\n\t/** Delay the open until p resolves. Safe to call more than once (the open awaits\n\t * all of them), and safe to destructure (it closes over the detail, not `this`). */\n\twaitUntil(p: Promise<unknown>): void;\n}\n\n/**\n * Wire detail.waitUntil() so it sets detail.promise, combining via Promise.all when\n * called more than once. Direct `detail.promise = …` keeps working alongside it.\n */\nexport function attachWaitUntil(detail: Awaitable): void {\n\tdetail.waitUntil = (p) => {\n\t\tdetail.promise = detail.promise ? Promise.all([detail.promise, p]) : p;\n\t};\n}\n\n/**\n * Register an async content handler on a CustomEvent.\n * The handler receives the target element and an AbortSignal.\n * If it returns a Promise, it is handed to event.detail.waitUntil() so the\n * consuming code awaits it (combining with any other waitUntil calls).\n * Pass once:true to skip the handler after the first successful load\n * (tracked via target.dataset.loaded).\n */\nexport function registerBeforeOpenHandler<D extends Awaitable & { signal: AbortSignal }>(\n\telement: HTMLElement,\n\teventName: string,\n\tgetTarget: (detail: D) => HTMLElement,\n\thandler: (target: HTMLElement, signal: AbortSignal) => Promise<void> | void,\n\toptions: { once?: boolean } = {}\n): void {\n\tconst once = options.once === true;\n\telement.addEventListener(eventName, (e) => {\n\t\tconst event = e as CustomEvent<D>;\n\t\tconst target = getTarget(event.detail);\n\t\tconst { signal } = event.detail;\n\t\tif (once && target.dataset.loaded === 'true') return;\n\t\tconst result = handler(target, signal);\n\t\tif (result && typeof result.then === 'function') {\n\t\t\tevent.detail.waitUntil(result.then(() => {\n\t\t\t\tif (once) target.dataset.loaded = 'true';\n\t\t\t}));\n\t\t}\n\t});\n}\n","import '../style/panelset.scss';\nimport { Core } from './functions/core.js';\nimport { autoFocus } from './functions/focus.js';\nimport type { AutoFocusMode } from './functions/focus.js';\nimport { readPanelParam, writePanelParam, readStored, writeStored } from './functions/persist.js';\n\n\nimport type { PanelSetConfig, ReadyEventDetail, BeforeActivateEventDetail, BeforeOpenEventDetail, ActivationEventDetail, ActivationAbortedEventDetail, HandlerOptions, ShowOptions, AsyncContentHandler } from './panelset.types.js';\nimport { parseDataAttrs, type AttrMap } from './functions/config.js';\nimport { log, logInterpolateSizeOnce, registerBeforeOpenHandler, attachWaitUntil, setDescribedBy } from './functions/utils.js';\n\ndeclare global {\n\tinterface HTMLElement {\n\t\tpanelSet?: PanelSet;\n\t}\n}\n\nexport class PanelSet {\n\t// Default configuration\n\tstatic defaults: Required<Omit<PanelSetConfig, 'selector'>> = {\n\t\talign: 'start',\n\t\ttransitions: true,\n\t\tlevels: false,\n\t\tloop: false,\n\t\tclosable: false,\n\t\tcloseOnTab: false,\n\t\tdisabledMode: 'aria',\n\t\tloadingHeight: 150,\n\t\tloadingDelay: 320,\n\t\treturnFocus: false,\n\t\tautoFocus: false,\n\t\tpersist: false,\n\t\tdeepLink: false,\n\t\tinterruptible: true,\n\t\tmanageTriggers: true,\n\t\tmanageLabels: true,\n\t\tdebug: false\n\t};\n\n\t// Instance properties\n\telement!: HTMLElement;\n\tconfig!: Required<Omit<PanelSetConfig, 'selector'>>;\n\tpanels!: HTMLElement[];\n\tactivePanel!: HTMLElement;\n\tpanelWrapper!: HTMLElement;\n\tpendingPanel!: HTMLElement;\n\t/** True once an async content handler has been registered via onBeforeOpen(). */\n\thasAsyncContent: boolean = false;\n\n\tprivate _animShow = new Core(); // panel switching + async content\n\tprivate _animOpenClose = new Core(); // container open/close\n\tprivate _isLoadingAsync: boolean = false;\n\tprivate _activating: boolean = false;\n\tprivate _switchDirection: 'levelup' | 'leveldown' | null = null;\n\tprivate _returnFocusTarget: HTMLElement | null = null;\n\tprivate _heightObserver: ResizeObserver | null = null;\n\t// Listeners for end-of-range reflection on this set's verb buttons; aborted on\n\t// destroy so a torn-down instance stops reflecting.\n\tprivate _verbController = new AbortController();\n\n\tprivate static readonly _nativeInterpolateSize =\n\t\ttypeof CSS !== 'undefined' && CSS.supports('interpolate-size: allow-keywords');\n\n\t// One document-level click listener, shared across all PanelSet instances,\n\t// handles the verb buttons (data-ps-next / -prev / -close). Delegation (not\n\t// per-instance binding) is required because verb buttons commonly live inside\n\t// async-loaded panel content that does not exist at init. Installed lazily on\n\t// first construction — same spirit as logInterpolateSizeOnce.\n\tprivate static _verbDelegationInstalled = false;\n\n\tstatic readonly attrs: AttrMap<PanelSetConfig> = {\n\t\talign: ['panelsetAlign', 'string'],\n\t\ttransitions: ['transitions', 'json'],\n\t\tlevels: ['psLevels', 'boolean'],\n\t\tloop: ['psLoop', 'boolean'],\n\t\tclosable: ['closable', 'boolean'],\n\t\tcloseOnTab: ['closeOnTab', 'boolean'],\n\t\tdisabledMode: ['psDisabledMode', 'string'],\n\t\tloadingHeight: ['loadingHeight', 'number'],\n\t\tloadingDelay: ['loadingDelay', 'number'],\n\t\tautoFocus: ['autoFocus', 'string'],\n\t\treturnFocus: ['returnFocus', 'boolean'],\n\t\tpersist: ['panelPersist', 'boolean'],\n\t\tdeepLink: ['panelDeeplink', 'boolean'],\n\t\tinterruptible: ['interruptible', 'boolean'],\n\t\tmanageTriggers: ['manageTriggers', 'boolean'],\n\t\tmanageLabels: ['manageLabels', 'boolean'],\n\t\tdebug: ['debug', 'boolean'],\n\t};\n\n\t/**\n\t * Initialize PanelSet instances\n\t * @param selectorOrOptions - CSS selector string or config object\n\t * @param options - Additional config options (when first param is selector)\n\t * @returns Array of PanelSet instances\n\t */\n\tstatic init(selectorOrOptions: string | PanelSetConfig = {}, options: PanelSetConfig = {}): PanelSet[] {\n\t\t// Handle different call signatures\n\t\tlet selector: string;\n\t\tlet config: PanelSetConfig;\n\n\t\tif (typeof selectorOrOptions === 'string') {\n\t\t\t// init('#demo') or init('#demo', {debug: true})\n\t\t\tselector = selectorOrOptions;\n\t\t\tconfig = options;\n\t\t} else {\n\t\t\t// init() or init({selector: '#demo', debug: true})\n\t\t\tconfig = selectorOrOptions;\n\t\t\tselector = config.selector || '[data-panelset]';\n\t\t}\n\n\t\tconst elements = document.querySelectorAll<HTMLElement>(selector);\n\t\tconst instances: PanelSet[] = [];\n\n\t\telements.forEach(el => {\n\n\t\t\ttry {\n\t\t\t\tPanelSet._validateElement(el);\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error((error as Error).message);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Skip if already initialized\n\t\t\tif (el.panelSet) {\n\t\t\t\tinstances.push(el.panelSet);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst instance = new PanelSet(el, config);\n\t\t\tinstances.push(instance);\n\t\t});\n\n\t\treturn instances;\n\t}\n\n\tconstructor(elementOrSelector: HTMLElement | string, options: PanelSetConfig = {}) {\n\t\t// Handle both element and selector\n\t\tlet element: HTMLElement | null;\n\t\tif (typeof elementOrSelector === 'string') {\n\t\t\telement = document.querySelector<HTMLElement>(elementOrSelector);\n\t\t\tif (!element) {\n\t\t\t\tthrow new Error(`PanelSet: No element found for selector \"${elementOrSelector}\"`);\n\t\t\t}\n\t\t} else {\n\t\t\telement = elementOrSelector;\n\t\t}\n\n\t\tthis.element = element;\n\n\t\t// Validate element\n\t\tPanelSet._validateElement(element);\n\n\t\t// Check if already initialized\n\t\tif (element.panelSet) {\n\t\t\tconsole.warn('PanelSet: already initialized');\n\t\t\treturn element.panelSet!;\n\t\t}\n\n\t\t// Store instance on element\n\t\telement.panelSet = this;\n\n\t\t// Install the shared verb-button click delegation once (self-guards).\n\t\tPanelSet._installVerbDelegation();\n\n\t\t// Precedence: defaults < init() options < per-element data-attributes.\n\t\t// The attribute is the most specific signal, so it wins — this lets an\n\t\t// element opt out of a global flag, e.g. data-panel-persist=\"false\"\n\t\t// overriding PanelSet.init({ persist: true }).\n\t\t\n\t\tconst dataConfig = parseDataAttrs<PanelSetConfig>(element.dataset, PanelSet.attrs);\n\t\tthis.config = { ...PanelSet.defaults, ...options, ...dataConfig } as Required<Omit<PanelSetConfig, 'selector'>>;\n\n\t\t// Only this set's own panels (a nested PanelSet/Panel would otherwise have\n\t\t// its panels claimed by the outer instance). See _collectPanels.\n\t\tthis.panels = this._collectPanels();\n\n\t\tif (this.panels.length === 0) {\n\t\t\t// An empty set is valid for dynamic / windowed flows that addPanel() their\n\t\t\t// panels later. Establish the wrapper so addPanel() has somewhere to insert;\n\t\t\t// activePanel / pendingPanel are assigned on the first add (via refresh()).\n\t\t\tthis.panelWrapper =\n\t\t\t\tthis.element.querySelector<HTMLElement>(':scope > .panel-wrapper') || this._autoWrapPanels();\n\t\t\tthis._log('Initialized empty (0 panels) — ready for addPanel()');\n\t\t\tthis._dispatch<ReadyEventDetail>('ps:ready', { container: this.element, instance: this });\n\t\t\tthis._initVerbButtons();\n\t\t\tthis._observeTrackHeight();\n\t\t\treturn;\n\t\t}\n\n\n\t\tconst resolvedId = this._resolveInitialPanel();\n\t\tthis.activePanel =\n\t\t\t(resolvedId ? this.panels.find(p => p.id === resolvedId) : null)\n\t\t\t?? this.panels.find(p => p.classList.contains('active'))\n\t\t\t?? this.panels[0];\n\t\t// Direct-child wrapper only — a descendant query could return a nested\n\t\t// component's wrapper.\n\t\tthis.panelWrapper =\n\t\t\tthis.element.querySelector<HTMLElement>(':scope > .panel-wrapper') || this._autoWrapPanels();\n\n\t\tthis.pendingPanel = this.activePanel;\n\n\n\n\n\t\t// 'start' is the default (no CSS targets it), so only stamp the attribute\n\t\t// for non-default alignments — mirrors Panel and keeps the DOM clean.\n\t\tif (this.config.align !== 'start') this.element.dataset.panelsetAlign = this.config.align;\n\n\t\t// this.element.setAttribute('data-panelset-ready', ''); // For styling (turning this off for now)\n\n\t\t// Closable sets are closed by default; only an explicit .is-open opens them.\n\t\t// A closed set is inert until opened.\n\t\tif (this.config.closable && !this.element.classList.contains('is-open')) {\n\t\t\tthis.element.setAttribute('inert', '');\n\t\t}\n\n\t\tif (PanelSet._nativeInterpolateSize) logInterpolateSizeOnce(this.config.debug);\n\t\tthis._log(`Initialized (${this.panels.length} panels)`);\n\t\tthis._dispatch<ReadyEventDetail>('ps:ready', { container: this.element, instance: this });\n\n\t\tthis._internalInit();\n\n\t\tthis._initVerbButtons();\n\n\t\tthis._observeTrackHeight();\n\n\t}\n\n\t// Re-measure the tallest panel whenever the tracking parent's WIDTH changes.\n\t// A ResizeObserver reacts to any layout change (window, flex, container\n\t// queries), not just window resize, and updates promptly instead of after a\n\t// debounce — so --ps-max-height stays in step with the current width. We\n\t// guard on width because our own height writes would otherwise re-trigger it.\n\tprivate _observeTrackHeight(): void {\n\t\tconst trackingParent = this.element.closest<HTMLElement>('[data-panelset-trackheight]');\n\t\tif (!trackingParent || typeof ResizeObserver === 'undefined') return;\n\n\t\tlet lastWidth = trackingParent.clientWidth;\n\t\tlet rafId = 0;\n\t\tthis._heightObserver = new ResizeObserver(() => {\n\t\t\tconst width = trackingParent.clientWidth;\n\t\t\tif (width === lastWidth) return;\n\t\t\tlastWidth = width;\n\t\t\tcancelAnimationFrame(rafId);\n\t\t\trafId = requestAnimationFrame(() => this._updateHighestPanel());\n\t\t});\n\t\tthis._heightObserver.observe(trackingParent);\n\t}\n\n\t// Debug logging helper\n\tprivate _log(message: string): void { log('PanelSet', this.element, this.config.debug, message); }\n\n\t// Closed = a closable set without the .is-open class (and not mid-open).\n\t// Non-closable tabsets are conceptually always open, so never \"closed\".\n\tprivate get _isClosed(): boolean {\n\t\treturn this.config.closable\n\t\t\t&& !this.element.classList.contains('is-open')\n\t\t\t&& !this.element.classList.contains('is-opening');\n\t}\n\n\t// URL param + localStorage helpers\n\n\tprivate _parsePanelParam = (): string | null => {\n\t\tconst ids = readPanelParam();\n\t\treturn this.panels.find(p => p.id && ids.includes(p.id))?.id ?? null;\n\t};\n\n\tprivate _persistState = (panelId: string): void => {\n\t\tif (this.config.persist && this.element.id) writeStored(`ps:${this.element.id}`, panelId);\n\t\tif (this.config.deepLink) {\n\t\t\tthis._updatePanelParam(panelId);\n\t\t} else {\n\t\t\t// No deepLink: clean up any stale ?panel= IDs left by a snap-open.\n\t\t\tconst myIds = new Set(this.panels.map(p => p.id).filter(Boolean));\n\t\t\tconst current = readPanelParam();\n\t\t\tif (current.some(id => myIds.has(id))) writePanelParam(current.filter(id => !myIds.has(id)));\n\t\t}\n\t};\n\n\tprivate _updatePanelParam = (panelId: string): void => {\n\t\tconst myIds = new Set(this.panels.map(p => p.id).filter(Boolean));\n\t\tconst next = [...readPanelParam().filter(id => !myIds.has(id)), panelId].filter(Boolean);\n\t\twritePanelParam(next);\n\t};\n\n\tprivate _resolveInitialPanel = (): string | null => {\n\t\t// URL param is always honoured: a ?panel=id link is explicit and\n\t\t// page-specific, so shareable deep links work with no config.\n\t\tconst fromUrl = this._parsePanelParam();\n\t\tif (fromUrl) return fromUrl;\n\t\t// localStorage is opt-in only, so a stale entry can't override the markup\n\t\t// .active panel unless this set actually persists.\n\t\tif (this.config.persist) {\n\t\t\tconst { id } = this.element;\n\t\t\tif (!id) return null;\n\t\t\tconst saved = readStored(`ps:${id}`);\n\t\t\treturn saved && this.panels.some(p => p.id === saved) ? saved : null;\n\t\t}\n\t\treturn null;\n\t};\n\n\tprivate static _validateElement(element: HTMLElement): void {\n\t\tif (!element.hasAttribute('data-panelset') && !element.tagName.includes('-')) {\n\t\t\tthrow new Error('PanelSet: element must have [data-panelset] or be a custom element');\n\t\t}\n\t}\n\n\tprivate _autoWrapPanels(): HTMLElement {\n\t\tconst wrapper = document.createElement('div');\n\t\twrapper.className = 'panel-wrapper';\n\t\tthis.panels.forEach(panel => wrapper.appendChild(panel));\n\t\tthis.element.appendChild(wrapper);\n\t\treturn wrapper;\n\t}\n\n\t// Collect this set's own [role=\"tabpanel\"] panels. querySelectorAll is\n\t// unscoped, so a nested PanelSet/Panel could otherwise have its panels claimed\n\t// by an outer instance; closest() keeps only panels whose nearest panelset/\n\t// panel container is this element.\n\tprivate _collectPanels(): HTMLElement[] {\n\t\tconst ownContainer = (el: HTMLElement): boolean =>\n\t\t\tel.closest('[data-panelset], ps-panelset, [data-panel], ps-panel') === this.element;\n\t\treturn Array.from(this.element.querySelectorAll<HTMLElement>('[role=\"tabpanel\"]')).filter(ownContainer);\n\t}\n\n\tprivate _internalInit(): void {\n\t\tthis.panels.forEach(panel => {\n\t\t\tpanel.classList.remove('fade', 'incoming', 'outgoing', 'levelup', 'leveldown');\n\t\t\tif (panel !== this.activePanel) {\n\t\t\t\tpanel.hidden = true;\n\t\t\t\tpanel.classList.remove('active');\n\t\t\t} else {\n\t\t\t\tpanel.hidden = false;\n\t\t\t\tpanel.classList.add('active');\n\t\t\t}\n\t\t});\n\t\tthis.element.style.height = '';\n\t\tthis._updateHighestPanel();\n\t\tif (this.config.manageTriggers) this._updateTabTriggers(this.activePanel);\n\t\tif (this.config.manageLabels) this._reflectLabels();\n\t}\n\t\n\n\t// Dispatch custom event helper\n\tprivate _dispatch<T = unknown>(eventName: string, detail: T): void {\n\t\tthis.element.dispatchEvent(\n\t\t\tnew CustomEvent(eventName, {\n\t\t\t\tdetail,\n\t\t\t\tbubbles: true,\n\t\t\t\tcancelable: false\n\t\t\t})\n\t\t);\n\t}\n\n\t/* --- Modular helpers --- */\n\n\tprivate _getVerticalMetrics(el: HTMLElement | null): number {\n\t\tif (!el) return 0;\n\t\tconst s = getComputedStyle(el);\n\t\treturn (parseFloat(s.paddingTop) || 0) + (parseFloat(s.paddingBottom) || 0)\n\t\t + (parseFloat(s.borderTopWidth) || 0) + (parseFloat(s.borderBottomWidth) || 0);\n\t}\n\n\tprivate _measureHeight(panel: HTMLElement): number {\n\t\tlet total = panel.offsetHeight;\n\t\ttotal += this._getVerticalMetrics(this.panelWrapper);\n\t\ttotal += this._getVerticalMetrics(this.element);\n\t\treturn total;\n\t}\n\n\tprivate _updateHighestPanel(): void {\n\t\tif (this.element.hasAttribute('data-panelset-trackheight')) {\n\t\t\tconsole.warn('PanelSet: data-panelset-trackheight on parent only');\n\t\t\treturn;\n\t\t}\n\t\tconst trackingParent = this.element.closest<HTMLElement>('[data-panelset-trackheight]');\n\t\tif (!trackingParent) return;\n\n\t\t// Hide all panels before measuring each one individually.\n\t\tthis.panels.forEach(p => { p.hidden = true; p.classList.remove('active'); });\n\n\t\tlet max = 0;\n\t\tthis.panels.forEach(panel => {\n\t\t\tpanel.hidden = false;\n\t\t\tpanel.classList.add('active');\n\t\t\tpanel.style.visibility = 'hidden';\n\t\t\tconst h = this.element.offsetHeight;\n\t\t\tif (h > max) max = h;\n\t\t\tpanel.hidden = true;\n\t\t\tpanel.classList.remove('active');\n\t\t\tpanel.style.visibility = '';\n\t\t});\n\n\t\t// Restore the active panel.\n\t\tif (this.activePanel) {\n\t\t\tthis.activePanel.hidden = false;\n\t\t\tthis.activePanel.classList.add('active');\n\t\t}\n\n\t\ttrackingParent.style.setProperty('--ps-max-height', `${max}px`);\n\t\tthis._log(`Max container height: ${max}px`);\n\t}\n\n\tprivate _updateTabTriggers(activePanel: HTMLElement): void {\n\t\tthis.panels.forEach(panel => {\n\t\t\tif (!panel.id) return;\n\t\t\tdocument.querySelectorAll<HTMLElement>(`[aria-controls=\"${panel.id}\"]`).forEach(trigger => {\n\t\t\t\tconst active = panel === activePanel;\n\n\t\t\t\t// aria-selected is only valid on a role=\"tab\" inside a tablist. A real\n\t\t\t\t// tab keeps aria-selected on every tab (true/false); anything else (nav,\n\t\t\t\t// plain button group) gets aria-current on the active one and nothing on\n\t\t\t\t// the rest, so we never put aria-selected on a non-tab.\n\t\t\t\tconst isTab = trigger.getAttribute('role') === 'tab' && !!trigger.closest('[role=\"tablist\"]');\n\t\t\t\tif (isTab) {\n\t\t\t\t\ttrigger.setAttribute('aria-selected', String(active));\n\t\t\t\t\ttrigger.removeAttribute('aria-current');\n\t\t\t\t} else {\n\t\t\t\t\tif (active) trigger.setAttribute('aria-current', 'true');\n\t\t\t\t\telse trigger.removeAttribute('aria-current');\n\t\t\t\t\ttrigger.removeAttribute('aria-selected');\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\t}\n\n\t// Auto-label each panel from the trigger that controls it (the reverse of the\n\t// [aria-controls] link). This is static structure, so it runs at init / refresh\n\t// only, never on activation. Conservative: it never overrides an existing\n\t// accessible name, and only acts when one trigger unambiguously controls the panel.\n\tprivate _reflectLabels(): void {\n\t\tthis.panels.forEach(panel => {\n\t\t\tif (!panel.id) return;\n\t\t\tif (panel.hasAttribute('aria-labelledby') || panel.hasAttribute('aria-label')) return;\n\n\t\t\tconst triggers = Array.from(\n\t\t\t\tdocument.querySelectorAll<HTMLElement>(`[aria-controls=\"${panel.id}\"]`)\n\t\t\t);\n\t\t\tif (triggers.length === 0) return;\n\n\t\t\t// Prefer a single role=\"tab\" when several controls point at this panel\n\t\t\t// (e.g. a tab plus a remote control); otherwise require exactly one trigger.\n\t\t\tconst tabs = triggers.filter(t => t.getAttribute('role') === 'tab');\n\t\t\tconst labelling = tabs.length === 1 ? tabs[0]\n\t\t\t\t: triggers.length === 1 ? triggers[0]\n\t\t\t\t: null;\n\t\t\tif (!labelling) return; // ambiguous — leave naming to the author\n\n\t\t\tif (!labelling.id) labelling.id = this._uniqueId(`${panel.id}-tab`);\n\t\t\tpanel.setAttribute('aria-labelledby', labelling.id);\n\t\t});\n\t}\n\n\t// A document-unique id derived from a base, for a generated trigger id.\n\tprivate _uniqueId(base: string): string {\n\t\tlet id = base, n = 2;\n\t\twhile (document.getElementById(id)) id = `${base}-${n++}`;\n\t\treturn id;\n\t}\n\n\tprivate _setTriggersActivating(active: boolean): void {\n\t\tthis.panels.forEach(panel => {\n\t\t\tif (!panel.id) return;\n\t\t\tdocument.querySelectorAll<HTMLElement>(`[aria-controls=\"${panel.id}\"]`).forEach(trigger => {\n\t\t\t\ttrigger.classList.toggle('is-activating', active);\n\t\t\t});\n\t\t});\n\t}\n\n\tprivate _cleanupPanels(newPanel: HTMLElement): void {\n\t\tthis.panels.forEach(panel => {\n\t\t\tpanel.classList.remove('fade', 'incoming', 'outgoing', 'levelup', 'leveldown');\n\t\t\tif (panel !== newPanel) {\n\t\t\t\tpanel.classList.remove('active');\n\t\t\t\tpanel.hidden = true;\n\t\t\t} else {\n\t\t\t\tpanel.classList.add('active');\n\t\t\t\tpanel.hidden = false;\n\t\t\t\tpanel.removeAttribute('inert');\n\t\t\t}\n\t\t});\n\t\tthis.element.style.height = '';\n\t\tthis.element.classList.remove('is-transitioning');\n\t\tthis.activePanel = newPanel;\n\t\tif (this.config.manageTriggers) this._updateTabTriggers(newPanel);\n\t}\n\n\tprivate _resolveAutoFocus(resolvedTrigger: HTMLElement | null, autoFocus?: AutoFocusMode): AutoFocusMode | undefined {\n\t\tif (this.config.manageTriggers) {\n\t\t\tconst attrValue = resolvedTrigger?.getAttribute('data-auto-focus');\n\t\t\tif (attrValue != null) {\n\t\t\t\tif (attrValue === 'true') return true;\n\t\t\t\tif (attrValue === 'false') return false;\n\t\t\t\tif (attrValue === 'heading' || attrValue === 'first' || attrValue === 'input') return attrValue as AutoFocusMode;\n\t\t\t}\n\t\t}\n\t\tif (autoFocus !== undefined) return autoFocus;\n\t\treturn this.config.autoFocus;\n\t}\n\n\tprivate _handleAutoFocus(panel: HTMLElement, mode: AutoFocusMode, event?: Event): void {\n\t\tautoFocus(panel, mode, event);\n\t}\n\n\t// Shared helper for open/close\n\tprivate _animateOpenClose(isOpening: boolean, withTransition: boolean, event?: Event): void {\n\t\tconst action = isOpening ? 'opening' : 'closing';\n\t\tconst oppositeClass = `is-${isOpening ? 'closing' : 'opening'}`;\n\t\tconst actionClass = `is-${action}`;\n\n\t\tthis._log(isOpening ? 'Opening' : 'Closing');\n\n\t\tconst signal = this._animOpenClose.start();\n\n\t\t// Capture position before removing the opposite class — needed to resume\n\t\t// from where it is, not from the start, when reversing mid-animation.\n\t\tconst isReversing = this.element.classList.contains(oppositeClass);\n\t\tconst reverseStartHeight = isReversing ? this.element.offsetHeight : null;\n\n\t\t// Capture the open height BEFORE removing is-open. Since closable sets are\n\t\t// closed-by-default (height:0 when not .is-open), removing is-open collapses\n\t\t// the resting height immediately — so a later offsetHeight read would return 0\n\t\t// and the close would animate 0 → 0 (no transition). This is the real \"from\".\n\t\tconst closeStartHeight = !isOpening ? this.element.offsetHeight : null;\n\n\t\tthis.element.classList.remove(oppositeClass);\n\t\tif (!isOpening) this.element.classList.remove('is-open');\n\n\t\tif (isOpening) this.element.removeAttribute('inert');\n\n\t\t// Settle into the closed resting state (no is-open class) and restore focus.\n\t\tconst settleClosed = () => {\n\t\t\tthis.element.setAttribute('inert', '');\n\t\t\tconst byPointer = event instanceof PointerEvent && event.pointerType !== '';\n\t\t\tif (this.config.returnFocus && this._returnFocusTarget && !byPointer) {\n\t\t\t\tthis._returnFocusTarget.focus();\n\t\t\t}\n\t\t};\n\n\t\tif (withTransition && this.config.transitions) {\n\t\t\t// Mirror Panel exactly: animate under the .is-opening / .is-closing class\n\t\t\t// only, never pinning the wrapper. The wrapper reveal lives entirely in CSS\n\t\t\t// (.is-opening / .is-closing .panel-wrapper) and animates from whatever value\n\t\t\t// is currently committed — so a reclick mid-transition just swaps the class\n\t\t\t// and the browser interpolates from the live position. .is-open is added only\n\t\t\t// once the animation settles. height:auto during opening comes from the\n\t\t\t// @supports .is-opening rule, so is-open is not needed mid-animation.\n\t\t\tthis.element.classList.add(actionClass);\n\n\t\t\tif (PanelSet._nativeInterpolateSize) {\n\t\t\t\tif (isOpening) {\n\t\t\t\t\tthis.element.style.height = reverseStartHeight !== null ? `${reverseStartHeight}px` : '0px';\n\t\t\t\t\trequestAnimationFrame(() => {\n\t\t\t\t\t\tthis.element.style.height = ''; // .is-opening's height: auto takes over\n\t\t\t\t\t\tCore.waitForTransition(this.element, 'height').then(() => {\n\t\t\t\t\t\t\tif (signal.aborted) return;\n\t\t\t\t\t\t\t// Wait for the wrapper transition too — its GPU layer keeps the\n\t\t\t\t\t\t\t// clip alive in WebKit until it finishes.\n\t\t\t\t\t\t\tconst wrapperDone = this.panelWrapper\n\t\t\t\t\t\t\t\t? Core.waitForTransition(this.panelWrapper)\n\t\t\t\t\t\t\t\t: Promise.resolve();\n\t\t\t\t\t\t\twrapperDone.then(() => {\n\t\t\t\t\t\t\t\tif (signal.aborted) return;\n\t\t\t\t\t\t\t\tthis.element.classList.remove(actionClass);\n\t\t\t\t\t\t\t\tthis.element.classList.add('is-open');\n\t\t\t\t\t\t\t\tvoid this.element.offsetHeight;\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t});\n\t\t\t\t\t});\n\t\t\t\t} else {\n\t\t\t\t\t// Lock at px — interpolate-size alone can't animate auto → 0 in Firefox.\n\t\t\t\t\t// Use the height captured before is-open was removed (resting height\n\t\t\t\t\t// is already 0 now that the class is gone).\n\t\t\t\t\tthis.element.style.height = reverseStartHeight !== null\n\t\t\t\t\t\t? `${reverseStartHeight}px`\n\t\t\t\t\t\t: `${closeStartHeight}px`;\n\t\t\t\t\trequestAnimationFrame(() => {\n\t\t\t\t\t\tthis.element.style.height = ''; // closed resting height: 0 takes over\n\t\t\t\t\t\tCore.waitForTransition(this.element, 'height').then(() => {\n\t\t\t\t\t\t\tif (signal.aborted) return;\n\t\t\t\t\t\t\tthis.element.classList.remove(actionClass);\n\t\t\t\t\t\t\tvoid this.element.offsetHeight;\n\t\t\t\t\t\t\tsettleClosed();\n\t\t\t\t\t\t});\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// JS fallback: measure > lock > animate > unlock\n\t\t\t\tconst targetHeight = isOpening ? this._measureHeight(this.pendingPanel) : 0;\n\t\t\t\t// On open the current height is the (closed) start, unless reversing a\n\t\t\t\t// close mid-flight; on close use the height captured before is-open was\n\t\t\t\t// removed (resting height is already 0).\n\t\t\t\tconst currentHeight = reverseStartHeight !== null\n\t\t\t\t\t? reverseStartHeight\n\t\t\t\t\t: (isOpening ? this.element.offsetHeight : (closeStartHeight ?? 0));\n\t\t\t\tthis.element.style.height = `${currentHeight}px`;\n\t\t\t\t// Force a flush so the Npx lock is committed before the rAF changes it.\n\t\t\t\t// Without it the lock is overwritten and Firefox sees auto → 0px in one\n\t\t\t\t// step — non-animatable, so it jumps.\n\t\t\t\tvoid getComputedStyle(this.element).height;\n\n\t\t\t\trequestAnimationFrame(() => {\n\t\t\t\t\tthis.element.style.height = `${targetHeight}px`;\n\n\t\t\t\t\tCore.waitForTransition(this.element).then(() => {\n\t\t\t\t\t\tif (signal.aborted) return;\n\t\t\t\t\t\tthis.element.style.height = '';\n\t\t\t\t\t\tthis.element.classList.remove(actionClass);\n\t\t\t\t\t\tif (isOpening) this.element.classList.add('is-open');\n\t\t\t\t\t\tvoid this.element.offsetHeight;\n\t\t\t\t\t\tif (!isOpening) settleClosed();\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t}\n\t\t} else {\n\t\t\tif (isOpening) {\n\t\t\t\tthis.element.classList.add('is-open');\n\t\t\t} else {\n\t\t\t\tthis.element.classList.remove('is-open');\n\t\t\t\tsettleClosed();\n\t\t\t}\n\t\t\tthis.element.style.height = '';\n\t\t}\n\t}\n\n\t/**\n\t * Get the ID of the currently active panel\n\t * @returns Panel ID or null if no panel is active\n\t */\n\tgetActive(): string | null {\n\t\treturn this.pendingPanel?.id || null;\n\t}\n\n\t/**\n\t * Re-scan the DOM for this set's panels and reconcile internal state — the\n\t * active panel, trigger state, and the Prev/Next end-of-range disabling. Call\n\t * after adding, removing, or reordering [role=\"tabpanel\"] elements at runtime\n\t * (e.g. lazy or windowed wizards). The active panel is preserved when it is\n\t * still present; otherwise it falls back to the marked .active panel, then the\n\t * first panel. Newly added panels are initialised to the hidden state.\n\t * Call when idle (not mid-transition).\n\t */\n\trefresh(): void {\n\t\tconst previousActive = this.activePanel;\n\t\tthis.panels = this._collectPanels();\n\t\tif (this.panels.length === 0) return;\n\n\t\tthis.activePanel = (previousActive && this.panels.includes(previousActive))\n\t\t\t? previousActive\n\t\t\t: (this.panels.find(p => p.classList.contains('active')) ?? this.panels[0]);\n\t\tthis.pendingPanel = this.activePanel;\n\t\t// A runtime-added wrapper (or first wrap) may differ from the cached one.\n\t\tthis.panelWrapper = this.element.querySelector<HTMLElement>(':scope > .panel-wrapper') || this.panelWrapper;\n\n\t\tthis._internalInit();\n\t\tthis._reflectEnds(); // add/remove/reorder may change first/last → re-sync verb buttons\n\t\tthis._log(`Refreshed (${this.panels.length} panels)`);\n\t}\n\n\t/**\n\t * Insert a panel at runtime and refresh. The node is appended to the wrapper\n\t * unless a position is given. Ensures the element carries role=\"tabpanel\".\n\t * @param panel - The [role=\"tabpanel\"] element to add.\n\t * @param position - { before } / { after } an existing panel id, or { index }.\n\t * @returns The inserted panel.\n\t */\n\taddPanel(panel: HTMLElement, position?: { before?: string; after?: string; index?: number }): HTMLElement {\n\t\tif (!panel.hasAttribute('role')) panel.setAttribute('role', 'tabpanel');\n\n\t\tlet ref: HTMLElement | null = null;\n\t\tif (position?.before) {\n\t\t\tref = this.panels.find(p => p.id === position.before) ?? null;\n\t\t} else if (position?.after) {\n\t\t\tconst after = this.panels.find(p => p.id === position.after);\n\t\t\tref = (after?.nextElementSibling as HTMLElement | null) ?? null;\n\t\t} else if (typeof position?.index === 'number') {\n\t\t\tref = this.panels[position.index] ?? null;\n\t\t}\n\n\t\t(this.panelWrapper || this._autoWrapPanels()).insertBefore(panel, ref);\n\t\tthis.refresh();\n\t\treturn panel;\n\t}\n\n\t/**\n\t * Remove a panel by id and refresh.\n\t * @param panelId - ID of the panel to remove.\n\t */\n\tremovePanel(panelId: string): void {\n\t\tconst panel = this.panels.find(p => p.id === panelId);\n\t\tif (!panel) return;\n\t\tpanel.remove();\n\t\tthis.refresh();\n\t}\n\n\t/**\n\t * Destroy this instance\n\t */\n\tdestroy(): void {\n\t\tthis._animShow.start(); // abort pending .then() callbacks (they check signal.aborted)\n\t\tthis._animOpenClose.start();\n\t\tthis._heightObserver?.disconnect();\n\t\tthis._heightObserver = null;\n\t\tthis._verbController.abort(); // stop end-state reflection; the static click\n\t\t // delegation no-ops once .panelSet is gone\n\t\tdelete this.element.panelSet;\n\t\tthis._log('Destroyed');\n\t}\n\n\t// Edge info for the currently targeted panel (pendingPanel), for event detail.\n\tprivate _edgeInfo(panel: HTMLElement | undefined): { index: number; total: number; atStart: boolean; atEnd: boolean } {\n\t\tconst total = this.panels.length;\n\t\tconst index = panel ? this.panels.indexOf(panel) : -1;\n\t\treturn { index, total, atStart: index <= 0, atEnd: index === total - 1 };\n\t}\n\n\t/* --- Verb buttons (data-ps-next / -prev / -close) --- */\n\n\t// Markup sugar over next() / prev() / close(): one document-level click\n\t// listener drives every set's verb buttons. Delegation is required (not a\n\t// nicety) — verb buttons commonly live inside async-loaded panel content that\n\t// does not exist at init. Installed once, shared by all instances.\n\tprivate static _installVerbDelegation(): void {\n\t\tif (PanelSet._verbDelegationInstalled) return;\n\t\tPanelSet._verbDelegationInstalled = true;\n\t\tdocument.addEventListener('click', PanelSet._onVerbClick);\n\t}\n\n\t// Resolve the set element a verb button drives. An explicit selector value —\n\t// data-ps-next=\"#wizard\" — always wins; otherwise the nearest enclosing set.\n\tprivate static _resolveVerbSet(btn: HTMLElement, verb: 'next' | 'prev' | 'close'): HTMLElement | null {\n\t\tconst sel = btn.getAttribute(`data-ps-${verb}`);\n\t\tif (sel) return document.querySelector<HTMLElement>(sel);\n\t\treturn btn.closest<HTMLElement>('[data-panelset], ps-panelset');\n\t}\n\n\tprivate static _onVerbClick = (event: Event): void => {\n\t\tconst start = event.target;\n\t\tif (!(start instanceof Element)) return;\n\t\tconst btn = start.closest<HTMLElement>('[data-ps-next], [data-ps-prev], [data-ps-close]');\n\t\t// aria-disabled is our end-of-range guard; a native disabled button never\n\t\t// fires click, so there is nothing extra to check for that.\n\t\tif (!btn || btn.getAttribute('aria-disabled') === 'true') return;\n\n\t\tconst verb: 'next' | 'prev' | 'close' =\n\t\t\tbtn.hasAttribute('data-ps-next') ? 'next' :\n\t\t\tbtn.hasAttribute('data-ps-prev') ? 'prev' : 'close';\n\n\t\tconst setEl = PanelSet._resolveVerbSet(btn, verb);\n\t\tconst instance = setEl?.panelSet;\n\t\tif (!instance) {\n\t\t\t// Same tone as PanelControl's \"not initialised\" notice. No instance means\n\t\t\t// no merged config, so gate the log on the set element's data-debug.\n\t\t\tif (setEl) log('PanelSet', setEl, setEl.dataset.debug != null && setEl.dataset.debug !== 'false',\n\t\t\t\t`data-ps-${verb}: PanelSet is not initialised. Add a PanelSet.init().`);\n\t\t\treturn;\n\t\t}\n\t\tinstance[verb]({ event });\n\t};\n\n\t// Wire end-of-range reflection for this set's verb buttons and stamp the\n\t// initial state. Clicks are handled globally (see _installVerbDelegation); here\n\t// we only keep aria-disabled in step with the ends.\n\tprivate _initVerbButtons(): void {\n\t\tconst { signal } = this._verbController;\n\t\tthis.element.addEventListener('ps:activationstart', this._onActivationEdge, { signal });\n\t\tthis.element.addEventListener('ps:activationcomplete', this._onActivationEdge, { signal });\n\t\tthis._reflectEnds();\n\t}\n\n\t// Recompute first/last from the current panels and re-apply the verb buttons'\n\t// end-of-range state. Run at init and on refresh() — so adding / removing /\n\t// reordering panels keeps Prev/Next correct (otherwise an appended panel leaves\n\t// the old last step's Next stuck disabled until the next activation). Activation\n\t// uses the event's own edge flags instead (see _onActivationEdge).\n\tprivate _reflectEnds(): void {\n\t\tconst { atStart, atEnd } = this._edgeInfo(this.pendingPanel);\n\t\tthis._reflectVerbEndState(atStart, atEnd);\n\t}\n\n\t// Reflect on both activationstart and activationcomplete. The edge flags ride\n\t// on the event detail and describe the *targeted* panel — i.e. pendingPanel,\n\t// which is what _step() steps from. Tracking pendingPanel (not activePanel)\n\t// keeps the button state agreeing with the guard during rapid interruptible\n\t// switches and reversals.\n\tprivate _onActivationEdge = (e: Event): void => {\n\t\tconst { atStart, atEnd } = (e as CustomEvent<ActivationEventDetail>).detail;\n\t\tthis._reflectVerbEndState(atStart, atEnd);\n\t};\n\n\t// End-of-range reflection on this set's prev/next buttons: prev is disabled at\n\t// the first panel, next at the last. With loop on, the ends wrap around, so the\n\t// buttons are never disabled — leave them alone in either mode.\n\t//\n\t// 'aria' (default): toggle aria-disabled, never the native disabled (the\n\t// author's). The button stays focusable, so no focus dance is needed.\n\t//\n\t// 'native': PanelSet owns the native disabled attribute on these buttons (it\n\t// must re-enable when stepping away from an end); aria-disabled is the author's\n\t// and untouched. Disabling the focused element drops focus to <body>, so the\n\t// focus dance moves focus off a button before disabling it.\n\tprivate _reflectVerbEndState(atStart: boolean, atEnd: boolean): void {\n\t\tif (this.config.loop) return;\n\t\tconst prev = this._verbButtonsFor('prev');\n\t\tconst next = this._verbButtonsFor('next');\n\n\t\tif (this.config.disabledMode !== 'native') {\n\t\t\tprev.forEach(b => this._applyVerbDisabled(b, atStart));\n\t\t\tnext.forEach(b => this._applyVerbDisabled(b, atEnd));\n\t\t\treturn;\n\t\t}\n\n\t\t// Re-enable first (never moves focus), so the counterpart is ready to\n\t\t// receive focus before we disable an end button.\n\t\tif (!atStart) prev.forEach(b => this._applyVerbDisabled(b, false));\n\t\tif (!atEnd) next.forEach(b => this._applyVerbDisabled(b, false));\n\t\t// Then disable the end button(s). The counterpart is the opposite-direction\n\t\t// button, but only when it stays enabled (i.e. not also at its end).\n\t\tif (atStart) this._disableVerbNative(prev, atEnd ? [] : next);\n\t\tif (atEnd) this._disableVerbNative(next, atStart ? [] : prev);\n\t}\n\n\t// Apply the disabled state to one verb button per the configured mode, and keep\n\t// its aria-describedby hint (data-ps-disabled-hint) in step — the hint id is\n\t// attached only while the button is disabled, so it is not announced when the\n\t// button is usable. Native disabling that needs the focus dance routes through\n\t// _disableVerbNative, which calls this after moving focus.\n\tprivate _applyVerbDisabled(btn: HTMLElement, disabled: boolean): void {\n\t\tif (this.config.disabledMode === 'native') {\n\t\t\tif (disabled) btn.setAttribute('disabled', ''); else btn.removeAttribute('disabled');\n\t\t} else {\n\t\t\tbtn.setAttribute('aria-disabled', String(disabled));\n\t\t}\n\t\tconst hint = btn.getAttribute('data-ps-disabled-hint');\n\t\tif (hint) setDescribedBy(btn, hint, disabled);\n\t}\n\n\t// Disable verb `buttons` (native mode). Before disabling one that holds focus,\n\t// move focus to the first enabled counterpart, else to the active panel — so\n\t// focus never lands on <body>.\n\tprivate _disableVerbNative(buttons: HTMLElement[], counterparts: HTMLElement[]): void {\n\t\tbuttons.forEach(btn => {\n\t\t\tif (!btn.hasAttribute('disabled') && document.activeElement === btn) {\n\t\t\t\tconst target = counterparts.find(c => !c.hasAttribute('disabled')) ?? this._verbFocusFallback();\n\t\t\t\ttarget?.focus();\n\t\t\t}\n\t\t\tthis._applyVerbDisabled(btn, true);\n\t\t});\n\t}\n\n\t// Fallback focus target when no enabled counterpart exists: the panel the user\n\t// is on (pendingPanel during a switch, else activePanel). Make it focusable the\n\t// same way autoFocus: true does.\n\tprivate _verbFocusFallback(): HTMLElement | null {\n\t\tconst panel = this.pendingPanel ?? this.activePanel;\n\t\tif (!panel) return null;\n\t\tif (!panel.hasAttribute('tabindex')) panel.setAttribute('tabindex', '-1');\n\t\treturn panel;\n\t}\n\n\t// All data-ps-prev / data-ps-next buttons that resolve to this set — interior\n\t// (closest) and explicit-target (data-ps-next=\"#sel\") alike.\n\tprivate _verbButtonsFor(verb: 'prev' | 'next'): HTMLElement[] {\n\t\treturn Array.from(document.querySelectorAll<HTMLElement>(`[data-ps-${verb}]`))\n\t\t\t.filter(btn => PanelSet._resolveVerbSet(btn, verb) === this.element);\n\t}\n\n\t/**\n\t * Activate the next panel in DOM order. Stops at the last panel unless the\n\t * `loop` option is set, in which case it wraps to the first.\n\t * @param options - Configuration options for the activation\n\t */\n\tnext(options?: ShowOptions): void {\n\t\tthis._step(1, options);\n\t}\n\n\t/**\n\t * Activate the previous panel in DOM order. Stops at the first panel unless\n\t * the `loop` option is set, in which case it wraps to the last.\n\t * @param options - Configuration options for the activation\n\t */\n\tprev(options?: ShowOptions): void {\n\t\tthis._step(-1, options);\n\t}\n\n\tprivate _step(dir: 1 | -1, options?: ShowOptions): void {\n\t\tconst total = this.panels.length;\n\t\tif (total === 0) return;\n\t\t// Step from the panel being targeted, so rapid clicks queue correctly.\n\t\tconst from = this.panels.indexOf(this.pendingPanel);\n\t\tconst current = from === -1 ? 0 : from;\n\t\tlet target = current + dir;\n\t\tlet wrapped = false;\n\t\tif (target < 0 || target >= total) {\n\t\t\tif (!this.config.loop) return; // clamp at the ends\n\t\t\ttarget = (target + total) % total; // wrap\n\t\t\twrapped = true;\n\t\t}\n\t\tconst next = this.panels[target];\n\t\t// Only a loop wrap needs the direction hint: its DOM-order delta points the\n\t\t// wrong way (last->first looks backward), so honour the step's direction. A\n\t\t// normal step's DOM order already matches the action, so leave it alone.\n\t\tif (next && next !== this.pendingPanel)\n\t\t\tthis.show(next.id, wrapped ? { ...options, direction: dir > 0 ? 'forward' : 'backward' } : options);\n\t}\n\n\n\t/**\n\t * Open a closable panelset\n\t * @param options - Configuration options\n\t */\n\topen(options?: ShowOptions): void {\n\t\tconst {\n\t\t\tevent,\n\t\t\ttransition = true,\n\t\t\tautoFocus\n\t\t} = options || {};\n\n\t\tif (!this.config.closable) {\n\t\t\tthis._log('Not closable');\n\t\t\treturn;\n\t\t}\n\n\t\tconst isClosed = this._isClosed;\n\t\tconst isClosing = this.element.classList.contains('is-closing');\n\t\tconst isLoading = this.element.classList.contains('is-loading');\n\n\t\tif (!isClosed && !isClosing) return;\n\t\tif (this.element.classList.contains('is-transitioning') && !isLoading) return;\n\n\t\t// Derive trigger for data-attribute check\n\t\tconst resolvedTrigger = event?.target instanceof HTMLElement \n\t\t\t? (event.target.closest('button, a, [role=\"tab\"]') as HTMLElement) ?? event.target\n\t\t\t: null;\n\n\t\tconst finalAutoFocus = this._resolveAutoFocus(resolvedTrigger, autoFocus);\n\t\tif (resolvedTrigger) this._returnFocusTarget = resolvedTrigger;\n\n\t\tthis._animateOpenClose(true, transition);\n\t\t\n\t\t// Handle autofocus after opening\n\t\tif (finalAutoFocus !== false && finalAutoFocus !== undefined && this.pendingPanel) {\n\t\t\tif (transition && this.config.transitions) {\n\t\t\t\tCore.waitForTransition(this.element).then(() => {\n\t\t\t\t\tthis._handleAutoFocus(this.pendingPanel, finalAutoFocus, event);\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tthis._handleAutoFocus(this.pendingPanel, finalAutoFocus, event);\n\t\t\t}\n\t\t}\n\t}\n\n\n\t/**\n\t * Close a closable panelset\n\t * @param options - Configuration options\n\t */\n\tclose(options?: ShowOptions): void {\n\t\tconst {\n\t\t\ttransition = true,\n\t\t\tevent\n\t\t} = options || {};\n\n\t\tif (!this.config.closable) {\n\t\t\tthis._log('Not closable');\n\t\t\treturn;\n\t\t}\n\n\t\tconst isClosed = this._isClosed;\n\t\tconst isClosing = this.element.classList.contains('is-closing');\n\t\tconst isOpening = this.element.classList.contains('is-opening');\n\t\tconst isLoading = this.element.classList.contains('is-loading');\n\n\t\tif ((isClosed || isClosing) && !isOpening) return;\n\t\tif (this.element.classList.contains('is-transitioning') && !isLoading) return;\n\n\t\tthis._animateOpenClose(false, transition, event);\n\t}\n\n\n\t/**\n\t * Toggle a closable panelset between open and closed\n\t * @param options - Configuration options\n\t */\n\ttoggle(options?: ShowOptions): void {\n\t\tconst {\n\t\t\tevent,\n\t\t\ttransition = true,\n\t\t\tautoFocus\n\t\t} = options || {};\n\n\t\tconst isClosed = this._isClosed;\n\t\tconst isClosing = this.element.classList.contains('is-closing');\n\n\t\t// If closed or closing, open it\n\t\tif (isClosed || isClosing) {\n\t\t\t// Just pass through to open() - it handles priority cascade\n\t\t\tthis.open({ event, transition, autoFocus });\n\t\t} else {\n\t\t\tthis.close({ transition, event });\n\t\t}\n\t}\n\n\t/**\n\t * Register a handler for async content loading\n\t * @param handler - Async content handler function\n\t * @param options - Handler options (once: whether to load only once)\n\t */\n\tonBeforeOpen(handler: AsyncContentHandler, options: HandlerOptions = {}): void {\n\t\tthis.hasAsyncContent = true;\n\t\tregisterBeforeOpenHandler<BeforeOpenEventDetail>(\n\t\t\tthis.element,\n\t\t\t'ps:beforeopen',\n\t\t\t(detail) => detail.targetPanel,\n\t\t\thandler,\n\t\t\toptions\n\t\t);\n\t}\n\n\t/* --- Main logic --- */\n\n\n\t/**\n\t * Show a panel by ID\n\t * @param panelId - ID of the panel to show\n\t * @param options - Configuration options for this activation\n\t */\n\tasync show(panelId: string, options?: ShowOptions): Promise<void> {\n\t\tif (this.config.interruptible === false && this._activating) return;\n\n\t\tconst {\n\t\t\tevent,\n\t\t\ttransition = true,\n\t\t\tautoFocus,\n\t\t\tdirection: stepDirection\n\t\t} = options || {};\n\n\t\t// Always derive trigger from event\n\t\tconst resolvedTrigger = event?.target instanceof HTMLElement \n\t\t\t? (event.target.closest('button, a, [role=\"tab\"]') as HTMLElement) ?? event.target\n\t\t\t: null;\n\n\t\tconst finalAutoFocus = this._resolveAutoFocus(resolvedTrigger, autoFocus);\n\n\t\tconst newPanel = this.panels.find(p => p.id === panelId);\n\n\t\tif (!newPanel) {\n\t\t\tthis._log(`Panel not found: ${panelId}`);\n\t\t\treturn;\n\t\t}\n\n\t\t// Cancelable gate, fired before any state changes. A listener can call\n\t\t// preventDefault() to veto the activation — e.g. a wizard that only allows\n\t\t// a step once required fields are filled. Covers every path (tab click,\n\t\t// next()/prev(), deep link) since they all funnel through show().\n\t\tconst beforeActivate = new CustomEvent<BeforeActivateEventDetail>('ps:beforeactivate', {\n\t\t\tdetail: {\n\t\t\t\tpanelId,\n\t\t\t\ttargetPanel: newPanel,\n\t\t\t\toutgoingPanel: this.activePanel ?? null,\n\t\t\t\ttrigger: resolvedTrigger\n\t\t\t},\n\t\t\tbubbles: true,\n\t\t\tcancelable: true\n\t\t});\n\t\tif (!this.element.dispatchEvent(beforeActivate)) {\n\t\t\tthis._log(`Vetoed by ps:beforeactivate: ${panelId}`);\n\t\t\treturn;\n\t\t}\n\n\t\tconst isClosed = this._isClosed;\n\t\tconst isClosing = this.element.classList.contains('is-closing');\n\t\tconst isLoading = this.element.classList.contains('is-loading');\n\n\t\tif (newPanel === this.pendingPanel) {\n\t\t\tif (isClosed || isClosing) {\n\t\t\t\t// Same panel, but closed or closing: open it\n\t\t\t\tthis.open({ event, transition, autoFocus: finalAutoFocus });\n\t\t\t} else if (this.config.closable && this.config.closeOnTab) {\n\t\t\t\t// Clicking the active tab while open: close if closeOnTab is enabled\n\t\t\t\tthis.close({ transition, event });\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\t// Block tab switches during open/close animations (but not during async loading)\n\t\tif ((this.element.classList.contains('is-opening') || isClosing) && !isLoading) return;\n\n\t\t// When closed: silently swap to the target panel, then open\n\t\tif (isClosed) {\n\t\t\tthis.pendingPanel = newPanel;\n\t\t\tthis._cleanupPanels(newPanel);\n\t\t\tthis.open({ event, transition, autoFocus: finalAutoFocus });\n\t\t\treturn;\n\t\t}\n\n\t\tconst switchInFlight = this._activating;\n\t\tthis._activating = true;\n\t\tif (this.config.manageTriggers && this.config.interruptible === false) this._setTriggersActivating(true);\n\n\t\tconst prevPanel = this.pendingPanel;\n\t\tconst prevPanelId = prevPanel?.id;\n\t\tthis.pendingPanel = newPanel;\n\n\t\t// Reversal: a switch is mid-flight and the user re-requested the panel that\n\t\t// is still animating out (the current activePanel). Treat the in-flight\n\t\t// incoming panel (prevPanel) as the new outgoing one and apply the opposite\n\t\t// direction, so the CSS transition rolls back from the live positions.\n\t\tconst isReversal = switchInFlight && newPanel === this.activePanel && prevPanel !== newPanel;\n\t\tif (this.config.manageTriggers) this._updateTabTriggers(newPanel);\n\n\t\tthis._persistState(panelId);\n\n\t\tthis.element.classList.remove('is-loading');\n\n\t\tif (!isReversal && prevPanel && prevPanel !== this.activePanel && prevPanel !== newPanel) {\n\t\t\tprevPanel.classList.remove('incoming', 'outgoing', 'levelup', 'leveldown');\n\t\t\tif (prevPanel.hidden) {\n\t\t\t\t// Was never visible, keep hidden\n\t\t\t} else {\n\t\t\t\tprevPanel.classList.remove('active');\n\t\t\t}\n\t\t}\n\n\t\tconst wasLoadingAsync = this._isLoadingAsync;\n\n\t\t// start() aborts the previous signal — cancels in-flight animation AND\n\t\t// any fetch() that received the previous signal via ps:beforeopen.\n\t\tconst prevSignalAborted = this._animShow.signal.aborted;\n\t\tconst signal = this._animShow.start();\n\n\t\tif (!prevSignalAborted && wasLoadingAsync && prevPanelId && prevPanelId !== panelId) {\n\t\t\tthis._dispatch<ActivationAbortedEventDetail>('ps:activationaborted', {\n\t\t\t\tpanelId: prevPanelId,\n\t\t\t\ttrigger: resolvedTrigger\n\t\t\t});\n\t\t}\n\n\t\tthis._isLoadingAsync = false;\n\n\t\tthis._log(`${prevPanel?.id || 'none'} > ${panelId}`);\n\n\t\tconst beforeOpenDetail: BeforeOpenEventDetail = {\n\t\t\tpanelId,\n\t\t\ttargetPanel: newPanel,\n\t\t\toutgoingPanel: prevPanel,\n\t\t\tsignal,\n\t\t\tpromise: null,\n\t\t\twaitUntil() {} // wired below; closes over the detail so it is safe to destructure\n\t\t};\n\t\tattachWaitUntil(beforeOpenDetail);\n\n\t\tconst beforeOpenEvent = new CustomEvent('ps:beforeopen', {\n\t\t\tdetail: beforeOpenDetail,\n\t\t\tbubbles: true,\n\t\t\tcancelable: false\n\t\t});\n\n\t\tthis.element.dispatchEvent(beforeOpenEvent);\n\n\t\tconst userPromise = beforeOpenDetail.promise;\n\n\t\tif (userPromise) {\n\t\t\tthis._isLoadingAsync = true;\n\t\t\tthis._log('Waiting for content...');\n\n\t\t\t\t// Add is-loading immediately so the wrapper dims without flash.\n\t\t\t// The spinner's appearance is delayed via CSS transition-delay\n\t\t\t// (--ps-loading-delay) so it only shows for slow loads, without a JS timer.\n\t\t\tthis.element.style.setProperty('--ps-loading-delay', `${this.config.loadingDelay}ms`);\n\t\t\tthis.element.classList.add('is-loading');\n\n\t\t\tlet openTransition: Promise<void> | null = null;\n\n\t\t\tconst shouldTransition = transition !== false && this.config.transitions !== false;\n\t\t\tlet heightTransition = shouldTransition;\n\t\t\tif (typeof this.config.transitions === 'object') {\n\t\t\t\theightTransition = shouldTransition && this.config.transitions.height !== false;\n\t\t\t}\n\n\t\t\tif (heightTransition) {\n\t\t\t\tif (isClosed) {\n\t\t\t\t\tthis.element.classList.add('is-open', 'is-opening');\n\t\t\t\t\tthis.element.style.height = '0px';\n\t\t\t\t\trequestAnimationFrame(() => {\n\t\t\t\t\t\tthis.element.style.height = `${this.config.loadingHeight}px`;\n\t\t\t\t\t});\n\t\t\t\t\topenTransition = Core.waitForTransition(this.element, 'height');\n\t\t\t\t} else {\n\t\t\t\t\t// loadingHeight is a minimum: only expand if the current height is shorter.\n\t\t\t\t\tconst currentHeight = this.element.offsetHeight;\n\t\t\t\t\tconst targetHeight = Math.max(currentHeight, this.config.loadingHeight);\n\t\t\t\t\tif (targetHeight > currentHeight) {\n\t\t\t\t\t\tthis.element.style.height = `${currentHeight}px`;\n\t\t\t\t\t\trequestAnimationFrame(() => {\n\t\t\t\t\t\t\tthis.element.style.height = `${targetHeight}px`;\n\t\t\t\t\t\t});\n\t\t\t\t\t\topenTransition = Core.waitForTransition(this.element, 'height');\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tawait Promise.all([userPromise, openTransition].filter(Boolean) as Promise<void>[]);\n\n\t\t\t\tif (signal.aborted) {\n\t\t\t\t\tthis._log(`Aborted during load: ${panelId}`);\n\t\t\t\t\tthis.element.classList.remove('is-loading');\n\t\t\t\t\tthis.element.style.removeProperty('--ps-loading-delay');\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tthis._log('Content loaded');\n\n\t\t\t\tif (newPanel.dataset.loaded === 'true') {\n\t\t\t\t\tthis._updateHighestPanel();\n\t\t\t\t}\n\n\t\t\t} catch (error) {\n\t\t\t\tconst err = error as Error;\n\t\t\t\tthis._log(`Load failed: ${err.message}`);\n\t\t\t\tthis.element.classList.remove('is-loading');\n\t\t\t\tthis.element.style.removeProperty('--ps-loading-delay');\n\n\t\t\t\tif (err.name !== 'AbortError') {\n\t\t\t\t\tconsole.error('Panel load error:', error);\n\t\t\t\t}\n\n\t\t\t\tthis._activating = false;\n\t\t\t\tif (this.config.manageTriggers && this.config.interruptible === false) this._setTriggersActivating(false);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis.element.classList.remove('is-loading');\n\t\t\tthis.element.style.removeProperty('--ps-loading-delay');\n\t\t\tthis.element.classList.remove('is-opening');\n\t\t}\n\n\t\tif (signal.aborted) {\n\t\t\tthis._log(`Aborted: ${panelId}`);\n\t\t\treturn;\n\t\t}\n\n\t\tconst outgoingPanel = isReversal ? prevPanel : this.activePanel;\n\n\t\tthis._dispatch<ActivationEventDetail>('ps:activationstart', {\n\t\t\tpanelId,\n\t\t\ttrigger: resolvedTrigger,\n\t\t\toutgoingPanel,\n\t\t\t...this._edgeInfo(newPanel)\n\t\t});\n\n\t\tconst shouldTransition = transition !== false && this.config.transitions !== false;\n\n\t\tlet panelTransition = shouldTransition;\n\t\tlet heightTransition = shouldTransition;\n\n\t\tif (typeof this.config.transitions === 'object') {\n\t\t\tpanelTransition = shouldTransition && this.config.transitions.panels !== false;\n\t\t\theightTransition = shouldTransition && this.config.transitions.height !== false;\n\t\t}\n\n\t\tthis.panels.forEach(panel => panel.classList.toggle('fade', panelTransition));\n\n\t\t// Direction (levels feature). DOM order is the implicit level: a later\n\t\t// panel is \"higher\". Going to a higher panel is levelup, lower is leveldown.\n\t\t// When levels is off, no direction class is set and the default\n\t\t// (--ps-panel-in-transform-from / --ps-panel-out-transform-to) direction is always used.\n\t\tlet direction: 'levelup' | 'leveldown' | null = null;\n\t\tif (isReversal) {\n\t\t\t// Opposite of the in-flight direction. A plain (no-levels) slide always\n\t\t\t// runs in the default (levelup) direction, so its reverse is leveldown.\n\t\t\tdirection = this._switchDirection === 'leveldown' ? 'levelup' : 'leveldown';\n\t\t} else if (this.config.levels && outgoingPanel && outgoingPanel !== newPanel) {\n\t\t\t// next()/prev() pass their step direction so a loop wrap slides in the\n\t\t\t// action's direction ('forward' = like Next), not the DOM-order delta —\n\t\t\t// which would slide a last->first wrap backwards. A direct jump (e.g. a tab\n\t\t\t// click) carries no intent, so it falls back to DOM order.\n\t\t\tif (stepDirection) {\n\t\t\t\tdirection = stepDirection === 'forward' ? 'levelup' : 'leveldown';\n\t\t\t} else {\n\t\t\t\tconst fromIdx = this.panels.indexOf(outgoingPanel);\n\t\t\t\tconst toIdx = this.panels.indexOf(newPanel);\n\t\t\t\tif (fromIdx !== -1 && toIdx !== -1 && fromIdx !== toIdx) {\n\t\t\t\t\tdirection = toIdx > fromIdx ? 'levelup' : 'leveldown';\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tthis._switchDirection = direction;\n\n\t\t// Clear any stale state from an interrupted switch synchronously, so CSS\n\t\t// transitions interpolate from the current position rather than snapping.\n\t\tthis.panels.forEach(p => p.classList.remove('outgoing', 'levelup', 'leveldown'));\n\n\t\tconst startHeight = this.element.offsetHeight;\n\t\tif (heightTransition) {\n\t\t\tthis.element.style.height = `${startHeight}px`;\n\t\t}\n\n\t\tnewPanel.hidden = false;\n\t\tnewPanel.setAttribute('inert', '');\n\t\tnewPanel.classList.add('incoming');\n\t\tif (direction) newPanel.classList.add(direction);\n\t\tif (panelTransition) {\n\t\t\tthis.element.classList.add('is-transitioning');\n\t\t}\n\t\tif (outgoingPanel && outgoingPanel !== newPanel) {\n\t\t\toutgoingPanel.classList.remove('active', 'incoming');\n\t\t\toutgoingPanel.classList.add('outgoing');\n\t\t\tif (direction) outgoingPanel.classList.add(direction);\n\t\t\toutgoingPanel.hidden = false;\n\t\t\toutgoingPanel.setAttribute('inert', '');\n\t\t}\n\n\t\t// Double rAF: first frame commits incoming (opacity:0) state to the\n\t\t// rendering pipeline; second frame adds active (opacity:1) so the\n\t\t// fade-in transition fires. Single rAF causes Firefox to skip the\n\t\t// transition and show the new panel at full opacity immediately.\n\t\trequestAnimationFrame(() => requestAnimationFrame(() => {\n\t\t\tnewPanel.classList.add('active');\n\t\t\tif (outgoingPanel && outgoingPanel !== newPanel) {\n\t\t\t\toutgoingPanel.classList.remove('incoming');\n\t\t\t}\n\n\t\t\tconst targetHeight = this._measureHeight(newPanel);\n\t\t\tconst heightChanged = startHeight !== targetHeight;\n\n\t\t\tif (heightTransition) {\n\t\t\t\tthis.element.style.height = `${targetHeight}px`;\n\t\t\t}\n\n\t\t\tconst promises: Promise<void>[] = [];\n\t\t\tif (panelTransition) {\n\t\t\t\tpromises.push(Core.waitForTransition(newPanel));\n\t\t\t}\n\t\t\tif (heightTransition && heightChanged) {\n\t\t\t\tpromises.push(Core.waitForTransition(this.element));\n\t\t\t}\n\t\t\tif (!promises.length) promises.push(Promise.resolve());\n\n\t\t\tPromise.all(promises).then(() => {\n\t\t\t\tif (signal.aborted) {\n\t\t\t\t\tthis._log(`Interrupted: ${panelId}`);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tthis._cleanupPanels(newPanel);\n\t\t\t\tthis._log(`✓ ${panelId}`);\n\n\t\t\t\tif (finalAutoFocus !== false && finalAutoFocus !== undefined) {\n\t\t\t\t\tthis._handleAutoFocus(newPanel, finalAutoFocus, event);\n\t\t\t\t}\n\n\t\t\t\tthis._activating = false;\n\t\t\t\tif (this.config.manageTriggers && this.config.interruptible === false) this._setTriggersActivating(false);\n\t\t\t\tthis._dispatch<ActivationEventDetail>('ps:activationcomplete', {\n\t\t\t\t\tpanelId,\n\t\t\t\t\ttrigger: resolvedTrigger,\n\t\t\t\t\toutgoingPanel,\n\t\t\t\t\t...this._edgeInfo(newPanel)\n\t\t\t\t});\n\t\t\t});\n\t\t}));\n\t}\n\n}\n\nexport default PanelSet;","/**\n * Pinning elements (for 'push' panels)\n */\n\n\nexport const findBody = (element: HTMLElement): HTMLElement | null => {\n\tconst parent = element.parentElement;\n\tif (!parent?.querySelector('[data-panel-body]')) return null;\n\n\treturn Array.from(parent.children).find(\n\t\t(el): el is HTMLElement =>\n\t\t\tel instanceof HTMLElement && el.hasAttribute('data-panel-body')\n\t) ?? null;\n};\n\n\nexport const lockBody = (body: HTMLElement): void => {\n\tconst pins = Array.from(body.querySelectorAll<HTMLElement>('[data-panel-pin]'));\n\tif (!pins.length) return;\n\n\t// Measure everything before touching any styles — avoids layout thrashing.\n\tconst snapshots = pins.map(el => ({\n\t\tel,\n\t\tpin: el.dataset.panelPin as 'start' | 'end',\n\t\tw: el.offsetWidth,\n\t}));\n\n\tsnapshots.forEach(({ el, pin, w }) => {\n\t\tel.style.boxSizing = 'border-box';\n\t\tel.style.width = `${w}px`;\n\t\tif (pin === 'end') {\n\t\t\tel.style.marginLeft = `calc(100% - ${w}px)`;\n\t\t}\n\t});\n};\n\n\nexport const unlockBody = (body: HTMLElement): void => {\n\tbody.querySelectorAll<HTMLElement>('[data-panel-pin]').forEach(el => {\n\t\tel.style.boxSizing = '';\n\t\tel.style.width = '';\n\t\tel.style.marginLeft = '';\n\t});\n};","import '../style/panelset.scss';\nimport { Core } from './functions/core.js';\nimport { autoFocus } from './functions/focus.js';\nimport { readPanelParam, writePanelParam, readStored, writeStored } from './functions/persist.js';\nimport { findBody, lockBody, unlockBody } from './functions/pinning.js';\n\nimport type { PanelConfig, BeforeOpenEventDetail, PanelEventDetail, AsyncOpenHandler } from './panel.types.js';\nimport { parseDataAttrs, type AttrMap } from './functions/config.js';\nimport { log, logInterpolateSizeOnce, registerBeforeOpenHandler, attachWaitUntil } from './functions/utils.js';\n\ndeclare global {\n\tinterface HTMLElement {\n\t\tpanel?: Panel;\n\t}\n}\n\nfunction trueSiblings(\n\titem: HTMLElement,\n\topts: {\n\t\tgroupSelector: string;\n\t\tscopeSelector?: string;\n\t\titemSelector: string;\n\t\tfilter?: (el: HTMLElement) => boolean;\n\t}\n): HTMLElement[] {\n\tconst { groupSelector, scopeSelector = groupSelector, itemSelector, filter } = opts;\n\n\tconst belongsToGroup = (el: HTMLElement, group: HTMLElement): boolean => {\n\t\tif (el.closest(scopeSelector) !== group) return false;\n\t\tconst parentItem = el.parentElement?.closest<HTMLElement>(itemSelector);\n\t\treturn !parentItem || !group.contains(parentItem);\n\t};\n\n\tconst group = item.closest<HTMLElement>(groupSelector);\n\tif (!group || !belongsToGroup(item, group)) return [];\n\n\treturn [...group.querySelectorAll<HTMLElement>(itemSelector)].filter(sibling =>\n\t\tsibling !== item &&\n\t\tbelongsToGroup(sibling, group) &&\n\t\t(filter ? filter(sibling) : true)\n\t);\n}\n\nexport class Panel {\n\telement: HTMLElement;\n\tconfig: Required<PanelConfig>;\n\n\tprivate _returnFocusTarget: HTMLElement | null = null;\n\tprivate _tempCloseGroup: HTMLElement | null = null;\n\tprivate _anim = new Core();\n\tprivate _listenerController = new AbortController();\n\tprivate _activating = false;\n\n\tstatic defaults: Required<PanelConfig> = {\n\t\taxis: 'vertical',\n\t\talign: 'start',\n\t\tcloseOnResize: false,\n\t\ttransitions: true,\n\t\tautoFocus: false,\n\t\treturnFocus: true,\n\t\tcloseSiblings: false,\n\t\tloadingDelay: 320,\n\t\tloadingHeight: 150,\n\t\tinterruptible: true,\n\t\tpersist: false,\n\t\tdeepLink: false,\n\t\tdebug: false,\n\t};\n\n\tstatic readonly attrs: AttrMap<PanelConfig> = {\n\t\taxis: ['panelAxis', 'string'],\n\t\talign: ['panelAlign', 'string'],\n\t\tautoFocus: ['panelAutoFocus', 'string'],\n\t\tcloseOnResize: ['panelCloseOnResize', 'boolean'],\n\t\ttransitions: ['panelTransitions', 'boolean'],\n\t\treturnFocus: ['panelReturnFocus', 'boolean'],\n\t\tcloseSiblings: ['panelCloseSiblings', 'boolean'],\n\t\tloadingDelay: ['panelLoadingDelay', 'number'],\n\t\tloadingHeight: ['panelLoadingHeight', 'number'],\n\t\tinterruptible: ['panelInterruptible', 'boolean'],\n\t\tpersist: ['panelPersist', 'boolean'],\n\t\tdeepLink: ['panelDeeplink', 'boolean'],\n\t\tdebug: ['debug', 'boolean'],\n\t};\n\n\t// True when the browser supports interpolate-size: allow-keywords.\n\t// When set, CSS animates height/width 0 to/from auto natively and the JS\n\t// measure-animate cycle is skipped (open/close just toggle state classes).\n\tprivate static readonly _nativeInterpolateSize =\n\t\ttypeof CSS !== 'undefined' && CSS.supports('interpolate-size: allow-keywords');\n\n\tprivate static _autoIdCounter = 0;\n\n\tstatic init(selectorOrOptions: string | PanelConfig = '[data-panel]', options: PanelConfig = {}): Panel[] {\n\t\tlet selector: string;\n\t\tlet config: PanelConfig;\n\t\tif (typeof selectorOrOptions === 'string') {\n\t\t\tselector = selectorOrOptions;\n\t\t\tconfig = options;\n\t\t} else {\n\t\t\tconfig = selectorOrOptions;\n\t\t\tselector = '[data-panel]';\n\t\t}\n\n\t\t// Implicit trigger wiring (a [data-panel-trigger] button next to its panel)\n\t\t// is handled per-instance in the constructor — see _wireImplicitTriggers —\n\t\t// so it works for Panel.init(), the <ps-panel> web component, and any\n\t\t// panel constructed directly, not just [data-panel] in this one pass.\n\n\t\treturn Array.from(document.querySelectorAll<HTMLElement>(selector))\n\t\t\t.filter(el => !el.panel)\n\t\t\t.filter(el => !el.dataset.panel || el.dataset.panel === 'data-panel') // skip data-panel=\"id\" trigger buttons; Panel containers have no value (or Pug's boolean \"data-panel\")\n\t\t\t.map(el => new Panel(el, config));\n\t}\n\n\tconstructor(elementOrSelector: HTMLElement | string, options: PanelConfig = {}) {\n\t\tconst element = typeof elementOrSelector === 'string'\n\t\t\t? document.querySelector<HTMLElement>(elementOrSelector)\n\t\t\t: elementOrSelector;\n\t\tif (!element) throw new Error(`Panel: No element found for selector \"${elementOrSelector}\"`);\n\t\tthis.element = element;\n\t\telement.panel = this;\n\n\t\tif (!element.querySelector(':scope > .panel-wrapper')) {\n\t\t\tconst wrapper = document.createElement('div');\n\t\t\twrapper.className = 'panel-wrapper';\n\t\t\twrapper.append(...Array.from(element.childNodes));\n\t\t\telement.appendChild(wrapper);\n\t\t}\n\n\t\t// Precedence: defaults < init() options < per-element data-attributes.\n\t\t// The attribute is the most specific signal, so it wins — this lets an\n\t\t// element opt out of a global flag, e.g. data-panel-persist=\"false\"\n\t\t// overriding Panel.init({ persist: true }).\n\t\tconst dataConfig = parseDataAttrs<PanelConfig>(element.dataset, Panel.attrs);\n\t\tthis.config = { ...Panel.defaults, ...options, ...dataConfig };\n\n\t\tif (this.config.axis === 'horizontal') element.dataset.panelAxis = 'horizontal';\n\t\tif (this.config.align !== 'start') element.dataset.panelAlign = this.config.align;\n\n\t\tthis._wireImplicitTriggers();\n\t\tthis._bindTriggers();\n\n\t\t// Start open if persisted/deep-linked state says so, OR if the markup was\n\t\t// authored with .is-open. Either way snap open without animation and sync\n\t\t// the trigger's aria-expanded, so hand-authored markup needs no extra ARIA.\n\t\tif (this._resolveInitialState() || this.element.classList.contains('is-open')) {\n\t\t\tthis.element.classList.add('is-open');\n\t\t\tthis.element.removeAttribute('inert');\n\t\t\tthis._setTriggerState(true);\n\t\t\t// is-restored is present for exactly one paint so CSS can suppress\n\t\t\t// transitions on parent/sibling elements. Double rAF ensures the class\n\t\t\t// survives the first paint before being removed.\n\t\t\tthis.element.classList.add('is-restored');\n\t\t\trequestAnimationFrame(() => requestAnimationFrame(() => this.element.classList.remove('is-restored')));\n\t\t\tthis._dispatch('panel:opened');\n\t\t} else {\n\t\t\tthis.element.setAttribute('inert', '');\n\t\t}\n\n\t\tif (Panel._nativeInterpolateSize) logInterpolateSizeOnce(this.config.debug);\n\t\tthis._log('Initialized');\n\t}\n\n\tprivate _log(msg: string) { log('Panel', this.element, this.config.debug, msg); }\n\n\t// URL param + localStorage helpers \n\n\tprivate _parsePanelParam = (): boolean => {\n\t\tconst { id } = this.element;\n\t\tif (!id) return false;\n\t\treturn readPanelParam().includes(id);\n\t};\n\n\tprivate _updatePanelParam = (open: boolean): void => {\n\t\tconst { id } = this.element;\n\t\tif (!id) return;\n\t\tconst current = readPanelParam();\n\t\tconst next = open\n\t\t\t? [...new Set([...current, id])]\n\t\t\t: current.filter(i => i !== id);\n\t\twritePanelParam(next);\n\t};\n\n\t// Resolve persist/deepLink with precedence: element attribute > group attribute\n\t// > init option / default. The element's own attribute is the most specific\n\t// signal, so an explicit data-panel-persist=\"false\" opts the element out even\n\t// inside a persisting [data-panel-group]. An attribute is \"set\" only when\n\t// present; presence with any value except \"false\" means true.\n\tprivate _resolveStateConfig = (): { persist: boolean; deepLink: boolean } => {\n\t\t// undefined = attribute not present on this element.\n\t\tconst ownAttr = (name: string): boolean | undefined =>\n\t\t\tthis.element.hasAttribute(name)\n\t\t\t\t? this.element.getAttribute(name) !== 'false'\n\t\t\t\t: undefined;\n\n\t\tconst ownPersist = ownAttr('data-panel-persist');\n\t\tconst ownDeepLink = ownAttr('data-panel-deeplink');\n\n\t\t// Nearest enclosing group (stop at any parent [data-panel]).\n\t\tlet groupPersist: boolean | undefined;\n\t\tlet groupDeepLink: boolean | undefined;\n\t\tlet el = this.element.parentElement;\n\t\twhile (el) {\n\t\t\tif (el.hasAttribute('data-panel')) break;\n\t\t\tif (el.hasAttribute('data-panel-group')) {\n\t\t\t\tif (el.hasAttribute('data-panel-persist')) groupPersist = el.getAttribute('data-panel-persist') !== 'false';\n\t\t\t\tif (el.hasAttribute('data-panel-deeplink')) groupDeepLink = el.getAttribute('data-panel-deeplink') !== 'false';\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tel = el.parentElement;\n\t\t}\n\n\t\treturn {\n\t\t\tpersist: ownPersist ?? groupPersist ?? this.config.persist,\n\t\t\tdeepLink: ownDeepLink ?? groupDeepLink ?? this.config.deepLink,\n\t\t};\n\t};\n\n\tprivate _persistState = (open: boolean): void => {\n\t\tif (!this.element.id) return;\n\n\t\tconst { persist: hasPersist, deepLink: hasDeepLink } = this._resolveStateConfig();\n\n\t\tif (hasPersist) {\n\t\t\twriteStored(`panel:${this.element.id}`, open ? 'open' : 'closed');\n\t\t}\n\n\t\tif (hasDeepLink) {\n\t\t\tthis._updatePanelParam(open);\n\t\t} else if (!open && this._parsePanelParam()) {\n\t\t\t// No deepLink configured: on close, still clean up a stale ?panel= ID\n\t\t\t// left by a snap-open so the URL doesn't keep reopening the panel.\n\t\t\tthis._updatePanelParam(false);\n\t\t}\n\t};\n\n\tprivate _resolveInitialState = (): boolean => {\n\t\tconst { id } = this.element;\n\t\tif (!id) return false;\n\t\t// URL param is always honoured: a ?panel=id link is explicit and\n\t\t// page-specific, so shareable deep links work with no config.\n\t\tif (this._parsePanelParam()) return true;\n\t\t// localStorage is opt-in only. Without persist, a stale entry — e.g. an\n\t\t// auto-assigned id (panel-1, …) left by another page — must not reopen this.\n\t\tconst { persist } = this._resolveStateConfig();\n\t\tif (persist && readStored(`panel:${id}`) === 'open') return true;\n\t\treturn false;\n\t};\n\n\tprivate _cssProp = (): 'height' | 'width' =>\n\t\tthis.config.axis === 'horizontal' ? 'width' : 'height';\n\n\n\t// Turn an adjacent [data-panel-trigger] button into a wired aria-controls\n\t// trigger for THIS panel. Searching outward from the panel (rather than from\n\t// the trigger to a [data-panel] sibling) means it matches however the panel\n\t// is authored — a [data-panel] div or a <ps-panel> custom element — and runs\n\t// for every construction path, so it no longer depends on calling init().\n\t// The panel gets a stable auto-ID only when a trigger actually needs one.\n\tprivate _wireImplicitTriggers() {\n\t\tconst isPanel = (el: HTMLElement): boolean => el.hasAttribute('data-panel') || !!el.panel;\n\t\tconst wire = (trigger: HTMLElement): void => {\n\t\t\tif (!this.element.id) this.element.id = `panel-${++Panel._autoIdCounter}`;\n\t\t\ttrigger.setAttribute('aria-controls', this.element.id);\n\t\t\tif (!trigger.hasAttribute('aria-expanded')) trigger.setAttribute('aria-expanded', 'false');\n\t\t\ttrigger.removeAttribute('data-panel-trigger');\n\t\t};\n\t\t// The trigger can be the sibling itself, or a direct child of a heading\n\t\t// sibling (e.g. <h2><button data-panel-trigger>…</button></h2>).\n\t\tconst triggerIn = (el: HTMLElement): HTMLElement | null =>\n\t\t\tel.hasAttribute('data-panel-trigger') ? el\n\t\t\t: /^H[1-6]$/.test(el.tagName) ? el.querySelector<HTMLElement>(':scope > [data-panel-trigger]')\n\t\t\t: null;\n\t\t// Nearest trigger on each side, without crossing into another panel.\n\t\tfor (const dir of ['previousElementSibling', 'nextElementSibling'] as const) {\n\t\t\tlet el = this.element[dir] as HTMLElement | null;\n\t\t\twhile (el && !isPanel(el)) {\n\t\t\t\tconst trigger = triggerIn(el);\n\t\t\t\tif (trigger) { wire(trigger); break; }\n\t\t\t\tel = el[dir] as HTMLElement | null;\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate _bindTriggers() {\n\t\tconst id = this.element.id;\n\t\tif (!id) return;\n\t\tconst { signal } = this._listenerController;\n\n\t\tdocument.querySelectorAll<HTMLElement>(`[aria-controls=\"${id}\"]`).forEach(trigger => {\n\t\t\ttrigger.addEventListener('click', e => {\n\t\t\t\tthis._returnFocusTarget = trigger;\n\t\t\t\tthis.toggle(e);\n\t\t\t}, { signal });\n\t\t});\n\n\t\tthis.element.querySelectorAll<HTMLElement>('[data-panel-close]')\n\t\t\t.forEach(btn => {\n\t\t\t\tif (btn.closest('[data-panel]') !== this.element) return;\n\t\t\t\tbtn.addEventListener('click', () => this.close(), { signal });\n\t\t\t});\n\n\t\tif (this.config.closeOnResize) {\n\t\t\twindow.addEventListener('resize', () => {\n\t\t\t\tif (!this.isOpen || this.element.classList.contains('is-closing')) return;\n\t\t\t\tconst body = findBody(this.element);\n\t\t\t\tif (body) unlockBody(body);\n\t\t\t\tthis.close();\n\t\t\t}, { signal });\n\t\t}\n\t}\n\n\tprivate _setTriggerState(open: boolean) {\n\t\tconst id = this.element.id;\n\t\tif (!id) return;\n\t\tdocument.querySelectorAll(`[aria-controls=\"${id}\"]`).forEach(t =>\n\t\t\tt.setAttribute('aria-expanded', String(open))\n\t\t);\n\t}\n\n\tprivate _cleanupTempClose() {\n\t\tif (!this._tempCloseGroup) return;\n\t\tthis._tempCloseGroup.style.removeProperty('--ps-tempclose-speed');\n\t\tthis._tempCloseGroup.style.removeProperty('--ps-tempclose-timing');\n\t\tthis._tempCloseGroup = null;\n\t}\n\n\tprivate _closeGroupSiblings() {\n\t\tconst group = this.element.closest<HTMLElement>('[data-panel-group]');\n\t\tconst groupClose = group?.hasAttribute('data-panel-close-siblings') ?? false;\n\t\tif (!this.config.closeSiblings && !groupClose) return;\n\n\t\tconst toClose: HTMLElement[] = group\n\t\t\t? trueSiblings(this.element, {\n\t\t\t\tgroupSelector: '[data-panel-group]',\n\t\t\t\titemSelector: '[data-panel]',\n\t\t\t\tfilter: el => !!el.panel?.isOpen,\n\t\t\t})\n\t\t\t: Array.from(this.element.parentElement?.children ?? [])\n\t\t\t\t.filter((el): el is HTMLElement =>\n\t\t\t\t\tel instanceof HTMLElement && el !== this.element && !!el.panel?.isOpen\n\t\t\t\t);\n\n\t\tif (toClose.length && group) {\n\t\t\tgroup.style.setProperty('--ps-tempclose-speed', 'var(--ps-open-speed)');\n\t\t\tgroup.style.setProperty('--ps-tempclose-timing', 'var(--ps-open-timing)');\n\t\t\tthis._tempCloseGroup = group;\n\t\t}\n\n\t\ttoClose.forEach(el => {\n\t\t\tel.panel!._returnFocusTarget = null;\n\t\t\tel.panel!.close();\n\t\t});\n\t}\n\n\tprivate _handleAutoFocus(event?: Event) {\n\t\tif (!this.config.autoFocus) return;\n\t\tautoFocus(this.element, this.config.autoFocus, event);\n\t}\n\n\tprivate _dispatch(name: string) {\n\t\tif (name === 'panel:opened' || name === 'panel:closed') this._activating = false;\n\t\tconst detail: PanelEventDetail = { trigger: this._returnFocusTarget };\n\t\tthis.element.dispatchEvent(new CustomEvent(name, { detail, bubbles: true }));\n\t}\n\n\t// Public API\n\n\tget isOpen(): boolean {\n\t\treturn this.element.classList.contains('is-open') || this.element.classList.contains('is-opening');\n\t}\n\n\n\n\t// open\n\n\tasync open(event?: Event) {\n\t\tif (this.isOpen && !this.element.classList.contains('is-closing')) return;\n\t\tif (this.config.interruptible === false && this._activating) return;\n\n\t\tthis._activating = true;\n\t\tconst signal = this._anim.start();\n\t\tconst cssProp = this._cssProp();\n\n\t\tconst beforeOpenDetail: BeforeOpenEventDetail = {\n\t\t\tsignal,\n\t\t\tpromise: null,\n\t\t\twaitUntil() {}, // wired below; closes over the detail so it is safe to destructure\n\t\t\ttrigger: this._returnFocusTarget\n\t\t};\n\t\tattachWaitUntil(beforeOpenDetail);\n\n\t\tthis.element.dispatchEvent(\n\t\t\tnew CustomEvent('panel:beforeopen', { detail: beforeOpenDetail, bubbles: true })\n\t\t);\n\n\t\tif (beforeOpenDetail.promise) {\n\t\t\tawait this._openAsync(signal, cssProp, beforeOpenDetail.promise, event);\n\t\t} else {\n\t\t\tthis._openSync(signal, cssProp, event);\n\t\t}\n\t}\n\n\n\t// async content path\n\n\tprivate async _openAsync(\n\t\tsignal: AbortSignal,\n\t\tcssProp: 'height' | 'width',\n\t\tcontentPromise: Promise<unknown>,\n\t\tevent?: Event\n\t) {\n\t\t// Race content arrival against loadingDelay.\n\t\t// If content arrives first, skip Phase 1 entirely — no spinner, no loadingHeight.\n\t\tconst contentFirst = await Promise.race([\n\t\t\tcontentPromise.then(() => true as const),\n\t\t\tnew Promise<false>(res => {\n\t\t\t\tconst t = setTimeout(() => res(false), this.config.loadingDelay);\n\t\t\t\tsignal.addEventListener('abort', () => clearTimeout(t));\n\t\t\t}),\n\t\t]).catch(() => false as const);\n\n\t\tif (signal.aborted) return;\n\n\t\tif (contentFirst) {\n\t\t\t// Fast path: content ready before loadingDelay — open like a normal panel.\n\t\t\tthis._openSync(signal, cssProp, event);\n\t\t\treturn;\n\t\t}\n\n\t\t// Slow path: loadingDelay elapsed, content not yet ready.\n\t\t// Add is-loading BEFORE any forced style flush. If the wrapper is committed\n\t\t// at opacity 1 (e.g. panel was previously open) before is-loading is added,\n\t\t// then adding is-opening creates a 1→0 opacity transition on the wrapper\n\t\t// that makes content visible throughout Phase 1. Adding is-loading first\n\t\t// ensures the wrapper is committed at opacity 0, so no transition fires.\n\t\tthis.element.classList.remove('is-closing');\n\t\tthis.element.removeAttribute('inert');\n\t\tthis.element.classList.add('is-loading');\n\n\t\t// Clear stale content so old content doesn't reappear when is-loading is removed.\n\t\tthis.element.querySelector(':scope > .panel-wrapper')?.replaceChildren();\n\n\t\t// JS already waited loadingDelay, so the spinner should appear immediately.\n\t\tthis.element.style.setProperty('--ps-loading-delay', '0ms');\n\n\t\tthis._setTriggerState(true);\n\t\tthis._persistState(true);\n\t\tthis._dispatch('panel:opening');\n\n\t\tconst body = findBody(this.element);\n\t\tif (body) lockBody(body);\n\n\t\tlet openTransition: Promise<void> | undefined;\n\n\t\tif (this.config.transitions) {\n\t\t\tthis.element.classList.add('is-opening');\n\t\t\tthis.element.style[cssProp] = '0px';\n\t\t\tvoid getComputedStyle(this.element)[cssProp]; // commit 0px before rAF\n\n\t\t\trequestAnimationFrame(() => {\n\t\t\t\tthis.element.style[cssProp] = `${this.config.loadingHeight}px`;\n\t\t\t});\n\n\t\t\topenTransition = Core.waitForTransition(this.element, cssProp);\n\t\t} else {\n\t\t\tthis.element.style[cssProp] = `${this.config.loadingHeight}px`;\n\t\t}\n\n\t\ttry {\n\t\t\tawait Promise.all([contentPromise, openTransition].filter(Boolean) as Promise<void>[]);\n\t\t} catch {\n\t\t\t// AbortError or content error — fall through to signal check below\n\t\t} finally {\n\t\t\tthis.element.classList.remove('is-loading');\n\t\t\tthis.element.style.removeProperty('--ps-loading-delay');\n\t\t}\n\n\t\tif (signal.aborted) return;\n\n\t\t// Phase 2: animate from loadingHeight to content height.\n\t\tconst currentRect = this.element.getBoundingClientRect();\n\t\tconst current = cssProp === 'height' ? currentRect.height : currentRect.width;\n\t\tthis.element.style[cssProp] = '';\n\n\t\tif (this.config.transitions) {\n\t\t\tif (Panel._nativeInterpolateSize) {\n\t\t\t\t// Inline cleared; @supports block now applies height:auto.\n\t\t\t\t// Browser transitions from loadingHeight to natural auto size.\n\t\t\t\tCore.waitForTransition(this.element, cssProp).then(() => {\n\t\t\t\t\tif (signal.aborted) return;\n\t\t\t\t\tthis.element.classList.remove('is-opening');\n\t\t\t\t\tthis.element.classList.add('is-open');\n\t\t\t\t\tthis._dispatch('panel:opened');\n\t\t\t\t\tthis._log('Opened');\n\t\t\t\t\tthis._handleAutoFocus(event);\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\t// JS fallback: measure natural size, re-lock at loadingHeight, animate.\n\t\t\t\t// Set to 'auto' before measuring — base CSS gives height:0 so the cleared\n\t\t\t\t// inline style would return 0 from getBoundingClientRect.\n\t\t\t\tthis.element.style[cssProp] = 'auto';\n\t\t\t\tconst targetRect = this.element.getBoundingClientRect();\n\t\t\t\tconst target = cssProp === 'height' ? targetRect.height : targetRect.width;\n\t\t\t\tthis.element.style[cssProp] = `${current}px`;\n\t\t\t\tvoid getComputedStyle(this.element)[cssProp];\n\n\t\t\t\trequestAnimationFrame(() => {\n\t\t\t\t\tthis.element.style[cssProp] = `${target}px`;\n\n\t\t\t\t\tCore.waitForTransition(this.element, cssProp).then(() => {\n\t\t\t\t\t\tif (signal.aborted) return;\n\t\t\t\t\t\tthis.element.style[cssProp] = '';\n\t\t\t\t\t\tthis.element.classList.remove('is-opening');\n\t\t\t\t\t\tthis.element.classList.add('is-open');\n\t\t\t\t\t\tthis._dispatch('panel:opened');\n\t\t\t\t\t\tthis._log('Opened');\n\t\t\t\t\t\tthis._handleAutoFocus(event);\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t}\n\t\t} else {\n\t\t\tthis.element.classList.remove('is-opening');\n\t\t\tthis.element.classList.add('is-open');\n\t\t\tthis._dispatch('panel:opened');\n\t\t\tthis._log('Opened');\n\t\t\tthis._handleAutoFocus(event);\n\t\t}\n\t}\n\n\n\t// sync path\n\n\tprivate _openSync(\n\t\tsignal: AbortSignal,\n\t\tcssProp: 'height' | 'width',\n\t\tevent?: Event\n\t) {\n\t\tconst isReversingClose = this.element.classList.contains('is-closing');\n\t\tconst reverseStartSize = isReversingClose\n\t\t\t? this.element.getBoundingClientRect()[cssProp === 'height' ? 'height' : 'width']\n\t\t\t: null;\n\n\t\tthis.element.classList.remove('is-closing');\n\t\tthis.element.removeAttribute('inert');\n\n\t\tconst body = findBody(this.element);\n\n\t\tif (this.config.transitions) {\n\t\t\tif (Panel._nativeInterpolateSize) {\n\t\t\t\t// Native path: lock BEFORE closeGroupSiblings so the layout flush inside\n\t\t\t\t// sibling close() sees this panel already committed at 0px, not at its\n\t\t\t\t// natural open height. Without this, the flush overwrites the 0px lock\n\t\t\t\t// and the 0→auto transition has no delta to animate.\n\t\t\t\tthis.element.classList.add('is-opening');\n\t\t\t\tthis.element.style[cssProp] = reverseStartSize !== null ? `${reverseStartSize}px` : '0px';\n\t\t\t\tif (body) lockBody(body);\n\t\t\t\tvoid getComputedStyle(this.element)[cssProp]; // commit 0px before sibling flush\n\n\t\t\t\tthis._setTriggerState(true);\n\t\t\t\tthis._persistState(true);\n\t\t\t\tthis._closeGroupSiblings();\n\t\t\t\tthis._dispatch('panel:opening');\n\n\t\t\t\trequestAnimationFrame(() => {\n\t\t\t\t\tthis.element.style[cssProp] = '';\n\t\t\t\t\tCore.waitForTransition(this.element, cssProp).then(() => {\n\t\t\t\t\t\tif (signal.aborted) return;\n\t\t\t\t\t\tthis.element.classList.remove('is-opening');\n\t\t\t\t\t\tthis.element.classList.add('is-open');\n\t\t\t\t\t\tthis._dispatch('panel:opened');\n\t\t\t\t\t\tthis._cleanupTempClose();\n\t\t\t\t\t\tthis._log('Opened');\n\t\t\t\t\t\tthis._handleAutoFocus(event);\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tthis._setTriggerState(true);\n\t\t\t\tthis._persistState(true);\n\t\t\t\tthis._closeGroupSiblings();\n\t\t\t\tthis._dispatch('panel:opening');\n\t\t\t\t// JS fallback: measure natural size, lock at 0 (or reverse start), animate\n\t\t\t\t// to target px, then clear inline on complete.\n\t\t\t\t// Set to 'auto' so getBoundingClientRect returns the natural content size.\n\t\t\t\t// The base CSS gives height:0, so without this the measured target would be 0.\n\t\t\t\tthis.element.style[cssProp] = 'auto';\n\n\t\t\t\tconst rect = this.element.getBoundingClientRect();\n\t\t\t\tconst target = cssProp === 'height' ? rect.height : rect.width;\n\n\t\t\t\tthis.element.style[cssProp] = reverseStartSize !== null ? `${reverseStartSize}px` : '0px';\n\t\t\t\tthis.element.classList.add('is-opening');\n\t\t\t\tif (body) lockBody(body);\n\t\t\t\t// Force a flush so Firefox commits the locked state before the rAF.\n\t\t\t\tvoid getComputedStyle(this.element)[cssProp];\n\n\t\t\t\trequestAnimationFrame(() => {\n\t\t\t\t\tthis.element.style[cssProp] = `${target}px`;\n\t\t\t\t\tCore.waitForTransition(this.element, cssProp).then(() => {\n\t\t\t\t\t\tif (signal.aborted) return;\n\t\t\t\t\t\tthis.element.style[cssProp] = '';\n\t\t\t\t\t\tthis.element.classList.remove('is-opening');\n\t\t\t\t\t\tthis.element.classList.add('is-open');\n\t\t\t\t\t\tthis._dispatch('panel:opened');\n\t\t\t\t\t\tthis._cleanupTempClose();\n\t\t\t\t\t\tthis._log('Opened');\n\t\t\t\t\t\tthis._handleAutoFocus(event);\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t}\n\t\t} else {\n\t\t\tthis._setTriggerState(true);\n\t\t\tthis._persistState(true);\n\t\t\tthis._closeGroupSiblings();\n\t\t\tthis._dispatch('panel:opening');\n\t\t\tthis.element.classList.add('is-open');\n\t\t\tthis._dispatch('panel:opened');\n\t\t\tthis._cleanupTempClose();\n\t\t\tthis._log('Opened');\n\t\t\tthis._handleAutoFocus(event);\n\t\t}\n\t}\n\n\n\t/**\n\t * Register a handler for async content loading before the panel opens.\n\t * The handler receives the panel element and an AbortSignal.\n\t * If it returns a Promise, the panel waits for it before animating open.\n\t */\n\tonBeforeOpen(handler: AsyncOpenHandler, options: { once?: boolean } = {}): void {\n\t\tregisterBeforeOpenHandler<BeforeOpenEventDetail>(\n\t\t\tthis.element,\n\t\t\t'panel:beforeopen',\n\t\t\t() => this.element,\n\t\t\thandler,\n\t\t\toptions\n\t\t);\n\t}\n\n\tclose(event?: Event) {\n\t\tif (!this.isOpen) return;\n\t\tif (this.config.interruptible === false && this._activating) return;\n\n\t\tthis._activating = true;\n\t\tthis.element.setAttribute('inert', '');\n\t\tthis._setTriggerState(false);\n\n\t\tconst prop = this._cssProp();\n\t\tconst body = findBody(this.element);\n\t\tconst signal = this._anim.start();\n\n\t\tthis._dispatch('panel:closing');\n\n\t\tconst finish = () => {\n\t\t\tthis.element.classList.remove('is-closing', 'is-open', 'is-opening');\n\t\t\tthis.element.style[prop] = '';\n\t\t\tif (body) unlockBody(body);\n\t\t\tthis._persistState(false);\n\t\t\tthis._dispatch('panel:closed');\n\t\t\tthis._log('Closed');\n\t\t\tconst byPointer = event instanceof PointerEvent && event.pointerType !== '';\n\t\t\tif (this.config.returnFocus && this._returnFocusTarget && !byPointer) {\n\t\t\t\tthis._returnFocusTarget.focus();\n\t\t\t}\n\t\t};\n\n\t\tif (!this.config.transitions) {\n\t\t\tfinish();\n\t\t\treturn;\n\t\t}\n\n\t\tconst rect = this.element.getBoundingClientRect();\n\t\tconst current = prop === 'height' ? rect.height : rect.width;\n\t\tthis.element.style[prop] = `${current}px`;\n\t\tthis.element.classList.remove('is-opening', 'is-open');\n\t\tthis.element.classList.add('is-closing');\n\t\t// Force a flush so Firefox sees { is-closing, height: Npx } as a committed\n\t\t// state. Without it the lock is overwritten in the rAF and Firefox sees\n\t\t// auto → 0px in one step — non-animatable, so it jumps.\n\t\tvoid getComputedStyle(this.element)[prop];\n\t\trequestAnimationFrame(() => {\n\t\t\tthis.element.style[prop] = '0px';\n\t\t\tCore.waitForTransition(this.element, prop).then(() => {\n\t\t\t\tif (signal.aborted) return;\n\t\t\t\tfinish();\n\t\t\t});\n\t\t});\n\t}\n\n\ttoggle(event?: Event) {\n\t\tif (this.element.classList.contains('is-closing')) {\n\t\t\tthis.open(event); // reverse: re-open from mid-close\n\t\t} else if (this.isOpen) {\n\t\t\tthis.close(event);\n\t\t} else {\n\t\t\tif (event?.target) {\n\t\t\t\tthis._returnFocusTarget =\n\t\t\t\t\t(event.target as HTMLElement).closest('button, a') as HTMLElement\n\t\t\t\t\t?? event.target as HTMLElement;\n\t\t\t}\n\t\t\tthis.open(event);\n\t\t}\n\t}\n\n\t/**\n\t * Tear down this instance. Removes listeners, resets element state, and\n\t * clears element.panel so Panel.init() can re-bind it.\n\t */\n\tdestroy() {\n\t\tthis._anim.start(); // pending .then() callbacks check signal.aborted\n\t\tthis._listenerController.abort();\n\n\t\tthis.element.classList.remove('is-opening', 'is-closing', 'is-loading', 'is-open');\n\t\tthis.element.style[this._cssProp()] = '';\n\t\tthis.element.setAttribute('inert', '');\n\n\t\tthis._setTriggerState(false);\n\t\tconst body = findBody(this.element);\n\t\tif (body) unlockBody(body);\n\n\t\tdelete this.element.panel;\n\t\tthis._log('Destroyed');\n\t}\n}\n\nexport default Panel;\n","import type { PanelControlConfig } from './panelcontrol.types.js';\nimport type { ShowOptions } from './panelset.types.js';\nimport { parseDataAttrs, type AttrMap } from './functions/config.js';\nimport { log, setDescribedBy } from './functions/utils.js';\n\ndeclare global {\n\tinterface HTMLElement {\n\t\tpanelControl?: PanelControl;\n\t}\n}\n\nexport class PanelControl {\n\tstatic defaults: Required<Omit<PanelControlConfig, 'selector'>> = {\n\t\tactivation: 'manual',\n\t\tdebug: false,\n\t};\n\n\tstatic readonly attrs: AttrMap<PanelControlConfig> = {\n\t\tactivation: ['activation', 'string'],\n\t\tdebug: ['debug', 'boolean'],\n\t};\n\n\telement!: HTMLElement;\n\tconfig!: Required<Omit<PanelControlConfig, 'selector'>>;\n\tprivate _setEl: HTMLElement | null = null;\n\tprivate _controller = new AbortController();\n\tprivate _isTablist = false;\n\tprivate _activationWired = false;\n\n\t/**\n\t * Initialise all PanelControl containers matching the selector.\n\t * @param selectorOrOptions - CSS selector string or config object.\n\t * @param options - Config (used when the first argument is a selector).\n\t */\n\tstatic init(selectorOrOptions: string | PanelControlConfig = '[data-panelcontrol]', options: PanelControlConfig = {}): PanelControl[] {\n\t\tlet selector: string;\n\t\tlet config: PanelControlConfig;\n\t\tif (typeof selectorOrOptions === 'string') {\n\t\t\tselector = selectorOrOptions;\n\t\t\tconfig = options;\n\t\t} else {\n\t\t\tconfig = selectorOrOptions;\n\t\t\tselector = config.selector || '[data-panelcontrol]';\n\t\t}\n\t\treturn Array.from(document.querySelectorAll<HTMLElement>(selector))\n\t\t\t.filter(el => !el.panelControl)\n\t\t\t.map(el => new PanelControl(el, config));\n\t}\n\n\tconstructor(elementOrSelector: HTMLElement | string, options: PanelControlConfig = {}) {\n\t\tconst element = typeof elementOrSelector === 'string'\n\t\t\t? document.querySelector<HTMLElement>(elementOrSelector)\n\t\t\t: elementOrSelector;\n\t\tif (!element) throw new Error(`PanelControl: No element found for selector \"${elementOrSelector}\"`);\n\t\tthis.element = element;\n\n\t\tif (element.panelControl) {\n\t\t\tconsole.warn('PanelControl: already initialized');\n\t\t\treturn element.panelControl;\n\t\t}\n\t\telement.panelControl = this;\n\n\t\t// Precedence: defaults < init() options < per-element data-attributes.\n\t\tconst dataConfig = parseDataAttrs<PanelControlConfig>(element.dataset, PanelControl.attrs);\n\t\tthis.config = { ...PanelControl.defaults, ...options, ...dataConfig } as Required<Omit<PanelControlConfig, 'selector'>>;\n\n\t\tthis._isTablist = element.getAttribute('role') === 'tablist';\n\t\tthis._bindTriggers();\n\t\tif (this._isTablist) this._setupKeyboard();\n\n\t\t// First resolution attempt now — wires the element-dependent bits (roving\n\t\t// sync, closeable reflection) if the PanelSet is already present. The getter\n\t\t// retries on later access, so a PanelSet added after init is picked up too.\n\t\tconst linked = this.panelSetElement;\n\n\t\tthis._log(`Initialized (${linked ? 'linked to a PanelSet' : 'no PanelSet found yet'}${this._isTablist ? ', tablist keyboard nav' : ''})`);\n\t}\n\n\t/**\n\t * The PanelSet container this control drives. Resolved lazily on first access\n\t * and then cached — so a PanelSet added to the DOM after init is still found.\n\t */\n\tget panelSetElement(): HTMLElement | null {\n\t\tif (!this._setEl) {\n\t\t\tconst el = this._resolvePanelSet();\n\t\t\tif (el) {\n\t\t\t\tthis._setEl = el;\n\t\t\t\tthis._onElementResolved(el);\n\t\t\t}\n\t\t}\n\t\treturn this._setEl;\n\t}\n\n\t/** The live PanelSet instance this control drives, if initialised. */\n\tget panelSet() {\n\t\treturn this.panelSetElement?.panelSet;\n\t}\n\n\t// ---- Public API -------------------------------------------------------\n\n\t/** Activate a tab's panel through the linked PanelSet. */\n\tshow(panelId: string, options?: ShowOptions): void { this.panelSet?.show(panelId, options); }\n\n\t/**\n\t * Lock or unlock a tab. PanelControl only applies the state it is told to\n\t * apply — it does not decide *when* a tab should be locked (that is the\n\t * caller's concern, e.g. a flow controller). 'disabled' sets aria-disabled so\n\t * keyboard nav skips the tab and clicks / Enter no longer activate it;\n\t * 'enabled' clears it. A tab may carry data-pc-disabled-hint=\"hintId\"; that\n\t * hint is attached to aria-describedby only while the tab is disabled, so a\n\t * focusable (aria-disabled) tab can explain why it is locked.\n\t * @param panelId - aria-controls target id of the tab(s) to update.\n\t * @param state - 'enabled' or 'disabled'.\n\t */\n\tsetTabState(panelId: string, state: 'enabled' | 'disabled'): void {\n\t\tconst disabled = state === 'disabled';\n\t\tthis.element.querySelectorAll<HTMLElement>(`[aria-controls=\"${panelId}\"]`).forEach(tab => {\n\t\t\ttab.setAttribute('aria-disabled', String(disabled));\n\t\t\tconst hint = tab.getAttribute('data-pc-disabled-hint');\n\t\t\tif (hint) setDescribedBy(tab, hint, disabled);\n\t\t\tif (this._isTablist && disabled) tab.tabIndex = -1; // can't hold the roving stop\n\t\t});\n\t\t// If the disabled tab held the roving stop, hand it to an enabled tab.\n\t\tif (this._isTablist && disabled) this._ensureRovingStop();\n\t}\n\n\t// ---- Internals --------------------------------------------------------\n\n\tprivate _log(msg: string) { log('PanelControl', this.element, this.config.debug, msg); }\n\n\t// Reflect whether the linked set closes on re-click (closable + closeOnTab)\n\t// onto the control as [data-closeable]. CSS can use it to keep the active\n\t// trigger interactive — an active-tab pointer-events:none would otherwise\n\t// block re-click-to-close. Prefers the merged config (covers JS options and\n\t// data attributes); falls back to the set element's attributes pre-init.\n\tprivate _reflectCloseable = (): void => {\n\t\tconst set = this.panelSet;\n\t\tconst el = this.panelSetElement;\n\t\tlet closeable = false;\n\t\tif (set) {\n\t\t\tcloseable = !!(set.config.closable && set.config.closeOnTab);\n\t\t} else if (el) {\n\t\t\tconst closable = el.dataset.closable != null || el.hasAttribute('closable');\n\t\t\tconst onTab = el.dataset.closeOnTab != null || el.hasAttribute('close-on-tab');\n\t\t\tcloseable = closable && onTab;\n\t\t}\n\t\tthis.element.toggleAttribute('data-closeable', closeable);\n\t};\n\n\t// Resolve the PanelSet element. An explicit target — data-panelcontrol=\"#sel\"\n\t// — wins (handy for remote or late-added sets). Otherwise discover it from the\n\t// first trigger's target panel: [aria-controls] → panel → nearest panelset\n\t// container, which is what lets the control sit anywhere in the DOM. One\n\t// PanelControl is linked to one PanelSet.\n\tprivate _resolvePanelSet(): HTMLElement | null {\n\t\tconst target = this.element.getAttribute('data-panelcontrol');\n\t\tif (target) return document.querySelector<HTMLElement>(target);\n\n\t\tconst trigger = this.element.querySelector<HTMLElement>('[aria-controls]');\n\t\tconst panelId = trigger?.getAttribute('aria-controls');\n\t\tif (!panelId) return null;\n\t\tconst panel = document.getElementById(panelId);\n\t\treturn panel?.closest<HTMLElement>('[data-panelset], ps-panelset') ?? null;\n\t}\n\n\t// Wire the element-dependent bits, once — runs when the PanelSet element is\n\t// first resolved (which may be after init, on the first click).\n\tprivate _onElementResolved(el: HTMLElement): void {\n\t\tconst { signal } = this._controller;\n\t\t// Keep roving in sync when the set activates a panel (click or programmatic).\n\t\tif (this._isTablist && !this._activationWired) {\n\t\t\tel.addEventListener('ps:activationcomplete', this._onActivation as EventListener, { signal });\n\t\t\tthis._activationWired = true;\n\t\t}\n\t\t// Reflect closeable now; re-check once the instance is ready.\n\t\tthis._reflectCloseable();\n\t\tif (!el.panelSet) {\n\t\t\tel.addEventListener('ps:ready', this._reflectCloseable, { once: true, signal });\n\t\t}\n\t}\n\n\tprivate _bindTriggers() {\n\t\tconst { signal } = this._controller;\n\t\tthis.element.querySelectorAll<HTMLElement>('[aria-controls]').forEach(trigger => {\n\t\t\ttrigger.addEventListener('click', event => {\n\t\t\t\tthis._activate(trigger, event);\n\t\t\t}, { signal });\n\t\t});\n\t}\n\n\t// Activate the panel a trigger controls, and keep roving tabindex in step.\n\t// Locked triggers (aria-disabled) never activate.\n\tprivate _activate(trigger: HTMLElement, event: Event) {\n\t\tif (trigger.getAttribute('aria-disabled') === 'true') return;\n\t\tconst panelId = trigger.getAttribute('aria-controls');\n\t\tif (!panelId) return;\n\t\t// The PanelSet does the switching. If its instance isn't there, the most\n\t\t// likely cause is a missing PanelSet.init() — warn rather than no-op silently.\n\t\tif (!this.panelSet) {\n\t\t\tthis._log(`Can’t activate '${panelId}': its PanelSet is not initialised. Add a PanelSet.init().`);\n\t\t\treturn;\n\t\t}\n\t\tthis.panelSet.show(panelId, { event }); // instance resolved lazily\n\t\tif (this._isTablist) this._setRoving(trigger);\n\t}\n\n\t// ---- Tablist keyboard pattern ----------------------------------------\n\n\tprivate _tabs(): HTMLElement[] {\n\t\treturn Array.from(this.element.querySelectorAll<HTMLElement>('[role=\"tab\"]'));\n\t}\n\n\tprivate _enabled = (tab: HTMLElement): boolean =>\n\t\ttab.getAttribute('aria-disabled') !== 'true' && !tab.hidden;\n\n\t// Roving tabindex: only the given tab is in the tab order.\n\tprivate _setRoving(active: HTMLElement) {\n\t\tthis._tabs().forEach(tab => { tab.tabIndex = tab === active ? 0 : -1; });\n\t}\n\n\t// Make sure one enabled tab still holds the tab stop (e.g. after the tab that\n\t// held it was disabled). Prefers the active tab, else the first enabled one.\n\tprivate _ensureRovingStop() {\n\t\tconst tabs = this._tabs();\n\t\tif (tabs.some(t => t.tabIndex === 0 && this._enabled(t))) return;\n\t\tconst stop = tabs.find(t => t.getAttribute('aria-selected') === 'true' && this._enabled(t))\n\t\t\t?? tabs.find(this._enabled);\n\t\tif (stop) this._setRoving(stop);\n\t}\n\n\tprivate _setupKeyboard() {\n\t\tconst tabs = this._tabs();\n\t\tif (!tabs.length) return;\n\t\t// Start with the marked-selected tab (or the first) as the tab stop.\n\t\tconst active = tabs.find(t => t.getAttribute('aria-selected') === 'true') ?? tabs[0];\n\t\tthis._setRoving(active);\n\t\tthis.element.addEventListener('keydown', this._onKeydown, { signal: this._controller.signal });\n\t\t// The ps:activationcomplete roving sync is wired in _onElementResolved,\n\t\t// once the PanelSet element is known (it may resolve after init).\n\t}\n\n\tprivate _onActivation = (e: CustomEvent<{ panelId: string }>) => {\n\t\tconst tab = this._tabs().find(t => t.getAttribute('aria-controls') === e.detail?.panelId);\n\t\tif (tab) this._setRoving(tab);\n\t};\n\n\tprivate _onKeydown = (e: KeyboardEvent) => {\n\t\tconst tabs = this._tabs().filter(this._enabled);\n\t\tif (!tabs.length) return;\n\n\t\tconst vertical = this.element.getAttribute('aria-orientation') === 'vertical';\n\t\tconst nextKey = vertical ? 'ArrowDown' : 'ArrowRight';\n\t\tconst prevKey = vertical ? 'ArrowUp' : 'ArrowLeft';\n\n\t\tconst idx = tabs.indexOf(document.activeElement as HTMLElement);\n\t\tlet target: HTMLElement | undefined;\n\n\t\tswitch (e.key) {\n\t\t\tcase nextKey: target = tabs[(idx + 1) % tabs.length]; break;\n\t\t\tcase prevKey: target = tabs[(idx - 1 + tabs.length) % tabs.length]; break;\n\t\t\tcase 'Home': target = tabs[0]; break;\n\t\t\tcase 'End': target = tabs[tabs.length - 1]; break;\n\t\t\tcase 'Enter':\n\t\t\tcase ' ':\n\t\t\t\t// Activate the focused tab (covers non-<button> tabs; buttons would\n\t\t\t\t// fire click natively, but handling it here is harmless and uniform).\n\t\t\t\tif (idx >= 0) { e.preventDefault(); this._activate(tabs[idx], e); }\n\t\t\t\treturn;\n\t\t\tdefault: return;\n\t\t}\n\n\t\tif (!target) return;\n\t\te.preventDefault();\n\t\tthis._setRoving(target);\n\t\ttarget.focus();\n\t\t// 'auto' activation, but only when it is safe to do so.\n\t\tif (this._autoActivate()) this._activate(target, e);\n\t};\n\n\t// 'auto' self-downgrades to manual when activating-on-arrow would fight the\n\t// user: autoFocus would yank focus into the panel, async content would fire\n\t// loads on every keystroke.\n\tprivate _autoActivate(): boolean {\n\t\treturn this.config.activation === 'auto'\n\t\t\t&& !this._autoFocusInPlay()\n\t\t\t&& !this.panelSet?.hasAsyncContent;\n\t}\n\n\t// autoFocus can live on the PanelSet (config / data-auto-focus / web attr) or\n\t// on an individual trigger (data-auto-focus). Any of them makes auto unsafe.\n\tprivate _autoFocusInPlay(): boolean {\n\t\tconst ps = this.panelSet;\n\t\tif (ps && ps.config.autoFocus !== false) return true;\n\n\t\tconst set = this.panelSetElement;\n\t\tconst setAttr = set && (set.dataset.autoFocus ?? set.getAttribute('auto-focus'));\n\t\tif (setAttr != null && setAttr !== 'false') return true;\n\n\t\treturn this._tabs().some(tab => {\n\t\t\tconst a = tab.getAttribute('data-auto-focus');\n\t\t\treturn a != null && a !== 'false';\n\t\t});\n\t}\n\n\t/** Remove all listeners and drop the reference from the element. */\n\tdestroy() {\n\t\tthis._controller.abort();\n\t\tdelete this.element.panelControl;\n\t\tthis._log('Destroyed');\n\t}\n}\n\nexport default PanelControl;\n","import { Panel } from './panel.js';\nimport type { PanelConfig } from './panel.types.js';\nimport { parseAttrs } from './functions/config.js';\n\nexport class PanelElement extends HTMLElement {\n\tconnectedCallback(): void {\n\t\tif (this.panel) return;\n\t\tconst options = parseAttrs<PanelConfig>(this, Panel.attrs);\n\t\tnew Panel(this, options);\n\t}\n\n\tdisconnectedCallback(): void {}\n}\n","import { PanelSet } from './panelset.js';\nimport type { PanelSetConfig } from './panelset.types.js';\nimport { parseAttrs } from './functions/config.js';\n\nexport class PanelSetElement extends HTMLElement {\n\tconnectedCallback(): void {\n\t\tif (this.panelSet) return;\n\t\tconst options = parseAttrs<PanelSetConfig>(this, PanelSet.attrs);\n\t\tnew PanelSet(this, options);\n\t}\n\n\tdisconnectedCallback(): void {}\n}\n","import { PanelControl } from './panelcontrol.js';\nimport type { PanelControlConfig } from './panelcontrol.types.js';\nimport { parseAttrs } from './functions/config.js';\n\nexport class PanelControlElement extends HTMLElement {\n\tconnectedCallback(): void {\n\t\tif (this.panelControl) return;\n\t\tconst options = parseAttrs<PanelControlConfig>(this, PanelControl.attrs);\n\t\tnew PanelControl(this, options);\n\t}\n\n\tdisconnectedCallback(): void {}\n}\n\n/**\n * Register the <ps-panelcontrol> custom element.\n * @param prefix - Element name prefix. Defaults to 'ps' → <ps-panelcontrol>.\n */\nexport function registerPanelControl(prefix = 'ps'): void {\n\tconst name = `${prefix}-panelcontrol`;\n\tif (!customElements.get(name)) customElements.define(name, PanelControlElement);\n}\n","export { PanelSet } from './panelset.js';\nexport type {\n\tPanelSetConfig,\n\tReadyEventDetail,\n\tBeforeActivateEventDetail,\n\tBeforeOpenEventDetail,\n\tActivationEventDetail,\n\tActivationAbortedEventDetail,\n\tHandlerOptions,\n\tShowOptions,\n\tAsyncContentHandler,\n} from './panelset.types.js';\n\nexport { Panel } from './panel.js';\nexport type {\n\tPanelConfig,\n\t// Aliased: PanelSet also exports a (differently shaped) BeforeOpenEventDetail.\n\tBeforeOpenEventDetail as PanelBeforeOpenEventDetail,\n\tPanelEventDetail,\n\tAsyncOpenHandler,\n} from './panel.types.js';\n\nexport { PanelControl } from './panelcontrol.js';\nexport type { PanelControlConfig } from './panelcontrol.types.js';\n\nimport { PanelElement } from './panel.element.js';\nimport { PanelSetElement } from './panelset.element.js';\nimport { PanelControlElement, registerPanelControl } from './panelcontrol.element.js';\nexport { PanelElement, PanelSetElement, PanelControlElement, registerPanelControl };\n\n\nexport function register(prefix = 'ps'): void {\n\tconst define = (name: string, ctor: CustomElementConstructor) => {\n\t\tif (!customElements.get(name)) customElements.define(name, ctor);\n\t};\n\tdefine(`${prefix}-panel`, PanelElement);\n\tdefine(`${prefix}-panelset`, PanelSetElement);\n\tdefine(`${prefix}-panelcontrol`, PanelControlElement);\n}\n\nexport { PanelSet as default } from './panelset.js';\n"],"mappings":";AAMA,IAAa,IAAb,MAAkB;;qBACK,IAAI,gBAAgB;;CAE1C,IAAI,SAAsB;EACzB,OAAO,KAAK,YAAY;CACzB;CAEA,QAAqB;EAGpB,OAFA,KAAK,YAAY,MAAM,GACvB,KAAK,cAAc,IAAI,gBAAgB,GAChC,KAAK,YAAY;CACzB;CAIA,OAAO,kBAAkB,GAAiB,GAAsC;EAC/E,OAAO,IAAI,SAAQ,MAAW;GAC7B,IAAM,IAAI,iBAAiB,CAAE,GACvB,KAAS,WAAW,EAAE,kBAAkB,KAAK,MACpC,WAAW,EAAE,eAAe,KAAQ;GACnD,IAAI,MAAU,GAAG,OAAO,EAAQ;GAEhC,IAAI,IAAU,IACR,UAAe;IAChB,MACJ,IAAU,IACV,EAAG,oBAAoB,iBAAiB,CAAO,GAC/C,EAAQ;GACT,GACM,KAAW,MAAuB;IACnC,EAAE,WAAW,MACb,KAAgB,EAAE,iBAAiB,KACvC,EAAO;GACR;GAEA,AADA,EAAG,iBAAiB,iBAAiB,CAAO,GAC5C,WAAW,IAAS,IAAQ,OAAQ,GAAI;EACzC,CAAC;CACF;AACD;;;ACvBA,SAAgB,EAAU,GAAiB,GAAqB,GAAqB;CAGpF,IAFI,CAAC,KAED,MAAS,WAAW,KAInB,EAFH,EAAM,KAAK,WAAW,KAAK,KAC1B,aAAiB,cAAc,EAAM,WAAW,IACjC;CAGlB,IAAM,KAAS,MAAwB;EACtC,iBAAiB,EAAO,MAAM,GAAG,GAAG;CACrC;CAEA,IAAI,MAAS,IAEZ,AADK,EAAG,aAAa,UAAU,KAAG,EAAG,aAAa,YAAY,IAAI,GAClE,EAAM,CAAE;MACF,IAAI,MAAS,WAAW;EAC9B,IAAM,IAAU,EAAG,cAA2B,wBAAwB;EACtE,AAAI,MACE,EAAQ,aAAa,UAAU,KAAG,EAAQ,aAAa,YAAY,IAAI,GAC5E,EAAM,CAAO;CAEf,OAAO,IAAI,MAAS,SAAS;EAC5B,IAAM,IAAY,EAAG,cACpB,kEACD;EACA,AAAI,KAAW,EAAM,CAAS;CAC/B,OAAO,IAAI,MAAS,SAAS;EAC5B,IAAM,IAAQ,EAAG,cAChB,0FACD;EACA,AAAI,KAAO,EAAM,CAAK;CACvB,OAAO,AAAI,OAAO,KAAS,cAC1B,iBAAkB,EAAmC,CAAE,GAAG,GAAG;AAE/D;;;AClDA,IAAa,UAAiC;CAC7C,IAAM,IAAQ,IAAI,gBAAgB,SAAS,MAAM,EAAE,IAAI,OAAO;CAC9D,OAAO,IAAQ,EAAM,MAAM,GAAG,EAAE,OAAO,OAAO,IAAI,CAAC;AACpD,GAEa,KAAmB,MAAwB;CACvD,IAAM,IAAM,IAAI,IAAI,SAAS,IAAI;CAGjC,IAFA,EAAI,aAAa,OAAO,OAAO,GAE3B,EAAI,QAAQ;EACf,IAAM,IAAM,EAAI,SAAS,MAAM;EAC/B,QAAQ,aAAa,MAAM,IAAI,GAAG,IAAM,EAAI,QAAQ,EAAI,KAAK,GAAG,GAAG;CACpE,OACC,QAAQ,aAAa,MAAM,IAAI,CAAG;AAEpC,GASM,KAAa,MAAwB,GAAG,SAAS,SAAS,IAAI,KAEvD,KAAc,MAC1B,aAAa,QAAQ,EAAU,CAAG,CAAC,GAEvB,KAAe,GAAa,MACxC,aAAa,QAAQ,EAAU,CAAG,GAAG,CAAK;;;AC9B3C,SAAS,EAAQ,GAAe,GAAyB;CACxD,QAAQ,GAAR;EACC,KAAK,UAAW,OAAO;EACvB,KAAK,WAAW,OAAO,MAAU;EACjC,KAAK,UAAW,OAAO,SAAS,GAAO,EAAE;EACzC,KAAK,QACJ,IAAI;GAAE,OAAO,KAAK,MAAM,CAAK;EAAG,QAC1B;GAAE,OAAO,MAAU;EAAS;CACpC;AACD;AAMA,SAAgB,EAAkB,GAAuB,GAAiC;CACzF,IAAM,IAAqB,CAAC;CAC5B,KAAK,IAAM,CAAC,GAAW,MAAU,OAAO,QAAQ,CAAO,GAA+C;EACrG,IAAM,CAAC,GAAY,KAAQ,GACrB,IAAQ,EAAQ;EAClB,MAAU,KAAA,MACd,EAAoC,KAAa,EAAQ,GAAO,CAAI;CACrE;CACA,OAAO;AACR;AAQA,SAAgB,EAAc,GAAkB,GAAiC;CAChF,IAAM,IAAqB,CAAC;CAC5B,KAAK,IAAM,CAAC,GAAW,MAAU,OAAO,QAAQ,CAAO,GAA+C;EACrG,IAAM,CAAC,GAAY,KAAQ,GACrB,IAAW,EAAW,QAAQ,YAAY,KAAK,EAAE,YAAY,GAC7D,IAAQ,EAAQ,aAAa,CAAQ;EACvC,MAAU,SACd,EAAoC,KAAa,EAAQ,GAAO,CAAI;CACrE;CACA,OAAO;AACR;;;AC9CA,SAAgB,EAAI,GAAgB,GAAsB,GAAgB,GAAuB;CAC3F,KACL,QAAQ,IAAI,IAAI,EAAO,KAAK,EAAQ,MAAM,QAAQ,MAAM,CAAO;AAChE;AASA,SAAgB,EAAe,GAAiB,GAAa,GAAwB;CACpF,IAAM,IAAO,EAAI,MAAM,KAAK,EAAE,OAAO,OAAO;CAC5C,IAAI,CAAC,EAAK,QAAQ;CAClB,IAAM,KAAO,EAAG,aAAa,kBAAkB,KAAK,IAAI,MAAM,KAAK,EAAE,OAAO,OAAO,GAC/E,IAAU;CACd,KAAK,IAAM,KAAM,GAAM;EACtB,IAAM,IAAM,EAAI,SAAS,CAAE;EAC3B,AAAI,KAAW,CAAC,KAAO,EAAI,KAAK,CAAE,GAAG,IAAU,MACtC,CAAC,KAAW,MAAO,EAAI,OAAO,EAAI,QAAQ,CAAE,GAAG,CAAC,GAAG,IAAU;CACvE;CACK,MACD,EAAI,SAAQ,EAAG,aAAa,oBAAoB,EAAI,KAAK,GAAG,CAAC,IAC5D,EAAG,gBAAgB,kBAAkB;AAC3C;AAGA,IAAI,IAAyB;AAM7B,SAAgB,EAAuB,GAAsB;CACxD,CAAC,KAAS,MACd,IAAyB,IACzB,QAAQ,IAAI,mGAAmG;AAChH;AAgBA,SAAgB,EAAgB,GAAyB;CACxD,EAAO,aAAa,MAAM;EACzB,EAAO,UAAU,EAAO,UAAU,QAAQ,IAAI,CAAC,EAAO,SAAS,CAAC,CAAC,IAAI;CACtE;AACD;AAUA,SAAgB,EACf,GACA,GACA,GACA,GACA,IAA8B,CAAC,GACxB;CACP,IAAM,IAAO,EAAQ,SAAS;CAC9B,EAAQ,iBAAiB,IAAY,MAAM;EAC1C,IAAM,IAAQ,GACR,IAAS,EAAU,EAAM,MAAM,GAC/B,EAAE,cAAW,EAAM;EACzB,IAAI,KAAQ,EAAO,QAAQ,WAAW,QAAQ;EAC9C,IAAM,IAAS,EAAQ,GAAQ,CAAM;EACrC,AAAI,KAAU,OAAO,EAAO,QAAS,cACpC,EAAM,OAAO,UAAU,EAAO,WAAW;GACxC,AAAI,MAAM,EAAO,QAAQ,SAAS;EACnC,CAAC,CAAC;CAEJ,CAAC;AACF;;;OC1Ea,IAAb,MAAa,EAAS;CA+ErB,OAAO,KAAK,IAA6C,CAAC,GAAG,IAA0B,CAAC,GAAe;EAEtG,IAAI,GACA;EAEJ,AAAI,OAAO,KAAsB,YAEhC,IAAW,GACX,IAAS,MAGT,IAAS,GACT,IAAW,EAAO,YAAY;EAG/B,IAAM,IAAW,SAAS,iBAA8B,CAAQ,GAC1D,IAAwB,CAAC;EAqB/B,OAnBA,EAAS,SAAQ,MAAM;GAEtB,IAAI;IACH,EAAS,iBAAiB,CAAE;GAC7B,SAAS,GAAO;IACf,QAAQ,MAAO,EAAgB,OAAO;IACtC;GACD;GAGA,IAAI,EAAG,UAAU;IAChB,EAAU,KAAK,EAAG,QAAQ;IAC1B;GACD;GAEA,IAAM,IAAW,IAAI,EAAS,GAAI,CAAM;GACxC,EAAU,KAAK,CAAQ;EACxB,CAAC,GAEM;CACR;CAEA,YAAY,GAAyC,IAA0B,CAAC,GAAG;yBAzFxD,qBAEJ,IAAI,EAAK,yBACP,IAAI,EAAK,0BACC,uBACJ,4BAC4B,gCACV,6BACA,6BAGvB,IAAI,gBAAgB,iCA8ME;GAC/C,IAAM,IAAM,EAAe;GAC3B,OAAO,KAAK,OAAO,MAAK,MAAK,EAAE,MAAM,EAAI,SAAS,EAAE,EAAE,CAAC,GAAG,MAAM;EACjE,yBAEyB,MAA0B;GAElD,IADI,KAAK,OAAO,WAAW,KAAK,QAAQ,MAAI,EAAY,MAAM,KAAK,QAAQ,MAAM,CAAO,GACpF,KAAK,OAAO,UACf,KAAK,kBAAkB,CAAO;QACxB;IAEN,IAAM,IAAQ,IAAI,IAAI,KAAK,OAAO,KAAI,MAAK,EAAE,EAAE,EAAE,OAAO,OAAO,CAAC,GAC1D,IAAU,EAAe;IAC/B,AAAI,EAAQ,MAAK,MAAM,EAAM,IAAI,CAAE,CAAC,KAAG,EAAgB,EAAQ,QAAO,MAAM,CAAC,EAAM,IAAI,CAAE,CAAC,CAAC;GAC5F;EACD,6BAE6B,MAA0B;GACtD,IAAM,IAAQ,IAAI,IAAI,KAAK,OAAO,KAAI,MAAK,EAAE,EAAE,EAAE,OAAO,OAAO,CAAC;GAEhE,EADa,CAAC,GAAG,EAAe,EAAE,QAAO,MAAM,CAAC,EAAM,IAAI,CAAE,CAAC,GAAG,CAAO,EAAE,OAAO,OAChE,CAAI;EACrB,qCAEoD;GAGnD,IAAM,IAAU,KAAK,iBAAiB;GACtC,IAAI,GAAS,OAAO;GAGpB,IAAI,KAAK,OAAO,SAAS;IACxB,IAAM,EAAE,UAAO,KAAK;IACpB,IAAI,CAAC,GAAI,OAAO;IAChB,IAAM,IAAQ,EAAW,MAAM,GAAI;IACnC,OAAO,KAAS,KAAK,OAAO,MAAK,MAAK,EAAE,OAAO,CAAK,IAAI,IAAQ;GACjE;GACA,OAAO;EACR,6BAse6B,MAAmB;GAC/C,IAAM,EAAE,YAAS,aAAW,EAAyC;GACrE,KAAK,qBAAqB,GAAS,CAAK;EACzC;EA5oBC,IAAI;EACJ,IAAI,OAAO,KAAsB,UAEhC;OADA,IAAU,SAAS,cAA2B,CAAiB,GAC3D,CAAC,GACJ,MAAU,MAAM,4CAA4C,EAAkB,EAAE;EAAA,OAGjF,IAAU;EASX,IANA,KAAK,UAAU,GAGf,EAAS,iBAAiB,CAAO,GAG7B,EAAQ,UAEX,OADA,QAAQ,KAAK,+BAA+B,GACrC,EAAQ;EAOhB,AAHA,EAAQ,WAAW,MAGnB,EAAS,uBAAuB;EAOhC,IAAM,IAAa,EAA+B,EAAQ,SAAS,EAAS,KAAK;EAOjF,IANA,KAAK,SAAS;GAAE,GAAG,EAAS;GAAU,GAAG;GAAS,GAAG;EAAW,GAIhE,KAAK,SAAS,KAAK,eAAe,GAE9B,KAAK,OAAO,WAAW,GAAG;GAS7B,AALA,KAAK,eACJ,KAAK,QAAQ,cAA2B,yBAAyB,KAAK,KAAK,gBAAgB,GAC5F,KAAK,KAAK,qDAAqD,GAC/D,KAAK,UAA4B,YAAY;IAAE,WAAW,KAAK;IAAS,UAAU;GAAK,CAAC,GACxF,KAAK,iBAAiB,GACtB,KAAK,oBAAoB;GACzB;EACD;EAGA,IAAM,IAAa,KAAK,qBAAqB;EAmC7C,AAlCA,KAAK,eACH,IAAa,KAAK,OAAO,MAAK,MAAK,EAAE,OAAO,CAAU,IAAI,SACxD,KAAK,OAAO,MAAK,MAAK,EAAE,UAAU,SAAS,QAAQ,CAAC,KACpD,KAAK,OAAO,IAGhB,KAAK,eACJ,KAAK,QAAQ,cAA2B,yBAAyB,KAAK,KAAK,gBAAgB,GAE5F,KAAK,eAAe,KAAK,aAOrB,KAAK,OAAO,UAAU,YAAS,KAAK,QAAQ,QAAQ,gBAAgB,KAAK,OAAO,QAMhF,KAAK,OAAO,YAAY,CAAC,KAAK,QAAQ,UAAU,SAAS,SAAS,KACrE,KAAK,QAAQ,aAAa,SAAS,EAAE,GAGlC,EAAS,0BAAwB,EAAuB,KAAK,OAAO,KAAK,GAC7E,KAAK,KAAK,gBAAgB,KAAK,OAAO,OAAO,SAAS,GACtD,KAAK,UAA4B,YAAY;GAAE,WAAW,KAAK;GAAS,UAAU;EAAK,CAAC,GAExF,KAAK,cAAc,GAEnB,KAAK,iBAAiB,GAEtB,KAAK,oBAAoB;CAE1B;CAOA,sBAAoC;EACnC,IAAM,IAAiB,KAAK,QAAQ,QAAqB,6BAA6B;EACtF,IAAI,CAAC,KAAkB,OAAO,iBAAmB,KAAa;EAE9D,IAAI,IAAY,EAAe,aAC3B,IAAQ;EAQZ,AAPA,KAAK,kBAAkB,IAAI,qBAAqB;GAC/C,IAAM,IAAQ,EAAe;GACzB,MAAU,MACd,IAAY,GACZ,qBAAqB,CAAK,GAC1B,IAAQ,4BAA4B,KAAK,oBAAoB,CAAC;EAC/D,CAAC,GACD,KAAK,gBAAgB,QAAQ,CAAc;CAC5C;CAGA,KAAa,GAAuB;EAAE,EAAI,YAAY,KAAK,SAAS,KAAK,OAAO,OAAO,CAAO;CAAG;CAIjG,IAAY,YAAqB;EAChC,OAAO,KAAK,OAAO,YACf,CAAC,KAAK,QAAQ,UAAU,SAAS,SAAS,KAC1C,CAAC,KAAK,QAAQ,UAAU,SAAS,YAAY;CAClD;CA2CA,OAAe,iBAAiB,GAA4B;EAC3D,IAAI,CAAC,EAAQ,aAAa,eAAe,KAAK,CAAC,EAAQ,QAAQ,SAAS,GAAG,GAC1E,MAAU,MAAM,oEAAoE;CAEtF;CAEA,kBAAuC;EACtC,IAAM,IAAU,SAAS,cAAc,KAAK;EAI5C,OAHA,EAAQ,YAAY,iBACpB,KAAK,OAAO,SAAQ,MAAS,EAAQ,YAAY,CAAK,CAAC,GACvD,KAAK,QAAQ,YAAY,CAAO,GACzB;CACR;CAMA,iBAAwC;EAGvC,OAAO,MAAM,KAAK,KAAK,QAAQ,iBAA8B,qBAAmB,CAAC,EAAE,QAF7D,MACrB,EAAG,QAAQ,sDAAsD,MAAM,KAAK,OACyB;CACvG;CAEA,gBAA8B;EAc7B,AAbA,KAAK,OAAO,SAAQ,MAAS;GAE5B,AADA,EAAM,UAAU,OAAO,QAAQ,YAAY,YAAY,WAAW,WAAW,GACzE,MAAU,KAAK,eAIlB,EAAM,SAAS,IACf,EAAM,UAAU,IAAI,QAAQ,MAJ5B,EAAM,SAAS,IACf,EAAM,UAAU,OAAO,QAAQ;EAKjC,CAAC,GACD,KAAK,QAAQ,MAAM,SAAS,IAC5B,KAAK,oBAAoB,GACrB,KAAK,OAAO,kBAAgB,KAAK,mBAAmB,KAAK,WAAW,GACpE,KAAK,OAAO,gBAAc,KAAK,eAAe;CACnD;CAIA,UAA+B,GAAmB,GAAiB;EAClE,KAAK,QAAQ,cACZ,IAAI,YAAY,GAAW;GAC1B;GACA,SAAS;GACT,YAAY;EACb,CAAC,CACF;CACD;CAIA,oBAA4B,GAAgC;EAC3D,IAAI,CAAC,GAAI,OAAO;EAChB,IAAM,IAAI,iBAAiB,CAAE;EAC7B,QAAQ,WAAW,EAAE,UAAU,KAAK,MAAM,WAAW,EAAE,aAAa,KAAK,MACjE,WAAW,EAAE,cAAc,KAAK,MAAM,WAAW,EAAE,iBAAiB,KAAK;CAClF;CAEA,eAAuB,GAA4B;EAClD,IAAI,IAAQ,EAAM;EAGlB,OAFA,KAAS,KAAK,oBAAoB,KAAK,YAAY,GACnD,KAAS,KAAK,oBAAoB,KAAK,OAAO,GACvC;CACR;CAEA,sBAAoC;EACnC,IAAI,KAAK,QAAQ,aAAa,2BAA2B,GAAG;GAC3D,QAAQ,KAAK,oDAAoD;GACjE;EACD;EACA,IAAM,IAAiB,KAAK,QAAQ,QAAqB,6BAA6B;EACtF,IAAI,CAAC,GAAgB;EAGrB,KAAK,OAAO,SAAQ,MAAK;GAAmB,AAAjB,EAAE,SAAS,IAAM,EAAE,UAAU,OAAO,QAAQ;EAAG,CAAC;EAE3E,IAAI,IAAM;EAmBV,AAlBA,KAAK,OAAO,SAAQ,MAAS;GAG5B,AAFA,EAAM,SAAS,IACf,EAAM,UAAU,IAAI,QAAQ,GAC5B,EAAM,MAAM,aAAa;GACzB,IAAM,IAAI,KAAK,QAAQ;GAIvB,AAHI,IAAI,MAAK,IAAM,IACnB,EAAM,SAAS,IACf,EAAM,UAAU,OAAO,QAAQ,GAC/B,EAAM,MAAM,aAAa;EAC1B,CAAC,GAGG,KAAK,gBACR,KAAK,YAAY,SAAS,IAC1B,KAAK,YAAY,UAAU,IAAI,QAAQ,IAGxC,EAAe,MAAM,YAAY,mBAAmB,GAAG,EAAI,GAAG,GAC9D,KAAK,KAAK,yBAAyB,EAAI,GAAG;CAC3C;CAEA,mBAA2B,GAAgC;EAC1D,KAAK,OAAO,SAAQ,MAAS;GACvB,EAAM,MACX,SAAS,iBAA8B,mBAAmB,EAAM,GAAG,GAAG,EAAE,SAAQ,MAAW;IAC1F,IAAM,IAAS,MAAU;IAOzB,AADc,EAAQ,aAAa,MAAM,MAAM,SAAW,EAAQ,QAAQ,oBAAkB,KAE3F,EAAQ,aAAa,iBAAiB,OAAO,CAAM,CAAC,GACpD,EAAQ,gBAAgB,cAAc,MAElC,IAAQ,EAAQ,aAAa,gBAAgB,MAAM,IAClD,EAAQ,gBAAgB,cAAc,GAC3C,EAAQ,gBAAgB,eAAe;GAEzC,CAAC;EACF,CAAC;CACF;CAMA,iBAA+B;EAC9B,KAAK,OAAO,SAAQ,MAAS;GAE5B,IADI,CAAC,EAAM,MACP,EAAM,aAAa,iBAAiB,KAAK,EAAM,aAAa,YAAY,GAAG;GAE/E,IAAM,IAAW,MAAM,KACtB,SAAS,iBAA8B,mBAAmB,EAAM,GAAG,GAAG,CACvE;GACA,IAAI,EAAS,WAAW,GAAG;GAI3B,IAAM,IAAO,EAAS,QAAO,MAAK,EAAE,aAAa,MAAM,MAAM,KAAK,GAC5D,IAAY,EAAK,WAAW,IAAI,EAAK,KACxC,EAAS,WAAW,IAAI,EAAS,KACjC;GACE,MAEA,EAAU,OAAI,EAAU,KAAK,KAAK,UAAU,GAAG,EAAM,GAAG,KAAK,IAClE,EAAM,aAAa,mBAAmB,EAAU,EAAE;EACnD,CAAC;CACF;CAGA,UAAkB,GAAsB;EACvC,IAAI,IAAK,GAAM,IAAI;EACnB,OAAO,SAAS,eAAe,CAAE,IAAG,IAAK,GAAG,EAAK,GAAG;EACpD,OAAO;CACR;CAEA,uBAA+B,GAAuB;EACrD,KAAK,OAAO,SAAQ,MAAS;GACvB,EAAM,MACX,SAAS,iBAA8B,mBAAmB,EAAM,GAAG,GAAG,EAAE,SAAQ,MAAW;IAC1F,EAAQ,UAAU,OAAO,iBAAiB,CAAM;GACjD,CAAC;EACF,CAAC;CACF;CAEA,eAAuB,GAA6B;EAenD,AAdA,KAAK,OAAO,SAAQ,MAAS;GAE5B,AADA,EAAM,UAAU,OAAO,QAAQ,YAAY,YAAY,WAAW,WAAW,GACzE,MAAU,KAIb,EAAM,UAAU,IAAI,QAAQ,GAC5B,EAAM,SAAS,IACf,EAAM,gBAAgB,OAAO,MAL7B,EAAM,UAAU,OAAO,QAAQ,GAC/B,EAAM,SAAS;EAMjB,CAAC,GACD,KAAK,QAAQ,MAAM,SAAS,IAC5B,KAAK,QAAQ,UAAU,OAAO,kBAAkB,GAChD,KAAK,cAAc,GACf,KAAK,OAAO,kBAAgB,KAAK,mBAAmB,CAAQ;CACjE;CAEA,kBAA0B,GAAqC,GAAsD;EACpH,IAAI,KAAK,OAAO,gBAAgB;GAC/B,IAAM,IAAY,GAAiB,aAAa,iBAAiB;GACjE,IAAI,KAAa,MAAM;IACtB,IAAI,MAAc,QAAQ,OAAO;IACjC,IAAI,MAAc,SAAS,OAAO;IAClC,IAAI,MAAc,aAAa,MAAc,WAAW,MAAc,SAAS,OAAO;GACvF;EACD;EAEA,OADI,MAAc,KAAA,IACX,KAAK,OAAO,YADiB;CAErC;CAEA,iBAAyB,GAAoB,GAAqB,GAAqB;EACtF,EAAU,GAAO,GAAM,CAAK;CAC7B;CAGA,kBAA0B,GAAoB,GAAyB,GAAqB;EAC3F,IAAM,IAAS,IAAY,YAAY,WACjC,IAAgB,MAAM,IAAY,YAAY,aAC9C,IAAc,MAAM;EAE1B,KAAK,KAAK,IAAY,YAAY,SAAS;EAE3C,IAAM,IAAS,KAAK,eAAe,MAAM,GAKnC,IADc,KAAK,QAAQ,UAAU,SAAS,CACzB,IAAc,KAAK,QAAQ,eAAe,MAM/D,IAAoB,IAAwC,OAA5B,KAAK,QAAQ;EAKnD,AAHA,KAAK,QAAQ,UAAU,OAAO,CAAa,GACtC,KAAW,KAAK,QAAQ,UAAU,OAAO,SAAS,GAEnD,KAAW,KAAK,QAAQ,gBAAgB,OAAO;EAGnD,IAAM,UAAqB;GAC1B,KAAK,QAAQ,aAAa,SAAS,EAAE;GACrC,IAAM,IAAY,aAAiB,gBAAgB,EAAM,gBAAgB;GACzE,AAAI,KAAK,OAAO,eAAe,KAAK,sBAAsB,CAAC,KAC1D,KAAK,mBAAmB,MAAM;EAEhC;EAEA,IAAI,KAAkB,KAAK,OAAO,aAUjC,IAFA,KAAK,QAAQ,UAAU,IAAI,CAAW,GAElC,EAAS,wBACZ,AAAI,KACH,KAAK,QAAQ,MAAM,SAAS,MAAuB,OAAmC,QAA5B,GAAG,EAAmB,KAChF,4BAA4B;GAE3B,AADA,KAAK,QAAQ,MAAM,SAAS,IAC5B,EAAK,kBAAkB,KAAK,SAAS,QAAQ,EAAE,WAAW;IACrD,EAAO,YAGS,KAAK,eACtB,EAAK,kBAAkB,KAAK,YAAY,IACxC,QAAQ,QAAQ,GACP,WAAW;KAClB,EAAO,YACX,KAAK,QAAQ,UAAU,OAAO,CAAW,GACzC,KAAK,QAAQ,UAAU,IAAI,SAAS,GACpC,KAAU,QAAQ;IACnB,CAAC;GACF,CAAC;EACF,CAAC,MAKD,KAAK,QAAQ,MAAM,SAAS,MAAuB,OAEhD,GAAG,EAAiB,MADpB,GAAG,EAAmB,KAEzB,4BAA4B;GAE3B,AADA,KAAK,QAAQ,MAAM,SAAS,IAC5B,EAAK,kBAAkB,KAAK,SAAS,QAAQ,EAAE,WAAW;IACrD,EAAO,YACX,KAAK,QAAQ,UAAU,OAAO,CAAW,GACzC,KAAU,QAAQ,cAClB,EAAa;GACd,CAAC;EACF,CAAC;OAEI;GAEN,IAAM,IAAe,IAAY,KAAK,eAAe,KAAK,YAAY,IAAI,GAIpE,IAAgB,MAAuB,OAEzC,IAAY,KAAK,QAAQ,eAAgB,KAAoB,IAD9D;GAQH,AANA,KAAK,QAAQ,MAAM,SAAS,GAAG,EAAc,KAI7C,iBAAsB,KAAK,OAAO,EAAE,QAEpC,4BAA4B;IAG3B,AAFA,KAAK,QAAQ,MAAM,SAAS,GAAG,EAAa,KAE5C,EAAK,kBAAkB,KAAK,OAAO,EAAE,WAAW;KAC3C,EAAO,YACX,KAAK,QAAQ,MAAM,SAAS,IAC5B,KAAK,QAAQ,UAAU,OAAO,CAAW,GACrC,KAAW,KAAK,QAAQ,UAAU,IAAI,SAAS,GACnD,KAAU,QAAQ,cACb,KAAW,EAAa;IAC9B,CAAC;GACF,CAAC;EACF;OAQA,AANI,IACH,KAAK,QAAQ,UAAU,IAAI,SAAS,KAEpC,KAAK,QAAQ,UAAU,OAAO,SAAS,GACvC,EAAa,IAEd,KAAK,QAAQ,MAAM,SAAS;CAE9B;CAMA,YAA2B;EAC1B,OAAO,KAAK,cAAc,MAAM;CACjC;CAWA,UAAgB;EACf,IAAM,IAAiB,KAAK;EAC5B,KAAK,SAAS,KAAK,eAAe,GAC9B,KAAK,OAAO,WAAW,MAE3B,KAAK,cAAe,KAAkB,KAAK,OAAO,SAAS,CAAc,IACtE,IACC,KAAK,OAAO,MAAK,MAAK,EAAE,UAAU,SAAS,QAAQ,CAAC,KAAK,KAAK,OAAO,IACzE,KAAK,eAAe,KAAK,aAEzB,KAAK,eAAe,KAAK,QAAQ,cAA2B,yBAAyB,KAAK,KAAK,cAE/F,KAAK,cAAc,GACnB,KAAK,aAAa,GAClB,KAAK,KAAK,cAAc,KAAK,OAAO,OAAO,SAAS;CACrD;CASA,SAAS,GAAoB,GAA6E;EACzG,AAAK,EAAM,aAAa,MAAM,KAAG,EAAM,aAAa,QAAQ,UAAU;EAEtE,IAAI,IAA0B;EAY9B,OAXI,GAAU,SACb,IAAM,KAAK,OAAO,MAAK,MAAK,EAAE,OAAO,EAAS,MAAM,KAAK,OAC/C,GAAU,QAEpB,IADc,KAAK,OAAO,MAAK,MAAK,EAAE,OAAO,EAAS,KAC/C,GAAO,sBAA6C,OACjD,OAAO,GAAU,SAAU,aACrC,IAAM,KAAK,OAAO,EAAS,UAAU,QAGrC,KAAK,gBAAgB,KAAK,gBAAgB,GAAG,aAAa,GAAO,CAAG,GACrE,KAAK,QAAQ,GACN;CACR;CAMA,YAAY,GAAuB;EAClC,IAAM,IAAQ,KAAK,OAAO,MAAK,MAAK,EAAE,OAAO,CAAO;EAC/C,MACL,EAAM,OAAO,GACb,KAAK,QAAQ;CACd;CAKA,UAAgB;EAQf,AAPA,KAAK,UAAU,MAAM,GACrB,KAAK,eAAe,MAAM,GAC1B,KAAK,iBAAiB,WAAW,GACjC,KAAK,kBAAkB,MACvB,KAAK,gBAAgB,MAAM,GAE3B,OAAO,KAAK,QAAQ,UACpB,KAAK,KAAK,WAAW;CACtB;CAGA,UAAkB,GAAoG;EACrH,IAAM,IAAQ,KAAK,OAAO,QACpB,IAAQ,IAAQ,KAAK,OAAO,QAAQ,CAAK,IAAI;EACnD,OAAO;GAAE;GAAO;GAAO,SAAS,KAAS;GAAG,OAAO,MAAU,IAAQ;EAAE;CACxE;CAQA,OAAe,yBAA+B;EACzC,EAAS,6BACb,EAAS,2BAA2B,IACpC,SAAS,iBAAiB,SAAS,EAAS,YAAY;CACzD;CAIA,OAAe,gBAAgB,GAAkB,GAAqD;EACrG,IAAM,IAAM,EAAI,aAAa,WAAW,GAAM;EAE9C,OADI,IAAY,SAAS,cAA2B,CAAG,IAChD,EAAI,QAAqB,8BAA8B;CAC/D;CA6BA,mBAAiC;EAChC,IAAM,EAAE,cAAW,KAAK;EAGxB,AAFA,KAAK,QAAQ,iBAAiB,sBAAsB,KAAK,mBAAmB,EAAE,UAAO,CAAC,GACtF,KAAK,QAAQ,iBAAiB,yBAAyB,KAAK,mBAAmB,EAAE,UAAO,CAAC,GACzF,KAAK,aAAa;CACnB;CAOA,eAA6B;EAC5B,IAAM,EAAE,YAAS,aAAU,KAAK,UAAU,KAAK,YAAY;EAC3D,KAAK,qBAAqB,GAAS,CAAK;CACzC;CAuBA,qBAA6B,GAAkB,GAAsB;EACpE,IAAI,KAAK,OAAO,MAAM;EACtB,IAAM,IAAO,KAAK,gBAAgB,MAAM,GAClC,IAAO,KAAK,gBAAgB,MAAM;EAExC,IAAI,KAAK,OAAO,iBAAiB,UAAU;GAE1C,AADA,EAAK,SAAQ,MAAK,KAAK,mBAAmB,GAAG,CAAO,CAAC,GACrD,EAAK,SAAQ,MAAK,KAAK,mBAAmB,GAAG,CAAK,CAAC;GACnD;EACD;EASA,AALK,KAAS,EAAK,SAAQ,MAAK,KAAK,mBAAmB,GAAG,EAAK,CAAC,GAC5D,KAAS,EAAK,SAAQ,MAAK,KAAK,mBAAmB,GAAG,EAAK,CAAC,GAG7D,KAAS,KAAK,mBAAmB,GAAM,IAAU,CAAC,IAAI,CAAI,GAC1D,KAAS,KAAK,mBAAmB,GAAM,IAAU,CAAC,IAAI,CAAI;CAC/D;CAOA,mBAA2B,GAAkB,GAAyB;EACrE,AAAI,KAAK,OAAO,iBAAiB,WAC5B,IAAU,EAAI,aAAa,YAAY,EAAE,IAAQ,EAAI,gBAAgB,UAAU,IAEnF,EAAI,aAAa,iBAAiB,OAAO,CAAQ,CAAC;EAEnD,IAAM,IAAO,EAAI,aAAa,uBAAuB;EACrD,AAAI,KAAM,EAAe,GAAK,GAAM,CAAQ;CAC7C;CAKA,mBAA2B,GAAwB,GAAmC;EACrF,EAAQ,SAAQ,MAAO;GAKtB,AAJI,CAAC,EAAI,aAAa,UAAU,KAAK,SAAS,kBAAkB,MAChD,EAAa,MAAK,MAAK,CAAC,EAAE,aAAa,UAAU,CAAC,KAAK,KAAK,mBAAmB,IACtF,MAAM,GAEf,KAAK,mBAAmB,GAAK,EAAI;EAClC,CAAC;CACF;CAKA,qBAAiD;EAChD,IAAM,IAAQ,KAAK,gBAAgB,KAAK;EAGxC,OAFK,KACA,EAAM,aAAa,UAAU,KAAG,EAAM,aAAa,YAAY,IAAI,GACjE,KAFY;CAGpB;CAIA,gBAAwB,GAAsC;EAC7D,OAAO,MAAM,KAAK,SAAS,iBAA8B,YAAY,EAAK,EAAE,CAAC,EAC3E,QAAO,MAAO,EAAS,gBAAgB,GAAK,CAAI,MAAM,KAAK,OAAO;CACrE;CAOA,KAAK,GAA6B;EACjC,KAAK,MAAM,GAAG,CAAO;CACtB;CAOA,KAAK,GAA6B;EACjC,KAAK,MAAM,IAAI,CAAO;CACvB;CAEA,MAAc,GAAa,GAA6B;EACvD,IAAM,IAAQ,KAAK,OAAO;EAC1B,IAAI,MAAU,GAAG;EAEjB,IAAM,IAAO,KAAK,OAAO,QAAQ,KAAK,YAAY,GAE9C,KADY,MAAS,KAAK,IAAI,KACX,GACnB,IAAU;EACd,IAAI,IAAS,KAAK,KAAU,GAAO;GAClC,IAAI,CAAC,KAAK,OAAO,MAAM;GAEvB,AADA,KAAU,IAAS,KAAS,GAC5B,IAAU;EACX;EACA,IAAM,IAAO,KAAK,OAAO;EAIzB,AAAI,KAAQ,MAAS,KAAK,gBACzB,KAAK,KAAK,EAAK,IAAI,IAAU;GAAE,GAAG;GAAS,WAAW,IAAM,IAAI,YAAY;EAAW,IAAI,CAAO;CACpG;CAOA,KAAK,GAA6B;EACjC,IAAM,EACL,UACA,gBAAa,IACb,iBACG,KAAW,CAAC;EAEhB,IAAI,CAAC,KAAK,OAAO,UAAU;GAC1B,KAAK,KAAK,cAAc;GACxB;EACD;EAEA,IAAM,IAAW,KAAK,WAChB,IAAY,KAAK,QAAQ,UAAU,SAAS,YAAY,GACxD,IAAY,KAAK,QAAQ,UAAU,SAAS,YAAY;EAG9D,IADI,CAAC,KAAY,CAAC,KACd,KAAK,QAAQ,UAAU,SAAS,kBAAkB,KAAK,CAAC,GAAW;EAGvE,IAAM,IAAkB,GAAO,kBAAkB,cAC7C,EAAM,OAAO,QAAQ,2BAAyB,KAAqB,EAAM,SAC1E,MAEG,IAAiB,KAAK,kBAAkB,GAAiB,CAAS;EAMxE,AALI,MAAiB,KAAK,qBAAqB,IAE/C,KAAK,kBAAkB,IAAM,CAAU,GAGnC,MAAmB,MAAS,MAAmB,KAAA,KAAa,KAAK,iBAChE,KAAc,KAAK,OAAO,cAC7B,EAAK,kBAAkB,KAAK,OAAO,EAAE,WAAW;GAC/C,KAAK,iBAAiB,KAAK,cAAc,GAAgB,CAAK;EAC/D,CAAC,IAED,KAAK,iBAAiB,KAAK,cAAc,GAAgB,CAAK;CAGjE;CAOA,MAAM,GAA6B;EAClC,IAAM,EACL,gBAAa,IACb,aACG,KAAW,CAAC;EAEhB,IAAI,CAAC,KAAK,OAAO,UAAU;GAC1B,KAAK,KAAK,cAAc;GACxB;EACD;EAEA,IAAM,IAAW,KAAK,WAChB,IAAY,KAAK,QAAQ,UAAU,SAAS,YAAY,GACxD,IAAY,KAAK,QAAQ,UAAU,SAAS,YAAY,GACxD,IAAY,KAAK,QAAQ,UAAU,SAAS,YAAY;EAE9D,CAAK,KAAY,MAAc,CAAC,KAC5B,KAAK,QAAQ,UAAU,SAAS,kBAAkB,KAAK,CAAC,KAE5D,KAAK,kBAAkB,IAAO,GAAY,CAAK;CAChD;CAOA,OAAO,GAA6B;EACnC,IAAM,EACL,UACA,gBAAa,IACb,iBACG,KAAW,CAAC,GAEV,IAAW,KAAK,WAChB,IAAY,KAAK,QAAQ,UAAU,SAAS,YAAY;EAG9D,AAAI,KAAY,IAEf,KAAK,KAAK;GAAE;GAAO;GAAY;EAAU,CAAC,IAE1C,KAAK,MAAM;GAAE;GAAY;EAAM,CAAC;CAElC;CAOA,aAAa,GAA8B,IAA0B,CAAC,GAAS;EAE9E,AADA,KAAK,kBAAkB,IACvB,EACC,KAAK,SACL,kBACC,MAAW,EAAO,aACnB,GACA,CACD;CACD;CAUA,MAAM,KAAK,GAAiB,GAAsC;EACjE,IAAI,KAAK,OAAO,kBAAkB,MAAS,KAAK,aAAa;EAE7D,IAAM,EACL,UACA,gBAAa,IACb,cACA,WAAW,MACR,KAAW,CAAC,GAGV,IAAkB,GAAO,kBAAkB,cAC7C,EAAM,OAAO,QAAQ,2BAAyB,KAAqB,EAAM,SAC1E,MAEG,IAAiB,KAAK,kBAAkB,GAAiB,CAAS,GAElE,IAAW,KAAK,OAAO,MAAK,MAAK,EAAE,OAAO,CAAO;EAEvD,IAAI,CAAC,GAAU;GACd,KAAK,KAAK,oBAAoB,GAAS;GACvC;EACD;EAMA,IAAM,IAAiB,IAAI,YAAuC,qBAAqB;GACtF,QAAQ;IACP;IACA,aAAa;IACb,eAAe,KAAK,eAAe;IACnC,SAAS;GACV;GACA,SAAS;GACT,YAAY;EACb,CAAC;EACD,IAAI,CAAC,KAAK,QAAQ,cAAc,CAAc,GAAG;GAChD,KAAK,KAAK,gCAAgC,GAAS;GACnD;EACD;EAEA,IAAM,IAAW,KAAK,WAChB,IAAY,KAAK,QAAQ,UAAU,SAAS,YAAY,GACxD,IAAY,KAAK,QAAQ,UAAU,SAAS,YAAY;EAE9D,IAAI,MAAa,KAAK,cAAc;GACnC,AAAI,KAAY,IAEf,KAAK,KAAK;IAAE;IAAO;IAAY,WAAW;GAAe,CAAC,IAChD,KAAK,OAAO,YAAY,KAAK,OAAO,cAE9C,KAAK,MAAM;IAAE;IAAY;GAAM,CAAC;GAEjC;EACD;EAGA,KAAK,KAAK,QAAQ,UAAU,SAAS,YAAY,KAAK,MAAc,CAAC,GAAW;EAGhF,IAAI,GAAU;GAGb,AAFA,KAAK,eAAe,GACpB,KAAK,eAAe,CAAQ,GAC5B,KAAK,KAAK;IAAE;IAAO;IAAY,WAAW;GAAe,CAAC;GAC1D;EACD;EAEA,IAAM,IAAiB,KAAK;EAE5B,AADA,KAAK,cAAc,IACf,KAAK,OAAO,kBAAkB,KAAK,OAAO,kBAAkB,MAAO,KAAK,uBAAuB,EAAI;EAEvG,IAAM,IAAY,KAAK,cACjB,IAAc,GAAW;EAC/B,KAAK,eAAe;EAMpB,IAAM,IAAa,KAAkB,MAAa,KAAK,eAAe,MAAc;EAOpF,AANI,KAAK,OAAO,kBAAgB,KAAK,mBAAmB,CAAQ,GAEhE,KAAK,cAAc,CAAO,GAE1B,KAAK,QAAQ,UAAU,OAAO,YAAY,GAEtC,CAAC,KAAc,KAAa,MAAc,KAAK,eAAe,MAAc,MAC/E,EAAU,UAAU,OAAO,YAAY,YAAY,WAAW,WAAW,GACrE,EAAU,UAGb,EAAU,UAAU,OAAO,QAAQ;EAIrC,IAAM,IAAkB,KAAK,iBAIvB,IAAoB,KAAK,UAAU,OAAO,SAC1C,IAAS,KAAK,UAAU,MAAM;EAWpC,AATI,CAAC,KAAqB,KAAmB,KAAe,MAAgB,KAC3E,KAAK,UAAwC,wBAAwB;GACpE,SAAS;GACT,SAAS;EACV,CAAC,GAGF,KAAK,kBAAkB,IAEvB,KAAK,KAAK,GAAG,GAAW,MAAM,OAAO,KAAK,GAAS;EAEnD,IAAM,IAA0C;GAC/C;GACA,aAAa;GACb,eAAe;GACf;GACA,SAAS;GACT,YAAY,CAAC;EACd;EACA,EAAgB,CAAgB;EAEhC,IAAM,IAAkB,IAAI,YAAY,iBAAiB;GACxD,QAAQ;GACR,SAAS;GACT,YAAY;EACb,CAAC;EAED,KAAK,QAAQ,cAAc,CAAe;EAE1C,IAAM,IAAc,EAAiB;EAErC,IAAI,GAAa;GAQhB,AAPA,KAAK,kBAAkB,IACvB,KAAK,KAAK,wBAAwB,GAKlC,KAAK,QAAQ,MAAM,YAAY,sBAAsB,GAAG,KAAK,OAAO,aAAa,GAAG,GACpF,KAAK,QAAQ,UAAU,IAAI,YAAY;GAEvC,IAAI,IAAuC,MAErC,IAAmB,MAAe,MAAS,KAAK,OAAO,gBAAgB,IACzE,IAAmB;GAKvB,IAJI,OAAO,KAAK,OAAO,eAAgB,aACtC,IAAmB,KAAoB,KAAK,OAAO,YAAY,WAAW,KAGvE,GACH,IAAI,GAMH,AALA,KAAK,QAAQ,UAAU,IAAI,WAAW,YAAY,GAClD,KAAK,QAAQ,MAAM,SAAS,OAC5B,4BAA4B;IAC3B,KAAK,QAAQ,MAAM,SAAS,GAAG,KAAK,OAAO,cAAc;GAC1D,CAAC,GACD,IAAiB,EAAK,kBAAkB,KAAK,SAAS,QAAQ;QACxD;IAEN,IAAM,IAAgB,KAAK,QAAQ,cAC7B,IAAe,KAAK,IAAI,GAAe,KAAK,OAAO,aAAa;IACtE,AAAI,IAAe,MAClB,KAAK,QAAQ,MAAM,SAAS,GAAG,EAAc,KAC7C,4BAA4B;KAC3B,KAAK,QAAQ,MAAM,SAAS,GAAG,EAAa;IAC7C,CAAC,GACD,IAAiB,EAAK,kBAAkB,KAAK,SAAS,QAAQ;GAEhE;GAGD,IAAI;IAGH,IAFA,MAAM,QAAQ,IAAI,CAAC,GAAa,CAAc,EAAE,OAAO,OAAO,CAAoB,GAE9E,EAAO,SAAS;KAGnB,AAFA,KAAK,KAAK,wBAAwB,GAAS,GAC3C,KAAK,QAAQ,UAAU,OAAO,YAAY,GAC1C,KAAK,QAAQ,MAAM,eAAe,oBAAoB;KACtD;IACD;IAIA,AAFA,KAAK,KAAK,gBAAgB,GAEtB,EAAS,QAAQ,WAAW,UAC/B,KAAK,oBAAoB;GAG3B,SAAS,GAAO;IACf,IAAM,IAAM;IAUZ,AATA,KAAK,KAAK,gBAAgB,EAAI,SAAS,GACvC,KAAK,QAAQ,UAAU,OAAO,YAAY,GAC1C,KAAK,QAAQ,MAAM,eAAe,oBAAoB,GAElD,EAAI,SAAS,gBAChB,QAAQ,MAAM,qBAAqB,CAAK,GAGzC,KAAK,cAAc,IACf,KAAK,OAAO,kBAAkB,KAAK,OAAO,kBAAkB,MAAO,KAAK,uBAAuB,EAAK;IACxG;GACD;GAIA,AAFA,KAAK,QAAQ,UAAU,OAAO,YAAY,GAC1C,KAAK,QAAQ,MAAM,eAAe,oBAAoB,GACtD,KAAK,QAAQ,UAAU,OAAO,YAAY;EAC3C;EAEA,IAAI,EAAO,SAAS;GACnB,KAAK,KAAK,YAAY,GAAS;GAC/B;EACD;EAEA,IAAM,IAAgB,IAAa,IAAY,KAAK;EAEpD,KAAK,UAAiC,sBAAsB;GAC3D;GACA,SAAS;GACT;GACA,GAAG,KAAK,UAAU,CAAQ;EAC3B,CAAC;EAED,IAAM,IAAmB,MAAe,MAAS,KAAK,OAAO,gBAAgB,IAEzE,IAAkB,GAClB,IAAmB;EAOvB,AALI,OAAO,KAAK,OAAO,eAAgB,aACtC,IAAkB,KAAoB,KAAK,OAAO,YAAY,WAAW,IACzE,IAAmB,KAAoB,KAAK,OAAO,YAAY,WAAW,KAG3E,KAAK,OAAO,SAAQ,MAAS,EAAM,UAAU,OAAO,QAAQ,CAAe,CAAC;EAM5E,IAAI,IAA4C;EAChD,IAAI,GAGH,IAAY,KAAK,qBAAqB,cAAc,YAAY;OAC1D,IAAI,KAAK,OAAO,UAAU,KAAiB,MAAkB,GAKnE,IAAI,GACH,IAAY,MAAkB,YAAY,YAAY;OAChD;GACN,IAAM,IAAU,KAAK,OAAO,QAAQ,CAAa,GAC3C,IAAU,KAAK,OAAO,QAAQ,CAAQ;GAC5C,AAAI,MAAY,MAAM,MAAU,MAAM,MAAY,MACjD,IAAY,IAAQ,IAAU,YAAY;EAE5C;EAMD,AAJA,KAAK,mBAAmB,GAIxB,KAAK,OAAO,SAAQ,MAAK,EAAE,UAAU,OAAO,YAAY,WAAW,WAAW,CAAC;EAE/E,IAAM,IAAc,KAAK,QAAQ;EAwBjC,AAvBI,MACH,KAAK,QAAQ,MAAM,SAAS,GAAG,EAAY,MAG5C,EAAS,SAAS,IAClB,EAAS,aAAa,SAAS,EAAE,GACjC,EAAS,UAAU,IAAI,UAAU,GAC7B,KAAW,EAAS,UAAU,IAAI,CAAS,GAC3C,KACH,KAAK,QAAQ,UAAU,IAAI,kBAAkB,GAE1C,KAAiB,MAAkB,MACtC,EAAc,UAAU,OAAO,UAAU,UAAU,GACnD,EAAc,UAAU,IAAI,UAAU,GAClC,KAAW,EAAc,UAAU,IAAI,CAAS,GACpD,EAAc,SAAS,IACvB,EAAc,aAAa,SAAS,EAAE,IAOvC,4BAA4B,4BAA4B;GAEvD,AADA,EAAS,UAAU,IAAI,QAAQ,GAC3B,KAAiB,MAAkB,KACtC,EAAc,UAAU,OAAO,UAAU;GAG1C,IAAM,IAAe,KAAK,eAAe,CAAQ,GAC3C,IAAgB,MAAgB;GAEtC,AAAI,MACH,KAAK,QAAQ,MAAM,SAAS,GAAG,EAAa;GAG7C,IAAM,IAA4B,CAAC;GASnC,AARI,KACH,EAAS,KAAK,EAAK,kBAAkB,CAAQ,CAAC,GAE3C,KAAoB,KACvB,EAAS,KAAK,EAAK,kBAAkB,KAAK,OAAO,CAAC,GAE9C,EAAS,UAAQ,EAAS,KAAK,QAAQ,QAAQ,CAAC,GAErD,QAAQ,IAAI,CAAQ,EAAE,WAAW;IAChC,IAAI,EAAO,SAAS;KACnB,KAAK,KAAK,gBAAgB,GAAS;KACnC;IACD;IAWA,AATA,KAAK,eAAe,CAAQ,GAC5B,KAAK,KAAK,KAAK,GAAS,GAEpB,MAAmB,MAAS,MAAmB,KAAA,KAClD,KAAK,iBAAiB,GAAU,GAAgB,CAAK,GAGtD,KAAK,cAAc,IACf,KAAK,OAAO,kBAAkB,KAAK,OAAO,kBAAkB,MAAO,KAAK,uBAAuB,EAAK,GACxG,KAAK,UAAiC,yBAAyB;KAC9D;KACA,SAAS;KACT;KACA,GAAG,KAAK,UAAU,CAAQ;IAC3B,CAAC;GACF,CAAC;EACF,CAAC,CAAC;CACH;AAED;oBAp0C+D;CAC7D,OAAO;CACP,aAAa;CACb,QAAQ;CACR,MAAM;CACN,UAAU;CACV,YAAY;CACZ,cAAc;CACd,eAAe;CACf,cAAc;CACd,aAAa;CACb,WAAW;CACX,SAAS;CACT,UAAU;CACV,eAAe;CACf,gBAAgB;CAChB,cAAc;CACd,OAAO;AACR,8BAwBC,OAAO,MAAQ,OAAe,IAAI,SAAS,kCAAkC,gCAOpC,cAEO;CAChD,OAAe,CAAC,iBAAkB,QAAQ;CAC1C,aAAe,CAAC,eAAiB,MAAM;CACvC,QAAe,CAAC,YAAiB,SAAS;CAC1C,MAAe,CAAC,UAAiB,SAAS;CAC1C,UAAe,CAAC,YAAiB,SAAS;CAC1C,YAAe,CAAC,cAAiB,SAAS;CAC1C,cAAe,CAAC,kBAAkB,QAAQ;CAC1C,eAAe,CAAC,iBAAiB,QAAQ;CACzC,cAAe,CAAC,gBAAiB,QAAQ;CACzC,WAAgB,CAAC,aAAkB,QAAQ;CAC3C,aAAgB,CAAC,eAAkB,SAAS;CAC5C,SAAgB,CAAC,gBAAkB,SAAS;CAC5C,UAAgB,CAAC,iBAAkB,SAAS;CAC5C,eAAgB,CAAC,iBAAkB,SAAS;CAC5C,gBAAgB,CAAC,kBAAkB,SAAS;CAC5C,cAAgB,CAAC,gBAAkB,SAAS;CAC5C,OAAgB,CAAC,SAAkB,SAAS;AAC7C,qBA0oB+B,MAAuB;CACrD,IAAM,IAAQ,EAAM;CACpB,IAAI,EAAE,aAAiB,UAAU;CACjC,IAAM,IAAM,EAAM,QAAqB,iDAAiD;CAGxF,IAAI,CAAC,KAAO,EAAI,aAAa,eAAe,MAAM,QAAQ;CAE1D,IAAM,IACL,EAAI,aAAa,cAAc,IAAI,SACnC,EAAI,aAAa,cAAc,IAAI,SAAS,SAEvC,IAAQ,EAAS,gBAAgB,GAAK,CAAI,GAC1C,IAAW,GAAO;CACxB,IAAI,CAAC,GAAU;EAGd,AAAI,KAAO,EAAI,YAAY,GAAO,EAAM,QAAQ,SAAS,QAAQ,EAAM,QAAQ,UAAU,SACxF,WAAW,EAAK,sDAAsD;EACvE;CACD;CACA,EAAS,GAAM,EAAE,SAAM,CAAC;AACzB;;;ACnvBD,IAAa,KAAY,MAA6C;CACrE,IAAM,IAAS,EAAQ;CAGvB,OAFK,GAAQ,cAAc,mBAAmB,IAEvC,MAAM,KAAK,EAAO,QAAQ,EAAE,MACjC,MACA,aAAc,eAAe,EAAG,aAAa,iBAAiB,CAChE,KAAK,OALmD;AAMzD,GAGa,KAAY,MAA4B;CACpD,IAAM,IAAO,MAAM,KAAK,EAAK,iBAA8B,kBAAkB,CAAC;CACzE,EAAK,UASV,EANuB,KAAI,OAAO;EACjC;EACA,KAAK,EAAG,QAAQ;EAChB,GAAG,EAAG;CACP,EAEA,EAAU,SAAS,EAAE,OAAI,QAAK,WAAQ;EAGrC,AAFA,EAAG,MAAM,YAAY,cACrB,EAAG,MAAM,QAAQ,GAAG,EAAE,KAClB,MAAQ,UACX,EAAG,MAAM,aAAa,eAAe,EAAE;CAEzC,CAAC;AACF,GAGa,KAAc,MAA4B;CACtD,EAAK,iBAA8B,kBAAkB,EAAE,SAAQ,MAAM;EAGpE,AAFA,EAAG,MAAM,YAAY,IACrB,EAAG,MAAM,QAAQ,IACjB,EAAG,MAAM,aAAa;CACvB,CAAC;AACF;AC3BA,SAAS,EACR,GACA,GAMgB;CAChB,IAAM,EAAE,kBAAe,mBAAgB,GAAe,iBAAc,cAAW,GAEzE,KAAkB,GAAiB,MAAgC;EACxE,IAAI,EAAG,QAAQ,CAAa,MAAM,GAAO,OAAO;EAChD,IAAM,IAAa,EAAG,eAAe,QAAqB,CAAY;EACtE,OAAO,CAAC,KAAc,CAAC,EAAM,SAAS,CAAU;CACjD,GAEM,IAAQ,EAAK,QAAqB,CAAa;CAGrD,OAFI,CAAC,KAAS,CAAC,EAAe,GAAM,CAAK,IAAU,CAAC,IAE7C,CAAC,GAAG,EAAM,iBAA8B,CAAY,CAAC,EAAE,QAAO,MACpE,MAAY,KACZ,EAAe,GAAS,CAAK,MAC5B,IAAS,EAAO,CAAO,IAAI,GAC7B;AACD;AAEA,IAAa,IAAb,MAAa,EAAM;CAkDlB,OAAO,KAAK,IAA0C,gBAAgB,IAAuB,CAAC,GAAY;EACzG,IAAI,GACA;EAcJ,OAbI,OAAO,KAAsB,YAChC,IAAW,GACX,IAAS,MAET,IAAS,GACT,IAAW,iBAQL,MAAM,KAAK,SAAS,iBAA8B,CAAQ,CAAC,EAChE,QAAO,MAAM,CAAC,EAAG,KAAK,EACtB,QAAO,MAAM,CAAC,EAAG,QAAQ,SAAS,EAAG,QAAQ,UAAU,YAAY,EACnE,KAAI,MAAM,IAAI,EAAM,GAAI,CAAM,CAAC;CAClC;CAEA,YAAY,GAAyC,IAAuB,CAAC,GAAG;4BApE/B,6BACH,mBAC9B,IAAI,EAAK,8BACK,IAAI,gBAAgB,sBAC5B,kCAqHoB;GACzC,IAAM,EAAE,UAAO,KAAK;GAEpB,OADK,IACE,EAAe,EAAE,SAAS,CAAE,IADnB;EAEjB,6BAE6B,MAAwB;GACpD,IAAM,EAAE,UAAO,KAAK;GACpB,IAAI,CAAC,GAAI;GACT,IAAM,IAAU,EAAe;GAI/B,EAHa,IACV,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,GAAS,CAAE,CAAC,CAAC,IAC7B,EAAQ,QAAO,MAAK,MAAM,CAAE,CACX;EACrB,oCAO6E;GAE5E,IAAM,KAAW,MAChB,KAAK,QAAQ,aAAa,CAAI,IAC3B,KAAK,QAAQ,aAAa,CAAI,MAAM,UACpC,KAAA,GAEE,IAAa,EAAQ,oBAAoB,GACzC,IAAc,EAAQ,qBAAqB,GAG7C,GACA,GACA,IAAK,KAAK,QAAQ;GACtB,OAAO,KACF,GAAG,aAAa,YAAY,IADtB;IAEV,IAAI,EAAG,aAAa,kBAAkB,GAAG;KAExC,AADI,EAAG,aAAa,oBAAoB,MAAI,IAAgB,EAAG,aAAa,oBAAoB,MAAO,UACnG,EAAG,aAAa,qBAAqB,MAAG,IAAgB,EAAG,aAAa,qBAAqB,MAAM;KACvG;IACD;IACA,IAAK,EAAG;GACT;GAEA,OAAO;IACN,SAAU,KAAe,KAAiB,KAAK,OAAO;IACtD,UAAU,KAAe,KAAiB,KAAK,OAAO;GACvD;EACD,yBAEyB,MAAwB;GAChD,IAAI,CAAC,KAAK,QAAQ,IAAI;GAEtB,IAAM,EAAE,SAAS,GAAY,UAAU,MAAgB,KAAK,oBAAoB;GAMhF,AAJI,KACH,EAAY,SAAS,KAAK,QAAQ,MAAM,IAAO,SAAS,QAAQ,GAG7D,IACH,KAAK,kBAAkB,CAAI,IACjB,CAAC,KAAQ,KAAK,iBAAiB,KAGzC,KAAK,kBAAkB,EAAK;EAE9B,qCAE8C;GAC7C,IAAM,EAAE,UAAO,KAAK;GACpB,IAAI,CAAC,GAAI,OAAO;GAGhB,IAAI,KAAK,iBAAiB,GAAG,OAAO;GAGpC,IAAM,EAAE,eAAY,KAAK,oBAAoB;GAE7C,OADA,GAAI,KAAW,EAAW,SAAS,GAAI,MAAM;EAE9C,yBAGC,KAAK,OAAO,SAAS,eAAe,UAAU;EAvI9C,IAAM,IAAU,OAAO,KAAsB,WAC1C,SAAS,cAA2B,CAAiB,IACrD;EACH,IAAI,CAAC,GAAS,MAAU,MAAM,yCAAyC,EAAkB,EAAE;EAI3F,IAHA,KAAK,UAAU,GACf,EAAQ,QAAQ,MAEZ,CAAC,EAAQ,cAAc,yBAAyB,GAAG;GACtD,IAAM,IAAU,SAAS,cAAc,KAAK;GAG5C,AAFA,EAAQ,YAAY,iBACpB,EAAQ,OAAO,GAAG,MAAM,KAAK,EAAQ,UAAU,CAAC,GAChD,EAAQ,YAAY,CAAO;EAC5B;EAMA,IAAM,IAAa,EAA4B,EAAQ,SAAS,EAAM,KAAK;EA2B3E,AA1BA,KAAK,SAAS;GAAE,GAAG,EAAM;GAAU,GAAG;GAAS,GAAG;EAAW,GAEzD,KAAK,OAAO,SAAS,iBAAc,EAAQ,QAAQ,YAAY,eAC/D,KAAK,OAAO,UAAU,YAAS,EAAQ,QAAQ,aAAa,KAAK,OAAO,QAE5E,KAAK,sBAAsB,GAC3B,KAAK,cAAc,GAKf,KAAK,qBAAqB,KAAK,KAAK,QAAQ,UAAU,SAAS,SAAS,KAC3E,KAAK,QAAQ,UAAU,IAAI,SAAS,GACpC,KAAK,QAAQ,gBAAgB,OAAO,GACpC,KAAK,iBAAiB,EAAI,GAI1B,KAAK,QAAQ,UAAU,IAAI,aAAa,GACxC,4BAA4B,4BAA4B,KAAK,QAAQ,UAAU,OAAO,aAAa,CAAC,CAAC,GACrG,KAAK,UAAU,cAAc,KAE7B,KAAK,QAAQ,aAAa,SAAS,EAAE,GAGlC,EAAM,0BAAwB,EAAuB,KAAK,OAAO,KAAK,GAC1E,KAAK,KAAK,aAAa;CACxB;CAEA,KAAa,GAAa;EAAE,EAAI,SAAS,KAAK,SAAS,KAAK,OAAO,OAAO,CAAG;CAAG;CAgGhF,wBAAgC;EAC/B,IAAM,KAAW,MAA6B,EAAG,aAAa,YAAY,KAAK,CAAC,CAAC,EAAG,OAC9E,KAAQ,MAA+B;GAI5C,AAHK,KAAK,QAAQ,OAAI,KAAK,QAAQ,KAAK,SAAS,EAAE,EAAM,mBACzD,EAAQ,aAAa,iBAAiB,KAAK,QAAQ,EAAE,GAChD,EAAQ,aAAa,eAAe,KAAG,EAAQ,aAAa,iBAAiB,OAAO,GACzF,EAAQ,gBAAgB,oBAAoB;EAC7C,GAGM,KAAa,MAClB,EAAG,aAAa,oBAAoB,IAAI,IACtC,WAAW,KAAK,EAAG,OAAO,IAAI,EAAG,cAA2B,+BAA+B,IAC3F;EAEH,KAAK,IAAM,KAAO,CAAC,0BAA0B,oBAAoB,GAAY;GAC5E,IAAI,IAAK,KAAK,QAAQ;GACtB,OAAO,KAAM,CAAC,EAAQ,CAAE,IAAG;IAC1B,IAAM,IAAU,EAAU,CAAE;IAC5B,IAAI,GAAS;KAAE,EAAK,CAAO;KAAG;IAAO;IACrC,IAAK,EAAG;GACT;EACD;CACD;CAEA,gBAAwB;EACvB,IAAM,IAAK,KAAK,QAAQ;EACxB,IAAI,CAAC,GAAI;EACT,IAAM,EAAE,cAAW,KAAK;EAexB,AAbA,SAAS,iBAA8B,mBAAmB,EAAG,GAAG,EAAE,SAAQ,MAAW;GACpF,EAAQ,iBAAiB,UAAS,MAAK;IAEtC,AADA,KAAK,qBAAqB,GAC1B,KAAK,OAAO,CAAC;GACd,GAAG,EAAE,UAAO,CAAC;EACd,CAAC,GAED,KAAK,QAAQ,iBAA8B,oBAAoB,EAC7D,SAAQ,MAAO;GACX,EAAI,QAAQ,cAAc,MAAM,KAAK,WACzC,EAAI,iBAAiB,eAAe,KAAK,MAAM,GAAG,EAAE,UAAO,CAAC;EAC7D,CAAC,GAEE,KAAK,OAAO,iBACf,OAAO,iBAAiB,gBAAgB;GACvC,IAAI,CAAC,KAAK,UAAU,KAAK,QAAQ,UAAU,SAAS,YAAY,GAAG;GACnE,IAAM,IAAO,EAAS,KAAK,OAAO;GAElC,AADI,KAAM,EAAW,CAAI,GACzB,KAAK,MAAM;EACZ,GAAG,EAAE,UAAO,CAAC;CAEf;CAEA,iBAAyB,GAAe;EACvC,IAAM,IAAK,KAAK,QAAQ;EACnB,KACL,SAAS,iBAAiB,mBAAmB,EAAG,GAAG,EAAE,SAAQ,MAC5D,EAAE,aAAa,iBAAiB,OAAO,CAAI,CAAC,CAC7C;CACD;CAEA,oBAA4B;EACtB,KAAK,oBACV,KAAK,gBAAgB,MAAM,eAAe,sBAAsB,GAChE,KAAK,gBAAgB,MAAM,eAAe,uBAAuB,GACjE,KAAK,kBAAkB;CACxB;CAEA,sBAA8B;EAC7B,IAAM,IAAQ,KAAK,QAAQ,QAAqB,oBAAoB,GAC9D,IAAa,GAAO,aAAa,2BAA2B,KAAK;EACvE,IAAI,CAAC,KAAK,OAAO,iBAAiB,CAAC,GAAY;EAE/C,IAAM,IAAyB,IAC5B,EAAa,KAAK,SAAS;GAC5B,eAAe;GACf,cAAe;GACf,SAAe,MAAM,CAAC,CAAC,EAAG,OAAO;EAClC,CAAC,IACC,MAAM,KAAK,KAAK,QAAQ,eAAe,YAAY,CAAC,CAAC,EACrD,QAAQ,MACR,aAAc,eAAe,MAAO,KAAK,WAAW,CAAC,CAAC,EAAG,OAAO,MACjE;EAQF,AANI,EAAQ,UAAU,MACrB,EAAM,MAAM,YAAY,wBAAwB,sBAAsB,GACtE,EAAM,MAAM,YAAY,yBAAyB,uBAAuB,GACxE,KAAK,kBAAkB,IAGxB,EAAQ,SAAQ,MAAM;GAErB,AADA,EAAG,MAAO,qBAAqB,MAC/B,EAAG,MAAO,MAAM;EACjB,CAAC;CACF;CAEA,iBAAyB,GAAe;EAClC,KAAK,OAAO,aACjB,EAAU,KAAK,SAAS,KAAK,OAAO,WAAW,CAAK;CACrD;CAEA,UAAkB,GAAc;EAC/B,CAAI,MAAS,kBAAkB,MAAS,oBAAgB,KAAK,cAAc;EAC3E,IAAM,IAA2B,EAAE,SAAS,KAAK,mBAAmB;EACpE,KAAK,QAAQ,cAAc,IAAI,YAAY,GAAM;GAAE;GAAQ,SAAS;EAAK,CAAC,CAAC;CAC5E;CAIA,IAAI,SAAkB;EACrB,OAAO,KAAK,QAAQ,UAAU,SAAS,SAAS,KAAK,KAAK,QAAQ,UAAU,SAAS,YAAY;CAClG;CAMA,MAAM,KAAK,GAAe;EAEzB,IADI,KAAK,UAAU,CAAC,KAAK,QAAQ,UAAU,SAAS,YAAY,KAC5D,KAAK,OAAO,kBAAkB,MAAS,KAAK,aAAa;EAE7D,KAAK,cAAc;EACnB,IAAM,IAAU,KAAK,MAAM,MAAM,GAC3B,IAAU,KAAK,SAAS,GAExB,IAA0C;GAC/C;GACA,SAAS;GACT,YAAY,CAAC;GACb,SAAS,KAAK;EACf;EAOA,AANA,EAAgB,CAAgB,GAEhC,KAAK,QAAQ,cACZ,IAAI,YAAY,oBAAoB;GAAE,QAAQ;GAAkB,SAAS;EAAK,CAAC,CAChF,GAEI,EAAiB,UACpB,MAAM,KAAK,WAAW,GAAQ,GAAS,EAAiB,SAAS,CAAK,IAEtE,KAAK,UAAU,GAAQ,GAAS,CAAK;CAEvC;CAKA,MAAc,WACb,GACA,GACA,GACA,GACC;EAGD,IAAM,IAAe,MAAM,QAAQ,KAAK,CACvC,EAAe,WAAW,EAAa,GACvC,IAAI,SAAe,MAAO;GACzB,IAAM,IAAI,iBAAiB,EAAI,EAAK,GAAG,KAAK,OAAO,YAAY;GAC/D,EAAO,iBAAiB,eAAe,aAAa,CAAC,CAAC;EACvD,CAAC,CACF,CAAC,EAAE,YAAY,EAAc;EAE7B,IAAI,EAAO,SAAS;EAEpB,IAAI,GAAc;GAEjB,KAAK,UAAU,GAAQ,GAAS,CAAK;GACrC;EACD;EAoBA,AAZA,KAAK,QAAQ,UAAU,OAAO,YAAY,GAC1C,KAAK,QAAQ,gBAAgB,OAAO,GACpC,KAAK,QAAQ,UAAU,IAAI,YAAY,GAGvC,KAAK,QAAQ,cAAc,yBAAyB,GAAG,gBAAgB,GAGvE,KAAK,QAAQ,MAAM,YAAY,sBAAsB,KAAK,GAE1D,KAAK,iBAAiB,EAAI,GAC1B,KAAK,cAAc,EAAI,GACvB,KAAK,UAAU,eAAe;EAE9B,IAAM,IAAO,EAAS,KAAK,OAAO;EAClC,AAAI,KAAM,EAAS,CAAI;EAEvB,IAAI;EAEJ,AAAI,KAAK,OAAO,eACf,KAAK,QAAQ,UAAU,IAAI,YAAY,GACvC,KAAK,QAAQ,MAAM,KAAW,OAC9B,iBAAsB,KAAK,OAAO,EAAE,IAEpC,4BAA4B;GAC3B,KAAK,QAAQ,MAAM,KAAW,GAAG,KAAK,OAAO,cAAc;EAC5D,CAAC,GAED,IAAiB,EAAK,kBAAkB,KAAK,SAAS,CAAO,KAE7D,KAAK,QAAQ,MAAM,KAAW,GAAG,KAAK,OAAO,cAAc;EAG5D,IAAI;GACH,MAAM,QAAQ,IAAI,CAAC,GAAgB,CAAc,EAAE,OAAO,OAAO,CAAoB;EACtF,QAAQ,CAER,UAAU;GAET,AADA,KAAK,QAAQ,UAAU,OAAO,YAAY,GAC1C,KAAK,QAAQ,MAAM,eAAe,oBAAoB;EACvD;EAEA,IAAI,EAAO,SAAS;EAGpB,IAAM,IAAc,KAAK,QAAQ,sBAAsB,GACjD,IAAU,MAAY,WAAW,EAAY,SAAS,EAAY;EAGxE,IAFA,KAAK,QAAQ,MAAM,KAAW,IAE1B,KAAK,OAAO,aACf,IAAI,EAAM,wBAGT,EAAK,kBAAkB,KAAK,SAAS,CAAO,EAAE,WAAW;GACpD,EAAO,YACX,KAAK,QAAQ,UAAU,OAAO,YAAY,GAC1C,KAAK,QAAQ,UAAU,IAAI,SAAS,GACpC,KAAK,UAAU,cAAc,GAC7B,KAAK,KAAK,QAAQ,GAClB,KAAK,iBAAiB,CAAK;EAC5B,CAAC;OACK;GAIN,KAAK,QAAQ,MAAM,KAAW;GAC9B,IAAM,IAAa,KAAK,QAAQ,sBAAsB,GAChD,IAAS,MAAY,WAAW,EAAW,SAAS,EAAW;GAIrE,AAHA,KAAK,QAAQ,MAAM,KAAW,GAAG,EAAQ,KACzC,iBAAsB,KAAK,OAAO,EAAE,IAEpC,4BAA4B;IAG3B,AAFA,KAAK,QAAQ,MAAM,KAAW,GAAG,EAAO,KAExC,EAAK,kBAAkB,KAAK,SAAS,CAAO,EAAE,WAAW;KACpD,EAAO,YACX,KAAK,QAAQ,MAAM,KAAW,IAC9B,KAAK,QAAQ,UAAU,OAAO,YAAY,GAC1C,KAAK,QAAQ,UAAU,IAAI,SAAS,GACpC,KAAK,UAAU,cAAc,GAC7B,KAAK,KAAK,QAAQ,GAClB,KAAK,iBAAiB,CAAK;IAC5B,CAAC;GACF,CAAC;EACF;OAMA,AAJA,KAAK,QAAQ,UAAU,OAAO,YAAY,GAC1C,KAAK,QAAQ,UAAU,IAAI,SAAS,GACpC,KAAK,UAAU,cAAc,GAC7B,KAAK,KAAK,QAAQ,GAClB,KAAK,iBAAiB,CAAK;CAE7B;CAKA,UACC,GACA,GACA,GACC;EAED,IAAM,IADmB,KAAK,QAAQ,UAAU,SAAS,YAChC,IACtB,KAAK,QAAQ,sBAAsB,EAAE,MAAY,WAAW,WAAW,WACvE;EAGH,AADA,KAAK,QAAQ,UAAU,OAAO,YAAY,GAC1C,KAAK,QAAQ,gBAAgB,OAAO;EAEpC,IAAM,IAAO,EAAS,KAAK,OAAO;EAElC,IAAI,KAAK,OAAO,aACf,IAAI,EAAM,wBAeT,AAVA,KAAK,QAAQ,UAAU,IAAI,YAAY,GACvC,KAAK,QAAQ,MAAM,KAAW,MAAqB,OAAiC,QAA1B,GAAG,EAAiB,KAC1E,KAAM,EAAS,CAAI,GACvB,iBAAsB,KAAK,OAAO,EAAE,IAEpC,KAAK,iBAAiB,EAAI,GAC1B,KAAK,cAAc,EAAI,GACvB,KAAK,oBAAoB,GACzB,KAAK,UAAU,eAAe,GAE9B,4BAA4B;GAE3B,AADA,KAAK,QAAQ,MAAM,KAAW,IAC9B,EAAK,kBAAkB,KAAK,SAAS,CAAO,EAAE,WAAW;IACpD,EAAO,YACX,KAAK,QAAQ,UAAU,OAAO,YAAY,GAC1C,KAAK,QAAQ,UAAU,IAAI,SAAS,GACpC,KAAK,UAAU,cAAc,GAC7B,KAAK,kBAAkB,GACvB,KAAK,KAAK,QAAQ,GAClB,KAAK,iBAAiB,CAAK;GAC5B,CAAC;EACF,CAAC;OACK;GASN,AARA,KAAK,iBAAiB,EAAI,GAC1B,KAAK,cAAc,EAAI,GACvB,KAAK,oBAAoB,GACzB,KAAK,UAAU,eAAe,GAK9B,KAAK,QAAQ,MAAM,KAAW;GAE9B,IAAM,IAAS,KAAK,QAAQ,sBAAsB,GAC5C,IAAS,MAAY,WAAW,EAAK,SAAS,EAAK;GAQzD,AANA,KAAK,QAAQ,MAAM,KAAW,MAAqB,OAAiC,QAA1B,GAAG,EAAiB,KAC9E,KAAK,QAAQ,UAAU,IAAI,YAAY,GACnC,KAAM,EAAS,CAAI,GAEvB,iBAAsB,KAAK,OAAO,EAAE,IAEpC,4BAA4B;IAE3B,AADA,KAAK,QAAQ,MAAM,KAAW,GAAG,EAAO,KACxC,EAAK,kBAAkB,KAAK,SAAS,CAAO,EAAE,WAAW;KACpD,EAAO,YACX,KAAK,QAAQ,MAAM,KAAW,IAC9B,KAAK,QAAQ,UAAU,OAAO,YAAY,GAC1C,KAAK,QAAQ,UAAU,IAAI,SAAS,GACpC,KAAK,UAAU,cAAc,GAC7B,KAAK,kBAAkB,GACvB,KAAK,KAAK,QAAQ,GAClB,KAAK,iBAAiB,CAAK;IAC5B,CAAC;GACF,CAAC;EACF;OAUA,AARA,KAAK,iBAAiB,EAAI,GAC1B,KAAK,cAAc,EAAI,GACvB,KAAK,oBAAoB,GACzB,KAAK,UAAU,eAAe,GAC9B,KAAK,QAAQ,UAAU,IAAI,SAAS,GACpC,KAAK,UAAU,cAAc,GAC7B,KAAK,kBAAkB,GACvB,KAAK,KAAK,QAAQ,GAClB,KAAK,iBAAiB,CAAK;CAE7B;CAQA,aAAa,GAA2B,IAA8B,CAAC,GAAS;EAC/E,EACC,KAAK,SACL,0BACM,KAAK,SACX,GACA,CACD;CACD;CAEA,MAAM,GAAe;EAEpB,IADI,CAAC,KAAK,UACN,KAAK,OAAO,kBAAkB,MAAS,KAAK,aAAa;EAI7D,AAFA,KAAK,cAAc,IACnB,KAAK,QAAQ,aAAa,SAAS,EAAE,GACrC,KAAK,iBAAiB,EAAK;EAE3B,IAAM,IAAO,KAAK,SAAS,GACrB,IAAO,EAAS,KAAK,OAAO,GAC5B,IAAS,KAAK,MAAM,MAAM;EAEhC,KAAK,UAAU,eAAe;EAE9B,IAAM,UAAe;GAMpB,AALA,KAAK,QAAQ,UAAU,OAAO,cAAc,WAAW,YAAY,GACnE,KAAK,QAAQ,MAAM,KAAQ,IACvB,KAAM,EAAW,CAAI,GACzB,KAAK,cAAc,EAAK,GACxB,KAAK,UAAU,cAAc,GAC7B,KAAK,KAAK,QAAQ;GAClB,IAAM,IAAY,aAAiB,gBAAgB,EAAM,gBAAgB;GACzE,AAAI,KAAK,OAAO,eAAe,KAAK,sBAAsB,CAAC,KAC1D,KAAK,mBAAmB,MAAM;EAEhC;EAEA,IAAI,CAAC,KAAK,OAAO,aAAa;GAC7B,EAAO;GACP;EACD;EAEA,IAAM,IAAU,KAAK,QAAQ,sBAAsB,GAC7C,IAAU,MAAS,WAAW,EAAK,SAAS,EAAK;EAQvD,AAPA,KAAK,QAAQ,MAAM,KAAQ,GAAG,EAAQ,KACtC,KAAK,QAAQ,UAAU,OAAO,cAAc,SAAS,GACrD,KAAK,QAAQ,UAAU,IAAI,YAAY,GAIvC,iBAAsB,KAAK,OAAO,EAAE,IACpC,4BAA4B;GAE3B,AADA,KAAK,QAAQ,MAAM,KAAQ,OAC3B,EAAK,kBAAkB,KAAK,SAAS,CAAI,EAAE,WAAW;IACjD,EAAO,WACX,EAAO;GACR,CAAC;EACF,CAAC;CACF;CAEA,OAAO,GAAe;EACrB,AAAI,KAAK,QAAQ,UAAU,SAAS,YAAY,IAC/C,KAAK,KAAK,CAAK,IACL,KAAK,SACf,KAAK,MAAM,CAAK,KAEZ,GAAO,WACV,KAAK,qBACH,EAAM,OAAuB,QAAQ,WAAW,KAC9C,EAAM,SAEX,KAAK,KAAK,CAAK;CAEjB;CAMA,UAAU;EAQT,AAPA,KAAK,MAAM,MAAM,GACjB,KAAK,oBAAoB,MAAM,GAE/B,KAAK,QAAQ,UAAU,OAAO,cAAc,cAAc,cAAc,SAAS,GACjF,KAAK,QAAQ,MAAM,KAAK,SAAS,KAAK,IACtC,KAAK,QAAQ,aAAa,SAAS,EAAE,GAErC,KAAK,iBAAiB,EAAK;EAC3B,IAAM,IAAO,EAAS,KAAK,OAAO;EAIlC,AAHI,KAAM,EAAW,CAAI,GAEzB,OAAO,KAAK,QAAQ,OACpB,KAAK,KAAK,WAAW;CACtB;AACD;oBA/pB0C;CACxC,MAAM;CACN,OAAO;CACP,eAAe;CACf,aAAa;CACb,WAAW;CACX,aAAa;CACb,eAAe;CACf,cAAc;CACd,eAAe;CACf,eAAe;CACf,SAAS;CACT,UAAU;CACV,OAAO;AACR,aAE8C;CAC7C,MAAe,CAAC,aAAsB,QAAQ;CAC9C,OAAe,CAAC,cAAsB,QAAQ;CAC9C,WAAe,CAAC,kBAAuB,QAAQ;CAC/C,eAAe,CAAC,sBAAuB,SAAS;CAChD,aAAe,CAAC,oBAAsB,SAAS;CAC/C,aAAe,CAAC,oBAAsB,SAAS;CAC/C,eAAe,CAAC,sBAAsB,SAAS;CAC/C,cAAe,CAAC,qBAAsB,QAAQ;CAC9C,eAAgB,CAAC,sBAAuB,QAAQ;CAChD,eAAgB,CAAC,sBAAuB,SAAS;CACjD,SAAgB,CAAC,gBAAuB,SAAS;CACjD,UAAgB,CAAC,iBAAuB,SAAS;CACjD,OAAgB,CAAC,SAAuB,SAAS;AAClD,8BAMC,OAAO,MAAQ,OAAe,IAAI,SAAS,kCAAkC,sBAE9C;;;OChFpB,IAAb,MAAa,EAAa;CAuBzB,OAAO,KAAK,IAAiD,uBAAuB,IAA8B,CAAC,GAAmB;EACrI,IAAI,GACA;EAQJ,OAPI,OAAO,KAAsB,YAChC,IAAW,GACX,IAAS,MAET,IAAS,GACT,IAAW,EAAO,YAAY,wBAExB,MAAM,KAAK,SAAS,iBAA8B,CAAQ,CAAC,EAChE,QAAO,MAAM,CAAC,EAAG,YAAY,EAC7B,KAAI,MAAM,IAAI,EAAa,GAAI,CAAM,CAAC;CACzC;CAEA,YAAY,GAAyC,IAA8B,CAAC,GAAG;gBAzBlD,yBACf,IAAI,gBAAgB,qBACrB,4BACM,mCA4Ga;GACvC,IAAM,IAAM,KAAK,UACX,IAAK,KAAK,iBACZ,IAAY;GAChB,IAAI,GACH,IAAY,CAAC,EAAE,EAAI,OAAO,YAAY,EAAI,OAAO;QAC3C,IAAI,GAAI;IACd,IAAM,IAAW,EAAG,QAAQ,YAAY,QAAQ,EAAG,aAAa,UAAU,GACpE,IAAQ,EAAG,QAAQ,cAAc,QAAQ,EAAG,aAAa,cAAc;IAC7E,IAAY,KAAY;GACzB;GACA,KAAK,QAAQ,gBAAgB,kBAAkB,CAAS;EACzD,oBAiEoB,MACnB,EAAI,aAAa,eAAe,MAAM,UAAU,CAAC,EAAI,8BA4B7B,MAAwC;GAChE,IAAM,IAAM,KAAK,MAAM,EAAE,MAAK,MAAK,EAAE,aAAa,eAAe,MAAM,EAAE,QAAQ,OAAO;GACxF,AAAI,KAAK,KAAK,WAAW,CAAG;EAC7B,sBAEsB,MAAqB;GAC1C,IAAM,IAAO,KAAK,MAAM,EAAE,OAAO,KAAK,QAAQ;GAC9C,IAAI,CAAC,EAAK,QAAQ;GAElB,IAAM,IAAW,KAAK,QAAQ,aAAa,kBAAkB,MAAM,YAC7D,IAAU,IAAW,cAAc,cACnC,IAAU,IAAW,YAAY,aAEjC,IAAM,EAAK,QAAQ,SAAS,aAA4B,GAC1D;GAEJ,QAAQ,EAAE,KAAV;IACC,KAAK;KAAS,IAAS,GAAM,IAAM,KAAK,EAAK;KAAS;IACtD,KAAK;KAAS,IAAS,GAAM,IAAM,IAAI,EAAK,UAAU,EAAK;KAAS;IACpE,KAAK;KAAS,IAAS,EAAK;KAAI;IAChC,KAAK;KAAS,IAAS,EAAK,EAAK,SAAS;KAAI;IAC9C,KAAK;IACL,KAAK;KAGJ,AAAI,KAAO,MAAK,EAAE,eAAe,GAAG,KAAK,UAAU,EAAK,IAAM,CAAC;KAC/D;IACD,SAAS;GACV;GAEK,MACL,EAAE,eAAe,GACjB,KAAK,WAAW,CAAM,GACtB,EAAO,MAAM,GAET,KAAK,cAAc,KAAG,KAAK,UAAU,GAAQ,CAAC;EACnD;EAnOC,IAAM,IAAU,OAAO,KAAsB,WAC1C,SAAS,cAA2B,CAAiB,IACrD;EACH,IAAI,CAAC,GAAS,MAAU,MAAM,gDAAgD,EAAkB,EAAE;EAGlG,IAFA,KAAK,UAAU,GAEX,EAAQ,cAEX,OADA,QAAQ,KAAK,mCAAmC,GACzC,EAAQ;EAEhB,EAAQ,eAAe;EAGvB,IAAM,IAAa,EAAmC,EAAQ,SAAS,EAAa,KAAK;EAKzF,AAJA,KAAK,SAAS;GAAE,GAAG,EAAa;GAAU,GAAG;GAAS,GAAG;EAAW,GAEpE,KAAK,aAAa,EAAQ,aAAa,MAAM,MAAM,WACnD,KAAK,cAAc,GACf,KAAK,cAAY,KAAK,eAAe;EAKzC,IAAM,IAAS,KAAK;EAEpB,KAAK,KAAK,gBAAgB,IAAS,yBAAyB,0BAA0B,KAAK,aAAa,2BAA2B,GAAG,EAAE;CACzI;CAMA,IAAI,kBAAsC;EACzC,IAAI,CAAC,KAAK,QAAQ;GACjB,IAAM,IAAK,KAAK,iBAAiB;GACjC,AAAI,MACH,KAAK,SAAS,GACd,KAAK,mBAAmB,CAAE;EAE5B;EACA,OAAO,KAAK;CACb;CAGA,IAAI,WAAW;EACd,OAAO,KAAK,iBAAiB;CAC9B;CAKA,KAAK,GAAiB,GAA6B;EAAE,KAAK,UAAU,KAAK,GAAS,CAAO;CAAG;CAa5F,YAAY,GAAiB,GAAqC;EACjE,IAAM,IAAW,MAAU;EAQ3B,AAPA,KAAK,QAAQ,iBAA8B,mBAAmB,EAAQ,GAAG,EAAE,SAAQ,MAAO;GACzF,EAAI,aAAa,iBAAiB,OAAO,CAAQ,CAAC;GAClD,IAAM,IAAO,EAAI,aAAa,uBAAuB;GAErD,AADI,KAAM,EAAe,GAAK,GAAM,CAAQ,GACxC,KAAK,cAAc,MAAU,EAAI,WAAW;EACjD,CAAC,GAEG,KAAK,cAAc,KAAU,KAAK,kBAAkB;CACzD;CAIA,KAAa,GAAa;EAAE,EAAI,gBAAgB,KAAK,SAAS,KAAK,OAAO,OAAO,CAAG;CAAG;CA0BvF,mBAA+C;EAC9C,IAAM,IAAS,KAAK,QAAQ,aAAa,mBAAmB;EAC5D,IAAI,GAAQ,OAAO,SAAS,cAA2B,CAAM;EAG7D,IAAM,IADU,KAAK,QAAQ,cAA2B,iBACxC,GAAS,aAAa,eAAe;EAGrD,OAFK,IACS,SAAS,eAAe,CAC/B,GAAO,QAAqB,8BAA8B,KAAK,OAFjD;CAGtB;CAIA,mBAA2B,GAAuB;EACjD,IAAM,EAAE,cAAW,KAAK;EAQxB,AANI,KAAK,cAAc,CAAC,KAAK,qBAC5B,EAAG,iBAAiB,yBAAyB,KAAK,eAAgC,EAAE,UAAO,CAAC,GAC5F,KAAK,mBAAmB,KAGzB,KAAK,kBAAkB,GAClB,EAAG,YACP,EAAG,iBAAiB,YAAY,KAAK,mBAAmB;GAAE,MAAM;GAAM;EAAO,CAAC;CAEhF;CAEA,gBAAwB;EACvB,IAAM,EAAE,cAAW,KAAK;EACxB,KAAK,QAAQ,iBAA8B,iBAAiB,EAAE,SAAQ,MAAW;GAChF,EAAQ,iBAAiB,UAAS,MAAS;IAC1C,KAAK,UAAU,GAAS,CAAK;GAC9B,GAAG,EAAE,UAAO,CAAC;EACd,CAAC;CACF;CAIA,UAAkB,GAAsB,GAAc;EACrD,IAAI,EAAQ,aAAa,eAAe,MAAM,QAAQ;EACtD,IAAM,IAAU,EAAQ,aAAa,eAAe;EAC/C,OAGL;OAAI,CAAC,KAAK,UAAU;IACnB,KAAK,KAAK,mBAAmB,EAAQ,2DAA2D;IAChG;GACD;GAEA,AADA,KAAK,SAAS,KAAK,GAAS,EAAE,SAAM,CAAC,GACjC,KAAK,cAAY,KAAK,WAAW,CAAO;EAF5C;CAGD;CAIA,QAA+B;EAC9B,OAAO,MAAM,KAAK,KAAK,QAAQ,iBAA8B,gBAAc,CAAC;CAC7E;CAMA,WAAmB,GAAqB;EACvC,KAAK,MAAM,EAAE,SAAQ,MAAO;GAAE,EAAI,WAAW,MAAQ,IAAS,IAAI;EAAI,CAAC;CACxE;CAIA,oBAA4B;EAC3B,IAAM,IAAO,KAAK,MAAM;EACxB,IAAI,EAAK,MAAK,MAAK,EAAE,aAAa,KAAK,KAAK,SAAS,CAAC,CAAC,GAAG;EAC1D,IAAM,IAAO,EAAK,MAAK,MAAK,EAAE,aAAa,eAAe,MAAM,UAAU,KAAK,SAAS,CAAC,CAAC,KACtF,EAAK,KAAK,KAAK,QAAQ;EAC3B,AAAI,KAAM,KAAK,WAAW,CAAI;CAC/B;CAEA,iBAAyB;EACxB,IAAM,IAAO,KAAK,MAAM;EACxB,IAAI,CAAC,EAAK,QAAQ;EAElB,IAAM,IAAS,EAAK,MAAK,MAAK,EAAE,aAAa,eAAe,MAAM,MAAM,KAAK,EAAK;EAElF,AADA,KAAK,WAAW,CAAM,GACtB,KAAK,QAAQ,iBAAiB,WAAW,KAAK,YAAY,EAAE,QAAQ,KAAK,YAAY,OAAO,CAAC;CAG9F;CA2CA,gBAAiC;EAChC,OAAO,KAAK,OAAO,eAAe,UAC9B,CAAC,KAAK,iBAAiB,KACvB,CAAC,KAAK,UAAU;CACrB;CAIA,mBAAoC;EACnC,IAAM,IAAK,KAAK;EAChB,IAAI,KAAM,EAAG,OAAO,cAAc,IAAO,OAAO;EAEhD,IAAM,IAAM,KAAK,iBACX,IAAU,MAAQ,EAAI,QAAQ,aAAa,EAAI,aAAa,YAAY;EAG9E,OAFI,KAAW,QAAQ,MAAY,UAAgB,KAE5C,KAAK,MAAM,EAAE,MAAK,MAAO;GAC/B,IAAM,IAAI,EAAI,aAAa,iBAAiB;GAC5C,OAAO,KAAK,QAAQ,MAAM;EAC3B,CAAC;CACF;CAGA,UAAU;EAGT,AAFA,KAAK,YAAY,MAAM,GACvB,OAAO,KAAK,QAAQ,cACpB,KAAK,KAAK,WAAW;CACtB;AACD;oBA1SmE;CACjE,YAAY;CACZ,OAAO;AACR,aAEqD;CACpD,YAAY,CAAC,cAAc,QAAQ;CACnC,OAAO,CAAC,SAAS,SAAS;AAC3B;;;AChBD,IAAa,IAAb,cAAkC,YAAY;CAC7C,oBAA0B;EACzB,IAAI,KAAK,OAAO;EAChB,IAAM,IAAU,EAAwB,MAAM,EAAM,KAAK;EACzD,IAAI,EAAM,MAAM,CAAO;CACxB;CAEA,uBAA6B,CAAC;AAC/B,GCRa,IAAb,cAAqC,YAAY;CAChD,oBAA0B;EACzB,IAAI,KAAK,UAAU;EACnB,IAAM,IAAU,EAA2B,MAAM,EAAS,KAAK;EAC/D,IAAI,EAAS,MAAM,CAAO;CAC3B;CAEA,uBAA6B,CAAC;AAC/B,GCRa,IAAb,cAAyC,YAAY;CACpD,oBAA0B;EACzB,IAAI,KAAK,cAAc;EACvB,IAAM,IAAU,EAA+B,MAAM,EAAa,KAAK;EACvE,IAAI,EAAa,MAAM,CAAO;CAC/B;CAEA,uBAA6B,CAAC;AAC/B;AAMA,SAAgB,EAAqB,IAAS,MAAY;CACzD,IAAM,IAAO,GAAG,EAAO;CACvB,AAAK,eAAe,IAAI,CAAI,KAAG,eAAe,OAAO,GAAM,CAAmB;AAC/E;;;ACUA,SAAgB,EAAS,IAAS,MAAY;CAC7C,IAAM,KAAU,GAAc,MAAmC;EAChE,AAAK,eAAe,IAAI,CAAI,KAAG,eAAe,OAAO,GAAM,CAAI;CAChE;CAGA,AAFA,EAAO,GAAG,EAAO,SAAS,CAAY,GACtC,EAAO,GAAG,EAAO,YAAY,CAAe,GAC5C,EAAO,GAAG,EAAO,gBAAgB,CAAmB;AACrD"}
|
package/dist/panelset.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
!function(){var t=class{constructor(){this.t=new AbortController}get signal(){return this.t.signal}start(){return this.t.abort(),this.t=new AbortController,this.t.signal}static waitForTransition(t,i){return new Promise(s=>{const e=getComputedStyle(t),n=(parseFloat(e.transitionDuration)||0)+(parseFloat(e.transitionDelay)||0);if(0===n)return s();let o=!1;const a=()=>{o||(o=!0,t.removeEventListener("transitionend",h),s())},h=s=>{s.target===t&&(i&&s.propertyName!==i||a())};t.addEventListener("transitionend",h),setTimeout(a,1e3*(n+.05))})}};function i(t,i,s){if(!i)return;if("input"!==i&&s&&!(s.type.startsWith("key")||s instanceof MouseEvent&&0===s.detail))return;const e=t=>{setTimeout(()=>t.focus(),100)};if(!0===i)t.hasAttribute("tabindex")||t.setAttribute("tabindex","-1"),e(t);else if("heading"===i){const i=t.querySelector("h1, h2, h3, h4, h5, h6");i&&(i.hasAttribute("tabindex")||i.setAttribute("tabindex","-1"),e(i))}else if("first"===i){const i=t.querySelector('a,button,input,select,textarea,[tabindex]:not([tabindex="-1"])');i&&e(i)}else if("input"===i){const i=t.querySelector("input:not([type=hidden]):not([disabled]),select:not([disabled]),textarea:not([disabled])");i&&e(i)}else"function"==typeof i&&setTimeout(()=>i(t),100)}var s=()=>{const t=new URLSearchParams(location.search).get("panel");return t?t.split(",").filter(Boolean):[]},e=t=>{const i=new URL(location.href);if(i.searchParams.delete("panel"),t.length){const s=i.search?"&":"?";history.replaceState(null,"",`${i}${s}panel=${t.join(",")}`)}else history.replaceState(null,"",i)},n=t=>`${location.pathname}::${t}`,o=t=>localStorage.getItem(n(t)),a=(t,i)=>localStorage.setItem(n(t),i);function h(t,i){switch(i){case"string":return t;case"boolean":return"false"!==t;case"number":return parseInt(t,10);case"json":try{return JSON.parse(t)}catch{return"false"!==t}}}function l(t,i){const s={};for(const[e,n]of Object.entries(i)){const[i,o]=n,a=t[i];void 0!==a&&(s[e]=h(a,o))}return s}function r(t,i){const s={};for(const[e,n]of Object.entries(i)){const[i,o]=n,a=i.replace(/([A-Z])/g,"-$1").toLowerCase(),l=t.getAttribute(a);null!==l&&(s[e]=h(l,o))}return s}function c(t,i,s,e){s&&console.log(`[${t}] "${i.id||"no id"}" -`,e)}function p(t,i,s){const e=i.split(/\s+/).filter(Boolean);if(!e.length)return;const n=(t.getAttribute("aria-describedby")||"").split(/\s+/).filter(Boolean);let o=!1;for(const a of e){const t=n.includes(a);s&&!t?(n.push(a),o=!0):!s&&t&&(n.splice(n.indexOf(a),1),o=!0)}o&&(n.length?t.setAttribute("aria-describedby",n.join(" ")):t.removeAttribute("aria-describedby"))}var d,u=!1;function g(t){t&&!u&&(u=!0,console.log("[Panel/PanelSet] Browser supports 'interpolate-size', which will be used for opening and closing."))}function f(t){t.waitUntil=i=>{t.promise=t.promise?Promise.all([t.promise,i]):i}}function b(t,i,s,e,n={}){const o=!0===n.once;t.addEventListener(i,t=>{const i=t,n=s(i.detail),{signal:a}=i.detail;if(o&&"true"===n.dataset.loaded)return;const h=e(n,a);h&&"function"==typeof h.then&&i.detail.waitUntil(h.then(()=>{o&&(n.dataset.loaded="true")}))})}var m=class n{static init(t={},i={}){let s,e;"string"==typeof t?(s=t,e=i):(e=t,s=e.selector||"[data-panelset]");const o=document.querySelectorAll(s),a=[];return o.forEach(t=>{try{n.i(t)}catch(s){return void console.error(s.message)}if(t.panelSet)return void a.push(t.panelSet);const i=new n(t,e);a.push(i)}),a}constructor(i,h={}){let r;if(this.hasAsyncContent=!1,this.o=new t,this.h=new t,this.l=!1,this.p=!1,this.u=null,this.m=null,this.v=null,this.$=new AbortController,this.S=()=>{const t=s();return this.panels.find(i=>i.id&&t.includes(i.id))?.id??null},this.A=t=>{if(this.config.persist&&this.element.id&&a(`ps:${this.element.id}`,t),this.config.deepLink)this._(t);else{const t=new Set(this.panels.map(t=>t.id).filter(Boolean)),i=s();i.some(i=>t.has(i))&&e(i.filter(i=>!t.has(i)))}},this._=t=>{const i=new Set(this.panels.map(t=>t.id).filter(Boolean));e([...s().filter(t=>!i.has(t)),t].filter(Boolean))},this.P=()=>{const t=this.S();if(t)return t;if(this.config.persist){const{id:t}=this.element;if(!t)return null;const i=o(`ps:${t}`);return i&&this.panels.some(t=>t.id===i)?i:null}return null},this.F=t=>{const{atStart:i,atEnd:s}=t.detail;this.k(i,s)},"string"==typeof i){if(r=document.querySelector(i),!r)throw new Error(`PanelSet: No element found for selector "${i}"`)}else r=i;if(this.element=r,n.i(r),r.panelSet)return console.warn("PanelSet: already initialized"),r.panelSet;r.panelSet=this,n.C();const c=l(r.dataset,n.attrs);if(this.config={...n.defaults,...h,...c},this.panels=this.T(),0===this.panels.length)return this.panelWrapper=this.element.querySelector(":scope > .panel-wrapper")||this.L(),this.O("Initialized empty (0 panels) — ready for addPanel()"),this.H("ps:ready",{container:this.element,instance:this}),this.I(),void this.q();const p=this.P();this.activePanel=(p?this.panels.find(t=>t.id===p):null)??this.panels.find(t=>t.classList.contains("active"))??this.panels[0],this.panelWrapper=this.element.querySelector(":scope > .panel-wrapper")||this.L(),this.pendingPanel=this.activePanel,"start"!==this.config.align&&(this.element.dataset.panelsetAlign=this.config.align),this.config.closable&&!this.element.classList.contains("is-open")&&this.element.setAttribute("inert",""),n.D&&g(this.config.debug),this.O(`Initialized (${this.panels.length} panels)`),this.H("ps:ready",{container:this.element,instance:this}),this.M(),this.I(),this.q()}q(){const t=this.element.closest("[data-panelset-trackheight]");if(!t||"undefined"==typeof ResizeObserver)return;let i=t.clientWidth,s=0;this.v=new ResizeObserver(()=>{const e=t.clientWidth;e!==i&&(i=e,cancelAnimationFrame(s),s=requestAnimationFrame(()=>this.B()))}),this.v.observe(t)}O(t){c("PanelSet",this.element,this.config.debug,t)}get R(){return this.config.closable&&!this.element.classList.contains("is-open")&&!this.element.classList.contains("is-opening")}static i(t){if(!t.hasAttribute("data-panelset")&&!t.tagName.includes("-"))throw new Error("PanelSet: element must have [data-panelset] or be a custom element")}L(){const t=document.createElement("div");return t.className="panel-wrapper",this.panels.forEach(i=>t.appendChild(i)),this.element.appendChild(t),t}T(){return Array.from(this.element.querySelectorAll('[role="tabpanel"]')).filter(t=>t.closest("[data-panelset], ps-panelset, [data-panel], ps-panel")===this.element)}M(){this.panels.forEach(t=>{t.classList.remove("fade","incoming","outgoing","levelup","leveldown"),t!==this.activePanel?(t.hidden=!0,t.classList.remove("active")):(t.hidden=!1,t.classList.add("active"))}),this.element.style.height="",this.B(),this.config.manageTriggers&&this.V(this.activePanel),this.config.manageLabels&&this.N()}H(t,i){this.element.dispatchEvent(new CustomEvent(t,{detail:i,bubbles:!0,cancelable:!1}))}j(t){if(!t)return 0;const i=getComputedStyle(t);return(parseFloat(i.paddingTop)||0)+(parseFloat(i.paddingBottom)||0)+(parseFloat(i.borderTopWidth)||0)+(parseFloat(i.borderBottomWidth)||0)}U(t){let i=t.offsetHeight;return i+=this.j(this.panelWrapper),i+=this.j(this.element),i}B(){if(this.element.hasAttribute("data-panelset-trackheight"))return void console.warn("PanelSet: data-panelset-trackheight on parent only");const t=this.element.closest("[data-panelset-trackheight]");if(!t)return;this.panels.forEach(t=>{t.hidden=!0,t.classList.remove("active")});let i=0;this.panels.forEach(t=>{t.hidden=!1,t.classList.add("active"),t.style.visibility="hidden";const s=this.element.offsetHeight;s>i&&(i=s),t.hidden=!0,t.classList.remove("active"),t.style.visibility=""}),this.activePanel&&(this.activePanel.hidden=!1,this.activePanel.classList.add("active")),t.style.setProperty("--ps-max-height",`${i}px`),this.O(`Max container height: ${i}px`)}V(t){this.panels.forEach(i=>{i.id&&document.querySelectorAll(`[aria-controls="${i.id}"]`).forEach(s=>{s.setAttribute("aria-selected",String(i===t))})})}N(){this.panels.forEach(t=>{if(!t.id)return;if(t.hasAttribute("aria-labelledby")||t.hasAttribute("aria-label"))return;const i=Array.from(document.querySelectorAll(`[aria-controls="${t.id}"]`));if(0===i.length)return;const s=i.filter(t=>"tab"===t.getAttribute("role")),e=1===s.length?s[0]:1===i.length?i[0]:null;e&&(e.id||(e.id=this.W(`${t.id}-tab`)),t.setAttribute("aria-labelledby",e.id))})}W(t){let i=t,s=2;for(;document.getElementById(i);)i=`${t}-${s++}`;return i}G(t){this.panels.forEach(i=>{i.id&&document.querySelectorAll(`[aria-controls="${i.id}"]`).forEach(i=>{i.classList.toggle("is-activating",t)})})}J(t){this.panels.forEach(i=>{i.classList.remove("fade","incoming","outgoing","levelup","leveldown"),i!==t?(i.classList.remove("active"),i.hidden=!0):(i.classList.add("active"),i.hidden=!1,i.removeAttribute("inert"))}),this.element.style.height="",this.element.classList.remove("is-transitioning"),this.activePanel=t,this.config.manageTriggers&&this.V(t)}K(t,i){if(this.config.manageTriggers){const i=t?.getAttribute("data-auto-focus");if(null!=i){if("true"===i)return!0;if("false"===i)return!1;if("heading"===i||"first"===i||"input"===i)return i}}return void 0!==i?i:this.config.autoFocus}Z(t,s,e){i(t,s,e)}X(i,s,e){const o="is-"+(i?"closing":"opening"),a="is-"+(i?"opening":"closing");this.O(i?"Opening":"Closing");const h=this.h.start(),l=this.element.classList.contains(o)?this.element.offsetHeight:null,r=i?null:this.element.offsetHeight;this.element.classList.remove(o),i||this.element.classList.remove("is-open"),i&&this.element.removeAttribute("inert");const c=()=>{this.element.setAttribute("inert","");const t=e instanceof PointerEvent&&""!==e.pointerType;this.config.returnFocus&&this.m&&!t&&this.m.focus()};if(s&&this.config.transitions)if(this.element.classList.add(a),n.D)i?(this.element.style.height=null!==l?`${l}px`:"0px",requestAnimationFrame(()=>{this.element.style.height="",t.waitForTransition(this.element,"height").then(()=>{h.aborted||(this.panelWrapper?t.waitForTransition(this.panelWrapper):Promise.resolve()).then(()=>{h.aborted||(this.element.classList.remove(a),this.element.classList.add("is-open"),this.element.offsetHeight)})})})):(this.element.style.height=null!==l?`${l}px`:`${r}px`,requestAnimationFrame(()=>{this.element.style.height="",t.waitForTransition(this.element,"height").then(()=>{h.aborted||(this.element.classList.remove(a),this.element.offsetHeight,c())})}));else{const s=i?this.U(this.pendingPanel):0,e=null!==l?l:i?this.element.offsetHeight:r??0;this.element.style.height=`${e}px`,getComputedStyle(this.element).height,requestAnimationFrame(()=>{this.element.style.height=`${s}px`,t.waitForTransition(this.element).then(()=>{h.aborted||(this.element.style.height="",this.element.classList.remove(a),i&&this.element.classList.add("is-open"),this.element.offsetHeight,i||c())})})}else i?this.element.classList.add("is-open"):(this.element.classList.remove("is-open"),c()),this.element.style.height=""}getActive(){return this.pendingPanel?.id||null}refresh(){const t=this.activePanel;this.panels=this.T(),0!==this.panels.length&&(this.activePanel=t&&this.panels.includes(t)?t:this.panels.find(t=>t.classList.contains("active"))??this.panels[0],this.pendingPanel=this.activePanel,this.panelWrapper=this.element.querySelector(":scope > .panel-wrapper")||this.panelWrapper,this.M(),this.Y(),this.O(`Refreshed (${this.panels.length} panels)`))}addPanel(t,i){t.hasAttribute("role")||t.setAttribute("role","tabpanel");let s=null;return i?.before?s=this.panels.find(t=>t.id===i.before)??null:i?.after?s=this.panels.find(t=>t.id===i.after)?.nextElementSibling??null:"number"==typeof i?.index&&(s=this.panels[i.index]??null),(this.panelWrapper||this.L()).insertBefore(t,s),this.refresh(),t}removePanel(t){const i=this.panels.find(i=>i.id===t);i&&(i.remove(),this.refresh())}destroy(){this.o.start(),this.h.start(),this.v?.disconnect(),this.v=null,this.$.abort(),delete this.element.panelSet,this.O("Destroyed")}tt(t){const i=this.panels.length,s=t?this.panels.indexOf(t):-1;return{index:s,total:i,atStart:s<=0,atEnd:s===i-1}}static C(){n.it||(n.it=!0,document.addEventListener("click",n.st))}static et(t,i){const s=t.getAttribute(`data-ps-${i}`);return s?document.querySelector(s):t.closest("[data-panelset], ps-panelset")}I(){const{signal:t}=this.$;this.element.addEventListener("ps:activationstart",this.F,{signal:t}),this.element.addEventListener("ps:activationcomplete",this.F,{signal:t}),this.Y()}Y(){const{atStart:t,atEnd:i}=this.tt(this.pendingPanel);this.k(t,i)}k(t,i){if(this.config.loop)return;const s=this.nt("prev"),e=this.nt("next");if("native"!==this.config.disabledMode)return s.forEach(i=>this.ot(i,t)),void e.forEach(t=>this.ot(t,i));t||s.forEach(t=>this.ot(t,!1)),i||e.forEach(t=>this.ot(t,!1)),t&&this.ht(s,i?[]:e),i&&this.ht(e,t?[]:s)}ot(t,i){"native"===this.config.disabledMode?i?t.setAttribute("disabled",""):t.removeAttribute("disabled"):t.setAttribute("aria-disabled",String(i));const s=t.getAttribute("data-ps-disabled-hint");s&&p(t,s,i)}ht(t,i){t.forEach(t=>{t.hasAttribute("disabled")||document.activeElement!==t||(i.find(t=>!t.hasAttribute("disabled"))??this.lt())?.focus(),this.ot(t,!0)})}lt(){const t=this.pendingPanel??this.activePanel;return t?(t.hasAttribute("tabindex")||t.setAttribute("tabindex","-1"),t):null}nt(t){return Array.from(document.querySelectorAll(`[data-ps-${t}]`)).filter(i=>n.et(i,t)===this.element)}next(t){this.rt(1,t)}prev(t){this.rt(-1,t)}rt(t,i){const s=this.panels.length;if(0===s)return;const e=this.panels.indexOf(this.pendingPanel);let n=(-1===e?0:e)+t,o=!1;if(n<0||n>=s){if(!this.config.loop)return;n=(n+s)%s,o=!0}const a=this.panels[n];a&&a!==this.pendingPanel&&this.show(a.id,o?{...i,direction:t>0?"forward":"backward"}:i)}open(i){const{event:s,transition:e=!0,autoFocus:n}=i||{};if(!this.config.closable)return void this.O("Not closable");const o=this.R,a=this.element.classList.contains("is-closing"),h=this.element.classList.contains("is-loading");if(!o&&!a)return;if(this.element.classList.contains("is-transitioning")&&!h)return;const l=s?.target instanceof HTMLElement?s.target.closest('button, a, [role="tab"]')??s.target:null,r=this.K(l,n);l&&(this.m=l),this.X(!0,e),!1!==r&&void 0!==r&&this.pendingPanel&&(e&&this.config.transitions?t.waitForTransition(this.element).then(()=>{this.Z(this.pendingPanel,r,s)}):this.Z(this.pendingPanel,r,s))}close(t){const{transition:i=!0,event:s}=t||{};if(!this.config.closable)return void this.O("Not closable");const e=this.R,n=this.element.classList.contains("is-closing"),o=this.element.classList.contains("is-opening"),a=this.element.classList.contains("is-loading");(!e&&!n||o)&&(this.element.classList.contains("is-transitioning")&&!a||this.X(!1,i,s))}toggle(t){const{event:i,transition:s=!0,autoFocus:e}=t||{},n=this.R,o=this.element.classList.contains("is-closing");n||o?this.open({event:i,transition:s,autoFocus:e}):this.close({transition:s,event:i})}onBeforeOpen(t,i={}){this.hasAsyncContent=!0,b(this.element,"ps:beforeopen",t=>t.targetPanel,t,i)}async show(i,s){if(!1===this.config.interruptible&&this.p)return;const{event:e,transition:n=!0,autoFocus:o,direction:a}=s||{},h=e?.target instanceof HTMLElement?e.target.closest('button, a, [role="tab"]')??e.target:null,l=this.K(h,o),r=this.panels.find(t=>t.id===i);if(!r)return void this.O(`Panel not found: ${i}`);const c=new CustomEvent("ps:beforeactivate",{detail:{panelId:i,targetPanel:r,outgoingPanel:this.activePanel??null,trigger:h},bubbles:!0,cancelable:!0});if(!this.element.dispatchEvent(c))return void this.O(`Vetoed by ps:beforeactivate: ${i}`);const p=this.R,d=this.element.classList.contains("is-closing"),u=this.element.classList.contains("is-loading");if(r===this.pendingPanel)return void(p||d?this.open({event:e,transition:n,autoFocus:l}):this.config.closable&&this.config.closeOnTab&&this.close({transition:n,event:e}));if((this.element.classList.contains("is-opening")||d)&&!u)return;if(p)return this.pendingPanel=r,this.J(r),void this.open({event:e,transition:n,autoFocus:l});const g=this.p;this.p=!0,this.config.manageTriggers&&!1===this.config.interruptible&&this.G(!0);const b=this.pendingPanel,m=b?.id;this.pendingPanel=r;const v=g&&r===this.activePanel&&b!==r;this.config.manageTriggers&&this.V(r),this.A(i),this.element.classList.remove("is-loading"),!v&&b&&b!==this.activePanel&&b!==r&&(b.classList.remove("incoming","outgoing","levelup","leveldown"),b.hidden||b.classList.remove("active"));const w=this.l,y=this.o.signal.aborted,$=this.o.start();!y&&w&&m&&m!==i&&this.H("ps:activationaborted",{panelId:m,trigger:h}),this.l=!1,this.O(`${b?.id||"none"} > ${i}`);const S={panelId:i,targetPanel:r,outgoingPanel:b,signal:$,promise:null,waitUntil(){}};f(S);const x=new CustomEvent("ps:beforeopen",{detail:S,bubbles:!0,cancelable:!1});this.element.dispatchEvent(x);const A=S.promise;if(A){this.l=!0,this.O("Waiting for content..."),this.element.style.setProperty("--ps-loading-delay",`${this.config.loadingDelay}ms`),this.element.classList.add("is-loading");let s=null;const e=!1!==n&&!1!==this.config.transitions;let o=e;if("object"==typeof this.config.transitions&&(o=e&&!1!==this.config.transitions.height),o)if(p)this.element.classList.add("is-open","is-opening"),this.element.style.height="0px",requestAnimationFrame(()=>{this.element.style.height=`${this.config.loadingHeight}px`}),s=t.waitForTransition(this.element,"height");else{const i=this.element.offsetHeight,e=Math.max(i,this.config.loadingHeight);e>i&&(this.element.style.height=`${i}px`,requestAnimationFrame(()=>{this.element.style.height=`${e}px`}),s=t.waitForTransition(this.element,"height"))}try{if(await Promise.all([A,s].filter(Boolean)),$.aborted)return this.O(`Aborted during load: ${i}`),this.element.classList.remove("is-loading"),void this.element.style.removeProperty("--ps-loading-delay");this.O("Content loaded"),"true"===r.dataset.loaded&&this.B()}catch(T){const t=T;return this.O(`Load failed: ${t.message}`),this.element.classList.remove("is-loading"),this.element.style.removeProperty("--ps-loading-delay"),"AbortError"!==t.name&&console.error("Panel load error:",T),this.p=!1,void(this.config.manageTriggers&&!1===this.config.interruptible&&this.G(!1))}this.element.classList.remove("is-loading"),this.element.style.removeProperty("--ps-loading-delay"),this.element.classList.remove("is-opening")}if($.aborted)return void this.O(`Aborted: ${i}`);const _=v?b:this.activePanel;this.H("ps:activationstart",{panelId:i,trigger:h,outgoingPanel:_,...this.tt(r)});const P=!1!==n&&!1!==this.config.transitions;let F=P,k=P;"object"==typeof this.config.transitions&&(F=P&&!1!==this.config.transitions.panels,k=P&&!1!==this.config.transitions.height),this.panels.forEach(t=>t.classList.toggle("fade",F));let C=null;if(v)C="leveldown"===this.u?"levelup":"leveldown";else if(this.config.levels&&_&&_!==r)if(a)C="forward"===a?"levelup":"leveldown";else{const t=this.panels.indexOf(_),i=this.panels.indexOf(r);-1!==t&&-1!==i&&t!==i&&(C=i>t?"levelup":"leveldown")}this.u=C,this.panels.forEach(t=>t.classList.remove("outgoing","levelup","leveldown"));const E=this.element.offsetHeight;k&&(this.element.style.height=`${E}px`),r.hidden=!1,r.setAttribute("inert",""),r.classList.add("incoming"),C&&r.classList.add(C),F&&this.element.classList.add("is-transitioning"),_&&_!==r&&(_.classList.remove("active","incoming"),_.classList.add("outgoing"),C&&_.classList.add(C),_.hidden=!1,_.setAttribute("inert","")),requestAnimationFrame(()=>requestAnimationFrame(()=>{r.classList.add("active"),_&&_!==r&&_.classList.remove("incoming");const s=this.U(r),n=E!==s;k&&(this.element.style.height=`${s}px`);const o=[];F&&o.push(t.waitForTransition(r)),k&&n&&o.push(t.waitForTransition(this.element)),o.length||o.push(Promise.resolve()),Promise.all(o).then(()=>{$.aborted?this.O(`Interrupted: ${i}`):(this.J(r),this.O(`✓ ${i}`),!1!==l&&void 0!==l&&this.Z(r,l,e),this.p=!1,this.config.manageTriggers&&!1===this.config.interruptible&&this.G(!1),this.H("ps:activationcomplete",{panelId:i,trigger:h,outgoingPanel:_,...this.tt(r)}))})}))}};(d=m).defaults={align:"start",transitions:!0,levels:!1,loop:!1,closable:!1,closeOnTab:!1,disabledMode:"aria",loadingHeight:150,loadingDelay:320,returnFocus:!1,autoFocus:!1,persist:!1,deepLink:!1,interruptible:!0,manageTriggers:!0,manageLabels:!0,debug:!1},d.D="undefined"!=typeof CSS&&CSS.supports("interpolate-size: allow-keywords"),d.it=!1,d.attrs={align:["panelsetAlign","string"],transitions:["transitions","json"],levels:["psLevels","boolean"],loop:["psLoop","boolean"],closable:["closable","boolean"],closeOnTab:["closeOnTab","boolean"],disabledMode:["psDisabledMode","string"],loadingHeight:["loadingHeight","number"],loadingDelay:["loadingDelay","number"],autoFocus:["autoFocus","string"],returnFocus:["returnFocus","boolean"],persist:["panelPersist","boolean"],deepLink:["panelDeeplink","boolean"],interruptible:["interruptible","boolean"],manageTriggers:["manageTriggers","boolean"],manageLabels:["manageLabels","boolean"],debug:["debug","boolean"]},d.st=t=>{const i=t.target;if(!(i instanceof Element))return;const s=i.closest("[data-ps-next], [data-ps-prev], [data-ps-close]");if(!s||"true"===s.getAttribute("aria-disabled"))return;const e=s.hasAttribute("data-ps-next")?"next":s.hasAttribute("data-ps-prev")?"prev":"close",n=d.et(s,e),o=n?.panelSet;o?o[e]({event:t}):n&&c("PanelSet",n,null!=n.dataset.debug&&"false"!==n.dataset.debug,`data-ps-${e}: PanelSet is not initialised. Add a PanelSet.init().`)};var v,w,y=t=>{const i=t.parentElement;return i?.querySelector("[data-panel-body]")?Array.from(i.children).find(t=>t instanceof HTMLElement&&t.hasAttribute("data-panel-body"))??null:null},$=t=>{const i=Array.from(t.querySelectorAll("[data-panel-pin]"));i.length&&i.map(t=>({el:t,pin:t.dataset.panelPin,w:t.offsetWidth})).forEach(({el:t,pin:i,w:s})=>{t.style.boxSizing="border-box",t.style.width=`${s}px`,"end"===i&&(t.style.marginLeft=`calc(100% - ${s}px)`)})},S=t=>{t.querySelectorAll("[data-panel-pin]").forEach(t=>{t.style.boxSizing="",t.style.width="",t.style.marginLeft=""})},x=class n{static init(t="[data-panel]",i={}){let s,e;return"string"==typeof t?(s=t,e=i):(e=t,s="[data-panel]"),Array.from(document.querySelectorAll(s)).filter(t=>!t.panel).filter(t=>!t.dataset.panel||"data-panel"===t.dataset.panel).map(t=>new n(t,e))}constructor(i,h={}){this.m=null,this.ct=null,this.dt=new t,this.ut=new AbortController,this.p=!1,this.S=()=>{const{id:t}=this.element;return!!t&&s().includes(t)},this._=t=>{const{id:i}=this.element;if(!i)return;const n=s();e(t?[...new Set([...n,i])]:n.filter(t=>t!==i))},this.gt=()=>{const t=t=>this.element.hasAttribute(t)?"false"!==this.element.getAttribute(t):void 0,i=t("data-panel-persist"),s=t("data-panel-deeplink");let e,n,o=this.element.parentElement;for(;o&&!o.hasAttribute("data-panel");){if(o.hasAttribute("data-panel-group")){o.hasAttribute("data-panel-persist")&&(e="false"!==o.getAttribute("data-panel-persist")),o.hasAttribute("data-panel-deeplink")&&(n="false"!==o.getAttribute("data-panel-deeplink"));break}o=o.parentElement}return{persist:i??e??this.config.persist,deepLink:s??n??this.config.deepLink}},this.A=t=>{if(!this.element.id)return;const{persist:i,deepLink:s}=this.gt();i&&a(`panel:${this.element.id}`,t?"open":"closed"),s?this._(t):!t&&this.S()&&this._(!1)},this.ft=()=>{const{id:t}=this.element;if(!t)return!1;if(this.S())return!0;const{persist:i}=this.gt();return!(!i||"open"!==o(`panel:${t}`))},this.bt=()=>"horizontal"===this.config.axis?"width":"height";const r="string"==typeof i?document.querySelector(i):i;if(!r)throw new Error(`Panel: No element found for selector "${i}"`);if(this.element=r,r.panel=this,!r.querySelector(":scope > .panel-wrapper")){const t=document.createElement("div");t.className="panel-wrapper",t.append(...Array.from(r.childNodes)),r.appendChild(t)}const c=l(r.dataset,n.attrs);this.config={...n.defaults,...h,...c},"horizontal"===this.config.axis&&(r.dataset.panelAxis="horizontal"),"start"!==this.config.align&&(r.dataset.panelAlign=this.config.align),this.vt(),this.wt(),this.ft()||this.element.classList.contains("is-open")?(this.element.classList.add("is-open"),this.element.removeAttribute("inert"),this.yt(!0),this.element.classList.add("is-restored"),requestAnimationFrame(()=>requestAnimationFrame(()=>this.element.classList.remove("is-restored"))),this.H("panel:opened")):this.element.setAttribute("inert",""),n.D&&g(this.config.debug),this.O("Initialized")}O(t){c("Panel",this.element,this.config.debug,t)}vt(){const t=t=>t.hasAttribute("data-panel")||!!t.panel,i=t=>{this.element.id||(this.element.id="panel-"+ ++n.$t),t.setAttribute("aria-controls",this.element.id),t.hasAttribute("aria-expanded")||t.setAttribute("aria-expanded","false"),t.removeAttribute("data-panel-trigger")},s=t=>t.hasAttribute("data-panel-trigger")?t:/^H[1-6]$/.test(t.tagName)?t.querySelector(":scope > [data-panel-trigger]"):null;for(const e of["previousElementSibling","nextElementSibling"]){let n=this.element[e];for(;n&&!t(n);){const t=s(n);if(t){i(t);break}n=n[e]}}}wt(){const t=this.element.id;if(!t)return;const{signal:i}=this.ut;document.querySelectorAll(`[aria-controls="${t}"]`).forEach(t=>{t.addEventListener("click",i=>{this.m=t,this.toggle(i)},{signal:i})}),this.element.querySelectorAll("[data-panel-close]").forEach(t=>{t.closest("[data-panel]")===this.element&&t.addEventListener("click",()=>this.close(),{signal:i})}),this.config.closeOnResize&&window.addEventListener("resize",()=>{if(!this.isOpen||this.element.classList.contains("is-closing"))return;const t=y(this.element);t&&S(t),this.close()},{signal:i})}yt(t){const i=this.element.id;i&&document.querySelectorAll(`[aria-controls="${i}"]`).forEach(i=>i.setAttribute("aria-expanded",String(t)))}St(){this.ct&&(this.ct.style.removeProperty("--ps-tempclose-speed"),this.ct.style.removeProperty("--ps-tempclose-timing"),this.ct=null)}xt(){const t=this.element.closest("[data-panel-group]"),i=t?.hasAttribute("data-panel-close-siblings")??!1;if(!this.config.closeSiblings&&!i)return;const s=t?function(t){const{groupSelector:i,scopeSelector:s=i,itemSelector:e,filter:n}={groupSelector:"[data-panel-group]",itemSelector:"[data-panel]",filter:t=>!!t.panel?.isOpen},o=(t,i)=>{if(t.closest(s)!==i)return!1;const n=t.parentElement?.closest(e);return!n||!i.contains(n)},a=t.closest(i);return a&&o(t,a)?[...a.querySelectorAll(e)].filter(i=>i!==t&&o(i,a)&&(!n||n(i))):[]}(this.element):Array.from(this.element.parentElement?.children??[]).filter(t=>t instanceof HTMLElement&&t!==this.element&&!!t.panel?.isOpen);s.length&&t&&(t.style.setProperty("--ps-tempclose-speed","var(--ps-open-speed)"),t.style.setProperty("--ps-tempclose-timing","var(--ps-open-timing)"),this.ct=t),s.forEach(t=>{t.panel.m=null,t.panel.close()})}Z(t){this.config.autoFocus&&i(this.element,this.config.autoFocus,t)}H(t){"panel:opened"!==t&&"panel:closed"!==t||(this.p=!1);const i={trigger:this.m};this.element.dispatchEvent(new CustomEvent(t,{detail:i,bubbles:!0}))}get isOpen(){return this.element.classList.contains("is-open")||this.element.classList.contains("is-opening")}async open(t){if(this.isOpen&&!this.element.classList.contains("is-closing"))return;if(!1===this.config.interruptible&&this.p)return;this.p=!0;const i=this.dt.start(),s=this.bt(),e={signal:i,promise:null,waitUntil(){},trigger:this.m};f(e),this.element.dispatchEvent(new CustomEvent("panel:beforeopen",{detail:e,bubbles:!0})),e.promise?await this.At(i,s,e.promise,t):this._t(i,s,t)}async At(i,s,e,o){const a=await Promise.race([e.then(()=>!0),new Promise(t=>{const s=setTimeout(()=>t(!1),this.config.loadingDelay);i.addEventListener("abort",()=>clearTimeout(s))})]).catch(()=>!1);if(i.aborted)return;if(a)return void this._t(i,s,o);this.element.classList.remove("is-closing"),this.element.removeAttribute("inert"),this.element.classList.add("is-loading"),this.element.querySelector(":scope > .panel-wrapper")?.replaceChildren(),this.element.style.setProperty("--ps-loading-delay","0ms"),this.yt(!0),this.A(!0),this.H("panel:opening");const h=y(this.element);let l;h&&$(h),this.config.transitions?(this.element.classList.add("is-opening"),this.element.style[s]="0px",getComputedStyle(this.element)[s],requestAnimationFrame(()=>{this.element.style[s]=`${this.config.loadingHeight}px`}),l=t.waitForTransition(this.element,s)):this.element.style[s]=`${this.config.loadingHeight}px`;try{await Promise.all([e,l].filter(Boolean))}catch{}finally{this.element.classList.remove("is-loading"),this.element.style.removeProperty("--ps-loading-delay")}if(i.aborted)return;const r=this.element.getBoundingClientRect(),c="height"===s?r.height:r.width;if(this.element.style[s]="",this.config.transitions)if(n.D)t.waitForTransition(this.element,s).then(()=>{i.aborted||(this.element.classList.remove("is-opening"),this.element.classList.add("is-open"),this.H("panel:opened"),this.O("Opened"),this.Z(o))});else{this.element.style[s]="auto";const e=this.element.getBoundingClientRect(),n="height"===s?e.height:e.width;this.element.style[s]=`${c}px`,getComputedStyle(this.element)[s],requestAnimationFrame(()=>{this.element.style[s]=`${n}px`,t.waitForTransition(this.element,s).then(()=>{i.aborted||(this.element.style[s]="",this.element.classList.remove("is-opening"),this.element.classList.add("is-open"),this.H("panel:opened"),this.O("Opened"),this.Z(o))})})}else this.element.classList.remove("is-opening"),this.element.classList.add("is-open"),this.H("panel:opened"),this.O("Opened"),this.Z(o)}_t(i,s,e){const o=this.element.classList.contains("is-closing")?this.element.getBoundingClientRect()["height"===s?"height":"width"]:null;this.element.classList.remove("is-closing"),this.element.removeAttribute("inert");const a=y(this.element);if(this.config.transitions)if(n.D)this.element.classList.add("is-opening"),this.element.style[s]=null!==o?`${o}px`:"0px",a&&$(a),getComputedStyle(this.element)[s],this.yt(!0),this.A(!0),this.xt(),this.H("panel:opening"),requestAnimationFrame(()=>{this.element.style[s]="",t.waitForTransition(this.element,s).then(()=>{i.aborted||(this.element.classList.remove("is-opening"),this.element.classList.add("is-open"),this.H("panel:opened"),this.St(),this.O("Opened"),this.Z(e))})});else{this.yt(!0),this.A(!0),this.xt(),this.H("panel:opening"),this.element.style[s]="auto";const n=this.element.getBoundingClientRect(),h="height"===s?n.height:n.width;this.element.style[s]=null!==o?`${o}px`:"0px",this.element.classList.add("is-opening"),a&&$(a),getComputedStyle(this.element)[s],requestAnimationFrame(()=>{this.element.style[s]=`${h}px`,t.waitForTransition(this.element,s).then(()=>{i.aborted||(this.element.style[s]="",this.element.classList.remove("is-opening"),this.element.classList.add("is-open"),this.H("panel:opened"),this.St(),this.O("Opened"),this.Z(e))})})}else this.yt(!0),this.A(!0),this.xt(),this.H("panel:opening"),this.element.classList.add("is-open"),this.H("panel:opened"),this.St(),this.O("Opened"),this.Z(e)}onBeforeOpen(t,i={}){b(this.element,"panel:beforeopen",()=>this.element,t,i)}close(i){if(!this.isOpen)return;if(!1===this.config.interruptible&&this.p)return;this.p=!0,this.element.setAttribute("inert",""),this.yt(!1);const s=this.bt(),e=y(this.element),n=this.dt.start();this.H("panel:closing");const o=()=>{this.element.classList.remove("is-closing","is-open","is-opening"),this.element.style[s]="",e&&S(e),this.A(!1),this.H("panel:closed"),this.O("Closed");const t=i instanceof PointerEvent&&""!==i.pointerType;this.config.returnFocus&&this.m&&!t&&this.m.focus()};if(!this.config.transitions)return void o();const a=this.element.getBoundingClientRect(),h="height"===s?a.height:a.width;this.element.style[s]=`${h}px`,this.element.classList.remove("is-opening","is-open"),this.element.classList.add("is-closing"),getComputedStyle(this.element)[s],requestAnimationFrame(()=>{this.element.style[s]="0px",t.waitForTransition(this.element,s).then(()=>{n.aborted||o()})})}toggle(t){this.element.classList.contains("is-closing")?this.open(t):this.isOpen?this.close(t):(t?.target&&(this.m=t.target.closest("button, a")??t.target),this.open(t))}destroy(){this.dt.start(),this.ut.abort(),this.element.classList.remove("is-opening","is-closing","is-loading","is-open"),this.element.style[this.bt()]="",this.element.setAttribute("inert",""),this.yt(!1);const t=y(this.element);t&&S(t),delete this.element.panel,this.O("Destroyed")}};(v=x).defaults={axis:"vertical",align:"start",closeOnResize:!1,transitions:!0,autoFocus:!1,returnFocus:!0,closeSiblings:!1,loadingDelay:320,loadingHeight:150,interruptible:!0,persist:!1,deepLink:!1,debug:!1},v.attrs={axis:["panelAxis","string"],align:["panelAlign","string"],autoFocus:["panelAutoFocus","string"],closeOnResize:["panelCloseOnResize","boolean"],transitions:["panelTransitions","boolean"],returnFocus:["panelReturnFocus","boolean"],closeSiblings:["panelCloseSiblings","boolean"],loadingDelay:["panelLoadingDelay","number"],loadingHeight:["panelLoadingHeight","number"],interruptible:["panelInterruptible","boolean"],persist:["panelPersist","boolean"],deepLink:["panelDeeplink","boolean"],debug:["debug","boolean"]},v.D="undefined"!=typeof CSS&&CSS.supports("interpolate-size: allow-keywords"),v.$t=0;var A=class t{static init(i="[data-panelcontrol]",s={}){let e,n;return"string"==typeof i?(e=i,n=s):(n=i,e=n.selector||"[data-panelcontrol]"),Array.from(document.querySelectorAll(e)).filter(t=>!t.panelControl).map(i=>new t(i,n))}constructor(i,s={}){this.Pt=null,this.t=new AbortController,this.Ft=!1,this.kt=!1,this.Ct=()=>{const t=this.panelSet,i=this.panelSetElement;let s=!1;if(t)s=!(!t.config.closable||!t.config.closeOnTab);else if(i){const t=null!=i.dataset.closable||i.hasAttribute("closable"),e=null!=i.dataset.closeOnTab||i.hasAttribute("close-on-tab");s=t&&e}this.element.toggleAttribute("data-closeable",s)},this.Et=t=>"true"!==t.getAttribute("aria-disabled")&&!t.hidden,this.Tt=t=>{const i=this.Lt().find(i=>i.getAttribute("aria-controls")===t.detail?.panelId);i&&this.Ot(i)},this.zt=t=>{const i=this.Lt().filter(this.Et);if(!i.length)return;const s="vertical"===this.element.getAttribute("aria-orientation"),e=s?"ArrowDown":"ArrowRight",n=s?"ArrowUp":"ArrowLeft",o=i.indexOf(document.activeElement);let a;switch(t.key){case e:a=i[(o+1)%i.length];break;case n:a=i[(o-1+i.length)%i.length];break;case"Home":a=i[0];break;case"End":a=i[i.length-1];break;case"Enter":case" ":return void(o>=0&&(t.preventDefault(),this.Ht(i[o],t)));default:return}a&&(t.preventDefault(),this.Ot(a),a.focus(),this.It()&&this.Ht(a,t))};const e="string"==typeof i?document.querySelector(i):i;if(!e)throw new Error(`PanelControl: No element found for selector "${i}"`);if(this.element=e,e.panelControl)return console.warn("PanelControl: already initialized"),e.panelControl;e.panelControl=this;const n=l(e.dataset,t.attrs);this.config={...t.defaults,...s,...n},this.Ft="tablist"===e.getAttribute("role"),this.wt(),this.Ft&&this.qt();const o=this.panelSetElement;this.O(`Initialized (${o?"linked to a PanelSet":"no PanelSet found yet"}${this.Ft?", tablist keyboard nav":""})`)}get panelSetElement(){if(!this.Pt){const t=this.Dt();t&&(this.Pt=t,this.Mt(t))}return this.Pt}get panelSet(){return this.panelSetElement?.panelSet}show(t,i){this.panelSet?.show(t,i)}setTabState(t,i){const s="disabled"===i;this.element.querySelectorAll(`[aria-controls="${t}"]`).forEach(t=>{t.setAttribute("aria-disabled",String(s));const i=t.getAttribute("data-pc-disabled-hint");i&&p(t,i,s),this.Ft&&s&&(t.tabIndex=-1)}),this.Ft&&s&&this.Bt()}O(t){c("PanelControl",this.element,this.config.debug,t)}Dt(){const t=this.element.getAttribute("data-panelcontrol");if(t)return document.querySelector(t);const i=this.element.querySelector("[aria-controls]")?.getAttribute("aria-controls");return i?document.getElementById(i)?.closest("[data-panelset], ps-panelset")??null:null}Mt(t){const{signal:i}=this.t;this.Ft&&!this.kt&&(t.addEventListener("ps:activationcomplete",this.Tt,{signal:i}),this.kt=!0),this.Ct(),t.panelSet||t.addEventListener("ps:ready",this.Ct,{once:!0,signal:i})}wt(){const{signal:t}=this.t;this.element.querySelectorAll("[aria-controls]").forEach(i=>{i.addEventListener("click",t=>{this.Ht(i,t)},{signal:t})})}Ht(t,i){if("true"===t.getAttribute("aria-disabled"))return;const s=t.getAttribute("aria-controls");s&&(this.panelSet?(this.panelSet.show(s,{event:i}),this.Ft&&this.Ot(t)):this.O(`Can’t activate '${s}': its PanelSet is not initialised. Add a PanelSet.init().`))}Lt(){return Array.from(this.element.querySelectorAll('[role="tab"]'))}Ot(t){this.Lt().forEach(i=>{i.tabIndex=i===t?0:-1})}Bt(){const t=this.Lt();if(t.some(t=>0===t.tabIndex&&this.Et(t)))return;const i=t.find(t=>"true"===t.getAttribute("aria-selected")&&this.Et(t))??t.find(this.Et);i&&this.Ot(i)}qt(){const t=this.Lt();if(!t.length)return;const i=t.find(t=>"true"===t.getAttribute("aria-selected"))??t[0];this.Ot(i),this.element.addEventListener("keydown",this.zt,{signal:this.t.signal})}It(){return"auto"===this.config.activation&&!this.Rt()&&!this.panelSet?.hasAsyncContent}Rt(){const t=this.panelSet;if(t&&!1!==t.config.autoFocus)return!0;const i=this.panelSetElement,s=i&&(i.dataset.autoFocus??i.getAttribute("auto-focus"));return null!=s&&"false"!==s||this.Lt().some(t=>{const i=t.getAttribute("data-auto-focus");return null!=i&&"false"!==i})}destroy(){this.t.abort(),delete this.element.panelControl,this.O("Destroyed")}};(w=A).defaults={activation:"manual",debug:!1},w.attrs={activation:["activation","string"],debug:["debug","boolean"]};var _=class extends HTMLElement{connectedCallback(){if(this.panel)return;const t=r(this,x.attrs);new x(this,t)}disconnectedCallback(){}},P=class extends HTMLElement{connectedCallback(){if(this.panelSet)return;const t=r(this,m.attrs);new m(this,t)}disconnectedCallback(){}},F=class extends HTMLElement{connectedCallback(){if(this.panelControl)return;const t=r(this,A.attrs);new A(this,t)}disconnectedCallback(){}};window.PanelSet=m,window.Panel=x,window.PanelControl=A,function(t="ps"){const i=(t,i)=>{customElements.get(t)||customElements.define(t,i)};i(`${t}-panel`,_),i(`${t}-panelset`,P),i(`${t}-panelcontrol`,F)}()}();
|
|
1
|
+
!function(){var t=class{constructor(){this.t=new AbortController}get signal(){return this.t.signal}start(){return this.t.abort(),this.t=new AbortController,this.t.signal}static waitForTransition(t,i){return new Promise(s=>{const e=getComputedStyle(t),n=(parseFloat(e.transitionDuration)||0)+(parseFloat(e.transitionDelay)||0);if(0===n)return s();let o=!1;const a=()=>{o||(o=!0,t.removeEventListener("transitionend",h),s())},h=s=>{s.target===t&&(i&&s.propertyName!==i||a())};t.addEventListener("transitionend",h),setTimeout(a,1e3*(n+.05))})}};function i(t,i,s){if(!i)return;if("input"!==i&&s&&!(s.type.startsWith("key")||s instanceof MouseEvent&&0===s.detail))return;const e=t=>{setTimeout(()=>t.focus(),100)};if(!0===i)t.hasAttribute("tabindex")||t.setAttribute("tabindex","-1"),e(t);else if("heading"===i){const i=t.querySelector("h1, h2, h3, h4, h5, h6");i&&(i.hasAttribute("tabindex")||i.setAttribute("tabindex","-1"),e(i))}else if("first"===i){const i=t.querySelector('a,button,input,select,textarea,[tabindex]:not([tabindex="-1"])');i&&e(i)}else if("input"===i){const i=t.querySelector("input:not([type=hidden]):not([disabled]),select:not([disabled]),textarea:not([disabled])");i&&e(i)}else"function"==typeof i&&setTimeout(()=>i(t),100)}var s=()=>{const t=new URLSearchParams(location.search).get("panel");return t?t.split(",").filter(Boolean):[]},e=t=>{const i=new URL(location.href);if(i.searchParams.delete("panel"),t.length){const s=i.search?"&":"?";history.replaceState(null,"",`${i}${s}panel=${t.join(",")}`)}else history.replaceState(null,"",i)},n=t=>`${location.pathname}::${t}`,o=t=>localStorage.getItem(n(t)),a=(t,i)=>localStorage.setItem(n(t),i);function h(t,i){switch(i){case"string":return t;case"boolean":return"false"!==t;case"number":return parseInt(t,10);case"json":try{return JSON.parse(t)}catch{return"false"!==t}}}function r(t,i){const s={};for(const[e,n]of Object.entries(i)){const[i,o]=n,a=t[i];void 0!==a&&(s[e]=h(a,o))}return s}function l(t,i){const s={};for(const[e,n]of Object.entries(i)){const[i,o]=n,a=i.replace(/([A-Z])/g,"-$1").toLowerCase(),r=t.getAttribute(a);null!==r&&(s[e]=h(r,o))}return s}function c(t,i,s,e){s&&console.log(`[${t}] "${i.id||"no id"}" -`,e)}function p(t,i,s){const e=i.split(/\s+/).filter(Boolean);if(!e.length)return;const n=(t.getAttribute("aria-describedby")||"").split(/\s+/).filter(Boolean);let o=!1;for(const a of e){const t=n.includes(a);s&&!t?(n.push(a),o=!0):!s&&t&&(n.splice(n.indexOf(a),1),o=!0)}o&&(n.length?t.setAttribute("aria-describedby",n.join(" ")):t.removeAttribute("aria-describedby"))}var d,u=!1;function g(t){t&&!u&&(u=!0,console.log("[Panel/PanelSet] Browser supports 'interpolate-size', which will be used for opening and closing."))}function f(t){t.waitUntil=i=>{t.promise=t.promise?Promise.all([t.promise,i]):i}}function b(t,i,s,e,n={}){const o=!0===n.once;t.addEventListener(i,t=>{const i=t,n=s(i.detail),{signal:a}=i.detail;if(o&&"true"===n.dataset.loaded)return;const h=e(n,a);h&&"function"==typeof h.then&&i.detail.waitUntil(h.then(()=>{o&&(n.dataset.loaded="true")}))})}var m=class n{static init(t={},i={}){let s,e;"string"==typeof t?(s=t,e=i):(e=t,s=e.selector||"[data-panelset]");const o=document.querySelectorAll(s),a=[];return o.forEach(t=>{try{n.i(t)}catch(s){return void console.error(s.message)}if(t.panelSet)return void a.push(t.panelSet);const i=new n(t,e);a.push(i)}),a}constructor(i,h={}){let l;if(this.hasAsyncContent=!1,this.o=new t,this.h=new t,this.l=!1,this.p=!1,this.u=null,this.m=null,this.v=null,this.$=new AbortController,this.S=()=>{const t=s();return this.panels.find(i=>i.id&&t.includes(i.id))?.id??null},this.A=t=>{if(this.config.persist&&this.element.id&&a(`ps:${this.element.id}`,t),this.config.deepLink)this._(t);else{const t=new Set(this.panels.map(t=>t.id).filter(Boolean)),i=s();i.some(i=>t.has(i))&&e(i.filter(i=>!t.has(i)))}},this._=t=>{const i=new Set(this.panels.map(t=>t.id).filter(Boolean));e([...s().filter(t=>!i.has(t)),t].filter(Boolean))},this.P=()=>{const t=this.S();if(t)return t;if(this.config.persist){const{id:t}=this.element;if(!t)return null;const i=o(`ps:${t}`);return i&&this.panels.some(t=>t.id===i)?i:null}return null},this.F=t=>{const{atStart:i,atEnd:s}=t.detail;this.k(i,s)},"string"==typeof i){if(l=document.querySelector(i),!l)throw new Error(`PanelSet: No element found for selector "${i}"`)}else l=i;if(this.element=l,n.i(l),l.panelSet)return console.warn("PanelSet: already initialized"),l.panelSet;l.panelSet=this,n.C();const c=r(l.dataset,n.attrs);if(this.config={...n.defaults,...h,...c},this.panels=this.T(),0===this.panels.length)return this.panelWrapper=this.element.querySelector(":scope > .panel-wrapper")||this.L(),this.O("Initialized empty (0 panels) — ready for addPanel()"),this.H("ps:ready",{container:this.element,instance:this}),this.I(),void this.q();const p=this.P();this.activePanel=(p?this.panels.find(t=>t.id===p):null)??this.panels.find(t=>t.classList.contains("active"))??this.panels[0],this.panelWrapper=this.element.querySelector(":scope > .panel-wrapper")||this.L(),this.pendingPanel=this.activePanel,"start"!==this.config.align&&(this.element.dataset.panelsetAlign=this.config.align),this.config.closable&&!this.element.classList.contains("is-open")&&this.element.setAttribute("inert",""),n.D&&g(this.config.debug),this.O(`Initialized (${this.panels.length} panels)`),this.H("ps:ready",{container:this.element,instance:this}),this.M(),this.I(),this.q()}q(){const t=this.element.closest("[data-panelset-trackheight]");if(!t||"undefined"==typeof ResizeObserver)return;let i=t.clientWidth,s=0;this.v=new ResizeObserver(()=>{const e=t.clientWidth;e!==i&&(i=e,cancelAnimationFrame(s),s=requestAnimationFrame(()=>this.B()))}),this.v.observe(t)}O(t){c("PanelSet",this.element,this.config.debug,t)}get R(){return this.config.closable&&!this.element.classList.contains("is-open")&&!this.element.classList.contains("is-opening")}static i(t){if(!t.hasAttribute("data-panelset")&&!t.tagName.includes("-"))throw new Error("PanelSet: element must have [data-panelset] or be a custom element")}L(){const t=document.createElement("div");return t.className="panel-wrapper",this.panels.forEach(i=>t.appendChild(i)),this.element.appendChild(t),t}T(){return Array.from(this.element.querySelectorAll('[role="tabpanel"]')).filter(t=>t.closest("[data-panelset], ps-panelset, [data-panel], ps-panel")===this.element)}M(){this.panels.forEach(t=>{t.classList.remove("fade","incoming","outgoing","levelup","leveldown"),t!==this.activePanel?(t.hidden=!0,t.classList.remove("active")):(t.hidden=!1,t.classList.add("active"))}),this.element.style.height="",this.B(),this.config.manageTriggers&&this.V(this.activePanel),this.config.manageLabels&&this.N()}H(t,i){this.element.dispatchEvent(new CustomEvent(t,{detail:i,bubbles:!0,cancelable:!1}))}j(t){if(!t)return 0;const i=getComputedStyle(t);return(parseFloat(i.paddingTop)||0)+(parseFloat(i.paddingBottom)||0)+(parseFloat(i.borderTopWidth)||0)+(parseFloat(i.borderBottomWidth)||0)}U(t){let i=t.offsetHeight;return i+=this.j(this.panelWrapper),i+=this.j(this.element),i}B(){if(this.element.hasAttribute("data-panelset-trackheight"))return void console.warn("PanelSet: data-panelset-trackheight on parent only");const t=this.element.closest("[data-panelset-trackheight]");if(!t)return;this.panels.forEach(t=>{t.hidden=!0,t.classList.remove("active")});let i=0;this.panels.forEach(t=>{t.hidden=!1,t.classList.add("active"),t.style.visibility="hidden";const s=this.element.offsetHeight;s>i&&(i=s),t.hidden=!0,t.classList.remove("active"),t.style.visibility=""}),this.activePanel&&(this.activePanel.hidden=!1,this.activePanel.classList.add("active")),t.style.setProperty("--ps-max-height",`${i}px`),this.O(`Max container height: ${i}px`)}V(t){this.panels.forEach(i=>{i.id&&document.querySelectorAll(`[aria-controls="${i.id}"]`).forEach(s=>{const e=i===t;"tab"===s.getAttribute("role")&&s.closest('[role="tablist"]')?(s.setAttribute("aria-selected",String(e)),s.removeAttribute("aria-current")):(e?s.setAttribute("aria-current","true"):s.removeAttribute("aria-current"),s.removeAttribute("aria-selected"))})})}N(){this.panels.forEach(t=>{if(!t.id)return;if(t.hasAttribute("aria-labelledby")||t.hasAttribute("aria-label"))return;const i=Array.from(document.querySelectorAll(`[aria-controls="${t.id}"]`));if(0===i.length)return;const s=i.filter(t=>"tab"===t.getAttribute("role")),e=1===s.length?s[0]:1===i.length?i[0]:null;e&&(e.id||(e.id=this.W(`${t.id}-tab`)),t.setAttribute("aria-labelledby",e.id))})}W(t){let i=t,s=2;for(;document.getElementById(i);)i=`${t}-${s++}`;return i}G(t){this.panels.forEach(i=>{i.id&&document.querySelectorAll(`[aria-controls="${i.id}"]`).forEach(i=>{i.classList.toggle("is-activating",t)})})}J(t){this.panels.forEach(i=>{i.classList.remove("fade","incoming","outgoing","levelup","leveldown"),i!==t?(i.classList.remove("active"),i.hidden=!0):(i.classList.add("active"),i.hidden=!1,i.removeAttribute("inert"))}),this.element.style.height="",this.element.classList.remove("is-transitioning"),this.activePanel=t,this.config.manageTriggers&&this.V(t)}K(t,i){if(this.config.manageTriggers){const i=t?.getAttribute("data-auto-focus");if(null!=i){if("true"===i)return!0;if("false"===i)return!1;if("heading"===i||"first"===i||"input"===i)return i}}return void 0!==i?i:this.config.autoFocus}Z(t,s,e){i(t,s,e)}X(i,s,e){const o="is-"+(i?"closing":"opening"),a="is-"+(i?"opening":"closing");this.O(i?"Opening":"Closing");const h=this.h.start(),r=this.element.classList.contains(o)?this.element.offsetHeight:null,l=i?null:this.element.offsetHeight;this.element.classList.remove(o),i||this.element.classList.remove("is-open"),i&&this.element.removeAttribute("inert");const c=()=>{this.element.setAttribute("inert","");const t=e instanceof PointerEvent&&""!==e.pointerType;this.config.returnFocus&&this.m&&!t&&this.m.focus()};if(s&&this.config.transitions)if(this.element.classList.add(a),n.D)i?(this.element.style.height=null!==r?`${r}px`:"0px",requestAnimationFrame(()=>{this.element.style.height="",t.waitForTransition(this.element,"height").then(()=>{h.aborted||(this.panelWrapper?t.waitForTransition(this.panelWrapper):Promise.resolve()).then(()=>{h.aborted||(this.element.classList.remove(a),this.element.classList.add("is-open"),this.element.offsetHeight)})})})):(this.element.style.height=null!==r?`${r}px`:`${l}px`,requestAnimationFrame(()=>{this.element.style.height="",t.waitForTransition(this.element,"height").then(()=>{h.aborted||(this.element.classList.remove(a),this.element.offsetHeight,c())})}));else{const s=i?this.U(this.pendingPanel):0,e=null!==r?r:i?this.element.offsetHeight:l??0;this.element.style.height=`${e}px`,getComputedStyle(this.element).height,requestAnimationFrame(()=>{this.element.style.height=`${s}px`,t.waitForTransition(this.element).then(()=>{h.aborted||(this.element.style.height="",this.element.classList.remove(a),i&&this.element.classList.add("is-open"),this.element.offsetHeight,i||c())})})}else i?this.element.classList.add("is-open"):(this.element.classList.remove("is-open"),c()),this.element.style.height=""}getActive(){return this.pendingPanel?.id||null}refresh(){const t=this.activePanel;this.panels=this.T(),0!==this.panels.length&&(this.activePanel=t&&this.panels.includes(t)?t:this.panels.find(t=>t.classList.contains("active"))??this.panels[0],this.pendingPanel=this.activePanel,this.panelWrapper=this.element.querySelector(":scope > .panel-wrapper")||this.panelWrapper,this.M(),this.Y(),this.O(`Refreshed (${this.panels.length} panels)`))}addPanel(t,i){t.hasAttribute("role")||t.setAttribute("role","tabpanel");let s=null;return i?.before?s=this.panels.find(t=>t.id===i.before)??null:i?.after?s=this.panels.find(t=>t.id===i.after)?.nextElementSibling??null:"number"==typeof i?.index&&(s=this.panels[i.index]??null),(this.panelWrapper||this.L()).insertBefore(t,s),this.refresh(),t}removePanel(t){const i=this.panels.find(i=>i.id===t);i&&(i.remove(),this.refresh())}destroy(){this.o.start(),this.h.start(),this.v?.disconnect(),this.v=null,this.$.abort(),delete this.element.panelSet,this.O("Destroyed")}tt(t){const i=this.panels.length,s=t?this.panels.indexOf(t):-1;return{index:s,total:i,atStart:s<=0,atEnd:s===i-1}}static C(){n.it||(n.it=!0,document.addEventListener("click",n.st))}static et(t,i){const s=t.getAttribute(`data-ps-${i}`);return s?document.querySelector(s):t.closest("[data-panelset], ps-panelset")}I(){const{signal:t}=this.$;this.element.addEventListener("ps:activationstart",this.F,{signal:t}),this.element.addEventListener("ps:activationcomplete",this.F,{signal:t}),this.Y()}Y(){const{atStart:t,atEnd:i}=this.tt(this.pendingPanel);this.k(t,i)}k(t,i){if(this.config.loop)return;const s=this.nt("prev"),e=this.nt("next");if("native"!==this.config.disabledMode)return s.forEach(i=>this.ot(i,t)),void e.forEach(t=>this.ot(t,i));t||s.forEach(t=>this.ot(t,!1)),i||e.forEach(t=>this.ot(t,!1)),t&&this.ht(s,i?[]:e),i&&this.ht(e,t?[]:s)}ot(t,i){"native"===this.config.disabledMode?i?t.setAttribute("disabled",""):t.removeAttribute("disabled"):t.setAttribute("aria-disabled",String(i));const s=t.getAttribute("data-ps-disabled-hint");s&&p(t,s,i)}ht(t,i){t.forEach(t=>{t.hasAttribute("disabled")||document.activeElement!==t||(i.find(t=>!t.hasAttribute("disabled"))??this.rt())?.focus(),this.ot(t,!0)})}rt(){const t=this.pendingPanel??this.activePanel;return t?(t.hasAttribute("tabindex")||t.setAttribute("tabindex","-1"),t):null}nt(t){return Array.from(document.querySelectorAll(`[data-ps-${t}]`)).filter(i=>n.et(i,t)===this.element)}next(t){this.lt(1,t)}prev(t){this.lt(-1,t)}lt(t,i){const s=this.panels.length;if(0===s)return;const e=this.panels.indexOf(this.pendingPanel);let n=(-1===e?0:e)+t,o=!1;if(n<0||n>=s){if(!this.config.loop)return;n=(n+s)%s,o=!0}const a=this.panels[n];a&&a!==this.pendingPanel&&this.show(a.id,o?{...i,direction:t>0?"forward":"backward"}:i)}open(i){const{event:s,transition:e=!0,autoFocus:n}=i||{};if(!this.config.closable)return void this.O("Not closable");const o=this.R,a=this.element.classList.contains("is-closing"),h=this.element.classList.contains("is-loading");if(!o&&!a)return;if(this.element.classList.contains("is-transitioning")&&!h)return;const r=s?.target instanceof HTMLElement?s.target.closest('button, a, [role="tab"]')??s.target:null,l=this.K(r,n);r&&(this.m=r),this.X(!0,e),!1!==l&&void 0!==l&&this.pendingPanel&&(e&&this.config.transitions?t.waitForTransition(this.element).then(()=>{this.Z(this.pendingPanel,l,s)}):this.Z(this.pendingPanel,l,s))}close(t){const{transition:i=!0,event:s}=t||{};if(!this.config.closable)return void this.O("Not closable");const e=this.R,n=this.element.classList.contains("is-closing"),o=this.element.classList.contains("is-opening"),a=this.element.classList.contains("is-loading");(!e&&!n||o)&&(this.element.classList.contains("is-transitioning")&&!a||this.X(!1,i,s))}toggle(t){const{event:i,transition:s=!0,autoFocus:e}=t||{},n=this.R,o=this.element.classList.contains("is-closing");n||o?this.open({event:i,transition:s,autoFocus:e}):this.close({transition:s,event:i})}onBeforeOpen(t,i={}){this.hasAsyncContent=!0,b(this.element,"ps:beforeopen",t=>t.targetPanel,t,i)}async show(i,s){if(!1===this.config.interruptible&&this.p)return;const{event:e,transition:n=!0,autoFocus:o,direction:a}=s||{},h=e?.target instanceof HTMLElement?e.target.closest('button, a, [role="tab"]')??e.target:null,r=this.K(h,o),l=this.panels.find(t=>t.id===i);if(!l)return void this.O(`Panel not found: ${i}`);const c=new CustomEvent("ps:beforeactivate",{detail:{panelId:i,targetPanel:l,outgoingPanel:this.activePanel??null,trigger:h},bubbles:!0,cancelable:!0});if(!this.element.dispatchEvent(c))return void this.O(`Vetoed by ps:beforeactivate: ${i}`);const p=this.R,d=this.element.classList.contains("is-closing"),u=this.element.classList.contains("is-loading");if(l===this.pendingPanel)return void(p||d?this.open({event:e,transition:n,autoFocus:r}):this.config.closable&&this.config.closeOnTab&&this.close({transition:n,event:e}));if((this.element.classList.contains("is-opening")||d)&&!u)return;if(p)return this.pendingPanel=l,this.J(l),void this.open({event:e,transition:n,autoFocus:r});const g=this.p;this.p=!0,this.config.manageTriggers&&!1===this.config.interruptible&&this.G(!0);const b=this.pendingPanel,m=b?.id;this.pendingPanel=l;const v=g&&l===this.activePanel&&b!==l;this.config.manageTriggers&&this.V(l),this.A(i),this.element.classList.remove("is-loading"),!v&&b&&b!==this.activePanel&&b!==l&&(b.classList.remove("incoming","outgoing","levelup","leveldown"),b.hidden||b.classList.remove("active"));const w=this.l,y=this.o.signal.aborted,$=this.o.start();!y&&w&&m&&m!==i&&this.H("ps:activationaborted",{panelId:m,trigger:h}),this.l=!1,this.O(`${b?.id||"none"} > ${i}`);const S={panelId:i,targetPanel:l,outgoingPanel:b,signal:$,promise:null,waitUntil(){}};f(S);const x=new CustomEvent("ps:beforeopen",{detail:S,bubbles:!0,cancelable:!1});this.element.dispatchEvent(x);const A=S.promise;if(A){this.l=!0,this.O("Waiting for content..."),this.element.style.setProperty("--ps-loading-delay",`${this.config.loadingDelay}ms`),this.element.classList.add("is-loading");let s=null;const e=!1!==n&&!1!==this.config.transitions;let o=e;if("object"==typeof this.config.transitions&&(o=e&&!1!==this.config.transitions.height),o)if(p)this.element.classList.add("is-open","is-opening"),this.element.style.height="0px",requestAnimationFrame(()=>{this.element.style.height=`${this.config.loadingHeight}px`}),s=t.waitForTransition(this.element,"height");else{const i=this.element.offsetHeight,e=Math.max(i,this.config.loadingHeight);e>i&&(this.element.style.height=`${i}px`,requestAnimationFrame(()=>{this.element.style.height=`${e}px`}),s=t.waitForTransition(this.element,"height"))}try{if(await Promise.all([A,s].filter(Boolean)),$.aborted)return this.O(`Aborted during load: ${i}`),this.element.classList.remove("is-loading"),void this.element.style.removeProperty("--ps-loading-delay");this.O("Content loaded"),"true"===l.dataset.loaded&&this.B()}catch(T){const t=T;return this.O(`Load failed: ${t.message}`),this.element.classList.remove("is-loading"),this.element.style.removeProperty("--ps-loading-delay"),"AbortError"!==t.name&&console.error("Panel load error:",T),this.p=!1,void(this.config.manageTriggers&&!1===this.config.interruptible&&this.G(!1))}this.element.classList.remove("is-loading"),this.element.style.removeProperty("--ps-loading-delay"),this.element.classList.remove("is-opening")}if($.aborted)return void this.O(`Aborted: ${i}`);const _=v?b:this.activePanel;this.H("ps:activationstart",{panelId:i,trigger:h,outgoingPanel:_,...this.tt(l)});const P=!1!==n&&!1!==this.config.transitions;let F=P,k=P;"object"==typeof this.config.transitions&&(F=P&&!1!==this.config.transitions.panels,k=P&&!1!==this.config.transitions.height),this.panels.forEach(t=>t.classList.toggle("fade",F));let C=null;if(v)C="leveldown"===this.u?"levelup":"leveldown";else if(this.config.levels&&_&&_!==l)if(a)C="forward"===a?"levelup":"leveldown";else{const t=this.panels.indexOf(_),i=this.panels.indexOf(l);-1!==t&&-1!==i&&t!==i&&(C=i>t?"levelup":"leveldown")}this.u=C,this.panels.forEach(t=>t.classList.remove("outgoing","levelup","leveldown"));const E=this.element.offsetHeight;k&&(this.element.style.height=`${E}px`),l.hidden=!1,l.setAttribute("inert",""),l.classList.add("incoming"),C&&l.classList.add(C),F&&this.element.classList.add("is-transitioning"),_&&_!==l&&(_.classList.remove("active","incoming"),_.classList.add("outgoing"),C&&_.classList.add(C),_.hidden=!1,_.setAttribute("inert","")),requestAnimationFrame(()=>requestAnimationFrame(()=>{l.classList.add("active"),_&&_!==l&&_.classList.remove("incoming");const s=this.U(l),n=E!==s;k&&(this.element.style.height=`${s}px`);const o=[];F&&o.push(t.waitForTransition(l)),k&&n&&o.push(t.waitForTransition(this.element)),o.length||o.push(Promise.resolve()),Promise.all(o).then(()=>{$.aborted?this.O(`Interrupted: ${i}`):(this.J(l),this.O(`✓ ${i}`),!1!==r&&void 0!==r&&this.Z(l,r,e),this.p=!1,this.config.manageTriggers&&!1===this.config.interruptible&&this.G(!1),this.H("ps:activationcomplete",{panelId:i,trigger:h,outgoingPanel:_,...this.tt(l)}))})}))}};(d=m).defaults={align:"start",transitions:!0,levels:!1,loop:!1,closable:!1,closeOnTab:!1,disabledMode:"aria",loadingHeight:150,loadingDelay:320,returnFocus:!1,autoFocus:!1,persist:!1,deepLink:!1,interruptible:!0,manageTriggers:!0,manageLabels:!0,debug:!1},d.D="undefined"!=typeof CSS&&CSS.supports("interpolate-size: allow-keywords"),d.it=!1,d.attrs={align:["panelsetAlign","string"],transitions:["transitions","json"],levels:["psLevels","boolean"],loop:["psLoop","boolean"],closable:["closable","boolean"],closeOnTab:["closeOnTab","boolean"],disabledMode:["psDisabledMode","string"],loadingHeight:["loadingHeight","number"],loadingDelay:["loadingDelay","number"],autoFocus:["autoFocus","string"],returnFocus:["returnFocus","boolean"],persist:["panelPersist","boolean"],deepLink:["panelDeeplink","boolean"],interruptible:["interruptible","boolean"],manageTriggers:["manageTriggers","boolean"],manageLabels:["manageLabels","boolean"],debug:["debug","boolean"]},d.st=t=>{const i=t.target;if(!(i instanceof Element))return;const s=i.closest("[data-ps-next], [data-ps-prev], [data-ps-close]");if(!s||"true"===s.getAttribute("aria-disabled"))return;const e=s.hasAttribute("data-ps-next")?"next":s.hasAttribute("data-ps-prev")?"prev":"close",n=d.et(s,e),o=n?.panelSet;o?o[e]({event:t}):n&&c("PanelSet",n,null!=n.dataset.debug&&"false"!==n.dataset.debug,`data-ps-${e}: PanelSet is not initialised. Add a PanelSet.init().`)};var v,w,y=t=>{const i=t.parentElement;return i?.querySelector("[data-panel-body]")?Array.from(i.children).find(t=>t instanceof HTMLElement&&t.hasAttribute("data-panel-body"))??null:null},$=t=>{const i=Array.from(t.querySelectorAll("[data-panel-pin]"));i.length&&i.map(t=>({el:t,pin:t.dataset.panelPin,w:t.offsetWidth})).forEach(({el:t,pin:i,w:s})=>{t.style.boxSizing="border-box",t.style.width=`${s}px`,"end"===i&&(t.style.marginLeft=`calc(100% - ${s}px)`)})},S=t=>{t.querySelectorAll("[data-panel-pin]").forEach(t=>{t.style.boxSizing="",t.style.width="",t.style.marginLeft=""})},x=class n{static init(t="[data-panel]",i={}){let s,e;return"string"==typeof t?(s=t,e=i):(e=t,s="[data-panel]"),Array.from(document.querySelectorAll(s)).filter(t=>!t.panel).filter(t=>!t.dataset.panel||"data-panel"===t.dataset.panel).map(t=>new n(t,e))}constructor(i,h={}){this.m=null,this.ct=null,this.dt=new t,this.ut=new AbortController,this.p=!1,this.S=()=>{const{id:t}=this.element;return!!t&&s().includes(t)},this._=t=>{const{id:i}=this.element;if(!i)return;const n=s();e(t?[...new Set([...n,i])]:n.filter(t=>t!==i))},this.gt=()=>{const t=t=>this.element.hasAttribute(t)?"false"!==this.element.getAttribute(t):void 0,i=t("data-panel-persist"),s=t("data-panel-deeplink");let e,n,o=this.element.parentElement;for(;o&&!o.hasAttribute("data-panel");){if(o.hasAttribute("data-panel-group")){o.hasAttribute("data-panel-persist")&&(e="false"!==o.getAttribute("data-panel-persist")),o.hasAttribute("data-panel-deeplink")&&(n="false"!==o.getAttribute("data-panel-deeplink"));break}o=o.parentElement}return{persist:i??e??this.config.persist,deepLink:s??n??this.config.deepLink}},this.A=t=>{if(!this.element.id)return;const{persist:i,deepLink:s}=this.gt();i&&a(`panel:${this.element.id}`,t?"open":"closed"),s?this._(t):!t&&this.S()&&this._(!1)},this.ft=()=>{const{id:t}=this.element;if(!t)return!1;if(this.S())return!0;const{persist:i}=this.gt();return!(!i||"open"!==o(`panel:${t}`))},this.bt=()=>"horizontal"===this.config.axis?"width":"height";const l="string"==typeof i?document.querySelector(i):i;if(!l)throw new Error(`Panel: No element found for selector "${i}"`);if(this.element=l,l.panel=this,!l.querySelector(":scope > .panel-wrapper")){const t=document.createElement("div");t.className="panel-wrapper",t.append(...Array.from(l.childNodes)),l.appendChild(t)}const c=r(l.dataset,n.attrs);this.config={...n.defaults,...h,...c},"horizontal"===this.config.axis&&(l.dataset.panelAxis="horizontal"),"start"!==this.config.align&&(l.dataset.panelAlign=this.config.align),this.vt(),this.wt(),this.ft()||this.element.classList.contains("is-open")?(this.element.classList.add("is-open"),this.element.removeAttribute("inert"),this.yt(!0),this.element.classList.add("is-restored"),requestAnimationFrame(()=>requestAnimationFrame(()=>this.element.classList.remove("is-restored"))),this.H("panel:opened")):this.element.setAttribute("inert",""),n.D&&g(this.config.debug),this.O("Initialized")}O(t){c("Panel",this.element,this.config.debug,t)}vt(){const t=t=>t.hasAttribute("data-panel")||!!t.panel,i=t=>{this.element.id||(this.element.id="panel-"+ ++n.$t),t.setAttribute("aria-controls",this.element.id),t.hasAttribute("aria-expanded")||t.setAttribute("aria-expanded","false"),t.removeAttribute("data-panel-trigger")},s=t=>t.hasAttribute("data-panel-trigger")?t:/^H[1-6]$/.test(t.tagName)?t.querySelector(":scope > [data-panel-trigger]"):null;for(const e of["previousElementSibling","nextElementSibling"]){let n=this.element[e];for(;n&&!t(n);){const t=s(n);if(t){i(t);break}n=n[e]}}}wt(){const t=this.element.id;if(!t)return;const{signal:i}=this.ut;document.querySelectorAll(`[aria-controls="${t}"]`).forEach(t=>{t.addEventListener("click",i=>{this.m=t,this.toggle(i)},{signal:i})}),this.element.querySelectorAll("[data-panel-close]").forEach(t=>{t.closest("[data-panel]")===this.element&&t.addEventListener("click",()=>this.close(),{signal:i})}),this.config.closeOnResize&&window.addEventListener("resize",()=>{if(!this.isOpen||this.element.classList.contains("is-closing"))return;const t=y(this.element);t&&S(t),this.close()},{signal:i})}yt(t){const i=this.element.id;i&&document.querySelectorAll(`[aria-controls="${i}"]`).forEach(i=>i.setAttribute("aria-expanded",String(t)))}St(){this.ct&&(this.ct.style.removeProperty("--ps-tempclose-speed"),this.ct.style.removeProperty("--ps-tempclose-timing"),this.ct=null)}xt(){const t=this.element.closest("[data-panel-group]"),i=t?.hasAttribute("data-panel-close-siblings")??!1;if(!this.config.closeSiblings&&!i)return;const s=t?function(t){const{groupSelector:i,scopeSelector:s=i,itemSelector:e,filter:n}={groupSelector:"[data-panel-group]",itemSelector:"[data-panel]",filter:t=>!!t.panel?.isOpen},o=(t,i)=>{if(t.closest(s)!==i)return!1;const n=t.parentElement?.closest(e);return!n||!i.contains(n)},a=t.closest(i);return a&&o(t,a)?[...a.querySelectorAll(e)].filter(i=>i!==t&&o(i,a)&&(!n||n(i))):[]}(this.element):Array.from(this.element.parentElement?.children??[]).filter(t=>t instanceof HTMLElement&&t!==this.element&&!!t.panel?.isOpen);s.length&&t&&(t.style.setProperty("--ps-tempclose-speed","var(--ps-open-speed)"),t.style.setProperty("--ps-tempclose-timing","var(--ps-open-timing)"),this.ct=t),s.forEach(t=>{t.panel.m=null,t.panel.close()})}Z(t){this.config.autoFocus&&i(this.element,this.config.autoFocus,t)}H(t){"panel:opened"!==t&&"panel:closed"!==t||(this.p=!1);const i={trigger:this.m};this.element.dispatchEvent(new CustomEvent(t,{detail:i,bubbles:!0}))}get isOpen(){return this.element.classList.contains("is-open")||this.element.classList.contains("is-opening")}async open(t){if(this.isOpen&&!this.element.classList.contains("is-closing"))return;if(!1===this.config.interruptible&&this.p)return;this.p=!0;const i=this.dt.start(),s=this.bt(),e={signal:i,promise:null,waitUntil(){},trigger:this.m};f(e),this.element.dispatchEvent(new CustomEvent("panel:beforeopen",{detail:e,bubbles:!0})),e.promise?await this.At(i,s,e.promise,t):this._t(i,s,t)}async At(i,s,e,o){const a=await Promise.race([e.then(()=>!0),new Promise(t=>{const s=setTimeout(()=>t(!1),this.config.loadingDelay);i.addEventListener("abort",()=>clearTimeout(s))})]).catch(()=>!1);if(i.aborted)return;if(a)return void this._t(i,s,o);this.element.classList.remove("is-closing"),this.element.removeAttribute("inert"),this.element.classList.add("is-loading"),this.element.querySelector(":scope > .panel-wrapper")?.replaceChildren(),this.element.style.setProperty("--ps-loading-delay","0ms"),this.yt(!0),this.A(!0),this.H("panel:opening");const h=y(this.element);let r;h&&$(h),this.config.transitions?(this.element.classList.add("is-opening"),this.element.style[s]="0px",getComputedStyle(this.element)[s],requestAnimationFrame(()=>{this.element.style[s]=`${this.config.loadingHeight}px`}),r=t.waitForTransition(this.element,s)):this.element.style[s]=`${this.config.loadingHeight}px`;try{await Promise.all([e,r].filter(Boolean))}catch{}finally{this.element.classList.remove("is-loading"),this.element.style.removeProperty("--ps-loading-delay")}if(i.aborted)return;const l=this.element.getBoundingClientRect(),c="height"===s?l.height:l.width;if(this.element.style[s]="",this.config.transitions)if(n.D)t.waitForTransition(this.element,s).then(()=>{i.aborted||(this.element.classList.remove("is-opening"),this.element.classList.add("is-open"),this.H("panel:opened"),this.O("Opened"),this.Z(o))});else{this.element.style[s]="auto";const e=this.element.getBoundingClientRect(),n="height"===s?e.height:e.width;this.element.style[s]=`${c}px`,getComputedStyle(this.element)[s],requestAnimationFrame(()=>{this.element.style[s]=`${n}px`,t.waitForTransition(this.element,s).then(()=>{i.aborted||(this.element.style[s]="",this.element.classList.remove("is-opening"),this.element.classList.add("is-open"),this.H("panel:opened"),this.O("Opened"),this.Z(o))})})}else this.element.classList.remove("is-opening"),this.element.classList.add("is-open"),this.H("panel:opened"),this.O("Opened"),this.Z(o)}_t(i,s,e){const o=this.element.classList.contains("is-closing")?this.element.getBoundingClientRect()["height"===s?"height":"width"]:null;this.element.classList.remove("is-closing"),this.element.removeAttribute("inert");const a=y(this.element);if(this.config.transitions)if(n.D)this.element.classList.add("is-opening"),this.element.style[s]=null!==o?`${o}px`:"0px",a&&$(a),getComputedStyle(this.element)[s],this.yt(!0),this.A(!0),this.xt(),this.H("panel:opening"),requestAnimationFrame(()=>{this.element.style[s]="",t.waitForTransition(this.element,s).then(()=>{i.aborted||(this.element.classList.remove("is-opening"),this.element.classList.add("is-open"),this.H("panel:opened"),this.St(),this.O("Opened"),this.Z(e))})});else{this.yt(!0),this.A(!0),this.xt(),this.H("panel:opening"),this.element.style[s]="auto";const n=this.element.getBoundingClientRect(),h="height"===s?n.height:n.width;this.element.style[s]=null!==o?`${o}px`:"0px",this.element.classList.add("is-opening"),a&&$(a),getComputedStyle(this.element)[s],requestAnimationFrame(()=>{this.element.style[s]=`${h}px`,t.waitForTransition(this.element,s).then(()=>{i.aborted||(this.element.style[s]="",this.element.classList.remove("is-opening"),this.element.classList.add("is-open"),this.H("panel:opened"),this.St(),this.O("Opened"),this.Z(e))})})}else this.yt(!0),this.A(!0),this.xt(),this.H("panel:opening"),this.element.classList.add("is-open"),this.H("panel:opened"),this.St(),this.O("Opened"),this.Z(e)}onBeforeOpen(t,i={}){b(this.element,"panel:beforeopen",()=>this.element,t,i)}close(i){if(!this.isOpen)return;if(!1===this.config.interruptible&&this.p)return;this.p=!0,this.element.setAttribute("inert",""),this.yt(!1);const s=this.bt(),e=y(this.element),n=this.dt.start();this.H("panel:closing");const o=()=>{this.element.classList.remove("is-closing","is-open","is-opening"),this.element.style[s]="",e&&S(e),this.A(!1),this.H("panel:closed"),this.O("Closed");const t=i instanceof PointerEvent&&""!==i.pointerType;this.config.returnFocus&&this.m&&!t&&this.m.focus()};if(!this.config.transitions)return void o();const a=this.element.getBoundingClientRect(),h="height"===s?a.height:a.width;this.element.style[s]=`${h}px`,this.element.classList.remove("is-opening","is-open"),this.element.classList.add("is-closing"),getComputedStyle(this.element)[s],requestAnimationFrame(()=>{this.element.style[s]="0px",t.waitForTransition(this.element,s).then(()=>{n.aborted||o()})})}toggle(t){this.element.classList.contains("is-closing")?this.open(t):this.isOpen?this.close(t):(t?.target&&(this.m=t.target.closest("button, a")??t.target),this.open(t))}destroy(){this.dt.start(),this.ut.abort(),this.element.classList.remove("is-opening","is-closing","is-loading","is-open"),this.element.style[this.bt()]="",this.element.setAttribute("inert",""),this.yt(!1);const t=y(this.element);t&&S(t),delete this.element.panel,this.O("Destroyed")}};(v=x).defaults={axis:"vertical",align:"start",closeOnResize:!1,transitions:!0,autoFocus:!1,returnFocus:!0,closeSiblings:!1,loadingDelay:320,loadingHeight:150,interruptible:!0,persist:!1,deepLink:!1,debug:!1},v.attrs={axis:["panelAxis","string"],align:["panelAlign","string"],autoFocus:["panelAutoFocus","string"],closeOnResize:["panelCloseOnResize","boolean"],transitions:["panelTransitions","boolean"],returnFocus:["panelReturnFocus","boolean"],closeSiblings:["panelCloseSiblings","boolean"],loadingDelay:["panelLoadingDelay","number"],loadingHeight:["panelLoadingHeight","number"],interruptible:["panelInterruptible","boolean"],persist:["panelPersist","boolean"],deepLink:["panelDeeplink","boolean"],debug:["debug","boolean"]},v.D="undefined"!=typeof CSS&&CSS.supports("interpolate-size: allow-keywords"),v.$t=0;var A=class t{static init(i="[data-panelcontrol]",s={}){let e,n;return"string"==typeof i?(e=i,n=s):(n=i,e=n.selector||"[data-panelcontrol]"),Array.from(document.querySelectorAll(e)).filter(t=>!t.panelControl).map(i=>new t(i,n))}constructor(i,s={}){this.Pt=null,this.t=new AbortController,this.Ft=!1,this.kt=!1,this.Ct=()=>{const t=this.panelSet,i=this.panelSetElement;let s=!1;if(t)s=!(!t.config.closable||!t.config.closeOnTab);else if(i){const t=null!=i.dataset.closable||i.hasAttribute("closable"),e=null!=i.dataset.closeOnTab||i.hasAttribute("close-on-tab");s=t&&e}this.element.toggleAttribute("data-closeable",s)},this.Et=t=>"true"!==t.getAttribute("aria-disabled")&&!t.hidden,this.Tt=t=>{const i=this.Lt().find(i=>i.getAttribute("aria-controls")===t.detail?.panelId);i&&this.Ot(i)},this.zt=t=>{const i=this.Lt().filter(this.Et);if(!i.length)return;const s="vertical"===this.element.getAttribute("aria-orientation"),e=s?"ArrowDown":"ArrowRight",n=s?"ArrowUp":"ArrowLeft",o=i.indexOf(document.activeElement);let a;switch(t.key){case e:a=i[(o+1)%i.length];break;case n:a=i[(o-1+i.length)%i.length];break;case"Home":a=i[0];break;case"End":a=i[i.length-1];break;case"Enter":case" ":return void(o>=0&&(t.preventDefault(),this.Ht(i[o],t)));default:return}a&&(t.preventDefault(),this.Ot(a),a.focus(),this.It()&&this.Ht(a,t))};const e="string"==typeof i?document.querySelector(i):i;if(!e)throw new Error(`PanelControl: No element found for selector "${i}"`);if(this.element=e,e.panelControl)return console.warn("PanelControl: already initialized"),e.panelControl;e.panelControl=this;const n=r(e.dataset,t.attrs);this.config={...t.defaults,...s,...n},this.Ft="tablist"===e.getAttribute("role"),this.wt(),this.Ft&&this.qt();const o=this.panelSetElement;this.O(`Initialized (${o?"linked to a PanelSet":"no PanelSet found yet"}${this.Ft?", tablist keyboard nav":""})`)}get panelSetElement(){if(!this.Pt){const t=this.Dt();t&&(this.Pt=t,this.Mt(t))}return this.Pt}get panelSet(){return this.panelSetElement?.panelSet}show(t,i){this.panelSet?.show(t,i)}setTabState(t,i){const s="disabled"===i;this.element.querySelectorAll(`[aria-controls="${t}"]`).forEach(t=>{t.setAttribute("aria-disabled",String(s));const i=t.getAttribute("data-pc-disabled-hint");i&&p(t,i,s),this.Ft&&s&&(t.tabIndex=-1)}),this.Ft&&s&&this.Bt()}O(t){c("PanelControl",this.element,this.config.debug,t)}Dt(){const t=this.element.getAttribute("data-panelcontrol");if(t)return document.querySelector(t);const i=this.element.querySelector("[aria-controls]")?.getAttribute("aria-controls");return i?document.getElementById(i)?.closest("[data-panelset], ps-panelset")??null:null}Mt(t){const{signal:i}=this.t;this.Ft&&!this.kt&&(t.addEventListener("ps:activationcomplete",this.Tt,{signal:i}),this.kt=!0),this.Ct(),t.panelSet||t.addEventListener("ps:ready",this.Ct,{once:!0,signal:i})}wt(){const{signal:t}=this.t;this.element.querySelectorAll("[aria-controls]").forEach(i=>{i.addEventListener("click",t=>{this.Ht(i,t)},{signal:t})})}Ht(t,i){if("true"===t.getAttribute("aria-disabled"))return;const s=t.getAttribute("aria-controls");s&&(this.panelSet?(this.panelSet.show(s,{event:i}),this.Ft&&this.Ot(t)):this.O(`Can’t activate '${s}': its PanelSet is not initialised. Add a PanelSet.init().`))}Lt(){return Array.from(this.element.querySelectorAll('[role="tab"]'))}Ot(t){this.Lt().forEach(i=>{i.tabIndex=i===t?0:-1})}Bt(){const t=this.Lt();if(t.some(t=>0===t.tabIndex&&this.Et(t)))return;const i=t.find(t=>"true"===t.getAttribute("aria-selected")&&this.Et(t))??t.find(this.Et);i&&this.Ot(i)}qt(){const t=this.Lt();if(!t.length)return;const i=t.find(t=>"true"===t.getAttribute("aria-selected"))??t[0];this.Ot(i),this.element.addEventListener("keydown",this.zt,{signal:this.t.signal})}It(){return"auto"===this.config.activation&&!this.Rt()&&!this.panelSet?.hasAsyncContent}Rt(){const t=this.panelSet;if(t&&!1!==t.config.autoFocus)return!0;const i=this.panelSetElement,s=i&&(i.dataset.autoFocus??i.getAttribute("auto-focus"));return null!=s&&"false"!==s||this.Lt().some(t=>{const i=t.getAttribute("data-auto-focus");return null!=i&&"false"!==i})}destroy(){this.t.abort(),delete this.element.panelControl,this.O("Destroyed")}};(w=A).defaults={activation:"manual",debug:!1},w.attrs={activation:["activation","string"],debug:["debug","boolean"]};var _=class extends HTMLElement{connectedCallback(){if(this.panel)return;const t=l(this,x.attrs);new x(this,t)}disconnectedCallback(){}},P=class extends HTMLElement{connectedCallback(){if(this.panelSet)return;const t=l(this,m.attrs);new m(this,t)}disconnectedCallback(){}},F=class extends HTMLElement{connectedCallback(){if(this.panelControl)return;const t=l(this,A.attrs);new A(this,t)}disconnectedCallback(){}};window.PanelSet=m,window.Panel=x,window.PanelControl=A,function(t="ps"){const i=(t,i)=>{customElements.get(t)||customElements.define(t,i)};i(`${t}-panel`,_),i(`${t}-panelset`,P),i(`${t}-panelcontrol`,F)}()}();
|