fold-ng 0.28.0 → 0.28.2

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/CHANGELOG.md CHANGED
@@ -8,6 +8,40 @@ All notable changes to **fold-ng** are documented here. The format follows
8
8
 
9
9
  _Nothing yet._
10
10
 
11
+ ## [0.28.2] - 2026-10-13
12
+
13
+ ### Fixed
14
+
15
+ - **`fold-menu` replié défile.** Replié, le corps du menu gardait
16
+ `overflow: visible` pour laisser sortir les infobulles : un menu plus haut
17
+ que l'écran débordait et ses entrées se tassaient. Le corps défile désormais
18
+ dans les deux états (barre masquée replié), les entrées ne rétrécissent plus
19
+ (`flex-shrink: 0`), et l'infobulle passe en `position: fixed`, placée au
20
+ survol (`--mi-tip-x/y`), pour échapper au défilement.
21
+
22
+ ### Changed
23
+
24
+ - **`fold-menu-section` déplié : un retrait et une barre de couleur.** Menu
25
+ déplié, les entrées d'une section ont un léger retrait derrière une barre
26
+ verticale à la couleur de la section, pour les distinguer du premier niveau.
27
+ Le rail replié ne change pas.
28
+
29
+ ## [0.28.1] - 2026-10-06
30
+
31
+ ### Fixed
32
+
33
+ - **`fold-nav-launcher` défile au niveau 1.** La grille portait les tuiles dans
34
+ un corps `overflow: hidden` : au-delà d'un écran, les dernières tuiles étaient
35
+ coupées et inatteignables (iPad). C'est la grille qui défile désormais
36
+ (`overflow-y: auto; overscroll-behavior: contain`) — pas le corps, sans quoi
37
+ la feuille du niveau 2 s'ouvrirait décalée — et le pied reste en place.
38
+ - **`fold-nav-launcher` : des tuiles de taille bornée sur tablette.** En
39
+ `columns="auto"` (défaut) la largeur décide : `auto-fill` avec un minimum de
40
+ 96 px (144 px pour ≤4 éléments). Téléphone inchangé (3 colonnes, ou 2), iPad
41
+ 7 colonnes de ~96 px au lieu de 2 de ~370 px. La grille est plafonnée à
42
+ `--fold-nav-launcher-max-width` (720 px), centrée — y compris avec un
43
+ `columns` numérique, qui reste prioritaire.
44
+
11
45
  ## [0.28.0] - 2026-10-05
12
46
 
13
47
  ### Added
@@ -2622,7 +2656,9 @@ design-token stylesheet.
2622
2656
  `currentColor`; `prefers-reduced-motion` + `forced-colors` are respected;
2623
2657
  strings localise via inputs / providers (`provideFoldPanelLabels`).
2624
2658
 
2625
- [unreleased]: https://github.com/hugoheynard/fold-ng/compare/v0.28.0...HEAD
2659
+ [unreleased]: https://github.com/hugoheynard/fold-ng/compare/v0.28.2...HEAD
2660
+ [0.28.2]: https://github.com/hugoheynard/fold-ng/releases/tag/v0.28.2
2661
+ [0.28.1]: https://github.com/hugoheynard/fold-ng/releases/tag/v0.28.1
2626
2662
  [0.28.0]: https://github.com/hugoheynard/fold-ng/releases/tag/v0.28.0
2627
2663
  [0.27.2]: https://github.com/hugoheynard/fold-ng/releases/tag/v0.27.2
2628
2664
  [0.27.1]: https://github.com/hugoheynard/fold-ng/releases/tag/v0.27.1
@@ -4359,7 +4359,7 @@ class FoldMenuComponent {
4359
4359
  this.expanded.set(!this.isExpanded());
4360
4360
  }
4361
4361
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: FoldMenuComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
4362
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: FoldMenuComponent, isStandalone: true, selector: "fold-menu", inputs: { collapsible: { classPropertyName: "collapsible", publicName: "collapsible", isSignal: true, isRequired: false, transformFunction: null }, expanded: { classPropertyName: "expanded", publicName: "expanded", isSignal: true, isRequired: false, transformFunction: null }, tint: { classPropertyName: "tint", publicName: "tint", isSignal: true, isRequired: false, transformFunction: null }, level: { classPropertyName: "level", publicName: "level", isSignal: true, isRequired: false, transformFunction: null }, togglePlacement: { classPropertyName: "togglePlacement", publicName: "togglePlacement", isSignal: true, isRequired: false, transformFunction: null }, navLabel: { classPropertyName: "navLabel", publicName: "navLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { expanded: "expandedChange" }, host: { properties: { "class.expanded": "isExpanded()", "attr.data-tint": "tint()", "attr.data-level": "level()" } }, viewQueries: [{ propertyName: "headRef", first: true, predicate: ["head"], descendants: true, isSignal: true }, { propertyName: "footRef", first: true, predicate: ["foot"], descendants: true, isSignal: true }], ngImport: i0, template: "<div\n class=\"menu-head\"\n [class.head-has-toggle]=\"collapsible() && resolvedPlacement() === 'header'\"\n #head\n>\n <ng-content select=\"[header]\" />\n @if (collapsible() && resolvedPlacement() === \"header\") {\n <ng-container [ngTemplateOutlet]=\"toggleTpl\" />\n }\n</div>\n\n<nav class=\"menu-body\" [attr.aria-label]=\"navLabel() ?? null\">\n <ng-content />\n @if (collapsible() && resolvedPlacement() === \"body\") {\n <ng-container [ngTemplateOutlet]=\"toggleTpl\" />\n }\n</nav>\n\n<div\n class=\"menu-foot\"\n [class.foot-has-toggle]=\"collapsible() && resolvedPlacement() === 'footer'\"\n #foot\n>\n @if (collapsible() && resolvedPlacement() === \"footer\") {\n <ng-container [ngTemplateOutlet]=\"toggleTpl\" />\n }\n <ng-content select=\"[footer]\" />\n</div>\n\n<ng-template #toggleTpl>\n <button\n type=\"button\"\n class=\"menu-toggle\"\n [attr.aria-label]=\"isExpanded() ? 'Collapse menu' : 'Expand menu'\"\n (click)=\"toggle()\"\n >\n <fold-icon\n [name]=\"isExpanded() ? 'chevron-left' : 'chevron-right'\"\n [size]=\"14\"\n />\n </button>\n</ng-template>\n", styles: ["@charset \"UTF-8\";:host{display:flex;flex-direction:column;align-items:center;width:var(--fold-shell-rail-width, var(--fold-rail-primary, 64px));height:100%;box-sizing:border-box;padding:var(--fold-space-sm) 0;gap:var(--fold-space-xs);background:var(--fold-color-bg-rail-primary);border-right:1px solid var(--fold-color-border);overflow:visible;-webkit-user-select:none;user-select:none;transition:width var(--fold-motion-base)}:host([data-level=secondary]){background:var(--fold-color-bg-rail-secondary)}:host([data-level=tertiary]){background:var(--fold-color-bg-rail-tertiary)}:host([data-elevated]){border-right:none}:host(.expanded){width:max-content;min-width:190px;max-width:260px;align-items:stretch}.menu-head,.menu-foot{flex-shrink:0;display:flex;flex-direction:column;align-items:center;gap:var(--fold-space-xs);width:100%}.menu-head:empty,.menu-foot:empty{display:none}.menu-head{padding-bottom:var(--fold-space-sm);border-bottom:1px solid var(--fold-color-border-subtle)}.menu-foot{padding-top:var(--fold-space-sm);border-top:1px solid var(--fold-color-border-subtle)}:host(.expanded) .menu-head,:host(.expanded) .menu-foot{align-items:stretch;width:auto;padding-left:var(--fold-space-sm);padding-right:var(--fold-space-sm)}.menu-body{flex:1;display:flex;flex-direction:column;align-items:center;gap:var(--fold-space-xs);width:100%}:host(.expanded) .menu-body{align-items:stretch;width:auto;padding:0 var(--fold-space-sm);min-height:0;overflow-y:auto;overscroll-behavior:contain;scrollbar-width:thin}.menu-toggle{flex-shrink:0;width:28px;height:28px;display:grid;place-items:center;border:none;border-radius:var(--fold-radius-sm);background:none;color:var(--fold-color-text-muted);cursor:pointer;transition:background var(--fold-motion-fast),color var(--fold-motion-fast)}.menu-toggle:hover{background:var(--fold-color-surface-hover);color:var(--fold-color-text-secondary)}:host(.expanded) .menu-toggle{align-self:flex-end;margin-right:var(--fold-space-sm)}:host(.expanded) .menu-head.head-has-toggle,:host(.expanded) .menu-foot.foot-has-toggle{position:relative;padding-right:var(--fold-space-4xl)}:host(.expanded) .menu-head.head-has-toggle .menu-toggle,:host(.expanded) .menu-foot.foot-has-toggle .menu-toggle{position:absolute;right:8px;bottom:8px;margin:0}\n"], dependencies: [{ kind: "component", type: FoldIconComponent, selector: "fold-icon", inputs: ["name", "size", "tone", "title"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }] });
4362
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: FoldMenuComponent, isStandalone: true, selector: "fold-menu", inputs: { collapsible: { classPropertyName: "collapsible", publicName: "collapsible", isSignal: true, isRequired: false, transformFunction: null }, expanded: { classPropertyName: "expanded", publicName: "expanded", isSignal: true, isRequired: false, transformFunction: null }, tint: { classPropertyName: "tint", publicName: "tint", isSignal: true, isRequired: false, transformFunction: null }, level: { classPropertyName: "level", publicName: "level", isSignal: true, isRequired: false, transformFunction: null }, togglePlacement: { classPropertyName: "togglePlacement", publicName: "togglePlacement", isSignal: true, isRequired: false, transformFunction: null }, navLabel: { classPropertyName: "navLabel", publicName: "navLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { expanded: "expandedChange" }, host: { properties: { "class.expanded": "isExpanded()", "attr.data-tint": "tint()", "attr.data-level": "level()" } }, viewQueries: [{ propertyName: "headRef", first: true, predicate: ["head"], descendants: true, isSignal: true }, { propertyName: "footRef", first: true, predicate: ["foot"], descendants: true, isSignal: true }], ngImport: i0, template: "<div\n class=\"menu-head\"\n [class.head-has-toggle]=\"collapsible() && resolvedPlacement() === 'header'\"\n #head\n>\n <ng-content select=\"[header]\" />\n @if (collapsible() && resolvedPlacement() === \"header\") {\n <ng-container [ngTemplateOutlet]=\"toggleTpl\" />\n }\n</div>\n\n<nav class=\"menu-body\" [attr.aria-label]=\"navLabel() ?? null\">\n <ng-content />\n @if (collapsible() && resolvedPlacement() === \"body\") {\n <ng-container [ngTemplateOutlet]=\"toggleTpl\" />\n }\n</nav>\n\n<div\n class=\"menu-foot\"\n [class.foot-has-toggle]=\"collapsible() && resolvedPlacement() === 'footer'\"\n #foot\n>\n @if (collapsible() && resolvedPlacement() === \"footer\") {\n <ng-container [ngTemplateOutlet]=\"toggleTpl\" />\n }\n <ng-content select=\"[footer]\" />\n</div>\n\n<ng-template #toggleTpl>\n <button\n type=\"button\"\n class=\"menu-toggle\"\n [attr.aria-label]=\"isExpanded() ? 'Collapse menu' : 'Expand menu'\"\n (click)=\"toggle()\"\n >\n <fold-icon\n [name]=\"isExpanded() ? 'chevron-left' : 'chevron-right'\"\n [size]=\"14\"\n />\n </button>\n</ng-template>\n", styles: ["@charset \"UTF-8\";:host{display:flex;flex-direction:column;align-items:center;width:var(--fold-shell-rail-width, var(--fold-rail-primary, 64px));height:100%;box-sizing:border-box;padding:var(--fold-space-sm) 0;gap:var(--fold-space-xs);background:var(--fold-color-bg-rail-primary);border-right:1px solid var(--fold-color-border);overflow:visible;-webkit-user-select:none;user-select:none;transition:width var(--fold-motion-base)}:host([data-level=secondary]){background:var(--fold-color-bg-rail-secondary)}:host([data-level=tertiary]){background:var(--fold-color-bg-rail-tertiary)}:host([data-elevated]){border-right:none}:host(.expanded){width:max-content;min-width:190px;max-width:260px;align-items:stretch}.menu-head,.menu-foot{flex-shrink:0;display:flex;flex-direction:column;align-items:center;gap:var(--fold-space-xs);width:100%}.menu-head:empty,.menu-foot:empty{display:none}.menu-head{padding-bottom:var(--fold-space-sm);border-bottom:1px solid var(--fold-color-border-subtle)}.menu-foot{padding-top:var(--fold-space-sm);border-top:1px solid var(--fold-color-border-subtle)}:host(.expanded) .menu-head,:host(.expanded) .menu-foot{align-items:stretch;width:auto;padding-left:var(--fold-space-sm);padding-right:var(--fold-space-sm)}.menu-body{flex:1;display:flex;flex-direction:column;align-items:center;gap:var(--fold-space-xs);width:100%;min-height:0;overflow-y:auto;overscroll-behavior:contain;scrollbar-width:none}.menu-body::-webkit-scrollbar{display:none}:host(.expanded) .menu-body{align-items:stretch;width:auto;padding:0 var(--fold-space-sm);scrollbar-width:thin}.menu-toggle{flex-shrink:0;width:28px;height:28px;display:grid;place-items:center;border:none;border-radius:var(--fold-radius-sm);background:none;color:var(--fold-color-text-muted);cursor:pointer;transition:background var(--fold-motion-fast),color var(--fold-motion-fast)}.menu-toggle:hover{background:var(--fold-color-surface-hover);color:var(--fold-color-text-secondary)}:host(.expanded) .menu-toggle{align-self:flex-end;margin-right:var(--fold-space-sm)}:host(.expanded) .menu-head.head-has-toggle,:host(.expanded) .menu-foot.foot-has-toggle{position:relative;padding-right:var(--fold-space-4xl)}:host(.expanded) .menu-head.head-has-toggle .menu-toggle,:host(.expanded) .menu-foot.foot-has-toggle .menu-toggle{position:absolute;right:8px;bottom:8px;margin:0}\n"], dependencies: [{ kind: "component", type: FoldIconComponent, selector: "fold-icon", inputs: ["name", "size", "tone", "title"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }] });
4363
4363
  }
4364
4364
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: FoldMenuComponent, decorators: [{
4365
4365
  type: Component,
@@ -4367,7 +4367,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
4367
4367
  "[class.expanded]": "isExpanded()",
4368
4368
  "[attr.data-tint]": "tint()",
4369
4369
  "[attr.data-level]": "level()",
4370
- }, template: "<div\n class=\"menu-head\"\n [class.head-has-toggle]=\"collapsible() && resolvedPlacement() === 'header'\"\n #head\n>\n <ng-content select=\"[header]\" />\n @if (collapsible() && resolvedPlacement() === \"header\") {\n <ng-container [ngTemplateOutlet]=\"toggleTpl\" />\n }\n</div>\n\n<nav class=\"menu-body\" [attr.aria-label]=\"navLabel() ?? null\">\n <ng-content />\n @if (collapsible() && resolvedPlacement() === \"body\") {\n <ng-container [ngTemplateOutlet]=\"toggleTpl\" />\n }\n</nav>\n\n<div\n class=\"menu-foot\"\n [class.foot-has-toggle]=\"collapsible() && resolvedPlacement() === 'footer'\"\n #foot\n>\n @if (collapsible() && resolvedPlacement() === \"footer\") {\n <ng-container [ngTemplateOutlet]=\"toggleTpl\" />\n }\n <ng-content select=\"[footer]\" />\n</div>\n\n<ng-template #toggleTpl>\n <button\n type=\"button\"\n class=\"menu-toggle\"\n [attr.aria-label]=\"isExpanded() ? 'Collapse menu' : 'Expand menu'\"\n (click)=\"toggle()\"\n >\n <fold-icon\n [name]=\"isExpanded() ? 'chevron-left' : 'chevron-right'\"\n [size]=\"14\"\n />\n </button>\n</ng-template>\n", styles: ["@charset \"UTF-8\";:host{display:flex;flex-direction:column;align-items:center;width:var(--fold-shell-rail-width, var(--fold-rail-primary, 64px));height:100%;box-sizing:border-box;padding:var(--fold-space-sm) 0;gap:var(--fold-space-xs);background:var(--fold-color-bg-rail-primary);border-right:1px solid var(--fold-color-border);overflow:visible;-webkit-user-select:none;user-select:none;transition:width var(--fold-motion-base)}:host([data-level=secondary]){background:var(--fold-color-bg-rail-secondary)}:host([data-level=tertiary]){background:var(--fold-color-bg-rail-tertiary)}:host([data-elevated]){border-right:none}:host(.expanded){width:max-content;min-width:190px;max-width:260px;align-items:stretch}.menu-head,.menu-foot{flex-shrink:0;display:flex;flex-direction:column;align-items:center;gap:var(--fold-space-xs);width:100%}.menu-head:empty,.menu-foot:empty{display:none}.menu-head{padding-bottom:var(--fold-space-sm);border-bottom:1px solid var(--fold-color-border-subtle)}.menu-foot{padding-top:var(--fold-space-sm);border-top:1px solid var(--fold-color-border-subtle)}:host(.expanded) .menu-head,:host(.expanded) .menu-foot{align-items:stretch;width:auto;padding-left:var(--fold-space-sm);padding-right:var(--fold-space-sm)}.menu-body{flex:1;display:flex;flex-direction:column;align-items:center;gap:var(--fold-space-xs);width:100%}:host(.expanded) .menu-body{align-items:stretch;width:auto;padding:0 var(--fold-space-sm);min-height:0;overflow-y:auto;overscroll-behavior:contain;scrollbar-width:thin}.menu-toggle{flex-shrink:0;width:28px;height:28px;display:grid;place-items:center;border:none;border-radius:var(--fold-radius-sm);background:none;color:var(--fold-color-text-muted);cursor:pointer;transition:background var(--fold-motion-fast),color var(--fold-motion-fast)}.menu-toggle:hover{background:var(--fold-color-surface-hover);color:var(--fold-color-text-secondary)}:host(.expanded) .menu-toggle{align-self:flex-end;margin-right:var(--fold-space-sm)}:host(.expanded) .menu-head.head-has-toggle,:host(.expanded) .menu-foot.foot-has-toggle{position:relative;padding-right:var(--fold-space-4xl)}:host(.expanded) .menu-head.head-has-toggle .menu-toggle,:host(.expanded) .menu-foot.foot-has-toggle .menu-toggle{position:absolute;right:8px;bottom:8px;margin:0}\n"] }]
4370
+ }, template: "<div\n class=\"menu-head\"\n [class.head-has-toggle]=\"collapsible() && resolvedPlacement() === 'header'\"\n #head\n>\n <ng-content select=\"[header]\" />\n @if (collapsible() && resolvedPlacement() === \"header\") {\n <ng-container [ngTemplateOutlet]=\"toggleTpl\" />\n }\n</div>\n\n<nav class=\"menu-body\" [attr.aria-label]=\"navLabel() ?? null\">\n <ng-content />\n @if (collapsible() && resolvedPlacement() === \"body\") {\n <ng-container [ngTemplateOutlet]=\"toggleTpl\" />\n }\n</nav>\n\n<div\n class=\"menu-foot\"\n [class.foot-has-toggle]=\"collapsible() && resolvedPlacement() === 'footer'\"\n #foot\n>\n @if (collapsible() && resolvedPlacement() === \"footer\") {\n <ng-container [ngTemplateOutlet]=\"toggleTpl\" />\n }\n <ng-content select=\"[footer]\" />\n</div>\n\n<ng-template #toggleTpl>\n <button\n type=\"button\"\n class=\"menu-toggle\"\n [attr.aria-label]=\"isExpanded() ? 'Collapse menu' : 'Expand menu'\"\n (click)=\"toggle()\"\n >\n <fold-icon\n [name]=\"isExpanded() ? 'chevron-left' : 'chevron-right'\"\n [size]=\"14\"\n />\n </button>\n</ng-template>\n", styles: ["@charset \"UTF-8\";:host{display:flex;flex-direction:column;align-items:center;width:var(--fold-shell-rail-width, var(--fold-rail-primary, 64px));height:100%;box-sizing:border-box;padding:var(--fold-space-sm) 0;gap:var(--fold-space-xs);background:var(--fold-color-bg-rail-primary);border-right:1px solid var(--fold-color-border);overflow:visible;-webkit-user-select:none;user-select:none;transition:width var(--fold-motion-base)}:host([data-level=secondary]){background:var(--fold-color-bg-rail-secondary)}:host([data-level=tertiary]){background:var(--fold-color-bg-rail-tertiary)}:host([data-elevated]){border-right:none}:host(.expanded){width:max-content;min-width:190px;max-width:260px;align-items:stretch}.menu-head,.menu-foot{flex-shrink:0;display:flex;flex-direction:column;align-items:center;gap:var(--fold-space-xs);width:100%}.menu-head:empty,.menu-foot:empty{display:none}.menu-head{padding-bottom:var(--fold-space-sm);border-bottom:1px solid var(--fold-color-border-subtle)}.menu-foot{padding-top:var(--fold-space-sm);border-top:1px solid var(--fold-color-border-subtle)}:host(.expanded) .menu-head,:host(.expanded) .menu-foot{align-items:stretch;width:auto;padding-left:var(--fold-space-sm);padding-right:var(--fold-space-sm)}.menu-body{flex:1;display:flex;flex-direction:column;align-items:center;gap:var(--fold-space-xs);width:100%;min-height:0;overflow-y:auto;overscroll-behavior:contain;scrollbar-width:none}.menu-body::-webkit-scrollbar{display:none}:host(.expanded) .menu-body{align-items:stretch;width:auto;padding:0 var(--fold-space-sm);scrollbar-width:thin}.menu-toggle{flex-shrink:0;width:28px;height:28px;display:grid;place-items:center;border:none;border-radius:var(--fold-radius-sm);background:none;color:var(--fold-color-text-muted);cursor:pointer;transition:background var(--fold-motion-fast),color var(--fold-motion-fast)}.menu-toggle:hover{background:var(--fold-color-surface-hover);color:var(--fold-color-text-secondary)}:host(.expanded) .menu-toggle{align-self:flex-end;margin-right:var(--fold-space-sm)}:host(.expanded) .menu-head.head-has-toggle,:host(.expanded) .menu-foot.foot-has-toggle{position:relative;padding-right:var(--fold-space-4xl)}:host(.expanded) .menu-head.head-has-toggle .menu-toggle,:host(.expanded) .menu-foot.foot-has-toggle .menu-toggle{position:absolute;right:8px;bottom:8px;margin:0}\n"] }]
4371
4371
  }], ctorParameters: () => [], propDecorators: { collapsible: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsible", required: false }] }], expanded: [{ type: i0.Input, args: [{ isSignal: true, alias: "expanded", required: false }] }, { type: i0.Output, args: ["expandedChange"] }], tint: [{ type: i0.Input, args: [{ isSignal: true, alias: "tint", required: false }] }], level: [{ type: i0.Input, args: [{ isSignal: true, alias: "level", required: false }] }], togglePlacement: [{ type: i0.Input, args: [{ isSignal: true, alias: "togglePlacement", required: false }] }], navLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "navLabel", required: false }] }], headRef: [{ type: i0.ViewChild, args: ["head", { isSignal: true }] }], footRef: [{ type: i0.ViewChild, args: ["foot", { isSignal: true }] }] } });
4372
4372
 
4373
4373
  /** Solid accent colour per semantic tone (drives the dot + follow-pill). */
@@ -4406,6 +4406,18 @@ const TONE_ACCENT = {
4406
4406
  * ```
4407
4407
  */
4408
4408
  class FoldMenuItemComponent {
4409
+ host = inject(ElementRef);
4410
+ /**
4411
+ * Pins the collapsed-rail tooltip next to the item, in viewport coordinates.
4412
+ * The chip is `position: fixed` so the scrolling rail body cannot clip it;
4413
+ * it therefore needs the item's on-screen position at the moment it shows.
4414
+ */
4415
+ placeTip() {
4416
+ const el = this.host.nativeElement;
4417
+ const box = el.getBoundingClientRect();
4418
+ el.style.setProperty("--mi-tip-x", `${box.right + 8}px`);
4419
+ el.style.setProperty("--mi-tip-y", `${box.top + box.height / 2}px`);
4420
+ }
4409
4421
  icon = input.required(/* @ts-ignore */
4410
4422
  ...(ngDevMode ? [{ debugName: "icon" }] : /* istanbul ignore next */ []));
4411
4423
  /** The label shown in the hover tooltip (also the accessible name). */
@@ -4465,7 +4477,7 @@ class FoldMenuItemComponent {
4465
4477
  ariaLabel = computed(() => this.hasBadge() ? `${this.label()}, ${this.badgeText()}` : null, /* @ts-ignore */
4466
4478
  ...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
4467
4479
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: FoldMenuItemComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
4468
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: FoldMenuItemComponent, isStandalone: true, selector: "a[fold-menu-item], button[fold-menu-item]", inputs: { icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: true, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: true, transformFunction: null }, active: { classPropertyName: "active", publicName: "active", isSignal: true, isRequired: false, transformFunction: null }, badge: { classPropertyName: "badge", publicName: "badge", isSignal: true, isRequired: false, transformFunction: null }, badgeTone: { classPropertyName: "badgeTone", publicName: "badgeTone", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class.is-active": "active()", "attr.aria-label": "ariaLabel()", "style.--mi-badge-accent": "badgeAccent()" } }, ngImport: i0, template: "<fold-icon [name]=\"icon()\" [size]=\"18\" class=\"mi-icon\" />\n\n<!-- Collapsed rail: a corner dot, or a count bubble for a number. -->\n@if (hasBadge()) {\n <span class=\"mi-dot\" [class.mi-dot-count]=\"isCount()\" aria-hidden=\"true\">{{\n dotText()\n }}</span>\n}\n\n<span class=\"mi-tip\">{{ label() }}</span>\n\n<!-- Expanded rail: the badge pill, pushed to the row's trailing edge. `follow`\n tints from the item's own accent; the semantic tones reuse fold-badge. -->\n@if (hasBadge()) {\n @if (isFollowTone()) {\n <span class=\"mi-badge mi-badge-follow\">{{ badgeText() }}</span>\n } @else {\n <fold-badge\n class=\"mi-badge\"\n [content]=\"badgeText()\"\n [variant]=\"badgeVariant()\"\n />\n }\n}\n", styles: ["@charset \"UTF-8\";:host{position:relative;width:40px;height:36px;box-sizing:border-box;display:grid;place-items:center;border-radius:var(--fold-radius-sm);color:var(--fold-color-text-muted);background:transparent;border:none;cursor:pointer;text-decoration:none;transition:background var(--fold-motion-fast),color var(--fold-motion-fast);--mi-accent: var(--fold-menu-section-color, var(--fold-color-text-secondary));--mi-hover-bg: color-mix( in srgb, var(--mi-accent) 16%, var(--fold-color-surface-hover) );--mi-hover-fg: var(--mi-accent);--mi-active-bg: color-mix(in srgb, var(--mi-accent) 15%, transparent);--mi-active-fg: color-mix( in srgb, var(--mi-accent) 80%, var(--fold-color-text) );--mi-active-icon: var(--mi-accent)}:host-context(fold-menu[data-tint=neutral]){--mi-accent: var(--fold-color-text-secondary);--mi-hover-bg: var(--fold-color-surface-hover);--mi-hover-fg: var(--fold-color-text-secondary);--mi-active-bg: var(--fold-color-surface-hover);--mi-active-fg: var(--fold-color-text);--mi-active-icon: var(--fold-color-text)}:host-context(fold-menu[data-tint=primary]){--mi-accent: var(--fold-color-primary)}:host(:hover){background:var(--mi-hover-bg);color:var(--mi-hover-fg)}:host(:focus-visible){outline:2px solid var(--fold-color-primary);outline-offset:2px}:host(.is-active){color:var(--mi-active-fg);background:var(--mi-active-bg)}:host(.is-active) .mi-icon{color:var(--mi-active-icon)}:host(.is-active):before{content:\"\";position:absolute;left:-8px;top:8px;bottom:8px;width:2px;border-radius:0 2px 2px 0;background:var(--mi-accent);box-shadow:0 0 8px var(--mi-accent)}.mi-icon{color:inherit;transition:color var(--fold-motion-fast)}.mi-dot{position:absolute;top:5px;right:5px;width:8px;height:8px;border-radius:var(--fold-radius-round);background:var(--mi-badge-accent, var(--mi-accent));pointer-events:none}.mi-dot-count{top:2px;right:2px;width:auto;min-width:16px;height:16px;padding:0 var(--fold-space-xs);display:grid;place-items:center;border-radius:var(--fold-radius-pill);font-size:var(--fold-text-2xs);font-weight:var(--fold-weight-semibold);line-height:var(--fold-leading-none);color:var(--fold-color-on-primary)}.mi-badge{display:none}.mi-badge-follow{padding:1px var(--fold-space-sm);border-radius:var(--fold-radius-pill);font-size:var(--fold-text-xs);font-weight:var(--fold-weight-medium);line-height:var(--fold-leading-normal);white-space:nowrap;background:color-mix(in srgb,var(--mi-badge-accent) 16%,transparent);border:1px solid color-mix(in srgb,var(--mi-badge-accent) 35%,transparent);color:color-mix(in srgb,var(--mi-badge-accent) 85%,var(--fold-color-text))}:host-context(fold-menu.expanded) .mi-dot{display:none}:host-context(fold-menu.expanded) .mi-badge{display:inline-flex;margin-left:auto}.mi-tip{position:absolute;left:calc(100% + 8px);top:50%;transform:translateY(-50%);padding:var(--fold-space-xs) var(--fold-space-sm);border-radius:var(--fold-radius-sm);background:var(--fold-color-glass);border:1px solid var(--fold-color-glass-border);color:var(--fold-color-text);font-size:var(--fold-text-xs);white-space:nowrap;opacity:0;pointer-events:none;box-shadow:var(--fold-shadow-md);transition:opacity var(--fold-motion-fast);z-index:100}:host(:hover) .mi-tip{opacity:1}:host-context(fold-menu.expanded){width:auto;height:36px;display:flex;align-items:center;gap:var(--fold-space-md);padding:0 var(--fold-space-md)}:host-context(fold-menu.expanded) .mi-tip{position:static;transform:none;padding:0;border:none;background:none;box-shadow:none;color:inherit;font-size:var(--fold-text-sm);opacity:1;pointer-events:auto}\n"], dependencies: [{ kind: "component", type: FoldIconComponent, selector: "fold-icon", inputs: ["name", "size", "tone", "title"] }, { kind: "component", type: FoldBadgeComponent, selector: "fold-badge", inputs: ["content", "radius", "variant"] }] });
4480
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: FoldMenuItemComponent, isStandalone: true, selector: "a[fold-menu-item], button[fold-menu-item]", inputs: { icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: true, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: true, transformFunction: null }, active: { classPropertyName: "active", publicName: "active", isSignal: true, isRequired: false, transformFunction: null }, badge: { classPropertyName: "badge", publicName: "badge", isSignal: true, isRequired: false, transformFunction: null }, badgeTone: { classPropertyName: "badgeTone", publicName: "badgeTone", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "mouseenter": "placeTip()", "focusin": "placeTip()" }, properties: { "class.is-active": "active()", "attr.aria-label": "ariaLabel()", "style.--mi-badge-accent": "badgeAccent()" } }, ngImport: i0, template: "<fold-icon [name]=\"icon()\" [size]=\"18\" class=\"mi-icon\" />\n\n<!-- Collapsed rail: a corner dot, or a count bubble for a number. -->\n@if (hasBadge()) {\n <span class=\"mi-dot\" [class.mi-dot-count]=\"isCount()\" aria-hidden=\"true\">{{\n dotText()\n }}</span>\n}\n\n<span class=\"mi-tip\">{{ label() }}</span>\n\n<!-- Expanded rail: the badge pill, pushed to the row's trailing edge. `follow`\n tints from the item's own accent; the semantic tones reuse fold-badge. -->\n@if (hasBadge()) {\n @if (isFollowTone()) {\n <span class=\"mi-badge mi-badge-follow\">{{ badgeText() }}</span>\n } @else {\n <fold-badge\n class=\"mi-badge\"\n [content]=\"badgeText()\"\n [variant]=\"badgeVariant()\"\n />\n }\n}\n", styles: ["@charset \"UTF-8\";:host{position:relative;width:40px;height:36px;flex-shrink:0;box-sizing:border-box;display:grid;place-items:center;border-radius:var(--fold-radius-sm);color:var(--fold-color-text-muted);background:transparent;border:none;cursor:pointer;text-decoration:none;transition:background var(--fold-motion-fast),color var(--fold-motion-fast);--mi-accent: var(--fold-menu-section-color, var(--fold-color-text-secondary));--mi-hover-bg: color-mix( in srgb, var(--mi-accent) 16%, var(--fold-color-surface-hover) );--mi-hover-fg: var(--mi-accent);--mi-active-bg: color-mix(in srgb, var(--mi-accent) 15%, transparent);--mi-active-fg: color-mix( in srgb, var(--mi-accent) 80%, var(--fold-color-text) );--mi-active-icon: var(--mi-accent)}:host-context(fold-menu[data-tint=neutral]){--mi-accent: var(--fold-color-text-secondary);--mi-hover-bg: var(--fold-color-surface-hover);--mi-hover-fg: var(--fold-color-text-secondary);--mi-active-bg: var(--fold-color-surface-hover);--mi-active-fg: var(--fold-color-text);--mi-active-icon: var(--fold-color-text)}:host-context(fold-menu[data-tint=primary]){--mi-accent: var(--fold-color-primary)}:host(:hover){background:var(--mi-hover-bg);color:var(--mi-hover-fg)}:host(:focus-visible){outline:2px solid var(--fold-color-primary);outline-offset:2px}:host(.is-active){color:var(--mi-active-fg);background:var(--mi-active-bg)}:host(.is-active) .mi-icon{color:var(--mi-active-icon)}:host(.is-active):before{content:\"\";position:absolute;left:-8px;top:8px;bottom:8px;width:2px;border-radius:0 2px 2px 0;background:var(--mi-accent);box-shadow:0 0 8px var(--mi-accent)}.mi-icon{color:inherit;transition:color var(--fold-motion-fast)}.mi-dot{position:absolute;top:5px;right:5px;width:8px;height:8px;border-radius:var(--fold-radius-round);background:var(--mi-badge-accent, var(--mi-accent));pointer-events:none}.mi-dot-count{top:2px;right:2px;width:auto;min-width:16px;height:16px;padding:0 var(--fold-space-xs);display:grid;place-items:center;border-radius:var(--fold-radius-pill);font-size:var(--fold-text-2xs);font-weight:var(--fold-weight-semibold);line-height:var(--fold-leading-none);color:var(--fold-color-on-primary)}.mi-badge{display:none}.mi-badge-follow{padding:1px var(--fold-space-sm);border-radius:var(--fold-radius-pill);font-size:var(--fold-text-xs);font-weight:var(--fold-weight-medium);line-height:var(--fold-leading-normal);white-space:nowrap;background:color-mix(in srgb,var(--mi-badge-accent) 16%,transparent);border:1px solid color-mix(in srgb,var(--mi-badge-accent) 35%,transparent);color:color-mix(in srgb,var(--mi-badge-accent) 85%,var(--fold-color-text))}:host-context(fold-menu.expanded) .mi-dot{display:none}:host-context(fold-menu.expanded) .mi-badge{display:inline-flex;margin-left:auto}.mi-tip{position:fixed;left:var(--mi-tip-x, -9999px);top:var(--mi-tip-y, 0);transform:translateY(-50%);padding:var(--fold-space-xs) var(--fold-space-sm);border-radius:var(--fold-radius-sm);background:var(--fold-color-glass);border:1px solid var(--fold-color-glass-border);color:var(--fold-color-text);font-size:var(--fold-text-xs);white-space:nowrap;opacity:0;pointer-events:none;box-shadow:var(--fold-shadow-md);transition:opacity var(--fold-motion-fast);z-index:100}:host(:hover) .mi-tip{opacity:1}:host-context(fold-menu.expanded){width:auto;height:36px;display:flex;align-items:center;gap:var(--fold-space-md);padding:0 var(--fold-space-md)}:host-context(fold-menu.expanded) .mi-tip{position:static;transform:none;padding:0;border:none;background:none;box-shadow:none;color:inherit;font-size:var(--fold-text-sm);opacity:1;pointer-events:auto}\n"], dependencies: [{ kind: "component", type: FoldIconComponent, selector: "fold-icon", inputs: ["name", "size", "tone", "title"] }, { kind: "component", type: FoldBadgeComponent, selector: "fold-badge", inputs: ["content", "radius", "variant"] }] });
4469
4481
  }
4470
4482
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: FoldMenuItemComponent, decorators: [{
4471
4483
  type: Component,
@@ -4473,7 +4485,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
4473
4485
  "[class.is-active]": "active()",
4474
4486
  "[attr.aria-label]": "ariaLabel()",
4475
4487
  "[style.--mi-badge-accent]": "badgeAccent()",
4476
- }, template: "<fold-icon [name]=\"icon()\" [size]=\"18\" class=\"mi-icon\" />\n\n<!-- Collapsed rail: a corner dot, or a count bubble for a number. -->\n@if (hasBadge()) {\n <span class=\"mi-dot\" [class.mi-dot-count]=\"isCount()\" aria-hidden=\"true\">{{\n dotText()\n }}</span>\n}\n\n<span class=\"mi-tip\">{{ label() }}</span>\n\n<!-- Expanded rail: the badge pill, pushed to the row's trailing edge. `follow`\n tints from the item's own accent; the semantic tones reuse fold-badge. -->\n@if (hasBadge()) {\n @if (isFollowTone()) {\n <span class=\"mi-badge mi-badge-follow\">{{ badgeText() }}</span>\n } @else {\n <fold-badge\n class=\"mi-badge\"\n [content]=\"badgeText()\"\n [variant]=\"badgeVariant()\"\n />\n }\n}\n", styles: ["@charset \"UTF-8\";:host{position:relative;width:40px;height:36px;box-sizing:border-box;display:grid;place-items:center;border-radius:var(--fold-radius-sm);color:var(--fold-color-text-muted);background:transparent;border:none;cursor:pointer;text-decoration:none;transition:background var(--fold-motion-fast),color var(--fold-motion-fast);--mi-accent: var(--fold-menu-section-color, var(--fold-color-text-secondary));--mi-hover-bg: color-mix( in srgb, var(--mi-accent) 16%, var(--fold-color-surface-hover) );--mi-hover-fg: var(--mi-accent);--mi-active-bg: color-mix(in srgb, var(--mi-accent) 15%, transparent);--mi-active-fg: color-mix( in srgb, var(--mi-accent) 80%, var(--fold-color-text) );--mi-active-icon: var(--mi-accent)}:host-context(fold-menu[data-tint=neutral]){--mi-accent: var(--fold-color-text-secondary);--mi-hover-bg: var(--fold-color-surface-hover);--mi-hover-fg: var(--fold-color-text-secondary);--mi-active-bg: var(--fold-color-surface-hover);--mi-active-fg: var(--fold-color-text);--mi-active-icon: var(--fold-color-text)}:host-context(fold-menu[data-tint=primary]){--mi-accent: var(--fold-color-primary)}:host(:hover){background:var(--mi-hover-bg);color:var(--mi-hover-fg)}:host(:focus-visible){outline:2px solid var(--fold-color-primary);outline-offset:2px}:host(.is-active){color:var(--mi-active-fg);background:var(--mi-active-bg)}:host(.is-active) .mi-icon{color:var(--mi-active-icon)}:host(.is-active):before{content:\"\";position:absolute;left:-8px;top:8px;bottom:8px;width:2px;border-radius:0 2px 2px 0;background:var(--mi-accent);box-shadow:0 0 8px var(--mi-accent)}.mi-icon{color:inherit;transition:color var(--fold-motion-fast)}.mi-dot{position:absolute;top:5px;right:5px;width:8px;height:8px;border-radius:var(--fold-radius-round);background:var(--mi-badge-accent, var(--mi-accent));pointer-events:none}.mi-dot-count{top:2px;right:2px;width:auto;min-width:16px;height:16px;padding:0 var(--fold-space-xs);display:grid;place-items:center;border-radius:var(--fold-radius-pill);font-size:var(--fold-text-2xs);font-weight:var(--fold-weight-semibold);line-height:var(--fold-leading-none);color:var(--fold-color-on-primary)}.mi-badge{display:none}.mi-badge-follow{padding:1px var(--fold-space-sm);border-radius:var(--fold-radius-pill);font-size:var(--fold-text-xs);font-weight:var(--fold-weight-medium);line-height:var(--fold-leading-normal);white-space:nowrap;background:color-mix(in srgb,var(--mi-badge-accent) 16%,transparent);border:1px solid color-mix(in srgb,var(--mi-badge-accent) 35%,transparent);color:color-mix(in srgb,var(--mi-badge-accent) 85%,var(--fold-color-text))}:host-context(fold-menu.expanded) .mi-dot{display:none}:host-context(fold-menu.expanded) .mi-badge{display:inline-flex;margin-left:auto}.mi-tip{position:absolute;left:calc(100% + 8px);top:50%;transform:translateY(-50%);padding:var(--fold-space-xs) var(--fold-space-sm);border-radius:var(--fold-radius-sm);background:var(--fold-color-glass);border:1px solid var(--fold-color-glass-border);color:var(--fold-color-text);font-size:var(--fold-text-xs);white-space:nowrap;opacity:0;pointer-events:none;box-shadow:var(--fold-shadow-md);transition:opacity var(--fold-motion-fast);z-index:100}:host(:hover) .mi-tip{opacity:1}:host-context(fold-menu.expanded){width:auto;height:36px;display:flex;align-items:center;gap:var(--fold-space-md);padding:0 var(--fold-space-md)}:host-context(fold-menu.expanded) .mi-tip{position:static;transform:none;padding:0;border:none;background:none;box-shadow:none;color:inherit;font-size:var(--fold-text-sm);opacity:1;pointer-events:auto}\n"] }]
4488
+ "(mouseenter)": "placeTip()",
4489
+ "(focusin)": "placeTip()",
4490
+ }, template: "<fold-icon [name]=\"icon()\" [size]=\"18\" class=\"mi-icon\" />\n\n<!-- Collapsed rail: a corner dot, or a count bubble for a number. -->\n@if (hasBadge()) {\n <span class=\"mi-dot\" [class.mi-dot-count]=\"isCount()\" aria-hidden=\"true\">{{\n dotText()\n }}</span>\n}\n\n<span class=\"mi-tip\">{{ label() }}</span>\n\n<!-- Expanded rail: the badge pill, pushed to the row's trailing edge. `follow`\n tints from the item's own accent; the semantic tones reuse fold-badge. -->\n@if (hasBadge()) {\n @if (isFollowTone()) {\n <span class=\"mi-badge mi-badge-follow\">{{ badgeText() }}</span>\n } @else {\n <fold-badge\n class=\"mi-badge\"\n [content]=\"badgeText()\"\n [variant]=\"badgeVariant()\"\n />\n }\n}\n", styles: ["@charset \"UTF-8\";:host{position:relative;width:40px;height:36px;flex-shrink:0;box-sizing:border-box;display:grid;place-items:center;border-radius:var(--fold-radius-sm);color:var(--fold-color-text-muted);background:transparent;border:none;cursor:pointer;text-decoration:none;transition:background var(--fold-motion-fast),color var(--fold-motion-fast);--mi-accent: var(--fold-menu-section-color, var(--fold-color-text-secondary));--mi-hover-bg: color-mix( in srgb, var(--mi-accent) 16%, var(--fold-color-surface-hover) );--mi-hover-fg: var(--mi-accent);--mi-active-bg: color-mix(in srgb, var(--mi-accent) 15%, transparent);--mi-active-fg: color-mix( in srgb, var(--mi-accent) 80%, var(--fold-color-text) );--mi-active-icon: var(--mi-accent)}:host-context(fold-menu[data-tint=neutral]){--mi-accent: var(--fold-color-text-secondary);--mi-hover-bg: var(--fold-color-surface-hover);--mi-hover-fg: var(--fold-color-text-secondary);--mi-active-bg: var(--fold-color-surface-hover);--mi-active-fg: var(--fold-color-text);--mi-active-icon: var(--fold-color-text)}:host-context(fold-menu[data-tint=primary]){--mi-accent: var(--fold-color-primary)}:host(:hover){background:var(--mi-hover-bg);color:var(--mi-hover-fg)}:host(:focus-visible){outline:2px solid var(--fold-color-primary);outline-offset:2px}:host(.is-active){color:var(--mi-active-fg);background:var(--mi-active-bg)}:host(.is-active) .mi-icon{color:var(--mi-active-icon)}:host(.is-active):before{content:\"\";position:absolute;left:-8px;top:8px;bottom:8px;width:2px;border-radius:0 2px 2px 0;background:var(--mi-accent);box-shadow:0 0 8px var(--mi-accent)}.mi-icon{color:inherit;transition:color var(--fold-motion-fast)}.mi-dot{position:absolute;top:5px;right:5px;width:8px;height:8px;border-radius:var(--fold-radius-round);background:var(--mi-badge-accent, var(--mi-accent));pointer-events:none}.mi-dot-count{top:2px;right:2px;width:auto;min-width:16px;height:16px;padding:0 var(--fold-space-xs);display:grid;place-items:center;border-radius:var(--fold-radius-pill);font-size:var(--fold-text-2xs);font-weight:var(--fold-weight-semibold);line-height:var(--fold-leading-none);color:var(--fold-color-on-primary)}.mi-badge{display:none}.mi-badge-follow{padding:1px var(--fold-space-sm);border-radius:var(--fold-radius-pill);font-size:var(--fold-text-xs);font-weight:var(--fold-weight-medium);line-height:var(--fold-leading-normal);white-space:nowrap;background:color-mix(in srgb,var(--mi-badge-accent) 16%,transparent);border:1px solid color-mix(in srgb,var(--mi-badge-accent) 35%,transparent);color:color-mix(in srgb,var(--mi-badge-accent) 85%,var(--fold-color-text))}:host-context(fold-menu.expanded) .mi-dot{display:none}:host-context(fold-menu.expanded) .mi-badge{display:inline-flex;margin-left:auto}.mi-tip{position:fixed;left:var(--mi-tip-x, -9999px);top:var(--mi-tip-y, 0);transform:translateY(-50%);padding:var(--fold-space-xs) var(--fold-space-sm);border-radius:var(--fold-radius-sm);background:var(--fold-color-glass);border:1px solid var(--fold-color-glass-border);color:var(--fold-color-text);font-size:var(--fold-text-xs);white-space:nowrap;opacity:0;pointer-events:none;box-shadow:var(--fold-shadow-md);transition:opacity var(--fold-motion-fast);z-index:100}:host(:hover) .mi-tip{opacity:1}:host-context(fold-menu.expanded){width:auto;height:36px;display:flex;align-items:center;gap:var(--fold-space-md);padding:0 var(--fold-space-md)}:host-context(fold-menu.expanded) .mi-tip{position:static;transform:none;padding:0;border:none;background:none;box-shadow:none;color:inherit;font-size:var(--fold-text-sm);opacity:1;pointer-events:auto}\n"] }]
4477
4491
  }], propDecorators: { icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: true }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: true }] }], active: [{ type: i0.Input, args: [{ isSignal: true, alias: "active", required: false }] }], badge: [{ type: i0.Input, args: [{ isSignal: true, alias: "badge", required: false }] }], badgeTone: [{ type: i0.Input, args: [{ isSignal: true, alias: "badgeTone", required: false }] }] } });
4478
4492
 
4479
4493
  /**
@@ -4559,11 +4573,11 @@ class FoldMenuSectionComponent {
4559
4573
  this.collapsed.update((v) => !v);
4560
4574
  }
4561
4575
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: FoldMenuSectionComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
4562
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: FoldMenuSectionComponent, isStandalone: true, selector: "fold-menu-section", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, collapsible: { classPropertyName: "collapsible", publicName: "collapsible", isSignal: true, isRequired: false, transformFunction: null }, collapsed: { classPropertyName: "collapsed", publicName: "collapsed", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { collapsed: "collapsedChange" }, host: { properties: { "style.--fold-menu-section-color": "color() ?? null" } }, queries: [{ propertyName: "items", predicate: FoldMenuItemComponent, descendants: true, isSignal: true }], ngImport: i0, template: "@if (collapsible()) {\n <button\n type=\"button\"\n class=\"section-head\"\n [attr.aria-expanded]=\"open()\"\n [attr.aria-controls]=\"bodyId\"\n (click)=\"toggle()\"\n >\n <fold-menu-separator [label]=\"label()\" [color]=\"color()\" />\n <fold-icon\n class=\"section-chevron\"\n [class.is-open]=\"open()\"\n name=\"chevron-right\"\n [size]=\"12\"\n aria-hidden=\"true\"\n />\n </button>\n} @else {\n <fold-menu-separator [label]=\"label()\" [color]=\"color()\" />\n}\n\n<div\n class=\"section-items\"\n [id]=\"bodyId\"\n [class.foldable]=\"collapsible()\"\n [class.is-collapsed]=\"!open()\"\n>\n <ng-content />\n</div>\n", styles: ["@charset \"UTF-8\";:host{display:flex;flex-direction:column;align-items:center;gap:var(--fold-space-xs);width:100%}:host-context(fold-menu.expanded){align-items:stretch;width:auto}.section-items{display:contents}.section-head{all:unset;display:flex;align-items:center;width:100%;box-sizing:border-box;cursor:pointer}.section-head fold-menu-separator{flex:1;min-width:0}.section-chevron{flex-shrink:0;margin-left:auto;margin-right:var(--fold-space-sm);color:var(--fold-color-text-faded);transition:transform var(--fold-motion-fast)}.section-chevron.is-open{transform:rotate(90deg)}:host-context(fold-menu:not(.expanded)) .section-head{pointer-events:none}:host-context(fold-menu:not(.expanded)) .section-chevron{display:none}.section-items.foldable{display:flex;flex-direction:column;align-items:center;gap:var(--fold-space-xs);width:100%;overflow:hidden;max-height:60vh;opacity:1;transition:max-height var(--fold-motion-base),opacity var(--fold-motion-base)}:host-context(fold-menu.expanded) .section-items.foldable{align-items:stretch;width:auto}.section-items.foldable.is-collapsed{max-height:0;opacity:0}:host-context(fold-menu:not(.expanded)) .section-items.foldable{max-height:none;opacity:1}@media(prefers-reduced-motion:reduce){.section-items.foldable,.section-chevron{transition:none}}\n"], dependencies: [{ kind: "component", type: FoldMenuSeparatorComponent, selector: "fold-menu-separator", inputs: ["label", "color"] }, { kind: "component", type: FoldIconComponent, selector: "fold-icon", inputs: ["name", "size", "tone", "title"] }] });
4576
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: FoldMenuSectionComponent, isStandalone: true, selector: "fold-menu-section", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, collapsible: { classPropertyName: "collapsible", publicName: "collapsible", isSignal: true, isRequired: false, transformFunction: null }, collapsed: { classPropertyName: "collapsed", publicName: "collapsed", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { collapsed: "collapsedChange" }, host: { properties: { "style.--fold-menu-section-color": "color() ?? null" } }, queries: [{ propertyName: "items", predicate: FoldMenuItemComponent, descendants: true, isSignal: true }], ngImport: i0, template: "@if (collapsible()) {\n <button\n type=\"button\"\n class=\"section-head\"\n [attr.aria-expanded]=\"open()\"\n [attr.aria-controls]=\"bodyId\"\n (click)=\"toggle()\"\n >\n <fold-menu-separator [label]=\"label()\" [color]=\"color()\" />\n <fold-icon\n class=\"section-chevron\"\n [class.is-open]=\"open()\"\n name=\"chevron-right\"\n [size]=\"12\"\n aria-hidden=\"true\"\n />\n </button>\n} @else {\n <fold-menu-separator [label]=\"label()\" [color]=\"color()\" />\n}\n\n<div\n class=\"section-items\"\n [id]=\"bodyId\"\n [class.foldable]=\"collapsible()\"\n [class.is-collapsed]=\"!open()\"\n>\n <ng-content />\n</div>\n", styles: ["@charset \"UTF-8\";:host{display:flex;flex-direction:column;align-items:center;gap:var(--fold-space-xs);width:100%}:host-context(fold-menu.expanded){align-items:stretch;width:auto}.section-items{display:contents}.section-head{all:unset;display:flex;align-items:center;width:100%;box-sizing:border-box;cursor:pointer}.section-head fold-menu-separator{flex:1;min-width:0}.section-chevron{flex-shrink:0;margin-left:auto;margin-right:var(--fold-space-sm);color:var(--fold-color-text-faded);transition:transform var(--fold-motion-fast)}.section-chevron.is-open{transform:rotate(90deg)}:host-context(fold-menu:not(.expanded)) .section-head{pointer-events:none}:host-context(fold-menu:not(.expanded)) .section-chevron{display:none}.section-items.foldable{display:flex;flex-direction:column;align-items:center;gap:var(--fold-space-xs);width:100%;overflow:hidden;max-height:60vh;opacity:1;transition:max-height var(--fold-motion-base),opacity var(--fold-motion-base)}:host-context(fold-menu.expanded) .section-items.foldable{align-items:stretch;width:auto}.section-items.foldable.is-collapsed{max-height:0;opacity:0}:host-context(fold-menu:not(.expanded)) .section-items.foldable{max-height:none;opacity:1}@media(prefers-reduced-motion:reduce){.section-items.foldable,.section-chevron{transition:none}}:host-context(fold-menu.expanded) .section-items{display:flex;flex-direction:column;align-items:stretch;gap:var(--fold-space-xs);margin-left:var(--fold-space-md);padding-left:var(--fold-space-xs);border-left:2px solid color-mix(in srgb,var(--fold-menu-section-color, var(--fold-color-border)) 60%,transparent)}\n"], dependencies: [{ kind: "component", type: FoldMenuSeparatorComponent, selector: "fold-menu-separator", inputs: ["label", "color"] }, { kind: "component", type: FoldIconComponent, selector: "fold-icon", inputs: ["name", "size", "tone", "title"] }] });
4563
4577
  }
4564
4578
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: FoldMenuSectionComponent, decorators: [{
4565
4579
  type: Component,
4566
- args: [{ selector: "fold-menu-section", standalone: true, imports: [FoldMenuSeparatorComponent, FoldIconComponent], host: { "[style.--fold-menu-section-color]": "color() ?? null" }, template: "@if (collapsible()) {\n <button\n type=\"button\"\n class=\"section-head\"\n [attr.aria-expanded]=\"open()\"\n [attr.aria-controls]=\"bodyId\"\n (click)=\"toggle()\"\n >\n <fold-menu-separator [label]=\"label()\" [color]=\"color()\" />\n <fold-icon\n class=\"section-chevron\"\n [class.is-open]=\"open()\"\n name=\"chevron-right\"\n [size]=\"12\"\n aria-hidden=\"true\"\n />\n </button>\n} @else {\n <fold-menu-separator [label]=\"label()\" [color]=\"color()\" />\n}\n\n<div\n class=\"section-items\"\n [id]=\"bodyId\"\n [class.foldable]=\"collapsible()\"\n [class.is-collapsed]=\"!open()\"\n>\n <ng-content />\n</div>\n", styles: ["@charset \"UTF-8\";:host{display:flex;flex-direction:column;align-items:center;gap:var(--fold-space-xs);width:100%}:host-context(fold-menu.expanded){align-items:stretch;width:auto}.section-items{display:contents}.section-head{all:unset;display:flex;align-items:center;width:100%;box-sizing:border-box;cursor:pointer}.section-head fold-menu-separator{flex:1;min-width:0}.section-chevron{flex-shrink:0;margin-left:auto;margin-right:var(--fold-space-sm);color:var(--fold-color-text-faded);transition:transform var(--fold-motion-fast)}.section-chevron.is-open{transform:rotate(90deg)}:host-context(fold-menu:not(.expanded)) .section-head{pointer-events:none}:host-context(fold-menu:not(.expanded)) .section-chevron{display:none}.section-items.foldable{display:flex;flex-direction:column;align-items:center;gap:var(--fold-space-xs);width:100%;overflow:hidden;max-height:60vh;opacity:1;transition:max-height var(--fold-motion-base),opacity var(--fold-motion-base)}:host-context(fold-menu.expanded) .section-items.foldable{align-items:stretch;width:auto}.section-items.foldable.is-collapsed{max-height:0;opacity:0}:host-context(fold-menu:not(.expanded)) .section-items.foldable{max-height:none;opacity:1}@media(prefers-reduced-motion:reduce){.section-items.foldable,.section-chevron{transition:none}}\n"] }]
4580
+ args: [{ selector: "fold-menu-section", standalone: true, imports: [FoldMenuSeparatorComponent, FoldIconComponent], host: { "[style.--fold-menu-section-color]": "color() ?? null" }, template: "@if (collapsible()) {\n <button\n type=\"button\"\n class=\"section-head\"\n [attr.aria-expanded]=\"open()\"\n [attr.aria-controls]=\"bodyId\"\n (click)=\"toggle()\"\n >\n <fold-menu-separator [label]=\"label()\" [color]=\"color()\" />\n <fold-icon\n class=\"section-chevron\"\n [class.is-open]=\"open()\"\n name=\"chevron-right\"\n [size]=\"12\"\n aria-hidden=\"true\"\n />\n </button>\n} @else {\n <fold-menu-separator [label]=\"label()\" [color]=\"color()\" />\n}\n\n<div\n class=\"section-items\"\n [id]=\"bodyId\"\n [class.foldable]=\"collapsible()\"\n [class.is-collapsed]=\"!open()\"\n>\n <ng-content />\n</div>\n", styles: ["@charset \"UTF-8\";:host{display:flex;flex-direction:column;align-items:center;gap:var(--fold-space-xs);width:100%}:host-context(fold-menu.expanded){align-items:stretch;width:auto}.section-items{display:contents}.section-head{all:unset;display:flex;align-items:center;width:100%;box-sizing:border-box;cursor:pointer}.section-head fold-menu-separator{flex:1;min-width:0}.section-chevron{flex-shrink:0;margin-left:auto;margin-right:var(--fold-space-sm);color:var(--fold-color-text-faded);transition:transform var(--fold-motion-fast)}.section-chevron.is-open{transform:rotate(90deg)}:host-context(fold-menu:not(.expanded)) .section-head{pointer-events:none}:host-context(fold-menu:not(.expanded)) .section-chevron{display:none}.section-items.foldable{display:flex;flex-direction:column;align-items:center;gap:var(--fold-space-xs);width:100%;overflow:hidden;max-height:60vh;opacity:1;transition:max-height var(--fold-motion-base),opacity var(--fold-motion-base)}:host-context(fold-menu.expanded) .section-items.foldable{align-items:stretch;width:auto}.section-items.foldable.is-collapsed{max-height:0;opacity:0}:host-context(fold-menu:not(.expanded)) .section-items.foldable{max-height:none;opacity:1}@media(prefers-reduced-motion:reduce){.section-items.foldable,.section-chevron{transition:none}}:host-context(fold-menu.expanded) .section-items{display:flex;flex-direction:column;align-items:stretch;gap:var(--fold-space-xs);margin-left:var(--fold-space-md);padding-left:var(--fold-space-xs);border-left:2px solid color-mix(in srgb,var(--fold-menu-section-color, var(--fold-color-border)) 60%,transparent)}\n"] }]
4567
4581
  }], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }], collapsible: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsible", required: false }] }], collapsed: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapsed", required: false }] }, { type: i0.Output, args: ["collapsedChange"] }], items: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => FoldMenuItemComponent), { ...{
4568
4582
  descendants: true,
4569
4583
  }, isSignal: true }] }] } });
@@ -4930,6 +4944,8 @@ const DRILL_MS = 260;
4930
4944
  const BACK_MS = 200;
4931
4945
  /** When the entrance cascade is over and `:active` gets the transform back (ms). */
4932
4946
  const SETTLE_MS = 760;
4947
+ /** Up to this many level-1 items, `"auto"` lays out large tiles. */
4948
+ const FEW_ITEMS = 4;
4933
4949
  /** Horizontal travel that counts as a "swipe right" (px). */
4934
4950
  const SWIPE_PX = 56;
4935
4951
  /**
@@ -4999,8 +5015,14 @@ class FoldNavLauncherComponent {
4999
5015
  */
5000
5016
  glass = input(false, { ...(ngDevMode ? { debugName: "glass" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
5001
5017
  /**
5002
- * Grid column count. `"auto"` (default) scales to the number of level-1
5003
- * items: ≤4 → 2 columns, more → 3.
5018
+ * Grid column count. `"auto"` (default) lets the WIDTH decide: tiles fill the
5019
+ * row at a minimum size, so a phone keeps 2 (≤4 items) or 3 columns while a
5020
+ * tablet gets more, smaller columns instead of four 370 px squares. The
5021
+ * minimum depends on the item count — few items, large tiles.
5022
+ *
5023
+ * A number pins the count. Either way the grid never grows past
5024
+ * `--fold-nav-launcher-max-width` (default `720px`), centred, so a pinned
5025
+ * count cannot blow tiles up on a wide screen either.
5004
5026
  */
5005
5027
  columns = input("auto", /* @ts-ignore */
5006
5028
  ...(ngDevMode ? [{ debugName: "columns" }] : /* istanbul ignore next */ []));
@@ -5032,15 +5054,25 @@ class FoldNavLauncherComponent {
5032
5054
  /** The group whose tile is the anchor: the open one, or the one being opened. */
5033
5055
  anchor = computed(() => this.openGroup() ?? this.pending(), /* @ts-ignore */
5034
5056
  ...(ngDevMode ? [{ debugName: "anchor" }] : /* istanbul ignore next */ []));
5035
- /** The resolved column count (always a number for the grid var). */
5036
- resolvedCols = computed(() => {
5057
+ /** The pinned column count, or `null` when the width decides (`"auto"`). */
5058
+ fixedCols = computed(() => {
5037
5059
  const cols = this.columns();
5038
- if (cols !== "auto") {
5039
- return cols;
5060
+ return cols === "auto" ? null : cols;
5061
+ }, /* @ts-ignore */
5062
+ ...(ngDevMode ? [{ debugName: "fixedCols" }] : /* istanbul ignore next */ []));
5063
+ /**
5064
+ * Tile density in `"auto"` mode — picks the tile's minimum width in CSS:
5065
+ * `few` (≤4 items) → large tiles, `many` → compact ones. `null` when pinned.
5066
+ */
5067
+ density = computed(() => {
5068
+ if (this.fixedCols() !== null) {
5069
+ return null;
5040
5070
  }
5041
- return this.tiles().length + this.groups().length <= 4 ? 2 : 3;
5071
+ return this.tiles().length + this.groups().length <= FEW_ITEMS
5072
+ ? "few"
5073
+ : "many";
5042
5074
  }, /* @ts-ignore */
5043
- ...(ngDevMode ? [{ debugName: "resolvedCols" }] : /* istanbul ignore next */ []));
5075
+ ...(ngDevMode ? [{ debugName: "density" }] : /* istanbul ignore next */ []));
5044
5076
  /** The sheet's subtitle — derived from the group's own children, never passed. */
5045
5077
  entryCountText = computed(() => {
5046
5078
  const group = this.openGroup();
@@ -5223,13 +5255,13 @@ class FoldNavLauncherComponent {
5223
5255
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: FoldNavLauncherComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
5224
5256
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.8", type: FoldNavLauncherComponent, isStandalone: true, selector: "fold-nav-launcher", inputs: { open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, eyebrow: { classPropertyName: "eyebrow", publicName: "eyebrow", isSignal: true, isRequired: false, transformFunction: null }, heading: { classPropertyName: "heading", publicName: "heading", isSignal: true, isRequired: false, transformFunction: null }, closeLabel: { classPropertyName: "closeLabel", publicName: "closeLabel", isSignal: true, isRequired: false, transformFunction: null }, backLabel: { classPropertyName: "backLabel", publicName: "backLabel", isSignal: true, isRequired: false, transformFunction: null }, glass: { classPropertyName: "glass", publicName: "glass", isSignal: true, isRequired: false, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { open: "openChange" }, host: { listeners: { "document:keydown.escape": "onEscape()" } }, providers: [
5225
5257
  { provide: FOLD_NAV_LAUNCHER, useExisting: FoldNavLauncherComponent },
5226
- ], queries: [{ propertyName: "tiles", predicate: FoldNavTileComponent, isSignal: true }, { propertyName: "groups", predicate: FoldNavGroupComponent, isSignal: true }], ngImport: i0, template: "@if (open()) {\n <div class=\"nl-scrim\" aria-hidden=\"true\"></div>\n <!-- Le gestionnaire de renvoi vit sur le DIALOGUE, pas sur le voile : le\n dialogue est `position: fixed; inset: 0` par-dessus, donc un clic\n n'atteignait jamais le voile. Le clavier sort par `Escape`. -->\n <!-- Une SURFACE DE CHROME, et pas seulement un fond sombre : sans cette\n d\u00E9claration le lanceur peignait le sol du rail tout en lisant l'encre de\n la PAGE \u2014 texte sombre sur sombre, et des tuiles claires au milieu d'un\n panneau noir, sous tout th\u00E8me mixte (navi). Peindre le sol d'une famille\n sans en rejoindre la polarit\u00E9, c'est en revendiquer la moiti\u00E9. -->\n <div\n class=\"nl-dialog\"\n foldSurface=\"chrome\"\n role=\"dialog\"\n aria-modal=\"true\"\n [attr.aria-label]=\"label()\"\n [attr.data-level]=\"level()\"\n [attr.data-glass]=\"glass() ? '' : null\"\n [foldFocusTrap]=\"open()\"\n tabindex=\"-1\"\n (click)=\"onSurfaceClick($event)\"\n >\n <!-- Le voile de l'option verre. Sans lui, le flou n'a rien \u00E0 flouter et on\n n'obtient que des panneaux plus sombres. -->\n <div class=\"nl-veil\" aria-hidden=\"true\"></div>\n\n <header class=\"nl-head\">\n @if (anchor(); as group) {\n <button\n type=\"button\"\n class=\"nl-back\"\n [attr.aria-label]=\"backLabel()\"\n (click)=\"back()\"\n >\n <fold-icon name=\"chevron-left\" size=\"sm\" />\n </button>\n <!-- L'ANCRE. La tuile touch\u00E9e ne dispara\u00EEt pas : elle remonte ici, \u00E0\n sa taille de pastille. Cliquable, parce que l'\u00E9l\u00E9ment qui a servi\n de porte doit aussi servir de sortie. -->\n <button\n type=\"button\"\n class=\"nl-anchor\"\n [attr.aria-label]=\"backLabel()\"\n (click)=\"back()\"\n >\n @if (group.icon(); as name) {\n <fold-icon [name]=\"name\" size=\"sm\" />\n } @else {\n <span aria-hidden=\"true\">{{ group.label().charAt(0) }}</span>\n }\n </button>\n <span class=\"nl-titles\">\n <span class=\"nl-title\">{{ group.label() }}</span>\n <span class=\"nl-sub\">{{ entryCountText() }}</span>\n </span>\n } @else {\n <span class=\"nl-titles\">\n @if (eyebrow(); as e) {\n <span class=\"nl-eyebrow\">{{ e }}</span>\n }\n @if (heading(); as h) {\n <span class=\"nl-heading\">{{ h }}</span>\n }\n </span>\n }\n\n <button\n type=\"button\"\n class=\"nl-close\"\n [attr.aria-label]=\"closeLabel()\"\n (click)=\"close()\"\n >\n <fold-icon name=\"close\" size=\"md\" />\n </button>\n </header>\n\n <div\n class=\"nl-body\"\n (pointerdown)=\"onPointerDown($event)\"\n (pointerup)=\"onPointerUp($event)\"\n >\n <!-- La grille porte les DEUX niveaux : un groupe ouvert sort de la\n grille et couvre ce corps, sans que rien ne bouge dans le DOM. -->\n <div class=\"nl-grid\" [style.--nav-cols]=\"resolvedCols()\">\n <ng-content />\n </div>\n </div>\n\n <div class=\"nl-foot\">\n <ng-content select=\"[footer]\" />\n </div>\n\n <!-- Les deux crans de profondeur. `aria-hidden` : la r\u00E9gion vive dit la\n m\u00EAme chose en mots, et un lecteur d'\u00E9cran n'a que faire de deux\n pastilles. -->\n <div class=\"nl-dots\" aria-hidden=\"true\">\n <span class=\"nl-dot\" [class.is-on]=\"level() === 1\"></span>\n <span class=\"nl-dot\" [class.is-on]=\"level() === 2\"></span>\n </div>\n\n <!-- La descente est MUETTE sans ceci : l'animation ne compense rien. -->\n <p class=\"nl-live\" aria-live=\"polite\">{{ announcement() }}</p>\n </div>\n}\n", styles: ["@charset \"UTF-8\";:host{display:contents}.nl-scrim{position:fixed;inset:0;z-index:200;background:var(--fold-color-scrim);backdrop-filter:blur(var(--fold-blur-glass));-webkit-backdrop-filter:blur(var(--fold-blur-glass));animation:fold-nl-fade .2s ease}.nl-dialog{--fold-nl-gutter: var(--fold-space-xl);--fold-nl-ease-in: cubic-bezier(.22, 1, .36, 1);--fold-nl-tile-bg: var(--fold-color-surface-raised);--fold-nl-accent-bg: var(--fold-color-primary-surface);--fold-nl-sheet-bg: var(--fold-color-bg-rail-secondary);--fold-nl-row-bg: var(--fold-color-surface-card);--fold-nl-backdrop: none;--fold-nl-sheet-backdrop: none;position:fixed;inset:0;z-index:201;display:flex;flex-direction:column;padding:var(--fold-space-3xl) var(--fold-nl-gutter) var(--fold-space-xl);background:var(--fold-color-bg-rail-primary);color:var(--fold-color-text)}.nl-head{flex:none;display:flex;align-items:center;justify-content:space-between;gap:var(--fold-space-md);min-height:44px;margin-bottom:var(--fold-space-xl)}.nl-titles{display:flex;min-width:0;flex-direction:column}.nl-eyebrow{font-family:var(--fold-font-mono);font-size:var(--fold-text-xs);letter-spacing:var(--fold-tracking-caps);text-transform:uppercase;color:var(--fold-color-text-muted)}.nl-heading{font-size:var(--fold-text-xl);font-weight:var(--fold-weight-bold);letter-spacing:var(--fold-tracking-tighter);color:var(--fold-color-text)}.nl-title{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:var(--fold-text-lg);font-weight:var(--fold-weight-bold);letter-spacing:var(--fold-tracking-tighter);color:var(--fold-color-text);animation:fold-nl-crumb .32s var(--fold-nl-ease-in) both;animation-delay:40ms}.nl-sub{font-size:var(--fold-text-xs);color:var(--fold-color-text-muted);animation:fold-nl-crumb .32s var(--fold-nl-ease-in) both;animation-delay:40ms}.nl-back,.nl-close,.nl-anchor{flex:none;display:grid;place-items:center;width:30px;height:30px;padding:0;border-radius:var(--fold-radius-sm);background:var(--fold-color-surface-raised);border:1px solid var(--fold-color-border);color:var(--fold-color-text-secondary);cursor:pointer;transition:background .14s ease,color .14s ease}.nl-back:hover,.nl-close:hover{background:var(--fold-color-surface-hover);color:var(--fold-color-text)}.nl-anchor{background:var(--fold-color-primary);border-color:transparent;color:var(--fold-color-on-primary);animation:fold-nl-anchor-in .3s var(--fold-nl-ease-in) both}.nl-close{margin-inline-start:auto}.nl-body{position:relative;flex:1 1 auto;min-height:0;margin-inline:calc(-1 * var(--fold-nl-gutter));overflow:hidden}.nl-grid{padding-inline:var(--fold-nl-gutter);display:grid;grid-template-columns:repeat(var(--nav-cols, 3),1fr);gap:var(--fold-space-sm)}@media(max-width:360px){.nl-grid{grid-template-columns:repeat(2,1fr)}}.nl-dialog[data-level=\"2\"] .nl-grid{visibility:hidden}.nl-foot:not(:empty){flex:none;margin-top:auto;padding-top:var(--fold-space-md);border-top:1px solid var(--fold-color-border-subtle)}.nl-dots{flex:none;display:flex;align-items:center;justify-content:center;gap:var(--fold-space-xs);margin-top:var(--fold-space-md)}.nl-dot{width:22px;height:3px;border-radius:var(--fold-radius-pill);background:var(--fold-color-border);transition:background .28s ease}.nl-dot.is-on{background:var(--fold-color-primary)}.nl-live{position:absolute;width:1px;height:1px;margin:0;overflow:hidden;clip-path:inset(50%);white-space:nowrap}.nl-veil{position:absolute;inset:0;opacity:0;pointer-events:none;transition:opacity .3s ease;background:radial-gradient(120% 70% at 12% 4%,color-mix(in srgb,var(--fold-color-primary) 34%,transparent),transparent 58%),radial-gradient(90% 60% at 88% 22%,color-mix(in srgb,var(--fold-color-primary-strong) 30%,transparent),transparent 60%),radial-gradient(80% 55% at 70% 96%,color-mix(in srgb,var(--fold-color-warning) 16%,transparent),transparent 62%)}.nl-dialog[data-glass]{--fold-nl-tile-bg: color-mix( in srgb, var(--fold-color-bg-rail-secondary) 52%, transparent );--fold-nl-accent-bg: color-mix( in srgb, var(--fold-color-primary) 14%, transparent );--fold-nl-sheet-bg: color-mix( in srgb, var(--fold-color-bg-rail-secondary) 60%, transparent );--fold-nl-row-bg: color-mix( in srgb, var(--fold-color-surface-card) 50%, transparent );--fold-nl-backdrop: blur(20px) saturate(150%);--fold-nl-sheet-backdrop: blur(26px) saturate(150%);background:var(--fold-color-bg-header)}.nl-dialog[data-glass] .nl-veil{opacity:1}@keyframes fold-nl-fade{0%{opacity:0}to{opacity:1}}@keyframes fold-nl-crumb{0%{opacity:0;transform:translate(-12px)}to{opacity:1;transform:none}}@keyframes fold-nl-anchor-in{0%{opacity:0;transform:scale(.6) rotate(-8deg)}to{opacity:1;transform:none}}@media(prefers-reduced-motion:reduce){.nl-scrim,.nl-title,.nl-sub,.nl-anchor{animation:none}}\n"], dependencies: [{ kind: "directive", type: FocusTrapDirective, selector: "[foldFocusTrap]", inputs: ["foldFocusTrap"] }, { kind: "component", type: FoldIconComponent, selector: "fold-icon", inputs: ["name", "size", "tone", "title"] }, { kind: "directive", type: FoldSurfaceDirective, selector: "[foldSurface]", inputs: ["foldSurface"] }] });
5258
+ ], queries: [{ propertyName: "tiles", predicate: FoldNavTileComponent, isSignal: true }, { propertyName: "groups", predicate: FoldNavGroupComponent, isSignal: true }], ngImport: i0, template: "@if (open()) {\n <div class=\"nl-scrim\" aria-hidden=\"true\"></div>\n <!-- Le gestionnaire de renvoi vit sur le DIALOGUE, pas sur le voile : le\n dialogue est `position: fixed; inset: 0` par-dessus, donc un clic\n n'atteignait jamais le voile. Le clavier sort par `Escape`. -->\n <!-- Une SURFACE DE CHROME, et pas seulement un fond sombre : sans cette\n d\u00E9claration le lanceur peignait le sol du rail tout en lisant l'encre de\n la PAGE \u2014 texte sombre sur sombre, et des tuiles claires au milieu d'un\n panneau noir, sous tout th\u00E8me mixte (navi). Peindre le sol d'une famille\n sans en rejoindre la polarit\u00E9, c'est en revendiquer la moiti\u00E9. -->\n <div\n class=\"nl-dialog\"\n foldSurface=\"chrome\"\n role=\"dialog\"\n aria-modal=\"true\"\n [attr.aria-label]=\"label()\"\n [attr.data-level]=\"level()\"\n [attr.data-glass]=\"glass() ? '' : null\"\n [foldFocusTrap]=\"open()\"\n tabindex=\"-1\"\n (click)=\"onSurfaceClick($event)\"\n >\n <!-- Le voile de l'option verre. Sans lui, le flou n'a rien \u00E0 flouter et on\n n'obtient que des panneaux plus sombres. -->\n <div class=\"nl-veil\" aria-hidden=\"true\"></div>\n\n <header class=\"nl-head\">\n @if (anchor(); as group) {\n <button\n type=\"button\"\n class=\"nl-back\"\n [attr.aria-label]=\"backLabel()\"\n (click)=\"back()\"\n >\n <fold-icon name=\"chevron-left\" size=\"sm\" />\n </button>\n <!-- L'ANCRE. La tuile touch\u00E9e ne dispara\u00EEt pas : elle remonte ici, \u00E0\n sa taille de pastille. Cliquable, parce que l'\u00E9l\u00E9ment qui a servi\n de porte doit aussi servir de sortie. -->\n <button\n type=\"button\"\n class=\"nl-anchor\"\n [attr.aria-label]=\"backLabel()\"\n (click)=\"back()\"\n >\n @if (group.icon(); as name) {\n <fold-icon [name]=\"name\" size=\"sm\" />\n } @else {\n <span aria-hidden=\"true\">{{ group.label().charAt(0) }}</span>\n }\n </button>\n <span class=\"nl-titles\">\n <span class=\"nl-title\">{{ group.label() }}</span>\n <span class=\"nl-sub\">{{ entryCountText() }}</span>\n </span>\n } @else {\n <span class=\"nl-titles\">\n @if (eyebrow(); as e) {\n <span class=\"nl-eyebrow\">{{ e }}</span>\n }\n @if (heading(); as h) {\n <span class=\"nl-heading\">{{ h }}</span>\n }\n </span>\n }\n\n <button\n type=\"button\"\n class=\"nl-close\"\n [attr.aria-label]=\"closeLabel()\"\n (click)=\"close()\"\n >\n <fold-icon name=\"close\" size=\"md\" />\n </button>\n </header>\n\n <div\n class=\"nl-body\"\n (pointerdown)=\"onPointerDown($event)\"\n (pointerup)=\"onPointerUp($event)\"\n >\n <!-- La grille porte les DEUX niveaux : un groupe ouvert sort de la\n grille et couvre ce corps, sans que rien ne bouge dans le DOM. -->\n <div\n class=\"nl-grid\"\n [style.--nav-cols]=\"fixedCols()\"\n [attr.data-cols]=\"fixedCols() === null ? null : ''\"\n [attr.data-density]=\"density()\"\n >\n <ng-content />\n </div>\n </div>\n\n <div class=\"nl-foot\">\n <ng-content select=\"[footer]\" />\n </div>\n\n <!-- Les deux crans de profondeur. `aria-hidden` : la r\u00E9gion vive dit la\n m\u00EAme chose en mots, et un lecteur d'\u00E9cran n'a que faire de deux\n pastilles. -->\n <div class=\"nl-dots\" aria-hidden=\"true\">\n <span class=\"nl-dot\" [class.is-on]=\"level() === 1\"></span>\n <span class=\"nl-dot\" [class.is-on]=\"level() === 2\"></span>\n </div>\n\n <!-- La descente est MUETTE sans ceci : l'animation ne compense rien. -->\n <p class=\"nl-live\" aria-live=\"polite\">{{ announcement() }}</p>\n </div>\n}\n", styles: ["@charset \"UTF-8\";:host{display:contents}.nl-scrim{position:fixed;inset:0;z-index:200;background:var(--fold-color-scrim);backdrop-filter:blur(var(--fold-blur-glass));-webkit-backdrop-filter:blur(var(--fold-blur-glass));animation:fold-nl-fade .2s ease}.nl-dialog{--fold-nl-gutter: var(--fold-space-xl);--fold-nav-launcher-max-width: 720px;--fold-nl-ease-in: cubic-bezier(.22, 1, .36, 1);--fold-nl-tile-bg: var(--fold-color-surface-raised);--fold-nl-accent-bg: var(--fold-color-primary-surface);--fold-nl-sheet-bg: var(--fold-color-bg-rail-secondary);--fold-nl-row-bg: var(--fold-color-surface-card);--fold-nl-backdrop: none;--fold-nl-sheet-backdrop: none;position:fixed;inset:0;z-index:201;display:flex;flex-direction:column;padding:var(--fold-space-3xl) var(--fold-nl-gutter) var(--fold-space-xl);background:var(--fold-color-bg-rail-primary);color:var(--fold-color-text)}.nl-head{flex:none;display:flex;align-items:center;justify-content:space-between;gap:var(--fold-space-md);min-height:44px;margin-bottom:var(--fold-space-xl)}.nl-titles{display:flex;min-width:0;flex-direction:column}.nl-eyebrow{font-family:var(--fold-font-mono);font-size:var(--fold-text-xs);letter-spacing:var(--fold-tracking-caps);text-transform:uppercase;color:var(--fold-color-text-muted)}.nl-heading{font-size:var(--fold-text-xl);font-weight:var(--fold-weight-bold);letter-spacing:var(--fold-tracking-tighter);color:var(--fold-color-text)}.nl-title{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:var(--fold-text-lg);font-weight:var(--fold-weight-bold);letter-spacing:var(--fold-tracking-tighter);color:var(--fold-color-text);animation:fold-nl-crumb .32s var(--fold-nl-ease-in) both;animation-delay:40ms}.nl-sub{font-size:var(--fold-text-xs);color:var(--fold-color-text-muted);animation:fold-nl-crumb .32s var(--fold-nl-ease-in) both;animation-delay:40ms}.nl-back,.nl-close,.nl-anchor{flex:none;display:grid;place-items:center;width:30px;height:30px;padding:0;border-radius:var(--fold-radius-sm);background:var(--fold-color-surface-raised);border:1px solid var(--fold-color-border);color:var(--fold-color-text-secondary);cursor:pointer;transition:background .14s ease,color .14s ease}.nl-back:hover,.nl-close:hover{background:var(--fold-color-surface-hover);color:var(--fold-color-text)}.nl-anchor{background:var(--fold-color-primary);border-color:transparent;color:var(--fold-color-on-primary);animation:fold-nl-anchor-in .3s var(--fold-nl-ease-in) both}.nl-close{margin-inline-start:auto}.nl-body{position:relative;display:flex;flex-direction:column;flex:1 1 auto;min-height:0;margin-inline:calc(-1 * var(--fold-nl-gutter));overflow:hidden}.nl-grid{--nav-tile-min: 96px;flex:1 1 auto;min-height:0;overflow-y:auto;overscroll-behavior:contain;-webkit-overflow-scrolling:touch;padding-inline:max(var(--fold-nl-gutter),(100% - var(--fold-nav-launcher-max-width)) / 2);padding-block-end:var(--fold-space-sm);display:grid;grid-template-columns:repeat(auto-fill,minmax(min(100%,var(--nav-tile-min)),1fr));grid-auto-rows:max-content;align-content:start;gap:var(--fold-space-sm)}.nl-grid[data-density=few]{--nav-tile-min: 144px}.nl-grid[data-cols]{grid-template-columns:repeat(var(--nav-cols),minmax(0,1fr))}@media(max-width:360px){.nl-grid,.nl-grid[data-cols]{grid-template-columns:repeat(2,minmax(0,1fr))}}.nl-dialog[data-level=\"2\"] .nl-grid{visibility:hidden}.nl-foot:not(:empty){flex:none;margin-top:auto;padding-top:var(--fold-space-md);border-top:1px solid var(--fold-color-border-subtle)}.nl-dots{flex:none;display:flex;align-items:center;justify-content:center;gap:var(--fold-space-xs);margin-top:var(--fold-space-md)}.nl-dot{width:22px;height:3px;border-radius:var(--fold-radius-pill);background:var(--fold-color-border);transition:background .28s ease}.nl-dot.is-on{background:var(--fold-color-primary)}.nl-live{position:absolute;width:1px;height:1px;margin:0;overflow:hidden;clip-path:inset(50%);white-space:nowrap}.nl-veil{position:absolute;inset:0;opacity:0;pointer-events:none;transition:opacity .3s ease;background:radial-gradient(120% 70% at 12% 4%,color-mix(in srgb,var(--fold-color-primary) 34%,transparent),transparent 58%),radial-gradient(90% 60% at 88% 22%,color-mix(in srgb,var(--fold-color-primary-strong) 30%,transparent),transparent 60%),radial-gradient(80% 55% at 70% 96%,color-mix(in srgb,var(--fold-color-warning) 16%,transparent),transparent 62%)}.nl-dialog[data-glass]{--fold-nl-tile-bg: color-mix( in srgb, var(--fold-color-bg-rail-secondary) 52%, transparent );--fold-nl-accent-bg: color-mix( in srgb, var(--fold-color-primary) 14%, transparent );--fold-nl-sheet-bg: color-mix( in srgb, var(--fold-color-bg-rail-secondary) 60%, transparent );--fold-nl-row-bg: color-mix( in srgb, var(--fold-color-surface-card) 50%, transparent );--fold-nl-backdrop: blur(20px) saturate(150%);--fold-nl-sheet-backdrop: blur(26px) saturate(150%);background:var(--fold-color-bg-header)}.nl-dialog[data-glass] .nl-veil{opacity:1}@keyframes fold-nl-fade{0%{opacity:0}to{opacity:1}}@keyframes fold-nl-crumb{0%{opacity:0;transform:translate(-12px)}to{opacity:1;transform:none}}@keyframes fold-nl-anchor-in{0%{opacity:0;transform:scale(.6) rotate(-8deg)}to{opacity:1;transform:none}}@media(prefers-reduced-motion:reduce){.nl-scrim,.nl-title,.nl-sub,.nl-anchor{animation:none}}\n"], dependencies: [{ kind: "directive", type: FocusTrapDirective, selector: "[foldFocusTrap]", inputs: ["foldFocusTrap"] }, { kind: "component", type: FoldIconComponent, selector: "fold-icon", inputs: ["name", "size", "tone", "title"] }, { kind: "directive", type: FoldSurfaceDirective, selector: "[foldSurface]", inputs: ["foldSurface"] }] });
5227
5259
  }
5228
5260
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: FoldNavLauncherComponent, decorators: [{
5229
5261
  type: Component,
5230
5262
  args: [{ selector: "fold-nav-launcher", standalone: true, imports: [FocusTrapDirective, FoldIconComponent, FoldSurfaceDirective], providers: [
5231
5263
  { provide: FOLD_NAV_LAUNCHER, useExisting: FoldNavLauncherComponent },
5232
- ], template: "@if (open()) {\n <div class=\"nl-scrim\" aria-hidden=\"true\"></div>\n <!-- Le gestionnaire de renvoi vit sur le DIALOGUE, pas sur le voile : le\n dialogue est `position: fixed; inset: 0` par-dessus, donc un clic\n n'atteignait jamais le voile. Le clavier sort par `Escape`. -->\n <!-- Une SURFACE DE CHROME, et pas seulement un fond sombre : sans cette\n d\u00E9claration le lanceur peignait le sol du rail tout en lisant l'encre de\n la PAGE \u2014 texte sombre sur sombre, et des tuiles claires au milieu d'un\n panneau noir, sous tout th\u00E8me mixte (navi). Peindre le sol d'une famille\n sans en rejoindre la polarit\u00E9, c'est en revendiquer la moiti\u00E9. -->\n <div\n class=\"nl-dialog\"\n foldSurface=\"chrome\"\n role=\"dialog\"\n aria-modal=\"true\"\n [attr.aria-label]=\"label()\"\n [attr.data-level]=\"level()\"\n [attr.data-glass]=\"glass() ? '' : null\"\n [foldFocusTrap]=\"open()\"\n tabindex=\"-1\"\n (click)=\"onSurfaceClick($event)\"\n >\n <!-- Le voile de l'option verre. Sans lui, le flou n'a rien \u00E0 flouter et on\n n'obtient que des panneaux plus sombres. -->\n <div class=\"nl-veil\" aria-hidden=\"true\"></div>\n\n <header class=\"nl-head\">\n @if (anchor(); as group) {\n <button\n type=\"button\"\n class=\"nl-back\"\n [attr.aria-label]=\"backLabel()\"\n (click)=\"back()\"\n >\n <fold-icon name=\"chevron-left\" size=\"sm\" />\n </button>\n <!-- L'ANCRE. La tuile touch\u00E9e ne dispara\u00EEt pas : elle remonte ici, \u00E0\n sa taille de pastille. Cliquable, parce que l'\u00E9l\u00E9ment qui a servi\n de porte doit aussi servir de sortie. -->\n <button\n type=\"button\"\n class=\"nl-anchor\"\n [attr.aria-label]=\"backLabel()\"\n (click)=\"back()\"\n >\n @if (group.icon(); as name) {\n <fold-icon [name]=\"name\" size=\"sm\" />\n } @else {\n <span aria-hidden=\"true\">{{ group.label().charAt(0) }}</span>\n }\n </button>\n <span class=\"nl-titles\">\n <span class=\"nl-title\">{{ group.label() }}</span>\n <span class=\"nl-sub\">{{ entryCountText() }}</span>\n </span>\n } @else {\n <span class=\"nl-titles\">\n @if (eyebrow(); as e) {\n <span class=\"nl-eyebrow\">{{ e }}</span>\n }\n @if (heading(); as h) {\n <span class=\"nl-heading\">{{ h }}</span>\n }\n </span>\n }\n\n <button\n type=\"button\"\n class=\"nl-close\"\n [attr.aria-label]=\"closeLabel()\"\n (click)=\"close()\"\n >\n <fold-icon name=\"close\" size=\"md\" />\n </button>\n </header>\n\n <div\n class=\"nl-body\"\n (pointerdown)=\"onPointerDown($event)\"\n (pointerup)=\"onPointerUp($event)\"\n >\n <!-- La grille porte les DEUX niveaux : un groupe ouvert sort de la\n grille et couvre ce corps, sans que rien ne bouge dans le DOM. -->\n <div class=\"nl-grid\" [style.--nav-cols]=\"resolvedCols()\">\n <ng-content />\n </div>\n </div>\n\n <div class=\"nl-foot\">\n <ng-content select=\"[footer]\" />\n </div>\n\n <!-- Les deux crans de profondeur. `aria-hidden` : la r\u00E9gion vive dit la\n m\u00EAme chose en mots, et un lecteur d'\u00E9cran n'a que faire de deux\n pastilles. -->\n <div class=\"nl-dots\" aria-hidden=\"true\">\n <span class=\"nl-dot\" [class.is-on]=\"level() === 1\"></span>\n <span class=\"nl-dot\" [class.is-on]=\"level() === 2\"></span>\n </div>\n\n <!-- La descente est MUETTE sans ceci : l'animation ne compense rien. -->\n <p class=\"nl-live\" aria-live=\"polite\">{{ announcement() }}</p>\n </div>\n}\n", styles: ["@charset \"UTF-8\";:host{display:contents}.nl-scrim{position:fixed;inset:0;z-index:200;background:var(--fold-color-scrim);backdrop-filter:blur(var(--fold-blur-glass));-webkit-backdrop-filter:blur(var(--fold-blur-glass));animation:fold-nl-fade .2s ease}.nl-dialog{--fold-nl-gutter: var(--fold-space-xl);--fold-nl-ease-in: cubic-bezier(.22, 1, .36, 1);--fold-nl-tile-bg: var(--fold-color-surface-raised);--fold-nl-accent-bg: var(--fold-color-primary-surface);--fold-nl-sheet-bg: var(--fold-color-bg-rail-secondary);--fold-nl-row-bg: var(--fold-color-surface-card);--fold-nl-backdrop: none;--fold-nl-sheet-backdrop: none;position:fixed;inset:0;z-index:201;display:flex;flex-direction:column;padding:var(--fold-space-3xl) var(--fold-nl-gutter) var(--fold-space-xl);background:var(--fold-color-bg-rail-primary);color:var(--fold-color-text)}.nl-head{flex:none;display:flex;align-items:center;justify-content:space-between;gap:var(--fold-space-md);min-height:44px;margin-bottom:var(--fold-space-xl)}.nl-titles{display:flex;min-width:0;flex-direction:column}.nl-eyebrow{font-family:var(--fold-font-mono);font-size:var(--fold-text-xs);letter-spacing:var(--fold-tracking-caps);text-transform:uppercase;color:var(--fold-color-text-muted)}.nl-heading{font-size:var(--fold-text-xl);font-weight:var(--fold-weight-bold);letter-spacing:var(--fold-tracking-tighter);color:var(--fold-color-text)}.nl-title{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:var(--fold-text-lg);font-weight:var(--fold-weight-bold);letter-spacing:var(--fold-tracking-tighter);color:var(--fold-color-text);animation:fold-nl-crumb .32s var(--fold-nl-ease-in) both;animation-delay:40ms}.nl-sub{font-size:var(--fold-text-xs);color:var(--fold-color-text-muted);animation:fold-nl-crumb .32s var(--fold-nl-ease-in) both;animation-delay:40ms}.nl-back,.nl-close,.nl-anchor{flex:none;display:grid;place-items:center;width:30px;height:30px;padding:0;border-radius:var(--fold-radius-sm);background:var(--fold-color-surface-raised);border:1px solid var(--fold-color-border);color:var(--fold-color-text-secondary);cursor:pointer;transition:background .14s ease,color .14s ease}.nl-back:hover,.nl-close:hover{background:var(--fold-color-surface-hover);color:var(--fold-color-text)}.nl-anchor{background:var(--fold-color-primary);border-color:transparent;color:var(--fold-color-on-primary);animation:fold-nl-anchor-in .3s var(--fold-nl-ease-in) both}.nl-close{margin-inline-start:auto}.nl-body{position:relative;flex:1 1 auto;min-height:0;margin-inline:calc(-1 * var(--fold-nl-gutter));overflow:hidden}.nl-grid{padding-inline:var(--fold-nl-gutter);display:grid;grid-template-columns:repeat(var(--nav-cols, 3),1fr);gap:var(--fold-space-sm)}@media(max-width:360px){.nl-grid{grid-template-columns:repeat(2,1fr)}}.nl-dialog[data-level=\"2\"] .nl-grid{visibility:hidden}.nl-foot:not(:empty){flex:none;margin-top:auto;padding-top:var(--fold-space-md);border-top:1px solid var(--fold-color-border-subtle)}.nl-dots{flex:none;display:flex;align-items:center;justify-content:center;gap:var(--fold-space-xs);margin-top:var(--fold-space-md)}.nl-dot{width:22px;height:3px;border-radius:var(--fold-radius-pill);background:var(--fold-color-border);transition:background .28s ease}.nl-dot.is-on{background:var(--fold-color-primary)}.nl-live{position:absolute;width:1px;height:1px;margin:0;overflow:hidden;clip-path:inset(50%);white-space:nowrap}.nl-veil{position:absolute;inset:0;opacity:0;pointer-events:none;transition:opacity .3s ease;background:radial-gradient(120% 70% at 12% 4%,color-mix(in srgb,var(--fold-color-primary) 34%,transparent),transparent 58%),radial-gradient(90% 60% at 88% 22%,color-mix(in srgb,var(--fold-color-primary-strong) 30%,transparent),transparent 60%),radial-gradient(80% 55% at 70% 96%,color-mix(in srgb,var(--fold-color-warning) 16%,transparent),transparent 62%)}.nl-dialog[data-glass]{--fold-nl-tile-bg: color-mix( in srgb, var(--fold-color-bg-rail-secondary) 52%, transparent );--fold-nl-accent-bg: color-mix( in srgb, var(--fold-color-primary) 14%, transparent );--fold-nl-sheet-bg: color-mix( in srgb, var(--fold-color-bg-rail-secondary) 60%, transparent );--fold-nl-row-bg: color-mix( in srgb, var(--fold-color-surface-card) 50%, transparent );--fold-nl-backdrop: blur(20px) saturate(150%);--fold-nl-sheet-backdrop: blur(26px) saturate(150%);background:var(--fold-color-bg-header)}.nl-dialog[data-glass] .nl-veil{opacity:1}@keyframes fold-nl-fade{0%{opacity:0}to{opacity:1}}@keyframes fold-nl-crumb{0%{opacity:0;transform:translate(-12px)}to{opacity:1;transform:none}}@keyframes fold-nl-anchor-in{0%{opacity:0;transform:scale(.6) rotate(-8deg)}to{opacity:1;transform:none}}@media(prefers-reduced-motion:reduce){.nl-scrim,.nl-title,.nl-sub,.nl-anchor{animation:none}}\n"] }]
5264
+ ], template: "@if (open()) {\n <div class=\"nl-scrim\" aria-hidden=\"true\"></div>\n <!-- Le gestionnaire de renvoi vit sur le DIALOGUE, pas sur le voile : le\n dialogue est `position: fixed; inset: 0` par-dessus, donc un clic\n n'atteignait jamais le voile. Le clavier sort par `Escape`. -->\n <!-- Une SURFACE DE CHROME, et pas seulement un fond sombre : sans cette\n d\u00E9claration le lanceur peignait le sol du rail tout en lisant l'encre de\n la PAGE \u2014 texte sombre sur sombre, et des tuiles claires au milieu d'un\n panneau noir, sous tout th\u00E8me mixte (navi). Peindre le sol d'une famille\n sans en rejoindre la polarit\u00E9, c'est en revendiquer la moiti\u00E9. -->\n <div\n class=\"nl-dialog\"\n foldSurface=\"chrome\"\n role=\"dialog\"\n aria-modal=\"true\"\n [attr.aria-label]=\"label()\"\n [attr.data-level]=\"level()\"\n [attr.data-glass]=\"glass() ? '' : null\"\n [foldFocusTrap]=\"open()\"\n tabindex=\"-1\"\n (click)=\"onSurfaceClick($event)\"\n >\n <!-- Le voile de l'option verre. Sans lui, le flou n'a rien \u00E0 flouter et on\n n'obtient que des panneaux plus sombres. -->\n <div class=\"nl-veil\" aria-hidden=\"true\"></div>\n\n <header class=\"nl-head\">\n @if (anchor(); as group) {\n <button\n type=\"button\"\n class=\"nl-back\"\n [attr.aria-label]=\"backLabel()\"\n (click)=\"back()\"\n >\n <fold-icon name=\"chevron-left\" size=\"sm\" />\n </button>\n <!-- L'ANCRE. La tuile touch\u00E9e ne dispara\u00EEt pas : elle remonte ici, \u00E0\n sa taille de pastille. Cliquable, parce que l'\u00E9l\u00E9ment qui a servi\n de porte doit aussi servir de sortie. -->\n <button\n type=\"button\"\n class=\"nl-anchor\"\n [attr.aria-label]=\"backLabel()\"\n (click)=\"back()\"\n >\n @if (group.icon(); as name) {\n <fold-icon [name]=\"name\" size=\"sm\" />\n } @else {\n <span aria-hidden=\"true\">{{ group.label().charAt(0) }}</span>\n }\n </button>\n <span class=\"nl-titles\">\n <span class=\"nl-title\">{{ group.label() }}</span>\n <span class=\"nl-sub\">{{ entryCountText() }}</span>\n </span>\n } @else {\n <span class=\"nl-titles\">\n @if (eyebrow(); as e) {\n <span class=\"nl-eyebrow\">{{ e }}</span>\n }\n @if (heading(); as h) {\n <span class=\"nl-heading\">{{ h }}</span>\n }\n </span>\n }\n\n <button\n type=\"button\"\n class=\"nl-close\"\n [attr.aria-label]=\"closeLabel()\"\n (click)=\"close()\"\n >\n <fold-icon name=\"close\" size=\"md\" />\n </button>\n </header>\n\n <div\n class=\"nl-body\"\n (pointerdown)=\"onPointerDown($event)\"\n (pointerup)=\"onPointerUp($event)\"\n >\n <!-- La grille porte les DEUX niveaux : un groupe ouvert sort de la\n grille et couvre ce corps, sans que rien ne bouge dans le DOM. -->\n <div\n class=\"nl-grid\"\n [style.--nav-cols]=\"fixedCols()\"\n [attr.data-cols]=\"fixedCols() === null ? null : ''\"\n [attr.data-density]=\"density()\"\n >\n <ng-content />\n </div>\n </div>\n\n <div class=\"nl-foot\">\n <ng-content select=\"[footer]\" />\n </div>\n\n <!-- Les deux crans de profondeur. `aria-hidden` : la r\u00E9gion vive dit la\n m\u00EAme chose en mots, et un lecteur d'\u00E9cran n'a que faire de deux\n pastilles. -->\n <div class=\"nl-dots\" aria-hidden=\"true\">\n <span class=\"nl-dot\" [class.is-on]=\"level() === 1\"></span>\n <span class=\"nl-dot\" [class.is-on]=\"level() === 2\"></span>\n </div>\n\n <!-- La descente est MUETTE sans ceci : l'animation ne compense rien. -->\n <p class=\"nl-live\" aria-live=\"polite\">{{ announcement() }}</p>\n </div>\n}\n", styles: ["@charset \"UTF-8\";:host{display:contents}.nl-scrim{position:fixed;inset:0;z-index:200;background:var(--fold-color-scrim);backdrop-filter:blur(var(--fold-blur-glass));-webkit-backdrop-filter:blur(var(--fold-blur-glass));animation:fold-nl-fade .2s ease}.nl-dialog{--fold-nl-gutter: var(--fold-space-xl);--fold-nav-launcher-max-width: 720px;--fold-nl-ease-in: cubic-bezier(.22, 1, .36, 1);--fold-nl-tile-bg: var(--fold-color-surface-raised);--fold-nl-accent-bg: var(--fold-color-primary-surface);--fold-nl-sheet-bg: var(--fold-color-bg-rail-secondary);--fold-nl-row-bg: var(--fold-color-surface-card);--fold-nl-backdrop: none;--fold-nl-sheet-backdrop: none;position:fixed;inset:0;z-index:201;display:flex;flex-direction:column;padding:var(--fold-space-3xl) var(--fold-nl-gutter) var(--fold-space-xl);background:var(--fold-color-bg-rail-primary);color:var(--fold-color-text)}.nl-head{flex:none;display:flex;align-items:center;justify-content:space-between;gap:var(--fold-space-md);min-height:44px;margin-bottom:var(--fold-space-xl)}.nl-titles{display:flex;min-width:0;flex-direction:column}.nl-eyebrow{font-family:var(--fold-font-mono);font-size:var(--fold-text-xs);letter-spacing:var(--fold-tracking-caps);text-transform:uppercase;color:var(--fold-color-text-muted)}.nl-heading{font-size:var(--fold-text-xl);font-weight:var(--fold-weight-bold);letter-spacing:var(--fold-tracking-tighter);color:var(--fold-color-text)}.nl-title{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:var(--fold-text-lg);font-weight:var(--fold-weight-bold);letter-spacing:var(--fold-tracking-tighter);color:var(--fold-color-text);animation:fold-nl-crumb .32s var(--fold-nl-ease-in) both;animation-delay:40ms}.nl-sub{font-size:var(--fold-text-xs);color:var(--fold-color-text-muted);animation:fold-nl-crumb .32s var(--fold-nl-ease-in) both;animation-delay:40ms}.nl-back,.nl-close,.nl-anchor{flex:none;display:grid;place-items:center;width:30px;height:30px;padding:0;border-radius:var(--fold-radius-sm);background:var(--fold-color-surface-raised);border:1px solid var(--fold-color-border);color:var(--fold-color-text-secondary);cursor:pointer;transition:background .14s ease,color .14s ease}.nl-back:hover,.nl-close:hover{background:var(--fold-color-surface-hover);color:var(--fold-color-text)}.nl-anchor{background:var(--fold-color-primary);border-color:transparent;color:var(--fold-color-on-primary);animation:fold-nl-anchor-in .3s var(--fold-nl-ease-in) both}.nl-close{margin-inline-start:auto}.nl-body{position:relative;display:flex;flex-direction:column;flex:1 1 auto;min-height:0;margin-inline:calc(-1 * var(--fold-nl-gutter));overflow:hidden}.nl-grid{--nav-tile-min: 96px;flex:1 1 auto;min-height:0;overflow-y:auto;overscroll-behavior:contain;-webkit-overflow-scrolling:touch;padding-inline:max(var(--fold-nl-gutter),(100% - var(--fold-nav-launcher-max-width)) / 2);padding-block-end:var(--fold-space-sm);display:grid;grid-template-columns:repeat(auto-fill,minmax(min(100%,var(--nav-tile-min)),1fr));grid-auto-rows:max-content;align-content:start;gap:var(--fold-space-sm)}.nl-grid[data-density=few]{--nav-tile-min: 144px}.nl-grid[data-cols]{grid-template-columns:repeat(var(--nav-cols),minmax(0,1fr))}@media(max-width:360px){.nl-grid,.nl-grid[data-cols]{grid-template-columns:repeat(2,minmax(0,1fr))}}.nl-dialog[data-level=\"2\"] .nl-grid{visibility:hidden}.nl-foot:not(:empty){flex:none;margin-top:auto;padding-top:var(--fold-space-md);border-top:1px solid var(--fold-color-border-subtle)}.nl-dots{flex:none;display:flex;align-items:center;justify-content:center;gap:var(--fold-space-xs);margin-top:var(--fold-space-md)}.nl-dot{width:22px;height:3px;border-radius:var(--fold-radius-pill);background:var(--fold-color-border);transition:background .28s ease}.nl-dot.is-on{background:var(--fold-color-primary)}.nl-live{position:absolute;width:1px;height:1px;margin:0;overflow:hidden;clip-path:inset(50%);white-space:nowrap}.nl-veil{position:absolute;inset:0;opacity:0;pointer-events:none;transition:opacity .3s ease;background:radial-gradient(120% 70% at 12% 4%,color-mix(in srgb,var(--fold-color-primary) 34%,transparent),transparent 58%),radial-gradient(90% 60% at 88% 22%,color-mix(in srgb,var(--fold-color-primary-strong) 30%,transparent),transparent 60%),radial-gradient(80% 55% at 70% 96%,color-mix(in srgb,var(--fold-color-warning) 16%,transparent),transparent 62%)}.nl-dialog[data-glass]{--fold-nl-tile-bg: color-mix( in srgb, var(--fold-color-bg-rail-secondary) 52%, transparent );--fold-nl-accent-bg: color-mix( in srgb, var(--fold-color-primary) 14%, transparent );--fold-nl-sheet-bg: color-mix( in srgb, var(--fold-color-bg-rail-secondary) 60%, transparent );--fold-nl-row-bg: color-mix( in srgb, var(--fold-color-surface-card) 50%, transparent );--fold-nl-backdrop: blur(20px) saturate(150%);--fold-nl-sheet-backdrop: blur(26px) saturate(150%);background:var(--fold-color-bg-header)}.nl-dialog[data-glass] .nl-veil{opacity:1}@keyframes fold-nl-fade{0%{opacity:0}to{opacity:1}}@keyframes fold-nl-crumb{0%{opacity:0;transform:translate(-12px)}to{opacity:1;transform:none}}@keyframes fold-nl-anchor-in{0%{opacity:0;transform:scale(.6) rotate(-8deg)}to{opacity:1;transform:none}}@media(prefers-reduced-motion:reduce){.nl-scrim,.nl-title,.nl-sub,.nl-anchor{animation:none}}\n"] }]
5233
5265
  }], ctorParameters: () => [], propDecorators: { open: [{ type: i0.Input, args: [{ isSignal: true, alias: "open", required: false }] }, { type: i0.Output, args: ["openChange"] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], eyebrow: [{ type: i0.Input, args: [{ isSignal: true, alias: "eyebrow", required: false }] }], heading: [{ type: i0.Input, args: [{ isSignal: true, alias: "heading", required: false }] }], closeLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeLabel", required: false }] }], backLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "backLabel", required: false }] }], glass: [{ type: i0.Input, args: [{ isSignal: true, alias: "glass", required: false }] }], columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: false }] }], tiles: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => FoldNavTileComponent), { isSignal: true }] }], groups: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => FoldNavGroupComponent), { isSignal: true }] }], onEscape: [{
5234
5266
  type: HostListener,
5235
5267
  args: ["document:keydown.escape"]