staffa 0.10.1 → 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 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
- - `stacking: false` shows only the current panel, however wide the screen. Everything else behaves the same: the URL, the back button, unsaved panels, and the panels' own close buttons.
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. Routed mode only.
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
- * Set `false` to show only the current panel, however wide the screen (the
179
- * nav sidebar still sits beside it). Everything else behaves the same: the
180
- * URL, the back button, unsaved panels, and the panels' own close buttons.
181
- * This only changes how many you see. Defaults to `true`.
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
- stacking?: boolean;
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
  /**
@@ -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. It doesn't
29
- // shrink, and the title doesso the title is what truncates when the two
30
- // compete, and the app's chrome stays usable.
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:0 flex: 0 1 auto;",
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 0 auto;",
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
- stacking: opts.stacking,
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(ctl ? "a.s-logo aria-label=Home" : "div.s-logo", () => {
246
- if (ctl)
247
- A("href=", opts.home ?? "/");
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(ctl ? "a.s-title" : "div.s-title", () => {
261
- if (ctl)
262
- A("href=", opts.home ?? "/");
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("div.s-menu", () => drawSlot(slot));
283
+ A(`div.s-menu${actions != null ? ".s-panel-origin" : ""}`, () => drawSlot(slot));
275
284
  });
276
285
  });
277
286
  });
@@ -34,11 +34,13 @@ export interface MenuItem {
34
34
  attrs?: Attributes;
35
35
  /**
36
36
  * Child entries, which turn the item into a collapsible **branch** of a
37
- * tree. Only the branch holding the current page is expanded; navigate away
38
- * and it folds back up. Clicking a branch *selects* rather than toggles: it
39
- * follows the item's own `href`, or failing that the first linked leaf
40
- * below it which is what expands it. A branch with no link anywhere below
41
- * it falls back to plain open/close toggling.
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.
42
44
  *
43
45
  * Expanding is not selecting: a branch click never counts as picking an
44
46
  * item (see `onLeafSelect` on {@link menu}), so on a phone the nav stays up
@@ -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
- drawEntries(items, onLeafSelect);
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
  }
@@ -193,12 +199,24 @@ function drawLeaf(entry, onLeafSelect) {
193
199
  * linked branch is open exactly while it holds the current page. Only a branch
194
200
  * with no link anywhere below it keeps the native open/close toggle.
195
201
  */
196
- function drawBranch(entry, onLeafSelect) {
202
+ function drawBranch(entry, onLeafSelect, $menuHasCurrent) {
197
203
  const href = entry.href ?? firstLeafHref(entry.items);
198
204
  // The route-derived fold state, as a derived boolean so the attribute scope
199
205
  // below re-runs only when the answer flips — not on every navigation that
200
- // merely moves *between* pages inside the branch.
201
- const $open = href != null ? A.derive(() => containsCurrent(entry)) : null;
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;
202
220
  A("details.s-menu-details", () => {
203
221
  // For a no-link branch this scope has no subscriptions and never re-runs,
204
222
  // which is exactly what leaves the native toggle alone.
@@ -233,7 +251,7 @@ function drawBranch(entry, onLeafSelect) {
233
251
  drawSlot(entry.label);
234
252
  A("span.s-menu-chevron aria-hidden=true", () => chevronRight());
235
253
  });
236
- A("div.s-menu-sub", () => drawEntries(entry.items, onLeafSelect));
254
+ A("div.s-menu-sub", () => drawEntries(entry.items, onLeafSelect, $menuHasCurrent));
237
255
  });
238
256
  }
239
257
  /**
@@ -248,6 +266,10 @@ function foldedAway(el) {
248
266
  }
249
267
  return false;
250
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
+ }
251
273
  /** Whether `entry`'s own page, or any page linked below it, is the current one. */
252
274
  function containsCurrent(entry) {
253
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
- /** Set `false` to show only the current panel, however much room there is. */
254
- stacking?: boolean;
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` (the default), `replace`, or `open`, which drops the
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. An unrecognised value is a `push`.
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` (the default), `replace`, or `open`, which drops the
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. An unrecognised value is a `push`.
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
- const panel = mode === "open" ? null : anchor.closest(".s-panel");
957
- const origin = panel ? this.$state.live.find((entry) => entry.el === panel) : undefined;
958
- void this.navigate(url.href, origin?.path ?? null, mode === "replace");
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.stacking !== false;
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.
@@ -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 data-panel=open":"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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "staffa",
3
- "version": "0.10.1",
3
+ "version": "0.11.0",
4
4
  "description": "An opinionated component library for the Aberdeen reactive UI library.",
5
5
  "license": "ISC",
6
6
  "author": "",
@@ -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. Routed mode only.
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.stacking · member
205
+ ### mainOptions.columns · member
204
206
 
205
- Set `false` to show only the current panel, however wide the screen (the
206
- nav sidebar still sits beside it). Everything else behaves the same: the
207
- URL, the back button, unsaved panels, and the panels' own close buttons.
208
- This only changes how many you see. Defaults to `true`.
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:** `boolean`
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
@@ -59,11 +59,13 @@ Aberdeen attr/style string on the item element.
59
59
  ### menuItem.items · member
60
60
 
61
61
  Child entries, which turn the item into a collapsible **branch** of a
62
- tree. Only the branch holding the current page is expanded; navigate away
63
- and it folds back up. Clicking a branch *selects* rather than toggles: it
64
- follows the item's own `href`, or failing that the first linked leaf
65
- below it which is what expands it. A branch with no link anywhere below
66
- it falls back to plain open/close toggling.
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.
67
69
 
68
70
  Expanding is not selecting: a branch click never counts as picking an
69
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
- - `stacking: false` shows only the current panel, however wide the screen. Everything else behaves the same: the URL, the back button, unsaved panels, and the panels' own close buttons.
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.
@@ -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. Routed mode only.
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
- * Set `false` to show only the current panel, however wide the screen (the
191
- * nav sidebar still sits beside it). Everything else behaves the same: the
192
- * URL, the back button, unsaved panels, and the panels' own close buttons.
193
- * This only changes how many you see. Defaults to `true`.
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
- stacking?: boolean;
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. It doesn't
260
- // shrink, and the title doesso the title is what truncates when the two
261
- // compete, and the app's chrome stays usable.
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:0 flex: 0 1 auto;",
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 0 auto;",
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
- stacking: opts.stacking,
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(ctl ? "a.s-logo aria-label=Home" : "div.s-logo", () => {
531
- if (ctl) A("href=", opts.home ?? "/");
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(ctl ? "a.s-title" : "div.s-title", () => {
545
- if (ctl) A("href=", opts.home ?? "/");
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("div.s-menu", () => drawSlot(slot));
580
+ if (slot != null) A(`div.s-menu${actions != null ? ".s-panel-origin" : ""}`, () => drawSlot(slot));
558
581
  });
559
582
  });
560
583
  });
@@ -38,11 +38,13 @@ export interface MenuItem {
38
38
  attrs?: Attributes;
39
39
  /**
40
40
  * Child entries, which turn the item into a collapsible **branch** of a
41
- * tree. Only the branch holding the current page is expanded; navigate away
42
- * and it folds back up. Clicking a branch *selects* rather than toggles: it
43
- * follows the item's own `href`, or failing that the first linked leaf
44
- * below it which is what expands it. A branch with no link anywhere below
45
- * it falls back to plain open/close toggling.
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.
46
48
  *
47
49
  * Expanding is not selecting: a branch click never counts as picking an
48
50
  * item (see `onLeafSelect` on {@link menu}), so on a phone the nav stays up
@@ -243,14 +245,20 @@ export function drawMenu(items: MenuEntry[], onLeafSelect?: () => void): void {
243
245
  els[next].focus();
244
246
  });
245
247
 
246
- drawEntries(items, onLeafSelect);
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);
247
255
  }
248
256
 
249
- function drawEntries(items: MenuEntry[], onLeafSelect?: () => void): void {
257
+ function drawEntries(items: MenuEntry[], onLeafSelect?: () => void, $menuHasCurrent?: { value: boolean }): void {
250
258
  for (const entry of items) {
251
259
  if (typeof entry === "string" || typeof entry === "function") { drawSlot(entry); continue; }
252
260
  if ("separator" in entry) { A("hr.s-menu-sep"); continue; }
253
- if (entry.items) drawBranch(entry, onLeafSelect);
261
+ if (entry.items) drawBranch(entry, onLeafSelect, $menuHasCurrent);
254
262
  else drawLeaf(entry, onLeafSelect);
255
263
  }
256
264
  }
@@ -311,12 +319,22 @@ function drawLeaf(entry: MenuItem, onLeafSelect?: () => void): void {
311
319
  * linked branch is open exactly while it holds the current page. Only a branch
312
320
  * with no link anywhere below it keeps the native open/close toggle.
313
321
  */
314
- function drawBranch(entry: MenuItem, onLeafSelect?: () => void): void {
322
+ function drawBranch(entry: MenuItem, onLeafSelect?: () => void, $menuHasCurrent?: { value: boolean }): void {
315
323
  const href = entry.href ?? firstLeafHref(entry.items!);
316
324
  // The route-derived fold state, as a derived boolean so the attribute scope
317
325
  // below re-runs only when the answer flips — not on every navigation that
318
- // merely moves *between* pages inside the branch.
319
- const $open = href != null ? A.derive(() => containsCurrent(entry)) : null;
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;
320
338
 
321
339
  A("details.s-menu-details", () => {
322
340
  // For a no-link branch this scope has no subscriptions and never re-runs,
@@ -346,7 +364,7 @@ function drawBranch(entry: MenuItem, onLeafSelect?: () => void): void {
346
364
  A("span.s-menu-chevron aria-hidden=true", () => chevronRight());
347
365
  });
348
366
 
349
- A("div.s-menu-sub", () => drawEntries(entry.items!, onLeafSelect));
367
+ A("div.s-menu-sub", () => drawEntries(entry.items!, onLeafSelect, $menuHasCurrent));
350
368
  });
351
369
  }
352
370
 
@@ -366,6 +384,12 @@ function foldedAway(el: HTMLElement): boolean {
366
384
  return false;
367
385
  }
368
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
+
369
393
  /** Whether `entry`'s own page, or any page linked below it, is the current one. */
370
394
  function containsCurrent(entry: MenuItem): boolean {
371
395
  if (entry.href != null && matchCurrent(entry.href)) return true;
@@ -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
- /** Set `false` to show only the current panel, however much room there is. */
672
- stacking?: boolean;
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` (the default), `replace`, or `open`, which drops the
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. An unrecognised value is a `push`.
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
- const panel = mode === "open" ? null : anchor.closest<HTMLElement>(".s-panel");
1454
- const origin = panel ? this.$state.live.find((entry) => entry.el === panel) : undefined;
1455
- void this.navigate(url.href, origin?.path ?? null, mode === "replace");
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.stacking !== false;
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,