staffa 0.10.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -3
- package/dist/components/main.d.ts +21 -7
- package/dist/components/main.js +22 -13
- package/dist/components/menu.d.ts +12 -5
- package/dist/components/menu.js +38 -8
- package/dist/components/panels.d.ts +8 -4
- package/dist/components/panels.js +21 -7
- package/dist/staffa.esm.js +1 -1
- package/package.json +1 -1
- package/skill/MainOptions.md +23 -7
- package/skill/MenuItem.md +12 -5
- package/skill/SKILL.md +4 -3
- package/src/components/main.ts +41 -18
- package/src/components/menu.ts +50 -13
- package/src/components/panels.ts +24 -9
package/README.md
CHANGED
|
@@ -210,7 +210,7 @@ function drawTask($panel: S.Panel<{ taskId: number }>) {
|
|
|
210
210
|
|
|
211
211
|
On a wide screen the title becomes the stack's last crumb and the Save button sits in a quiet strip at the top of the column. On a phone the crumb is still there and Save moves into the top bar, where the app menu was. Nothing in your code measures the viewport, and no screen is written twice.
|
|
212
212
|
|
|
213
|
-
**The breadcrumbs are the navigation.** The top bar's second line writes the open panels out as breadcrumbs — `Projects / Trackle / Task 42` — with the panels currently on screen in bold. Clicking an earlier crumb goes back to it *without closing anything*: the panels right of it stay open, parked just past the viewport's right edge, and clicking their crumbs brings them back. Browsing the stack is free — it's opening a *new* panel that closes the panels after the one it came from. The app's name and logo link to the app's home (the `home` option, `/` by default), going back to it when it's already open and opening it when it isn't. A stack too long for the bar scrolls sideways, in an `S.scrollStrip` like the tab strip's.
|
|
213
|
+
**The breadcrumbs are the navigation.** The top bar's second line writes the open panels out as breadcrumbs — `Projects / Trackle / Task 42` — with the panels currently on screen in bold. Clicking an earlier crumb goes back to it *without closing anything*: the panels right of it stay open, parked just past the viewport's right edge, and clicking their crumbs brings them back. Browsing the stack is free — it's opening a *new* panel that closes the panels after the one it came from. The app's name and logo link to the app's home (the `home` option, `/` by default; `null` links neither), going back to it when it's already open and opening it when it isn't. A stack too long for the bar scrolls sideways, in an `S.scrollStrip` like the tab strip's.
|
|
214
214
|
|
|
215
215
|
That line is the `subtitle`'s while the stack has nothing to add: one panel open, reachable from a nav item that is already highlighted in a visible sidebar. Otherwise the stack takes it, since it is then the only thing naming the screen.
|
|
216
216
|
|
|
@@ -221,7 +221,7 @@ A crumb can also wear a **●**: the panel holds unsaved work, and nothing will
|
|
|
221
221
|
| `$panel` | what it does |
|
|
222
222
|
| --- | --- |
|
|
223
223
|
| `title` | Names the screen: its breadcrumb, and `document.title` while it's the current panel. A panel that sets none borrows the first line of text in its own body — good enough for a crumb, but say it yourself. |
|
|
224
|
-
| `actions` | The screen's buttons or menu. In the column's chrome while several columns fit; in the top bar (taking the app `menu`'s place) once the shell is narrow. |
|
|
224
|
+
| `actions` | The screen's buttons or menu. In the column's chrome while several columns fit; in the top bar (taking the app `menu`'s place) once the shell is narrow. A link among them builds on this panel at both widths. |
|
|
225
225
|
|
|
226
226
|
Two deliberate rules there. `actions` are the screen's *verbs* — Save, Delete, Share, a menu — not a second way out: going back is the crumbs' job, at every width, and there is no back button even on a phone. And **`title` names the screen; it does not draw a heading** — a screen that wants its name in its own body writes it there, where it owns the typography.
|
|
227
227
|
|
|
@@ -291,7 +291,8 @@ Search params and the `#hash` belong to the current panel only. Anything another
|
|
|
291
291
|
|
|
292
292
|
**A few more things.**
|
|
293
293
|
|
|
294
|
-
- `
|
|
294
|
+
- `columns: "single"` shows only the current panel, however wide the screen — the phone experience at every size. Only the display changes: the URL, the back button, unsaved panels and the panels' own close buttons all behave the same.
|
|
295
|
+
- `linkNavigation` sets what a link *without* a `data-panel` attribute does: `"push"` (the default), `"replace"`, or `"open"`. With `"open"` every click replaces the content as a whole — which, with flat routes, is the conventional sidebar-and-content app: one pane, swapped on every click, the crumb line simply naming it.
|
|
295
296
|
- Only one routed `S.main()` can be mounted at a time; a second one throws — the URL is global, so two of them would fight over it. Nothing else is global: the stack belongs to its shell, and each handler gets its own `$panel`, since several panels are alive at once.
|
|
296
297
|
- Navigating with `aberdeen/route`'s own `go()` works — an unsaved panel survives it too — but, like a link from outside a panel, it builds the whole stack from the path. So prefer the stack's own methods. A navigation guard your app registered with `route.setGuard` (an auth redirect, say) keeps working untouched: Staffa registers none of its own.
|
|
297
298
|
- Deep links need your static server to serve the app for unknown paths (the usual SPA fallback). For `http-server` that's `-P`, as in the demo command below.
|
|
@@ -41,9 +41,11 @@ export interface MainOptions<R = Routes> {
|
|
|
41
41
|
* when your home screen lives elsewhere. It's an ordinary link, so the
|
|
42
42
|
* usual rules apply: a home that is already open in the stack — its first
|
|
43
43
|
* panel, usually — is returned to, closing nothing, and one that isn't is
|
|
44
|
-
* opened the way a nav item would be.
|
|
44
|
+
* opened the way a nav item would be. Pass `null` to link neither — for a
|
|
45
|
+
* `title` or `logo` slot holding interactive content of its own, which
|
|
46
|
+
* can't sit inside a link. Routed mode only.
|
|
45
47
|
*/
|
|
46
|
-
home?: string;
|
|
48
|
+
home?: string | null;
|
|
47
49
|
/**
|
|
48
50
|
* The app's own chrome, at the trailing end of the top bar: an account
|
|
49
51
|
* button, a global search box, a settings menu. It may grow into the bar's
|
|
@@ -175,12 +177,24 @@ export interface MainOptions<R = Routes> {
|
|
|
175
177
|
*/
|
|
176
178
|
ancestors?: AncestorTable<NoInfer<R>>;
|
|
177
179
|
/**
|
|
178
|
-
*
|
|
179
|
-
*
|
|
180
|
-
*
|
|
181
|
-
*
|
|
180
|
+
* How many panels are *shown* at a time. `"auto"` (the default) shows as
|
|
181
|
+
* many columns, side by side, as comfortably fit, ending at the current
|
|
182
|
+
* panel; `"single"` shows only the current panel, however wide the screen
|
|
183
|
+
* — the phone experience at every size (the nav sidebar still sits beside
|
|
184
|
+
* it). Only the display differs: the stack, the breadcrumbs, the URL,
|
|
185
|
+
* Escape and the back button behave identically in both. Routed mode only.
|
|
182
186
|
*/
|
|
183
|
-
|
|
187
|
+
columns?: "auto" | "single";
|
|
188
|
+
/**
|
|
189
|
+
* What a link *without* a `data-panel` attribute does — the per-link
|
|
190
|
+
* attribute always wins. `"push"` (the default) opens the target on top of
|
|
191
|
+
* the panel the link sits in; `"replace"` opens it in that panel's place;
|
|
192
|
+
* `"open"` gives it its own stack, the way a nav item does. With `"open"`
|
|
193
|
+
* every click replaces the content as a whole — which, with flat routes,
|
|
194
|
+
* is the conventional sidebar-and-content app: one pane, swapped on every
|
|
195
|
+
* click, the crumb line simply naming it. Routed mode only.
|
|
196
|
+
*/
|
|
197
|
+
linkNavigation?: "push" | "replace" | "open";
|
|
184
198
|
/** Footer content, pinned below the scroll area. */
|
|
185
199
|
footer?: Slot;
|
|
186
200
|
/**
|
package/dist/components/main.js
CHANGED
|
@@ -25,9 +25,11 @@ A.insertGlobalCss({
|
|
|
25
25
|
"> footer": "border-top: 1px solid $s-faint; fg:$s-muted",
|
|
26
26
|
// The bar reads `[leading] [title] …spacer… [trailing]`. The spacer is the
|
|
27
27
|
// trailing slot's own growth: it takes the free space and right-aligns
|
|
28
|
-
// itself in it, which is what lets a search box live there.
|
|
29
|
-
//
|
|
30
|
-
//
|
|
28
|
+
// itself in it, which is what lets a search box live there. When the two
|
|
29
|
+
// compete, the title truncates first — but only down to a floor, past
|
|
30
|
+
// which the trailing slot shrinks instead: a wide search box must not
|
|
31
|
+
// starve the titles to nothing (the crumb strip's overlay buttons would
|
|
32
|
+
// escape their zero-width strip, over the ☰ beside it).
|
|
31
33
|
"> header > .s-bar, > footer > .s-bar": "display:flex align-items:center width:100% margin-inline:auto gap:$3 padding: $2 $3;",
|
|
32
34
|
"> header .s-logo, > header .s-nav-trigger": "display:flex align-items:center flex-shrink:0",
|
|
33
35
|
// The ☰ is a glyph in a 2rem hit area, so it carries ~6px of its own
|
|
@@ -35,7 +37,7 @@ A.insertGlobalCss({
|
|
|
35
37
|
// up with the bar's edge and with the stack below.
|
|
36
38
|
"> header .s-nav-trigger": "margin-left:-0.375rem",
|
|
37
39
|
"> header .s-logo": "font-size:1.4em background: $s-gradient; -webkit-background-clip:text; background-clip:text; color:transparent;",
|
|
38
|
-
"> header .s-titles": "display:flex flex-direction:column min-width:
|
|
40
|
+
"> header .s-titles": "display:flex flex-direction:column min-width:5rem flex: 0 1 auto;",
|
|
39
41
|
// Same font-size and line-height as `.s-crumb`, because in routed mode the
|
|
40
42
|
// two take turns on this line (see `drawSecondLine`): a different height
|
|
41
43
|
// would jog the whole bar as they swap.
|
|
@@ -46,7 +48,7 @@ A.insertGlobalCss({
|
|
|
46
48
|
// which their classes then provide. (`filter:none` keeps the global
|
|
47
49
|
// `a:hover` brighten off the gradient text.)
|
|
48
50
|
"> header a.s-logo, > header a.s-title": "text-decoration:none filter:none cursor:pointer",
|
|
49
|
-
"> header .s-menu": "display:flex align-items:center justify-content:flex-end gap:$2 flex: 1
|
|
51
|
+
"> header .s-menu": "display:flex align-items:center justify-content:flex-end gap:$2 flex: 1 1 auto; min-width:0",
|
|
50
52
|
// Body always wraps <main> (with or without a sidebar) so max-width centering
|
|
51
53
|
// and scrollbar alignment work identically in both cases.
|
|
52
54
|
// .s-body centres .s-body-inner; .s-body-inner caps the content to maxWidth.
|
|
@@ -182,11 +184,15 @@ export function main(opts = {}) {
|
|
|
182
184
|
routes,
|
|
183
185
|
notFound: opts.notFound,
|
|
184
186
|
ancestors: opts.ancestors,
|
|
185
|
-
|
|
187
|
+
columns: opts.columns,
|
|
188
|
+
linkNavigation: opts.linkNavigation,
|
|
186
189
|
title: opts.title,
|
|
187
190
|
$shell,
|
|
188
191
|
})
|
|
189
192
|
: null;
|
|
193
|
+
// Where the brand mark and the app's name link — or nowhere, when the app
|
|
194
|
+
// said `home: null` (a title slot holding a control of its own, say).
|
|
195
|
+
const homeHref = ctl && opts.home !== null ? opts.home ?? "/" : null;
|
|
190
196
|
// Routed mode caps the shell to the ensemble width the layout engine publishes,
|
|
191
197
|
// rather than to `maxWidth`.
|
|
192
198
|
const capWidth = ctl ? null : opts.maxWidth;
|
|
@@ -242,9 +248,9 @@ export function main(opts = {}) {
|
|
|
242
248
|
// twinned with the app's name beside it — a real link, so it
|
|
243
249
|
// has an address to hover, middle-click and copy, and a click
|
|
244
250
|
// runs the shell's usual link rules.
|
|
245
|
-
A(
|
|
246
|
-
if (
|
|
247
|
-
A("href=",
|
|
251
|
+
A(homeHref != null ? "a.s-logo aria-label=Home" : "div.s-logo", () => {
|
|
252
|
+
if (homeHref != null)
|
|
253
|
+
A("href=", homeHref);
|
|
248
254
|
drawSlot(opts.logo);
|
|
249
255
|
});
|
|
250
256
|
});
|
|
@@ -257,9 +263,9 @@ export function main(opts = {}) {
|
|
|
257
263
|
A(() => {
|
|
258
264
|
if (opts.title == null)
|
|
259
265
|
return;
|
|
260
|
-
A(
|
|
261
|
-
if (
|
|
262
|
-
A("href=",
|
|
266
|
+
A(homeHref != null ? "a.s-title" : "div.s-title", () => {
|
|
267
|
+
if (homeHref != null)
|
|
268
|
+
A("href=", homeHref);
|
|
263
269
|
drawSlot(opts.title);
|
|
264
270
|
});
|
|
265
271
|
});
|
|
@@ -267,11 +273,14 @@ export function main(opts = {}) {
|
|
|
267
273
|
});
|
|
268
274
|
// Trailing: on a narrow shell the screen's own verbs win the space,
|
|
269
275
|
// and a screen with none of its own leaves the app's chrome up.
|
|
276
|
+
// Promoted actions are marked as the current panel's own chrome
|
|
277
|
+
// (`.s-panel-origin`), so a link among them still builds on that
|
|
278
|
+
// panel — see `interceptLinks` in panels.ts.
|
|
270
279
|
A(() => {
|
|
271
280
|
const actions = $shell.narrow ? ctl?.currentPanel?.actions : undefined;
|
|
272
281
|
const slot = actions ?? opts.menu;
|
|
273
282
|
if (slot != null)
|
|
274
|
-
A(
|
|
283
|
+
A(`div.s-menu${actions != null ? ".s-panel-origin" : ""}`, () => drawSlot(slot));
|
|
275
284
|
});
|
|
276
285
|
});
|
|
277
286
|
});
|
|
@@ -19,6 +19,11 @@ export interface MenuItem {
|
|
|
19
19
|
* Render as a link (`<a>`) pointing here. Pairs naturally with
|
|
20
20
|
* `interceptLinks()` — the item is highlighted automatically when the URL
|
|
21
21
|
* matches, and scrolled into view if its list had scrolled it out.
|
|
22
|
+
*
|
|
23
|
+
* Under routed `S.main()` the link carries `data-panel=open`: a menu row
|
|
24
|
+
* leads elsewhere in the app, so its target arrives with its own stack of
|
|
25
|
+
* columns rather than on top of whatever panel the menu was drawn in. Pass
|
|
26
|
+
* `attrs: "data-panel=push"` for a row that should stack instead.
|
|
22
27
|
*/
|
|
23
28
|
href?: string;
|
|
24
29
|
/** `target` for the link (`_blank`, etc.). Only meaningful with `href`. */
|
|
@@ -29,11 +34,13 @@ export interface MenuItem {
|
|
|
29
34
|
attrs?: Attributes;
|
|
30
35
|
/**
|
|
31
36
|
* Child entries, which turn the item into a collapsible **branch** of a
|
|
32
|
-
* tree. Only the branch holding the current page is expanded; navigate
|
|
33
|
-
* and it folds back up.
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
* it
|
|
37
|
+
* tree. Only the branch holding the current page is expanded; navigate to
|
|
38
|
+
* another page in the menu and it folds back up. (Navigating to a page the
|
|
39
|
+
* menu doesn't hold *anywhere* leaves every fold as it was: there is no
|
|
40
|
+
* better answer to fold up to.) Clicking a branch *selects* rather than
|
|
41
|
+
* toggles: it follows the item's own `href`, or failing that the first
|
|
42
|
+
* linked leaf below it — which is what expands it. A branch with no link
|
|
43
|
+
* anywhere below it falls back to plain open/close toggling.
|
|
37
44
|
*
|
|
38
45
|
* Expanding is not selecting: a branch click never counts as picking an
|
|
39
46
|
* item (see `onLeafSelect` on {@link menu}), so on a phone the nav stays up
|
package/dist/components/menu.js
CHANGED
|
@@ -114,9 +114,15 @@ export function drawMenu(items, onLeafSelect) {
|
|
|
114
114
|
(cur + dir + els.length) % els.length;
|
|
115
115
|
els[next].focus();
|
|
116
116
|
});
|
|
117
|
-
|
|
117
|
+
// Whether the current page is in this menu *at all*, shared by every branch
|
|
118
|
+
// below: a navigation to a page the menu doesn't hold must leave the folds
|
|
119
|
+
// alone (see `drawBranch`), and that is a fact about the whole menu, which
|
|
120
|
+
// no branch can tell on its own. Derived, so the branches re-run only when
|
|
121
|
+
// the answer flips — not on every navigation between two held pages.
|
|
122
|
+
const $menuHasCurrent = A.derive(() => anyCurrent(items));
|
|
123
|
+
drawEntries(items, onLeafSelect, $menuHasCurrent);
|
|
118
124
|
}
|
|
119
|
-
function drawEntries(items, onLeafSelect) {
|
|
125
|
+
function drawEntries(items, onLeafSelect, $menuHasCurrent) {
|
|
120
126
|
for (const entry of items) {
|
|
121
127
|
if (typeof entry === "string" || typeof entry === "function") {
|
|
122
128
|
drawSlot(entry);
|
|
@@ -127,7 +133,7 @@ function drawEntries(items, onLeafSelect) {
|
|
|
127
133
|
continue;
|
|
128
134
|
}
|
|
129
135
|
if (entry.items)
|
|
130
|
-
drawBranch(entry, onLeafSelect);
|
|
136
|
+
drawBranch(entry, onLeafSelect, $menuHasCurrent);
|
|
131
137
|
else
|
|
132
138
|
drawLeaf(entry, onLeafSelect);
|
|
133
139
|
}
|
|
@@ -136,7 +142,15 @@ function drawLeaf(entry, onLeafSelect) {
|
|
|
136
142
|
// Whether the aria-current scope below has run before: it re-runs on
|
|
137
143
|
// every navigation, and only a *later* one should animate the reveal.
|
|
138
144
|
let drawn = false;
|
|
139
|
-
|
|
145
|
+
// `data-panel=open` because a menu row is navigation, not a link in the
|
|
146
|
+
// content: it leads somewhere else in the app, and the panel it was clicked
|
|
147
|
+
// from isn't the context to keep. A floating dropdown (portalled to the
|
|
148
|
+
// body) and `S.main()`'s sidebar are outside every panel and behave this way
|
|
149
|
+
// already; saying it outright makes an inline `menu()` — which may well sit
|
|
150
|
+
// *inside* a panel — behave the same wherever it's drawn. `attrs` comes
|
|
151
|
+
// after, so an item that really does want to stack can say
|
|
152
|
+
// `attrs: "data-panel=push"`.
|
|
153
|
+
const itemEl = A(entry.href ? "a.s-menu-item data-panel=open" : "button.s-menu-item type=button", entry.attrs, () => {
|
|
140
154
|
if (entry.href) {
|
|
141
155
|
A("href=", entry.href);
|
|
142
156
|
if (entry.target)
|
|
@@ -185,12 +199,24 @@ function drawLeaf(entry, onLeafSelect) {
|
|
|
185
199
|
* linked branch is open exactly while it holds the current page. Only a branch
|
|
186
200
|
* with no link anywhere below it keeps the native open/close toggle.
|
|
187
201
|
*/
|
|
188
|
-
function drawBranch(entry, onLeafSelect) {
|
|
202
|
+
function drawBranch(entry, onLeafSelect, $menuHasCurrent) {
|
|
189
203
|
const href = entry.href ?? firstLeafHref(entry.items);
|
|
190
204
|
// The route-derived fold state, as a derived boolean so the attribute scope
|
|
191
205
|
// below re-runs only when the answer flips — not on every navigation that
|
|
192
|
-
// merely moves *between* pages inside the branch.
|
|
193
|
-
|
|
206
|
+
// merely moves *between* pages inside the branch. When the current page is
|
|
207
|
+
// nowhere in the menu, nothing has an opinion, and the fold simply keeps
|
|
208
|
+
// its last state — folding everything up would answer a question nobody
|
|
209
|
+
// asked with a menu that forgot where the user was.
|
|
210
|
+
let last = false;
|
|
211
|
+
const $open = href != null
|
|
212
|
+
? A.derive(() => {
|
|
213
|
+
if (containsCurrent(entry))
|
|
214
|
+
return (last = true);
|
|
215
|
+
if ($menuHasCurrent == null || $menuHasCurrent.value)
|
|
216
|
+
return (last = false);
|
|
217
|
+
return last;
|
|
218
|
+
})
|
|
219
|
+
: null;
|
|
194
220
|
A("details.s-menu-details", () => {
|
|
195
221
|
// For a no-link branch this scope has no subscriptions and never re-runs,
|
|
196
222
|
// which is exactly what leaves the native toggle alone.
|
|
@@ -225,7 +251,7 @@ function drawBranch(entry, onLeafSelect) {
|
|
|
225
251
|
drawSlot(entry.label);
|
|
226
252
|
A("span.s-menu-chevron aria-hidden=true", () => chevronRight());
|
|
227
253
|
});
|
|
228
|
-
A("div.s-menu-sub", () => drawEntries(entry.items, onLeafSelect));
|
|
254
|
+
A("div.s-menu-sub", () => drawEntries(entry.items, onLeafSelect, $menuHasCurrent));
|
|
229
255
|
});
|
|
230
256
|
}
|
|
231
257
|
/**
|
|
@@ -240,6 +266,10 @@ function foldedAway(el) {
|
|
|
240
266
|
}
|
|
241
267
|
return false;
|
|
242
268
|
}
|
|
269
|
+
/** Whether any page linked anywhere in `items` is the current one. */
|
|
270
|
+
function anyCurrent(items) {
|
|
271
|
+
return items.some((entry) => typeof entry !== "string" && typeof entry !== "function" && !("separator" in entry) && containsCurrent(entry));
|
|
272
|
+
}
|
|
243
273
|
/** Whether `entry`'s own page, or any page linked below it, is the current one. */
|
|
244
274
|
function containsCurrent(entry) {
|
|
245
275
|
if (entry.href != null && matchCurrent(entry.href))
|
|
@@ -250,8 +250,10 @@ export interface PanelStackOptions {
|
|
|
250
250
|
notFound?: RouteHandler<{}>;
|
|
251
251
|
/** What to open beneath a path that arrives cold. See {@link MainOptions.ancestors}. */
|
|
252
252
|
ancestors?: Record<string, AncestorsHandler | undefined>;
|
|
253
|
-
/**
|
|
254
|
-
|
|
253
|
+
/** How many panels are shown at a time. See {@link MainOptions.columns}. */
|
|
254
|
+
columns?: "auto" | "single";
|
|
255
|
+
/** What a bare link does. See {@link MainOptions.linkNavigation}. */
|
|
256
|
+
linkNavigation?: "push" | "replace" | "open";
|
|
255
257
|
/** The shell's own title, used as the suffix of `document.title`. */
|
|
256
258
|
title?: unknown;
|
|
257
259
|
/**
|
|
@@ -601,9 +603,11 @@ export declare class PanelStackController implements PanelStack {
|
|
|
601
603
|
* close guards run in `checkChange` when our navigation reaches the router.
|
|
602
604
|
*
|
|
603
605
|
* `data-panel` names which of the three {@link PanelStack} navigations the
|
|
604
|
-
* click is: `push
|
|
606
|
+
* click is: `push`, `replace`, or `open`, which drops the
|
|
605
607
|
* originating panel so the target arrives with its own stack beneath it,
|
|
606
|
-
* exactly as a nav item's link does.
|
|
608
|
+
* exactly as a nav item's link does. A link that doesn't say gets the
|
|
609
|
+
* shell's {@link PanelStackOptions.linkNavigation} (`push` by default);
|
|
610
|
+
* an unrecognised value is a `push`.
|
|
607
611
|
*/
|
|
608
612
|
private interceptLinks;
|
|
609
613
|
get currentPanel(): Panel | undefined;
|
|
@@ -946,16 +946,30 @@ export class PanelStackController {
|
|
|
946
946
|
* close guards run in `checkChange` when our navigation reaches the router.
|
|
947
947
|
*
|
|
948
948
|
* `data-panel` names which of the three {@link PanelStack} navigations the
|
|
949
|
-
* click is: `push
|
|
949
|
+
* click is: `push`, `replace`, or `open`, which drops the
|
|
950
950
|
* originating panel so the target arrives with its own stack beneath it,
|
|
951
|
-
* exactly as a nav item's link does.
|
|
951
|
+
* exactly as a nav item's link does. A link that doesn't say gets the
|
|
952
|
+
* shell's {@link PanelStackOptions.linkNavigation} (`push` by default);
|
|
953
|
+
* an unrecognised value is a `push`.
|
|
952
954
|
*/
|
|
953
955
|
interceptLinks() {
|
|
954
956
|
route.interceptLinks((url, anchor) => {
|
|
955
|
-
const mode = anchor.getAttribute("data-panel");
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
957
|
+
const mode = anchor.getAttribute("data-panel") ?? this.opts.linkNavigation;
|
|
958
|
+
let origin = null;
|
|
959
|
+
if (mode !== "open") {
|
|
960
|
+
const panel = anchor.closest(".s-panel");
|
|
961
|
+
if (panel) {
|
|
962
|
+
origin = this.$state.live.find((entry) => entry.el === panel)?.path ?? null;
|
|
963
|
+
}
|
|
964
|
+
else if (anchor.closest(".s-panel-origin")) {
|
|
965
|
+
// The current panel's actions, promoted into the top bar on a
|
|
966
|
+
// narrow shell (see main.ts), sit outside every `.s-panel` — but
|
|
967
|
+
// they are still the current panel's own chrome, so a link among
|
|
968
|
+
// them builds on that panel, exactly as it does at full width.
|
|
969
|
+
origin = this.$state.live[this.$state.focus]?.path ?? null;
|
|
970
|
+
}
|
|
971
|
+
}
|
|
972
|
+
void this.navigate(url.href, origin, mode === "replace");
|
|
959
973
|
return true;
|
|
960
974
|
});
|
|
961
975
|
}
|
|
@@ -1375,7 +1389,7 @@ export class PanelStackController {
|
|
|
1375
1389
|
const geom = this.geometry();
|
|
1376
1390
|
if (!geom)
|
|
1377
1391
|
return;
|
|
1378
|
-
const stacking = this.opts.
|
|
1392
|
+
const stacking = this.opts.columns !== "single";
|
|
1379
1393
|
// A window resize (or the very first pass) must be adopted instantly —
|
|
1380
1394
|
// geometry tracking the window through a 450ms transition reads as lag,
|
|
1381
1395
|
// and a shell animating itself into place on load reads as a glitch.
|
package/dist/staffa.esm.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import E from"aberdeen";var Y="background: linear-gradient(170deg, color-mix(in oklab, $s-bg, white 9%), color-mix(in oklab, $s-bg, black 9%));",v1="staffa:darkMode",P1=E.proxy({value:a2()});function a2(){try{let t=localStorage.getItem(v1);if(t==="dark")return!0;if(t==="light")return!1}catch{}}function h2(t){P1.value=t;try{t===void 0?localStorage.removeItem(v1):localStorage.setItem(v1,t?"dark":"light")}catch{}}function O1(t=!1){let a=P1.value;return a===void 0&&!t?E.darkMode():a}E(()=>{O1()?E.insertGlobalCss({":root, .s-s.neutral":"--s-bg:#0e0f12 --s-text:#e9eaec",".s-s.neutral":"--s-bg:#191b1f --s-text:#e9eaec",".s-s.neutral .s-s.neutral":"--s-bg:#23262b"}):E.insertGlobalCss({":root, .s-s.neutral":"--s-bg:#eef0f3 --s-text:#1d1f24",".s-s.neutral, .s-s.neutral":"--s-bg:#ffffff --s-text:#1d1f24",".s-s.neutral .s-s.neutral":"--s-bg:#f6f7f9"})});E.setSpacingCssVars(1.1);E.insertGlobalCss({"*, *::before, *::after":"box-sizing:border-box",html:"text-size-adjust:100%",body:"m:0 p:$3 line-height:1.5 font-family: system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif; -webkit-font-smoothing:antialiased background-color:$s-bg text:$s-text",a:"color: $s-link-fg; text-decoration:underline text-underline-offset:2px; transition: color 0.12s, filter 0.12s;","a:hover":"filter: brightness(1.15)","input, button, textarea, select, optgroup":"font:inherit color:inherit","input:where(:not([type=checkbox],[type=radio],[type=range],[type=file],[type=color],[type=image],[type=submit],[type=button],[type=reset],[type=hidden])), textarea, select":"background:$s-bg border: 1px solid $s-faint; r:$s-radius-sm padding: 0.45em 0.65em; max-width:100%","input:where([type=checkbox],[type=radio])":"width:1.15em height:1.15em cursor:pointer","input[type=range]":"appearance:none background:transparent cursor:pointer vertical-align:middle","input[type=range]::-webkit-slider-runnable-track":"height:4px r:99px background:$s-faint","input[type=range]::-moz-range-track":"height:4px r:99px background:$s-faint","input[type=range]::-moz-range-progress":"height:4px r:99px background:$s-accent","input[type=range]::-webkit-slider-thumb":"appearance:none width:16px height:16px margin-top:-6px r:50% background:$s-accent","input[type=range]::-moz-range-thumb":"width:16px height:16px border:0 r:50% background:$s-accent","input[type=file]":"cursor:pointer",progress:"appearance:none border:0 height:6px r:99px background:$s-faint overflow:hidden vertical-align:middle","progress::-webkit-progress-bar":"background:$s-faint r:99px","progress::-webkit-progress-value":"background:$s-accent r:99px","progress::-moz-progress-bar":"background:$s-accent r:99px",meter:"vertical-align:middle",fieldset:"border: 1px solid $s-faint; r:$s-radius-sm padding:$2 min-width:0",legend:"padding: 0 $1; font-weight:600","code, kbd, samp, pre":"font-family: ui-monospace, 'SF Mono', Menlo, Consolas, monospace;",code:"background: color-mix(in oklab, $s-text, $s-bg 86%); padding: 0.12em 0.34em; r:4px font-size:0.9em",pre:"background: color-mix(in oklab, $s-text, $s-bg 92%); p:$3 r: $s-radius; overflow:auto","pre code":"background:transparent p:0","img, svg, video, canvas":"max-width:100% h:auto",hr:"border:0 border-top: 1px solid $s-faint;","::placeholder":"color: $s-muted; opacity:1",":focus-visible":"outline: 2px solid $s-focus; outline-offset:2px",small:"color:$s-muted font-size:0.9em","@media (prefers-reduced-motion: reduce)":{"*, *::before, *::after":"transition-duration: 0.01ms !important; animation-duration: 0.01ms !important; scroll-behavior: auto !important;"},":root":"--s-primary:#00a884 --s-danger:#dc5b41 --s-success:#00a884 --s-warning:#ef6b00 --s-link:#3f8cd8 --s-radius-sm:6px --s-radius:12px --s-radius-lg:18px --s-focus: color-mix(in srgb, $s-primary 38%, transparent); --s-gradient: linear-gradient(135deg, color-mix(in oklab, $s-primary, white 16%), color-mix(in oklab, $s-primary, black 14%));",":root, .s-s.neutral":"--s-accent:$s-primary --s-link-fg:$s-link",".s-s:not(.neutral)":"--s-bg:$s-primary border:0 --s-text:#eee --s-accent:#fff --s-link-fg:#eef --s-muted: color-mix(in srgb, #fff 70%, transparent); --s-faint: color-mix(in srgb, #fff 30%, transparent);",".s-s.danger":"--s-bg:$s-danger",".s-s.success":"--s-bg:$s-success",".s-s.warning":"--s-bg:$s-warning",".s-s.link":"--s-bg:$s-link",".s-s.primary":"--s-bg:$s-primary",":root, .s-s":"--s-muted: color-mix(in oklab, $s-text, $s-bg 42%); --s-faint: color-mix(in oklab, $s-text, $s-bg 80%); color:$s-text accent-color:$s-accent scrollbar-width:thin scrollbar-color: $s-faint transparent;",".s-s, body":Y,".s-s":"r:$s-radius",":where(.s-s.neutral)":"border: 1px solid $s-faint;",".s-s::-webkit-scrollbar, .s-s ::-webkit-scrollbar":"width:10px height:10px",".s-s::-webkit-scrollbar-track, .s-s ::-webkit-scrollbar-track":"background:transparent",".s-s::-webkit-scrollbar-thumb, .s-s ::-webkit-scrollbar-thumb":"background:$s-faint border-radius:99px border: 2px solid transparent; background-clip:padding-box",".s-s.shadow.neutral:not(.s-btn)":"box-shadow: 0 4px 14px rgba(0,0,0,0.13);",".s-s.extra-shadow.neutral:not(.s-btn)":"box-shadow: 0 18px 50px rgba(0,0,0,0.28);",".s-s.shadow:not(.neutral):not(.tonal):not(.outlined)":"box-shadow: 0 4px 14px color-mix(in srgb, $s-bg 30%, transparent);",".s-s.extra-shadow:not(.neutral):not(.tonal):not(.outlined)":"box-shadow: 0 14px 40px color-mix(in srgb, $s-bg 40%, transparent);",".s-s.no-shadow":"box-shadow: none !important;",".s-s:not(.neutral).tonal, .s-s:not(.neutral).outlined":"--s-text:$s-bg --s-accent:$s-bg --s-link-fg:$s-bg --s-faint: color-mix(in srgb, $s-bg 30%, transparent); --s-muted: color-mix(in srgb, $s-bg 70%, transparent);",".s-s:not(.neutral).tonal":"background: color-mix(in srgb, $s-bg 15%, transparent); border: 1px solid $s-faint;",".s-s:not(.neutral).outlined":"background: transparent; border: 1px solid color-mix(in srgb, $s-bg 45%, transparent);",".s-s:not(.neutral) .s-s.tonal, .s-s:not(.neutral) .s-s.outlined":"--s-text:#fff --s-accent:#fff --s-link-fg:#fff "+Y+" border-color: transparent;"});E.insertGlobalCss({".s-preload, .s-preload *, .s-preload *::before, .s-preload *::after":"transition: none !important; animation: none !important;"});if(typeof document<"u"&&typeof requestAnimationFrame=="function"){let t=document.documentElement;t.classList.add("s-preload"),requestAnimationFrame(()=>requestAnimationFrame(()=>t.classList.remove("s-preload")))}E.insertGlobalCss({":disabled, [aria-disabled=true]":"opacity:0.45 filter:saturate(0.6) user-select:none",":disabled, [aria-disabled=true], :disabled *, [aria-disabled=true] *":"pointer-events:none cursor:not-allowed"});var e2="p, ul, ol, dl, blockquote, pre, table, figure, hr, h1, h2, h3, h4, h5, h6";E.insertGlobalCss({[`${e2}`]:{"&":"margin:0","&:not(:first-child)":"margin-top:$3"},"h1, h2, h3, h4, h5, h6":{"&":"line-height:1.15 font-weight:700 text-wrap:balance","&:not(:first-child)":"margin-top:1.4em"},h1:"font-size:2em font-weight:800 letter-spacing:-0.022em",h2:"font-size:1.55em letter-spacing:-0.018em",h3:"font-size:1.3em letter-spacing:-0.011em",h4:"font-size:1.1em",h5:"font-size:0.95em letter-spacing:0.005em",h6:"font-size:0.8em fg:$s-muted text-transform:uppercase letter-spacing:0.07em","ul, ol":{"&":"padding-left:1.5em","> li:not(:first-child), li > &:not(:first-child)":"margin-top:$1"},blockquote:"border-left: 3px solid $s-faint; padding-left: $3; fg: $s-muted",table:"border-collapse:collapse","th, td":"text-align:left padding: $1 $2; border-bottom: 1px solid $s-faint; vertical-align:top",th:"font-weight:600","thead th":"border-bottom: 2px solid $s-faint;",dt:"font-weight:600",dd:"margin-left: 1.5em",figcaption:"fg:$s-muted font-size:0.9em margin-top:$1 text-align:center"});import s from"aberdeen";import E1 from"aberdeen";var r1=640,p2=0;function B(t="s"){return`${t}-${++p2}`}function x(t,...a){t!=null&&(typeof t=="function"?t(...a):E1("rich=",t))}var r2="a[href], button, input, select, textarea, [tabindex]";function j(t,a){let h=p=>p instanceof HTMLElement&&!p.hasAttribute("disabled")&&p.getAttribute("aria-disabled")!=="true"&&p.tabIndex>=0&&p.getClientRects().length>0,e=(a?[...t.querySelectorAll(a)].find(h):void 0)??[...t.querySelectorAll(r2)].find(h);return e?.focus(),e!=null}function F(t){queueMicrotask(()=>E1(t))}import L from"aberdeen";L.insertGlobalCss({".s-field":{"&":"display:flex flex-direction:column gap:$1","> label":"font-weight:600 font-size:0.9em fg:$s-text user-select:none"},".s-req":"fg:$s-danger margin-left:2px",".s-help":"font-size:0.82em fg:$s-muted",".s-error":"font-size:0.82em fg:$s-danger",".s-input":{"&":"w:100% background: color-mix(in oklab, $s-bg, $s-text 4%); color:$s-text border: 1px solid $s-faint; r:$s-radius padding: 0.55em 0.7em; transition: border-color 0.15s, box-shadow 0.15s;","&:hover:not(:disabled)":"border-color: color-mix(in oklab, $s-text, $s-bg 55%);","&:focus-visible":"border-color:$s-accent box-shadow: 0 0 0 3px $s-focus; outline:none","&[aria-invalid=true]":"border-color:$s-danger"}});function I(t,a){let h=t.id??B("field"),e=()=>!!t.error;L("div.s-field",t.attrs,()=>{L(()=>{t.label!=null&&L("label for=",h,()=>{x(t.label),t.required&&L("span.s-req aria-hidden=true #*")})}),a(h,e),L(()=>{t.help!=null&&!t.error&&L("div.s-help",()=>x(t.help))}),L(()=>{t.error&&L("div.s-error role=alert #",t.error)})})}function _(t,a,h,e){L("id=",a),t.name&&L("name=",t.name),L(()=>{t.disabled&&L("disabled=true")}),L(()=>{t.required&&L("aria-required=true")}),L(()=>L("aria-invalid=",h()?"true":"false")),e&&L("bind=",e)}s.insertGlobalCss({".s-ac":{"&":"position:relative","> .s-control":"display:flex flex-wrap:wrap align-items:center gap:$1 background: color-mix(in oklab, $s-bg, $s-text 4%); color:$s-text border: 1px solid $s-faint; r:$s-radius padding: 0.3em 0.4em; cursor:text; transition: border-color 0.15s, box-shadow 0.15s;","> .s-control:hover":"border-color: color-mix(in oklab, $s-text, $s-bg 55%);","> .s-control:focus-within":"border-color:$s-accent box-shadow: 0 0 0 3px $s-focus;","&[aria-invalid=true] > .s-control":"border-color:$s-danger",".s-chip":"display:inline-flex align-items:center gap:$1 font-size:0.85em background: color-mix(in oklab, $s-bg, $s-text 10%); border: 1px solid $s-faint; r:$s-radius padding: 0.1em 0.2em 0.1em 0.5em;",".s-chip > button":"cursor:pointer border:0 background:transparent fg:$s-muted font-size:1.1em line-height:1 padding: 0 0.2em; r:4px",".s-chip > button:hover":"fg:$s-text background:$s-faint",input:"flex:1 min-width:6ch border:0 background:transparent color:inherit outline:none padding:0.25em","> .s-menu":"position:absolute top:100% left:0 right:0 z-index:20 margin-top:4px max-height:15rem overflow-y:auto list-style:none p:$1 margin-bottom:0","> .s-menu li":"margin:0",".s-option":"padding: 0.45em 0.6em; r:6px cursor:pointer transition: background 0.1s;",".s-option[aria-selected=true]":"background: color-mix(in srgb, $s-text 10%, transparent);",".s-add":"fg:$s-accent font-style:italic",".s-empty":"padding: 0.45em 0.6em; fg:$s-muted"}});function d2(t){return typeof t=="string"?{value:t,label:t}:{value:t.value,label:t.label??t.value}}function o2(t){let a=B("ac-menu"),h=s.proxy({query:"",open:!1,active:0}),e=()=>(typeof t.options=="function"?t.options():t.options).map(d2),p=()=>{let l=t.bind?.value;return l==null||l===""?[]:Array.isArray(l)?l:[l]},r=l=>e().find(u=>u.value===l)?.label??l;if(!t.multi){let l=t.bind?s.peek(t.bind,"value"):void 0;typeof l=="string"&&l&&(h.query=s.peek(()=>r(l)))}let d=()=>{let l=new Set(p()),u=e();t.multi&&(u=u.filter(H=>!l.has(H.value)));let f=h.query.trim().toLowerCase();return f&&(u=u.filter(H=>H.label.toLowerCase().includes(f))),u},o=(l,u)=>{if(t.multi){let f=Array.isArray(t.bind?.value)?[...t.bind.value]:[];f.includes(l)||f.push(l),t.bind&&(t.bind.value=f),h.query=""}else t.bind&&(t.bind.value=l),h.query=r(l),h.open=!1;h.active=0,u?.focus()},c=l=>{if(!t.bind)return;let u=t.bind.value??[];t.bind.value=u.filter(f=>f!==l)};I(t,(l,u)=>{s("div.s-ac",t.inputAttrs,()=>{s(()=>s("aria-invalid=",u()?"true":"false"));let f;s("div.s-control",()=>{s("click=",()=>f?.focus()),s(()=>{if(t.multi)for(let H of p())s("span.s-chip",()=>{s("span #",s.peek(()=>r(H))),s("button type=button aria-label=",`Remove ${H}`,()=>{s("#\xD7"),s("click=",n=>{n.stopPropagation(),c(H),f?.focus()})})})}),f=s("input type=text role=combobox autocomplete=off",()=>{s("id=",l,`aria-controls=${a} aria-autocomplete=list`),t.placeholder!=null&&s("placeholder=",t.placeholder),t.disabled&&s("disabled=true"),t.required&&s("aria-required=true"),s("bind=",s.ref(h,"query")),s(()=>s("aria-expanded=",h.open?"true":"false")),s(()=>{let n=d()[h.active];s("aria-activedescendant=",h.open&&n?`${a}-opt-${h.active}`:"")}),s("input=",()=>{h.open=!0,h.active=0}),s("focus=",()=>{h.open=!0}),s("blur=",()=>{setTimeout(()=>m(),150)}),s("keydown=",H=>M(H,f))})}),s(()=>{if(!h.open)return;let H=d(),n=h.query.trim(),g=t.allowCustom!==!1&&n!==""&&!H.some(C=>C.label.toLowerCase()===n.toLowerCase());s("ul.s-menu.s-s.neutral.shadow role=listbox",`id=${a}`,()=>{H.forEach((C,S)=>{s("li.s-option role=option",`id=${a}-opt-${S}`,()=>{s(()=>s("aria-selected=",h.active===S?"true":"false")),s("#",C.label),s("mousedown=",t2=>t2.preventDefault()),s("click=",()=>o(C.value,f)),s("mousemove=",()=>{h.active=S})})}),g&&s("li.s-option.s-add role=option",()=>{s("#",`Add "${n}"`),s("mousedown=",C=>C.preventDefault()),s("click=",()=>o(n,f))}),H.length===0&&!g&&s("li.s-empty #No matches")})}),s(()=>{if(t.name)if(t.multi)for(let H of p())s("input type=hidden",()=>{s("name=",t.name),s("value=",H)});else s("input type=hidden",()=>{s("name=",t.name),s("value=",p()[0]??"")})})})});function M(l,u){let f=d(),H=f.length-1;if(l.key==="ArrowDown")l.preventDefault(),h.open=!0,h.active=Math.min(H,h.active+1);else if(l.key==="ArrowUp")l.preventDefault(),h.active=Math.max(0,h.active-1);else if(l.key==="Enter"){l.preventDefault();let n=f[h.active];n?o(n.value,u):t.allowCustom!==!1&&h.query.trim()?o(h.query.trim(),u):h.open&&(h.open=!1)}else if(l.key==="Escape")h.open&&(l.preventDefault(),h.open=!1,t.multi||(h.query=r(p()[0]??"")));else if(l.key==="Backspace"&&t.multi&&h.query===""){let n=p();n.length&&c(n[n.length-1])}}function m(){h.open=!1,t.multi?h.query="":t.allowCustom!==!1&&h.query.trim()?o(h.query.trim()):h.query=r(p()[0]??"")}}import W from"aberdeen";import c2 from"aberdeen";var t1={size:24,color:"currentColor",strokeWidth:2,cap:"round",join:"round"};function n2(t,a){let h=a.size??t1.size,e=c2('svg.s-icon aria-hidden=true viewBox="0 0 24 24" fill=none',"width=",h,"height=",h,"stroke=",a.color??t1.color,"stroke-width=",a.strokeWidth??t1.strokeWidth,"stroke-linecap=",a.cap??t1.cap,"stroke-linejoin=",a.join??t1.join,a.attrs);e.innerHTML=t}function z(t){return(a={})=>n2(t,a)}var q1=z('<path d="m9 18 6-6-6-6" />');var T1=z('<circle cx="12" cy="12" r="10" />');var D1=z('<path d="M15 3h6v6" /><path d="M10 14 21 3" /><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" />');var R1=z('<path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" /><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" />');var d1=z('<path d="M4 5h16" /><path d="M4 12h16" /><path d="M4 19h16" />');var Z1=z('<path d="M12 17v5" /><path d="M15 9.34V7a1 1 0 0 1 1-1 2 2 0 0 0 0-4H7.89" /><path d="m2 2 20 20" /><path d="M9 9v1.76a2 2 0 0 1-1.11 1.79l-1.78.9A2 2 0 0 0 5 15.24V16a1 1 0 0 0 1 1h11" />'),m1=z('<path d="M12 17v5" /><path d="M9 10.76a2 2 0 0 1-1.11 1.79l-1.78.9A2 2 0 0 0 5 15.24V16a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-.76a2 2 0 0 0-1.11-1.79l-1.78-.9A2 2 0 0 1 15 10.76V7a1 1 0 0 1 1-1 2 2 0 0 0 0-4H8a2 2 0 0 0 0 4 1 1 0 0 1 1 1z" />');var B1=z('<path d="M22 2 2 22" />');var Q=z('<path d="M18 6 6 18" /><path d="m6 6 12 12" />');import P from"aberdeen";P.insertGlobalCss({".s-btn":{"&":"display:inline-flex align-items:center justify-content:center gap:$2 font-weight:450 line-height:1.1 white-space:nowrap cursor:pointer text-decoration:none padding: $m2 $m3; transition: background 0.15s, border-color 0.15s, color 0.15s, filter 0.15s, box-shadow 0.15s, transform 0.08s;","&:focus-visible":"outline: 3px solid $s-focus; outline-offset: 1px;","&:hover":"filter: brightness(1.06)","&.tonal:hover, &.outlined:hover":"background: color-mix(in srgb, $s-bg 24%, transparent);","&.neutral:hover":"filter:none background: color-mix(in srgb, $s-text 8%, $s-bg);","> svg":"width:1.25em height:1.25em","&:active:not(:disabled)":"transform: translateY(1px)","&.small, .small > &":"padding: $m1 $m2; font-size:0.85em border-radius:$s-radius-sm","&.large, .large > &":"font-size:1.4em border-radius:$s-radius-lg"},".s-icon-btn":{"&":"display:inline-flex align-items:center justify-content:center flex-shrink:0 width:2rem height:2rem p:0 border:0 background:transparent cursor:pointer fg:$s-muted r:$s-radius-sm line-height:1 font-size:1rem text-decoration:none transition: color 0.12s, background 0.12s;","> svg":"width:1.25em height:1.25em","&:hover:not(:disabled):not([aria-disabled=true])":"fg:$s-text background: color-mix(in srgb, $s-text 10%, transparent);","&:focus-visible":"outline: 3px solid $s-focus; outline-offset:1px","&.small, .small > &":"width:1.6rem height:1.6rem font-size:0.8rem","&.large, .large > &":"width:2.4rem height:2.4rem font-size:1.2rem"}});function a1(t){let a=t.href!=null?"a":"button";P(`${a}.s-icon-btn`,t.attrs,()=>{F1(t),P("aria-label=",t.ariaLabel),x(t.icon)})}function F1(t){t.href!=null?(P("role=button"),t.disabled?P("aria-disabled=true"):P("href=",t.href)):(P("type=",t.type??"button"),t.disabled&&P("disabled=true")),t.click&&!t.disabled&&P("click=",t.click)}function O(t={}){let a=typeof t=="string"||typeof t=="function"?{content:t}:t,h=a.href!=null?"a":"button";P(`${h}.s-btn.s-s.shadow`,a.attrs,()=>{F1(a),a.ariaLabel&&P("aria-label=",a.ariaLabel),x(a.icon),x(a.content)})}W.insertGlobalCss({".s-box":{"&":"display:flex flex-direction:column overflow:hidden r: $s-radius-lg; position:relative","&:not(:first-child)":"margin-top: $3","> header":"display:flex align-items:center gap:$2 padding: $2 $3; border:0 border-bottom: 1px solid $s-faint; r:0 font-weight:600","> footer":"display:flex align-items:center justify-content:flex-end gap:$2 padding: $2 $3; border:0 border-top: 1px solid $s-faint; r:0","> div":"p:$3 gap:$3","> header > .s-box-close":"margin-left:auto","> .s-box-close":"position:absolute top:$2 right:$2 z-index:1"}});function i2(t={}){let a=typeof t=="string"||typeof t=="function"?{content:t}:t;W("section.s-box.s-s.neutral.shadow",a.attrs,()=>{W(()=>{a.header!=null?W("header.s-s.neutral",a.headerAttrs,()=>{x(a.header),typeof a.close=="function"&&I1(a.close)}):typeof a.close=="function"&&I1(a.close)}),W("div",a.contentAttrs,()=>{x(a.content)}),W(()=>{a.footer!=null&&W("footer.s-s.neutral",a.footerAttrs,()=>x(a.footer))})})}function I1(t){a1({icon:Q,ariaLabel:"Close",click:t,attrs:".s-box-close"})}import u1 from"aberdeen";import U1 from"aberdeen";U1.insertGlobalCss({".s-bgroup":{"&":"display:inline-flex align-items:stretch","&.s-spaced":"gap:$2 flex-wrap:wrap","&.s-vertical":"flex-direction:column","&.s-attached":"gap:0","&.s-attached:not(.s-vertical) > .s-btn:not(:first-child)":"margin-left:-1px","&.s-attached:not(.s-vertical) > .s-btn:not(:first-child):not(:last-child)":"r:0","&.s-attached:not(.s-vertical) > .s-btn:first-child:not(:last-child)":"border-top-right-radius:0 border-bottom-right-radius:0","&.s-attached:not(.s-vertical) > .s-btn:last-child:not(:first-child)":"border-top-left-radius:0 border-bottom-left-radius:0","&.s-attached.s-vertical > .s-btn:not(:first-child)":"margin-top:-1px","&.s-attached.s-vertical > .s-btn:not(:first-child):not(:last-child)":"r:0","&.s-attached.s-vertical > .s-btn:first-child:not(:last-child)":"border-bottom-left-radius:0 border-bottom-right-radius:0","&.s-attached.s-vertical > .s-btn:last-child:not(:first-child)":"border-top-left-radius:0 border-top-right-radius:0","&.s-attached > .s-btn:hover, &.s-attached > .s-btn:focus-visible":"z-index:1"}});function X(t={}){let h=`.s-${t.layout??"attached"}${t.vertical?".s-vertical":""}`;U1(`div.s-bgroup${h} role=group`,t.attrs,()=>{if(t.buttons)for(let e of t.buttons)O(e);x(t.content)})}function s2(t){u1(()=>{let a=t.bind.value;X({attrs:t.attrs,buttons:Object.entries(t.options).map(([h,e])=>({content:e,ariaLabel:typeof e=="function"?h:void 0,attrs:a===h?".primary":".neutral",click:()=>{t.bind.value=t.allowDeselect&&a===h?void 0:h}}))})}),t.name&&u1(()=>u1("input type=hidden name=",t.name,"value=",t.bind.value??""))}import k from"aberdeen";k.insertGlobalCss({".s-check":{"&":"display:flex flex-direction:column gap:$1","> label":"display:flex align-items:center gap:$2 cursor:pointer user-select:none","> label:has(input:disabled)":"cursor:not-allowed opacity:0.45 filter:saturate(0.6)",input:"cursor:inherit m:0"}});function l2(t={}){let a=t.id??B("check");k("div.s-check",t.attrs,()=>{k("label for=",a,()=>{k("input type=checkbox",t.inputAttrs,()=>{k("id=",a),t.name&&k("name=",t.name),t.checked&&!t.bind&&k("checked=true"),t.change&&k("change=",t.change),k(()=>{t.disabled&&k("disabled=true")}),k(()=>{t.required&&k("aria-required=true")}),t.bind&&k("bind=",t.bind)}),k(()=>{t.label!=null&&x(t.label),t.required&&k("span.s-req aria-hidden=true #*")})}),k(()=>{t.help!=null&&!t.error&&k("div.s-help",()=>x(t.help))}),k(()=>{t.error&&k("div.s-error role=alert #",t.error)})})}import G from"aberdeen";G.insertGlobalCss({".s-form":{"&":"display:flex flex-direction:column gap:$3","&.grid":"display:grid grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr)); gap:$3","&.grid > .s-wide, &.grid > footer":"grid-column: 1 / -1;","> footer":"display:flex align-items:center justify-content:flex-end gap:$2 flex-wrap:wrap margin-top:$1"}});function M2(t={}){let a=typeof t=="string"||typeof t=="function"?{content:t}:t;G("form.s-form",a.attrs,()=>{G(()=>{G(".grid=",a.layout==="grid")}),G("submit=",h=>{if(h.preventDefault(),a.submit){let e=new FormData(h.target),p={};for(let r of new Set(e.keys())){let d=e.getAll(r);p[r]=d.length===1?d[0]:d}a.submit(p,h)}}),x(a.content),G(()=>{a.actions&&G("footer",a.actionsAttrs,()=>x(a.actions))})})}import v from"aberdeen";import{current as $1,matchCurrent as U2}from"aberdeen/route";import y from"aberdeen";import{matchCurrent as f1,current as y1,go as x2}from"aberdeen/route";y.insertGlobalCss({".s-menu-list":"position:fixed z-index:350 min-width:10rem display:flex flex-direction:column p:$1 r:$s-radius-lg overflow-y:auto max-height:min(80vh,28rem) transition: opacity 0.15s, transform 0.15s;",".s-menu-list.hidden":"opacity:0 pointer-events:none transform:translateY(-6px)",".s-menu-item":"display:flex align-items:center gap:$2 w:100% outline:0 scroll-margin:$2 padding: $m2 0; line-height:1.1 r:$s-radius cursor:pointer text-align:left font-weight:450 font-size:0.9em border:0 background:transparent fg:$s-text text-decoration:none transition: color 0.12s, transform 0.12s, text-shadow 0.12s;",".s-menu-item:focus-visible:not([aria-current=page]), .s-menu-item:hover:not([aria-disabled=true]):not([aria-current=page])":"filter:none color: color-mix(in lab, $s-primary 33%, $s-text);",".s-menu-item[aria-current=page]":"color:$s-accent filter:none",".s-menu-list .s-menu-item":"padding-inline:$2",".s-menu-item[aria-disabled=true]":"opacity:0.45 cursor:not-allowed pointer-events:none",".s-menu-icon":"flex-shrink:0",".s-menu-list .s-menu-icon":"display:flex",".s-menu-list .s-menu-icon > svg":"width:1.25em height:1.25em","hr.s-menu-sep":"border:0 height:1px margin: $1 0.6rem; background: linear-gradient(to right, transparent, $s-faint 18%, $s-faint 82%, transparent);",".s-menu-chevron":"margin-left:auto flex-shrink:0 display:flex transition: transform 0.15s ease;",".s-menu-chevron > svg":"width:1em height:1em",".s-menu-details":{"> summary":"list-style:none","> summary::-webkit-details-marker":"display:none","&::details-content":"interpolate-size:allow-keywords block-size:0 overflow-y:clip transition: block-size 0.15s ease, content-visibility 0.15s allow-discrete;","&[open]::details-content":"block-size:auto","&[open] > summary .s-menu-chevron":"transform:rotate(90deg)"},".s-menu-sub":"display:flex flex-direction:column gap:$1 padding-left:$3",".s-menu-inline":"display:flex flex-direction:column gap:$1"});function h1(t,a){y("keydown=",h=>{if(h.key==="Enter"&&h.target.tagName==="A"){queueMicrotask(()=>a?.());return}if(h.key!=="ArrowDown"&&h.key!=="ArrowUp"&&h.key!=="Home"&&h.key!=="End")return;h.preventDefault();let p=[...h.currentTarget.querySelectorAll(".s-menu-item")].filter(c=>c.getAttribute("aria-disabled")!=="true"&&!u2(c));if(!p.length)return;let r=p.indexOf(document.activeElement),d=h.key==="ArrowUp"?-1:1,o=h.key==="Home"?0:h.key==="End"?p.length-1:r<0?d>0?0:p.length-1:(r+d+p.length)%p.length;p[o].focus()}),W1(t,a)}function W1(t,a){for(let h of t){if(typeof h=="string"||typeof h=="function"){x(h);continue}if("separator"in h){y("hr.s-menu-sep");continue}h.items?m2(h,a):v2(h,a)}}function v2(t,a){let h=!1,e=y(t.href?"a.s-menu-item":"button.s-menu-item type=button",t.attrs,()=>{t.href&&(y("href=",t.href),t.target&&y("target=",t.target),y(()=>{let p=!h;h=!0,f1(t.href)&&(y("aria-current=page"),requestAnimationFrame(()=>e.scrollIntoView({block:"nearest",behavior:p?"instant":"smooth"})))})),t.disabled&&y("aria-disabled=true"),y("click=",p=>{if(t.disabled){p.preventDefault();return}a?.(),t.click?.(p)}),t.icon&&y("span.s-menu-icon",()=>x(t.icon)),x(t.label)})}function m2(t,a){let h=t.href??G1(t.items),e=h!=null?y.derive(()=>X1(t)):null;y("details.s-menu-details",()=>{e&&y(()=>{e.value&&y("open=true")}),y("summary.s-menu-item.s-menu-branch",t.attrs,()=>{t.disabled&&y("aria-disabled=true"),y(()=>{t.href!=null&&f1(t.href)&&y("aria-current=page")}),y("click=",p=>{if(t.disabled){p.preventDefault();return}h!=null&&(p.preventDefault(),y2(h),x2(h)),t.click?.(p)}),t.icon&&y("span.s-menu-icon",()=>x(t.icon)),x(t.label),y("span.s-menu-chevron aria-hidden=true",()=>q1())}),y("div.s-menu-sub",()=>W1(t.items,a))})}function u2(t){for(let a=t.closest("details");a;a=a.parentElement&&a.parentElement.closest("details"))if(!a.open&&t.closest("summary")?.parentElement!==a)return!0;return!1}function X1(t){if(t.href!=null&&f1(t.href))return!0;for(let a of t.items??[])if(!(typeof a=="string"||typeof a=="function"||"separator"in a)&&X1(a))return!0;return!1}function G1(t){for(let a of t){if(typeof a=="string"||typeof a=="function"||"separator"in a)continue;let h=a.href??(a.items?G1(a.items):void 0);if(h!=null)return h}}var o1=null;function y2(t){try{o1=new URL(t,location.href).pathname.replace(/\/+$/,"")||"/"}catch{o1=null}}function g1(t){return o1!==t?!1:(o1=null,!0)}var U=y.proxy({opts:null});function Z(){let t=U.opts?.anchor;U.opts=null,t?.focus()}function c1(t){let a=U.opts;return a!=null&&(t==null||a.anchor===t)}function f2(t){c1(t)&&Z()}function g2(t,a){let h=t.offsetWidth,e=t.offsetHeight,p=window.innerWidth,r=window.innerHeight,d=4,o=a.left;o+h>p-8&&(o=Math.max(8,a.right-h));let c=a.bottom+d;c+e>r-8&&a.top-e-d>=8&&(c=a.top-e-d),t.style.left=Math.max(8,o)+"px",t.style.top=Math.max(8,c)+"px"}F(()=>{let t=U.opts;if(!t)return;let a=y("div.s-menu-list.s-s.neutral.shadow create=hidden destroy=hidden",t.dropdownAttrs,()=>{h1(t.items,Z)}),h=r=>{let d=r.target;!a.contains(d)&&(t.closeOnAnchorClick||!t.anchor.contains(d))&&Z()},e=r=>{(r.key==="Escape"||r.key==="Tab")&&(r.preventDefault(),Z())},p=y.peek(y1,"path");y(()=>{y1.path!==p&&!g1(y1.path)&&Z()}),document.addEventListener("click",h,!0),document.addEventListener("keydown",e,!0),y.clean(()=>{document.removeEventListener("click",h,!0),document.removeEventListener("keydown",e,!0)}),requestAnimationFrame(()=>{if(!document.body.contains(a))return;let r=t.at?{left:t.at.x,right:t.at.x,top:t.at.y,bottom:t.at.y}:t.anchor.getBoundingClientRect();g2(a,r),j(a,".s-menu-item[aria-current=page]")})});function b2(t){y("nav.s-menu-inline",t.attrs,()=>h1(t.items,t.onLeafSelect))}function b1(t){return U.opts=t,Z}function w1(t){let a=null;y.clean(()=>{U.opts?.anchor===a&&Z()}),y("contextmenu=",h=>{h.preventDefault(),a=h.currentTarget,b1({items:t.items,anchor:a,at:{x:h.clientX,y:h.clientY},closeOnAnchorClick:!0,dropdownAttrs:t.dropdownAttrs})})}function w2(t){let a=null;y.clean(()=>{U.opts?.anchor===a&&Z()}),O({icon:d1,...t.button?.content==null?{ariaLabel:"Open menu"}:null,attrs:".neutral",...t.button,click:h=>{if(a=h.currentTarget,U.opts?.anchor===a){Z();return}b1({items:t.items,anchor:a,dropdownAttrs:t.dropdownAttrs})}})}import w from"aberdeen";import N from"aberdeen";function H1(t={}){I(t,(a,h)=>{N("input.s-input",t.inputAttrs,()=>{N("type=",t.type??"text"),t.placeholder!=null&&N("placeholder=",t.placeholder),t.autocomplete!=null&&N("autocomplete=",t.autocomplete),t.value!=null&&!t.bind&&N("value=",t.value),t.input&&N("input=",t.input),t.change&&N("change=",t.change),_(t,a,h,t.bind)})})}w.insertGlobalCss({".s-backdrop":{"&":"position:fixed inset:0 z-index:200 display:block background: rgba(0,0,0,0.55); transition: opacity 0.4s ease-in-out;","&.hidden":"opacity:0 pointer-events:none"},".s-dialog":{"&":"position:fixed z-index:200 top:50% left:50% display:flex flex-direction:column transform:translate(-50%,-50%) min-width:20rem max-width:min(90vw,44rem) max-height:min(88vh,800px) r: $s-radius-lg; overflow:hidden transition: opacity 0.2s ease-out, transform 0.2s ease-out;","> header":"display:flex align-items:center gap:$2 padding: $2 $3; border:0 border-bottom: 1px solid $s-faint; r:0 font-weight:600 flex-shrink:0","> footer":"display:flex align-items:center justify-content:flex-end gap:$2 padding: $2 $3; border:0 border-top: 1px solid $s-faint; r:0 flex-shrink:0","> div":"p:$3 gap:$3 display:flex flex-direction:column overflow-y:auto flex:1 min-height:0","&.hidden":"opacity:0 pointer-events:none transform: translate(-50%, calc(-50% + 20px)); pointer-events:none"}});var K=w.proxy({}),A1=0,N1=w.derive(()=>{let t=Object.keys(K);if(t.length)return t[t.length-1]});function V1(){return N1.value!=null}F(()=>{w.onEach(K,({resolve:t,opts:a},h)=>{let e=()=>{delete K[h]};w.clean(()=>{a.onClose?.(),t()});let p=w.derive(()=>N1.value!=h);w("div.s-backdrop create=hidden destroy=hidden .hidden=",p,"click=",()=>{a.allowCancel!==!1&&e()});let r=w("div.s-dialog.neutral.s-s.extra-shadow create=hidden destroy=hidden",a.attrs,()=>{w(()=>{a.header!=null&&w("header.s-s.neutral",a.headerAttrs,()=>x(a.header))}),w("div",a.contentAttrs,()=>{x(a.content,e)}),w(()=>{a.footer!=null&&w("footer.s-s.neutral",a.footerAttrs,()=>x(a.footer))})});requestAnimationFrame(()=>{document.body.contains(r)&&j(r)})})});function n1(t){A1||document.addEventListener("keydown",h=>{if(h.key!=="Escape"||h.defaultPrevented)return;let e=w.unproxy(K);for(let p=A1;p>0;p--)if(e[p]){h.preventDefault(),e[p].opts.allowCancel!==!1&&delete K[p];break}});let a=++A1;return t.cancelWithScope!==!1&&w.clean(()=>{delete K[a]}),new Promise(h=>{K[a]={resolve:h,opts:t}})}function H2(t,a={}){return n1({header:"Alert",allowCancel:!0,content:h=>{w("p",()=>{w("#",t)}),X({layout:"spaced",attrs:"align-self:flex-end",content:()=>{O({content:"OK",click:h})}})},...a})}function A2(t,a={}){return new Promise(h=>{let e=!1;n1({header:"Confirm",allowCancel:!0,content:p=>{w("p",()=>{w("#",t)}),X({layout:"spaced",attrs:"align-self:flex-end",content:()=>{O({content:"Cancel",attrs:".neutral",click:p}),O({content:"OK",click:()=>{e=!0,p()}})}})},...a,onClose:()=>{h(e),a.onClose?.()}})})}function V2(t,a="",h={}){return new Promise(e=>{let p=null;n1({header:"Input",allowCancel:!0,content:r=>{w("p",()=>{w("#",t)});let d=w.proxy({value:a});w("form display:contents",()=>{w("submit=",o=>{o.preventDefault(),p=d.value,r()}),H1({bind:w.ref(d,"value")}),X({layout:"spaced",attrs:"align-self:flex-end",content:()=>{O({content:"Cancel",attrs:".neutral",type:"button",click:r}),O({content:"OK",type:"submit"})}})})},...h,onClose:()=>{e(p),h.onClose?.()}})})}import i,{OPAQUE as j1}from"aberdeen";import*as b from"aberdeen/route";import A from"aberdeen";var k2=z('<path d="m15 18-6-6 6-6"/>'),L2=z('<path d="m9 18 6-6-6-6"/>');A.insertGlobalCss({".s-strip":{"&":"position:relative display:flex min-width:0","> .s-strip-row":"display:flex align-items:center flex:1 min-width:0 overflow-x:auto overflow-y:hidden scrollbar-width:none scroll-behavior:smooth","> .s-strip-row::-webkit-scrollbar":"display:none","> .s-strip-btn":"position:absolute top:0 bottom:0 z-index:1 display:none align-items:center justify-content:center width:2.4em border:0 padding:0 cursor:pointer fg:$s-muted transition: color 0.15s;","> .s-strip-btn:hover":"fg:$s-text","> .s-strip-btn-left":"left:0 justify-content:flex-start background: linear-gradient(to right, $s-bg 45%, transparent)","> .s-strip-btn-right":"right:0 justify-content:flex-end background: linear-gradient(to left, $s-bg 45%, transparent)","&.s-can-left > .s-strip-btn-left, &.s-can-right > .s-strip-btn-right":"display:flex"},".s-tabs":{"&":"display:flex flex-direction:column gap:$3",".s-tabbar":"border-bottom: 1px solid $s-faint;",".s-tablist":"gap:$1 align-items:stretch margin-bottom:-1px",".s-tab":"display:inline-flex align-items:center gap:$2 cursor:pointer background:transparent border:0 color: $s-muted; font-weight:600 padding: 0.6em 0.9em; white-space:nowrap border-bottom: 3px solid transparent; transition: color 0.15s, background 0.15s, border-color 0.15s;",".s-tab:hover:not(:disabled), .s-tab[aria-selected=true]":"color: $s-text;",".s-tab:focus-visible":"outline:none box-shadow: inset 0 0 0 2px $s-focus; r: $s-radius;",".s-tab[aria-selected=true]":"border-image: $s-gradient 1;",".s-tabpanel":"display:block"}});function i1(t){A("div.s-strip",t.attrs,()=>{let a=A("div.s-strip-row",t.stripAttrs,()=>x(t.content));K1(a,-1),K1(a,1),z2(a)})}function s1(t){let a=t.parentElement;if(!a||!t.isConnected)return;let h=parseFloat(getComputedStyle(a).fontSize)*2.6,e=t.getBoundingClientRect(),p=a.getBoundingClientRect();e.left<p.left+h?a.scrollBy({left:e.left-p.left-h,behavior:"smooth"}):e.right>p.right-h&&a.scrollBy({left:e.right-p.right+h,behavior:"smooth"})}function C2(t){let a=B("tabs"),h=(r,d)=>r.id??String(d),e=t.bind??A.proxy(h(t.tabs[0]??{label:""},0));t.tabs.length>0&&!t.tabs.some((r,d)=>h(r,d)===A.peek(()=>e.value))&&(e.value=h(t.tabs[0],0));let p=(r,d)=>{r.disabled||(e.value=h(r,d))};A("div.s-tabs",t.attrs,()=>{i1({attrs:".s-tabbar",stripAttrs:".s-tablist role=tablist",content:()=>{t.tabs.forEach((r,d)=>{let o=h(r,d),c=A("button.s-tab type=button role=tab",()=>{A("id=",`${a}-tab-${o}`,"aria-controls=",`${a}-panel-${o}`),A(()=>{let M=e.value===o;A("aria-selected=",M?"true":"false"),A("tabindex=",M?"0":"-1"),M&&requestAnimationFrame(()=>s1(c))}),r.disabled&&A("disabled=true"),A("click=",()=>p(r,d)),A("keydown=",M=>$2(M,t.tabs,d,p)),x(r.icon),x(r.label)})})}}),A("div.s-tabpanel role=tabpanel",t.contentAttrs,()=>{A(()=>{let r=e.value,d=t.tabs.findIndex((c,M)=>h(c,M)===r),o=t.tabs[d]??t.tabs[0];o&&(A("id=",`${a}-panel-${h(o,d)}`,"aria-labelledby=",`${a}-tab-${h(o,d)}`),x(o.content))})})})}function K1(t,a){A(`button.s-strip-btn.s-strip-btn-${a<0?"left":"right"} type=button`,()=>{A("tabindex=-1 aria-hidden=true"),A("click=",()=>t.scrollBy({left:a*t.clientWidth*.8,behavior:"smooth"})),(a<0?k2:L2)({size:"1.1em"})})}function z2(t){let a=t.parentElement;if(!a||typeof ResizeObserver>"u")return;let h=()=>{let r=t.scrollWidth-t.clientWidth;a.classList.toggle("s-can-left",t.scrollLeft>1),a.classList.toggle("s-can-right",t.scrollLeft<r-1)};t.addEventListener("scroll",h,{passive:!0});let e=new ResizeObserver(h);e.observe(t);let p=typeof MutationObserver>"u"?void 0:new MutationObserver(r=>{for(let d of r){for(let o of d.addedNodes)o instanceof Element&&e.observe(o);for(let o of d.removedNodes)o instanceof Element&&e.unobserve(o)}h()});p?.observe(t,{childList:!0});for(let r of Array.from(t.children))e.observe(r);h(),A.clean(()=>{t.removeEventListener("scroll",h),e.disconnect(),p?.disconnect()})}function $2(t,a,h,e){let p=h;if(t.key==="ArrowRight"||t.key==="ArrowDown")p=(h+1)%a.length;else if(t.key==="ArrowLeft"||t.key==="ArrowUp")p=(h-1+a.length)%a.length;else if(t.key==="Home")p=0;else if(t.key==="End")p=a.length-1;else return;t.preventDefault();let r=p>=h?1:-1;for(let d=0;d<a.length;d++){let o=a[p];if(o&&!o.disabled){e(o,p),t.currentTarget?.parentElement?.children[p]?.focus();return}p=(p+r+a.length)%a.length}}import V from"aberdeen";import{grow as S2,shrink as P2}from"aberdeen/transitions";V.insertGlobalCss({".s-toasts":"position:fixed bottom:$3 right:$3 z-index:400 display:flex flex-direction:column gap:$2 pointer-events:none max-width:min(90vw,24rem) w:24rem",".s-toast":{"&":"display:flex align-items:flex-start gap:$2 padding: $3; pointer-events:auto position:relative overflow:hidden",".s-toast-body":"display:flex flex-direction:column gap:$1 flex:1 min-width:0",".s-toast-title":"font-weight:700 line-height:1.3",".s-toast-close":"cursor:pointer border:0 background:transparent fg:$s-muted font-size:1.1em line-height:1 padding: 0 0.15em; r:4px flex-shrink:0 align-self:flex-start",".s-toast-close:hover":"fg:$s-text",".s-toast-close:focus-visible":"outline:none box-shadow: 0 0 0 3px $s-focus; fg:$s-text",".s-toast-progress":"position:absolute bottom:0 left:0 right:0 height:2px background:$s-accent width:100%"}});var O2=0,e1=V.proxy({});F(()=>{V.peek(()=>V.isEmpty(e1))&&V.isEmpty(e1)||V("div.s-toasts",()=>{V.onEach(e1,t=>{let{opts:a,id:h}=t,e=a.type==="danger"||a.type==="warning"?"alert":"status",p=a.type==null||a.type==="neutral"?"neutral":a.type,r=a.duration??6e3,d,o=null,c=()=>{clearTimeout(d),o&&(o.style.transition="none",o.style.width="100%",o.offsetWidth,o.style.transition=`width ${r}ms linear`,o.style.width="0%"),d=setTimeout(()=>k1(h),r)},M=()=>{clearTimeout(d),d=void 0,o&&(o.style.transition="none",o.style.width="100%")};V.clean(()=>clearTimeout(d)),V(`div.s-toast.s-s.${p}.extra-shadow aria-live=polite role=${e}`,"create=",S2,"destroy=",P2,a.attrs,()=>{r>0&&(V("mouseenter=",M),V("mouseleave=",c)),V("div.s-toast-body",()=>{V(()=>{a.title!=null&&V("div.s-toast-title",()=>x(a.title))}),V("div.s-toast-msg",()=>x(a.message))}),V(()=>{a.dismissible!==!1&&V("button.s-toast-close type=button aria-label=Dismiss",()=>{V("#\xD7"),V("click=",()=>k1(h))})}),r>0&&(o=V("div.s-toast-progress"))}),r>0&&requestAnimationFrame(c)})})});function k1(t){delete e1[t]}function l1(t){let a=++O2;return e1[a]={id:a,opts:t},()=>k1(a)}var z1={integer(t){if(!/^(0|-?[1-9]\d*)$/.test(t))return;let a=Number(t);return Number.isSafeInteger(a)?a:void 0}};function q(t){let a=String(t).replace(/\/+$/,"");return a.startsWith("/")||(a=`/${a}`),a}function p1(t){let a=q(t);return a==="/"?[]:a.slice(1).split("/")}function _1(t){let a=p1(t),h=a.map((e,p)=>{if(!e.startsWith("[")||!e.endsWith("]"))return{kind:"lit",value:e};let r=/^\[\.\.\.([A-Za-z_$][\w$]*)\]$/.exec(e);if(r){if(p!==a.length-1)throw new Error(`Staffa: "${e}" must be the last segment of route "${t}"`);return{kind:"rest",name:r[1]}}let d=/^\[([A-Za-z_$][\w$]*)(?:=([A-Za-z_$][\w$]*))?\]$/.exec(e);if(!d)throw new Error(`Staffa: malformed param "${e}" in route "${t}"`);let[,o,c]=d;if(c&&!(c in z1))throw new Error(`Staffa: unknown matcher "${c}" in route "${t}" (known: ${Object.keys(z1).join(", ")})`);return{kind:"param",name:o,matcher:c}});return{key:t,segs:h}}function E2(t){try{return decodeURIComponent(t)}catch{return t}}function L1(t,a){let h={};for(let e=0;e<t.segs.length;e++){let p=t.segs[e];if(p.kind==="rest")return e>=a.length?null:(h[p.name]=a.slice(e).join("/"),h);if(e>=a.length)return null;let r=a[e];if(p.kind==="lit"){if(r!==p.value)return null}else if(p.matcher){let d=z1[p.matcher](r);if(d===void 0)return null;h[p.name]=d}else h[p.name]=E2(r)}return t.segs.length===a.length?h:null}var J1=250,q2=300,T2=1280,D2=360,Q1=2;i.insertGlobalCss({":root":`--s-panel-ms:${J1}ms`,".s-panels":"flex:1 min-width:0 min-height:0 position:relative overflow:hidden isolation:isolate "+Y,".s-panel":{"&":"position:absolute top:0 bottom:0 left:0 display:flex flex-direction:column "+Y+" visibility:visible transition: left var(--s-panel-ms) ease, transform var(--s-panel-ms) ease-out, opacity var(--s-panel-ms) linear, visibility 0s;","&.s-panel-sep::before":"content:'' position:absolute left:0 top:0.6rem bottom:0.6rem width:1px z-index:1 background: linear-gradient(to bottom, transparent, $s-faint 18%, $s-faint 82%, transparent);","&.s-panel-enter":"opacity:0 transition:none transform: translateX(8cqw);","&.s-panel-closing":"opacity:0 pointer-events:none transform: translateX(8cqw);","&.s-panel-hidden, &.s-panel-parked":"opacity:0 visibility:hidden transition: left var(--s-panel-ms) ease, transform var(--s-panel-ms) ease-out, opacity var(--s-panel-ms) linear, visibility var(--s-panel-ms);","&.s-panel-hidden":"transform: translateX(-8cqw);","&.s-panel-parked":"transform: translateX(8cqw);"},".s-panel > .s-content":"flex:1 min-height:0 overflow-y:auto overflow-x:hidden p:$3",".s-panel-actions":"display:flex align-items:center justify-content:flex-end gap:$1 flex-shrink:0 padding: $3 $3 0;",".s-crumbs > .s-strip-row":"gap:$m1",".s-crumb":{"&":"flex-shrink:0 font-size:0.85em line-height:1.5 fg:$s-muted text-decoration:none white-space:nowrap max-width:14rem overflow:hidden text-overflow:ellipsis transition: color 0.12s;","&.s-crumb-on":"font-weight:600 fg:$s-text","a&:hover":"filter:none color: color-mix(in lab, $s-primary 33%, $s-text);","svg.s-crumb-pin":"vertical-align:-0.12em margin-right:0.3em opacity:0.8 fill:currentColor","svg.s-crumb-unsaved":"vertical-align:0.08em margin-right:0.3em fill:currentColor"},"svg.s-crumb-sep":"flex-shrink:0 opacity:0.4",".s-main.s-shell-snap .s-panel":"transition:none",".s-panel-loading":{"&":"position:absolute inset:0 display:flex align-items:center justify-content:center gap:$1 pointer-events:none",i:"width:0.5rem height:0.5rem r:50% background:$s-muted opacity:0.45 animation: s-panel-pulse 1s ease-in-out infinite;","i:nth-child(2)":"animation-delay:0.15s","i:nth-child(3)":"animation-delay:0.3s"},"@keyframes s-panel-pulse":{"0%, 100%":"opacity:0.25 transform:scale(0.8)","50%":"opacity:0.7 transform:scale(1)"}});var C1=!1,M1=class{[j1]=!0;compiled;ancestors;opts;$state=i.proxy({live:[],focus:0});$open=i.proxy({});nextOrder=0;containerEl;geom;lastBodyW=-1;layoutQueued=!1;timers=new Set;intent=null;settling=null;lastSeen=null;queued=null;constructor(a){if(C1)throw new Error("Staffa: only one routed S.main() (one with `routes`) can be active at a time");C1=!0,this.opts=a,this.compiled=Object.entries(a.routes).map(([h,e])=>({..._1(h),draw:e})),this.ancestors=Object.entries(a.ancestors??{}).filter(h=>h[1]!=null).map(([h,e])=>({..._1(h),fn:e})),i(()=>{let h=this.computeTarget(),e={...b.current.search},p=b.current.hash;i.peek(()=>{let r=this.lastSeen;if(r&&r.path!==b.current.path){let d=this.$state.live.find(o=>o.path===r.path);d&&(d.search=r.search,d.hash=r.hash)}this.lastSeen={path:b.current.path,search:e,hash:p},this.propose(h),Array.isArray(b.current.state.panels)||Object.assign(b.current.state,this.stateFor({stack:this.paths(),focus:this.$state.focus}))})}),this.interceptLinks(),this.watchTitle(),this.guardTabClose(),i.clean(()=>{for(let h of this.timers)clearTimeout(h);this.timers.clear(),this.queued?.settle(!1),this.queued=null,C1=!1})}resolve(a){let h=p1(a);for(let e of this.compiled){let p=L1(e,h);if(p)return{draw:e.draw,params:p}}return{draw:this.opts.notFound??I2,params:{}}}matches(a){let h=p1(a);return this.compiled.some(e=>L1(e,h)!=null)}deriveStack(a){let h=q(a),e=this.askAncestors(h),p=e?e.map(q):this.prefixesOf(h),r=[];for(let d of p)d!==h&&!r.includes(d)&&this.matches(d)&&r.push(d);return r.push(h),r}askAncestors(a){let h=p1(a);for(let e of this.ancestors){let p=L1(e,h);if(p)return e.fn(p,a)??void 0}}prefixesOf(a){let h=p1(a),e=[];for(let p=1;p<h.length;p++)e.push("/"+h.slice(0,p).join("/"));return e}pinnedIn(a,h){return a.filter(e=>h.includes(e)?!1:this.$state.live.find(p=>p.path===e)?.$panel.pinned===!0)}unsavedAt(a){return this.$state.live.find(h=>h.path===a)?.$panel.unsaved===!0}targetFor(a,h){let e=Array.isArray(h?.panels)?h.panels.map(String):null;if(e){let p=Array.isArray(h.parked)?h.parked.map(String):[],r=q(a),d=new Set([r]),o=M=>M.map(q).filter(m=>!d.has(m)&&!!d.add(m)),c=o(e);return{stack:[...c,r,...o(p)],focus:c.length}}return i.peek(()=>{let p=this.deriveStack(a).slice(0,-1),r=[...p,...this.pinnedIn(this.paths(),[...p,q(a)]),q(a)];return{stack:r,focus:r.length-1}})}computeTarget(){return this.targetFor(b.current.path,b.current.state)}paths(){return this.$state.live.map(a=>a.path)}propose(a){let h=this.$state.live.filter(e=>!a.stack.includes(e.path)&&e.$panel.unsaved).map(e=>e.path);h.length&&(a={stack:[...a.stack,...h],focus:a.focus}),!(Z2(this.paths(),a.stack)&&a.focus===this.$state.focus)&&this.commit(a,b.current.nav)}commit(a,h){this.geom=void 0;let e=b.current.state.pinned,p=new Set(Array.isArray(e)?e.map(String):[]),r=new Map(this.$state.live.map(o=>[o.path,o])),d=[];for(let o of a.stack){let c=r.get(o);if(c){r.delete(o),d.push(c);continue}let M=this.createEntry(o,d.length<=a.focus,p.has(o));h!=="load"&&h!=="back"&&(M.enter=!0),d.push(M),this.$open[o]=M}for(let o of r.values())this.beginClose(o);this.$state.live=d,this.$state.focus=Math.min(a.focus,d.length-1),this.scheduleLayout()}createEntry(a,h,e){let{draw:p,params:r}=this.resolve(a),d={[j1]:!0,order:this.nextOrder++,path:a,draw:p,$ui:i.proxy({holding:!1}),maxWidth:"full",width:0};return d.$panel=i.proxy({stack:this,params:r,path:a,width:0,visible:h,pinned:e||void 0,close:()=>this.closePath(d.path)}),d}beginClose(a){a.closing=!0,a.$panel.visible=!1,a.el&&(a.el.style.zIndex=String(Q1*this.$state.live.indexOf(a))),delete this.$open[a.path]}playExit(a,h){if(!a.closing){h.remove();return}h.classList.add("s-panel-closing"),h.setAttribute("inert","");let e=()=>{clearTimeout(p),this.timers.delete(p),h.remove()};h.addEventListener("transitionend",r=>{r.target===h&&r.propertyName==="opacity"&&e()});let p=setTimeout(e,J1+80);this.timers.add(p)}intended(){return this.intent??{stack:this.paths(),focus:this.$state.focus}}stateFor(a){return{panels:a.stack.slice(0,a.focus),parked:a.stack.slice(a.focus+1),pinned:this.pinnedPaths()}}pinnedPaths(){return this.$state.live.filter(a=>a.$panel.pinned).map(a=>a.path)}issue(a,h){return this.intent=a,this.settling?(this.queued?.settle(!1),new Promise(e=>{this.queued={run:h,settle:e}})):this.start(h)}start(a){let h=p=>{this.settling=null;let r=this.queued;return this.queued=null,p&&r?this.start(r.run).then(r.settle,()=>r.settle(!1)):(this.intent=null,r?.settle(!1)),p},e=Promise.resolve(a()).then(h,p=>(console.error(p),h(!1)));return this.settling=e,e}focusAt(a,h,e){let p=this.intended();if(a<0||a>=p.stack.length||a===p.focus)return Promise.resolve(!1);let r={stack:p.stack,focus:a},d=p.stack[a];return this.issue(r,()=>{let o=this.$state.live.find(c=>c.path===d);return b.go({path:d,search:h??o?.search,hash:e??o?.hash,state:this.stateFor(r)})})}back(){return i.peek(()=>{let a=this.intended();return a.focus===a.stack.length-1&&!this.unsavedAt(a.stack[a.focus])?this.closePath(a.stack[a.focus]??""):a.focus===0?Promise.resolve(!1):this.focusAt(a.focus-1)})}closePath(a){return i.peek(()=>{let h=this.intended(),e=h.stack.indexOf(q(a));if(e<0||h.stack.length<2||this.unsavedAt(h.stack[e]))return Promise.resolve(!1);let p=h.stack.filter((M,m)=>m!==e),r=e===h.focus?Math.max(0,e-1):h.focus-(e<h.focus?1:0),d={stack:p,focus:r};if(e===h.focus&&e===h.stack.length-1){let M=this.$state.live.find(u=>u.path===p[r]),m={};M?.search&&(m.search=M.search),M?.hash&&(m.hash=M.hash);let l=p.filter(u=>this.$state.live.find(f=>f.path===u)?.$panel.pinned===!0);return this.issue(d,()=>Promise.resolve(b.back({path:p[r],state:{panels:p.slice(0,r),parked:[]}},m)).then(u=>(u&&(b.current.state.pinned=l),u)))}let o=p[r],c=o!==h.stack[h.focus];return this.issue(d,()=>{let M=c?this.$state.live.find(m=>m.path===o):void 0;return b.go({path:o,search:c?M?.search:{...b.current.search},hash:c?M?.hash:b.current.hash,state:this.stateFor(d)})})})}navigate(a,h,e=!1,p){return i.peek(()=>{let r;try{r=new URL(a,location.href)}catch{return Promise.resolve(!1)}let d=q(r.pathname),o=Object.fromEntries(new URLSearchParams(r.search)),c=r.hash,M=this.intended(),m=p?-1:M.stack.indexOf(d);if(m>=0&&m!==M.focus)return this.focusAt(m,r.search?o:void 0,c||void 0);if(m>=0)return r.search===location.search&&(r.hash||"")===(location.hash||"")?Promise.resolve(!0):this.issue(M,()=>b.go({path:d,search:o,hash:c,state:this.stateFor(M)}));let l=h==null?-1:M.stack.indexOf(h),u=p?p.map(q).filter((n,g,C)=>n!==d&&C.indexOf(n)===g):l<0?this.deriveStack(d).slice(0,-1):M.stack.slice(0,e?l:l+1),f=[...u,...this.pinnedIn(M.stack,[...u,d,e?h:null])],H={stack:[...f,d],focus:f.length};return this.issue(H,()=>b.go({path:d,search:o,hash:c,state:this.stateFor(H)}))})}pushPath(a,h){return i.peek(()=>{let e=this.intended();return this.navigate(a,e.stack[e.focus]??null,h)})}interceptLinks(){b.interceptLinks((a,h)=>{let e=h.getAttribute("data-panel"),p=e==="open"?null:h.closest(".s-panel"),r=p?this.$state.live.find(d=>d.el===p):void 0;return this.navigate(a.href,r?.path??null,e==="replace"),!0})}get currentPanel(){return this.$state.live[this.$state.focus]?.$panel}get panels(){return this.$state.live.map(a=>a.$panel)}get currentPanelIndex(){return this.$state.focus}pushPanel(a){return this.pushPath(a,!1)}replacePanel(a){return this.pushPath(a,!0)}openPanelStack(a,h){return this.navigate(a,null,!1,h)}closePanel(a){return i.peek(()=>{let h=this.intended();return this.closePath(a??h.stack[h.focus]??"")})}drawCrumbs(){i1({attrs:".s-crumbs role=navigation aria-label=Breadcrumbs",content:()=>{i(()=>{let a=this.panels.map(p=>p.path),h=this.currentPanelIndex,e;for(let p=0;p<a.length;p++){p&&B1({size:"0.85em",attrs:".s-crumb-sep"});let r=this.drawCrumb(a[p],p,p===h);p===h&&(e=r)}requestAnimationFrame(()=>{e&&s1(e)})})}})}drawCrumb(a,h,e){let p=this.$state.live[h];return i(e?"span.s-crumb aria-current=page":"a.s-crumb",()=>{e||i("href=",a),i(()=>{p?.$panel.visible&&i(".s-crumb-on")}),i(()=>{p?.$panel.unsaved&&T1({size:"0.45em",attrs:".s-crumb-unsaved"})}),i(()=>{p?.$panel.pinned&&m1({size:"0.85em",attrs:".s-crumb-pin"})}),i(()=>{i("#",p?.$panel.title??p?.$ui.fallback??(a.split("/").pop()||a))}),w1({items:[{label:"Open in new tab",icon:D1,click:()=>{window.open(a,"_blank","noopener")}},{label:"Copy link",icon:R1,click:()=>{F2(a)}},{separator:!0},{label:()=>{i(()=>{i("#",p?.$panel.pinned?"Unpin":"Pin")})},icon:()=>{i(()=>{(p?.$panel.pinned?Z1:m1)()})},click:()=>{p&&this.togglePin(p)}},{label:"Close",icon:Q,disabled:p?.$panel.unsaved===!0,click:()=>{this.closePath(a)}}]})})}togglePin(a){a.$panel.pinned=!a.$panel.pinned||void 0,b.current.state.pinned=this.pinnedPaths()}watchTitle(){let a=document.title;i(()=>{let h=this.$state.live[this.$state.focus],e=h?.$panel.title??h?.$ui.fallback,p=typeof this.opts.title=="string"?this.opts.title:void 0,r=this.$state.live.some(o=>o.$panel.unsaved),d=e&&p?`${e} \xB7 ${p}`:e||p;d&&(document.title=(r?"\u2022 ":"")+d)}),i.clean(()=>{document.title=a})}guardTabClose(){if(typeof window>"u")return;let a=!1,h=()=>{a=!0},e=p=>{a=!1;let r=this.$state.live.find(o=>o.$panel.unsaved);if(!r)return;p.preventDefault(),p.returnValue=!0;let d=r.path;setTimeout(()=>{if(a)return;let o=this.$state.live.find(c=>c.path===d);o&&!o.$panel.visible&&this.focusAt(this.intended().stack.indexOf(d))},0)};i(()=>{this.$state.live.some(p=>p.$panel.unsaved)&&(window.addEventListener("beforeunload",e),window.addEventListener("pagehide",h),i.clean(()=>{window.removeEventListener("beforeunload",e),window.removeEventListener("pagehide",h)}))})}drawColumns(){let a=i("div.s-panels role=main",()=>{this.containerEl=i(),i.onEach(this.$open,h=>this.drawPanel(h),h=>h.order)});if(typeof ResizeObserver<"u"){let h=new ResizeObserver(()=>this.layout());h.observe(a);let e=a.parentElement?.parentElement;e&&h.observe(e),i.clean(()=>h.disconnect())}i.clean(()=>{this.containerEl===a&&(this.containerEl=void 0)}),this.scheduleLayout()}drawPanel(a){let h;i(()=>{let e=a.$panel.maxWidth;a.maxWidth=e==="half"||e==="screen"?e:"full";let p=this.roomFor(a.maxWidth);p&&(a.width=p,i.peek(a.$panel,"width")!==p&&(a.$panel.width=p),h&&(h.style.width=`${p}px`,this.scheduleLayout()))}),h=i(`section.s-panel${a.width?` w:${a.width}px`:""}`,"destroy=",e=>this.playExit(a,e),()=>{i(()=>this.drawActions(a)),i("div.s-content",()=>{if(a.draw(a.$panel),b.persistScroll(a.path),i.peek(a.$panel,"title")==null){let e=B2(i());e&&i.peek(a.$ui,"fallback")!==e&&(a.$ui.fallback=e)}}),i(()=>{!a.$panel.loading||a.$ui.holding||i("div.s-panel-loading aria-hidden=true",()=>{i("i"),i("i"),i("i")})})}),a.el=h,a.placed=!1,h.style.transition="none",i.clean(()=>{a.el===h&&(a.el=void 0)}),i(()=>{a.$panel.loading,this.scheduleLayout()}),this.scheduleLayout()}drawActions(a){this.opts.$shell.narrow||a.$panel.actions==null||i("div.s-panel-actions",()=>x(a.$panel.actions))}scheduleLayout(){this.layoutQueued||(this.layoutQueued=!0,requestAnimationFrame(()=>{this.layoutQueued=!1,this.layout()}))}measure(){let a=this.containerEl,h=a?.parentElement,e=h?.parentElement;if(!a||!h||!e)return;let p=e.getBoundingClientRect().width;if(!p)return;let r=0;for(let c of h.children)c!==a&&(r+=c.getBoundingClientRect().width);let d=Math.max(0,Math.min(T2,p)-r),o=d/2;return{total:p,chrome:r,half:o>=D2?o:d,full:d,screen:Math.max(0,p-r)}}geometry(){return this.geom??=this.measure()}roomFor(a){return this.geometry()?.[a]??0}layout(){let a=this.containerEl,h=a?.closest(".s-main");if(!a||!h)return;let e=this.$state.live,p=e.length;if(!p||e.some(n=>!n.el))return;this.geom=void 0;let r=this.geometry();if(!r)return;let d=this.opts.stacking!==!1,o=this.lastBodyW!==r.total;o&&(this.lastBodyW=r.total,h.classList.add("s-shell-snap"));let c=n=>r[n.maxWidth],M=Math.min(this.$state.focus,p-1),m=M,l=c(e[M]);if(d)for(let n=M-1;n>=0;n--){let g=l+c(e[n]);if(g>r.screen)break;l=g,m=n}let u=Math.min(r.screen,Math.max(r.full,l));for(let n=m;n<=M;n++)e[n].width=c(e[n]);for(let n of e)n.width||(n.width=c(n));h.style.setProperty("--s-shell-w",`${r.chrome+u}px`);let f=[],H=0;for(let n=0;n<p;n++){let g=e[n],C=g.el,S=n>=m&&n<=M;R2(C,S?H:n>M?u:0,g.width,Q1*n+1),g.$panel.visible!==S&&(g.$panel.visible=S),g.$panel.width!==g.width&&(g.$panel.width=g.width),S&&(H+=g.width),C.classList.toggle("s-panel-sep",S&&n>m),C.classList.toggle("s-panel-hidden",n<m),C.classList.toggle("s-panel-parked",n>M),C.toggleAttribute("inert",!S),!g.placed&&(f.push(g),!g.$panel.loading||g.holdDone?g.$ui.holding=!1:g.$ui.holding||(g.$ui.holding=!0,this.holdEnter(g)),g.enter&&S&&C.classList.add("s-panel-enter"))}(f.length||o)&&a.offsetWidth,o&&h.classList.remove("s-shell-snap");for(let n of f)n.$ui.holding||(n.el.style.transition="",n.el.classList.remove("s-panel-enter"),n.enter=!1,n.placed=!0)}holdEnter(a){let h=setTimeout(()=>{this.timers.delete(h),a.holdDone=!0,a.$ui.holding&&(a.$ui.holding=!1,this.scheduleLayout())},q2);this.timers.add(h)}};function R2(t,a,h,e){t.style.left=`${a}px`,t.style.width=`${h}px`,t.style.zIndex=String(e)}function Z2(t,a){return t.length===a.length&&t.every((h,e)=>h===a[e])}function B2(t){let a=document.createTreeWalker(t,NodeFilter.SHOW_TEXT);for(let h=a.nextNode();h;h=a.nextNode()){let e=h.textContent.trim();if(e)return e.length>48?`${e.slice(0,47).trimEnd()}\u2026`:e}}async function F2(t){let a=new URL(t,location.href).href;try{await navigator.clipboard.writeText(a),l1({message:"Link copied."})}catch{l1({message:"Couldn't copy the link.",type:"danger"})}}function I2(t){i("p fg:$s-muted",()=>i("#",`No panel at ${t.path}`))}v.insertGlobalCss({".s-main":{"&":"display:flex flex-direction:column min-height:100vh max-height:100vh container-type:inline-size","body > &":"margin: calc(-1 * $3)","> header":"border:0 border-bottom: 1px solid $s-faint; r:0 position:sticky top:0 z-index:10","> footer":"border-top: 1px solid $s-faint; fg:$s-muted","> header > .s-bar, > footer > .s-bar":"display:flex align-items:center width:100% margin-inline:auto gap:$3 padding: $2 $3;","> header .s-logo, > header .s-nav-trigger":"display:flex align-items:center flex-shrink:0","> header .s-nav-trigger":"margin-left:-0.375rem","> header .s-logo":"font-size:1.4em background: $s-gradient; -webkit-background-clip:text; background-clip:text; color:transparent;","> header .s-titles":"display:flex flex-direction:column min-width:0 flex: 0 1 auto;","> header .s-subtitle":"fg:$s-muted font-size:0.85em line-height:1.5 overflow:hidden text-overflow:ellipsis white-space:nowrap","> header .s-title":"font-weight:800 font-size:1.1em line-height:1.2 overflow:hidden text-overflow:ellipsis white-space:nowrap letter-spacing:-0.01em background: $s-gradient; -webkit-background-clip:text; background-clip:text; color:transparent; width:fit-content max-width:100%","> header a.s-logo, > header a.s-title":"text-decoration:none filter:none cursor:pointer","> header .s-menu":"display:flex align-items:center justify-content:flex-end gap:$2 flex: 1 0 auto;",".s-body":"flex:1 overflow:hidden display:flex flex-direction:row min-height:0 justify-content:center position:relative",".s-body-inner":"flex:1 min-width:0 display:flex flex-direction:row min-height:0","&.s-nav-right .s-body-inner":"flex-direction:row-reverse",".s-nav-sep":"width:1px flex-shrink:0 align-self:stretch margin: 0.6rem 0; border:0 background: linear-gradient(to bottom, transparent, $s-faint 18%, $s-faint 82%, transparent);",".s-body main":"flex:1 min-width:0 min-height:0 overflow-x:hidden overflow-y:auto display:flex flex-direction:column transition: transform var(--s-panel-ms) ease;",".s-body main.s-slide-in":"transform: translateX(100%); transition:none",".s-body main > .s-content":"width:100% flex:1 p:$3",".s-body main.s-scroll-y":"margin-right:$3","&.s-routed > .s-body > .s-body-inner":"max-width: var(--s-shell-w, 100%);","&.s-routed > header > .s-bar":"max-width: var(--s-shell-w, 100%);","&.s-routed > footer > .s-bar":"max-width: var(--s-shell-w, 100%);","&.s-routed > .s-body > .s-body-inner, &.s-routed > header > .s-bar, &.s-routed > footer > .s-bar":"transition: max-width var(--s-panel-ms) ease;","&.s-routed.s-shell-snap > .s-body > .s-body-inner, &.s-routed.s-shell-snap > header > .s-bar, &.s-routed.s-shell-snap > footer > .s-bar":"transition:none"},".s-nav-panel":{"&":"display:flex flex-direction:column overflow-y:auto flex-shrink:0 max-width:228px padding:$3 gap:$1"},".s-nav-page":{"&":"position:absolute inset:0 z-index:5 display:flex flex-direction:column overflow-y:auto overscroll-behavior:contain border:0 r:0 padding:$2 gap:$1 transition: transform var(--s-panel-ms) ease;","&.s-nav-page-off":"transform:translateX(-100%) pointer-events:none",".s-menu-item":"padding: $2 $3; min-height:3rem font-size:1.05em gap:$3"},[`@container (max-width: ${r1}px)`]:{".s-main .s-nav-panel, .s-main .s-nav-sep":"display:none",".s-main > header > .s-bar":"gap:$1 padding: $1 $2;",".s-content > .s-box":"margin-inline: calc(-1 * $3); r:0 border-inline:0",".s-main .s-body main.s-scroll-y":"margin-right:0"}});function W2(t={}){let a=t.nav,h=t.navPosition??"left",e=v.proxy({open:!1}),p=v.proxy({narrow:typeof document<"u"&&document.documentElement.clientWidth<=r1}),r=t.routes;if(r!=null&&t.content!=null)throw new Error("Staffa: S.main() takes either `content` or `routes`, not both");let d=r?new M1({routes:r,notFound:t.notFound,ancestors:t.ancestors,stacking:t.stacking,title:t.title,$shell:p}):null,o=d?null:t.maxWidth,c=v(`div.s-main${d?".s-routed":""}`,t.attrs,()=>{v(()=>{a==null||!a.items.length||v(`.s-nav-${h}`)}),v(()=>{(d!=null||t.title!=null||t.subtitle!=null||t.logo!=null||t.menu!=null||a!=null&&a.items.length>0)&&v("header.s-s.neutral",t.topbarAttrs,()=>{v("div.s-bar",()=>{v(()=>{o!=null&&v("max-width:",o)}),v(()=>{if(p.narrow&&a!=null&&a.items.length){v("div.s-nav-trigger",()=>j2(a,e));return}t.logo!=null&&v(d?"a.s-logo aria-label=Home":"div.s-logo",()=>{d&&v("href=",t.home??"/"),x(t.logo)})}),v("div.s-titles",()=>{v(()=>{t.title!=null&&v(d?"a.s-title":"div.s-title",()=>{d&&v("href=",t.home??"/"),x(t.title)})}),G2(t,d,a,p)}),v(()=>{let l=(p.narrow?d?.currentPanel?.actions:void 0)??t.menu;l!=null&&v("div.s-menu",()=>x(l))})})})}),v("div.s-body",()=>{v("div.s-body-inner",()=>{v(()=>{o!=null&&v("max-width:",o)}),v(()=>{a==null||!a.items.length||(v(`nav.s-nav-panel.s-nav-${h}`,t.navAttrs,()=>{h1(a.items)}),v("div.s-nav-sep aria-hidden=true"))}),J2(t,d)}),v(()=>{a!=null&&a.items.length&&e.open&&_2(a,t.navPageAttrs,e,p)})}),v(()=>{t.footer!=null&&v("footer",()=>{v("div.s-bar",()=>{v(()=>{o!=null&&v("max-width:",o)}),x(t.footer)})})})});if(K2(c,p),a!=null||d){let M=m=>{if(m.key!=="Escape"||m.defaultPrevented||V1()||c1())return;let l=c.querySelector(".s-nav-trigger button");if(e.open){m.preventDefault(),e.open=!1,l?.focus();return}if(d&&d.currentPanelIndex>0){m.preventDefault(),d.back();return}let u=c.querySelector(".s-nav-panel");if(u?.offsetParent!=null){let f=u.querySelector("[aria-current=page]")??u.querySelector(".s-menu-item:not([aria-disabled=true])");f&&(m.preventDefault(),f.focus());return}l&&(m.preventDefault(),l.click())};document.addEventListener("keydown",M),v.clean(()=>document.removeEventListener("keydown",M))}return d??void 0}var x1=null;function X2(){x1?.()}function G2(t,a,h,e){v(()=>{if(t.subtitle!=null&&(a==null||N2(a,h,e))){v("div.s-subtitle",()=>x(t.subtitle));return}a?.drawCrumbs()})}function N2(t,a,h){return h.narrow||a==null||t.panels.length>1?!1:a.items.some(e=>typeof e!="string"&&typeof e!="function"&&!("separator"in e)&&e.href!=null&&U2(e.href))}function K2(t,a){if(typeof ResizeObserver>"u")return;let h=new ResizeObserver(e=>{let p=e[0]?.contentBoxSize?.[0],r=p?p.inlineSize:e[0]?.contentRect.width;r!=null&&(a.narrow=r<=r1)});h.observe(t),v.clean(()=>h.disconnect())}function j2(t,a){a1({icon:t.button?.icon??(()=>v(()=>(a.open?Q:d1)())),ariaLabel:t.button?.ariaLabel??"Open navigation",attrs:t.button?.attrs,click:()=>{a.open=!a.open}})}function _2(t,a,h,e){let p=!1,r=()=>{p=!0,h.open=!1},d=v("nav.s-nav-page.s-s.neutral aria-label=Navigation create=s-nav-page-off destroy=s-nav-page-off",a,()=>h1(t.items,r));x1=r,v.clean(()=>{x1===r&&(x1=null)});let o=v.peek($1,"path");v(()=>{$1.path!==o&&!g1($1.path)&&r()});let c=d.closest(".s-main"),M=d.parentElement?.querySelector(":scope > .s-body-inner"),m=M?.querySelector(":scope > main");M?.setAttribute("inert",""),v(()=>{e.narrow||(h.open=!1)}),v.clean(()=>{M?.removeAttribute("inert"),p&&(m&&Q2(m),c?.querySelector(".s-nav-trigger button")?.focus())}),requestAnimationFrame(()=>{document.body.contains(d)&&j(d,".s-menu-item[aria-current=page]")})}function Q2(t){t.classList.add("s-slide-in"),t.offsetWidth,t.classList.remove("s-slide-in")}function J2(t,a){if(a){a.drawColumns();return}let h=v("main",()=>{v("div.s-content",t.contentAttrs,()=>{x(t.content)})});Y2(h)}function Y2(t){if(typeof ResizeObserver>"u")return;let a=()=>t.classList.toggle("s-scroll-y",t.offsetWidth>t.clientWidth),h=new ResizeObserver(a);h.observe(t),t.firstElementChild&&h.observe(t.firstElementChild),a(),v.clean(()=>h.disconnect())}import $ from"aberdeen";$.insertGlobalCss({".s-select_wrap":{"&":"position:relative display:block",select:"w:100% cursor:pointer padding-right:2.2em; appearance:none","&::after":"content: '\u25BE'; position:absolute right:0.7em top:50%; transform: translateY(-50%); pointer-events:none fg:$s-muted font-size:0.85em"}});function t0(t){I(t,(a,h)=>{$("div.s-select_wrap",t.inputAttrs,()=>{$("select.s-input",()=>{_(t,a,h),$("change=",e=>{t.bind&&(t.bind.value=e.target.value)}),$(()=>{let e=typeof t.options=="function"?t.options():t.options,p=t.bind?.value??"";t.placeholder!=null&&$("option",()=>{$("value= disabled=true hidden=true"),p||$("selected=true"),$("#",t.placeholder)});for(let r of e){let d=typeof r=="string"?{value:r,label:r}:{value:r.value,label:r.label??r.value};$("option",()=>{$("value=",d.value),d.value===p&&$("selected=true"),$("#",d.label)})}})})})})}import T from"aberdeen";T.insertGlobalCss({"textarea.s-input":"resize:vertical min-height:3em line-height:1.45","textarea.s-input.s-autoGrow":"resize:none min-height:2.5em overflow-y:hidden"});function a0(t={}){let a=t.autoGrow!==!1;I(t,(h,e)=>{let p=T("textarea.s-input",t.inputAttrs,()=>{a?(T(".s-autoGrow"),T("input=",r=>{Y1(r.currentTarget),t.input&&t.input(r)})):(T("rows=",t.rows??4),T("resize:",t.resize??"vertical"),t.input&&T("input=",t.input)),t.placeholder!=null&&T("placeholder=",t.placeholder),t.value!=null&&!t.bind&&T("value=",t.value),t.change&&T("change=",t.change),_(t,h,e,t.bind)});a&&requestAnimationFrame(()=>Y1(p))})}function Y1(t){t.style.height="auto",t.style.height=`${t.scrollHeight}px`}import D from"aberdeen";D.insertGlobalCss({".s-tt-tip":{"&":"position:fixed z-index:500 max-width:20rem w:max-content padding: 0.3em 0.65em; font-size:0.85em line-height:1.4 pointer-events:none"}});var J=D.proxy(void 0),R=null;typeof window<"u"&&window.addEventListener("scroll",()=>{J.value=void 0},{capture:!0,passive:!0});function h0(t,a,h,e){let r=window.innerWidth,d=window.innerHeight,o=0,c=0;return e==="bottom"?(o=t.left+(t.width-a)/2,c=t.bottom+7,c+h>d-8&&(c=t.top-h-7)):e==="left"?(o=t.left-a-7,c=t.top+(t.height-h)/2,o<8&&(o=t.right+7)):e==="right"?(o=t.right+7,c=t.top+(t.height-h)/2,o+a>r-8&&(o=t.left-a-7)):(o=t.left+(t.width-a)/2,c=t.top-h-7,c<8&&(c=t.bottom+7)),{x:Math.max(8,Math.min(o,r-a-8)),y:Math.max(8,Math.min(c,d-h-8))}}function S1(){R&&clearTimeout(R),R=setTimeout(()=>{J.value=void 0,R=null},100)}F(()=>{let t=J.value;if(!t)return;let{opts:a,anchor:h}=t,e=a.placement??"top",p=D("div.s-tt-tip.s-s.neutral.shadow role=tooltip visibility:hidden",a.attrs,()=>{D("mouseenter=",()=>{R&&(clearTimeout(R),R=null)}),D("mouseleave=",S1),x(a.tip)});requestAnimationFrame(()=>{if(!document.body.contains(p))return;let{x:r,y:d}=h0(h.getBoundingClientRect(),p.offsetWidth,p.offsetHeight,e);p.style.left=r+"px",p.style.top=d+"px",p.style.visibility=""})});function e0(t){let a=h=>{R&&(clearTimeout(R),R=null),J.value={opts:t,anchor:h.currentTarget}};D("mouseenter=",a),D("mouseleave=",S1),D("focusin=",a),D("focusout=",S1),D.clean(()=>{J.value?.opts===t&&(J.value=void 0)})}export{w1 as addContextMenu,e0 as addTooltip,H2 as alert,o2 as autocomplete,i2 as box,O as button,s2 as buttonChooser,X as buttonGroup,l2 as checkbox,f2 as closeFloatingMenu,X2 as closeNav,A2 as confirm,n1 as dialog,M2 as form,O1 as getDarkMode,a1 as iconButton,V1 as isDialogOpen,c1 as isFloatingMenuOpen,W2 as main,b2 as menu,w2 as menuButton,V2 as prompt,s1 as revealInStrip,i1 as scrollStrip,t0 as select,h2 as setDarkMode,b1 as showFloatingMenu,C2 as tabs,a0 as textarea,H1 as textline,l1 as toast};
|
|
1
|
+
import E from"aberdeen";var Y="background: linear-gradient(170deg, color-mix(in oklab, $s-bg, white 9%), color-mix(in oklab, $s-bg, black 9%));",v1="staffa:darkMode",O1=E.proxy({value:a2()});function a2(){try{let t=localStorage.getItem(v1);if(t==="dark")return!0;if(t==="light")return!1}catch{}}function h2(t){O1.value=t;try{t===void 0?localStorage.removeItem(v1):localStorage.setItem(v1,t?"dark":"light")}catch{}}function E1(t=!1){let a=O1.value;return a===void 0&&!t?E.darkMode():a}E(()=>{E1()?E.insertGlobalCss({":root, .s-s.neutral":"--s-bg:#0e0f12 --s-text:#e9eaec",".s-s.neutral":"--s-bg:#191b1f --s-text:#e9eaec",".s-s.neutral .s-s.neutral":"--s-bg:#23262b"}):E.insertGlobalCss({":root, .s-s.neutral":"--s-bg:#eef0f3 --s-text:#1d1f24",".s-s.neutral, .s-s.neutral":"--s-bg:#ffffff --s-text:#1d1f24",".s-s.neutral .s-s.neutral":"--s-bg:#f6f7f9"})});E.setSpacingCssVars(1.1);E.insertGlobalCss({"*, *::before, *::after":"box-sizing:border-box",html:"text-size-adjust:100%",body:"m:0 p:$3 line-height:1.5 font-family: system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif; -webkit-font-smoothing:antialiased background-color:$s-bg text:$s-text",a:"color: $s-link-fg; text-decoration:underline text-underline-offset:2px; transition: color 0.12s, filter 0.12s;","a:hover":"filter: brightness(1.15)","input, button, textarea, select, optgroup":"font:inherit color:inherit","input:where(:not([type=checkbox],[type=radio],[type=range],[type=file],[type=color],[type=image],[type=submit],[type=button],[type=reset],[type=hidden])), textarea, select":"background:$s-bg border: 1px solid $s-faint; r:$s-radius-sm padding: 0.45em 0.65em; max-width:100%","input:where([type=checkbox],[type=radio])":"width:1.15em height:1.15em cursor:pointer","input[type=range]":"appearance:none background:transparent cursor:pointer vertical-align:middle","input[type=range]::-webkit-slider-runnable-track":"height:4px r:99px background:$s-faint","input[type=range]::-moz-range-track":"height:4px r:99px background:$s-faint","input[type=range]::-moz-range-progress":"height:4px r:99px background:$s-accent","input[type=range]::-webkit-slider-thumb":"appearance:none width:16px height:16px margin-top:-6px r:50% background:$s-accent","input[type=range]::-moz-range-thumb":"width:16px height:16px border:0 r:50% background:$s-accent","input[type=file]":"cursor:pointer",progress:"appearance:none border:0 height:6px r:99px background:$s-faint overflow:hidden vertical-align:middle","progress::-webkit-progress-bar":"background:$s-faint r:99px","progress::-webkit-progress-value":"background:$s-accent r:99px","progress::-moz-progress-bar":"background:$s-accent r:99px",meter:"vertical-align:middle",fieldset:"border: 1px solid $s-faint; r:$s-radius-sm padding:$2 min-width:0",legend:"padding: 0 $1; font-weight:600","code, kbd, samp, pre":"font-family: ui-monospace, 'SF Mono', Menlo, Consolas, monospace;",code:"background: color-mix(in oklab, $s-text, $s-bg 86%); padding: 0.12em 0.34em; r:4px font-size:0.9em",pre:"background: color-mix(in oklab, $s-text, $s-bg 92%); p:$3 r: $s-radius; overflow:auto","pre code":"background:transparent p:0","img, svg, video, canvas":"max-width:100% h:auto",hr:"border:0 border-top: 1px solid $s-faint;","::placeholder":"color: $s-muted; opacity:1",":focus-visible":"outline: 2px solid $s-focus; outline-offset:2px",small:"color:$s-muted font-size:0.9em","@media (prefers-reduced-motion: reduce)":{"*, *::before, *::after":"transition-duration: 0.01ms !important; animation-duration: 0.01ms !important; scroll-behavior: auto !important;"},":root":"--s-primary:#00a884 --s-danger:#dc5b41 --s-success:#00a884 --s-warning:#ef6b00 --s-link:#3f8cd8 --s-radius-sm:6px --s-radius:12px --s-radius-lg:18px --s-focus: color-mix(in srgb, $s-primary 38%, transparent); --s-gradient: linear-gradient(135deg, color-mix(in oklab, $s-primary, white 16%), color-mix(in oklab, $s-primary, black 14%));",":root, .s-s.neutral":"--s-accent:$s-primary --s-link-fg:$s-link",".s-s:not(.neutral)":"--s-bg:$s-primary border:0 --s-text:#eee --s-accent:#fff --s-link-fg:#eef --s-muted: color-mix(in srgb, #fff 70%, transparent); --s-faint: color-mix(in srgb, #fff 30%, transparent);",".s-s.danger":"--s-bg:$s-danger",".s-s.success":"--s-bg:$s-success",".s-s.warning":"--s-bg:$s-warning",".s-s.link":"--s-bg:$s-link",".s-s.primary":"--s-bg:$s-primary",":root, .s-s":"--s-muted: color-mix(in oklab, $s-text, $s-bg 42%); --s-faint: color-mix(in oklab, $s-text, $s-bg 80%); color:$s-text accent-color:$s-accent scrollbar-width:thin scrollbar-color: $s-faint transparent;",".s-s, body":Y,".s-s":"r:$s-radius",":where(.s-s.neutral)":"border: 1px solid $s-faint;",".s-s::-webkit-scrollbar, .s-s ::-webkit-scrollbar":"width:10px height:10px",".s-s::-webkit-scrollbar-track, .s-s ::-webkit-scrollbar-track":"background:transparent",".s-s::-webkit-scrollbar-thumb, .s-s ::-webkit-scrollbar-thumb":"background:$s-faint border-radius:99px border: 2px solid transparent; background-clip:padding-box",".s-s.shadow.neutral:not(.s-btn)":"box-shadow: 0 4px 14px rgba(0,0,0,0.13);",".s-s.extra-shadow.neutral:not(.s-btn)":"box-shadow: 0 18px 50px rgba(0,0,0,0.28);",".s-s.shadow:not(.neutral):not(.tonal):not(.outlined)":"box-shadow: 0 4px 14px color-mix(in srgb, $s-bg 30%, transparent);",".s-s.extra-shadow:not(.neutral):not(.tonal):not(.outlined)":"box-shadow: 0 14px 40px color-mix(in srgb, $s-bg 40%, transparent);",".s-s.no-shadow":"box-shadow: none !important;",".s-s:not(.neutral).tonal, .s-s:not(.neutral).outlined":"--s-text:$s-bg --s-accent:$s-bg --s-link-fg:$s-bg --s-faint: color-mix(in srgb, $s-bg 30%, transparent); --s-muted: color-mix(in srgb, $s-bg 70%, transparent);",".s-s:not(.neutral).tonal":"background: color-mix(in srgb, $s-bg 15%, transparent); border: 1px solid $s-faint;",".s-s:not(.neutral).outlined":"background: transparent; border: 1px solid color-mix(in srgb, $s-bg 45%, transparent);",".s-s:not(.neutral) .s-s.tonal, .s-s:not(.neutral) .s-s.outlined":"--s-text:#fff --s-accent:#fff --s-link-fg:#fff "+Y+" border-color: transparent;"});E.insertGlobalCss({".s-preload, .s-preload *, .s-preload *::before, .s-preload *::after":"transition: none !important; animation: none !important;"});if(typeof document<"u"&&typeof requestAnimationFrame=="function"){let t=document.documentElement;t.classList.add("s-preload"),requestAnimationFrame(()=>requestAnimationFrame(()=>t.classList.remove("s-preload")))}E.insertGlobalCss({":disabled, [aria-disabled=true]":"opacity:0.45 filter:saturate(0.6) user-select:none",":disabled, [aria-disabled=true], :disabled *, [aria-disabled=true] *":"pointer-events:none cursor:not-allowed"});var e2="p, ul, ol, dl, blockquote, pre, table, figure, hr, h1, h2, h3, h4, h5, h6";E.insertGlobalCss({[`${e2}`]:{"&":"margin:0","&:not(:first-child)":"margin-top:$3"},"h1, h2, h3, h4, h5, h6":{"&":"line-height:1.15 font-weight:700 text-wrap:balance","&:not(:first-child)":"margin-top:1.4em"},h1:"font-size:2em font-weight:800 letter-spacing:-0.022em",h2:"font-size:1.55em letter-spacing:-0.018em",h3:"font-size:1.3em letter-spacing:-0.011em",h4:"font-size:1.1em",h5:"font-size:0.95em letter-spacing:0.005em",h6:"font-size:0.8em fg:$s-muted text-transform:uppercase letter-spacing:0.07em","ul, ol":{"&":"padding-left:1.5em","> li:not(:first-child), li > &:not(:first-child)":"margin-top:$1"},blockquote:"border-left: 3px solid $s-faint; padding-left: $3; fg: $s-muted",table:"border-collapse:collapse","th, td":"text-align:left padding: $1 $2; border-bottom: 1px solid $s-faint; vertical-align:top",th:"font-weight:600","thead th":"border-bottom: 2px solid $s-faint;",dt:"font-weight:600",dd:"margin-left: 1.5em",figcaption:"fg:$s-muted font-size:0.9em margin-top:$1 text-align:center"});import M from"aberdeen";import q1 from"aberdeen";var r1=640,p2=0;function B(t="s"){return`${t}-${++p2}`}function x(t,...a){t!=null&&(typeof t=="function"?t(...a):q1("rich=",t))}var r2="a[href], button, input, select, textarea, [tabindex]";function j(t,a){let h=p=>p instanceof HTMLElement&&!p.hasAttribute("disabled")&&p.getAttribute("aria-disabled")!=="true"&&p.tabIndex>=0&&p.getClientRects().length>0,e=(a?[...t.querySelectorAll(a)].find(h):void 0)??[...t.querySelectorAll(r2)].find(h);return e?.focus(),e!=null}function F(t){queueMicrotask(()=>q1(t))}import L from"aberdeen";L.insertGlobalCss({".s-field":{"&":"display:flex flex-direction:column gap:$1","> label":"font-weight:600 font-size:0.9em fg:$s-text user-select:none"},".s-req":"fg:$s-danger margin-left:2px",".s-help":"font-size:0.82em fg:$s-muted",".s-error":"font-size:0.82em fg:$s-danger",".s-input":{"&":"w:100% background: color-mix(in oklab, $s-bg, $s-text 4%); color:$s-text border: 1px solid $s-faint; r:$s-radius padding: 0.55em 0.7em; transition: border-color 0.15s, box-shadow 0.15s;","&:hover:not(:disabled)":"border-color: color-mix(in oklab, $s-text, $s-bg 55%);","&:focus-visible":"border-color:$s-accent box-shadow: 0 0 0 3px $s-focus; outline:none","&[aria-invalid=true]":"border-color:$s-danger"}});function I(t,a){let h=t.id??B("field"),e=()=>!!t.error;L("div.s-field",t.attrs,()=>{L(()=>{t.label!=null&&L("label for=",h,()=>{x(t.label),t.required&&L("span.s-req aria-hidden=true #*")})}),a(h,e),L(()=>{t.help!=null&&!t.error&&L("div.s-help",()=>x(t.help))}),L(()=>{t.error&&L("div.s-error role=alert #",t.error)})})}function _(t,a,h,e){L("id=",a),t.name&&L("name=",t.name),L(()=>{t.disabled&&L("disabled=true")}),L(()=>{t.required&&L("aria-required=true")}),L(()=>L("aria-invalid=",h()?"true":"false")),e&&L("bind=",e)}M.insertGlobalCss({".s-ac":{"&":"position:relative","> .s-control":"display:flex flex-wrap:wrap align-items:center gap:$1 background: color-mix(in oklab, $s-bg, $s-text 4%); color:$s-text border: 1px solid $s-faint; r:$s-radius padding: 0.3em 0.4em; cursor:text; transition: border-color 0.15s, box-shadow 0.15s;","> .s-control:hover":"border-color: color-mix(in oklab, $s-text, $s-bg 55%);","> .s-control:focus-within":"border-color:$s-accent box-shadow: 0 0 0 3px $s-focus;","&[aria-invalid=true] > .s-control":"border-color:$s-danger",".s-chip":"display:inline-flex align-items:center gap:$1 font-size:0.85em background: color-mix(in oklab, $s-bg, $s-text 10%); border: 1px solid $s-faint; r:$s-radius padding: 0.1em 0.2em 0.1em 0.5em;",".s-chip > button":"cursor:pointer border:0 background:transparent fg:$s-muted font-size:1.1em line-height:1 padding: 0 0.2em; r:4px",".s-chip > button:hover":"fg:$s-text background:$s-faint",input:"flex:1 min-width:6ch border:0 background:transparent color:inherit outline:none padding:0.25em","> .s-menu":"position:absolute top:100% left:0 right:0 z-index:20 margin-top:4px max-height:15rem overflow-y:auto list-style:none p:$1 margin-bottom:0","> .s-menu li":"margin:0",".s-option":"padding: 0.45em 0.6em; r:6px cursor:pointer transition: background 0.1s;",".s-option[aria-selected=true]":"background: color-mix(in srgb, $s-text 10%, transparent);",".s-add":"fg:$s-accent font-style:italic",".s-empty":"padding: 0.45em 0.6em; fg:$s-muted"}});function d2(t){return typeof t=="string"?{value:t,label:t}:{value:t.value,label:t.label??t.value}}function o2(t){let a=B("ac-menu"),h=M.proxy({query:"",open:!1,active:0}),e=()=>(typeof t.options=="function"?t.options():t.options).map(d2),p=()=>{let n=t.bind?.value;return n==null||n===""?[]:Array.isArray(n)?n:[n]},r=n=>e().find(m=>m.value===n)?.label??n;if(!t.multi){let n=t.bind?M.peek(t.bind,"value"):void 0;typeof n=="string"&&n&&(h.query=M.peek(()=>r(n)))}let d=()=>{let n=new Set(p()),m=e();t.multi&&(m=m.filter(g=>!n.has(g.value)));let y=h.query.trim().toLowerCase();return y&&(m=m.filter(g=>g.label.toLowerCase().includes(y))),m},o=(n,m)=>{if(t.multi){let y=Array.isArray(t.bind?.value)?[...t.bind.value]:[];y.includes(n)||y.push(n),t.bind&&(t.bind.value=y),h.query=""}else t.bind&&(t.bind.value=n),h.query=r(n),h.open=!1;h.active=0,m?.focus()},c=n=>{if(!t.bind)return;let m=t.bind.value??[];t.bind.value=m.filter(y=>y!==n)};I(t,(n,m)=>{M("div.s-ac",t.inputAttrs,()=>{M(()=>M("aria-invalid=",m()?"true":"false"));let y;M("div.s-control",()=>{M("click=",()=>y?.focus()),M(()=>{if(t.multi)for(let g of p())M("span.s-chip",()=>{M("span #",M.peek(()=>r(g))),M("button type=button aria-label=",`Remove ${g}`,()=>{M("#\xD7"),M("click=",s=>{s.stopPropagation(),c(g),y?.focus()})})})}),y=M("input type=text role=combobox autocomplete=off",()=>{M("id=",n,`aria-controls=${a} aria-autocomplete=list`),t.placeholder!=null&&M("placeholder=",t.placeholder),t.disabled&&M("disabled=true"),t.required&&M("aria-required=true"),M("bind=",M.ref(h,"query")),M(()=>M("aria-expanded=",h.open?"true":"false")),M(()=>{let s=d()[h.active];M("aria-activedescendant=",h.open&&s?`${a}-opt-${h.active}`:"")}),M("input=",()=>{h.open=!0,h.active=0}),M("focus=",()=>{h.open=!0}),M("blur=",()=>{setTimeout(()=>f(),150)}),M("keydown=",g=>i(g,y))})}),M(()=>{if(!h.open)return;let g=d(),s=h.query.trim(),b=t.allowCustom!==!1&&s!==""&&!g.some(C=>C.label.toLowerCase()===s.toLowerCase());M("ul.s-menu.s-s.neutral.shadow role=listbox",`id=${a}`,()=>{g.forEach((C,S)=>{M("li.s-option role=option",`id=${a}-opt-${S}`,()=>{M(()=>M("aria-selected=",h.active===S?"true":"false")),M("#",C.label),M("mousedown=",t2=>t2.preventDefault()),M("click=",()=>o(C.value,y)),M("mousemove=",()=>{h.active=S})})}),b&&M("li.s-option.s-add role=option",()=>{M("#",`Add "${s}"`),M("mousedown=",C=>C.preventDefault()),M("click=",()=>o(s,y))}),g.length===0&&!b&&M("li.s-empty #No matches")})}),M(()=>{if(t.name)if(t.multi)for(let g of p())M("input type=hidden",()=>{M("name=",t.name),M("value=",g)});else M("input type=hidden",()=>{M("name=",t.name),M("value=",p()[0]??"")})})})});function i(n,m){let y=d(),g=y.length-1;if(n.key==="ArrowDown")n.preventDefault(),h.open=!0,h.active=Math.min(g,h.active+1);else if(n.key==="ArrowUp")n.preventDefault(),h.active=Math.max(0,h.active-1);else if(n.key==="Enter"){n.preventDefault();let s=y[h.active];s?o(s.value,m):t.allowCustom!==!1&&h.query.trim()?o(h.query.trim(),m):h.open&&(h.open=!1)}else if(n.key==="Escape")h.open&&(n.preventDefault(),h.open=!1,t.multi||(h.query=r(p()[0]??"")));else if(n.key==="Backspace"&&t.multi&&h.query===""){let s=p();s.length&&c(s[s.length-1])}}function f(){h.open=!1,t.multi?h.query="":t.allowCustom!==!1&&h.query.trim()?o(h.query.trim()):h.query=r(p()[0]??"")}}import N from"aberdeen";import c2 from"aberdeen";var t1={size:24,color:"currentColor",strokeWidth:2,cap:"round",join:"round"};function n2(t,a){let h=a.size??t1.size,e=c2('svg.s-icon aria-hidden=true viewBox="0 0 24 24" fill=none',"width=",h,"height=",h,"stroke=",a.color??t1.color,"stroke-width=",a.strokeWidth??t1.strokeWidth,"stroke-linecap=",a.cap??t1.cap,"stroke-linejoin=",a.join??t1.join,a.attrs);e.innerHTML=t}function z(t){return(a={})=>n2(t,a)}var T1=z('<path d="m9 18 6-6-6-6" />');var D1=z('<circle cx="12" cy="12" r="10" />');var R1=z('<path d="M15 3h6v6" /><path d="M10 14 21 3" /><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" />');var Z1=z('<path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71" /><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71" />');var d1=z('<path d="M4 5h16" /><path d="M4 12h16" /><path d="M4 19h16" />');var B1=z('<path d="M12 17v5" /><path d="M15 9.34V7a1 1 0 0 1 1-1 2 2 0 0 0 0-4H7.89" /><path d="m2 2 20 20" /><path d="M9 9v1.76a2 2 0 0 1-1.11 1.79l-1.78.9A2 2 0 0 0 5 15.24V16a1 1 0 0 0 1 1h11" />'),m1=z('<path d="M12 17v5" /><path d="M9 10.76a2 2 0 0 1-1.11 1.79l-1.78.9A2 2 0 0 0 5 15.24V16a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-.76a2 2 0 0 0-1.11-1.79l-1.78-.9A2 2 0 0 1 15 10.76V7a1 1 0 0 1 1-1 2 2 0 0 0 0-4H8a2 2 0 0 0 0 4 1 1 0 0 1 1 1z" />');var F1=z('<path d="M22 2 2 22" />');var Q=z('<path d="M18 6 6 18" /><path d="m6 6 12 12" />');import P from"aberdeen";P.insertGlobalCss({".s-btn":{"&":"display:inline-flex align-items:center justify-content:center gap:$2 font-weight:450 line-height:1.1 white-space:nowrap cursor:pointer text-decoration:none padding: $m2 $m3; transition: background 0.15s, border-color 0.15s, color 0.15s, filter 0.15s, box-shadow 0.15s, transform 0.08s;","&:focus-visible":"outline: 3px solid $s-focus; outline-offset: 1px;","&:hover":"filter: brightness(1.06)","&.tonal:hover, &.outlined:hover":"background: color-mix(in srgb, $s-bg 24%, transparent);","&.neutral:hover":"filter:none background: color-mix(in srgb, $s-text 8%, $s-bg);","> svg":"width:1.25em height:1.25em","&:active:not(:disabled)":"transform: translateY(1px)","&.small, .small > &":"padding: $m1 $m2; font-size:0.85em border-radius:$s-radius-sm","&.large, .large > &":"font-size:1.4em border-radius:$s-radius-lg"},".s-icon-btn":{"&":"display:inline-flex align-items:center justify-content:center flex-shrink:0 width:2rem height:2rem p:0 border:0 background:transparent cursor:pointer fg:$s-muted r:$s-radius-sm line-height:1 font-size:1rem text-decoration:none transition: color 0.12s, background 0.12s;","> svg":"width:1.25em height:1.25em","&:hover:not(:disabled):not([aria-disabled=true])":"fg:$s-text background: color-mix(in srgb, $s-text 10%, transparent);","&:focus-visible":"outline: 3px solid $s-focus; outline-offset:1px","&.small, .small > &":"width:1.6rem height:1.6rem font-size:0.8rem","&.large, .large > &":"width:2.4rem height:2.4rem font-size:1.2rem"}});function a1(t){let a=t.href!=null?"a":"button";P(`${a}.s-icon-btn`,t.attrs,()=>{I1(t),P("aria-label=",t.ariaLabel),x(t.icon)})}function I1(t){t.href!=null?(P("role=button"),t.disabled?P("aria-disabled=true"):P("href=",t.href)):(P("type=",t.type??"button"),t.disabled&&P("disabled=true")),t.click&&!t.disabled&&P("click=",t.click)}function O(t={}){let a=typeof t=="string"||typeof t=="function"?{content:t}:t,h=a.href!=null?"a":"button";P(`${h}.s-btn.s-s.shadow`,a.attrs,()=>{I1(a),a.ariaLabel&&P("aria-label=",a.ariaLabel),x(a.icon),x(a.content)})}N.insertGlobalCss({".s-box":{"&":"display:flex flex-direction:column overflow:hidden r: $s-radius-lg; position:relative","&:not(:first-child)":"margin-top: $3","> header":"display:flex align-items:center gap:$2 padding: $2 $3; border:0 border-bottom: 1px solid $s-faint; r:0 font-weight:600","> footer":"display:flex align-items:center justify-content:flex-end gap:$2 padding: $2 $3; border:0 border-top: 1px solid $s-faint; r:0","> div":"p:$3 gap:$3","> header > .s-box-close":"margin-left:auto","> .s-box-close":"position:absolute top:$2 right:$2 z-index:1"}});function i2(t={}){let a=typeof t=="string"||typeof t=="function"?{content:t}:t;N("section.s-box.s-s.neutral.shadow",a.attrs,()=>{N(()=>{a.header!=null?N("header.s-s.neutral",a.headerAttrs,()=>{x(a.header),typeof a.close=="function"&&U1(a.close)}):typeof a.close=="function"&&U1(a.close)}),N("div",a.contentAttrs,()=>{x(a.content)}),N(()=>{a.footer!=null&&N("footer.s-s.neutral",a.footerAttrs,()=>x(a.footer))})})}function U1(t){a1({icon:Q,ariaLabel:"Close",click:t,attrs:".s-box-close"})}import u1 from"aberdeen";import N1 from"aberdeen";N1.insertGlobalCss({".s-bgroup":{"&":"display:inline-flex align-items:stretch","&.s-spaced":"gap:$2 flex-wrap:wrap","&.s-vertical":"flex-direction:column","&.s-attached":"gap:0","&.s-attached:not(.s-vertical) > .s-btn:not(:first-child)":"margin-left:-1px","&.s-attached:not(.s-vertical) > .s-btn:not(:first-child):not(:last-child)":"r:0","&.s-attached:not(.s-vertical) > .s-btn:first-child:not(:last-child)":"border-top-right-radius:0 border-bottom-right-radius:0","&.s-attached:not(.s-vertical) > .s-btn:last-child:not(:first-child)":"border-top-left-radius:0 border-bottom-left-radius:0","&.s-attached.s-vertical > .s-btn:not(:first-child)":"margin-top:-1px","&.s-attached.s-vertical > .s-btn:not(:first-child):not(:last-child)":"r:0","&.s-attached.s-vertical > .s-btn:first-child:not(:last-child)":"border-bottom-left-radius:0 border-bottom-right-radius:0","&.s-attached.s-vertical > .s-btn:last-child:not(:first-child)":"border-top-left-radius:0 border-top-right-radius:0","&.s-attached > .s-btn:hover, &.s-attached > .s-btn:focus-visible":"z-index:1"}});function W(t={}){let h=`.s-${t.layout??"attached"}${t.vertical?".s-vertical":""}`;N1(`div.s-bgroup${h} role=group`,t.attrs,()=>{if(t.buttons)for(let e of t.buttons)O(e);x(t.content)})}function s2(t){u1(()=>{let a=t.bind.value;W({attrs:t.attrs,buttons:Object.entries(t.options).map(([h,e])=>({content:e,ariaLabel:typeof e=="function"?h:void 0,attrs:a===h?".primary":".neutral",click:()=>{t.bind.value=t.allowDeselect&&a===h?void 0:h}}))})}),t.name&&u1(()=>u1("input type=hidden name=",t.name,"value=",t.bind.value??""))}import k from"aberdeen";k.insertGlobalCss({".s-check":{"&":"display:flex flex-direction:column gap:$1","> label":"display:flex align-items:center gap:$2 cursor:pointer user-select:none","> label:has(input:disabled)":"cursor:not-allowed opacity:0.45 filter:saturate(0.6)",input:"cursor:inherit m:0"}});function l2(t={}){let a=t.id??B("check");k("div.s-check",t.attrs,()=>{k("label for=",a,()=>{k("input type=checkbox",t.inputAttrs,()=>{k("id=",a),t.name&&k("name=",t.name),t.checked&&!t.bind&&k("checked=true"),t.change&&k("change=",t.change),k(()=>{t.disabled&&k("disabled=true")}),k(()=>{t.required&&k("aria-required=true")}),t.bind&&k("bind=",t.bind)}),k(()=>{t.label!=null&&x(t.label),t.required&&k("span.s-req aria-hidden=true #*")})}),k(()=>{t.help!=null&&!t.error&&k("div.s-help",()=>x(t.help))}),k(()=>{t.error&&k("div.s-error role=alert #",t.error)})})}import X from"aberdeen";X.insertGlobalCss({".s-form":{"&":"display:flex flex-direction:column gap:$3","&.grid":"display:grid grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr)); gap:$3","&.grid > .s-wide, &.grid > footer":"grid-column: 1 / -1;","> footer":"display:flex align-items:center justify-content:flex-end gap:$2 flex-wrap:wrap margin-top:$1"}});function M2(t={}){let a=typeof t=="string"||typeof t=="function"?{content:t}:t;X("form.s-form",a.attrs,()=>{X(()=>{X(".grid=",a.layout==="grid")}),X("submit=",h=>{if(h.preventDefault(),a.submit){let e=new FormData(h.target),p={};for(let r of new Set(e.keys())){let d=e.getAll(r);p[r]=d.length===1?d[0]:d}a.submit(p,h)}}),x(a.content),X(()=>{a.actions&&X("footer",a.actionsAttrs,()=>x(a.actions))})})}import v from"aberdeen";import{current as S1,matchCurrent as N2}from"aberdeen/route";import u from"aberdeen";import{matchCurrent as f1,current as y1,go as x2}from"aberdeen/route";u.insertGlobalCss({".s-menu-list":"position:fixed z-index:350 min-width:10rem display:flex flex-direction:column p:$1 r:$s-radius-lg overflow-y:auto max-height:min(80vh,28rem) transition: opacity 0.15s, transform 0.15s;",".s-menu-list.hidden":"opacity:0 pointer-events:none transform:translateY(-6px)",".s-menu-item":"display:flex align-items:center gap:$2 w:100% outline:0 scroll-margin:$2 padding: $m2 0; line-height:1.1 r:$s-radius cursor:pointer text-align:left font-weight:450 font-size:0.9em border:0 background:transparent fg:$s-text text-decoration:none transition: color 0.12s, transform 0.12s, text-shadow 0.12s;",".s-menu-item:focus-visible:not([aria-current=page]), .s-menu-item:hover:not([aria-disabled=true]):not([aria-current=page])":"filter:none color: color-mix(in lab, $s-primary 33%, $s-text);",".s-menu-item[aria-current=page]":"color:$s-accent filter:none",".s-menu-list .s-menu-item":"padding-inline:$2",".s-menu-item[aria-disabled=true]":"opacity:0.45 cursor:not-allowed pointer-events:none",".s-menu-icon":"flex-shrink:0",".s-menu-list .s-menu-icon":"display:flex",".s-menu-list .s-menu-icon > svg":"width:1.25em height:1.25em","hr.s-menu-sep":"border:0 height:1px margin: $1 0.6rem; background: linear-gradient(to right, transparent, $s-faint 18%, $s-faint 82%, transparent);",".s-menu-chevron":"margin-left:auto flex-shrink:0 display:flex transition: transform 0.15s ease;",".s-menu-chevron > svg":"width:1em height:1em",".s-menu-details":{"> summary":"list-style:none","> summary::-webkit-details-marker":"display:none","&::details-content":"interpolate-size:allow-keywords block-size:0 overflow-y:clip transition: block-size 0.15s ease, content-visibility 0.15s allow-discrete;","&[open]::details-content":"block-size:auto","&[open] > summary .s-menu-chevron":"transform:rotate(90deg)"},".s-menu-sub":"display:flex flex-direction:column gap:$1 padding-left:$3",".s-menu-inline":"display:flex flex-direction:column gap:$1"});function h1(t,a){u("keydown=",e=>{if(e.key==="Enter"&&e.target.tagName==="A"){queueMicrotask(()=>a?.());return}if(e.key!=="ArrowDown"&&e.key!=="ArrowUp"&&e.key!=="Home"&&e.key!=="End")return;e.preventDefault();let r=[...e.currentTarget.querySelectorAll(".s-menu-item")].filter(i=>i.getAttribute("aria-disabled")!=="true"&&!u2(i));if(!r.length)return;let d=r.indexOf(document.activeElement),o=e.key==="ArrowUp"?-1:1,c=e.key==="Home"?0:e.key==="End"?r.length-1:d<0?o>0?0:r.length-1:(d+o+r.length)%r.length;r[c].focus()});let h=u.derive(()=>y2(t));W1(t,a,h)}function W1(t,a,h){for(let e of t){if(typeof e=="string"||typeof e=="function"){x(e);continue}if("separator"in e){u("hr.s-menu-sep");continue}e.items?m2(e,a,h):v2(e,a)}}function v2(t,a){let h=!1,e=u(t.href?"a.s-menu-item data-panel=open":"button.s-menu-item type=button",t.attrs,()=>{t.href&&(u("href=",t.href),t.target&&u("target=",t.target),u(()=>{let p=!h;h=!0,f1(t.href)&&(u("aria-current=page"),requestAnimationFrame(()=>e.scrollIntoView({block:"nearest",behavior:p?"instant":"smooth"})))})),t.disabled&&u("aria-disabled=true"),u("click=",p=>{if(t.disabled){p.preventDefault();return}a?.(),t.click?.(p)}),t.icon&&u("span.s-menu-icon",()=>x(t.icon)),x(t.label)})}function m2(t,a,h){let e=t.href??X1(t.items),p=!1,r=e!=null?u.derive(()=>g1(t)?p=!0:h==null||h.value?p=!1:p):null;u("details.s-menu-details",()=>{r&&u(()=>{r.value&&u("open=true")}),u("summary.s-menu-item.s-menu-branch",t.attrs,()=>{t.disabled&&u("aria-disabled=true"),u(()=>{t.href!=null&&f1(t.href)&&u("aria-current=page")}),u("click=",d=>{if(t.disabled){d.preventDefault();return}e!=null&&(d.preventDefault(),f2(e),x2(e)),t.click?.(d)}),t.icon&&u("span.s-menu-icon",()=>x(t.icon)),x(t.label),u("span.s-menu-chevron aria-hidden=true",()=>T1())}),u("div.s-menu-sub",()=>W1(t.items,a,h))})}function u2(t){for(let a=t.closest("details");a;a=a.parentElement&&a.parentElement.closest("details"))if(!a.open&&t.closest("summary")?.parentElement!==a)return!0;return!1}function y2(t){return t.some(a=>typeof a!="string"&&typeof a!="function"&&!("separator"in a)&&g1(a))}function g1(t){if(t.href!=null&&f1(t.href))return!0;for(let a of t.items??[])if(!(typeof a=="string"||typeof a=="function"||"separator"in a)&&g1(a))return!0;return!1}function X1(t){for(let a of t){if(typeof a=="string"||typeof a=="function"||"separator"in a)continue;let h=a.href??(a.items?X1(a.items):void 0);if(h!=null)return h}}var o1=null;function f2(t){try{o1=new URL(t,location.href).pathname.replace(/\/+$/,"")||"/"}catch{o1=null}}function b1(t){return o1!==t?!1:(o1=null,!0)}var U=u.proxy({opts:null});function Z(){let t=U.opts?.anchor;U.opts=null,t?.focus()}function c1(t){let a=U.opts;return a!=null&&(t==null||a.anchor===t)}function g2(t){c1(t)&&Z()}function b2(t,a){let h=t.offsetWidth,e=t.offsetHeight,p=window.innerWidth,r=window.innerHeight,d=4,o=a.left;o+h>p-8&&(o=Math.max(8,a.right-h));let c=a.bottom+d;c+e>r-8&&a.top-e-d>=8&&(c=a.top-e-d),t.style.left=Math.max(8,o)+"px",t.style.top=Math.max(8,c)+"px"}F(()=>{let t=U.opts;if(!t)return;let a=u("div.s-menu-list.s-s.neutral.shadow create=hidden destroy=hidden",t.dropdownAttrs,()=>{h1(t.items,Z)}),h=r=>{let d=r.target;!a.contains(d)&&(t.closeOnAnchorClick||!t.anchor.contains(d))&&Z()},e=r=>{(r.key==="Escape"||r.key==="Tab")&&(r.preventDefault(),Z())},p=u.peek(y1,"path");u(()=>{y1.path!==p&&!b1(y1.path)&&Z()}),document.addEventListener("click",h,!0),document.addEventListener("keydown",e,!0),u.clean(()=>{document.removeEventListener("click",h,!0),document.removeEventListener("keydown",e,!0)}),requestAnimationFrame(()=>{if(!document.body.contains(a))return;let r=t.at?{left:t.at.x,right:t.at.x,top:t.at.y,bottom:t.at.y}:t.anchor.getBoundingClientRect();b2(a,r),j(a,".s-menu-item[aria-current=page]")})});function w2(t){u("nav.s-menu-inline",t.attrs,()=>h1(t.items,t.onLeafSelect))}function w1(t){return U.opts=t,Z}function H1(t){let a=null;u.clean(()=>{U.opts?.anchor===a&&Z()}),u("contextmenu=",h=>{h.preventDefault(),a=h.currentTarget,w1({items:t.items,anchor:a,at:{x:h.clientX,y:h.clientY},closeOnAnchorClick:!0,dropdownAttrs:t.dropdownAttrs})})}function H2(t){let a=null;u.clean(()=>{U.opts?.anchor===a&&Z()}),O({icon:d1,...t.button?.content==null?{ariaLabel:"Open menu"}:null,attrs:".neutral",...t.button,click:h=>{if(a=h.currentTarget,U.opts?.anchor===a){Z();return}w1({items:t.items,anchor:a,dropdownAttrs:t.dropdownAttrs})}})}import H from"aberdeen";import G from"aberdeen";function A1(t={}){I(t,(a,h)=>{G("input.s-input",t.inputAttrs,()=>{G("type=",t.type??"text"),t.placeholder!=null&&G("placeholder=",t.placeholder),t.autocomplete!=null&&G("autocomplete=",t.autocomplete),t.value!=null&&!t.bind&&G("value=",t.value),t.input&&G("input=",t.input),t.change&&G("change=",t.change),_(t,a,h,t.bind)})})}H.insertGlobalCss({".s-backdrop":{"&":"position:fixed inset:0 z-index:200 display:block background: rgba(0,0,0,0.55); transition: opacity 0.4s ease-in-out;","&.hidden":"opacity:0 pointer-events:none"},".s-dialog":{"&":"position:fixed z-index:200 top:50% left:50% display:flex flex-direction:column transform:translate(-50%,-50%) min-width:20rem max-width:min(90vw,44rem) max-height:min(88vh,800px) r: $s-radius-lg; overflow:hidden transition: opacity 0.2s ease-out, transform 0.2s ease-out;","> header":"display:flex align-items:center gap:$2 padding: $2 $3; border:0 border-bottom: 1px solid $s-faint; r:0 font-weight:600 flex-shrink:0","> footer":"display:flex align-items:center justify-content:flex-end gap:$2 padding: $2 $3; border:0 border-top: 1px solid $s-faint; r:0 flex-shrink:0","> div":"p:$3 gap:$3 display:flex flex-direction:column overflow-y:auto flex:1 min-height:0","&.hidden":"opacity:0 pointer-events:none transform: translate(-50%, calc(-50% + 20px)); pointer-events:none"}});var K=H.proxy({}),V1=0,G1=H.derive(()=>{let t=Object.keys(K);if(t.length)return t[t.length-1]});function k1(){return G1.value!=null}F(()=>{H.onEach(K,({resolve:t,opts:a},h)=>{let e=()=>{delete K[h]};H.clean(()=>{a.onClose?.(),t()});let p=H.derive(()=>G1.value!=h);H("div.s-backdrop create=hidden destroy=hidden .hidden=",p,"click=",()=>{a.allowCancel!==!1&&e()});let r=H("div.s-dialog.neutral.s-s.extra-shadow create=hidden destroy=hidden",a.attrs,()=>{H(()=>{a.header!=null&&H("header.s-s.neutral",a.headerAttrs,()=>x(a.header))}),H("div",a.contentAttrs,()=>{x(a.content,e)}),H(()=>{a.footer!=null&&H("footer.s-s.neutral",a.footerAttrs,()=>x(a.footer))})});requestAnimationFrame(()=>{document.body.contains(r)&&j(r)})})});function n1(t){V1||document.addEventListener("keydown",h=>{if(h.key!=="Escape"||h.defaultPrevented)return;let e=H.unproxy(K);for(let p=V1;p>0;p--)if(e[p]){h.preventDefault(),e[p].opts.allowCancel!==!1&&delete K[p];break}});let a=++V1;return t.cancelWithScope!==!1&&H.clean(()=>{delete K[a]}),new Promise(h=>{K[a]={resolve:h,opts:t}})}function A2(t,a={}){return n1({header:"Alert",allowCancel:!0,content:h=>{H("p",()=>{H("#",t)}),W({layout:"spaced",attrs:"align-self:flex-end",content:()=>{O({content:"OK",click:h})}})},...a})}function V2(t,a={}){return new Promise(h=>{let e=!1;n1({header:"Confirm",allowCancel:!0,content:p=>{H("p",()=>{H("#",t)}),W({layout:"spaced",attrs:"align-self:flex-end",content:()=>{O({content:"Cancel",attrs:".neutral",click:p}),O({content:"OK",click:()=>{e=!0,p()}})}})},...a,onClose:()=>{h(e),a.onClose?.()}})})}function k2(t,a="",h={}){return new Promise(e=>{let p=null;n1({header:"Input",allowCancel:!0,content:r=>{H("p",()=>{H("#",t)});let d=H.proxy({value:a});H("form display:contents",()=>{H("submit=",o=>{o.preventDefault(),p=d.value,r()}),A1({bind:H.ref(d,"value")}),W({layout:"spaced",attrs:"align-self:flex-end",content:()=>{O({content:"Cancel",attrs:".neutral",type:"button",click:r}),O({content:"OK",type:"submit"})}})})},...h,onClose:()=>{e(p),h.onClose?.()}})})}import l,{OPAQUE as j1}from"aberdeen";import*as w from"aberdeen/route";import A from"aberdeen";var L2=z('<path d="m15 18-6-6 6-6"/>'),C2=z('<path d="m9 18 6-6-6-6"/>');A.insertGlobalCss({".s-strip":{"&":"position:relative display:flex min-width:0","> .s-strip-row":"display:flex align-items:center flex:1 min-width:0 overflow-x:auto overflow-y:hidden scrollbar-width:none scroll-behavior:smooth","> .s-strip-row::-webkit-scrollbar":"display:none","> .s-strip-btn":"position:absolute top:0 bottom:0 z-index:1 display:none align-items:center justify-content:center width:2.4em border:0 padding:0 cursor:pointer fg:$s-muted transition: color 0.15s;","> .s-strip-btn:hover":"fg:$s-text","> .s-strip-btn-left":"left:0 justify-content:flex-start background: linear-gradient(to right, $s-bg 45%, transparent)","> .s-strip-btn-right":"right:0 justify-content:flex-end background: linear-gradient(to left, $s-bg 45%, transparent)","&.s-can-left > .s-strip-btn-left, &.s-can-right > .s-strip-btn-right":"display:flex"},".s-tabs":{"&":"display:flex flex-direction:column gap:$3",".s-tabbar":"border-bottom: 1px solid $s-faint;",".s-tablist":"gap:$1 align-items:stretch margin-bottom:-1px",".s-tab":"display:inline-flex align-items:center gap:$2 cursor:pointer background:transparent border:0 color: $s-muted; font-weight:600 padding: 0.6em 0.9em; white-space:nowrap border-bottom: 3px solid transparent; transition: color 0.15s, background 0.15s, border-color 0.15s;",".s-tab:hover:not(:disabled), .s-tab[aria-selected=true]":"color: $s-text;",".s-tab:focus-visible":"outline:none box-shadow: inset 0 0 0 2px $s-focus; r: $s-radius;",".s-tab[aria-selected=true]":"border-image: $s-gradient 1;",".s-tabpanel":"display:block"}});function i1(t){A("div.s-strip",t.attrs,()=>{let a=A("div.s-strip-row",t.stripAttrs,()=>x(t.content));K1(a,-1),K1(a,1),$2(a)})}function s1(t){let a=t.parentElement;if(!a||!t.isConnected)return;let h=parseFloat(getComputedStyle(a).fontSize)*2.6,e=t.getBoundingClientRect(),p=a.getBoundingClientRect();e.left<p.left+h?a.scrollBy({left:e.left-p.left-h,behavior:"smooth"}):e.right>p.right-h&&a.scrollBy({left:e.right-p.right+h,behavior:"smooth"})}function z2(t){let a=B("tabs"),h=(r,d)=>r.id??String(d),e=t.bind??A.proxy(h(t.tabs[0]??{label:""},0));t.tabs.length>0&&!t.tabs.some((r,d)=>h(r,d)===A.peek(()=>e.value))&&(e.value=h(t.tabs[0],0));let p=(r,d)=>{r.disabled||(e.value=h(r,d))};A("div.s-tabs",t.attrs,()=>{i1({attrs:".s-tabbar",stripAttrs:".s-tablist role=tablist",content:()=>{t.tabs.forEach((r,d)=>{let o=h(r,d),c=A("button.s-tab type=button role=tab",()=>{A("id=",`${a}-tab-${o}`,"aria-controls=",`${a}-panel-${o}`),A(()=>{let i=e.value===o;A("aria-selected=",i?"true":"false"),A("tabindex=",i?"0":"-1"),i&&requestAnimationFrame(()=>s1(c))}),r.disabled&&A("disabled=true"),A("click=",()=>p(r,d)),A("keydown=",i=>S2(i,t.tabs,d,p)),x(r.icon),x(r.label)})})}}),A("div.s-tabpanel role=tabpanel",t.contentAttrs,()=>{A(()=>{let r=e.value,d=t.tabs.findIndex((c,i)=>h(c,i)===r),o=t.tabs[d]??t.tabs[0];o&&(A("id=",`${a}-panel-${h(o,d)}`,"aria-labelledby=",`${a}-tab-${h(o,d)}`),x(o.content))})})})}function K1(t,a){A(`button.s-strip-btn.s-strip-btn-${a<0?"left":"right"} type=button`,()=>{A("tabindex=-1 aria-hidden=true"),A("click=",()=>t.scrollBy({left:a*t.clientWidth*.8,behavior:"smooth"})),(a<0?L2:C2)({size:"1.1em"})})}function $2(t){let a=t.parentElement;if(!a||typeof ResizeObserver>"u")return;let h=()=>{let r=t.scrollWidth-t.clientWidth;a.classList.toggle("s-can-left",t.scrollLeft>1),a.classList.toggle("s-can-right",t.scrollLeft<r-1)};t.addEventListener("scroll",h,{passive:!0});let e=new ResizeObserver(h);e.observe(t);let p=typeof MutationObserver>"u"?void 0:new MutationObserver(r=>{for(let d of r){for(let o of d.addedNodes)o instanceof Element&&e.observe(o);for(let o of d.removedNodes)o instanceof Element&&e.unobserve(o)}h()});p?.observe(t,{childList:!0});for(let r of Array.from(t.children))e.observe(r);h(),A.clean(()=>{t.removeEventListener("scroll",h),e.disconnect(),p?.disconnect()})}function S2(t,a,h,e){let p=h;if(t.key==="ArrowRight"||t.key==="ArrowDown")p=(h+1)%a.length;else if(t.key==="ArrowLeft"||t.key==="ArrowUp")p=(h-1+a.length)%a.length;else if(t.key==="Home")p=0;else if(t.key==="End")p=a.length-1;else return;t.preventDefault();let r=p>=h?1:-1;for(let d=0;d<a.length;d++){let o=a[p];if(o&&!o.disabled){e(o,p),t.currentTarget?.parentElement?.children[p]?.focus();return}p=(p+r+a.length)%a.length}}import V from"aberdeen";import{grow as P2,shrink as O2}from"aberdeen/transitions";V.insertGlobalCss({".s-toasts":"position:fixed bottom:$3 right:$3 z-index:400 display:flex flex-direction:column gap:$2 pointer-events:none max-width:min(90vw,24rem) w:24rem",".s-toast":{"&":"display:flex align-items:flex-start gap:$2 padding: $3; pointer-events:auto position:relative overflow:hidden",".s-toast-body":"display:flex flex-direction:column gap:$1 flex:1 min-width:0",".s-toast-title":"font-weight:700 line-height:1.3",".s-toast-close":"cursor:pointer border:0 background:transparent fg:$s-muted font-size:1.1em line-height:1 padding: 0 0.15em; r:4px flex-shrink:0 align-self:flex-start",".s-toast-close:hover":"fg:$s-text",".s-toast-close:focus-visible":"outline:none box-shadow: 0 0 0 3px $s-focus; fg:$s-text",".s-toast-progress":"position:absolute bottom:0 left:0 right:0 height:2px background:$s-accent width:100%"}});var E2=0,e1=V.proxy({});F(()=>{V.peek(()=>V.isEmpty(e1))&&V.isEmpty(e1)||V("div.s-toasts",()=>{V.onEach(e1,t=>{let{opts:a,id:h}=t,e=a.type==="danger"||a.type==="warning"?"alert":"status",p=a.type==null||a.type==="neutral"?"neutral":a.type,r=a.duration??6e3,d,o=null,c=()=>{clearTimeout(d),o&&(o.style.transition="none",o.style.width="100%",o.offsetWidth,o.style.transition=`width ${r}ms linear`,o.style.width="0%"),d=setTimeout(()=>L1(h),r)},i=()=>{clearTimeout(d),d=void 0,o&&(o.style.transition="none",o.style.width="100%")};V.clean(()=>clearTimeout(d)),V(`div.s-toast.s-s.${p}.extra-shadow aria-live=polite role=${e}`,"create=",P2,"destroy=",O2,a.attrs,()=>{r>0&&(V("mouseenter=",i),V("mouseleave=",c)),V("div.s-toast-body",()=>{V(()=>{a.title!=null&&V("div.s-toast-title",()=>x(a.title))}),V("div.s-toast-msg",()=>x(a.message))}),V(()=>{a.dismissible!==!1&&V("button.s-toast-close type=button aria-label=Dismiss",()=>{V("#\xD7"),V("click=",()=>L1(h))})}),r>0&&(o=V("div.s-toast-progress"))}),r>0&&requestAnimationFrame(c)})})});function L1(t){delete e1[t]}function l1(t){let a=++E2;return e1[a]={id:a,opts:t},()=>L1(a)}var $1={integer(t){if(!/^(0|-?[1-9]\d*)$/.test(t))return;let a=Number(t);return Number.isSafeInteger(a)?a:void 0}};function q(t){let a=String(t).replace(/\/+$/,"");return a.startsWith("/")||(a=`/${a}`),a}function p1(t){let a=q(t);return a==="/"?[]:a.slice(1).split("/")}function _1(t){let a=p1(t),h=a.map((e,p)=>{if(!e.startsWith("[")||!e.endsWith("]"))return{kind:"lit",value:e};let r=/^\[\.\.\.([A-Za-z_$][\w$]*)\]$/.exec(e);if(r){if(p!==a.length-1)throw new Error(`Staffa: "${e}" must be the last segment of route "${t}"`);return{kind:"rest",name:r[1]}}let d=/^\[([A-Za-z_$][\w$]*)(?:=([A-Za-z_$][\w$]*))?\]$/.exec(e);if(!d)throw new Error(`Staffa: malformed param "${e}" in route "${t}"`);let[,o,c]=d;if(c&&!(c in $1))throw new Error(`Staffa: unknown matcher "${c}" in route "${t}" (known: ${Object.keys($1).join(", ")})`);return{kind:"param",name:o,matcher:c}});return{key:t,segs:h}}function q2(t){try{return decodeURIComponent(t)}catch{return t}}function C1(t,a){let h={};for(let e=0;e<t.segs.length;e++){let p=t.segs[e];if(p.kind==="rest")return e>=a.length?null:(h[p.name]=a.slice(e).join("/"),h);if(e>=a.length)return null;let r=a[e];if(p.kind==="lit"){if(r!==p.value)return null}else if(p.matcher){let d=$1[p.matcher](r);if(d===void 0)return null;h[p.name]=d}else h[p.name]=q2(r)}return t.segs.length===a.length?h:null}var J1=250,T2=300,D2=1280,R2=360,Q1=2;l.insertGlobalCss({":root":`--s-panel-ms:${J1}ms`,".s-panels":"flex:1 min-width:0 min-height:0 position:relative overflow:hidden isolation:isolate "+Y,".s-panel":{"&":"position:absolute top:0 bottom:0 left:0 display:flex flex-direction:column "+Y+" visibility:visible transition: left var(--s-panel-ms) ease, transform var(--s-panel-ms) ease-out, opacity var(--s-panel-ms) linear, visibility 0s;","&.s-panel-sep::before":"content:'' position:absolute left:0 top:0.6rem bottom:0.6rem width:1px z-index:1 background: linear-gradient(to bottom, transparent, $s-faint 18%, $s-faint 82%, transparent);","&.s-panel-enter":"opacity:0 transition:none transform: translateX(8cqw);","&.s-panel-closing":"opacity:0 pointer-events:none transform: translateX(8cqw);","&.s-panel-hidden, &.s-panel-parked":"opacity:0 visibility:hidden transition: left var(--s-panel-ms) ease, transform var(--s-panel-ms) ease-out, opacity var(--s-panel-ms) linear, visibility var(--s-panel-ms);","&.s-panel-hidden":"transform: translateX(-8cqw);","&.s-panel-parked":"transform: translateX(8cqw);"},".s-panel > .s-content":"flex:1 min-height:0 overflow-y:auto overflow-x:hidden p:$3",".s-panel-actions":"display:flex align-items:center justify-content:flex-end gap:$1 flex-shrink:0 padding: $3 $3 0;",".s-crumbs > .s-strip-row":"gap:$m1",".s-crumb":{"&":"flex-shrink:0 font-size:0.85em line-height:1.5 fg:$s-muted text-decoration:none white-space:nowrap max-width:14rem overflow:hidden text-overflow:ellipsis transition: color 0.12s;","&.s-crumb-on":"font-weight:600 fg:$s-text","a&:hover":"filter:none color: color-mix(in lab, $s-primary 33%, $s-text);","svg.s-crumb-pin":"vertical-align:-0.12em margin-right:0.3em opacity:0.8 fill:currentColor","svg.s-crumb-unsaved":"vertical-align:0.08em margin-right:0.3em fill:currentColor"},"svg.s-crumb-sep":"flex-shrink:0 opacity:0.4",".s-main.s-shell-snap .s-panel":"transition:none",".s-panel-loading":{"&":"position:absolute inset:0 display:flex align-items:center justify-content:center gap:$1 pointer-events:none",i:"width:0.5rem height:0.5rem r:50% background:$s-muted opacity:0.45 animation: s-panel-pulse 1s ease-in-out infinite;","i:nth-child(2)":"animation-delay:0.15s","i:nth-child(3)":"animation-delay:0.3s"},"@keyframes s-panel-pulse":{"0%, 100%":"opacity:0.25 transform:scale(0.8)","50%":"opacity:0.7 transform:scale(1)"}});var z1=!1,M1=class{[j1]=!0;compiled;ancestors;opts;$state=l.proxy({live:[],focus:0});$open=l.proxy({});nextOrder=0;containerEl;geom;lastBodyW=-1;layoutQueued=!1;timers=new Set;intent=null;settling=null;lastSeen=null;queued=null;constructor(a){if(z1)throw new Error("Staffa: only one routed S.main() (one with `routes`) can be active at a time");z1=!0,this.opts=a,this.compiled=Object.entries(a.routes).map(([h,e])=>({..._1(h),draw:e})),this.ancestors=Object.entries(a.ancestors??{}).filter(h=>h[1]!=null).map(([h,e])=>({..._1(h),fn:e})),l(()=>{let h=this.computeTarget(),e={...w.current.search},p=w.current.hash;l.peek(()=>{let r=this.lastSeen;if(r&&r.path!==w.current.path){let d=this.$state.live.find(o=>o.path===r.path);d&&(d.search=r.search,d.hash=r.hash)}this.lastSeen={path:w.current.path,search:e,hash:p},this.propose(h),Array.isArray(w.current.state.panels)||Object.assign(w.current.state,this.stateFor({stack:this.paths(),focus:this.$state.focus}))})}),this.interceptLinks(),this.watchTitle(),this.guardTabClose(),l.clean(()=>{for(let h of this.timers)clearTimeout(h);this.timers.clear(),this.queued?.settle(!1),this.queued=null,z1=!1})}resolve(a){let h=p1(a);for(let e of this.compiled){let p=C1(e,h);if(p)return{draw:e.draw,params:p}}return{draw:this.opts.notFound??U2,params:{}}}matches(a){let h=p1(a);return this.compiled.some(e=>C1(e,h)!=null)}deriveStack(a){let h=q(a),e=this.askAncestors(h),p=e?e.map(q):this.prefixesOf(h),r=[];for(let d of p)d!==h&&!r.includes(d)&&this.matches(d)&&r.push(d);return r.push(h),r}askAncestors(a){let h=p1(a);for(let e of this.ancestors){let p=C1(e,h);if(p)return e.fn(p,a)??void 0}}prefixesOf(a){let h=p1(a),e=[];for(let p=1;p<h.length;p++)e.push("/"+h.slice(0,p).join("/"));return e}pinnedIn(a,h){return a.filter(e=>h.includes(e)?!1:this.$state.live.find(p=>p.path===e)?.$panel.pinned===!0)}unsavedAt(a){return this.$state.live.find(h=>h.path===a)?.$panel.unsaved===!0}targetFor(a,h){let e=Array.isArray(h?.panels)?h.panels.map(String):null;if(e){let p=Array.isArray(h.parked)?h.parked.map(String):[],r=q(a),d=new Set([r]),o=i=>i.map(q).filter(f=>!d.has(f)&&!!d.add(f)),c=o(e);return{stack:[...c,r,...o(p)],focus:c.length}}return l.peek(()=>{let p=this.deriveStack(a).slice(0,-1),r=[...p,...this.pinnedIn(this.paths(),[...p,q(a)]),q(a)];return{stack:r,focus:r.length-1}})}computeTarget(){return this.targetFor(w.current.path,w.current.state)}paths(){return this.$state.live.map(a=>a.path)}propose(a){let h=this.$state.live.filter(e=>!a.stack.includes(e.path)&&e.$panel.unsaved).map(e=>e.path);h.length&&(a={stack:[...a.stack,...h],focus:a.focus}),!(B2(this.paths(),a.stack)&&a.focus===this.$state.focus)&&this.commit(a,w.current.nav)}commit(a,h){this.geom=void 0;let e=w.current.state.pinned,p=new Set(Array.isArray(e)?e.map(String):[]),r=new Map(this.$state.live.map(o=>[o.path,o])),d=[];for(let o of a.stack){let c=r.get(o);if(c){r.delete(o),d.push(c);continue}let i=this.createEntry(o,d.length<=a.focus,p.has(o));h!=="load"&&h!=="back"&&(i.enter=!0),d.push(i),this.$open[o]=i}for(let o of r.values())this.beginClose(o);this.$state.live=d,this.$state.focus=Math.min(a.focus,d.length-1),this.scheduleLayout()}createEntry(a,h,e){let{draw:p,params:r}=this.resolve(a),d={[j1]:!0,order:this.nextOrder++,path:a,draw:p,$ui:l.proxy({holding:!1}),maxWidth:"full",width:0};return d.$panel=l.proxy({stack:this,params:r,path:a,width:0,visible:h,pinned:e||void 0,close:()=>this.closePath(d.path)}),d}beginClose(a){a.closing=!0,a.$panel.visible=!1,a.el&&(a.el.style.zIndex=String(Q1*this.$state.live.indexOf(a))),delete this.$open[a.path]}playExit(a,h){if(!a.closing){h.remove();return}h.classList.add("s-panel-closing"),h.setAttribute("inert","");let e=()=>{clearTimeout(p),this.timers.delete(p),h.remove()};h.addEventListener("transitionend",r=>{r.target===h&&r.propertyName==="opacity"&&e()});let p=setTimeout(e,J1+80);this.timers.add(p)}intended(){return this.intent??{stack:this.paths(),focus:this.$state.focus}}stateFor(a){return{panels:a.stack.slice(0,a.focus),parked:a.stack.slice(a.focus+1),pinned:this.pinnedPaths()}}pinnedPaths(){return this.$state.live.filter(a=>a.$panel.pinned).map(a=>a.path)}issue(a,h){return this.intent=a,this.settling?(this.queued?.settle(!1),new Promise(e=>{this.queued={run:h,settle:e}})):this.start(h)}start(a){let h=p=>{this.settling=null;let r=this.queued;return this.queued=null,p&&r?this.start(r.run).then(r.settle,()=>r.settle(!1)):(this.intent=null,r?.settle(!1)),p},e=Promise.resolve(a()).then(h,p=>(console.error(p),h(!1)));return this.settling=e,e}focusAt(a,h,e){let p=this.intended();if(a<0||a>=p.stack.length||a===p.focus)return Promise.resolve(!1);let r={stack:p.stack,focus:a},d=p.stack[a];return this.issue(r,()=>{let o=this.$state.live.find(c=>c.path===d);return w.go({path:d,search:h??o?.search,hash:e??o?.hash,state:this.stateFor(r)})})}back(){return l.peek(()=>{let a=this.intended();return a.focus===a.stack.length-1&&!this.unsavedAt(a.stack[a.focus])?this.closePath(a.stack[a.focus]??""):a.focus===0?Promise.resolve(!1):this.focusAt(a.focus-1)})}closePath(a){return l.peek(()=>{let h=this.intended(),e=h.stack.indexOf(q(a));if(e<0||h.stack.length<2||this.unsavedAt(h.stack[e]))return Promise.resolve(!1);let p=h.stack.filter((i,f)=>f!==e),r=e===h.focus?Math.max(0,e-1):h.focus-(e<h.focus?1:0),d={stack:p,focus:r};if(e===h.focus&&e===h.stack.length-1){let i=this.$state.live.find(m=>m.path===p[r]),f={};i?.search&&(f.search=i.search),i?.hash&&(f.hash=i.hash);let n=p.filter(m=>this.$state.live.find(y=>y.path===m)?.$panel.pinned===!0);return this.issue(d,()=>Promise.resolve(w.back({path:p[r],state:{panels:p.slice(0,r),parked:[]}},f)).then(m=>(m&&(w.current.state.pinned=n),m)))}let o=p[r],c=o!==h.stack[h.focus];return this.issue(d,()=>{let i=c?this.$state.live.find(f=>f.path===o):void 0;return w.go({path:o,search:c?i?.search:{...w.current.search},hash:c?i?.hash:w.current.hash,state:this.stateFor(d)})})})}navigate(a,h,e=!1,p){return l.peek(()=>{let r;try{r=new URL(a,location.href)}catch{return Promise.resolve(!1)}let d=q(r.pathname),o=Object.fromEntries(new URLSearchParams(r.search)),c=r.hash,i=this.intended(),f=p?-1:i.stack.indexOf(d);if(f>=0&&f!==i.focus)return this.focusAt(f,r.search?o:void 0,c||void 0);if(f>=0)return r.search===location.search&&(r.hash||"")===(location.hash||"")?Promise.resolve(!0):this.issue(i,()=>w.go({path:d,search:o,hash:c,state:this.stateFor(i)}));let n=h==null?-1:i.stack.indexOf(h),m=p?p.map(q).filter((s,b,C)=>s!==d&&C.indexOf(s)===b):n<0?this.deriveStack(d).slice(0,-1):i.stack.slice(0,e?n:n+1),y=[...m,...this.pinnedIn(i.stack,[...m,d,e?h:null])],g={stack:[...y,d],focus:y.length};return this.issue(g,()=>w.go({path:d,search:o,hash:c,state:this.stateFor(g)}))})}pushPath(a,h){return l.peek(()=>{let e=this.intended();return this.navigate(a,e.stack[e.focus]??null,h)})}interceptLinks(){w.interceptLinks((a,h)=>{let e=h.getAttribute("data-panel")??this.opts.linkNavigation,p=null;if(e!=="open"){let r=h.closest(".s-panel");r?p=this.$state.live.find(d=>d.el===r)?.path??null:h.closest(".s-panel-origin")&&(p=this.$state.live[this.$state.focus]?.path??null)}return this.navigate(a.href,p,e==="replace"),!0})}get currentPanel(){return this.$state.live[this.$state.focus]?.$panel}get panels(){return this.$state.live.map(a=>a.$panel)}get currentPanelIndex(){return this.$state.focus}pushPanel(a){return this.pushPath(a,!1)}replacePanel(a){return this.pushPath(a,!0)}openPanelStack(a,h){return this.navigate(a,null,!1,h)}closePanel(a){return l.peek(()=>{let h=this.intended();return this.closePath(a??h.stack[h.focus]??"")})}drawCrumbs(){i1({attrs:".s-crumbs role=navigation aria-label=Breadcrumbs",content:()=>{l(()=>{let a=this.panels.map(p=>p.path),h=this.currentPanelIndex,e;for(let p=0;p<a.length;p++){p&&F1({size:"0.85em",attrs:".s-crumb-sep"});let r=this.drawCrumb(a[p],p,p===h);p===h&&(e=r)}requestAnimationFrame(()=>{e&&s1(e)})})}})}drawCrumb(a,h,e){let p=this.$state.live[h];return l(e?"span.s-crumb aria-current=page":"a.s-crumb",()=>{e||l("href=",a),l(()=>{p?.$panel.visible&&l(".s-crumb-on")}),l(()=>{p?.$panel.unsaved&&D1({size:"0.45em",attrs:".s-crumb-unsaved"})}),l(()=>{p?.$panel.pinned&&m1({size:"0.85em",attrs:".s-crumb-pin"})}),l(()=>{l("#",p?.$panel.title??p?.$ui.fallback??(a.split("/").pop()||a))}),H1({items:[{label:"Open in new tab",icon:R1,click:()=>{window.open(a,"_blank","noopener")}},{label:"Copy link",icon:Z1,click:()=>{I2(a)}},{separator:!0},{label:()=>{l(()=>{l("#",p?.$panel.pinned?"Unpin":"Pin")})},icon:()=>{l(()=>{(p?.$panel.pinned?B1:m1)()})},click:()=>{p&&this.togglePin(p)}},{label:"Close",icon:Q,disabled:p?.$panel.unsaved===!0,click:()=>{this.closePath(a)}}]})})}togglePin(a){a.$panel.pinned=!a.$panel.pinned||void 0,w.current.state.pinned=this.pinnedPaths()}watchTitle(){let a=document.title;l(()=>{let h=this.$state.live[this.$state.focus],e=h?.$panel.title??h?.$ui.fallback,p=typeof this.opts.title=="string"?this.opts.title:void 0,r=this.$state.live.some(o=>o.$panel.unsaved),d=e&&p?`${e} \xB7 ${p}`:e||p;d&&(document.title=(r?"\u2022 ":"")+d)}),l.clean(()=>{document.title=a})}guardTabClose(){if(typeof window>"u")return;let a=!1,h=()=>{a=!0},e=p=>{a=!1;let r=this.$state.live.find(o=>o.$panel.unsaved);if(!r)return;p.preventDefault(),p.returnValue=!0;let d=r.path;setTimeout(()=>{if(a)return;let o=this.$state.live.find(c=>c.path===d);o&&!o.$panel.visible&&this.focusAt(this.intended().stack.indexOf(d))},0)};l(()=>{this.$state.live.some(p=>p.$panel.unsaved)&&(window.addEventListener("beforeunload",e),window.addEventListener("pagehide",h),l.clean(()=>{window.removeEventListener("beforeunload",e),window.removeEventListener("pagehide",h)}))})}drawColumns(){let a=l("div.s-panels role=main",()=>{this.containerEl=l(),l.onEach(this.$open,h=>this.drawPanel(h),h=>h.order)});if(typeof ResizeObserver<"u"){let h=new ResizeObserver(()=>this.layout());h.observe(a);let e=a.parentElement?.parentElement;e&&h.observe(e),l.clean(()=>h.disconnect())}l.clean(()=>{this.containerEl===a&&(this.containerEl=void 0)}),this.scheduleLayout()}drawPanel(a){let h;l(()=>{let e=a.$panel.maxWidth;a.maxWidth=e==="half"||e==="screen"?e:"full";let p=this.roomFor(a.maxWidth);p&&(a.width=p,l.peek(a.$panel,"width")!==p&&(a.$panel.width=p),h&&(h.style.width=`${p}px`,this.scheduleLayout()))}),h=l(`section.s-panel${a.width?` w:${a.width}px`:""}`,"destroy=",e=>this.playExit(a,e),()=>{l(()=>this.drawActions(a)),l("div.s-content",()=>{if(a.draw(a.$panel),w.persistScroll(a.path),l.peek(a.$panel,"title")==null){let e=F2(l());e&&l.peek(a.$ui,"fallback")!==e&&(a.$ui.fallback=e)}}),l(()=>{!a.$panel.loading||a.$ui.holding||l("div.s-panel-loading aria-hidden=true",()=>{l("i"),l("i"),l("i")})})}),a.el=h,a.placed=!1,h.style.transition="none",l.clean(()=>{a.el===h&&(a.el=void 0)}),l(()=>{a.$panel.loading,this.scheduleLayout()}),this.scheduleLayout()}drawActions(a){this.opts.$shell.narrow||a.$panel.actions==null||l("div.s-panel-actions",()=>x(a.$panel.actions))}scheduleLayout(){this.layoutQueued||(this.layoutQueued=!0,requestAnimationFrame(()=>{this.layoutQueued=!1,this.layout()}))}measure(){let a=this.containerEl,h=a?.parentElement,e=h?.parentElement;if(!a||!h||!e)return;let p=e.getBoundingClientRect().width;if(!p)return;let r=0;for(let c of h.children)c!==a&&(r+=c.getBoundingClientRect().width);let d=Math.max(0,Math.min(D2,p)-r),o=d/2;return{total:p,chrome:r,half:o>=R2?o:d,full:d,screen:Math.max(0,p-r)}}geometry(){return this.geom??=this.measure()}roomFor(a){return this.geometry()?.[a]??0}layout(){let a=this.containerEl,h=a?.closest(".s-main");if(!a||!h)return;let e=this.$state.live,p=e.length;if(!p||e.some(s=>!s.el))return;this.geom=void 0;let r=this.geometry();if(!r)return;let d=this.opts.columns!=="single",o=this.lastBodyW!==r.total;o&&(this.lastBodyW=r.total,h.classList.add("s-shell-snap"));let c=s=>r[s.maxWidth],i=Math.min(this.$state.focus,p-1),f=i,n=c(e[i]);if(d)for(let s=i-1;s>=0;s--){let b=n+c(e[s]);if(b>r.screen)break;n=b,f=s}let m=Math.min(r.screen,Math.max(r.full,n));for(let s=f;s<=i;s++)e[s].width=c(e[s]);for(let s of e)s.width||(s.width=c(s));h.style.setProperty("--s-shell-w",`${r.chrome+m}px`);let y=[],g=0;for(let s=0;s<p;s++){let b=e[s],C=b.el,S=s>=f&&s<=i;Z2(C,S?g:s>i?m:0,b.width,Q1*s+1),b.$panel.visible!==S&&(b.$panel.visible=S),b.$panel.width!==b.width&&(b.$panel.width=b.width),S&&(g+=b.width),C.classList.toggle("s-panel-sep",S&&s>f),C.classList.toggle("s-panel-hidden",s<f),C.classList.toggle("s-panel-parked",s>i),C.toggleAttribute("inert",!S),!b.placed&&(y.push(b),!b.$panel.loading||b.holdDone?b.$ui.holding=!1:b.$ui.holding||(b.$ui.holding=!0,this.holdEnter(b)),b.enter&&S&&C.classList.add("s-panel-enter"))}(y.length||o)&&a.offsetWidth,o&&h.classList.remove("s-shell-snap");for(let s of y)s.$ui.holding||(s.el.style.transition="",s.el.classList.remove("s-panel-enter"),s.enter=!1,s.placed=!0)}holdEnter(a){let h=setTimeout(()=>{this.timers.delete(h),a.holdDone=!0,a.$ui.holding&&(a.$ui.holding=!1,this.scheduleLayout())},T2);this.timers.add(h)}};function Z2(t,a,h,e){t.style.left=`${a}px`,t.style.width=`${h}px`,t.style.zIndex=String(e)}function B2(t,a){return t.length===a.length&&t.every((h,e)=>h===a[e])}function F2(t){let a=document.createTreeWalker(t,NodeFilter.SHOW_TEXT);for(let h=a.nextNode();h;h=a.nextNode()){let e=h.textContent.trim();if(e)return e.length>48?`${e.slice(0,47).trimEnd()}\u2026`:e}}async function I2(t){let a=new URL(t,location.href).href;try{await navigator.clipboard.writeText(a),l1({message:"Link copied."})}catch{l1({message:"Couldn't copy the link.",type:"danger"})}}function U2(t){l("p fg:$s-muted",()=>l("#",`No panel at ${t.path}`))}v.insertGlobalCss({".s-main":{"&":"display:flex flex-direction:column min-height:100vh max-height:100vh container-type:inline-size","body > &":"margin: calc(-1 * $3)","> header":"border:0 border-bottom: 1px solid $s-faint; r:0 position:sticky top:0 z-index:10","> footer":"border-top: 1px solid $s-faint; fg:$s-muted","> header > .s-bar, > footer > .s-bar":"display:flex align-items:center width:100% margin-inline:auto gap:$3 padding: $2 $3;","> header .s-logo, > header .s-nav-trigger":"display:flex align-items:center flex-shrink:0","> header .s-nav-trigger":"margin-left:-0.375rem","> header .s-logo":"font-size:1.4em background: $s-gradient; -webkit-background-clip:text; background-clip:text; color:transparent;","> header .s-titles":"display:flex flex-direction:column min-width:5rem flex: 0 1 auto;","> header .s-subtitle":"fg:$s-muted font-size:0.85em line-height:1.5 overflow:hidden text-overflow:ellipsis white-space:nowrap","> header .s-title":"font-weight:800 font-size:1.1em line-height:1.2 overflow:hidden text-overflow:ellipsis white-space:nowrap letter-spacing:-0.01em background: $s-gradient; -webkit-background-clip:text; background-clip:text; color:transparent; width:fit-content max-width:100%","> header a.s-logo, > header a.s-title":"text-decoration:none filter:none cursor:pointer","> header .s-menu":"display:flex align-items:center justify-content:flex-end gap:$2 flex: 1 1 auto; min-width:0",".s-body":"flex:1 overflow:hidden display:flex flex-direction:row min-height:0 justify-content:center position:relative",".s-body-inner":"flex:1 min-width:0 display:flex flex-direction:row min-height:0","&.s-nav-right .s-body-inner":"flex-direction:row-reverse",".s-nav-sep":"width:1px flex-shrink:0 align-self:stretch margin: 0.6rem 0; border:0 background: linear-gradient(to bottom, transparent, $s-faint 18%, $s-faint 82%, transparent);",".s-body main":"flex:1 min-width:0 min-height:0 overflow-x:hidden overflow-y:auto display:flex flex-direction:column transition: transform var(--s-panel-ms) ease;",".s-body main.s-slide-in":"transform: translateX(100%); transition:none",".s-body main > .s-content":"width:100% flex:1 p:$3",".s-body main.s-scroll-y":"margin-right:$3","&.s-routed > .s-body > .s-body-inner":"max-width: var(--s-shell-w, 100%);","&.s-routed > header > .s-bar":"max-width: var(--s-shell-w, 100%);","&.s-routed > footer > .s-bar":"max-width: var(--s-shell-w, 100%);","&.s-routed > .s-body > .s-body-inner, &.s-routed > header > .s-bar, &.s-routed > footer > .s-bar":"transition: max-width var(--s-panel-ms) ease;","&.s-routed.s-shell-snap > .s-body > .s-body-inner, &.s-routed.s-shell-snap > header > .s-bar, &.s-routed.s-shell-snap > footer > .s-bar":"transition:none"},".s-nav-panel":{"&":"display:flex flex-direction:column overflow-y:auto flex-shrink:0 max-width:228px padding:$3 gap:$1"},".s-nav-page":{"&":"position:absolute inset:0 z-index:5 display:flex flex-direction:column overflow-y:auto overscroll-behavior:contain border:0 r:0 padding:$2 gap:$1 transition: transform var(--s-panel-ms) ease;","&.s-nav-page-off":"transform:translateX(-100%) pointer-events:none",".s-menu-item":"padding: $2 $3; min-height:3rem font-size:1.05em gap:$3"},[`@container (max-width: ${r1}px)`]:{".s-main .s-nav-panel, .s-main .s-nav-sep":"display:none",".s-main > header > .s-bar":"gap:$1 padding: $1 $2;",".s-content > .s-box":"margin-inline: calc(-1 * $3); r:0 border-inline:0",".s-main .s-body main.s-scroll-y":"margin-right:0"}});function W2(t={}){let a=t.nav,h=t.navPosition??"left",e=v.proxy({open:!1}),p=v.proxy({narrow:typeof document<"u"&&document.documentElement.clientWidth<=r1}),r=t.routes;if(r!=null&&t.content!=null)throw new Error("Staffa: S.main() takes either `content` or `routes`, not both");let d=r?new M1({routes:r,notFound:t.notFound,ancestors:t.ancestors,columns:t.columns,linkNavigation:t.linkNavigation,title:t.title,$shell:p}):null,o=d&&t.home!==null?t.home??"/":null,c=d?null:t.maxWidth,i=v(`div.s-main${d?".s-routed":""}`,t.attrs,()=>{v(()=>{a==null||!a.items.length||v(`.s-nav-${h}`)}),v(()=>{(d!=null||t.title!=null||t.subtitle!=null||t.logo!=null||t.menu!=null||a!=null&&a.items.length>0)&&v("header.s-s.neutral",t.topbarAttrs,()=>{v("div.s-bar",()=>{v(()=>{c!=null&&v("max-width:",c)}),v(()=>{if(p.narrow&&a!=null&&a.items.length){v("div.s-nav-trigger",()=>_2(a,e));return}t.logo!=null&&v(o!=null?"a.s-logo aria-label=Home":"div.s-logo",()=>{o!=null&&v("href=",o),x(t.logo)})}),v("div.s-titles",()=>{v(()=>{t.title!=null&&v(o!=null?"a.s-title":"div.s-title",()=>{o!=null&&v("href=",o),x(t.title)})}),G2(t,d,a,p)}),v(()=>{let n=p.narrow?d?.currentPanel?.actions:void 0,m=n??t.menu;m!=null&&v(`div.s-menu${n!=null?".s-panel-origin":""}`,()=>x(m))})})})}),v("div.s-body",()=>{v("div.s-body-inner",()=>{v(()=>{c!=null&&v("max-width:",c)}),v(()=>{a==null||!a.items.length||(v(`nav.s-nav-panel.s-nav-${h}`,t.navAttrs,()=>{h1(a.items)}),v("div.s-nav-sep aria-hidden=true"))}),Y2(t,d)}),v(()=>{a!=null&&a.items.length&&e.open&&Q2(a,t.navPageAttrs,e,p)})}),v(()=>{t.footer!=null&&v("footer",()=>{v("div.s-bar",()=>{v(()=>{c!=null&&v("max-width:",c)}),x(t.footer)})})})});if(j2(i,p),a!=null||d){let f=n=>{if(n.key!=="Escape"||n.defaultPrevented||k1()||c1())return;let m=i.querySelector(".s-nav-trigger button");if(e.open){n.preventDefault(),e.open=!1,m?.focus();return}if(d&&d.currentPanelIndex>0){n.preventDefault(),d.back();return}let y=i.querySelector(".s-nav-panel");if(y?.offsetParent!=null){let g=y.querySelector("[aria-current=page]")??y.querySelector(".s-menu-item:not([aria-disabled=true])");g&&(n.preventDefault(),g.focus());return}m&&(n.preventDefault(),m.click())};document.addEventListener("keydown",f),v.clean(()=>document.removeEventListener("keydown",f))}return d??void 0}var x1=null;function X2(){x1?.()}function G2(t,a,h,e){v(()=>{if(t.subtitle!=null&&(a==null||K2(a,h,e))){v("div.s-subtitle",()=>x(t.subtitle));return}a?.drawCrumbs()})}function K2(t,a,h){return h.narrow||a==null||t.panels.length>1?!1:a.items.some(e=>typeof e!="string"&&typeof e!="function"&&!("separator"in e)&&e.href!=null&&N2(e.href))}function j2(t,a){if(typeof ResizeObserver>"u")return;let h=new ResizeObserver(e=>{let p=e[0]?.contentBoxSize?.[0],r=p?p.inlineSize:e[0]?.contentRect.width;r!=null&&(a.narrow=r<=r1)});h.observe(t),v.clean(()=>h.disconnect())}function _2(t,a){a1({icon:t.button?.icon??(()=>v(()=>(a.open?Q:d1)())),ariaLabel:t.button?.ariaLabel??"Open navigation",attrs:t.button?.attrs,click:()=>{a.open=!a.open}})}function Q2(t,a,h,e){let p=!1,r=()=>{p=!0,h.open=!1},d=v("nav.s-nav-page.s-s.neutral aria-label=Navigation create=s-nav-page-off destroy=s-nav-page-off",a,()=>h1(t.items,r));x1=r,v.clean(()=>{x1===r&&(x1=null)});let o=v.peek(S1,"path");v(()=>{S1.path!==o&&!b1(S1.path)&&r()});let c=d.closest(".s-main"),i=d.parentElement?.querySelector(":scope > .s-body-inner"),f=i?.querySelector(":scope > main");i?.setAttribute("inert",""),v(()=>{e.narrow||(h.open=!1)}),v.clean(()=>{i?.removeAttribute("inert"),p&&(f&&J2(f),c?.querySelector(".s-nav-trigger button")?.focus())}),requestAnimationFrame(()=>{document.body.contains(d)&&j(d,".s-menu-item[aria-current=page]")})}function J2(t){t.classList.add("s-slide-in"),t.offsetWidth,t.classList.remove("s-slide-in")}function Y2(t,a){if(a){a.drawColumns();return}let h=v("main",()=>{v("div.s-content",t.contentAttrs,()=>{x(t.content)})});t0(h)}function t0(t){if(typeof ResizeObserver>"u")return;let a=()=>t.classList.toggle("s-scroll-y",t.offsetWidth>t.clientWidth),h=new ResizeObserver(a);h.observe(t),t.firstElementChild&&h.observe(t.firstElementChild),a(),v.clean(()=>h.disconnect())}import $ from"aberdeen";$.insertGlobalCss({".s-select_wrap":{"&":"position:relative display:block",select:"w:100% cursor:pointer padding-right:2.2em; appearance:none","&::after":"content: '\u25BE'; position:absolute right:0.7em top:50%; transform: translateY(-50%); pointer-events:none fg:$s-muted font-size:0.85em"}});function a0(t){I(t,(a,h)=>{$("div.s-select_wrap",t.inputAttrs,()=>{$("select.s-input",()=>{_(t,a,h),$("change=",e=>{t.bind&&(t.bind.value=e.target.value)}),$(()=>{let e=typeof t.options=="function"?t.options():t.options,p=t.bind?.value??"";t.placeholder!=null&&$("option",()=>{$("value= disabled=true hidden=true"),p||$("selected=true"),$("#",t.placeholder)});for(let r of e){let d=typeof r=="string"?{value:r,label:r}:{value:r.value,label:r.label??r.value};$("option",()=>{$("value=",d.value),d.value===p&&$("selected=true"),$("#",d.label)})}})})})})}import T from"aberdeen";T.insertGlobalCss({"textarea.s-input":"resize:vertical min-height:3em line-height:1.45","textarea.s-input.s-autoGrow":"resize:none min-height:2.5em overflow-y:hidden"});function h0(t={}){let a=t.autoGrow!==!1;I(t,(h,e)=>{let p=T("textarea.s-input",t.inputAttrs,()=>{a?(T(".s-autoGrow"),T("input=",r=>{Y1(r.currentTarget),t.input&&t.input(r)})):(T("rows=",t.rows??4),T("resize:",t.resize??"vertical"),t.input&&T("input=",t.input)),t.placeholder!=null&&T("placeholder=",t.placeholder),t.value!=null&&!t.bind&&T("value=",t.value),t.change&&T("change=",t.change),_(t,h,e,t.bind)});a&&requestAnimationFrame(()=>Y1(p))})}function Y1(t){t.style.height="auto",t.style.height=`${t.scrollHeight}px`}import D from"aberdeen";D.insertGlobalCss({".s-tt-tip":{"&":"position:fixed z-index:500 max-width:20rem w:max-content padding: 0.3em 0.65em; font-size:0.85em line-height:1.4 pointer-events:none"}});var J=D.proxy(void 0),R=null;typeof window<"u"&&window.addEventListener("scroll",()=>{J.value=void 0},{capture:!0,passive:!0});function e0(t,a,h,e){let r=window.innerWidth,d=window.innerHeight,o=0,c=0;return e==="bottom"?(o=t.left+(t.width-a)/2,c=t.bottom+7,c+h>d-8&&(c=t.top-h-7)):e==="left"?(o=t.left-a-7,c=t.top+(t.height-h)/2,o<8&&(o=t.right+7)):e==="right"?(o=t.right+7,c=t.top+(t.height-h)/2,o+a>r-8&&(o=t.left-a-7)):(o=t.left+(t.width-a)/2,c=t.top-h-7,c<8&&(c=t.bottom+7)),{x:Math.max(8,Math.min(o,r-a-8)),y:Math.max(8,Math.min(c,d-h-8))}}function P1(){R&&clearTimeout(R),R=setTimeout(()=>{J.value=void 0,R=null},100)}F(()=>{let t=J.value;if(!t)return;let{opts:a,anchor:h}=t,e=a.placement??"top",p=D("div.s-tt-tip.s-s.neutral.shadow role=tooltip visibility:hidden",a.attrs,()=>{D("mouseenter=",()=>{R&&(clearTimeout(R),R=null)}),D("mouseleave=",P1),x(a.tip)});requestAnimationFrame(()=>{if(!document.body.contains(p))return;let{x:r,y:d}=e0(h.getBoundingClientRect(),p.offsetWidth,p.offsetHeight,e);p.style.left=r+"px",p.style.top=d+"px",p.style.visibility=""})});function p0(t){let a=h=>{R&&(clearTimeout(R),R=null),J.value={opts:t,anchor:h.currentTarget}};D("mouseenter=",a),D("mouseleave=",P1),D("focusin=",a),D("focusout=",P1),D.clean(()=>{J.value?.opts===t&&(J.value=void 0)})}export{H1 as addContextMenu,p0 as addTooltip,A2 as alert,o2 as autocomplete,i2 as box,O as button,s2 as buttonChooser,W as buttonGroup,l2 as checkbox,g2 as closeFloatingMenu,X2 as closeNav,V2 as confirm,n1 as dialog,M2 as form,E1 as getDarkMode,a1 as iconButton,k1 as isDialogOpen,c1 as isFloatingMenuOpen,W2 as main,w2 as menu,H2 as menuButton,k2 as prompt,s1 as revealInStrip,i1 as scrollStrip,a0 as select,h2 as setDarkMode,w1 as showFloatingMenu,z2 as tabs,h0 as textarea,A1 as textline,l1 as toast};
|
package/package.json
CHANGED
package/skill/MainOptions.md
CHANGED
|
@@ -55,7 +55,9 @@ top bar link, as every logo on the web does. Defaults to `"/"`; set it
|
|
|
55
55
|
when your home screen lives elsewhere. It's an ordinary link, so the
|
|
56
56
|
usual rules apply: a home that is already open in the stack — its first
|
|
57
57
|
panel, usually — is returned to, closing nothing, and one that isn't is
|
|
58
|
-
opened the way a nav item would be.
|
|
58
|
+
opened the way a nav item would be. Pass `null` to link neither — for a
|
|
59
|
+
`title` or `logo` slot holding interactive content of its own, which
|
|
60
|
+
can't sit inside a link. Routed mode only.
|
|
59
61
|
|
|
60
62
|
**Type:** `string`
|
|
61
63
|
|
|
@@ -200,14 +202,28 @@ answer without drawing anything. From code,
|
|
|
200
202
|
|
|
201
203
|
**Type:** `AncestorTable<NoInfer<R>>`
|
|
202
204
|
|
|
203
|
-
### mainOptions.
|
|
205
|
+
### mainOptions.columns · member
|
|
204
206
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
207
|
+
How many panels are *shown* at a time. `"auto"` (the default) shows as
|
|
208
|
+
many columns, side by side, as comfortably fit, ending at the current
|
|
209
|
+
panel; `"single"` shows only the current panel, however wide the screen
|
|
210
|
+
— the phone experience at every size (the nav sidebar still sits beside
|
|
211
|
+
it). Only the display differs: the stack, the breadcrumbs, the URL,
|
|
212
|
+
Escape and the back button behave identically in both. Routed mode only.
|
|
209
213
|
|
|
210
|
-
**Type:** `
|
|
214
|
+
**Type:** `"auto" | "single"`
|
|
215
|
+
|
|
216
|
+
### mainOptions.linkNavigation · member
|
|
217
|
+
|
|
218
|
+
What a link *without* a `data-panel` attribute does — the per-link
|
|
219
|
+
attribute always wins. `"push"` (the default) opens the target on top of
|
|
220
|
+
the panel the link sits in; `"replace"` opens it in that panel's place;
|
|
221
|
+
`"open"` gives it its own stack, the way a nav item does. With `"open"`
|
|
222
|
+
every click replaces the content as a whole — which, with flat routes,
|
|
223
|
+
is the conventional sidebar-and-content app: one pane, swapped on every
|
|
224
|
+
click, the crumb line simply naming it. Routed mode only.
|
|
225
|
+
|
|
226
|
+
**Type:** `"push" | "replace" | "open"`
|
|
211
227
|
|
|
212
228
|
### mainOptions.footer · member
|
|
213
229
|
|
package/skill/MenuItem.md
CHANGED
|
@@ -31,6 +31,11 @@ Render as a link (`<a>`) pointing here. Pairs naturally with
|
|
|
31
31
|
`interceptLinks()` — the item is highlighted automatically when the URL
|
|
32
32
|
matches, and scrolled into view if its list had scrolled it out.
|
|
33
33
|
|
|
34
|
+
Under routed `S.main()` the link carries `data-panel=open`: a menu row
|
|
35
|
+
leads elsewhere in the app, so its target arrives with its own stack of
|
|
36
|
+
columns rather than on top of whatever panel the menu was drawn in. Pass
|
|
37
|
+
`attrs: "data-panel=push"` for a row that should stack instead.
|
|
38
|
+
|
|
34
39
|
**Type:** `string`
|
|
35
40
|
|
|
36
41
|
### menuItem.target · member
|
|
@@ -54,11 +59,13 @@ Aberdeen attr/style string on the item element.
|
|
|
54
59
|
### menuItem.items · member
|
|
55
60
|
|
|
56
61
|
Child entries, which turn the item into a collapsible **branch** of a
|
|
57
|
-
tree. Only the branch holding the current page is expanded; navigate
|
|
58
|
-
and it folds back up.
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
it
|
|
62
|
+
tree. Only the branch holding the current page is expanded; navigate to
|
|
63
|
+
another page in the menu and it folds back up. (Navigating to a page the
|
|
64
|
+
menu doesn't hold *anywhere* leaves every fold as it was: there is no
|
|
65
|
+
better answer to fold up to.) Clicking a branch *selects* rather than
|
|
66
|
+
toggles: it follows the item's own `href`, or failing that the first
|
|
67
|
+
linked leaf below it — which is what expands it. A branch with no link
|
|
68
|
+
anywhere below it falls back to plain open/close toggling.
|
|
62
69
|
|
|
63
70
|
Expanding is not selecting: a branch click never counts as picking an
|
|
64
71
|
item (see `onLeafSelect` on `menu`), so on a phone the nav stays up
|
package/skill/SKILL.md
CHANGED
|
@@ -215,7 +215,7 @@ function drawTask($panel: S.Panel<{ taskId: number }>) {
|
|
|
215
215
|
|
|
216
216
|
On a wide screen the title becomes the stack's last crumb and the Save button sits in a quiet strip at the top of the column. On a phone the crumb is still there and Save moves into the top bar, where the app menu was. Nothing in your code measures the viewport, and no screen is written twice.
|
|
217
217
|
|
|
218
|
-
**The breadcrumbs are the navigation.** The top bar's second line writes the open panels out as breadcrumbs — `Projects / Trackle / Task 42` — with the panels currently on screen in bold. Clicking an earlier crumb goes back to it *without closing anything*: the panels right of it stay open, parked just past the viewport's right edge, and clicking their crumbs brings them back. Browsing the stack is free — it's opening a *new* panel that closes the panels after the one it came from. The app's name and logo link to the app's home (the `home` option, `/` by default), going back to it when it's already open and opening it when it isn't. A stack too long for the bar scrolls sideways, in an `S.scrollStrip` like the tab strip's.
|
|
218
|
+
**The breadcrumbs are the navigation.** The top bar's second line writes the open panels out as breadcrumbs — `Projects / Trackle / Task 42` — with the panels currently on screen in bold. Clicking an earlier crumb goes back to it *without closing anything*: the panels right of it stay open, parked just past the viewport's right edge, and clicking their crumbs brings them back. Browsing the stack is free — it's opening a *new* panel that closes the panels after the one it came from. The app's name and logo link to the app's home (the `home` option, `/` by default; `null` links neither), going back to it when it's already open and opening it when it isn't. A stack too long for the bar scrolls sideways, in an `S.scrollStrip` like the tab strip's.
|
|
219
219
|
|
|
220
220
|
That line is the `subtitle`'s while the stack has nothing to add: one panel open, reachable from a nav item that is already highlighted in a visible sidebar. Otherwise the stack takes it, since it is then the only thing naming the screen.
|
|
221
221
|
|
|
@@ -226,7 +226,7 @@ A crumb can also wear a **●**: the panel holds unsaved work, and nothing will
|
|
|
226
226
|
| `$panel` | what it does |
|
|
227
227
|
| --- | --- |
|
|
228
228
|
| `title` | Names the screen: its breadcrumb, and `document.title` while it's the current panel. A panel that sets none borrows the first line of text in its own body — good enough for a crumb, but say it yourself. |
|
|
229
|
-
| `actions` | The screen's buttons or menu. In the column's chrome while several columns fit; in the top bar (taking the app `menu`'s place) once the shell is narrow. |
|
|
229
|
+
| `actions` | The screen's buttons or menu. In the column's chrome while several columns fit; in the top bar (taking the app `menu`'s place) once the shell is narrow. A link among them builds on this panel at both widths. |
|
|
230
230
|
|
|
231
231
|
Two deliberate rules there. `actions` are the screen's *verbs* — Save, Delete, Share, a menu — not a second way out: going back is the crumbs' job, at every width, and there is no back button even on a phone. And **`title` names the screen; it does not draw a heading** — a screen that wants its name in its own body writes it there, where it owns the typography.
|
|
232
232
|
|
|
@@ -296,7 +296,8 @@ Search params and the `#hash` belong to the current panel only. Anything another
|
|
|
296
296
|
|
|
297
297
|
**A few more things.**
|
|
298
298
|
|
|
299
|
-
- `
|
|
299
|
+
- `columns: "single"` shows only the current panel, however wide the screen — the phone experience at every size. Only the display changes: the URL, the back button, unsaved panels and the panels' own close buttons all behave the same.
|
|
300
|
+
- `linkNavigation` sets what a link *without* a `data-panel` attribute does: `"push"` (the default), `"replace"`, or `"open"`. With `"open"` every click replaces the content as a whole — which, with flat routes, is the conventional sidebar-and-content app: one pane, swapped on every click, the crumb line simply naming it.
|
|
300
301
|
- Only one routed `S.main()` can be mounted at a time; a second one throws — the URL is global, so two of them would fight over it. Nothing else is global: the stack belongs to its shell, and each handler gets its own `$panel`, since several panels are alive at once.
|
|
301
302
|
- Navigating with `aberdeen/route`'s own `go()` works — an unsaved panel survives it too — but, like a link from outside a panel, it builds the whole stack from the path. So prefer the stack's own methods. A navigation guard your app registered with `route.setGuard` (an auth redirect, say) keeps working untouched: Staffa registers none of its own.
|
|
302
303
|
- Deep links need your static server to serve the app for unknown paths (the usual SPA fallback). For `http-server` that's `-P`, as in the demo command below.
|
package/src/components/main.ts
CHANGED
|
@@ -50,9 +50,11 @@ export interface MainOptions<R = Routes> {
|
|
|
50
50
|
* when your home screen lives elsewhere. It's an ordinary link, so the
|
|
51
51
|
* usual rules apply: a home that is already open in the stack — its first
|
|
52
52
|
* panel, usually — is returned to, closing nothing, and one that isn't is
|
|
53
|
-
* opened the way a nav item would be.
|
|
53
|
+
* opened the way a nav item would be. Pass `null` to link neither — for a
|
|
54
|
+
* `title` or `logo` slot holding interactive content of its own, which
|
|
55
|
+
* can't sit inside a link. Routed mode only.
|
|
54
56
|
*/
|
|
55
|
-
home?: string;
|
|
57
|
+
home?: string | null;
|
|
56
58
|
/**
|
|
57
59
|
* The app's own chrome, at the trailing end of the top bar: an account
|
|
58
60
|
* button, a global search box, a settings menu. It may grow into the bar's
|
|
@@ -187,12 +189,24 @@ export interface MainOptions<R = Routes> {
|
|
|
187
189
|
// `$panel` would quietly degrade to `any` (see the note on `main` below).
|
|
188
190
|
ancestors?: AncestorTable<NoInfer<R>>;
|
|
189
191
|
/**
|
|
190
|
-
*
|
|
191
|
-
*
|
|
192
|
-
*
|
|
193
|
-
*
|
|
192
|
+
* How many panels are *shown* at a time. `"auto"` (the default) shows as
|
|
193
|
+
* many columns, side by side, as comfortably fit, ending at the current
|
|
194
|
+
* panel; `"single"` shows only the current panel, however wide the screen
|
|
195
|
+
* — the phone experience at every size (the nav sidebar still sits beside
|
|
196
|
+
* it). Only the display differs: the stack, the breadcrumbs, the URL,
|
|
197
|
+
* Escape and the back button behave identically in both. Routed mode only.
|
|
194
198
|
*/
|
|
195
|
-
|
|
199
|
+
columns?: "auto" | "single";
|
|
200
|
+
/**
|
|
201
|
+
* What a link *without* a `data-panel` attribute does — the per-link
|
|
202
|
+
* attribute always wins. `"push"` (the default) opens the target on top of
|
|
203
|
+
* the panel the link sits in; `"replace"` opens it in that panel's place;
|
|
204
|
+
* `"open"` gives it its own stack, the way a nav item does. With `"open"`
|
|
205
|
+
* every click replaces the content as a whole — which, with flat routes,
|
|
206
|
+
* is the conventional sidebar-and-content app: one pane, swapped on every
|
|
207
|
+
* click, the crumb line simply naming it. Routed mode only.
|
|
208
|
+
*/
|
|
209
|
+
linkNavigation?: "push" | "replace" | "open";
|
|
196
210
|
/** Footer content, pinned below the scroll area. */
|
|
197
211
|
footer?: Slot;
|
|
198
212
|
/**
|
|
@@ -256,9 +270,11 @@ A.insertGlobalCss({
|
|
|
256
270
|
"> footer": "border-top: 1px solid $s-faint; fg:$s-muted",
|
|
257
271
|
// The bar reads `[leading] [title] …spacer… [trailing]`. The spacer is the
|
|
258
272
|
// trailing slot's own growth: it takes the free space and right-aligns
|
|
259
|
-
// itself in it, which is what lets a search box live there.
|
|
260
|
-
//
|
|
261
|
-
//
|
|
273
|
+
// itself in it, which is what lets a search box live there. When the two
|
|
274
|
+
// compete, the title truncates first — but only down to a floor, past
|
|
275
|
+
// which the trailing slot shrinks instead: a wide search box must not
|
|
276
|
+
// starve the titles to nothing (the crumb strip's overlay buttons would
|
|
277
|
+
// escape their zero-width strip, over the ☰ beside it).
|
|
262
278
|
"> header > .s-bar, > footer > .s-bar": "display:flex align-items:center width:100% margin-inline:auto gap:$3 padding: $2 $3;",
|
|
263
279
|
"> header .s-logo, > header .s-nav-trigger": "display:flex align-items:center flex-shrink:0",
|
|
264
280
|
// The ☰ is a glyph in a 2rem hit area, so it carries ~6px of its own
|
|
@@ -266,7 +282,7 @@ A.insertGlobalCss({
|
|
|
266
282
|
// up with the bar's edge and with the stack below.
|
|
267
283
|
"> header .s-nav-trigger": "margin-left:-0.375rem",
|
|
268
284
|
"> header .s-logo": "font-size:1.4em background: $s-gradient; -webkit-background-clip:text; background-clip:text; color:transparent;",
|
|
269
|
-
"> header .s-titles": "display:flex flex-direction:column min-width:
|
|
285
|
+
"> header .s-titles": "display:flex flex-direction:column min-width:5rem flex: 0 1 auto;",
|
|
270
286
|
// Same font-size and line-height as `.s-crumb`, because in routed mode the
|
|
271
287
|
// two take turns on this line (see `drawSecondLine`): a different height
|
|
272
288
|
// would jog the whole bar as they swap.
|
|
@@ -277,7 +293,7 @@ A.insertGlobalCss({
|
|
|
277
293
|
// which their classes then provide. (`filter:none` keeps the global
|
|
278
294
|
// `a:hover` brighten off the gradient text.)
|
|
279
295
|
"> header a.s-logo, > header a.s-title": "text-decoration:none filter:none cursor:pointer",
|
|
280
|
-
"> header .s-menu": "display:flex align-items:center justify-content:flex-end gap:$2 flex: 1
|
|
296
|
+
"> header .s-menu": "display:flex align-items:center justify-content:flex-end gap:$2 flex: 1 1 auto; min-width:0",
|
|
281
297
|
// Body always wraps <main> (with or without a sidebar) so max-width centering
|
|
282
298
|
// and scrollbar alignment work identically in both cases.
|
|
283
299
|
// .s-body centres .s-body-inner; .s-body-inner caps the content to maxWidth.
|
|
@@ -467,11 +483,15 @@ export function main<R extends RouteTable<R>>(opts: MainOptions<R> = {}): PanelS
|
|
|
467
483
|
routes,
|
|
468
484
|
notFound: opts.notFound,
|
|
469
485
|
ancestors: opts.ancestors,
|
|
470
|
-
|
|
486
|
+
columns: opts.columns,
|
|
487
|
+
linkNavigation: opts.linkNavigation,
|
|
471
488
|
title: opts.title,
|
|
472
489
|
$shell,
|
|
473
490
|
})
|
|
474
491
|
: null;
|
|
492
|
+
// Where the brand mark and the app's name link — or nowhere, when the app
|
|
493
|
+
// said `home: null` (a title slot holding a control of its own, say).
|
|
494
|
+
const homeHref = ctl && opts.home !== null ? opts.home ?? "/" : null;
|
|
475
495
|
// Routed mode caps the shell to the ensemble width the layout engine publishes,
|
|
476
496
|
// rather than to `maxWidth`.
|
|
477
497
|
const capWidth = ctl ? null : opts.maxWidth;
|
|
@@ -527,8 +547,8 @@ export function main<R extends RouteTable<R>>(opts: MainOptions<R> = {}): PanelS
|
|
|
527
547
|
// twinned with the app's name beside it — a real link, so it
|
|
528
548
|
// has an address to hover, middle-click and copy, and a click
|
|
529
549
|
// runs the shell's usual link rules.
|
|
530
|
-
A(
|
|
531
|
-
if (
|
|
550
|
+
A(homeHref != null ? "a.s-logo aria-label=Home" : "div.s-logo", () => {
|
|
551
|
+
if (homeHref != null) A("href=", homeHref);
|
|
532
552
|
drawSlot(opts.logo);
|
|
533
553
|
});
|
|
534
554
|
});
|
|
@@ -541,8 +561,8 @@ export function main<R extends RouteTable<R>>(opts: MainOptions<R> = {}): PanelS
|
|
|
541
561
|
A("div.s-titles", () => {
|
|
542
562
|
A(() => {
|
|
543
563
|
if (opts.title == null) return;
|
|
544
|
-
A(
|
|
545
|
-
if (
|
|
564
|
+
A(homeHref != null ? "a.s-title" : "div.s-title", () => {
|
|
565
|
+
if (homeHref != null) A("href=", homeHref);
|
|
546
566
|
drawSlot(opts.title);
|
|
547
567
|
});
|
|
548
568
|
});
|
|
@@ -551,10 +571,13 @@ export function main<R extends RouteTable<R>>(opts: MainOptions<R> = {}): PanelS
|
|
|
551
571
|
|
|
552
572
|
// Trailing: on a narrow shell the screen's own verbs win the space,
|
|
553
573
|
// and a screen with none of its own leaves the app's chrome up.
|
|
574
|
+
// Promoted actions are marked as the current panel's own chrome
|
|
575
|
+
// (`.s-panel-origin`), so a link among them still builds on that
|
|
576
|
+
// panel — see `interceptLinks` in panels.ts.
|
|
554
577
|
A(() => {
|
|
555
578
|
const actions = $shell.narrow ? ctl?.currentPanel?.actions : undefined;
|
|
556
579
|
const slot = actions ?? opts.menu;
|
|
557
|
-
if (slot != null) A(
|
|
580
|
+
if (slot != null) A(`div.s-menu${actions != null ? ".s-panel-origin" : ""}`, () => drawSlot(slot));
|
|
558
581
|
});
|
|
559
582
|
});
|
|
560
583
|
});
|
package/src/components/menu.ts
CHANGED
|
@@ -23,6 +23,11 @@ export interface MenuItem {
|
|
|
23
23
|
* Render as a link (`<a>`) pointing here. Pairs naturally with
|
|
24
24
|
* `interceptLinks()` — the item is highlighted automatically when the URL
|
|
25
25
|
* matches, and scrolled into view if its list had scrolled it out.
|
|
26
|
+
*
|
|
27
|
+
* Under routed `S.main()` the link carries `data-panel=open`: a menu row
|
|
28
|
+
* leads elsewhere in the app, so its target arrives with its own stack of
|
|
29
|
+
* columns rather than on top of whatever panel the menu was drawn in. Pass
|
|
30
|
+
* `attrs: "data-panel=push"` for a row that should stack instead.
|
|
26
31
|
*/
|
|
27
32
|
href?: string;
|
|
28
33
|
/** `target` for the link (`_blank`, etc.). Only meaningful with `href`. */
|
|
@@ -33,11 +38,13 @@ export interface MenuItem {
|
|
|
33
38
|
attrs?: Attributes;
|
|
34
39
|
/**
|
|
35
40
|
* Child entries, which turn the item into a collapsible **branch** of a
|
|
36
|
-
* tree. Only the branch holding the current page is expanded; navigate
|
|
37
|
-
* and it folds back up.
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
* it
|
|
41
|
+
* tree. Only the branch holding the current page is expanded; navigate to
|
|
42
|
+
* another page in the menu and it folds back up. (Navigating to a page the
|
|
43
|
+
* menu doesn't hold *anywhere* leaves every fold as it was: there is no
|
|
44
|
+
* better answer to fold up to.) Clicking a branch *selects* rather than
|
|
45
|
+
* toggles: it follows the item's own `href`, or failing that the first
|
|
46
|
+
* linked leaf below it — which is what expands it. A branch with no link
|
|
47
|
+
* anywhere below it falls back to plain open/close toggling.
|
|
41
48
|
*
|
|
42
49
|
* Expanding is not selecting: a branch click never counts as picking an
|
|
43
50
|
* item (see `onLeafSelect` on {@link menu}), so on a phone the nav stays up
|
|
@@ -238,14 +245,20 @@ export function drawMenu(items: MenuEntry[], onLeafSelect?: () => void): void {
|
|
|
238
245
|
els[next].focus();
|
|
239
246
|
});
|
|
240
247
|
|
|
241
|
-
|
|
248
|
+
// Whether the current page is in this menu *at all*, shared by every branch
|
|
249
|
+
// below: a navigation to a page the menu doesn't hold must leave the folds
|
|
250
|
+
// alone (see `drawBranch`), and that is a fact about the whole menu, which
|
|
251
|
+
// no branch can tell on its own. Derived, so the branches re-run only when
|
|
252
|
+
// the answer flips — not on every navigation between two held pages.
|
|
253
|
+
const $menuHasCurrent = A.derive(() => anyCurrent(items));
|
|
254
|
+
drawEntries(items, onLeafSelect, $menuHasCurrent);
|
|
242
255
|
}
|
|
243
256
|
|
|
244
|
-
function drawEntries(items: MenuEntry[], onLeafSelect?: () => void): void {
|
|
257
|
+
function drawEntries(items: MenuEntry[], onLeafSelect?: () => void, $menuHasCurrent?: { value: boolean }): void {
|
|
245
258
|
for (const entry of items) {
|
|
246
259
|
if (typeof entry === "string" || typeof entry === "function") { drawSlot(entry); continue; }
|
|
247
260
|
if ("separator" in entry) { A("hr.s-menu-sep"); continue; }
|
|
248
|
-
if (entry.items) drawBranch(entry, onLeafSelect);
|
|
261
|
+
if (entry.items) drawBranch(entry, onLeafSelect, $menuHasCurrent);
|
|
249
262
|
else drawLeaf(entry, onLeafSelect);
|
|
250
263
|
}
|
|
251
264
|
}
|
|
@@ -254,7 +267,15 @@ function drawLeaf(entry: MenuItem, onLeafSelect?: () => void): void {
|
|
|
254
267
|
// Whether the aria-current scope below has run before: it re-runs on
|
|
255
268
|
// every navigation, and only a *later* one should animate the reveal.
|
|
256
269
|
let drawn = false;
|
|
257
|
-
|
|
270
|
+
// `data-panel=open` because a menu row is navigation, not a link in the
|
|
271
|
+
// content: it leads somewhere else in the app, and the panel it was clicked
|
|
272
|
+
// from isn't the context to keep. A floating dropdown (portalled to the
|
|
273
|
+
// body) and `S.main()`'s sidebar are outside every panel and behave this way
|
|
274
|
+
// already; saying it outright makes an inline `menu()` — which may well sit
|
|
275
|
+
// *inside* a panel — behave the same wherever it's drawn. `attrs` comes
|
|
276
|
+
// after, so an item that really does want to stack can say
|
|
277
|
+
// `attrs: "data-panel=push"`.
|
|
278
|
+
const itemEl = A(entry.href ? "a.s-menu-item data-panel=open" : "button.s-menu-item type=button", entry.attrs, () => {
|
|
258
279
|
if (entry.href) {
|
|
259
280
|
A("href=", entry.href);
|
|
260
281
|
if (entry.target) A("target=", entry.target);
|
|
@@ -298,12 +319,22 @@ function drawLeaf(entry: MenuItem, onLeafSelect?: () => void): void {
|
|
|
298
319
|
* linked branch is open exactly while it holds the current page. Only a branch
|
|
299
320
|
* with no link anywhere below it keeps the native open/close toggle.
|
|
300
321
|
*/
|
|
301
|
-
function drawBranch(entry: MenuItem, onLeafSelect?: () => void): void {
|
|
322
|
+
function drawBranch(entry: MenuItem, onLeafSelect?: () => void, $menuHasCurrent?: { value: boolean }): void {
|
|
302
323
|
const href = entry.href ?? firstLeafHref(entry.items!);
|
|
303
324
|
// The route-derived fold state, as a derived boolean so the attribute scope
|
|
304
325
|
// below re-runs only when the answer flips — not on every navigation that
|
|
305
|
-
// merely moves *between* pages inside the branch.
|
|
306
|
-
|
|
326
|
+
// merely moves *between* pages inside the branch. When the current page is
|
|
327
|
+
// nowhere in the menu, nothing has an opinion, and the fold simply keeps
|
|
328
|
+
// its last state — folding everything up would answer a question nobody
|
|
329
|
+
// asked with a menu that forgot where the user was.
|
|
330
|
+
let last = false;
|
|
331
|
+
const $open = href != null
|
|
332
|
+
? A.derive(() => {
|
|
333
|
+
if (containsCurrent(entry)) return (last = true);
|
|
334
|
+
if ($menuHasCurrent == null || $menuHasCurrent.value) return (last = false);
|
|
335
|
+
return last;
|
|
336
|
+
})
|
|
337
|
+
: null;
|
|
307
338
|
|
|
308
339
|
A("details.s-menu-details", () => {
|
|
309
340
|
// For a no-link branch this scope has no subscriptions and never re-runs,
|
|
@@ -333,7 +364,7 @@ function drawBranch(entry: MenuItem, onLeafSelect?: () => void): void {
|
|
|
333
364
|
A("span.s-menu-chevron aria-hidden=true", () => chevronRight());
|
|
334
365
|
});
|
|
335
366
|
|
|
336
|
-
A("div.s-menu-sub", () => drawEntries(entry.items!, onLeafSelect));
|
|
367
|
+
A("div.s-menu-sub", () => drawEntries(entry.items!, onLeafSelect, $menuHasCurrent));
|
|
337
368
|
});
|
|
338
369
|
}
|
|
339
370
|
|
|
@@ -353,6 +384,12 @@ function foldedAway(el: HTMLElement): boolean {
|
|
|
353
384
|
return false;
|
|
354
385
|
}
|
|
355
386
|
|
|
387
|
+
/** Whether any page linked anywhere in `items` is the current one. */
|
|
388
|
+
function anyCurrent(items: MenuEntry[]): boolean {
|
|
389
|
+
return items.some((entry) =>
|
|
390
|
+
typeof entry !== "string" && typeof entry !== "function" && !("separator" in entry) && containsCurrent(entry));
|
|
391
|
+
}
|
|
392
|
+
|
|
356
393
|
/** Whether `entry`'s own page, or any page linked below it, is the current one. */
|
|
357
394
|
function containsCurrent(entry: MenuItem): boolean {
|
|
358
395
|
if (entry.href != null && matchCurrent(entry.href)) return true;
|
package/src/components/panels.ts
CHANGED
|
@@ -668,8 +668,10 @@ export interface PanelStackOptions {
|
|
|
668
668
|
notFound?: RouteHandler<{}>;
|
|
669
669
|
/** What to open beneath a path that arrives cold. See {@link MainOptions.ancestors}. */
|
|
670
670
|
ancestors?: Record<string, AncestorsHandler | undefined>;
|
|
671
|
-
/**
|
|
672
|
-
|
|
671
|
+
/** How many panels are shown at a time. See {@link MainOptions.columns}. */
|
|
672
|
+
columns?: "auto" | "single";
|
|
673
|
+
/** What a bare link does. See {@link MainOptions.linkNavigation}. */
|
|
674
|
+
linkNavigation?: "push" | "replace" | "open";
|
|
673
675
|
/** The shell's own title, used as the suffix of `document.title`. */
|
|
674
676
|
title?: unknown;
|
|
675
677
|
/**
|
|
@@ -1443,16 +1445,29 @@ export class PanelStackController implements PanelStack {
|
|
|
1443
1445
|
* close guards run in `checkChange` when our navigation reaches the router.
|
|
1444
1446
|
*
|
|
1445
1447
|
* `data-panel` names which of the three {@link PanelStack} navigations the
|
|
1446
|
-
* click is: `push
|
|
1448
|
+
* click is: `push`, `replace`, or `open`, which drops the
|
|
1447
1449
|
* originating panel so the target arrives with its own stack beneath it,
|
|
1448
|
-
* exactly as a nav item's link does.
|
|
1450
|
+
* exactly as a nav item's link does. A link that doesn't say gets the
|
|
1451
|
+
* shell's {@link PanelStackOptions.linkNavigation} (`push` by default);
|
|
1452
|
+
* an unrecognised value is a `push`.
|
|
1449
1453
|
*/
|
|
1450
1454
|
private interceptLinks(): void {
|
|
1451
1455
|
route.interceptLinks((url, anchor) => {
|
|
1452
|
-
const mode = anchor.getAttribute("data-panel");
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
+
const mode = anchor.getAttribute("data-panel") ?? this.opts.linkNavigation;
|
|
1457
|
+
let origin: string | null = null;
|
|
1458
|
+
if (mode !== "open") {
|
|
1459
|
+
const panel = anchor.closest<HTMLElement>(".s-panel");
|
|
1460
|
+
if (panel) {
|
|
1461
|
+
origin = this.$state.live.find((entry) => entry.el === panel)?.path ?? null;
|
|
1462
|
+
} else if (anchor.closest(".s-panel-origin")) {
|
|
1463
|
+
// The current panel's actions, promoted into the top bar on a
|
|
1464
|
+
// narrow shell (see main.ts), sit outside every `.s-panel` — but
|
|
1465
|
+
// they are still the current panel's own chrome, so a link among
|
|
1466
|
+
// them builds on that panel, exactly as it does at full width.
|
|
1467
|
+
origin = this.$state.live[this.$state.focus]?.path ?? null;
|
|
1468
|
+
}
|
|
1469
|
+
}
|
|
1470
|
+
void this.navigate(url.href, origin, mode === "replace");
|
|
1456
1471
|
return true;
|
|
1457
1472
|
});
|
|
1458
1473
|
}
|
|
@@ -1883,7 +1898,7 @@ export class PanelStackController implements PanelStack {
|
|
|
1883
1898
|
const geom = this.geometry();
|
|
1884
1899
|
if (!geom) return;
|
|
1885
1900
|
|
|
1886
|
-
const stacking = this.opts.
|
|
1901
|
+
const stacking = this.opts.columns !== "single";
|
|
1887
1902
|
|
|
1888
1903
|
// A window resize (or the very first pass) must be adopted instantly —
|
|
1889
1904
|
// geometry tracking the window through a 450ms transition reads as lag,
|