@flyos/design-system 3.10.0 → 3.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -47,7 +47,7 @@ import { CdkConnectedOverlay, CdkOverlayOrigin } from '@angular/cdk/overlay';
47
47
  // tools/publish-library.ps1 at bump time, and asserted by the spec beside this file.
48
48
  // Used only for the diagnostic message; the duplicate-instance detection itself is
49
49
  // version-agnostic, so a stale literal misnames a fork rather than hiding one.
50
- const FLY_DS_VERSION = '3.10.0';
50
+ const FLY_DS_VERSION = '3.11.0';
51
51
  const FLY_DS_REGISTRY_KEY = '__FLY_DS_INSTANCES__';
52
52
  /**
53
53
  * Records this design-system instance on the shared `scope` and returns the
@@ -3339,6 +3339,46 @@ function provideFlyStandaloneAuth(config) {
3339
3339
  ]);
3340
3340
  }
3341
3341
 
3342
+ const DEFAULT_TTL_MS = 24 * 60 * 60 * 1000;
3343
+ /**
3344
+ * Auth wiring for a UI-developer build: sign in as a representative tenant user so the app runs
3345
+ * with **no STS**, and present a fixed bearer to whatever backend (real or mocked) it talks to.
3346
+ *
3347
+ * <p>The offline counterpart of `provideFlyStandaloneAuth`, and it deliberately provides the SAME
3348
+ * {@link FLY_STANDALONE_AUTH_CONFIG}. Two reasons, both learned the hard way:</p>
3349
+ * <ul>
3350
+ * <li>`flyStandaloneAuthInterceptor` injects that token unconditionally. Omitting it here does
3351
+ * not degrade gracefully — every HTTP call in the offline build throws a DI error at runtime,
3352
+ * which no typecheck or unit test catches.</li>
3353
+ * <li>The interceptor's path rules then hold identically in all build modes instead of being
3354
+ * re-stated per mode.</li>
3355
+ * </ul>
3356
+ *
3357
+ * <p>Seeding the shared {@link AuthService} store is the whole implementation, because that store
3358
+ * is the single source of truth for identity: `FlyStandaloneAuthService.isAuthenticated()` delegates
3359
+ * to it, so `flyStandaloneAuthGuard` passes and never reaches `startLogin()`, and the interceptor
3360
+ * reads the same token. No PKCE code path is entered offline.</p>
3361
+ *
3362
+ * <p><b>`STEP_UP_REAUTH_HANDLER` is intentionally NOT provided.</b> A step-up challenge cannot
3363
+ * arise offline, and a handler that redirected to a real STS would be actively wrong in a build
3364
+ * that has none.</p>
3365
+ *
3366
+ * @example
3367
+ * providers: [
3368
+ * offlineDataEnabled
3369
+ * ? provideFlyOfflineAuth({ auth: PPM_AUTH_CONFIG, user: OFFLINE_USER, accessToken: DEV_BEARER })
3370
+ * : provideFlyStandaloneAuth(PPM_AUTH_CONFIG),
3371
+ * ]
3372
+ */
3373
+ function provideFlyOfflineAuth(config) {
3374
+ return makeEnvironmentProviders([
3375
+ { provide: FLY_STANDALONE_AUTH_CONFIG, useValue: config.auth },
3376
+ provideAppInitializer(() => {
3377
+ inject(AuthService).setSession(config.user, config.accessToken, Date.now() + (config.sessionTtlMs ?? DEFAULT_TTL_MS));
3378
+ }),
3379
+ ]);
3380
+ }
3381
+
3342
3382
  /** Single source of truth for persisted / API theme strings. */
3343
3383
  const FLY_THEME_MODE_IDS = ['light', 'dark'];
3344
3384
  /** Factory default: `dark` (opaque dark / `html.dark-theme`); shell i18n `settings.theme.dark`. Keep in sync with `UserSettings` defaults. */
@@ -23103,6 +23143,298 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
23103
23143
  args: [{ selector: 'fly-meta', standalone: true, imports: [TranslatePipe], changeDetection: ChangeDetectionStrategy.OnPush, template: "<dl>\r\n @for (item of items(); track $index) {\r\n <div>\r\n <dt>{{ item.labelKey | translate }}</dt>\r\n <dd [class.mono]=\"item.mono ?? false\">{{ item.value }}</dd>\r\n </div>\r\n }\r\n <ng-content />\r\n</dl>\r\n", styles: [":host{display:block}dl{margin:0;display:flex;flex-direction:column;gap:10px}dl ::ng-deep>div{display:grid;grid-template-columns:96px 1fr;gap:var(--sp-3);align-items:baseline;font-size:var(--text-sm)}dl ::ng-deep dt{margin:0;font-size:10.5px;font-weight:var(--fw-medium);letter-spacing:var(--tracking-wide);text-transform:uppercase;color:var(--ink-4)}dl ::ng-deep dd{margin:0;min-width:0;color:var(--ink);word-break:break-word;line-height:1.45}dl ::ng-deep dd.mono,dl ::ng-deep dd .mono{font-size:var(--text-2xs)}\n"] }]
23104
23144
  }], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: true }] }] } });
23105
23145
 
23146
+ /**
23147
+ * Generic Overview-section content surface — the `--w03`/`--w06` tinted
23148
+ * plate a non-card section body (Description text, a chips tray, a members
23149
+ * tray, an activity tray) sits on inside a {@link FlyOverviewSectionComponent}.
23150
+ * Deliberately presentation-only: no shadow, gradient, hover, or cursor —
23151
+ * this is quiet inner paper, not a clickable surface.
23152
+ *
23153
+ * Content is left to projection so each Overview variant keeps its own real
23154
+ * markup (and, for Members/Chips/Activity, its own live Angular bindings and
23155
+ * interactions) — this component only paints the box.
23156
+ *
23157
+ * `[proseText]` additionally applies the Description-section body-copy
23158
+ * typography directly on the host, for the common case of one bound string
23159
+ * with nothing else inside. Leave it off for any other content (chips,
23160
+ * member rows, a nested `fly-overview-rows`) — those bring their own type.
23161
+ *
23162
+ * ```html
23163
+ * <fly-overview-surface [proseText]="true">{{ project().description }}</fly-overview-surface>
23164
+ *
23165
+ * <fly-overview-surface>
23166
+ * @for (m of project().members; track m.id) { <fly-chip>{{ m.name }}</fly-chip> }
23167
+ * </fly-overview-surface>
23168
+ * ```
23169
+ */
23170
+ class FlyOverviewSurfaceComponent {
23171
+ /** Apply the Description-section body-copy typography on the host. */
23172
+ proseText = input(false, ...(ngDevMode ? [{ debugName: "proseText" }] : /* istanbul ignore next */ []));
23173
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: FlyOverviewSurfaceComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
23174
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.19", type: FlyOverviewSurfaceComponent, isStandalone: true, selector: "fly-overview-surface", inputs: { proseText: { classPropertyName: "proseText", publicName: "proseText", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class.ovsf--prose": "proseText()" }, classAttribute: "ovsf" }, ngImport: i0, template: '<ng-content />', isInline: true, styles: [":host{display:block;padding:12px 14px;border-radius:11px;background:var(--w03);border:1px solid var(--w06)}:host(.ovsf--prose){font-family:var(--font-family);font-weight:400;font-size:13px;line-height:1.55;color:var(--w72);text-wrap:pretty}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
23175
+ }
23176
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: FlyOverviewSurfaceComponent, decorators: [{
23177
+ type: Component,
23178
+ args: [{ selector: 'fly-overview-surface', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, host: {
23179
+ class: 'ovsf',
23180
+ '[class.ovsf--prose]': 'proseText()',
23181
+ }, template: '<ng-content />', styles: [":host{display:block;padding:12px 14px;border-radius:11px;background:var(--w03);border:1px solid var(--w06)}:host(.ovsf--prose){font-family:var(--font-family);font-weight:400;font-size:13px;line-height:1.55;color:var(--w72);text-wrap:pretty}\n"] }]
23182
+ }], propDecorators: { proseText: [{ type: i0.Input, args: [{ isSignal: true, alias: "proseText", required: false }] }] } });
23183
+
23184
+ /**
23185
+ * Overview "Summary" KPI row — a wrapping row of flat stat cards, each with
23186
+ * the value/label stack at inline-start and the icon on a solid tone tile at
23187
+ * inline-end (the KPI-tile treatment, 2026-08-20 fidelity pass).
23188
+ * `order: 1`/`order: 2` (not `flex-direction: row-reverse`) drive that split
23189
+ * so the layout auto-mirrors under `dir="rtl"`: inline-start/-end follow
23190
+ * direction, a fixed left/right would not.
23191
+ *
23192
+ * Default layout is a wrapping flex row (any item count degrades gracefully);
23193
+ * a design that pins an exact no-reflow column count (the Project-Details
23194
+ * Overview pins five) passes `columns` instead.
23195
+ *
23196
+ * ```html
23197
+ * <fly-overview-kpi-row [columns]="5" [items]="[
23198
+ * { icon: 'pi-chart-line', value: '64%', labelKey: 'ppm.projects.overview.progress', tone: 'blue' },
23199
+ * { icon: 'pi-flag', value: '3/8', labelKey: 'ppm.projects.overview.milestones', tone: 'purple' },
23200
+ * ]" />
23201
+ * ```
23202
+ */
23203
+ class FlyOverviewKpiRowComponent {
23204
+ items = input.required(...(ngDevMode ? [{ debugName: "items" }] : /* istanbul ignore next */ []));
23205
+ /** Exact equal-width column count (no reflow). Omit for the default wrapping flex row. */
23206
+ columns = input(...(ngDevMode ? [undefined, { debugName: "columns" }] : /* istanbul ignore next */ []));
23207
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: FlyOverviewKpiRowComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
23208
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.19", type: FlyOverviewKpiRowComponent, isStandalone: true, selector: "fly-overview-kpi-row", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: true, transformFunction: null }, columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
23209
+ <div class="okr" [class.okr--grid]="columns() != null" [style.--okr-columns]="columns()">
23210
+ @for (item of items(); track item.labelKey) {
23211
+ <div class="okr__card" [attr.data-tone]="item.tone">
23212
+ <div class="okr__text">
23213
+ <span class="okr__value">{{ item.value }}</span>
23214
+ <span class="okr__label">{{ item.labelKey | translate }}</span>
23215
+ </div>
23216
+ <i class="pi {{ item.icon }} okr__icon" aria-hidden="true"></i>
23217
+ </div>
23218
+ }
23219
+ </div>
23220
+ `, isInline: true, styles: [":host{display:block}.okr{display:flex;align-items:stretch;gap:10px;flex-wrap:wrap}.okr--grid{--okr-columns: 1;display:grid;grid-template-columns:repeat(var(--okr-columns),minmax(0,1fr))}.okr__card{flex:1;min-width:150px;display:flex;align-items:center;gap:11px;padding:13px 14px;border-radius:var(--r-lg);background:var(--w03);border:1px solid var(--w06)}.okr__card[data-tone=blue]{--okr-tone: var(--sys-blue)}.okr__card[data-tone=purple]{--okr-tone: var(--sys-purple)}.okr__card[data-tone=orange]{--okr-tone: var(--sys-orange)}.okr__card[data-tone=red]{--okr-tone: var(--sys-red)}.okr__card[data-tone=teal]{--okr-tone: var(--sys-teal)}.okr__text{order:1;flex:1;min-width:0;display:flex;flex-direction:column;gap:4px}.okr__icon{order:2;flex:none;inline-size:32px;block-size:32px;border-radius:9px;display:grid;place-items:center;background:var(--okr-tone, var(--w6));color:var(--ink-inverse);font-size:15px}.okr__value{font-family:var(--font-family-display);font-weight:var(--fw-bold);font-size:20px;line-height:1;letter-spacing:var(--tracking-tight);font-variant-numeric:tabular-nums;color:var(--ink)}.okr__label{font-family:var(--font-family);font-weight:var(--fw-medium);font-size:var(--text-2xs);line-height:1.2;color:var(--w45)}\n"], dependencies: [{ kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
23221
+ }
23222
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: FlyOverviewKpiRowComponent, decorators: [{
23223
+ type: Component,
23224
+ args: [{ selector: 'fly-overview-kpi-row', standalone: true, imports: [TranslatePipe], changeDetection: ChangeDetectionStrategy.OnPush, template: `
23225
+ <div class="okr" [class.okr--grid]="columns() != null" [style.--okr-columns]="columns()">
23226
+ @for (item of items(); track item.labelKey) {
23227
+ <div class="okr__card" [attr.data-tone]="item.tone">
23228
+ <div class="okr__text">
23229
+ <span class="okr__value">{{ item.value }}</span>
23230
+ <span class="okr__label">{{ item.labelKey | translate }}</span>
23231
+ </div>
23232
+ <i class="pi {{ item.icon }} okr__icon" aria-hidden="true"></i>
23233
+ </div>
23234
+ }
23235
+ </div>
23236
+ `, styles: [":host{display:block}.okr{display:flex;align-items:stretch;gap:10px;flex-wrap:wrap}.okr--grid{--okr-columns: 1;display:grid;grid-template-columns:repeat(var(--okr-columns),minmax(0,1fr))}.okr__card{flex:1;min-width:150px;display:flex;align-items:center;gap:11px;padding:13px 14px;border-radius:var(--r-lg);background:var(--w03);border:1px solid var(--w06)}.okr__card[data-tone=blue]{--okr-tone: var(--sys-blue)}.okr__card[data-tone=purple]{--okr-tone: var(--sys-purple)}.okr__card[data-tone=orange]{--okr-tone: var(--sys-orange)}.okr__card[data-tone=red]{--okr-tone: var(--sys-red)}.okr__card[data-tone=teal]{--okr-tone: var(--sys-teal)}.okr__text{order:1;flex:1;min-width:0;display:flex;flex-direction:column;gap:4px}.okr__icon{order:2;flex:none;inline-size:32px;block-size:32px;border-radius:9px;display:grid;place-items:center;background:var(--okr-tone, var(--w6));color:var(--ink-inverse);font-size:15px}.okr__value{font-family:var(--font-family-display);font-weight:var(--fw-bold);font-size:20px;line-height:1;letter-spacing:var(--tracking-tight);font-variant-numeric:tabular-nums;color:var(--ink)}.okr__label{font-family:var(--font-family);font-weight:var(--fw-medium);font-size:var(--text-2xs);line-height:1.2;color:var(--w45)}\n"] }]
23237
+ }], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: true }] }], columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: false }] }] } });
23238
+
23239
+ /**
23240
+ * Overview "Details" body — a self-contained `--w03`/`--w06` surface holding
23241
+ * label/value rows. Distinct from {@link FlyMetaListComponent} (`fly-meta`):
23242
+ * that component is the compact sidecard metalist (96px label column,
23243
+ * uppercase eyebrow labels, no surrounding surface — it expects to sit
23244
+ * inside a `fly-detail-card`), while this one is the wider Overview-page
23245
+ * "Details" block (132px label column, sentence-case labels, and the surface
23246
+ * built in) — the two visual specs don't share numbers, so this stays its
23247
+ * own component rather than a variant of the sidecard one.
23248
+ *
23249
+ * Simple rows come from `rows`; a richer value (a link, a chip, a user
23250
+ * label) projects through the default slot — reuse the `ovr__row` /
23251
+ * `ovr__label` / `ovr__value` classes on the projected markup to pick up the
23252
+ * same layout.
23253
+ *
23254
+ * ```html
23255
+ * <fly-overview-rows [rows]="[
23256
+ * { labelKey: 'ppm.projects.overview.owner', value: project().ownerName },
23257
+ * { labelKey: 'ppm.projects.overview.dueDate', value: project().dueDateLabel },
23258
+ * ]">
23259
+ * <div class="ovr__row">
23260
+ * <span class="ovr__label">{{ 'ppm.projects.overview.strategy' | translate }}</span>
23261
+ * <a class="ovr__value" [routerLink]="['/strategies', project().strategyId]">{{ project().strategyName }}</a>
23262
+ * </div>
23263
+ * </fly-overview-rows>
23264
+ * ```
23265
+ */
23266
+ class FlyOverviewRowsComponent {
23267
+ rows = input([], ...(ngDevMode ? [{ debugName: "rows" }] : /* istanbul ignore next */ []));
23268
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: FlyOverviewRowsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
23269
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.19", type: FlyOverviewRowsComponent, isStandalone: true, selector: "fly-overview-rows", inputs: { rows: { classPropertyName: "rows", publicName: "rows", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
23270
+ <div class="ovr">
23271
+ @for (row of rows(); track row.labelKey) {
23272
+ <div class="ovr__row">
23273
+ <span class="ovr__label">{{ row.labelKey | translate }}</span>
23274
+ <span class="ovr__value">{{ row.value }}</span>
23275
+ </div>
23276
+ }
23277
+ <ng-content />
23278
+ </div>
23279
+ `, isInline: true, styles: [":host{display:block}.ovr{display:flex;flex-direction:column;gap:9px;padding:12px 14px;border-radius:11px;background:var(--w03);border:1px solid var(--w06)}.ovr ::ng-deep .ovr__row{display:flex;align-items:baseline;gap:14px}.ovr ::ng-deep .ovr__label{flex:0 0 auto;width:132px;font-family:var(--font-family);font-weight:var(--fw-medium);font-size:12px;line-height:1.4;color:var(--w45)}.ovr ::ng-deep .ovr__value{flex:1;min-width:0;font-family:var(--font-family);font-weight:var(--fw-medium);font-size:var(--text-sm);line-height:1.4;color:var(--w85)}\n"], dependencies: [{ kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
23280
+ }
23281
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: FlyOverviewRowsComponent, decorators: [{
23282
+ type: Component,
23283
+ args: [{ selector: 'fly-overview-rows', standalone: true, imports: [TranslatePipe], changeDetection: ChangeDetectionStrategy.OnPush, template: `
23284
+ <div class="ovr">
23285
+ @for (row of rows(); track row.labelKey) {
23286
+ <div class="ovr__row">
23287
+ <span class="ovr__label">{{ row.labelKey | translate }}</span>
23288
+ <span class="ovr__value">{{ row.value }}</span>
23289
+ </div>
23290
+ }
23291
+ <ng-content />
23292
+ </div>
23293
+ `, styles: [":host{display:block}.ovr{display:flex;flex-direction:column;gap:9px;padding:12px 14px;border-radius:11px;background:var(--w03);border:1px solid var(--w06)}.ovr ::ng-deep .ovr__row{display:flex;align-items:baseline;gap:14px}.ovr ::ng-deep .ovr__label{flex:0 0 auto;width:132px;font-family:var(--font-family);font-weight:var(--fw-medium);font-size:12px;line-height:1.4;color:var(--w45)}.ovr ::ng-deep .ovr__value{flex:1;min-width:0;font-family:var(--font-family);font-weight:var(--fw-medium);font-size:var(--text-sm);line-height:1.4;color:var(--w85)}\n"] }]
23294
+ }], propDecorators: { rows: [{ type: i0.Input, args: [{ isSignal: true, alias: "rows", required: false }] }] } });
23295
+
23296
+ /**
23297
+ * Project-lifecycle phase-gate stepper — the Overview-section kit's fourth
23298
+ * body variant. Summary/Description/Details are `fly-overview-kpi-row` /
23299
+ * `-surface` / `-rows`; this is the "Lifecycle" section's own body, per
23300
+ * `fly-overview-section`'s own doc comment ("Lifecycle's 'Move to' actions").
23301
+ * A caller resolves the gate vocabulary (approved/in-progress/not-started, …)
23302
+ * into an already-formatted `tone` per step — this component stays
23303
+ * domain-agnostic, same discipline as `OverviewKpiItem`/`OverviewRow`. Step
23304
+ * names accept either an i18n `labelKey` or a verbatim `label`, because real
23305
+ * lifecycles carry server-provided gate names that are data, not locale keys.
23306
+ *
23307
+ * The index badge and the trailing `fly-chip` always share one color, driven
23308
+ * by the SAME `tone` field, so the two never drift out of sync. A
23309
+ * `success`-toned step swaps its numeral for a check mark. The optional
23310
+ * rollup strip is a flat tally legend, not another `fly-overview-rows` (that
23311
+ * component's 132px label column is built for a vertical "Details" block,
23312
+ * not an inline summary strip).
23313
+ *
23314
+ * ```html
23315
+ * <fly-lifecycle-pipeline ariaLabelKey="ppm.projects.lifecycle.stagesLabel" [steps]="[
23316
+ * { labelKey: 'ppm.projects.lifecycle.phase1Gate', statusLabelKey: 'common.status.approved', tone: 'success', progress: '1 / 1' },
23317
+ * { labelKey: 'ppm.projects.lifecycle.phase2Gate', statusLabelKey: 'ppm.projects.lifecycle.status.inProgress', tone: 'accent', current: true },
23318
+ * { labelKey: 'ppm.projects.lifecycle.closureGate', statusLabelKey: 'ppm.projects.lifecycle.status.notStarted', tone: 'neutral' },
23319
+ * ]" [rollup]="[
23320
+ * { labelKey: 'ppm.projects.lifecycle.rollup.planned', value: 2 },
23321
+ * { labelKey: 'ppm.projects.lifecycle.rollup.inProgress', value: 2 },
23322
+ * ]" />
23323
+ * ```
23324
+ */
23325
+ class FlyLifecyclePipelineComponent {
23326
+ steps = input.required(...(ngDevMode ? [{ debugName: "steps" }] : /* istanbul ignore next */ []));
23327
+ rollup = input([], ...(ngDevMode ? [{ debugName: "rollup" }] : /* istanbul ignore next */ []));
23328
+ /** i18n key for the `role="list"` accessible name. */
23329
+ ariaLabelKey = input.required(...(ngDevMode ? [{ debugName: "ariaLabelKey" }] : /* istanbul ignore next */ []));
23330
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: FlyLifecyclePipelineComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
23331
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.19", type: FlyLifecyclePipelineComponent, isStandalone: true, selector: "fly-lifecycle-pipeline", inputs: { steps: { classPropertyName: "steps", publicName: "steps", isSignal: true, isRequired: true, transformFunction: null }, rollup: { classPropertyName: "rollup", publicName: "rollup", isSignal: true, isRequired: false, transformFunction: null }, ariaLabelKey: { classPropertyName: "ariaLabelKey", publicName: "ariaLabelKey", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: `
23332
+ <div class="lp">
23333
+ <div class="lp__row" role="list" [attr.aria-label]="ariaLabelKey() | translate">
23334
+ @for (
23335
+ step of steps();
23336
+ track step.label ?? step.labelKey;
23337
+ let i = $index;
23338
+ let last = $last
23339
+ ) {
23340
+ <div
23341
+ class="lp__step"
23342
+ [class.lp__step--current]="step.current"
23343
+ role="listitem"
23344
+ [attr.aria-current]="step.current ? 'step' : null"
23345
+ >
23346
+ <span class="lp__index" [attr.data-tone]="step.tone">
23347
+ @if (step.tone === 'success') {
23348
+ <i class="pi pi-check" aria-hidden="true"></i>
23349
+ } @else {
23350
+ {{ i + 1 }}
23351
+ }
23352
+ </span>
23353
+ <span class="lp__name">
23354
+ @if (step.label) {
23355
+ {{ step.label }}
23356
+ } @else if (step.labelKey) {
23357
+ {{ step.labelKey | translate }}
23358
+ }
23359
+ </span>
23360
+ <fly-chip [tone]="step.tone">{{ step.statusLabelKey | translate }}</fly-chip>
23361
+ @if (step.progress) {
23362
+ <span class="lp__progress">{{ step.progress }}</span>
23363
+ }
23364
+ </div>
23365
+ @if (!last) {
23366
+ <span class="lp__connector" aria-hidden="true"></span>
23367
+ }
23368
+ }
23369
+ </div>
23370
+ @if (rollup().length) {
23371
+ <div class="lp__rollup">
23372
+ @for (item of rollup(); track item.labelKey) {
23373
+ <span class="lp__rollup-item">
23374
+ <span class="lp__rollup-label">{{ item.labelKey | translate }}</span>
23375
+ <span class="lp__rollup-value">{{ item.value }}</span>
23376
+ </span>
23377
+ }
23378
+ </div>
23379
+ }
23380
+ </div>
23381
+ `, isInline: true, styles: [":host{display:block}.lp{display:flex;flex-direction:column;gap:var(--sp-3)}.lp__row{display:flex;align-items:center;flex-wrap:wrap;row-gap:var(--sp-3)}.lp__step{display:flex;align-items:center;gap:var(--sp-2);padding:6px 10px;border-radius:var(--r-lg);border:1px solid transparent}.lp__step--current{border-color:var(--accent-fill);background:var(--tint-sel)}.lp__index{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:22px;height:22px;border-radius:999px;font-family:var(--font-family);font-size:11px;font-weight:var(--fw-bold);line-height:1}.lp__index .pi{font-size:10px}.lp__index[data-tone=neutral]{background:var(--w06);color:var(--w85)}.lp__index[data-tone=accent]{background:var(--accent-fill);color:var(--on-accent-fill)}.lp__index[data-tone=success]{background:var(--success-bg);color:var(--success)}.lp__index[data-tone=warning]{background:var(--warning-bg);color:var(--warning-fg)}.lp__index[data-tone=danger]{background:var(--danger-bg);color:var(--danger)}.lp__name{font-family:var(--font-family);font-weight:var(--fw-medium);font-size:var(--text-sm);color:var(--ink);white-space:nowrap}.lp__step--current .lp__name{font-weight:var(--fw-bold)}.lp__progress{font-family:var(--font-family);font-size:var(--text-xs);color:var(--w45);font-variant-numeric:tabular-nums}.lp__connector{flex:1 1 32px;min-width:20px;height:1px;background:var(--w16);margin-inline:2px}.lp__rollup{display:flex;flex-wrap:wrap;gap:var(--sp-1) var(--sp-4);padding-block-start:var(--sp-2);border-block-start:1px solid var(--w06)}.lp__rollup-item{display:inline-flex;align-items:baseline;gap:5px;font-family:var(--font-family);font-size:var(--text-xs)}.lp__rollup-label{color:var(--w45)}.lp__rollup-value{color:var(--w85);font-weight:var(--fw-bold);font-variant-numeric:tabular-nums}\n"], dependencies: [{ kind: "component", type: FlyChipComponent, selector: "fly-chip", inputs: ["tone"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
23382
+ }
23383
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: FlyLifecyclePipelineComponent, decorators: [{
23384
+ type: Component,
23385
+ args: [{ selector: 'fly-lifecycle-pipeline', standalone: true, imports: [TranslatePipe, FlyChipComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: `
23386
+ <div class="lp">
23387
+ <div class="lp__row" role="list" [attr.aria-label]="ariaLabelKey() | translate">
23388
+ @for (
23389
+ step of steps();
23390
+ track step.label ?? step.labelKey;
23391
+ let i = $index;
23392
+ let last = $last
23393
+ ) {
23394
+ <div
23395
+ class="lp__step"
23396
+ [class.lp__step--current]="step.current"
23397
+ role="listitem"
23398
+ [attr.aria-current]="step.current ? 'step' : null"
23399
+ >
23400
+ <span class="lp__index" [attr.data-tone]="step.tone">
23401
+ @if (step.tone === 'success') {
23402
+ <i class="pi pi-check" aria-hidden="true"></i>
23403
+ } @else {
23404
+ {{ i + 1 }}
23405
+ }
23406
+ </span>
23407
+ <span class="lp__name">
23408
+ @if (step.label) {
23409
+ {{ step.label }}
23410
+ } @else if (step.labelKey) {
23411
+ {{ step.labelKey | translate }}
23412
+ }
23413
+ </span>
23414
+ <fly-chip [tone]="step.tone">{{ step.statusLabelKey | translate }}</fly-chip>
23415
+ @if (step.progress) {
23416
+ <span class="lp__progress">{{ step.progress }}</span>
23417
+ }
23418
+ </div>
23419
+ @if (!last) {
23420
+ <span class="lp__connector" aria-hidden="true"></span>
23421
+ }
23422
+ }
23423
+ </div>
23424
+ @if (rollup().length) {
23425
+ <div class="lp__rollup">
23426
+ @for (item of rollup(); track item.labelKey) {
23427
+ <span class="lp__rollup-item">
23428
+ <span class="lp__rollup-label">{{ item.labelKey | translate }}</span>
23429
+ <span class="lp__rollup-value">{{ item.value }}</span>
23430
+ </span>
23431
+ }
23432
+ </div>
23433
+ }
23434
+ </div>
23435
+ `, styles: [":host{display:block}.lp{display:flex;flex-direction:column;gap:var(--sp-3)}.lp__row{display:flex;align-items:center;flex-wrap:wrap;row-gap:var(--sp-3)}.lp__step{display:flex;align-items:center;gap:var(--sp-2);padding:6px 10px;border-radius:var(--r-lg);border:1px solid transparent}.lp__step--current{border-color:var(--accent-fill);background:var(--tint-sel)}.lp__index{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:22px;height:22px;border-radius:999px;font-family:var(--font-family);font-size:11px;font-weight:var(--fw-bold);line-height:1}.lp__index .pi{font-size:10px}.lp__index[data-tone=neutral]{background:var(--w06);color:var(--w85)}.lp__index[data-tone=accent]{background:var(--accent-fill);color:var(--on-accent-fill)}.lp__index[data-tone=success]{background:var(--success-bg);color:var(--success)}.lp__index[data-tone=warning]{background:var(--warning-bg);color:var(--warning-fg)}.lp__index[data-tone=danger]{background:var(--danger-bg);color:var(--danger)}.lp__name{font-family:var(--font-family);font-weight:var(--fw-medium);font-size:var(--text-sm);color:var(--ink);white-space:nowrap}.lp__step--current .lp__name{font-weight:var(--fw-bold)}.lp__progress{font-family:var(--font-family);font-size:var(--text-xs);color:var(--w45);font-variant-numeric:tabular-nums}.lp__connector{flex:1 1 32px;min-width:20px;height:1px;background:var(--w16);margin-inline:2px}.lp__rollup{display:flex;flex-wrap:wrap;gap:var(--sp-1) var(--sp-4);padding-block-start:var(--sp-2);border-block-start:1px solid var(--w06)}.lp__rollup-item{display:inline-flex;align-items:baseline;gap:5px;font-family:var(--font-family);font-size:var(--text-xs)}.lp__rollup-label{color:var(--w45)}.lp__rollup-value{color:var(--w85);font-weight:var(--fw-bold);font-variant-numeric:tabular-nums}\n"] }]
23436
+ }], propDecorators: { steps: [{ type: i0.Input, args: [{ isSignal: true, alias: "steps", required: true }] }], rollup: [{ type: i0.Input, args: [{ isSignal: true, alias: "rollup", required: false }] }], ariaLabelKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabelKey", required: true }] }] } });
23437
+
23106
23438
  function canGoPrev$1(page) {
23107
23439
  return page > 1;
23108
23440
  }
@@ -24251,6 +24583,65 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImpo
24251
24583
  `, styles: [":host{display:block}.sh{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:13px 16px;border-block-end:1px solid var(--line-3)}.sh__t{margin:0;font-size:13px;font-weight:var(--fw-semibold);color:var(--ink);letter-spacing:-.005em;min-width:0}.sh__a{display:inline-flex;align-items:center;gap:var(--sp-1);flex-shrink:0}.sh__a ::ng-deep a:not([fly-button]),.sh__a ::ng-deep button:not([fly-button],[fly-icon-button]){display:inline-flex;align-items:center;gap:5px;background:transparent;border:0;color:var(--accent);font-size:12px;font-weight:var(--fw-medium);cursor:pointer;padding:4px 6px;border-radius:var(--r-sm);font-family:inherit;text-decoration:none;transition:background var(--t-state)}.sh__a ::ng-deep a:not([fly-button]):hover,.sh__a ::ng-deep button:not([fly-button],[fly-icon-button]):hover{background:color-mix(in srgb,var(--accent-soft) 50%,transparent)}.sh__a ::ng-deep a:not([fly-button]):focus-visible,.sh__a ::ng-deep button:not([fly-button],[fly-icon-button]):focus-visible{outline:2px solid;outline-color:var(--focus-ring);outline-offset:2px}\n"] }]
24252
24584
  }], propDecorators: { titleKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "titleKey", required: false }] }] } });
24253
24585
 
24586
+ /**
24587
+ * Shared shell for a Project-Details-style "Overview" page: a flat stack of
24588
+ * sections separated by hairlines — deliberately NOT a stack of cards. Every
24589
+ * section gets the same quiet eyebrow label; the body (stats / text / rows /
24590
+ * chips / members / …) is left to content projection, so a section that
24591
+ * carries real interaction (Members' add/remove, Lifecycle's "Move to"
24592
+ * actions) keeps its own live markup untouched. This component owns only the
24593
+ * shell + eyebrow + divider rhythm, never the variant bodies.
24594
+ *
24595
+ * First/last spacing resolves from DOM position (`:first-of-type` /
24596
+ * `:last-of-type` on the host tag), not an input — sections render from a
24597
+ * list, and a caller reordering or filtering that list should never also
24598
+ * have to recompute an explicit "am I first" flag.
24599
+ *
24600
+ * ```html
24601
+ * <fly-overview-section titleKey="ppm.projects.overview.summary">
24602
+ * <fly-overview-kpi-row [items]="kpis()" />
24603
+ * </fly-overview-section>
24604
+ *
24605
+ * <fly-overview-section titleKey="ppm.projects.overview.description">
24606
+ * <fly-overview-surface [proseText]="true">{{ project().description }}</fly-overview-surface>
24607
+ * </fly-overview-section>
24608
+ *
24609
+ * <!-- Sections with their own live interaction just project their existing
24610
+ * markup — the shell never dictates what a Members/Lifecycle body renders. -->
24611
+ * <fly-overview-section titleKey="ppm.projects.overview.members">
24612
+ * <fly-overview-surface>
24613
+ * <app-project-members-list [members]="members()" (removed)="onRemove($event)" />
24614
+ * </fly-overview-surface>
24615
+ * </fly-overview-section>
24616
+ * ```
24617
+ */
24618
+ class FlyOverviewSectionComponent {
24619
+ /** i18n key for the eyebrow label; alternatively project `[section-title]`. */
24620
+ titleKey = input(...(ngDevMode ? [undefined, { debugName: "titleKey" }] : /* istanbul ignore next */ []));
24621
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: FlyOverviewSectionComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
24622
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.19", type: FlyOverviewSectionComponent, isStandalone: true, selector: "fly-overview-section", inputs: { titleKey: { classPropertyName: "titleKey", publicName: "titleKey", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
24623
+ <h2 class="ovs__eyebrow">
24624
+ @if (titleKey(); as key) {
24625
+ {{ key | translate }}
24626
+ }
24627
+ <ng-content select="[section-title]" />
24628
+ </h2>
24629
+ <ng-content />
24630
+ `, isInline: true, styles: [":host{display:flex;flex-direction:column;gap:var(--sp-2);padding:var(--sp-4) 0;border-block-end:1px solid var(--w06)}:host:first-of-type{padding-block-start:0}:host:last-of-type{border-block-end:0}.ovs__eyebrow{margin:0;font-family:var(--font-family);font-weight:var(--fw-bold);font-size:10.5px;line-height:1;letter-spacing:.03em;color:var(--w42)}\n"], dependencies: [{ kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
24631
+ }
24632
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: FlyOverviewSectionComponent, decorators: [{
24633
+ type: Component,
24634
+ args: [{ selector: 'fly-overview-section', standalone: true, imports: [TranslatePipe], changeDetection: ChangeDetectionStrategy.OnPush, template: `
24635
+ <h2 class="ovs__eyebrow">
24636
+ @if (titleKey(); as key) {
24637
+ {{ key | translate }}
24638
+ }
24639
+ <ng-content select="[section-title]" />
24640
+ </h2>
24641
+ <ng-content />
24642
+ `, styles: [":host{display:flex;flex-direction:column;gap:var(--sp-2);padding:var(--sp-4) 0;border-block-end:1px solid var(--w06)}:host:first-of-type{padding-block-start:0}:host:last-of-type{border-block-end:0}.ovs__eyebrow{margin:0;font-family:var(--font-family);font-weight:var(--fw-bold);font-size:10.5px;line-height:1;letter-spacing:.03em;color:var(--w42)}\n"] }]
24643
+ }], propDecorators: { titleKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "titleKey", required: false }] }] } });
24644
+
24254
24645
  /**
24255
24646
  * Detail-page content card — the surface every panel and sidebar block on a detail
24256
24647
  * screen sits on: `card-surface` fill/hairline/radius/shadow, an optional
@@ -25015,11 +25406,11 @@ class FlyAppHomeComponent {
25015
25406
  return `fly-app-home-sec-${index}`;
25016
25407
  }
25017
25408
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: FlyAppHomeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
25018
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.19", type: FlyAppHomeComponent, isStandalone: true, selector: "fly-app-home", inputs: { brandLabelKey: { classPropertyName: "brandLabelKey", publicName: "brandLabelKey", isSignal: true, isRequired: false, transformFunction: null }, titleKey: { classPropertyName: "titleKey", publicName: "titleKey", isSignal: true, isRequired: false, transformFunction: null }, subtitleKey: { classPropertyName: "subtitleKey", publicName: "subtitleKey", isSignal: true, isRequired: false, transformFunction: null }, sections: { classPropertyName: "sections", publicName: "sections", isSignal: true, isRequired: false, transformFunction: null }, modulesLabelKey: { classPropertyName: "modulesLabelKey", publicName: "modulesLabelKey", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { moduleSelected: "moduleSelected", brandSelected: "brandSelected" }, queries: [{ propertyName: "icons", predicate: FlyModuleIconDirective, isSignal: true }], ngImport: i0, template: "<div class=\"ah\">\r\n <header class=\"ah__util\">\r\n <button type=\"button\" class=\"ah__brand\" (click)=\"brandSelected.emit()\">\r\n <span class=\"ah__brand-mark\"><ng-content select=\"[app-home-brand]\" /></span>\r\n @if (brandLabelKey(); as key) {\r\n <span class=\"ah__brand-name\">{{ key | translate }}</span>\r\n }\r\n </button>\r\n <ng-content select=\"[app-home-actions]\" />\r\n </header>\r\n\r\n <main class=\"ah__main\">\r\n @if (titleKey() || subtitleKey()) {\r\n <section class=\"ah__hero\">\r\n @if (titleKey(); as key) {\r\n <h1 class=\"ah__title\">{{ key | translate }}</h1>\r\n }\r\n @if (subtitleKey(); as key) {\r\n <p class=\"ah__sub\">{{ key | translate }}</p>\r\n }\r\n </section>\r\n }\r\n\r\n @for (row of rows(); track row.index) {\r\n <section\r\n class=\"ah__sec\"\r\n [class.ah__sec--secondary]=\"row.index > 0\"\r\n [attr.aria-label]=\"row.section.titleKey ? null : (modulesLabelKey() | translate)\"\r\n >\r\n @if (row.section.titleKey; as titleKey) {\r\n @if (row.section.collapsible) {\r\n <button\r\n type=\"button\"\r\n class=\"ah__sec-hd\"\r\n (click)=\"toggle(row.index)\"\r\n [attr.aria-expanded]=\"row.expanded\"\r\n [attr.aria-controls]=\"sectionId(row.index)\"\r\n >\r\n <!-- Points end-ward when shut, down when open. `--open` wins over the RTL\r\n flip below because a downward chevron has no direction to mirror. -->\r\n <svg\r\n class=\"ah__sec-chev\"\r\n [class.ah__sec-chev--open]=\"row.expanded\"\r\n width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"2.4\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"\r\n >\r\n <polyline points=\"9 6 15 12 9 18\" />\r\n </svg>\r\n <span class=\"ah__sec-title\">{{ titleKey | translate }}</span>\r\n <span class=\"ah__sec-count\">{{ row.section.modules.length }}</span>\r\n @if (row.hintKey; as hint) {\r\n <span class=\"ah__sec-hint\">{{ hint | translate }}</span>\r\n }\r\n </button>\r\n } @else {\r\n <h2 class=\"ah__sec-title ah__sec-title--static\">{{ titleKey | translate }}</h2>\r\n }\r\n }\r\n\r\n @if (row.expanded) {\r\n <div class=\"ah__grid\" [class.ah__grid--compact]=\"row.layout === 'compact'\" [id]=\"sectionId(row.index)\">\r\n @for (mod of row.section.modules; track mod.key) {\r\n <button\r\n type=\"button\"\r\n class=\"ah__card\"\r\n [class.ah__card--compact]=\"row.layout === 'compact'\"\r\n [disabled]=\"mod.disabled\"\r\n (click)=\"select(mod)\"\r\n >\r\n <span class=\"ah__card-ico\">\r\n @if (iconFor(mod.key); as tpl) {\r\n <ng-container *ngTemplateOutlet=\"tpl\" />\r\n } @else if (mod.iconClass) {\r\n <i [class]=\"mod.iconClass\" aria-hidden=\"true\"></i>\r\n }\r\n </span>\r\n\r\n @if (row.layout === 'compact') {\r\n <span class=\"ah__card-main\">\r\n <span class=\"ah__card-title\">{{ mod.labelKey | translate }}</span>\r\n @if (mod.descKey; as descKey) {\r\n <span class=\"ah__card-desc\">{{ descKey | translate }}</span>\r\n }\r\n </span>\r\n <svg\r\n class=\"ah__card-arrow\" width=\"11\" height=\"11\" viewBox=\"0 0 24 24\" fill=\"none\"\r\n stroke=\"currentColor\" stroke-width=\"2.6\" stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\" aria-hidden=\"true\"\r\n >\r\n <polyline points=\"9 6 15 12 9 18\" />\r\n </svg>\r\n } @else {\r\n <!-- No \"Open \u203A\" affordance row \u2014 the design's module card (MainContent.dc.html)\r\n ends at the description; the whole card is the click target and hover carries\r\n the affordance. Removed at the 2026-08-17 fidelity pass. -->\r\n <span class=\"ah__card-title ah__card-title--feature\">{{ mod.labelKey | translate }}</span>\r\n @if (mod.descKey; as descKey) {\r\n <span class=\"ah__card-desc ah__card-desc--feature\">{{ descKey | translate }}</span>\r\n }\r\n }\r\n </button>\r\n }\r\n </div>\r\n }\r\n </section>\r\n }\r\n </main>\r\n</div>\r\n", styles: [":host{display:flex;flex-direction:column;min-height:100%;container-type:inline-size}.ah{display:flex;flex-direction:column;flex:1;min-height:100%}.ah__util{display:flex;align-items:center;justify-content:space-between;gap:var(--sp-4);padding:var(--sp-4) var(--sp-6)}:host-context(.window-content) .ah__brand{display:none}:host-context(.window-content) .ah__util{justify-content:flex-end}:host-context(.window-content) .ah__util:not(:has(>:not(.ah__brand))){display:none}.ah__brand{display:inline-flex;align-items:center;gap:var(--sp-2);padding:0;border:0;background:none;color:var(--ink);font-family:inherit;cursor:pointer}.ah__brand:focus-visible{outline:2px solid;outline-color:var(--focus-ring);outline-offset:2px}.ah__brand-name{font-size:var(--text-md);font-weight:var(--fw-semibold);letter-spacing:-.01em}.ah__main{flex:1;inline-size:100%;max-inline-size:1120px;margin-inline:auto;padding:56px 40px;display:flex;flex-direction:column;justify-content:center;gap:44px}.ah__hero{max-inline-size:640px}.ah__title{margin:0 0 var(--sp-3);font-size:44px;font-weight:var(--fw-semibold);letter-spacing:-.03em;text-wrap:balance;background:linear-gradient(180deg,var(--ink),var(--ink-2));-webkit-background-clip:text;background-clip:text;color:transparent}.ah__sub{margin:0;max-inline-size:560px;font-size:var(--text-lg);line-height:1.55;color:var(--ink-3);text-wrap:pretty}.ah__sec{display:flex;flex-direction:column;gap:var(--sp-4)}.ah__sec--secondary{padding-block-start:28px;border-block-start:1px solid var(--w08)}.ah__sec-hd{display:flex;align-items:center;gap:var(--sp-3);inline-size:100%;padding:0;background:none;border:0;cursor:pointer;font-family:inherit;color:var(--ink);text-align:start}.ah__sec-hd:focus-visible{outline:2px solid;outline-color:var(--focus-ring);outline-offset:2px}.ah__sec-chev{flex-shrink:0;color:var(--ink-3);transition:transform var(--t-overlay)}.ah__sec-title{font-size:var(--text-md);font-weight:var(--fw-semibold);letter-spacing:-.01em}.ah__sec-title--static{margin:0;color:var(--ink-3);font-size:var(--text-xs);letter-spacing:var(--tracking-wide);text-transform:uppercase}.ah__sec-count{display:inline-grid;place-items:center;min-inline-size:22px;block-size:20px;padding-inline:6px;border-radius:999px;background:var(--bg-3);border:1px solid var(--line);font-size:var(--text-2xs);font-weight:var(--fw-medium);font-variant-numeric:tabular-nums;color:var(--ink-3)}.ah__sec-hint{margin-inline-start:auto;font-size:var(--text-xs);color:var(--ink-3)}.ah__grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:14px}.ah__card{display:flex;flex-direction:column;align-items:stretch;position:relative;overflow:hidden;text-align:start;padding:20px;background-image:linear-gradient(160deg,var(--w055),var(--w02));border:1px solid var(--w09);border-radius:20px;color:inherit;font-family:inherit;cursor:pointer;animation:appTileIn .3s var(--nova-ease-micro) both}.ah__card:nth-child(1){animation-delay:0ms}.ah__card:nth-child(2){animation-delay:20ms}.ah__card:nth-child(3){animation-delay:40ms}.ah__card:nth-child(4){animation-delay:60ms}.ah__card:nth-child(5){animation-delay:80ms}.ah__card:nth-child(6){animation-delay:.1s}.ah__card:nth-child(7){animation-delay:.12s}.ah__card:nth-child(8){animation-delay:.14s}.ah__card:nth-child(9){animation-delay:.16s}.ah__card:nth-child(10){animation-delay:.18s}.ah__card:nth-child(11){animation-delay:.2s}.ah__card:nth-child(12){animation-delay:.22s}.ah__card:nth-child(n+13){animation-delay:.22s}.ah__card{transition:transform var(--t-overlay),box-shadow var(--t-overlay),border-color var(--t-state),background-image var(--t-state)}.ah__card:hover:not(:disabled){transform:translateY(-3px);border-color:color-mix(in oklab,var(--accent) 50%,transparent);background-image:linear-gradient(160deg,var(--tint-hover),transparent);box-shadow:0 20px 46px color-mix(in oklab,var(--accent) 16%,transparent),var(--shadow-filter)}.ah__card:focus-visible{outline:0;border-color:color-mix(in oklab,var(--accent) 50%,transparent);background-image:linear-gradient(160deg,var(--tint-hover),transparent);box-shadow:0 0 0 3px var(--accent-soft),0 20px 46px color-mix(in oklab,var(--accent) 16%,transparent),var(--shadow-filter)}.ah__card:disabled{cursor:default;opacity:.5}.ah__card-ico{display:grid;place-items:center;inline-size:42px;block-size:42px;margin-block-end:16px;border-radius:13px;background:linear-gradient(140deg,color-mix(in srgb,var(--accent) 50%,transparent),color-mix(in srgb,var(--sys-teal) 22%,transparent));box-shadow:0 6px 16px color-mix(in srgb,var(--accent) 30%,transparent),inset 0 1px 0 var(--edge-highlight);border:0;color:var(--on-accent);font-size:var(--icon-lg)}.ah__card--compact:hover:not(:disabled) .ah__card-ico,.ah__card--compact:focus-visible .ah__card-ico{background:linear-gradient(135deg,var(--accent),var(--sys-teal));box-shadow:inset 0 1px 0 var(--edge-highlight);color:var(--on-accent)}.ah__card-title{font-size:var(--text-sm);font-weight:var(--fw-semibold);letter-spacing:-.01em;color:var(--ink)}.ah__card-title--feature{margin-block-end:5px;font-size:16.5px;line-height:1.25;letter-spacing:-.005em}.ah__card-desc{font-size:var(--text-xs);line-height:1.45;color:var(--ink-3);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ah__card-desc--feature{margin-block-end:0;font-size:13px;line-height:1.45;text-wrap:pretty;overflow:visible;white-space:normal}.ah__card-arrow{flex-shrink:0;transition:color var(--t-overlay),transform var(--t-overlay)}.ah__card--compact{flex-direction:row;align-items:center;gap:var(--sp-3);padding:14px 16px;background-color:var(--bg);background-image:linear-gradient(160deg,var(--w035),var(--w035));border-radius:16px;border-color:var(--w08)}.ah__card--compact:hover:not(:disabled),.ah__card--compact:focus-visible{border-color:color-mix(in oklab,var(--accent) 40%,transparent);background-image:linear-gradient(160deg,var(--tint-hover),transparent)}.ah__card--compact .ah__card-ico{inline-size:32px;block-size:32px;margin-block-end:0;flex-shrink:0;border-radius:10px;font-size:var(--icon-md);background:var(--bg-3);box-shadow:none;color:var(--ink)}.ah__card-main{display:flex;flex-direction:column;gap:2px;flex:1;min-inline-size:0}.ah__card--compact .ah__card-arrow{color:var(--ink-4)}.ah__card--compact:hover:not(:disabled) .ah__card-arrow{color:var(--accent);transform:translate(2px)}:host-context([dir=rtl]) .ah__card-arrow{transform:scaleX(-1)}:host-context([dir=rtl]) .ah__sec-chev:not(.ah__sec-chev--open){transform:scaleX(-1)}:host-context([dir=rtl]) .ah__card--compact:hover:not(:disabled) .ah__card-arrow{transform:scaleX(-1) translate(2px)}.ah__sec-chev--open{transform:rotate(90deg)}@container (width <= 900px){.ah__main{padding:40px 24px;gap:36px}.ah__title{font-size:36px}.ah__util{padding:var(--sp-3) var(--sp-5)}}@media(width<=900px){.ah__main{padding:40px 24px;gap:36px}.ah__title{font-size:36px}.ah__util{padding:var(--sp-3) var(--sp-5)}}@container (width <= 560px){.ah__title{font-size:30px}.ah__sub{font-size:var(--text-sm)}.ah__sec-hint{display:none}}@media(width<=560px){.ah__title{font-size:30px}.ah__sub{font-size:var(--text-sm)}.ah__sec-hint{display:none}}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
25409
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.19", type: FlyAppHomeComponent, isStandalone: true, selector: "fly-app-home", inputs: { brandLabelKey: { classPropertyName: "brandLabelKey", publicName: "brandLabelKey", isSignal: true, isRequired: false, transformFunction: null }, titleKey: { classPropertyName: "titleKey", publicName: "titleKey", isSignal: true, isRequired: false, transformFunction: null }, subtitleKey: { classPropertyName: "subtitleKey", publicName: "subtitleKey", isSignal: true, isRequired: false, transformFunction: null }, sections: { classPropertyName: "sections", publicName: "sections", isSignal: true, isRequired: false, transformFunction: null }, modulesLabelKey: { classPropertyName: "modulesLabelKey", publicName: "modulesLabelKey", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { moduleSelected: "moduleSelected", brandSelected: "brandSelected" }, queries: [{ propertyName: "icons", predicate: FlyModuleIconDirective, isSignal: true }], ngImport: i0, template: "<div class=\"ah\">\r\n <header class=\"ah__util\">\r\n <button type=\"button\" class=\"ah__brand\" (click)=\"brandSelected.emit()\">\r\n <span class=\"ah__brand-mark\"><ng-content select=\"[app-home-brand]\" /></span>\r\n @if (brandLabelKey(); as key) {\r\n <span class=\"ah__brand-name\">{{ key | translate }}</span>\r\n }\r\n </button>\r\n <ng-content select=\"[app-home-actions]\" />\r\n </header>\r\n\r\n <main class=\"ah__main\">\r\n @if (titleKey() || subtitleKey()) {\r\n <section class=\"ah__hero\">\r\n @if (titleKey(); as key) {\r\n <h1 class=\"ah__title\">{{ key | translate }}</h1>\r\n }\r\n @if (subtitleKey(); as key) {\r\n <p class=\"ah__sub\">{{ key | translate }}</p>\r\n }\r\n </section>\r\n }\r\n\r\n @for (row of rows(); track row.index) {\r\n <section\r\n class=\"ah__sec\"\r\n [class.ah__sec--secondary]=\"row.index > 0\"\r\n [attr.aria-label]=\"row.section.titleKey ? null : (modulesLabelKey() | translate)\"\r\n >\r\n @if (row.section.titleKey; as titleKey) {\r\n @if (row.section.collapsible) {\r\n <button\r\n type=\"button\"\r\n class=\"ah__sec-hd\"\r\n (click)=\"toggle(row.index)\"\r\n [attr.aria-expanded]=\"row.expanded\"\r\n [attr.aria-controls]=\"sectionId(row.index)\"\r\n >\r\n <!-- Points end-ward when shut, down when open. `--open` wins over the RTL\r\n flip below because a downward chevron has no direction to mirror. -->\r\n <svg\r\n class=\"ah__sec-chev\"\r\n [class.ah__sec-chev--open]=\"row.expanded\"\r\n width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"2.4\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"\r\n >\r\n <polyline points=\"9 6 15 12 9 18\" />\r\n </svg>\r\n <span class=\"ah__sec-title\">{{ titleKey | translate }}</span>\r\n <span class=\"ah__sec-count\">{{ row.section.modules.length }}</span>\r\n @if (row.hintKey; as hint) {\r\n <span class=\"ah__sec-hint\">{{ hint | translate }}</span>\r\n }\r\n </button>\r\n } @else {\r\n <h2 class=\"ah__sec-title ah__sec-title--static\">{{ titleKey | translate }}</h2>\r\n }\r\n }\r\n\r\n @if (row.expanded) {\r\n <div class=\"ah__grid\" [class.ah__grid--compact]=\"row.layout === 'compact'\" [id]=\"sectionId(row.index)\">\r\n @for (mod of row.section.modules; track mod.key) {\r\n <button\r\n type=\"button\"\r\n class=\"ah__card\"\r\n [class.ah__card--compact]=\"row.layout === 'compact'\"\r\n [disabled]=\"mod.disabled\"\r\n (click)=\"select(mod)\"\r\n >\r\n <span class=\"ah__card-ico\">\r\n @if (iconFor(mod.key); as tpl) {\r\n <ng-container *ngTemplateOutlet=\"tpl\" />\r\n } @else if (mod.iconClass) {\r\n <i [class]=\"mod.iconClass\" aria-hidden=\"true\"></i>\r\n }\r\n </span>\r\n\r\n @if (row.layout === 'compact') {\r\n <span class=\"ah__card-main\">\r\n <span class=\"ah__card-title\">{{ mod.labelKey | translate }}</span>\r\n @if (mod.descKey; as descKey) {\r\n <span class=\"ah__card-desc\">{{ descKey | translate }}</span>\r\n }\r\n </span>\r\n <svg\r\n class=\"ah__card-arrow\" width=\"11\" height=\"11\" viewBox=\"0 0 24 24\" fill=\"none\"\r\n stroke=\"currentColor\" stroke-width=\"2.6\" stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\" aria-hidden=\"true\"\r\n >\r\n <polyline points=\"9 6 15 12 9 18\" />\r\n </svg>\r\n } @else {\r\n <!-- No \"Open \u203A\" affordance row \u2014 the design's module card (MainContent.dc.html)\r\n ends at the description; the whole card is the click target and hover carries\r\n the affordance. Removed at the 2026-08-17 fidelity pass. -->\r\n <!-- Text stack: icon-to-text spacing is `.ah__card`'s own gap; this wrapper's\r\n gap is title-to-description only (module-card fidelity pass, 2026-08-20). -->\r\n <span class=\"ah__card-text\">\r\n <span class=\"ah__card-title ah__card-title--feature\">{{ mod.labelKey | translate }}</span>\r\n @if (mod.descKey; as descKey) {\r\n <span class=\"ah__card-desc ah__card-desc--feature\">{{ descKey | translate }}</span>\r\n }\r\n </span>\r\n }\r\n </button>\r\n }\r\n </div>\r\n }\r\n </section>\r\n }\r\n </main>\r\n</div>\r\n", styles: [":host{display:flex;flex-direction:column;min-height:100%;container-type:inline-size}.ah{display:flex;flex-direction:column;flex:1;min-height:100%}.ah__util{display:flex;align-items:center;justify-content:space-between;gap:var(--sp-4);padding:var(--sp-4) var(--sp-6)}:host-context(.window-content) .ah__brand{display:none}:host-context(.window-content) .ah__util{justify-content:flex-end}:host-context(.window-content) .ah__util:not(:has(>:not(.ah__brand))){display:none}.ah__brand{display:inline-flex;align-items:center;gap:var(--sp-2);padding:0;border:0;background:none;color:var(--ink);font-family:inherit;cursor:pointer}.ah__brand:focus-visible{outline:2px solid;outline-color:var(--focus-ring);outline-offset:2px}.ah__brand-name{font-size:var(--text-md);font-weight:var(--fw-semibold);letter-spacing:-.01em}.ah__main{flex:1;inline-size:100%;max-inline-size:1120px;margin-inline:auto;padding:56px 40px;display:flex;flex-direction:column;justify-content:center;gap:44px}.ah__hero{max-inline-size:640px}.ah__title{margin:0 0 var(--sp-3);font-size:44px;font-weight:var(--fw-semibold);letter-spacing:-.03em;text-wrap:balance;background:linear-gradient(180deg,var(--ink),var(--ink-2));-webkit-background-clip:text;background-clip:text;color:transparent}.ah__sub{margin:0;max-inline-size:560px;font-size:var(--text-lg);line-height:1.55;color:var(--ink-3);text-wrap:pretty}.ah__sec{display:flex;flex-direction:column;gap:var(--sp-4)}.ah__sec--secondary{padding-block-start:28px;border-block-start:1px solid var(--w08)}.ah__sec-hd{display:flex;align-items:center;gap:var(--sp-3);inline-size:100%;padding:0;background:none;border:0;cursor:pointer;font-family:inherit;color:var(--ink);text-align:start}.ah__sec-hd:focus-visible{outline:2px solid;outline-color:var(--focus-ring);outline-offset:2px}.ah__sec-chev{flex-shrink:0;color:var(--ink-3);transition:transform var(--t-overlay)}.ah__sec-title{font-size:var(--text-md);font-weight:var(--fw-semibold);letter-spacing:-.01em}.ah__sec-title--static{margin:0;color:var(--ink-3);font-size:var(--text-xs);letter-spacing:var(--tracking-wide);text-transform:uppercase}.ah__sec-count{display:inline-grid;place-items:center;min-inline-size:22px;block-size:20px;padding-inline:6px;border-radius:999px;background:var(--bg-3);border:1px solid var(--line);font-size:var(--text-2xs);font-weight:var(--fw-medium);font-variant-numeric:tabular-nums;color:var(--ink-3)}.ah__sec-hint{margin-inline-start:auto;font-size:var(--text-xs);color:var(--ink-3)}.ah__grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:14px;margin-top:4px;justify-content:flex-start}.ah__card{display:flex;flex-direction:column;align-items:stretch;position:relative;overflow:hidden;text-align:start;padding:20px;gap:16px;background:linear-gradient(160deg,var(--w055),var(--w02));border:1px solid var(--w09);border-radius:20px;color:inherit;font-family:inherit;cursor:pointer;animation:appTileIn .3s var(--nova-ease-micro) both}.ah__card:nth-child(1){animation-delay:0ms}.ah__card:nth-child(2){animation-delay:20ms}.ah__card:nth-child(3){animation-delay:40ms}.ah__card:nth-child(4){animation-delay:60ms}.ah__card:nth-child(5){animation-delay:80ms}.ah__card:nth-child(6){animation-delay:.1s}.ah__card:nth-child(7){animation-delay:.12s}.ah__card:nth-child(8){animation-delay:.14s}.ah__card:nth-child(9){animation-delay:.16s}.ah__card:nth-child(10){animation-delay:.18s}.ah__card:nth-child(11){animation-delay:.2s}.ah__card:nth-child(12){animation-delay:.22s}.ah__card:nth-child(n+13){animation-delay:.22s}.ah__card{transition:transform var(--t-overlay),box-shadow var(--t-overlay),border-color var(--t-state),background var(--t-state)}.ah__card:hover:not(:disabled){transform:translateY(-3px);background:linear-gradient(160deg,color-mix(in srgb,var(--module-teal) 22%,transparent),color-mix(in srgb,var(--sys-teal) 5%,transparent));border-color:color-mix(in srgb,var(--module-teal) 50%,transparent);box-shadow:inset 0 1px color-mix(in srgb,var(--edge-highlight) 20%,transparent),0 20px 46px color-mix(in srgb,var(--module-teal) 16%,transparent),var(--shadow-filter)}.ah__card:focus-visible{outline:0;border-color:color-mix(in oklab,var(--accent) 50%,transparent);background-image:linear-gradient(160deg,var(--tint-hover),transparent);box-shadow:0 0 0 3px var(--accent-soft),0 20px 46px color-mix(in oklab,var(--accent) 16%,transparent),var(--shadow-filter)}.ah__card:disabled{cursor:default;opacity:.5}.ah__card-ico{display:grid;place-items:center;inline-size:42px;block-size:42px;flex:none;border-radius:13px;background:linear-gradient(140deg,color-mix(in srgb,var(--module-teal-deep) 62%,transparent),color-mix(in srgb,var(--module-teal) 30%,transparent));box-shadow:0 6px 16px color-mix(in srgb,var(--module-teal-deep) 30%,transparent),inset 0 1px color-mix(in srgb,var(--edge-highlight) 50%,transparent);border:0;color:var(--ink-inverse);font-size:18px;transition:transform var(--t-overlay)}.ah__card--compact:hover:not(:disabled) .ah__card-ico,.ah__card--compact:focus-visible .ah__card-ico{background:linear-gradient(135deg,var(--accent),var(--sys-teal));box-shadow:inset 0 1px 0 var(--edge-highlight);color:var(--on-accent)}.ah__card-title{font-size:var(--text-sm);font-weight:var(--fw-semibold);letter-spacing:-.01em;color:var(--ink)}.ah__card-text{display:flex;flex-direction:column;gap:5px}.ah__card-title--feature{font-family:var(--font-family);font-weight:var(--fw-semibold);font-size:16.5px;line-height:1.25;letter-spacing:-.005em;color:var(--ink)}.ah__card-desc{font-size:var(--text-xs);line-height:1.45;color:var(--ink-3);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ah__card-desc--feature{font-family:var(--font-family);font-weight:400;font-size:13px;line-height:1.45;color:var(--w55);text-wrap:pretty;overflow:visible;white-space:normal}.ah__card-arrow{flex-shrink:0;transition:color var(--t-overlay),transform var(--t-overlay)}.ah__card--compact{flex-direction:row;align-items:center;gap:var(--sp-3);padding:14px 16px;background-color:var(--bg);background-image:linear-gradient(160deg,var(--w035),var(--w035));border-radius:16px;border-color:var(--w08)}.ah__card--compact:hover:not(:disabled),.ah__card--compact:focus-visible{border-color:color-mix(in oklab,var(--accent) 40%,transparent);background-image:linear-gradient(160deg,var(--tint-hover),transparent);box-shadow:0 20px 46px color-mix(in oklab,var(--accent) 16%,transparent),var(--shadow-filter)}.ah__card--compact .ah__card-ico{inline-size:32px;block-size:32px;margin-block-end:0;flex-shrink:0;border-radius:10px;font-size:var(--icon-md);background:var(--bg-3);box-shadow:none;color:var(--ink)}.ah__card-main{display:flex;flex-direction:column;gap:2px;flex:1;min-inline-size:0}.ah__card--compact .ah__card-arrow{color:var(--ink-4)}.ah__card--compact:hover:not(:disabled) .ah__card-arrow{color:var(--accent);transform:translate(2px)}:host-context([dir=rtl]) .ah__card-arrow{transform:scaleX(-1)}:host-context([dir=rtl]) .ah__sec-chev:not(.ah__sec-chev--open){transform:scaleX(-1)}:host-context([dir=rtl]) .ah__card--compact:hover:not(:disabled) .ah__card-arrow{transform:scaleX(-1) translate(2px)}.ah__sec-chev--open{transform:rotate(90deg)}@container (width <= 900px){.ah__main{padding:40px 24px;gap:36px}.ah__title{font-size:36px}.ah__util{padding:var(--sp-3) var(--sp-5)}}@media(width<=900px){.ah__main{padding:40px 24px;gap:36px}.ah__title{font-size:36px}.ah__util{padding:var(--sp-3) var(--sp-5)}}@container (width <= 560px){.ah__title{font-size:30px}.ah__sub{font-size:var(--text-sm)}.ah__sec-hint{display:none}}@media(width<=560px){.ah__title{font-size:30px}.ah__sub{font-size:var(--text-sm)}.ah__sec-hint{display:none}}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
25019
25410
  }
25020
25411
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.19", ngImport: i0, type: FlyAppHomeComponent, decorators: [{
25021
25412
  type: Component,
25022
- args: [{ selector: 'fly-app-home', standalone: true, imports: [NgTemplateOutlet, TranslatePipe], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"ah\">\r\n <header class=\"ah__util\">\r\n <button type=\"button\" class=\"ah__brand\" (click)=\"brandSelected.emit()\">\r\n <span class=\"ah__brand-mark\"><ng-content select=\"[app-home-brand]\" /></span>\r\n @if (brandLabelKey(); as key) {\r\n <span class=\"ah__brand-name\">{{ key | translate }}</span>\r\n }\r\n </button>\r\n <ng-content select=\"[app-home-actions]\" />\r\n </header>\r\n\r\n <main class=\"ah__main\">\r\n @if (titleKey() || subtitleKey()) {\r\n <section class=\"ah__hero\">\r\n @if (titleKey(); as key) {\r\n <h1 class=\"ah__title\">{{ key | translate }}</h1>\r\n }\r\n @if (subtitleKey(); as key) {\r\n <p class=\"ah__sub\">{{ key | translate }}</p>\r\n }\r\n </section>\r\n }\r\n\r\n @for (row of rows(); track row.index) {\r\n <section\r\n class=\"ah__sec\"\r\n [class.ah__sec--secondary]=\"row.index > 0\"\r\n [attr.aria-label]=\"row.section.titleKey ? null : (modulesLabelKey() | translate)\"\r\n >\r\n @if (row.section.titleKey; as titleKey) {\r\n @if (row.section.collapsible) {\r\n <button\r\n type=\"button\"\r\n class=\"ah__sec-hd\"\r\n (click)=\"toggle(row.index)\"\r\n [attr.aria-expanded]=\"row.expanded\"\r\n [attr.aria-controls]=\"sectionId(row.index)\"\r\n >\r\n <!-- Points end-ward when shut, down when open. `--open` wins over the RTL\r\n flip below because a downward chevron has no direction to mirror. -->\r\n <svg\r\n class=\"ah__sec-chev\"\r\n [class.ah__sec-chev--open]=\"row.expanded\"\r\n width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"2.4\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"\r\n >\r\n <polyline points=\"9 6 15 12 9 18\" />\r\n </svg>\r\n <span class=\"ah__sec-title\">{{ titleKey | translate }}</span>\r\n <span class=\"ah__sec-count\">{{ row.section.modules.length }}</span>\r\n @if (row.hintKey; as hint) {\r\n <span class=\"ah__sec-hint\">{{ hint | translate }}</span>\r\n }\r\n </button>\r\n } @else {\r\n <h2 class=\"ah__sec-title ah__sec-title--static\">{{ titleKey | translate }}</h2>\r\n }\r\n }\r\n\r\n @if (row.expanded) {\r\n <div class=\"ah__grid\" [class.ah__grid--compact]=\"row.layout === 'compact'\" [id]=\"sectionId(row.index)\">\r\n @for (mod of row.section.modules; track mod.key) {\r\n <button\r\n type=\"button\"\r\n class=\"ah__card\"\r\n [class.ah__card--compact]=\"row.layout === 'compact'\"\r\n [disabled]=\"mod.disabled\"\r\n (click)=\"select(mod)\"\r\n >\r\n <span class=\"ah__card-ico\">\r\n @if (iconFor(mod.key); as tpl) {\r\n <ng-container *ngTemplateOutlet=\"tpl\" />\r\n } @else if (mod.iconClass) {\r\n <i [class]=\"mod.iconClass\" aria-hidden=\"true\"></i>\r\n }\r\n </span>\r\n\r\n @if (row.layout === 'compact') {\r\n <span class=\"ah__card-main\">\r\n <span class=\"ah__card-title\">{{ mod.labelKey | translate }}</span>\r\n @if (mod.descKey; as descKey) {\r\n <span class=\"ah__card-desc\">{{ descKey | translate }}</span>\r\n }\r\n </span>\r\n <svg\r\n class=\"ah__card-arrow\" width=\"11\" height=\"11\" viewBox=\"0 0 24 24\" fill=\"none\"\r\n stroke=\"currentColor\" stroke-width=\"2.6\" stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\" aria-hidden=\"true\"\r\n >\r\n <polyline points=\"9 6 15 12 9 18\" />\r\n </svg>\r\n } @else {\r\n <!-- No \"Open \u203A\" affordance row \u2014 the design's module card (MainContent.dc.html)\r\n ends at the description; the whole card is the click target and hover carries\r\n the affordance. Removed at the 2026-08-17 fidelity pass. -->\r\n <span class=\"ah__card-title ah__card-title--feature\">{{ mod.labelKey | translate }}</span>\r\n @if (mod.descKey; as descKey) {\r\n <span class=\"ah__card-desc ah__card-desc--feature\">{{ descKey | translate }}</span>\r\n }\r\n }\r\n </button>\r\n }\r\n </div>\r\n }\r\n </section>\r\n }\r\n </main>\r\n</div>\r\n", styles: [":host{display:flex;flex-direction:column;min-height:100%;container-type:inline-size}.ah{display:flex;flex-direction:column;flex:1;min-height:100%}.ah__util{display:flex;align-items:center;justify-content:space-between;gap:var(--sp-4);padding:var(--sp-4) var(--sp-6)}:host-context(.window-content) .ah__brand{display:none}:host-context(.window-content) .ah__util{justify-content:flex-end}:host-context(.window-content) .ah__util:not(:has(>:not(.ah__brand))){display:none}.ah__brand{display:inline-flex;align-items:center;gap:var(--sp-2);padding:0;border:0;background:none;color:var(--ink);font-family:inherit;cursor:pointer}.ah__brand:focus-visible{outline:2px solid;outline-color:var(--focus-ring);outline-offset:2px}.ah__brand-name{font-size:var(--text-md);font-weight:var(--fw-semibold);letter-spacing:-.01em}.ah__main{flex:1;inline-size:100%;max-inline-size:1120px;margin-inline:auto;padding:56px 40px;display:flex;flex-direction:column;justify-content:center;gap:44px}.ah__hero{max-inline-size:640px}.ah__title{margin:0 0 var(--sp-3);font-size:44px;font-weight:var(--fw-semibold);letter-spacing:-.03em;text-wrap:balance;background:linear-gradient(180deg,var(--ink),var(--ink-2));-webkit-background-clip:text;background-clip:text;color:transparent}.ah__sub{margin:0;max-inline-size:560px;font-size:var(--text-lg);line-height:1.55;color:var(--ink-3);text-wrap:pretty}.ah__sec{display:flex;flex-direction:column;gap:var(--sp-4)}.ah__sec--secondary{padding-block-start:28px;border-block-start:1px solid var(--w08)}.ah__sec-hd{display:flex;align-items:center;gap:var(--sp-3);inline-size:100%;padding:0;background:none;border:0;cursor:pointer;font-family:inherit;color:var(--ink);text-align:start}.ah__sec-hd:focus-visible{outline:2px solid;outline-color:var(--focus-ring);outline-offset:2px}.ah__sec-chev{flex-shrink:0;color:var(--ink-3);transition:transform var(--t-overlay)}.ah__sec-title{font-size:var(--text-md);font-weight:var(--fw-semibold);letter-spacing:-.01em}.ah__sec-title--static{margin:0;color:var(--ink-3);font-size:var(--text-xs);letter-spacing:var(--tracking-wide);text-transform:uppercase}.ah__sec-count{display:inline-grid;place-items:center;min-inline-size:22px;block-size:20px;padding-inline:6px;border-radius:999px;background:var(--bg-3);border:1px solid var(--line);font-size:var(--text-2xs);font-weight:var(--fw-medium);font-variant-numeric:tabular-nums;color:var(--ink-3)}.ah__sec-hint{margin-inline-start:auto;font-size:var(--text-xs);color:var(--ink-3)}.ah__grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:14px}.ah__card{display:flex;flex-direction:column;align-items:stretch;position:relative;overflow:hidden;text-align:start;padding:20px;background-image:linear-gradient(160deg,var(--w055),var(--w02));border:1px solid var(--w09);border-radius:20px;color:inherit;font-family:inherit;cursor:pointer;animation:appTileIn .3s var(--nova-ease-micro) both}.ah__card:nth-child(1){animation-delay:0ms}.ah__card:nth-child(2){animation-delay:20ms}.ah__card:nth-child(3){animation-delay:40ms}.ah__card:nth-child(4){animation-delay:60ms}.ah__card:nth-child(5){animation-delay:80ms}.ah__card:nth-child(6){animation-delay:.1s}.ah__card:nth-child(7){animation-delay:.12s}.ah__card:nth-child(8){animation-delay:.14s}.ah__card:nth-child(9){animation-delay:.16s}.ah__card:nth-child(10){animation-delay:.18s}.ah__card:nth-child(11){animation-delay:.2s}.ah__card:nth-child(12){animation-delay:.22s}.ah__card:nth-child(n+13){animation-delay:.22s}.ah__card{transition:transform var(--t-overlay),box-shadow var(--t-overlay),border-color var(--t-state),background-image var(--t-state)}.ah__card:hover:not(:disabled){transform:translateY(-3px);border-color:color-mix(in oklab,var(--accent) 50%,transparent);background-image:linear-gradient(160deg,var(--tint-hover),transparent);box-shadow:0 20px 46px color-mix(in oklab,var(--accent) 16%,transparent),var(--shadow-filter)}.ah__card:focus-visible{outline:0;border-color:color-mix(in oklab,var(--accent) 50%,transparent);background-image:linear-gradient(160deg,var(--tint-hover),transparent);box-shadow:0 0 0 3px var(--accent-soft),0 20px 46px color-mix(in oklab,var(--accent) 16%,transparent),var(--shadow-filter)}.ah__card:disabled{cursor:default;opacity:.5}.ah__card-ico{display:grid;place-items:center;inline-size:42px;block-size:42px;margin-block-end:16px;border-radius:13px;background:linear-gradient(140deg,color-mix(in srgb,var(--accent) 50%,transparent),color-mix(in srgb,var(--sys-teal) 22%,transparent));box-shadow:0 6px 16px color-mix(in srgb,var(--accent) 30%,transparent),inset 0 1px 0 var(--edge-highlight);border:0;color:var(--on-accent);font-size:var(--icon-lg)}.ah__card--compact:hover:not(:disabled) .ah__card-ico,.ah__card--compact:focus-visible .ah__card-ico{background:linear-gradient(135deg,var(--accent),var(--sys-teal));box-shadow:inset 0 1px 0 var(--edge-highlight);color:var(--on-accent)}.ah__card-title{font-size:var(--text-sm);font-weight:var(--fw-semibold);letter-spacing:-.01em;color:var(--ink)}.ah__card-title--feature{margin-block-end:5px;font-size:16.5px;line-height:1.25;letter-spacing:-.005em}.ah__card-desc{font-size:var(--text-xs);line-height:1.45;color:var(--ink-3);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ah__card-desc--feature{margin-block-end:0;font-size:13px;line-height:1.45;text-wrap:pretty;overflow:visible;white-space:normal}.ah__card-arrow{flex-shrink:0;transition:color var(--t-overlay),transform var(--t-overlay)}.ah__card--compact{flex-direction:row;align-items:center;gap:var(--sp-3);padding:14px 16px;background-color:var(--bg);background-image:linear-gradient(160deg,var(--w035),var(--w035));border-radius:16px;border-color:var(--w08)}.ah__card--compact:hover:not(:disabled),.ah__card--compact:focus-visible{border-color:color-mix(in oklab,var(--accent) 40%,transparent);background-image:linear-gradient(160deg,var(--tint-hover),transparent)}.ah__card--compact .ah__card-ico{inline-size:32px;block-size:32px;margin-block-end:0;flex-shrink:0;border-radius:10px;font-size:var(--icon-md);background:var(--bg-3);box-shadow:none;color:var(--ink)}.ah__card-main{display:flex;flex-direction:column;gap:2px;flex:1;min-inline-size:0}.ah__card--compact .ah__card-arrow{color:var(--ink-4)}.ah__card--compact:hover:not(:disabled) .ah__card-arrow{color:var(--accent);transform:translate(2px)}:host-context([dir=rtl]) .ah__card-arrow{transform:scaleX(-1)}:host-context([dir=rtl]) .ah__sec-chev:not(.ah__sec-chev--open){transform:scaleX(-1)}:host-context([dir=rtl]) .ah__card--compact:hover:not(:disabled) .ah__card-arrow{transform:scaleX(-1) translate(2px)}.ah__sec-chev--open{transform:rotate(90deg)}@container (width <= 900px){.ah__main{padding:40px 24px;gap:36px}.ah__title{font-size:36px}.ah__util{padding:var(--sp-3) var(--sp-5)}}@media(width<=900px){.ah__main{padding:40px 24px;gap:36px}.ah__title{font-size:36px}.ah__util{padding:var(--sp-3) var(--sp-5)}}@container (width <= 560px){.ah__title{font-size:30px}.ah__sub{font-size:var(--text-sm)}.ah__sec-hint{display:none}}@media(width<=560px){.ah__title{font-size:30px}.ah__sub{font-size:var(--text-sm)}.ah__sec-hint{display:none}}\n"] }]
25413
+ args: [{ selector: 'fly-app-home', standalone: true, imports: [NgTemplateOutlet, TranslatePipe], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"ah\">\r\n <header class=\"ah__util\">\r\n <button type=\"button\" class=\"ah__brand\" (click)=\"brandSelected.emit()\">\r\n <span class=\"ah__brand-mark\"><ng-content select=\"[app-home-brand]\" /></span>\r\n @if (brandLabelKey(); as key) {\r\n <span class=\"ah__brand-name\">{{ key | translate }}</span>\r\n }\r\n </button>\r\n <ng-content select=\"[app-home-actions]\" />\r\n </header>\r\n\r\n <main class=\"ah__main\">\r\n @if (titleKey() || subtitleKey()) {\r\n <section class=\"ah__hero\">\r\n @if (titleKey(); as key) {\r\n <h1 class=\"ah__title\">{{ key | translate }}</h1>\r\n }\r\n @if (subtitleKey(); as key) {\r\n <p class=\"ah__sub\">{{ key | translate }}</p>\r\n }\r\n </section>\r\n }\r\n\r\n @for (row of rows(); track row.index) {\r\n <section\r\n class=\"ah__sec\"\r\n [class.ah__sec--secondary]=\"row.index > 0\"\r\n [attr.aria-label]=\"row.section.titleKey ? null : (modulesLabelKey() | translate)\"\r\n >\r\n @if (row.section.titleKey; as titleKey) {\r\n @if (row.section.collapsible) {\r\n <button\r\n type=\"button\"\r\n class=\"ah__sec-hd\"\r\n (click)=\"toggle(row.index)\"\r\n [attr.aria-expanded]=\"row.expanded\"\r\n [attr.aria-controls]=\"sectionId(row.index)\"\r\n >\r\n <!-- Points end-ward when shut, down when open. `--open` wins over the RTL\r\n flip below because a downward chevron has no direction to mirror. -->\r\n <svg\r\n class=\"ah__sec-chev\"\r\n [class.ah__sec-chev--open]=\"row.expanded\"\r\n width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\"\r\n stroke-width=\"2.4\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"\r\n >\r\n <polyline points=\"9 6 15 12 9 18\" />\r\n </svg>\r\n <span class=\"ah__sec-title\">{{ titleKey | translate }}</span>\r\n <span class=\"ah__sec-count\">{{ row.section.modules.length }}</span>\r\n @if (row.hintKey; as hint) {\r\n <span class=\"ah__sec-hint\">{{ hint | translate }}</span>\r\n }\r\n </button>\r\n } @else {\r\n <h2 class=\"ah__sec-title ah__sec-title--static\">{{ titleKey | translate }}</h2>\r\n }\r\n }\r\n\r\n @if (row.expanded) {\r\n <div class=\"ah__grid\" [class.ah__grid--compact]=\"row.layout === 'compact'\" [id]=\"sectionId(row.index)\">\r\n @for (mod of row.section.modules; track mod.key) {\r\n <button\r\n type=\"button\"\r\n class=\"ah__card\"\r\n [class.ah__card--compact]=\"row.layout === 'compact'\"\r\n [disabled]=\"mod.disabled\"\r\n (click)=\"select(mod)\"\r\n >\r\n <span class=\"ah__card-ico\">\r\n @if (iconFor(mod.key); as tpl) {\r\n <ng-container *ngTemplateOutlet=\"tpl\" />\r\n } @else if (mod.iconClass) {\r\n <i [class]=\"mod.iconClass\" aria-hidden=\"true\"></i>\r\n }\r\n </span>\r\n\r\n @if (row.layout === 'compact') {\r\n <span class=\"ah__card-main\">\r\n <span class=\"ah__card-title\">{{ mod.labelKey | translate }}</span>\r\n @if (mod.descKey; as descKey) {\r\n <span class=\"ah__card-desc\">{{ descKey | translate }}</span>\r\n }\r\n </span>\r\n <svg\r\n class=\"ah__card-arrow\" width=\"11\" height=\"11\" viewBox=\"0 0 24 24\" fill=\"none\"\r\n stroke=\"currentColor\" stroke-width=\"2.6\" stroke-linecap=\"round\"\r\n stroke-linejoin=\"round\" aria-hidden=\"true\"\r\n >\r\n <polyline points=\"9 6 15 12 9 18\" />\r\n </svg>\r\n } @else {\r\n <!-- No \"Open \u203A\" affordance row \u2014 the design's module card (MainContent.dc.html)\r\n ends at the description; the whole card is the click target and hover carries\r\n the affordance. Removed at the 2026-08-17 fidelity pass. -->\r\n <!-- Text stack: icon-to-text spacing is `.ah__card`'s own gap; this wrapper's\r\n gap is title-to-description only (module-card fidelity pass, 2026-08-20). -->\r\n <span class=\"ah__card-text\">\r\n <span class=\"ah__card-title ah__card-title--feature\">{{ mod.labelKey | translate }}</span>\r\n @if (mod.descKey; as descKey) {\r\n <span class=\"ah__card-desc ah__card-desc--feature\">{{ descKey | translate }}</span>\r\n }\r\n </span>\r\n }\r\n </button>\r\n }\r\n </div>\r\n }\r\n </section>\r\n }\r\n </main>\r\n</div>\r\n", styles: [":host{display:flex;flex-direction:column;min-height:100%;container-type:inline-size}.ah{display:flex;flex-direction:column;flex:1;min-height:100%}.ah__util{display:flex;align-items:center;justify-content:space-between;gap:var(--sp-4);padding:var(--sp-4) var(--sp-6)}:host-context(.window-content) .ah__brand{display:none}:host-context(.window-content) .ah__util{justify-content:flex-end}:host-context(.window-content) .ah__util:not(:has(>:not(.ah__brand))){display:none}.ah__brand{display:inline-flex;align-items:center;gap:var(--sp-2);padding:0;border:0;background:none;color:var(--ink);font-family:inherit;cursor:pointer}.ah__brand:focus-visible{outline:2px solid;outline-color:var(--focus-ring);outline-offset:2px}.ah__brand-name{font-size:var(--text-md);font-weight:var(--fw-semibold);letter-spacing:-.01em}.ah__main{flex:1;inline-size:100%;max-inline-size:1120px;margin-inline:auto;padding:56px 40px;display:flex;flex-direction:column;justify-content:center;gap:44px}.ah__hero{max-inline-size:640px}.ah__title{margin:0 0 var(--sp-3);font-size:44px;font-weight:var(--fw-semibold);letter-spacing:-.03em;text-wrap:balance;background:linear-gradient(180deg,var(--ink),var(--ink-2));-webkit-background-clip:text;background-clip:text;color:transparent}.ah__sub{margin:0;max-inline-size:560px;font-size:var(--text-lg);line-height:1.55;color:var(--ink-3);text-wrap:pretty}.ah__sec{display:flex;flex-direction:column;gap:var(--sp-4)}.ah__sec--secondary{padding-block-start:28px;border-block-start:1px solid var(--w08)}.ah__sec-hd{display:flex;align-items:center;gap:var(--sp-3);inline-size:100%;padding:0;background:none;border:0;cursor:pointer;font-family:inherit;color:var(--ink);text-align:start}.ah__sec-hd:focus-visible{outline:2px solid;outline-color:var(--focus-ring);outline-offset:2px}.ah__sec-chev{flex-shrink:0;color:var(--ink-3);transition:transform var(--t-overlay)}.ah__sec-title{font-size:var(--text-md);font-weight:var(--fw-semibold);letter-spacing:-.01em}.ah__sec-title--static{margin:0;color:var(--ink-3);font-size:var(--text-xs);letter-spacing:var(--tracking-wide);text-transform:uppercase}.ah__sec-count{display:inline-grid;place-items:center;min-inline-size:22px;block-size:20px;padding-inline:6px;border-radius:999px;background:var(--bg-3);border:1px solid var(--line);font-size:var(--text-2xs);font-weight:var(--fw-medium);font-variant-numeric:tabular-nums;color:var(--ink-3)}.ah__sec-hint{margin-inline-start:auto;font-size:var(--text-xs);color:var(--ink-3)}.ah__grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:14px;margin-top:4px;justify-content:flex-start}.ah__card{display:flex;flex-direction:column;align-items:stretch;position:relative;overflow:hidden;text-align:start;padding:20px;gap:16px;background:linear-gradient(160deg,var(--w055),var(--w02));border:1px solid var(--w09);border-radius:20px;color:inherit;font-family:inherit;cursor:pointer;animation:appTileIn .3s var(--nova-ease-micro) both}.ah__card:nth-child(1){animation-delay:0ms}.ah__card:nth-child(2){animation-delay:20ms}.ah__card:nth-child(3){animation-delay:40ms}.ah__card:nth-child(4){animation-delay:60ms}.ah__card:nth-child(5){animation-delay:80ms}.ah__card:nth-child(6){animation-delay:.1s}.ah__card:nth-child(7){animation-delay:.12s}.ah__card:nth-child(8){animation-delay:.14s}.ah__card:nth-child(9){animation-delay:.16s}.ah__card:nth-child(10){animation-delay:.18s}.ah__card:nth-child(11){animation-delay:.2s}.ah__card:nth-child(12){animation-delay:.22s}.ah__card:nth-child(n+13){animation-delay:.22s}.ah__card{transition:transform var(--t-overlay),box-shadow var(--t-overlay),border-color var(--t-state),background var(--t-state)}.ah__card:hover:not(:disabled){transform:translateY(-3px);background:linear-gradient(160deg,color-mix(in srgb,var(--module-teal) 22%,transparent),color-mix(in srgb,var(--sys-teal) 5%,transparent));border-color:color-mix(in srgb,var(--module-teal) 50%,transparent);box-shadow:inset 0 1px color-mix(in srgb,var(--edge-highlight) 20%,transparent),0 20px 46px color-mix(in srgb,var(--module-teal) 16%,transparent),var(--shadow-filter)}.ah__card:focus-visible{outline:0;border-color:color-mix(in oklab,var(--accent) 50%,transparent);background-image:linear-gradient(160deg,var(--tint-hover),transparent);box-shadow:0 0 0 3px var(--accent-soft),0 20px 46px color-mix(in oklab,var(--accent) 16%,transparent),var(--shadow-filter)}.ah__card:disabled{cursor:default;opacity:.5}.ah__card-ico{display:grid;place-items:center;inline-size:42px;block-size:42px;flex:none;border-radius:13px;background:linear-gradient(140deg,color-mix(in srgb,var(--module-teal-deep) 62%,transparent),color-mix(in srgb,var(--module-teal) 30%,transparent));box-shadow:0 6px 16px color-mix(in srgb,var(--module-teal-deep) 30%,transparent),inset 0 1px color-mix(in srgb,var(--edge-highlight) 50%,transparent);border:0;color:var(--ink-inverse);font-size:18px;transition:transform var(--t-overlay)}.ah__card--compact:hover:not(:disabled) .ah__card-ico,.ah__card--compact:focus-visible .ah__card-ico{background:linear-gradient(135deg,var(--accent),var(--sys-teal));box-shadow:inset 0 1px 0 var(--edge-highlight);color:var(--on-accent)}.ah__card-title{font-size:var(--text-sm);font-weight:var(--fw-semibold);letter-spacing:-.01em;color:var(--ink)}.ah__card-text{display:flex;flex-direction:column;gap:5px}.ah__card-title--feature{font-family:var(--font-family);font-weight:var(--fw-semibold);font-size:16.5px;line-height:1.25;letter-spacing:-.005em;color:var(--ink)}.ah__card-desc{font-size:var(--text-xs);line-height:1.45;color:var(--ink-3);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ah__card-desc--feature{font-family:var(--font-family);font-weight:400;font-size:13px;line-height:1.45;color:var(--w55);text-wrap:pretty;overflow:visible;white-space:normal}.ah__card-arrow{flex-shrink:0;transition:color var(--t-overlay),transform var(--t-overlay)}.ah__card--compact{flex-direction:row;align-items:center;gap:var(--sp-3);padding:14px 16px;background-color:var(--bg);background-image:linear-gradient(160deg,var(--w035),var(--w035));border-radius:16px;border-color:var(--w08)}.ah__card--compact:hover:not(:disabled),.ah__card--compact:focus-visible{border-color:color-mix(in oklab,var(--accent) 40%,transparent);background-image:linear-gradient(160deg,var(--tint-hover),transparent);box-shadow:0 20px 46px color-mix(in oklab,var(--accent) 16%,transparent),var(--shadow-filter)}.ah__card--compact .ah__card-ico{inline-size:32px;block-size:32px;margin-block-end:0;flex-shrink:0;border-radius:10px;font-size:var(--icon-md);background:var(--bg-3);box-shadow:none;color:var(--ink)}.ah__card-main{display:flex;flex-direction:column;gap:2px;flex:1;min-inline-size:0}.ah__card--compact .ah__card-arrow{color:var(--ink-4)}.ah__card--compact:hover:not(:disabled) .ah__card-arrow{color:var(--accent);transform:translate(2px)}:host-context([dir=rtl]) .ah__card-arrow{transform:scaleX(-1)}:host-context([dir=rtl]) .ah__sec-chev:not(.ah__sec-chev--open){transform:scaleX(-1)}:host-context([dir=rtl]) .ah__card--compact:hover:not(:disabled) .ah__card-arrow{transform:scaleX(-1) translate(2px)}.ah__sec-chev--open{transform:rotate(90deg)}@container (width <= 900px){.ah__main{padding:40px 24px;gap:36px}.ah__title{font-size:36px}.ah__util{padding:var(--sp-3) var(--sp-5)}}@media(width<=900px){.ah__main{padding:40px 24px;gap:36px}.ah__title{font-size:36px}.ah__util{padding:var(--sp-3) var(--sp-5)}}@container (width <= 560px){.ah__title{font-size:30px}.ah__sub{font-size:var(--text-sm)}.ah__sec-hint{display:none}}@media(width<=560px){.ah__title{font-size:30px}.ah__sub{font-size:var(--text-sm)}.ah__sec-hint{display:none}}\n"] }]
25023
25414
  }], propDecorators: { brandLabelKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "brandLabelKey", required: false }] }], titleKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "titleKey", required: false }] }], subtitleKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "subtitleKey", required: false }] }], sections: [{ type: i0.Input, args: [{ isSignal: true, alias: "sections", required: false }] }], modulesLabelKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "modulesLabelKey", required: false }] }], moduleSelected: [{ type: i0.Output, args: ["moduleSelected"] }], brandSelected: [{ type: i0.Output, args: ["brandSelected"] }], icons: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => FlyModuleIconDirective), { isSignal: true }] }] } });
25024
25415
 
25025
25416
  /**
@@ -27447,5 +27838,5 @@ const AUDIENCE_ERROR_CODES = {
27447
27838
  * Generated bundle index. Do not edit.
27448
27839
  */
27449
27840
 
27450
- export { AGENT_DRAG_MIME, AGENT_PAYLOAD_VERSION, APP_LOOKUP, AUDIENCE_ERROR_CODES, AUDIENCE_LIMITS, AUDIENCE_PRESETS, AUDIENCE_TERM_KINDS, AgentActionBus, AgentActionUnsupportedDispatchError, AgentCommandRegistry, AgentDropRegistry, AgentFlightAnimator, AgentLookupRegistry, AgentPayloadOversizeError, AudienceBuilderComponent, AuthService, BilingualFieldComponent, CRON_MODES, CRON_WEEKDAYS, ContextMenuComponent, DEFAULT_AGENT_PAYLOAD_LIMITS, DEFAULT_FLY_THEME_MODE, DS_BASELINE_LOCALES, DashboardKpiComponent, DialogResult, ENTITY_LINK_LAUNCHER, EntityLookupComponent, FLYOS_LAUNCH_EVENT, FLYOS_LAUNCH_REQUEST_EVENT, FLYOS_REMOTE_ROUTE_EVENT, FLY_ACCENT_PROPERTY, FLY_ADMIN_ROLES, FLY_CHUNK_RELOAD_FLAG, FLY_COMPACT_THRESHOLD, FLY_COUNTRIES, FLY_CURRENCIES_BRIEF_ENDPOINT, FLY_CURRENCY_DEFAULT_ENDPOINT, FLY_EMOJI_BY_ID, FLY_EMOJI_CATEGORIES, FLY_EMOJI_CATEGORY_BY_ID, FLY_EMOJI_DEFAULT_CATEGORIES, FLY_EMOJI_PACK, FLY_EMOJI_PACK_MISSING_MESSAGE, FLY_EMOJI_PREVIEW_COUNT, FLY_EMPTY_VALUE, FLY_LOCALE_CATALOG, FLY_MAGIC_BAR_EVENT, FLY_MAGIC_BAR_ICONS, FLY_MAGIC_BAR_STORE_KEY, FLY_NF_CACHE_HEAL_FLAG, FLY_RELOAD_DEBOUNCE_MS, FLY_RELOAD_REARM_MS, FLY_REMOTE_BASE_PATH, FLY_REMOTE_CONTEXT_EVENT, FLY_REMOTE_CONTEXT_STORE_KEY, FLY_REMOTE_ROUTES, FLY_SCAN_PENDING_DEFAULT_DELAY_MS, FLY_SCAN_PENDING_MAX_RETRIES, FLY_SCAN_PENDING_STATUS, FLY_SEARCH_DEBOUNCE_MS, FLY_SKIN_TONES, FLY_STANDALONE_AUTH_CONFIG, FLY_STRATEGY_OBJECTIVES_LOOKUP_ENDPOINT, FLY_THEME_MODE_IDS, FLY_VIEWPORT_IS_MOBILE, FLY_WINDOW_BREADCRUMBS_EVENT, FLY_WINDOW_BREADCRUMBS_STORE_KEY, FLY_WINDOW_HELP_HINT_EVENT, FLY_WINDOW_PAGE_TITLE_EVENT, FlyAchievementProgressComponent, FlyActionMenuComponent, FlyActionStackComponent, FlyAgentDraggableDirective, FlyAnimatedEmojiComponent, FlyAppHomeComponent, FlyAppTopbarComponent, FlyAppUnavailableComponent, FlyAuthLiveRefresh, FlyBadgeWallComponent, FlyBlockUiComponent, FlyBreadcrumbComponent, FlyButtonComponent, FlyBytesPipe, FlyCaptchaComponent, FlyCardActionsComponent, FlyCardBodyComponent, FlyCardComponent, FlyCardFooterComponent, FlyCardGridComponent, FlyCardMediaComponent, FlyCardMetaComponent, FlyCardStatusComponent, FlyCardTitleComponent, FlyCellDirective, FlyCheckboxComponent, FlyChipComponent, FlyChunkReloadErrorHandler, FlyClickOutsideDirective, FlyCollapsibleComponent, FlyCommentThreadComponent, FlyCompactNumberPipe, FlyConfirmDialogComponent, FlyControlDirective, FlyCronBuilderComponent, FlyCurrencyCatalogService, FlyCurrencySelectorComponent, FlyDataTableComponent, FlyDatePipe, FlyDateTimePipe, FlyDebouncer, FlyDecimalNumberPipe, FlyDeepLinkPrefetchService, FlyDetailCardComponent, FlyDetailShellComponent, FlyDrawerComponent, FlyDurationPipe, FlyDynamicFormComponent, FlyEmojiPickerComponent, FlyFieldComponent, FlyFileDownloadService, FlyFileUploadComponent, FlyFilterPanelComponent, FlyFormBannerComponent, FlyFormFooterComponent, FlyFormGridComponent, FlyFormSectionComponent, FlyFullNumberPipe, FlyGanttComponent, FlyHubClient, FlyIconButtonComponent, FlyIfAdminDirective, FlyIfRoleDirective, FlyImageUploadComponent, FlyLeaderboardComponent, FlyMagicActionsComponent, FlyMetaListComponent, FlyModalComponent, FlyModerationQueueComponent, FlyModuleIconDirective, FlyMoneyPipe, FlyPagerComponent, FlyPaginationComponent, FlyPeoplePickerComponent, FlyPointsTierComponent, FlyProgressComponent, FlyRelativeTimePipe, FlyRemoteContextService, FlyRemoteRouter, FlyRemoteRouterOutletComponent, FlySearchInputComponent, FlySectionHeaderComponent, FlySecureSrcDirective, FlySegmentedComponent, FlySelectComponent, FlySkeletonComponent, FlySliderComponent, FlySparklineComponent, FlySpinnerComponent, FlyStandaloneAuthCallbackComponent, FlyStandaloneAuthService, FlyStandaloneMagicActionsComponent, FlyStateMessageComponent, FlyStrategySelectorComponent, FlyDynamicFormComponent as FlySurveyFormComponent, FlyTabComponent, FlyTabsComponent, FlyTagsInputComponent, FlyThemeService, FlyTimePipe, FlyToastService, FlyToggleComponent, FlyTooltipDirective, FlyTreeNavComponent, FlyTypeaheadComponent, FlyUserDirectoryService, FlyWindowHelpService, FlyWindowTitleService, FlyosPendingLaunchesGlobalKey, FlyosShellHandlesLaunchRequestsGlobalKey, FlyosShellOwnsHistoryGlobalKey, GANTT_DEPENDENCY_TYPES, GANTT_ROW_TINT_ALPHA, GANTT_ZOOMS, I18nService, LAUNCH_CONTEXT, MAGIC_BAR_SEARCH_WIDTH_DEFAULT, MAGIC_BAR_SEARCH_WIDTH_MAX, MAGIC_BAR_SEARCH_WIDTH_MIN, MagicBarRegistry, MessageBoxButtons, MessageBoxComponent, MessageBoxIcon, MessageBoxService, MockAuthService, NOVA_PRIORITY_TONE, NOVA_STATUS_TONE, NOVA_TONE_FALLBACK, OverlayStack, PRESENCE_COLORS, PageHeaderComponent, RTL_LOCALE_SET, SHARE_ORG_CHART_SYSTEM_KEY_APPS, SHARE_ORG_CHART_SYSTEM_KEY_DEFAULT, SHARE_PANEL_DEFAULT_FILE_LEVELS, STATE_DEFAULT_ICONS, STATE_DEFAULT_MESSAGE_KEYS, STEP_UP_CODE, STEP_UP_REAUTH_HANDLER, STEP_UP_RETURN_KEY, SUPPORTED_AGENT_PAYLOAD_VERSIONS, SharePanelComponent, SourceAppResolver, StandaloneWindowManagerService, StatusBadgeComponent, StepUpService, ToastHostComponent, TranslatePipe, WINDOW_DATA, WINDOW_HELP_HINT, WindowBreadcrumbsRegistry, WindowManagerService, applySkinTone, applySuggestion, ariaSort, buildCron, canConfirm, canGoNext$1 as canGoNext, canGoPrev$1 as canGoPrev, captureFocus, clampMagicBarSearchWidth, clampPage$1 as clampPage, clampSliderValue, connectRemoteLaunch, enterActivatesNatively, filterGroup, filterSuggestions, findLocaleByDialect, findLocaleByPrefix, firstEnabledIndex, firstModuleIndex, flattenModules, flyAdminGuard, flyApiErrorMessage, flyCaptchaBase64Utf8, flyCaptchaBuildToken, flyCaptchaSha256Hex, flyCompactNumber, flyDebounced, flyDecimalNumber, flyDownloadBlob, flyDuration, flyEmojiFor, flyEmojiIsTonable, flyEmojiPackUrl, flyExportFileName, flyFirstEnabledIndex, flyFormatBytes, flyFormatDate, flyFormatDateTime, flyFormatMoney, flyFormatTime, flyFullNumber, flyNextEnabledIndex, flyNextSegmentIndex, flyRelativeTime, flyResolveActiveTab, flyRoleGuard, flyScanPendingDelayMs, flyScanRetry, flySignedCompact, flySkinToneLabelKey, flyStandaloneAuthGuard, flyStandaloneAuthInterceptor, flyToDateOnly, flyToPage, flyUnwrap, flyUnwrapCurrencies, flyUnwrapCurrency, flyUnwrapLenient, flyUnwrapObjectiveLookup, hasAnyRoleIn, healNativeFederationCacheOnce, initialExpanded, isAccentColor, isChunkLoadError, isFlyAuthStorePopulated, isNativeFederationCacheError, isRtlLocale, isRtlLocaleEntry, isValidCron, isValidSingleField, loadRemoteStyles, magicBarOwnerKey, magicBarSearchText, matchFlyRoutePattern, nextEnabledIndex, nextModuleIndex, nextSegmentIndex, nextSort, normalizeFlyTheme, normalizeRoles, novaPriorityToneVar, novaStatusToneVar, overlayStack, canGoNext as pagerCanGoNext, canGoPrev as pagerCanGoPrev, clampPage as pagerClampPage, parseCron, parseStepUpChallenge, parseTags, prefetchRemoteStyles, presenceColorFor, printConsoleSecurityWarning, provideFlyChunkReloadRecovery, provideFlyEmojiPack, provideFlyStandaloneAuth, reloadOnceForChunkError, requestAppLaunch, resolveActiveModule, resolveActiveSection, resolveActiveTab, resolveCellValue, resolveStateIcon, resolveStateMessageKey, restoreFocus, sameTags, sectionHintKey, sectionLayout, sliderTrackGradient, sparklinePath, sparklinePoints, stepUpInterceptor, stepUpReturnKey, trimAgentPayload, trimAgentString, unloadRemoteStyles, utf8ByteLength, validateAgentPayload, warnIfEmbeddedSessionMissing };
27841
+ export { AGENT_DRAG_MIME, AGENT_PAYLOAD_VERSION, APP_LOOKUP, AUDIENCE_ERROR_CODES, AUDIENCE_LIMITS, AUDIENCE_PRESETS, AUDIENCE_TERM_KINDS, AgentActionBus, AgentActionUnsupportedDispatchError, AgentCommandRegistry, AgentDropRegistry, AgentFlightAnimator, AgentLookupRegistry, AgentPayloadOversizeError, AudienceBuilderComponent, AuthService, BilingualFieldComponent, CRON_MODES, CRON_WEEKDAYS, ContextMenuComponent, DEFAULT_AGENT_PAYLOAD_LIMITS, DEFAULT_FLY_THEME_MODE, DS_BASELINE_LOCALES, DashboardKpiComponent, DialogResult, ENTITY_LINK_LAUNCHER, EntityLookupComponent, FLYOS_LAUNCH_EVENT, FLYOS_LAUNCH_REQUEST_EVENT, FLYOS_REMOTE_ROUTE_EVENT, FLY_ACCENT_PROPERTY, FLY_ADMIN_ROLES, FLY_CHUNK_RELOAD_FLAG, FLY_COMPACT_THRESHOLD, FLY_COUNTRIES, FLY_CURRENCIES_BRIEF_ENDPOINT, FLY_CURRENCY_DEFAULT_ENDPOINT, FLY_EMOJI_BY_ID, FLY_EMOJI_CATEGORIES, FLY_EMOJI_CATEGORY_BY_ID, FLY_EMOJI_DEFAULT_CATEGORIES, FLY_EMOJI_PACK, FLY_EMOJI_PACK_MISSING_MESSAGE, FLY_EMOJI_PREVIEW_COUNT, FLY_EMPTY_VALUE, FLY_LOCALE_CATALOG, FLY_MAGIC_BAR_EVENT, FLY_MAGIC_BAR_ICONS, FLY_MAGIC_BAR_STORE_KEY, FLY_NF_CACHE_HEAL_FLAG, FLY_RELOAD_DEBOUNCE_MS, FLY_RELOAD_REARM_MS, FLY_REMOTE_BASE_PATH, FLY_REMOTE_CONTEXT_EVENT, FLY_REMOTE_CONTEXT_STORE_KEY, FLY_REMOTE_ROUTES, FLY_SCAN_PENDING_DEFAULT_DELAY_MS, FLY_SCAN_PENDING_MAX_RETRIES, FLY_SCAN_PENDING_STATUS, FLY_SEARCH_DEBOUNCE_MS, FLY_SKIN_TONES, FLY_STANDALONE_AUTH_CONFIG, FLY_STRATEGY_OBJECTIVES_LOOKUP_ENDPOINT, FLY_THEME_MODE_IDS, FLY_VIEWPORT_IS_MOBILE, FLY_WINDOW_BREADCRUMBS_EVENT, FLY_WINDOW_BREADCRUMBS_STORE_KEY, FLY_WINDOW_HELP_HINT_EVENT, FLY_WINDOW_PAGE_TITLE_EVENT, FlyAchievementProgressComponent, FlyActionMenuComponent, FlyActionStackComponent, FlyAgentDraggableDirective, FlyAnimatedEmojiComponent, FlyAppHomeComponent, FlyAppTopbarComponent, FlyAppUnavailableComponent, FlyAuthLiveRefresh, FlyBadgeWallComponent, FlyBlockUiComponent, FlyBreadcrumbComponent, FlyButtonComponent, FlyBytesPipe, FlyCaptchaComponent, FlyCardActionsComponent, FlyCardBodyComponent, FlyCardComponent, FlyCardFooterComponent, FlyCardGridComponent, FlyCardMediaComponent, FlyCardMetaComponent, FlyCardStatusComponent, FlyCardTitleComponent, FlyCellDirective, FlyCheckboxComponent, FlyChipComponent, FlyChunkReloadErrorHandler, FlyClickOutsideDirective, FlyCollapsibleComponent, FlyCommentThreadComponent, FlyCompactNumberPipe, FlyConfirmDialogComponent, FlyControlDirective, FlyCronBuilderComponent, FlyCurrencyCatalogService, FlyCurrencySelectorComponent, FlyDataTableComponent, FlyDatePipe, FlyDateTimePipe, FlyDebouncer, FlyDecimalNumberPipe, FlyDeepLinkPrefetchService, FlyDetailCardComponent, FlyDetailShellComponent, FlyDrawerComponent, FlyDurationPipe, FlyDynamicFormComponent, FlyEmojiPickerComponent, FlyFieldComponent, FlyFileDownloadService, FlyFileUploadComponent, FlyFilterPanelComponent, FlyFormBannerComponent, FlyFormFooterComponent, FlyFormGridComponent, FlyFormSectionComponent, FlyFullNumberPipe, FlyGanttComponent, FlyHubClient, FlyIconButtonComponent, FlyIfAdminDirective, FlyIfRoleDirective, FlyImageUploadComponent, FlyLeaderboardComponent, FlyLifecyclePipelineComponent, FlyMagicActionsComponent, FlyMetaListComponent, FlyModalComponent, FlyModerationQueueComponent, FlyModuleIconDirective, FlyMoneyPipe, FlyOverviewKpiRowComponent, FlyOverviewRowsComponent, FlyOverviewSectionComponent, FlyOverviewSurfaceComponent, FlyPagerComponent, FlyPaginationComponent, FlyPeoplePickerComponent, FlyPointsTierComponent, FlyProgressComponent, FlyRelativeTimePipe, FlyRemoteContextService, FlyRemoteRouter, FlyRemoteRouterOutletComponent, FlySearchInputComponent, FlySectionHeaderComponent, FlySecureSrcDirective, FlySegmentedComponent, FlySelectComponent, FlySkeletonComponent, FlySliderComponent, FlySparklineComponent, FlySpinnerComponent, FlyStandaloneAuthCallbackComponent, FlyStandaloneAuthService, FlyStandaloneMagicActionsComponent, FlyStateMessageComponent, FlyStrategySelectorComponent, FlyDynamicFormComponent as FlySurveyFormComponent, FlyTabComponent, FlyTabsComponent, FlyTagsInputComponent, FlyThemeService, FlyTimePipe, FlyToastService, FlyToggleComponent, FlyTooltipDirective, FlyTreeNavComponent, FlyTypeaheadComponent, FlyUserDirectoryService, FlyWindowHelpService, FlyWindowTitleService, FlyosPendingLaunchesGlobalKey, FlyosShellHandlesLaunchRequestsGlobalKey, FlyosShellOwnsHistoryGlobalKey, GANTT_DEPENDENCY_TYPES, GANTT_ROW_TINT_ALPHA, GANTT_ZOOMS, I18nService, LAUNCH_CONTEXT, MAGIC_BAR_SEARCH_WIDTH_DEFAULT, MAGIC_BAR_SEARCH_WIDTH_MAX, MAGIC_BAR_SEARCH_WIDTH_MIN, MagicBarRegistry, MessageBoxButtons, MessageBoxComponent, MessageBoxIcon, MessageBoxService, MockAuthService, NOVA_PRIORITY_TONE, NOVA_STATUS_TONE, NOVA_TONE_FALLBACK, OverlayStack, PRESENCE_COLORS, PageHeaderComponent, RTL_LOCALE_SET, SHARE_ORG_CHART_SYSTEM_KEY_APPS, SHARE_ORG_CHART_SYSTEM_KEY_DEFAULT, SHARE_PANEL_DEFAULT_FILE_LEVELS, STATE_DEFAULT_ICONS, STATE_DEFAULT_MESSAGE_KEYS, STEP_UP_CODE, STEP_UP_REAUTH_HANDLER, STEP_UP_RETURN_KEY, SUPPORTED_AGENT_PAYLOAD_VERSIONS, SharePanelComponent, SourceAppResolver, StandaloneWindowManagerService, StatusBadgeComponent, StepUpService, ToastHostComponent, TranslatePipe, WINDOW_DATA, WINDOW_HELP_HINT, WindowBreadcrumbsRegistry, WindowManagerService, applySkinTone, applySuggestion, ariaSort, buildCron, canConfirm, canGoNext$1 as canGoNext, canGoPrev$1 as canGoPrev, captureFocus, clampMagicBarSearchWidth, clampPage$1 as clampPage, clampSliderValue, connectRemoteLaunch, enterActivatesNatively, filterGroup, filterSuggestions, findLocaleByDialect, findLocaleByPrefix, firstEnabledIndex, firstModuleIndex, flattenModules, flyAdminGuard, flyApiErrorMessage, flyCaptchaBase64Utf8, flyCaptchaBuildToken, flyCaptchaSha256Hex, flyCompactNumber, flyDebounced, flyDecimalNumber, flyDownloadBlob, flyDuration, flyEmojiFor, flyEmojiIsTonable, flyEmojiPackUrl, flyExportFileName, flyFirstEnabledIndex, flyFormatBytes, flyFormatDate, flyFormatDateTime, flyFormatMoney, flyFormatTime, flyFullNumber, flyNextEnabledIndex, flyNextSegmentIndex, flyRelativeTime, flyResolveActiveTab, flyRoleGuard, flyScanPendingDelayMs, flyScanRetry, flySignedCompact, flySkinToneLabelKey, flyStandaloneAuthGuard, flyStandaloneAuthInterceptor, flyToDateOnly, flyToPage, flyUnwrap, flyUnwrapCurrencies, flyUnwrapCurrency, flyUnwrapLenient, flyUnwrapObjectiveLookup, hasAnyRoleIn, healNativeFederationCacheOnce, initialExpanded, isAccentColor, isChunkLoadError, isFlyAuthStorePopulated, isNativeFederationCacheError, isRtlLocale, isRtlLocaleEntry, isValidCron, isValidSingleField, loadRemoteStyles, magicBarOwnerKey, magicBarSearchText, matchFlyRoutePattern, nextEnabledIndex, nextModuleIndex, nextSegmentIndex, nextSort, normalizeFlyTheme, normalizeRoles, novaPriorityToneVar, novaStatusToneVar, overlayStack, canGoNext as pagerCanGoNext, canGoPrev as pagerCanGoPrev, clampPage as pagerClampPage, parseCron, parseStepUpChallenge, parseTags, prefetchRemoteStyles, presenceColorFor, printConsoleSecurityWarning, provideFlyChunkReloadRecovery, provideFlyEmojiPack, provideFlyOfflineAuth, provideFlyStandaloneAuth, reloadOnceForChunkError, requestAppLaunch, resolveActiveModule, resolveActiveSection, resolveActiveTab, resolveCellValue, resolveStateIcon, resolveStateMessageKey, restoreFocus, sameTags, sectionHintKey, sectionLayout, sliderTrackGradient, sparklinePath, sparklinePoints, stepUpInterceptor, stepUpReturnKey, trimAgentPayload, trimAgentString, unloadRemoteStyles, utf8ByteLength, validateAgentPayload, warnIfEmbeddedSessionMissing };
27451
27842
  //# sourceMappingURL=flyos-design-system.mjs.map