@lifecorner/angular-ui-kit 3.27.1 → 3.28.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.
@@ -1,6 +1,10 @@
1
1
  import * as i0 from "@angular/core";
2
2
  import { ChangeDetectionStrategy, Component, DestroyRef, afterNextRender, computed, inject, input, viewChild } from "@angular/core";
3
+ import { OverlayInsetsService } from "@lifecorner/angular-ui-kit/internal/overlay";
3
4
  const BAR_VAR = "--_lc-app-shell-bar";
5
+ const TOP_INSET = "env(safe-area-inset-top, 0px)";
6
+ const BOTTOM_INSET = "env(safe-area-inset-bottom, 0px)";
7
+ const borderBoxHeight = (entry, target) => entry.borderBoxSize?.[0]?.blockSize ?? target.getBoundingClientRect().height;
4
8
  var AppShellComponent = class AppShellComponent {
5
9
  horizon = input(false, ...ngDevMode ? [{ debugName: "horizon" }] : /* istanbul ignore next */ []);
6
10
  navPlacement = input("below-header", ...ngDevMode ? [{ debugName: "navPlacement" }] : /* istanbul ignore next */ []);
@@ -11,21 +15,37 @@ var AppShellComponent = class AppShellComponent {
11
15
  return classes.join(" ");
12
16
  }, ...ngDevMode ? [{ debugName: "shellClasses" }] : /* istanbul ignore next */ []);
13
17
  shell = viewChild.required("shell", ...ngDevMode ? [{ debugName: "shell" }] : /* istanbul ignore next */ []);
18
+ headerSlot = viewChild.required("headerSlot", ...ngDevMode ? [{ debugName: "headerSlot" }] : /* istanbul ignore next */ []);
14
19
  barSlot = viewChild.required("barSlot", ...ngDevMode ? [{ debugName: "barSlot" }] : /* istanbul ignore next */ []);
15
20
  constructor() {
16
21
  const destroyRef = inject(DestroyRef);
22
+ const insets = inject(OverlayInsetsService);
17
23
  afterNextRender(() => {
18
24
  if (typeof ResizeObserver === "undefined") return;
19
25
  const shell = this.shell().nativeElement;
26
+ const header = this.headerSlot().nativeElement;
20
27
  const slot = this.barSlot().nativeElement;
21
- const clear = () => shell.style.removeProperty(BAR_VAR);
28
+ insets.top.set(TOP_INSET);
29
+ insets.bottom.set(BOTTOM_INSET);
30
+ let bar = null;
31
+ const clear = () => {
32
+ shell.style.removeProperty(BAR_VAR);
33
+ insets.bottom.set(BOTTOM_INSET);
34
+ };
22
35
  const sizes = new ResizeObserver((entries) => {
23
36
  const entry = entries[entries.length - 1];
24
37
  const height = entry.contentBoxSize?.[0]?.blockSize ?? entry.contentRect.height;
25
- if (height > 0) shell.style.setProperty(BAR_VAR, `${height}px`);
26
- else clear();
38
+ if (height > 0 && bar) {
39
+ shell.style.setProperty(BAR_VAR, `${height}px`);
40
+ const bottom = parseFloat(getComputedStyle(bar).bottom);
41
+ insets.bottom.set(`${(Number.isFinite(bottom) ? bottom : 0) + borderBoxHeight(entry, bar)}px`);
42
+ } else clear();
27
43
  });
28
- let bar = null;
44
+ const headerSizes = new ResizeObserver((entries) => {
45
+ const height = borderBoxHeight(entries[entries.length - 1], header);
46
+ insets.top.set(height > 0 ? `${height}px` : TOP_INSET);
47
+ });
48
+ headerSizes.observe(header);
29
49
  const pick = () => {
30
50
  const next = slot.querySelector(".lc-bottom-nav") ?? slot.firstElementChild;
31
51
  if (next === bar) return;
@@ -42,7 +62,10 @@ var AppShellComponent = class AppShellComponent {
42
62
  });
43
63
  destroyRef.onDestroy(() => {
44
64
  sizes.disconnect();
65
+ headerSizes.disconnect();
45
66
  changes?.disconnect();
67
+ insets.top.set(null);
68
+ insets.bottom.set(null);
46
69
  });
47
70
  });
48
71
  }
@@ -76,21 +99,31 @@ var AppShellComponent = class AppShellComponent {
76
99
  transformFunction: null
77
100
  }
78
101
  },
79
- viewQueries: [{
80
- propertyName: "shell",
81
- first: true,
82
- predicate: ["shell"],
83
- descendants: true,
84
- isSignal: true
85
- }, {
86
- propertyName: "barSlot",
87
- first: true,
88
- predicate: ["barSlot"],
89
- descendants: true,
90
- isSignal: true
91
- }],
102
+ viewQueries: [
103
+ {
104
+ propertyName: "shell",
105
+ first: true,
106
+ predicate: ["shell"],
107
+ descendants: true,
108
+ isSignal: true
109
+ },
110
+ {
111
+ propertyName: "headerSlot",
112
+ first: true,
113
+ predicate: ["headerSlot"],
114
+ descendants: true,
115
+ isSignal: true
116
+ },
117
+ {
118
+ propertyName: "barSlot",
119
+ first: true,
120
+ predicate: ["barSlot"],
121
+ descendants: true,
122
+ isSignal: true
123
+ }
124
+ ],
92
125
  ngImport: i0,
93
- template: "<div #shell [class]=\"shellClasses()\">\n <div class=\"lc-app-shell__header\"><ng-content select=\"[shell-header]\" /></div>\n <div class=\"lc-app-shell__nav\"><ng-content select=\"[shell-nav]\" /></div>\n <div class=\"lc-app-shell__body\"><ng-content /></div>\n @if (horizon()) {\n <div class=\"lc-app-shell__horizon lc-horizon\" aria-hidden=\"true\"><ng-content select=\"[shell-horizon-figure]\" /></div>\n }\n <div class=\"lc-app-shell__footer\"><ng-content select=\"[shell-footer]\" /></div>\n <div #barSlot class=\"lc-app-shell__bottom-nav\"><ng-content select=\"[shell-bottom-nav]\" /></div>\n</div>\n",
126
+ template: "<div #shell [class]=\"shellClasses()\">\n <div #headerSlot class=\"lc-app-shell__header\"><ng-content select=\"[shell-header]\" /></div>\n <div class=\"lc-app-shell__nav\"><ng-content select=\"[shell-nav]\" /></div>\n <div class=\"lc-app-shell__body\"><ng-content /></div>\n @if (horizon()) {\n <div class=\"lc-app-shell__horizon lc-horizon\" aria-hidden=\"true\"><ng-content select=\"[shell-horizon-figure]\" /></div>\n }\n <div class=\"lc-app-shell__footer\"><ng-content select=\"[shell-footer]\" /></div>\n <div #barSlot class=\"lc-app-shell__bottom-nav\"><ng-content select=\"[shell-bottom-nav]\" /></div>\n</div>\n",
94
127
  styles: [":host{display:block}.lc-app-shell{--_nav-width: var(--lc-app-shell-nav-width, 240px);--_clearance: var( --lc-app-shell-bottom-clearance, max( calc(112px + env(safe-area-inset-bottom, 0px)) , calc(var(--_lc-app-shell-bar, 72px) + 40px + env(safe-area-inset-bottom, 0px))) );display:grid;grid-template-columns:minmax(0,1fr);grid-template-rows:auto auto 1fr;grid-template-areas:\"header\" \"body\" \"end\";min-height:100vh;min-height:100dvh;box-sizing:border-box;background-color:var(--lc-app-shell-bg, var(--color-background));background-image:var(--lc-app-shell-bg-image, var(--app-background-image, none))}.lc-app-shell__header{grid-area:header;min-width:0;padding-top:env(safe-area-inset-top,0px);padding-left:env(safe-area-inset-left,0px);padding-right:env(safe-area-inset-right,0px)}.lc-app-shell__body{grid-area:body;min-width:0;padding-left:env(safe-area-inset-left,0px);padding-right:env(safe-area-inset-right,0px)}.lc-app-shell__nav{display:none}.lc-app-shell__horizon{grid-area:end;min-width:0}.lc-app-shell__footer{grid-area:end;align-self:end;min-width:0;padding-left:env(safe-area-inset-left,0px);padding-right:env(safe-area-inset-right,0px)}.lc-app-shell--horizon{grid-template-rows:auto auto 1fr auto}.lc-app-shell--horizon .lc-app-shell__footer{position:relative;z-index:1;grid-row:4;grid-column:1/-1;background-color:var(--color-land-3)}.lc-app-shell__footer:empty,.lc-app-shell__header:empty{display:none}.lc-app-shell__bottom-nav{display:contents}@media(max-width:1023.98px){.lc-app-shell:not(.lc-app-shell--horizon):has(>.lc-app-shell__bottom-nav:not(:empty)){padding-bottom:var(--_clearance)}.lc-app-shell--horizon:has(>.lc-app-shell__bottom-nav:not(:empty))>.lc-app-shell__horizon{--_lc-horizon-land: calc(var(--lc-horizon-land, 112px) + max(0px, var(--_lc-app-shell-bar, 72px) - 72px))}}@media(min-width:1024px){.lc-app-shell{grid-template-columns:var(--_nav-width) minmax(0,1fr);grid-template-areas:\"header header\" \"nav body\" \"end end\"}.lc-app-shell:has(>.lc-app-shell__nav:empty){grid-template-columns:minmax(0,1fr);grid-template-areas:\"header\" \"body\" \"end\"}.lc-app-shell__nav{grid-area:nav;display:block;min-width:0;position:sticky;top:0;align-self:start;max-height:100vh;max-height:100dvh;overflow-y:auto;padding-left:env(safe-area-inset-left,0px)}.lc-app-shell__nav:empty{display:none}.lc-app-shell:not(:has(>.lc-app-shell__nav:empty)) .lc-app-shell__body{padding-left:0}.lc-app-shell__bottom-nav{display:none}.lc-app-shell--nav-full-height:not(:has(>.lc-app-shell__nav:empty)){grid-template-areas:\"nav header\" \"nav body\" \"end end\"}.lc-app-shell--nav-full-height:not(:has(>.lc-app-shell__nav:empty))>.lc-app-shell__header{padding-left:0}.lc-app-shell--nav-full-height:not(:has(>.lc-app-shell__nav:empty))>.lc-app-shell__nav{grid-row:1/-1;grid-column:1;box-sizing:border-box;height:100vh;height:100dvh;max-height:none;z-index:2;padding-top:env(safe-area-inset-top,0px);display:grid;grid-template-columns:minmax(0,1fr);grid-template-rows:minmax(100%,auto)}.lc-app-shell--nav-full-height:not(:has(>.lc-app-shell__nav:empty))>.lc-app-shell__footer{grid-column:1/-1;padding-left:var(--_nav-width)}}@media(min-width:1280px){.lc-app-shell:has(.lc-app-page__aside)>.lc-app-shell__header{--_aside-width: var(--lc-app-page-aside-width, 360px);--_hairline: var(--color-hairline, var(--color-border));background:linear-gradient(var(--_hairline),var(--_hairline)) right calc(var(--_aside-width) - 1px) top/1px 100% no-repeat,linear-gradient(var(--color-background-low),var(--color-background-low)) right top/var(--_aside-width) 100% no-repeat}}@media(min-width:1440px){.lc-app-shell{--_nav-width: var(--lc-app-shell-nav-width, 248px)}.lc-app-shell:has(.lc-app-page__aside)>.lc-app-shell__header{--_aside-width: var(--lc-app-page-aside-width, 400px)}}@media(min-width:1920px){.lc-app-shell{--_nav-width: var(--lc-app-shell-nav-width, 280px)}.lc-app-shell:has(.lc-app-page__aside)>.lc-app-shell__header{--_aside-width: var(--lc-app-page-aside-width, 460px)}}@media(forced-colors:active){.lc-app-shell__header{background:none}}\n"],
95
128
  changeDetection: i0.ChangeDetectionStrategy.OnPush
96
129
  });
@@ -106,7 +139,7 @@ i0.ɵɵngDeclareClassMetadata({
106
139
  selector: "lc-app-shell",
107
140
  standalone: true,
108
141
  changeDetection: ChangeDetectionStrategy.OnPush,
109
- template: "<div #shell [class]=\"shellClasses()\">\n <div class=\"lc-app-shell__header\"><ng-content select=\"[shell-header]\" /></div>\n <div class=\"lc-app-shell__nav\"><ng-content select=\"[shell-nav]\" /></div>\n <div class=\"lc-app-shell__body\"><ng-content /></div>\n @if (horizon()) {\n <div class=\"lc-app-shell__horizon lc-horizon\" aria-hidden=\"true\"><ng-content select=\"[shell-horizon-figure]\" /></div>\n }\n <div class=\"lc-app-shell__footer\"><ng-content select=\"[shell-footer]\" /></div>\n <div #barSlot class=\"lc-app-shell__bottom-nav\"><ng-content select=\"[shell-bottom-nav]\" /></div>\n</div>\n",
142
+ template: "<div #shell [class]=\"shellClasses()\">\n <div #headerSlot class=\"lc-app-shell__header\"><ng-content select=\"[shell-header]\" /></div>\n <div class=\"lc-app-shell__nav\"><ng-content select=\"[shell-nav]\" /></div>\n <div class=\"lc-app-shell__body\"><ng-content /></div>\n @if (horizon()) {\n <div class=\"lc-app-shell__horizon lc-horizon\" aria-hidden=\"true\"><ng-content select=\"[shell-horizon-figure]\" /></div>\n }\n <div class=\"lc-app-shell__footer\"><ng-content select=\"[shell-footer]\" /></div>\n <div #barSlot class=\"lc-app-shell__bottom-nav\"><ng-content select=\"[shell-bottom-nav]\" /></div>\n</div>\n",
110
143
  styles: [":host{display:block}.lc-app-shell{--_nav-width: var(--lc-app-shell-nav-width, 240px);--_clearance: var( --lc-app-shell-bottom-clearance, max( calc(112px + env(safe-area-inset-bottom, 0px)) , calc(var(--_lc-app-shell-bar, 72px) + 40px + env(safe-area-inset-bottom, 0px))) );display:grid;grid-template-columns:minmax(0,1fr);grid-template-rows:auto auto 1fr;grid-template-areas:\"header\" \"body\" \"end\";min-height:100vh;min-height:100dvh;box-sizing:border-box;background-color:var(--lc-app-shell-bg, var(--color-background));background-image:var(--lc-app-shell-bg-image, var(--app-background-image, none))}.lc-app-shell__header{grid-area:header;min-width:0;padding-top:env(safe-area-inset-top,0px);padding-left:env(safe-area-inset-left,0px);padding-right:env(safe-area-inset-right,0px)}.lc-app-shell__body{grid-area:body;min-width:0;padding-left:env(safe-area-inset-left,0px);padding-right:env(safe-area-inset-right,0px)}.lc-app-shell__nav{display:none}.lc-app-shell__horizon{grid-area:end;min-width:0}.lc-app-shell__footer{grid-area:end;align-self:end;min-width:0;padding-left:env(safe-area-inset-left,0px);padding-right:env(safe-area-inset-right,0px)}.lc-app-shell--horizon{grid-template-rows:auto auto 1fr auto}.lc-app-shell--horizon .lc-app-shell__footer{position:relative;z-index:1;grid-row:4;grid-column:1/-1;background-color:var(--color-land-3)}.lc-app-shell__footer:empty,.lc-app-shell__header:empty{display:none}.lc-app-shell__bottom-nav{display:contents}@media(max-width:1023.98px){.lc-app-shell:not(.lc-app-shell--horizon):has(>.lc-app-shell__bottom-nav:not(:empty)){padding-bottom:var(--_clearance)}.lc-app-shell--horizon:has(>.lc-app-shell__bottom-nav:not(:empty))>.lc-app-shell__horizon{--_lc-horizon-land: calc(var(--lc-horizon-land, 112px) + max(0px, var(--_lc-app-shell-bar, 72px) - 72px))}}@media(min-width:1024px){.lc-app-shell{grid-template-columns:var(--_nav-width) minmax(0,1fr);grid-template-areas:\"header header\" \"nav body\" \"end end\"}.lc-app-shell:has(>.lc-app-shell__nav:empty){grid-template-columns:minmax(0,1fr);grid-template-areas:\"header\" \"body\" \"end\"}.lc-app-shell__nav{grid-area:nav;display:block;min-width:0;position:sticky;top:0;align-self:start;max-height:100vh;max-height:100dvh;overflow-y:auto;padding-left:env(safe-area-inset-left,0px)}.lc-app-shell__nav:empty{display:none}.lc-app-shell:not(:has(>.lc-app-shell__nav:empty)) .lc-app-shell__body{padding-left:0}.lc-app-shell__bottom-nav{display:none}.lc-app-shell--nav-full-height:not(:has(>.lc-app-shell__nav:empty)){grid-template-areas:\"nav header\" \"nav body\" \"end end\"}.lc-app-shell--nav-full-height:not(:has(>.lc-app-shell__nav:empty))>.lc-app-shell__header{padding-left:0}.lc-app-shell--nav-full-height:not(:has(>.lc-app-shell__nav:empty))>.lc-app-shell__nav{grid-row:1/-1;grid-column:1;box-sizing:border-box;height:100vh;height:100dvh;max-height:none;z-index:2;padding-top:env(safe-area-inset-top,0px);display:grid;grid-template-columns:minmax(0,1fr);grid-template-rows:minmax(100%,auto)}.lc-app-shell--nav-full-height:not(:has(>.lc-app-shell__nav:empty))>.lc-app-shell__footer{grid-column:1/-1;padding-left:var(--_nav-width)}}@media(min-width:1280px){.lc-app-shell:has(.lc-app-page__aside)>.lc-app-shell__header{--_aside-width: var(--lc-app-page-aside-width, 360px);--_hairline: var(--color-hairline, var(--color-border));background:linear-gradient(var(--_hairline),var(--_hairline)) right calc(var(--_aside-width) - 1px) top/1px 100% no-repeat,linear-gradient(var(--color-background-low),var(--color-background-low)) right top/var(--_aside-width) 100% no-repeat}}@media(min-width:1440px){.lc-app-shell{--_nav-width: var(--lc-app-shell-nav-width, 248px)}.lc-app-shell:has(.lc-app-page__aside)>.lc-app-shell__header{--_aside-width: var(--lc-app-page-aside-width, 400px)}}@media(min-width:1920px){.lc-app-shell{--_nav-width: var(--lc-app-shell-nav-width, 280px)}.lc-app-shell:has(.lc-app-page__aside)>.lc-app-shell__header{--_aside-width: var(--lc-app-page-aside-width, 460px)}}@media(forced-colors:active){.lc-app-shell__header{background:none}}\n"]
111
144
  }]
112
145
  }],
@@ -132,6 +165,10 @@ i0.ɵɵngDeclareClassMetadata({
132
165
  type: i0.ViewChild,
133
166
  args: ["shell", { isSignal: true }]
134
167
  }],
168
+ headerSlot: [{
169
+ type: i0.ViewChild,
170
+ args: ["headerSlot", { isSignal: true }]
171
+ }],
135
172
  barSlot: [{
136
173
  type: i0.ViewChild,
137
174
  args: ["barSlot", { isSignal: true }]
@@ -146,10 +183,21 @@ var AppPageComponent = class AppPageComponent {
146
183
  busy = input(false, ...ngDevMode ? [{ debugName: "busy" }] : /* istanbul ignore next */ []);
147
184
  paddingX = input("default", ...ngDevMode ? [{ debugName: "paddingX" }] : /* istanbul ignore next */ []);
148
185
  paddingTop = input("default", ...ngDevMode ? [{ debugName: "paddingTop" }] : /* istanbul ignore next */ []);
186
+ reserveAside = input(false, ...ngDevMode ? [{ debugName: "reserveAside" }] : /* istanbul ignore next */ []);
187
+ contentWidth = input("default", ...ngDevMode ? [{ debugName: "contentWidth" }] : /* istanbul ignore next */ []);
149
188
  hasAside = computed(() => !!(this.asideLabelledby() || this.asideAriaLabel()), ...ngDevMode ? [{ debugName: "hasAside" }] : /* istanbul ignore next */ []);
189
+ wide = computed(() => this.contentWidth() === "wide" && !this.hasAside(), ...ngDevMode ? [{ debugName: "wide" }] : /* istanbul ignore next */ []);
190
+ reserved = computed(() => this.reserveAside() && !this.hasAside() && !this.wide(), ...ngDevMode ? [{ debugName: "reserved" }] : /* istanbul ignore next */ []);
191
+ wideMax = computed(() => {
192
+ if (!this.wide()) return null;
193
+ const max = this.contentMaxWidth();
194
+ if (max === "880px") return null;
195
+ return max === "none" ? "100vw" : max;
196
+ }, ...ngDevMode ? [{ debugName: "wideMax" }] : /* istanbul ignore next */ []);
150
197
  pageClasses = computed(() => {
151
198
  const classes = ["lc-app-page"];
152
- if (this.hasAside()) classes.push("lc-app-page--aside");
199
+ if (this.hasAside() || this.reserveAside() || this.wide()) classes.push("lc-app-page--aside");
200
+ if (this.wide()) classes.push("lc-app-page--wide");
153
201
  if (this.paddingX() === "header") classes.push("lc-app-page--pad-x-header");
154
202
  if (this.paddingTop() !== "default") classes.push(`lc-app-page--pad-top-${this.paddingTop()}`);
155
203
  return classes.join(" ");
@@ -217,11 +265,25 @@ var AppPageComponent = class AppPageComponent {
217
265
  isSignal: true,
218
266
  isRequired: false,
219
267
  transformFunction: null
268
+ },
269
+ reserveAside: {
270
+ classPropertyName: "reserveAside",
271
+ publicName: "reserveAside",
272
+ isSignal: true,
273
+ isRequired: false,
274
+ transformFunction: null
275
+ },
276
+ contentWidth: {
277
+ classPropertyName: "contentWidth",
278
+ publicName: "contentWidth",
279
+ isSignal: true,
280
+ isRequired: false,
281
+ transformFunction: null
220
282
  }
221
283
  },
222
284
  ngImport: i0,
223
- template: "<div [class]=\"pageClasses()\" [style.--lc-app-page-content-max]=\"contentMaxWidth()\">\n <main class=\"lc-app-page__main\" [id]=\"mainId()\" [attr.aria-busy]=\"busy() ? 'true' : null\">\n <div class=\"lc-app-page__content\"><ng-content /></div>\n </main>\n @if (hasAside()) {\n <aside\n class=\"lc-app-page__aside\"\n [attr.aria-labelledby]=\"asideLabelledby() || null\"\n [attr.aria-label]=\"asideLabelledby() ? null : asideAriaLabel()\"\n >\n <ng-content select=\"[page-aside]\" />\n </aside>\n }\n</div>\n",
224
- styles: [":host{display:block;min-width:0}.lc-app-page{--_pad-x: var(--lc-app-page-padding-x, 24px);--_pad-top: var(--lc-app-page-padding-top, 24px);--_gap: var(--lc-app-page-gap, 24px);--_aside-width: var(--lc-app-page-aside-width, 360px);display:grid;grid-template-columns:minmax(0,1fr);min-height:100%}.lc-app-page__main{display:block;min-width:0;padding:var(--_pad-top) var(--_pad-x) 16px}.lc-app-page__content{display:flex;flex-direction:column;gap:var(--_gap);max-width:var(--lc-app-page-content-max, 880px);margin-inline:auto}.lc-app-page__aside{display:none}@media(min-width:640px){.lc-app-page{--_pad-x: var(--lc-app-page-padding-x, 32px);--_pad-top: var(--lc-app-page-padding-top, 32px)}}@media(min-width:1024px){.lc-app-page{--_pad-x: var(--lc-app-page-padding-x, 48px);--_pad-top: var(--lc-app-page-padding-top, 48px);--_gap: var(--lc-app-page-gap, 40px)}.lc-app-page__main{padding-bottom:32px}}@media(min-width:1280px){.lc-app-page{--_pad-x: var(--lc-app-page-padding-x, 56px);--_pad-top: var(--lc-app-page-padding-top, 56px)}.lc-app-page--aside{grid-template-columns:minmax(0,1fr) var(--_aside-width)}.lc-app-page__aside{display:block;min-width:0;box-sizing:border-box;padding:max(16px,var(--_pad-top) - 32px) 40px 40px;background:linear-gradient(180deg,var(--color-background-low),transparent);border-left:1px solid var(--color-hairline, var(--color-border));border-image:linear-gradient(180deg,var(--color-hairline, var(--color-border)) 60%,transparent) 1}}@media(min-width:1440px){.lc-app-page{--_pad-x: var(--lc-app-page-padding-x, 72px);--_pad-top: var(--lc-app-page-padding-top, 72px);--_aside-width: var(--lc-app-page-aside-width, 400px)}}@media(min-width:1920px){.lc-app-page{--_pad-x: var(--lc-app-page-padding-x, 96px);--_pad-top: var(--lc-app-page-padding-top, 112px);--_aside-width: var(--lc-app-page-aside-width, 460px)}}.lc-app-page.lc-app-page--pad-x-header{--_pad-x: var(--lc-app-page-padding-x, var(--lc-density-padding-lg, var(--spacing-6)))}@media(max-width:768px){.lc-app-page.lc-app-page--pad-x-header{--_pad-x: var(--lc-app-page-padding-x, var(--lc-density-padding-md, var(--spacing-4)))}}.lc-app-page.lc-app-page--pad-top-none{--_pad-top: var(--lc-app-page-padding-top, 0px)}.lc-app-page.lc-app-page--pad-top-sm{--_pad-top: var(--lc-app-page-padding-top, var(--spacing-2))}.lc-app-page.lc-app-page--pad-top-md{--_pad-top: var(--lc-app-page-padding-top, var(--spacing-4))}@media(forced-colors:active){.lc-app-page__aside{background:none;border-image:none;border-left-color:CanvasText}}\n"],
285
+ template: "<div [class]=\"pageClasses()\" [style.--lc-app-page-content-max]=\"contentMaxWidth()\" [style.--_lc-app-page-wide-max]=\"wideMax()\">\n <main class=\"lc-app-page__main\" [id]=\"mainId()\" [attr.aria-busy]=\"busy() ? 'true' : null\">\n <div class=\"lc-app-page__content\"><ng-content /></div>\n </main>\n <!-- One outer block, so a page without a right column keeps 3.27.2's single\n anchor (an @else branch adds one); the reserved column (AS-35) is empty,\n aria-hidden and no landmark. -->\n @if (hasAside() || reserved()) {\n @if (hasAside()) {\n <aside\n class=\"lc-app-page__aside\"\n [attr.aria-labelledby]=\"asideLabelledby() || null\"\n [attr.aria-label]=\"asideLabelledby() ? null : asideAriaLabel()\"\n >\n <ng-content select=\"[page-aside]\" />\n </aside>\n } @else {<div class=\"lc-app-page__aside lc-app-page__aside--reserved\" aria-hidden=\"true\"></div>}\n }\n</div>\n",
286
+ styles: [":host{display:block;min-width:0}.lc-app-page{--_pad-x: var(--lc-app-page-padding-x, 24px);--_pad-top: var(--lc-app-page-padding-top, 24px);--_gap: var(--lc-app-page-gap, 24px);--_aside-width: var(--lc-app-page-aside-width, 360px);display:grid;grid-template-columns:minmax(0,1fr);min-height:100%}.lc-app-page__main{display:block;min-width:0;padding:var(--_pad-top) var(--_pad-x) 16px}.lc-app-page__content{display:flex;flex-direction:column;gap:var(--_gap);max-width:var(--lc-app-page-content-max, 880px);margin-inline:auto}.lc-app-page__aside{display:none}@media(min-width:640px){.lc-app-page{--_pad-x: var(--lc-app-page-padding-x, 32px);--_pad-top: var(--lc-app-page-padding-top, 32px)}}@media(min-width:1024px){.lc-app-page{--_pad-x: var(--lc-app-page-padding-x, 48px);--_pad-top: var(--lc-app-page-padding-top, 48px);--_gap: var(--lc-app-page-gap, 40px)}.lc-app-page__main{padding-bottom:32px}}@media(min-width:1280px){.lc-app-page{--_pad-x: var(--lc-app-page-padding-x, 56px);--_pad-top: var(--lc-app-page-padding-top, 56px)}.lc-app-page--aside{grid-template-columns:minmax(0,1fr) var(--_aside-width)}.lc-app-page__aside{display:block;min-width:0;box-sizing:border-box;padding:max(16px,var(--_pad-top) - 32px) 40px 40px;background:linear-gradient(180deg,var(--color-background-low),transparent);border-left:1px solid var(--color-hairline, var(--color-border));border-image:linear-gradient(180deg,var(--color-hairline, var(--color-border)) 60%,transparent) 1}}@media(min-width:1440px){.lc-app-page{--_pad-x: var(--lc-app-page-padding-x, 72px);--_pad-top: var(--lc-app-page-padding-top, 72px);--_aside-width: var(--lc-app-page-aside-width, 400px)}}@media(min-width:1920px){.lc-app-page{--_pad-x: var(--lc-app-page-padding-x, 96px);--_pad-top: var(--lc-app-page-padding-top, 112px);--_aside-width: var(--lc-app-page-aside-width, 460px)}}.lc-app-page.lc-app-page--pad-x-header{--_pad-x: var(--lc-app-page-padding-x, var(--lc-density-padding-lg, var(--spacing-6)))}@media(max-width:768px){.lc-app-page.lc-app-page--pad-x-header{--_pad-x: var(--lc-app-page-padding-x, var(--lc-density-padding-md, var(--spacing-4)))}}.lc-app-page.lc-app-page--pad-top-none{--_pad-top: var(--lc-app-page-padding-top, 0px)}.lc-app-page.lc-app-page--pad-top-sm{--_pad-top: var(--lc-app-page-padding-top, var(--spacing-2))}.lc-app-page.lc-app-page--pad-top-md{--_pad-top: var(--lc-app-page-padding-top, var(--spacing-4))}@media(forced-colors:active){.lc-app-page__aside{background:none;border-image:none;border-left-color:CanvasText}}@media(min-width:1280px){:host ::ng-deep .lc-app-page--wide>.lc-app-page__main>.lc-app-page__content>[page-wide]{box-sizing:border-box;width:min(var(--_lc-app-page-wide-max, 928px),100% + var(--_aside-width));max-width:none}}\n"],
225
287
  changeDetection: i0.ChangeDetectionStrategy.OnPush
226
288
  });
227
289
  };
@@ -236,8 +298,8 @@ i0.ɵɵngDeclareClassMetadata({
236
298
  selector: "lc-app-page",
237
299
  standalone: true,
238
300
  changeDetection: ChangeDetectionStrategy.OnPush,
239
- template: "<div [class]=\"pageClasses()\" [style.--lc-app-page-content-max]=\"contentMaxWidth()\">\n <main class=\"lc-app-page__main\" [id]=\"mainId()\" [attr.aria-busy]=\"busy() ? 'true' : null\">\n <div class=\"lc-app-page__content\"><ng-content /></div>\n </main>\n @if (hasAside()) {\n <aside\n class=\"lc-app-page__aside\"\n [attr.aria-labelledby]=\"asideLabelledby() || null\"\n [attr.aria-label]=\"asideLabelledby() ? null : asideAriaLabel()\"\n >\n <ng-content select=\"[page-aside]\" />\n </aside>\n }\n</div>\n",
240
- styles: [":host{display:block;min-width:0}.lc-app-page{--_pad-x: var(--lc-app-page-padding-x, 24px);--_pad-top: var(--lc-app-page-padding-top, 24px);--_gap: var(--lc-app-page-gap, 24px);--_aside-width: var(--lc-app-page-aside-width, 360px);display:grid;grid-template-columns:minmax(0,1fr);min-height:100%}.lc-app-page__main{display:block;min-width:0;padding:var(--_pad-top) var(--_pad-x) 16px}.lc-app-page__content{display:flex;flex-direction:column;gap:var(--_gap);max-width:var(--lc-app-page-content-max, 880px);margin-inline:auto}.lc-app-page__aside{display:none}@media(min-width:640px){.lc-app-page{--_pad-x: var(--lc-app-page-padding-x, 32px);--_pad-top: var(--lc-app-page-padding-top, 32px)}}@media(min-width:1024px){.lc-app-page{--_pad-x: var(--lc-app-page-padding-x, 48px);--_pad-top: var(--lc-app-page-padding-top, 48px);--_gap: var(--lc-app-page-gap, 40px)}.lc-app-page__main{padding-bottom:32px}}@media(min-width:1280px){.lc-app-page{--_pad-x: var(--lc-app-page-padding-x, 56px);--_pad-top: var(--lc-app-page-padding-top, 56px)}.lc-app-page--aside{grid-template-columns:minmax(0,1fr) var(--_aside-width)}.lc-app-page__aside{display:block;min-width:0;box-sizing:border-box;padding:max(16px,var(--_pad-top) - 32px) 40px 40px;background:linear-gradient(180deg,var(--color-background-low),transparent);border-left:1px solid var(--color-hairline, var(--color-border));border-image:linear-gradient(180deg,var(--color-hairline, var(--color-border)) 60%,transparent) 1}}@media(min-width:1440px){.lc-app-page{--_pad-x: var(--lc-app-page-padding-x, 72px);--_pad-top: var(--lc-app-page-padding-top, 72px);--_aside-width: var(--lc-app-page-aside-width, 400px)}}@media(min-width:1920px){.lc-app-page{--_pad-x: var(--lc-app-page-padding-x, 96px);--_pad-top: var(--lc-app-page-padding-top, 112px);--_aside-width: var(--lc-app-page-aside-width, 460px)}}.lc-app-page.lc-app-page--pad-x-header{--_pad-x: var(--lc-app-page-padding-x, var(--lc-density-padding-lg, var(--spacing-6)))}@media(max-width:768px){.lc-app-page.lc-app-page--pad-x-header{--_pad-x: var(--lc-app-page-padding-x, var(--lc-density-padding-md, var(--spacing-4)))}}.lc-app-page.lc-app-page--pad-top-none{--_pad-top: var(--lc-app-page-padding-top, 0px)}.lc-app-page.lc-app-page--pad-top-sm{--_pad-top: var(--lc-app-page-padding-top, var(--spacing-2))}.lc-app-page.lc-app-page--pad-top-md{--_pad-top: var(--lc-app-page-padding-top, var(--spacing-4))}@media(forced-colors:active){.lc-app-page__aside{background:none;border-image:none;border-left-color:CanvasText}}\n"]
301
+ template: "<div [class]=\"pageClasses()\" [style.--lc-app-page-content-max]=\"contentMaxWidth()\" [style.--_lc-app-page-wide-max]=\"wideMax()\">\n <main class=\"lc-app-page__main\" [id]=\"mainId()\" [attr.aria-busy]=\"busy() ? 'true' : null\">\n <div class=\"lc-app-page__content\"><ng-content /></div>\n </main>\n <!-- One outer block, so a page without a right column keeps 3.27.2's single\n anchor (an @else branch adds one); the reserved column (AS-35) is empty,\n aria-hidden and no landmark. -->\n @if (hasAside() || reserved()) {\n @if (hasAside()) {\n <aside\n class=\"lc-app-page__aside\"\n [attr.aria-labelledby]=\"asideLabelledby() || null\"\n [attr.aria-label]=\"asideLabelledby() ? null : asideAriaLabel()\"\n >\n <ng-content select=\"[page-aside]\" />\n </aside>\n } @else {<div class=\"lc-app-page__aside lc-app-page__aside--reserved\" aria-hidden=\"true\"></div>}\n }\n</div>\n",
302
+ styles: [":host{display:block;min-width:0}.lc-app-page{--_pad-x: var(--lc-app-page-padding-x, 24px);--_pad-top: var(--lc-app-page-padding-top, 24px);--_gap: var(--lc-app-page-gap, 24px);--_aside-width: var(--lc-app-page-aside-width, 360px);display:grid;grid-template-columns:minmax(0,1fr);min-height:100%}.lc-app-page__main{display:block;min-width:0;padding:var(--_pad-top) var(--_pad-x) 16px}.lc-app-page__content{display:flex;flex-direction:column;gap:var(--_gap);max-width:var(--lc-app-page-content-max, 880px);margin-inline:auto}.lc-app-page__aside{display:none}@media(min-width:640px){.lc-app-page{--_pad-x: var(--lc-app-page-padding-x, 32px);--_pad-top: var(--lc-app-page-padding-top, 32px)}}@media(min-width:1024px){.lc-app-page{--_pad-x: var(--lc-app-page-padding-x, 48px);--_pad-top: var(--lc-app-page-padding-top, 48px);--_gap: var(--lc-app-page-gap, 40px)}.lc-app-page__main{padding-bottom:32px}}@media(min-width:1280px){.lc-app-page{--_pad-x: var(--lc-app-page-padding-x, 56px);--_pad-top: var(--lc-app-page-padding-top, 56px)}.lc-app-page--aside{grid-template-columns:minmax(0,1fr) var(--_aside-width)}.lc-app-page__aside{display:block;min-width:0;box-sizing:border-box;padding:max(16px,var(--_pad-top) - 32px) 40px 40px;background:linear-gradient(180deg,var(--color-background-low),transparent);border-left:1px solid var(--color-hairline, var(--color-border));border-image:linear-gradient(180deg,var(--color-hairline, var(--color-border)) 60%,transparent) 1}}@media(min-width:1440px){.lc-app-page{--_pad-x: var(--lc-app-page-padding-x, 72px);--_pad-top: var(--lc-app-page-padding-top, 72px);--_aside-width: var(--lc-app-page-aside-width, 400px)}}@media(min-width:1920px){.lc-app-page{--_pad-x: var(--lc-app-page-padding-x, 96px);--_pad-top: var(--lc-app-page-padding-top, 112px);--_aside-width: var(--lc-app-page-aside-width, 460px)}}.lc-app-page.lc-app-page--pad-x-header{--_pad-x: var(--lc-app-page-padding-x, var(--lc-density-padding-lg, var(--spacing-6)))}@media(max-width:768px){.lc-app-page.lc-app-page--pad-x-header{--_pad-x: var(--lc-app-page-padding-x, var(--lc-density-padding-md, var(--spacing-4)))}}.lc-app-page.lc-app-page--pad-top-none{--_pad-top: var(--lc-app-page-padding-top, 0px)}.lc-app-page.lc-app-page--pad-top-sm{--_pad-top: var(--lc-app-page-padding-top, var(--spacing-2))}.lc-app-page.lc-app-page--pad-top-md{--_pad-top: var(--lc-app-page-padding-top, var(--spacing-4))}@media(forced-colors:active){.lc-app-page__aside{background:none;border-image:none;border-left-color:CanvasText}}@media(min-width:1280px){:host ::ng-deep .lc-app-page--wide>.lc-app-page__main>.lc-app-page__content>[page-wide]{box-sizing:border-box;width:min(var(--_lc-app-page-wide-max, 928px),100% + var(--_aside-width));max-width:none}}\n"]
241
303
  }]
242
304
  }],
243
305
  propDecorators: {
@@ -296,6 +358,22 @@ i0.ɵɵngDeclareClassMetadata({
296
358
  alias: "paddingTop",
297
359
  required: false
298
360
  }]
361
+ }],
362
+ reserveAside: [{
363
+ type: i0.Input,
364
+ args: [{
365
+ isSignal: true,
366
+ alias: "reserveAside",
367
+ required: false
368
+ }]
369
+ }],
370
+ contentWidth: [{
371
+ type: i0.Input,
372
+ args: [{
373
+ isSignal: true,
374
+ alias: "contentWidth",
375
+ required: false
376
+ }]
299
377
  }]
300
378
  }
301
379
  });
@@ -1 +1 @@
1
- {"version":3,"file":"lifecorner-angular-ui-kit-app-shell.mjs","names":[],"sources":["../../../../libs/angular-ui-kit/src/lib/app-shell/app-shell.component.ts","../../../../libs/angular-ui-kit/src/lib/app-shell/app-shell.component.html","../../../../libs/angular-ui-kit/src/lib/app-shell/app-page.component.ts","../../../../libs/angular-ui-kit/src/lib/app-shell/app-page.component.html"],"sourcesContent":["import {\n afterNextRender,\n ChangeDetectionStrategy,\n Component,\n computed,\n DestroyRef,\n ElementRef,\n inject,\n input,\n viewChild,\n} from '@angular/core';\n\n/**\n * Private custom property the shell writes on `.lc-app-shell` in the browser:\n * the bar's content height. Its CSS fallback is 72 px (4 + 64 + 4 at 100 % text).\n */\nconst BAR_VAR = '--_lc-app-shell-bar';\n\n/**\n * Where the side navigation sits from 1024 px: `'below-header'` (the header\n * spans the full width, the nav starts below it) or `'full-height'` (the nav\n * runs from the top to the bottom of the viewport, the header beside it).\n */\nexport type AppShellNavPlacement = 'below-header' | 'full-height';\n\n/**\n * App shell: the frame around every page of an app — header, side navigation,\n * page, bottom navigation bar, footer and the horizon — laid out for phones\n * first, with the DOCUMENT scrolling (not an inner container), so the iOS\n * status-bar tap, address-bar collapse and pull-to-refresh keep working.\n *\n * Slots (content projection by attribute):\n * - `[shell-header]` — the `lc-header`; scrolls away with the page. Gets the\n * top, left and right safe-area insets.\n * - `[shell-nav]` — the docked side navigation (`lc-sidenav mode=\"docked\"\n * [isOpen]=\"true\" width=\"100%\" [mobileBreakpoint]=\"0\"`), shown from\n * 1024 px in a column of 240 px (248 from 1440, 280 from 1920; override\n * with `--lc-app-shell-nav-width`) and sticky once the header has gone.\n * An empty slot takes no column.\n * - default — the page, usually an `lc-app-page` (or a `<router-outlet>`\n * whose pages use one). It spans to the window's right edge, so a page's\n * right column docks there.\n * - `[shell-bottom-nav]` — the `lc-bottom-nav`, shown below 1024 px. The shell\n * reserves its real height at the end of the page: at least 112 px (16 + 72\n * + 24) plus the safe-area inset, more when the bar grows with the text size\n * (measured in the browser; `--lc-app-shell-bottom-clearance` overrides it),\n * so it never covers content. With the horizon, the bar rests on the land\n * instead, and the land grows with a taller bar (3.10.1, AS-31).\n * - `[shell-footer]` — e.g. a compact `lc-footer`; after the page, or with\n * `horizon` in a row of its own below the horizon, painted in the land's\n * colour (`--color-land-3`): the land grows by the footer's height, so\n * `--lc-horizon-land` stays the land above the footer and no page overrides\n * it (3.9, LK-12).\n * - `[shell-horizon-figure]` — Edu (or any decorative figure) on the horizon\n * line, left of the sun: `lc-character`, `<img>`, `<picture>` or an element\n * holding an inline `<svg>`. Projected as a direct child of `.lc-horizon`,\n * sized and placed by the horizon (`--lc-horizon-figure-size` / `-gap`).\n * Decorative: the horizon is `aria-hidden`, so give an `<img>` `alt=\"\"` and\n * nothing focusable. Shown only when `horizon` is on (3.9, AS-29).\n *\n * `horizon` closes the page with the \"Weite\" horizon (`.lc-horizon` from the\n * kit's styles): full-bleed, below the side navigation and the page, filling\n * the rest of the screen — on Today, the sign-in pages and the shell pages.\n *\n * `navPlacement=\"full-height\"` (3.14) runs the nav column from the top to the\n * bottom of the viewport (sticky, 100dvh) with the header beside it, from\n * 1024 px; below 1024 px it renders like the default. The DOM and tab order\n * stay header → nav → page → footer, so in full-height the header's controls\n * come before a brand at the top of the nav (banner, then navigation, then\n * content). The land and the footer run under the nav; the footer's content\n * starts at the nav width.\n *\n * CSS hooks (set them on `lc-app-shell` or any ancestor):\n * - `--lc-app-shell-nav-width` — the nav column from 1024 px. Default\n * `240px` (`248px` from 1440, `280px` from 1920).\n * - `--lc-app-shell-bottom-clearance` — the space kept free for the bottom\n * bar below 1024 px. Default: the bar's height + 40 px + the inset, at\n * least `112px` + the inset.\n * - `--lc-app-shell-bg` — the page colour behind everything (the sky).\n * Default `var(--color-background)`.\n * - `--lc-app-shell-bg-image` — a layer over the page colour. Default\n * `var(--app-background-image, none)`. A tint, for example:\n * `linear-gradient(to bottom, var(--color-land-1), var(--color-land-2), var(--color-land-3))`.\n * The horizon's land still paints over it.\n *\n * Needs `<meta name=\"viewport\" content=\"width=device-width, initial-scale=1,\n * viewport-fit=cover\">` for the safe-area insets. Breakpoints are fixed\n * (1024 px side navigation, 1440 / 1920 px widths), so the layout works\n * before JavaScript runs (SSR, prerendering).\n *\n * @example\n * ```html\n * <lc-app-shell [horizon]=\"isToday()\">\n * <lc-header shell-header variant=\"transparent\" [sticky]=\"false\" … />\n * <lc-sidenav shell-nav mode=\"docked\" [isOpen]=\"true\" width=\"100%\" [mobileBreakpoint]=\"0\"\n * variant=\"transparent\" [items]=\"nav\" [activeRoute]=\"url()\" />\n * <router-outlet />\n * <lc-bottom-nav shell-bottom-nav variant=\"floating\" [items]=\"nav\" [activeRoute]=\"url()\" />\n * </lc-app-shell>\n * ```\n */\n@Component({\n selector: 'lc-app-shell',\n standalone: true,\n templateUrl: './app-shell.component.html',\n styleUrl: './app-shell.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class AppShellComponent {\n /**\n * Close the page with the horizon (`.lc-horizon`): full width, below the\n * side navigation and the page, filling the rest of the screen; the footer\n * (in a row of its own, which adds to the land) and the floating bar rest\n * on its land, and `[shell-horizon-figure]` stands on its line.\n * @default false\n */\n readonly horizon = input(false);\n\n /**\n * Where the side navigation sits from 1024 px. `'below-header'`: the header\n * spans the full width and the nav starts below it. `'full-height'`: the nav\n * runs from the top to the bottom of the viewport, with the header beside\n * it. Below 1024 px both render the same. The DOM and tab order don't change\n * (header, nav, page). CSS only, so it holds before JavaScript runs.\n * `'full-height'` expects a brand block at the top of the rail\n * (`lc-sidenav brandName` or `showLogo`, with a `logoSize` that matches the\n * header's `size`, e.g. both `md`: 64 px) and the header's `showLogo` off.\n * @default 'below-header'\n */\n readonly navPlacement = input<AppShellNavPlacement>('below-header');\n\n protected readonly shellClasses = computed(() => {\n const classes = ['lc-app-shell'];\n if (this.horizon()) classes.push('lc-app-shell--horizon');\n if (this.navPlacement() === 'full-height') classes.push('lc-app-shell--nav-full-height');\n return classes.join(' ');\n });\n\n private readonly shell = viewChild.required<ElementRef<HTMLElement>>('shell');\n private readonly barSlot = viewChild.required<ElementRef<HTMLElement>>('barSlot');\n\n constructor() {\n const destroyRef = inject(DestroyRef);\n // Browser only (afterNextRender never runs on the server): follow the\n // bar's content height, so the clearance and the land grow with a bar\n // that grows with the text size (AS-31). Without ResizeObserver, and\n // before this runs, the CSS fallback (72 px → 112 px clearance) holds.\n afterNextRender(() => {\n if (typeof ResizeObserver === 'undefined') return;\n const shell = this.shell().nativeElement;\n const slot = this.barSlot().nativeElement;\n const clear = () => shell.style.removeProperty(BAR_VAR);\n const sizes = new ResizeObserver((entries) => {\n const entry = entries[entries.length - 1];\n const height = entry.contentBoxSize?.[0]?.blockSize ?? entry.contentRect.height;\n // 0 when the bar is hidden (from 1024 px).\n if (height > 0) shell.style.setProperty(BAR_VAR, `${height}px`);\n else clear();\n });\n let bar: Element | null = null;\n // The bar may come later (`@if (items())` around it) or go again.\n const pick = () => {\n const next = slot.querySelector('.lc-bottom-nav') ?? slot.firstElementChild;\n if (next === bar) return;\n if (bar) sizes.unobserve(bar);\n bar = next;\n if (bar) sizes.observe(bar);\n else clear();\n };\n pick();\n const changes = typeof MutationObserver === 'undefined' ? null : new MutationObserver(pick);\n changes?.observe(slot, { childList: true, subtree: true });\n destroyRef.onDestroy(() => {\n sizes.disconnect();\n changes?.disconnect();\n });\n });\n }\n}\n","<div #shell [class]=\"shellClasses()\">\n <div class=\"lc-app-shell__header\"><ng-content select=\"[shell-header]\" /></div>\n <div class=\"lc-app-shell__nav\"><ng-content select=\"[shell-nav]\" /></div>\n <div class=\"lc-app-shell__body\"><ng-content /></div>\n @if (horizon()) {\n <div class=\"lc-app-shell__horizon lc-horizon\" aria-hidden=\"true\"><ng-content select=\"[shell-horizon-figure]\" /></div>\n }\n <div class=\"lc-app-shell__footer\"><ng-content select=\"[shell-footer]\" /></div>\n <div #barSlot class=\"lc-app-shell__bottom-nav\"><ng-content select=\"[shell-bottom-nav]\" /></div>\n</div>\n","import { ChangeDetectionStrategy, Component, computed, input } from '@angular/core';\n\n/**\n * Horizontal padding of `lc-app-page` (3.15).\n * - `default`: 24 · 32 · 48 · 56 · 72 · 96 px from 0 · 640 · 1024 · 1280 · 1440 · 1920 px.\n * - `header`: `lc-header`'s padding (16 px up to 768 px, 24 px above), so the\n * content lines up with the header title and the user menu.\n */\nexport type AppPagePaddingX = 'default' | 'header';\n\n/**\n * Space above `lc-app-page`'s content (3.15).\n * - `default`: 24 · 32 · 48 · 56 · 72 · 112 px by width.\n * - `none` 0, `sm` 8 px, `md` 16 px at every width.\n */\nexport type AppPagePaddingTop = 'default' | 'none' | 'sm' | 'md';\n\n/**\n * A page inside `lc-app-shell`: the `<main>` landmark with the page's content\n * centred at a reading width, and an optional right column docked to the\n * window's right edge (LK-6).\n *\n * - `<main [id]=\"mainId\">` holds the default slot as a column (24 px apart,\n * 40 px from 1024 px), centred and capped at `contentMaxWidth` (880 px of\n * content). Side padding 24 · 32 · 48 · 56 · 72 · 96 px at 360 · 640 ·\n * 1024 · 1280 · 1440 · 1920 px.\n * - `[page-aside]` is the right column: an `<aside>` AFTER `<main>` in the DOM,\n * shown from 1280 px at 360 px (400 from 1440, 460 from 1920; override\n * with `--lc-app-page-aside-width`), with a tint and a hairline that fade\n * downwards; inside `lc-app-shell` they start at the top of the window,\n * behind a transparent header. Below 1280 px it is hidden: show the page's narrow equivalent\n * inside main instead (e.g. a member row). It renders only with an\n * accessible name — `asideLabelledby` (the id of its heading) or\n * `asideAriaLabel`.\n * - `busy` marks the page as loading: `aria-busy=\"true\"` on `<main>` while a\n * skeleton stands in for the content (AS-12). No visual change.\n * - `paddingX=\"header\"` lines the content up with `lc-header` (3.15): its\n * title and its user menu. Combine it with `contentMaxWidth=\"none\"` (or a\n * page narrower than the cap); centred content doesn't align.\n * `paddingTop` sets the space above the content (`none`, `sm` 8 px, `md`\n * 16 px), e.g. `md` with `lc-page-header paddingTop=\"none\"` puts the `h1`\n * 16 px below the header.\n *\n * CSS hooks (set them on `lc-app-page` or any ancestor; each wins over the\n * inputs and holds one value at every width):\n * - `--lc-app-page-padding-x`: the side padding (default: `paddingX`).\n * Per breakpoint, set it inside your own media query:\n * `lc-app-page { --lc-app-page-padding-x: 16px }` and\n * `@media (min-width: 1024px) { lc-app-page { --lc-app-page-padding-x: 32px } }`.\n * - `--lc-app-page-padding-top`: the space above the content (default: `paddingTop`).\n * - `--lc-app-page-gap`: the space between the content's children (24 px, 40 px from 1024 px).\n * - `--lc-app-page-aside-width`: the right column (360 px, 400 from 1440, 460 from 1920).\n *\n * @example\n * ```html\n * <lc-app-page asideLabelledby=\"members-title\">\n * <lc-page-header … />\n * <lc-next-step-card … />\n * <section page-aside>\n * <h2 id=\"members-title\">Mitglieder</h2>\n * <lc-list [items]=\"members\" />\n * </section>\n * </lc-app-page>\n * ```\n */\n@Component({\n selector: 'lc-app-page',\n standalone: true,\n templateUrl: './app-page.component.html',\n styleUrl: './app-page.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class AppPageComponent {\n /** Id of the `<main>` element (the skip link's target). */\n readonly mainId = input('main');\n\n /**\n * Widest the page content gets (CSS length; `none` for no cap). The default\n * keeps lines readable on wide screens: the page gains air, not line length.\n */\n readonly contentMaxWidth = input('880px');\n\n /** Id of the heading that names the right column (`aria-labelledby`). */\n readonly asideLabelledby = input('');\n\n /** Accessible name of the right column when it has no visible heading. */\n readonly asideAriaLabel = input('');\n\n /**\n * Marks the page as loading: `aria-busy=\"true\"` on its `<main>` while\n * `true`, no attribute while `false`. Set it while a skeleton stands in for\n * the content. Screen readers may hold back changes inside a busy region\n * until it clears, so a loading message that must be heard belongs outside\n * `<main>` (for example a `.sr-only` `role=\"status\"` next to the page) or is\n * static text. No visual change.\n * @default false\n */\n readonly busy = input(false);\n\n /**\n * Horizontal page padding. `'default'`: 24/32/48/56/72/96 px from\n * 0/640/1024/1280/1440/1920 px. `'header'`: the same padding as `lc-header`\n * (16 px up to 768 px, 24 px above, from `--lc-density-padding-md`/`-lg`),\n * so the content lines up with the header title and the user menu. Combine\n * it with `contentMaxWidth=\"none\"` (or a page narrower than the cap).\n * `--lc-app-page-padding-x` wins over both.\n * @default 'default'\n */\n readonly paddingX = input<AppPagePaddingX>('default');\n\n /**\n * Space above the page content. `'default'`: 24/32/48/56/72/112 px by\n * width. `'none'` 0, `'sm'` 8 px, `'md'` 16 px at every width.\n * `--lc-app-page-padding-top` wins.\n * @default 'default'\n */\n readonly paddingTop = input<AppPagePaddingTop>('default');\n\n /** The right column renders only when it has an accessible name. */\n protected readonly hasAside = computed(() => !!(this.asideLabelledby() || this.asideAriaLabel()));\n\n protected readonly pageClasses = computed(() => {\n const classes = ['lc-app-page'];\n if (this.hasAside()) classes.push('lc-app-page--aside');\n if (this.paddingX() === 'header') classes.push('lc-app-page--pad-x-header');\n if (this.paddingTop() !== 'default') classes.push(`lc-app-page--pad-top-${this.paddingTop()}`);\n return classes.join(' ');\n });\n}\n","<div [class]=\"pageClasses()\" [style.--lc-app-page-content-max]=\"contentMaxWidth()\">\n <main class=\"lc-app-page__main\" [id]=\"mainId()\" [attr.aria-busy]=\"busy() ? 'true' : null\">\n <div class=\"lc-app-page__content\"><ng-content /></div>\n </main>\n @if (hasAside()) {\n <aside\n class=\"lc-app-page__aside\"\n [attr.aria-labelledby]=\"asideLabelledby() || null\"\n [attr.aria-label]=\"asideLabelledby() ? null : asideAriaLabel()\"\n >\n <ng-content select=\"[page-aside]\" />\n </aside>\n }\n</div>\n"],"mappings":"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"}
1
+ {"version":3,"file":"lifecorner-angular-ui-kit-app-shell.mjs","names":[],"sources":["../../../../libs/angular-ui-kit/src/lib/app-shell/app-shell.component.ts","../../../../libs/angular-ui-kit/src/lib/app-shell/app-shell.component.html","../../../../libs/angular-ui-kit/src/lib/app-shell/app-page.component.ts","../../../../libs/angular-ui-kit/src/lib/app-shell/app-page.component.html"],"sourcesContent":["import {\n afterNextRender,\n ChangeDetectionStrategy,\n Component,\n computed,\n DestroyRef,\n ElementRef,\n inject,\n input,\n viewChild,\n} from '@angular/core';\nimport { OverlayInsetsService } from '@lifecorner/angular-ui-kit/internal/overlay';\n\n/**\n * Private custom property the shell writes on `.lc-app-shell` in the browser:\n * the bar's content height. Its CSS fallback is 72 px (4 + 64 + 4 at 100 % text).\n */\nconst BAR_VAR = '--_lc-app-shell-bar';\n\n/** What a fixed overlay keeps free without a header or without a shown bar (AS-34). */\nconst TOP_INSET = 'env(safe-area-inset-top, 0px)';\nconst BOTTOM_INSET = 'env(safe-area-inset-bottom, 0px)';\n\n/** The border-box height of a ResizeObserver entry, with a layout read where the browser doesn't report it. */\nconst borderBoxHeight = (entry: ResizeObserverEntry, target: Element) =>\n entry.borderBoxSize?.[0]?.blockSize ?? target.getBoundingClientRect().height;\n\n/**\n * Where the side navigation sits from 1024 px: `'below-header'` (the header\n * spans the full width, the nav starts below it) or `'full-height'` (the nav\n * runs from the top to the bottom of the viewport, the header beside it).\n */\nexport type AppShellNavPlacement = 'below-header' | 'full-height';\n\n/**\n * App shell: the frame around every page of an app — header, side navigation,\n * page, bottom navigation bar, footer and the horizon — laid out for phones\n * first, with the DOCUMENT scrolling (not an inner container), so the iOS\n * status-bar tap, address-bar collapse and pull-to-refresh keep working.\n *\n * Slots (content projection by attribute):\n * - `[shell-header]` — the `lc-header`; scrolls away with the page. Gets the\n * top, left and right safe-area insets.\n * - `[shell-nav]` — the docked side navigation (`lc-sidenav mode=\"docked\"\n * [isOpen]=\"true\" width=\"100%\" [mobileBreakpoint]=\"0\"`), shown from\n * 1024 px in a column of 240 px (248 from 1440, 280 from 1920; override\n * with `--lc-app-shell-nav-width`) and sticky once the header has gone.\n * An empty slot takes no column.\n * - default — the page, usually an `lc-app-page` (or a `<router-outlet>`\n * whose pages use one). It spans to the window's right edge, so a page's\n * right column docks there.\n * - `[shell-bottom-nav]` — the `lc-bottom-nav`, shown below 1024 px. The shell\n * reserves its real height at the end of the page: at least 112 px (16 + 72\n * + 24) plus the safe-area inset, more when the bar grows with the text size\n * (measured in the browser; `--lc-app-shell-bottom-clearance` overrides it),\n * so it never covers content. With the horizon, the bar rests on the land\n * instead, and the land grows with a taller bar (3.10.1, AS-31).\n * - `[shell-footer]` — e.g. a compact `lc-footer`; after the page, or with\n * `horizon` in a row of its own below the horizon, painted in the land's\n * colour (`--color-land-3`): the land grows by the footer's height, so\n * `--lc-horizon-land` stays the land above the footer and no page overrides\n * it (3.9, LK-12).\n * - `[shell-horizon-figure]` — Edu (or any decorative figure) on the horizon\n * line, left of the sun: `lc-character`, `<img>`, `<picture>` or an element\n * holding an inline `<svg>`. Projected as a direct child of `.lc-horizon`,\n * sized and placed by the horizon (`--lc-horizon-figure-size` / `-gap`).\n * Decorative: the horizon is `aria-hidden`, so give an `<img>` `alt=\"\"` and\n * nothing focusable. Shown only when `horizon` is on (3.9, AS-29).\n *\n * `horizon` closes the page with the \"Weite\" horizon (`.lc-horizon` from the\n * kit's styles): full-bleed, below the side navigation and the page, filling\n * the rest of the screen — on Today, the sign-in pages and the shell pages.\n *\n * `navPlacement=\"full-height\"` (3.14) runs the nav column from the top to the\n * bottom of the viewport (sticky, 100dvh) with the header beside it, from\n * 1024 px; below 1024 px it renders like the default. The DOM and tab order\n * stay header → nav → page → footer, so in full-height the header's controls\n * come before a brand at the top of the nav (banner, then navigation, then\n * content). The land and the footer run under the nav; the footer's content\n * starts at the nav width.\n *\n * Toasts (3.28, AS-34): in the browser the shell tells `lc-toast-outlet` —\n * wherever the app puts it, also after `</lc-app-shell>` — where its header\n * ends and where the shown bar starts, so top toasts sit below the header and\n * bottom toasts 16 px above the bar (from 1024 px: above the safe-area\n * inset). `--lc-toast-outlet-offset-top` / `-bottom` override both.\n *\n * CSS hooks (set them on `lc-app-shell` or any ancestor):\n * - `--lc-app-shell-nav-width` — the nav column from 1024 px. Default\n * `240px` (`248px` from 1440, `280px` from 1920).\n * - `--lc-app-shell-bottom-clearance` — the space kept free for the bottom\n * bar below 1024 px. Default: the bar's height + 40 px + the inset, at\n * least `112px` + the inset.\n * - `--lc-app-shell-bg` — the page colour behind everything (the sky).\n * Default `var(--color-background)`.\n * - `--lc-app-shell-bg-image` — a layer over the page colour. Default\n * `var(--app-background-image, none)`. A tint, for example:\n * `linear-gradient(to bottom, var(--color-land-1), var(--color-land-2), var(--color-land-3))`.\n * The horizon's land still paints over it.\n *\n * Needs `<meta name=\"viewport\" content=\"width=device-width, initial-scale=1,\n * viewport-fit=cover\">` for the safe-area insets. Breakpoints are fixed\n * (1024 px side navigation, 1440 / 1920 px widths), so the layout works\n * before JavaScript runs (SSR, prerendering).\n *\n * @example\n * ```html\n * <lc-app-shell [horizon]=\"isToday()\">\n * <lc-header shell-header variant=\"transparent\" [sticky]=\"false\" … />\n * <lc-sidenav shell-nav mode=\"docked\" [isOpen]=\"true\" width=\"100%\" [mobileBreakpoint]=\"0\"\n * variant=\"transparent\" [items]=\"nav\" [activeRoute]=\"url()\" />\n * <router-outlet />\n * <lc-bottom-nav shell-bottom-nav variant=\"floating\" [items]=\"nav\" [activeRoute]=\"url()\" />\n * </lc-app-shell>\n * ```\n */\n@Component({\n selector: 'lc-app-shell',\n standalone: true,\n templateUrl: './app-shell.component.html',\n styleUrl: './app-shell.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class AppShellComponent {\n /**\n * Close the page with the horizon (`.lc-horizon`): full width, below the\n * side navigation and the page, filling the rest of the screen; the footer\n * (in a row of its own, which adds to the land) and the floating bar rest\n * on its land, and `[shell-horizon-figure]` stands on its line.\n * @default false\n */\n readonly horizon = input(false);\n\n /**\n * Where the side navigation sits from 1024 px. `'below-header'`: the header\n * spans the full width and the nav starts below it. `'full-height'`: the nav\n * runs from the top to the bottom of the viewport, with the header beside\n * it. Below 1024 px both render the same. The DOM and tab order don't change\n * (header, nav, page). CSS only, so it holds before JavaScript runs.\n * `'full-height'` expects a brand block at the top of the rail\n * (`lc-sidenav brandName` or `showLogo`, with a `logoSize` that matches the\n * header's `size`, e.g. both `md`: 64 px) and the header's `showLogo` off.\n * @default 'below-header'\n */\n readonly navPlacement = input<AppShellNavPlacement>('below-header');\n\n protected readonly shellClasses = computed(() => {\n const classes = ['lc-app-shell'];\n if (this.horizon()) classes.push('lc-app-shell--horizon');\n if (this.navPlacement() === 'full-height') classes.push('lc-app-shell--nav-full-height');\n return classes.join(' ');\n });\n\n private readonly shell = viewChild.required<ElementRef<HTMLElement>>('shell');\n private readonly headerSlot = viewChild.required<ElementRef<HTMLElement>>('headerSlot');\n private readonly barSlot = viewChild.required<ElementRef<HTMLElement>>('barSlot');\n\n constructor() {\n const destroyRef = inject(DestroyRef);\n const insets = inject(OverlayInsetsService);\n // Browser only (afterNextRender never runs on the server): follow the\n // bar's content height, so the clearance and the land grow with a bar\n // that grows with the text size (AS-31). Without ResizeObserver, and\n // before this runs, the CSS fallback (72 px → 112 px clearance) holds.\n // The same measurements tell a fixed overlay (lc-toast-outlet, AS-34)\n // what to keep free: the header's bottom edge and the bar's top edge.\n afterNextRender(() => {\n if (typeof ResizeObserver === 'undefined') return;\n const shell = this.shell().nativeElement;\n const header = this.headerSlot().nativeElement;\n const slot = this.barSlot().nativeElement;\n // Until a box is measured (a hidden bar or an empty header reports\n // nothing): the safe-area insets.\n insets.top.set(TOP_INSET);\n insets.bottom.set(BOTTOM_INSET);\n let bar: Element | null = null;\n const clear = () => {\n shell.style.removeProperty(BAR_VAR);\n insets.bottom.set(BOTTOM_INSET);\n };\n const sizes = new ResizeObserver((entries) => {\n const entry = entries[entries.length - 1];\n const height = entry.contentBoxSize?.[0]?.blockSize ?? entry.contentRect.height;\n // 0 when the bar is hidden (from 1024 px).\n if (height > 0 && bar) {\n shell.style.setProperty(BAR_VAR, `${height}px`);\n // Its top edge from the viewport's bottom: its own `bottom` (16 px\n // plus the inset when floating) plus its border box.\n const bottom = parseFloat(getComputedStyle(bar).bottom);\n insets.bottom.set(`${(Number.isFinite(bottom) ? bottom : 0) + borderBoxHeight(entry, bar)}px`);\n } else clear();\n });\n // The header wrapper carries the top inset (its padding), so its border\n // box ends at the header's bottom edge; 0 when the slot is empty.\n const headerSizes = new ResizeObserver((entries) => {\n const height = borderBoxHeight(entries[entries.length - 1], header);\n insets.top.set(height > 0 ? `${height}px` : TOP_INSET);\n });\n headerSizes.observe(header);\n // The bar may come later (`@if (items())` around it) or go again.\n const pick = () => {\n const next = slot.querySelector('.lc-bottom-nav') ?? slot.firstElementChild;\n if (next === bar) return;\n if (bar) sizes.unobserve(bar);\n bar = next;\n if (bar) sizes.observe(bar);\n else clear();\n };\n pick();\n const changes = typeof MutationObserver === 'undefined' ? null : new MutationObserver(pick);\n changes?.observe(slot, { childList: true, subtree: true });\n destroyRef.onDestroy(() => {\n sizes.disconnect();\n headerSizes.disconnect();\n changes?.disconnect();\n insets.top.set(null);\n insets.bottom.set(null);\n });\n });\n }\n}\n","<div #shell [class]=\"shellClasses()\">\n <div #headerSlot class=\"lc-app-shell__header\"><ng-content select=\"[shell-header]\" /></div>\n <div class=\"lc-app-shell__nav\"><ng-content select=\"[shell-nav]\" /></div>\n <div class=\"lc-app-shell__body\"><ng-content /></div>\n @if (horizon()) {\n <div class=\"lc-app-shell__horizon lc-horizon\" aria-hidden=\"true\"><ng-content select=\"[shell-horizon-figure]\" /></div>\n }\n <div class=\"lc-app-shell__footer\"><ng-content select=\"[shell-footer]\" /></div>\n <div #barSlot class=\"lc-app-shell__bottom-nav\"><ng-content select=\"[shell-bottom-nav]\" /></div>\n</div>\n","import { ChangeDetectionStrategy, Component, computed, input } from '@angular/core';\n\n/**\n * Horizontal padding of `lc-app-page` (3.15).\n * - `default`: 24 · 32 · 48 · 56 · 72 · 96 px from 0 · 640 · 1024 · 1280 · 1440 · 1920 px.\n * - `header`: `lc-header`'s padding (16 px up to 768 px, 24 px above), so the\n * content lines up with the header title and the user menu.\n */\nexport type AppPagePaddingX = 'default' | 'header';\n\n/**\n * Space above `lc-app-page`'s content (3.15).\n * - `default`: 24 · 32 · 48 · 56 · 72 · 112 px by width.\n * - `none` 0, `sm` 8 px, `md` 16 px at every width.\n */\nexport type AppPagePaddingTop = 'default' | 'none' | 'sm' | 'md';\n\n/**\n * Width of `lc-app-page`'s content from 1280 px (3.28, AS-36).\n * - `default`: the content column, centred, capped at `contentMaxWidth`.\n * - `wide`: the standard column of a page with a right column, the right\n * column left empty, and `[page-wide]` children running over it, up to\n * 928 px. Below 1280 px, and next to a named right column, as `default`.\n */\nexport type AppPageContentWidth = 'default' | 'wide';\n\n/**\n * A page inside `lc-app-shell`: the `<main>` landmark with the page's content\n * centred at a reading width, and an optional right column docked to the\n * window's right edge (LK-6).\n *\n * - `<main [id]=\"mainId\">` holds the default slot as a column (24 px apart,\n * 40 px from 1024 px), centred and capped at `contentMaxWidth` (880 px of\n * content). Side padding 24 · 32 · 48 · 56 · 72 · 96 px at 360 · 640 ·\n * 1024 · 1280 · 1440 · 1920 px.\n * - `[page-aside]` is the right column: an `<aside>` AFTER `<main>` in the DOM,\n * shown from 1280 px at 360 px (400 from 1440, 460 from 1920; override\n * with `--lc-app-page-aside-width`), with a tint and a hairline that fade\n * downwards; inside `lc-app-shell` they start at the top of the window,\n * behind a transparent header. Below 1280 px it is hidden: show the page's narrow equivalent\n * inside main instead (e.g. a member row). It renders only with an\n * accessible name — `asideLabelledby` (the id of its heading) or\n * `asideAriaLabel`.\n * - `reserveAside` keeps that column from 1280 px — width, tint and hairline —\n * with no content and no landmark (`aria-hidden=\"true\"`), so a page without\n * right-column content keeps the same column as a page with one (3.28,\n * AS-35). A named aside wins.\n * - `contentWidth=\"wide\"` (3.28, AS-36) lays the page out like a page with a\n * right column, leaves the column empty and untinted, and lets children\n * marked `[page-wide]` (e.g. a table's wrapper) run over it, up to 928 px;\n * the other children (the page header, the next-step card) keep the\n * standard column, so the title doesn't move between pages. Next to a named\n * aside, and below 1280 px, it renders like `'default'`.\n * - `busy` marks the page as loading: `aria-busy=\"true\"` on `<main>` while a\n * skeleton stands in for the content (AS-12). No visual change.\n * - `paddingX=\"header\"` lines the content up with `lc-header` (3.15): its\n * title and its user menu. Combine it with `contentMaxWidth=\"none\"` (or a\n * page narrower than the cap); centred content doesn't align.\n * `paddingTop` sets the space above the content (`none`, `sm` 8 px, `md`\n * 16 px), e.g. `md` with `lc-page-header paddingTop=\"none\"` puts the `h1`\n * 16 px below the header.\n *\n * CSS hooks (set them on `lc-app-page` or any ancestor; each wins over the\n * inputs and holds one value at every width):\n * - `--lc-app-page-padding-x`: the side padding (default: `paddingX`).\n * Per breakpoint, set it inside your own media query:\n * `lc-app-page { --lc-app-page-padding-x: 16px }` and\n * `@media (min-width: 1024px) { lc-app-page { --lc-app-page-padding-x: 32px } }`.\n * - `--lc-app-page-padding-top`: the space above the content (default: `paddingTop`).\n * - `--lc-app-page-gap`: the space between the content's children (24 px, 40 px from 1024 px).\n * - `--lc-app-page-aside-width`: the right column (360 px, 400 from 1440, 460 from 1920).\n *\n * @example\n * ```html\n * <lc-app-page asideLabelledby=\"members-title\">\n * <lc-page-header … />\n * <lc-next-step-card … />\n * <section page-aside>\n * <h2 id=\"members-title\">Mitglieder</h2>\n * <lc-list [items]=\"members\" />\n * </section>\n * </lc-app-page>\n * ```\n */\n@Component({\n selector: 'lc-app-page',\n standalone: true,\n templateUrl: './app-page.component.html',\n styleUrl: './app-page.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class AppPageComponent {\n /** Id of the `<main>` element (the skip link's target). */\n readonly mainId = input('main');\n\n /**\n * Widest the page content gets (CSS length; `none` for no cap). The default\n * keeps lines readable on wide screens: the page gains air, not line length.\n */\n readonly contentMaxWidth = input('880px');\n\n /** Id of the heading that names the right column (`aria-labelledby`). */\n readonly asideLabelledby = input('');\n\n /** Accessible name of the right column when it has no visible heading. */\n readonly asideAriaLabel = input('');\n\n /**\n * Marks the page as loading: `aria-busy=\"true\"` on its `<main>` while\n * `true`, no attribute while `false`. Set it while a skeleton stands in for\n * the content. Screen readers may hold back changes inside a busy region\n * until it clears, so a loading message that must be heard belongs outside\n * `<main>` (for example a `.sr-only` `role=\"status\"` next to the page) or is\n * static text. No visual change.\n * @default false\n */\n readonly busy = input(false);\n\n /**\n * Horizontal page padding. `'default'`: 24/32/48/56/72/96 px from\n * 0/640/1024/1280/1440/1920 px. `'header'`: the same padding as `lc-header`\n * (16 px up to 768 px, 24 px above, from `--lc-density-padding-md`/`-lg`),\n * so the content lines up with the header title and the user menu. Combine\n * it with `contentMaxWidth=\"none\"` (or a page narrower than the cap).\n * `--lc-app-page-padding-x` wins over both.\n * @default 'default'\n */\n readonly paddingX = input<AppPagePaddingX>('default');\n\n /**\n * Space above the page content. `'default'`: 24/32/48/56/72/112 px by\n * width. `'none'` 0, `'sm'` 8 px, `'md'` 16 px at every width.\n * `--lc-app-page-padding-top` wins.\n * @default 'default'\n */\n readonly paddingTop = input<AppPagePaddingTop>('default');\n\n /**\n * Keeps the right column from 1280 px (360 · 400 · 460 px,\n * `--lc-app-page-aside-width`) with its tint and hairline but no content\n * and no landmark (`aria-hidden=\"true\"`, no role), so pages without\n * right-column content share one column with pages that have one. A named\n * aside (`asideLabelledby` / `asideAriaLabel`) wins; `contentWidth=\"wide\"`\n * leaves the column empty and untinted. Below 1280 px nothing shows.\n * @default false\n */\n readonly reserveAside = input(false);\n\n /**\n * `'wide'`, from 1280 px: the page keeps the standard column of a page with\n * a right column, the column stays empty and untinted, and `[page-wide]`\n * children run over it, up to 928 px (or `contentMaxWidth` when it is not\n * `880px`; `none` means the whole column). The other children keep the\n * standard column. With a named aside, `'wide'` has no effect. Below\n * 1280 px `'wide'` renders like `'default'`.\n * @default 'default'\n */\n readonly contentWidth = input<AppPageContentWidth>('default');\n\n /** The right column renders only when it has an accessible name. */\n protected readonly hasAside = computed(() => !!(this.asideLabelledby() || this.asideAriaLabel()));\n\n /** `contentWidth=\"wide\"` takes effect only without a named aside, which it yields to. */\n protected readonly wide = computed(() => this.contentWidth() === 'wide' && !this.hasAside());\n\n /** The empty, unnamed column (`reserveAside`), unless a named aside or `wide` takes the space. */\n protected readonly reserved = computed(() => this.reserveAside() && !this.hasAside() && !this.wide());\n\n /**\n * The cap of `[page-wide]` children: `null` keeps the CSS's 928 px (also\n * for the default `contentMaxWidth`), `none` means the whole column.\n */\n protected readonly wideMax = computed(() => {\n if (!this.wide()) return null;\n const max = this.contentMaxWidth();\n if (max === '880px') return null;\n return max === 'none' ? '100vw' : max;\n });\n\n protected readonly pageClasses = computed(() => {\n const classes = ['lc-app-page'];\n if (this.hasAside() || this.reserveAside() || this.wide()) classes.push('lc-app-page--aside');\n if (this.wide()) classes.push('lc-app-page--wide');\n if (this.paddingX() === 'header') classes.push('lc-app-page--pad-x-header');\n if (this.paddingTop() !== 'default') classes.push(`lc-app-page--pad-top-${this.paddingTop()}`);\n return classes.join(' ');\n });\n}\n","<div [class]=\"pageClasses()\" [style.--lc-app-page-content-max]=\"contentMaxWidth()\" [style.--_lc-app-page-wide-max]=\"wideMax()\">\n <main class=\"lc-app-page__main\" [id]=\"mainId()\" [attr.aria-busy]=\"busy() ? 'true' : null\">\n <div class=\"lc-app-page__content\"><ng-content /></div>\n </main>\n <!-- One outer block, so a page without a right column keeps 3.27.2's single\n anchor (an @else branch adds one); the reserved column (AS-35) is empty,\n aria-hidden and no landmark. -->\n @if (hasAside() || reserved()) {\n @if (hasAside()) {\n <aside\n class=\"lc-app-page__aside\"\n [attr.aria-labelledby]=\"asideLabelledby() || null\"\n [attr.aria-label]=\"asideLabelledby() ? null : asideAriaLabel()\"\n >\n <ng-content select=\"[page-aside]\" />\n </aside>\n } @else {<div class=\"lc-app-page__aside lc-app-page__aside--reserved\" aria-hidden=\"true\"></div>}\n }\n</div>\n"],"mappings":"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"}
@@ -470,7 +470,7 @@ var ChatComponent = class ChatComponent {
470
470
  ],
471
471
  ngImport: i0,
472
472
  template: "<div\n class=\"lc-chat\"\n [class.lc-chat--borderless]=\"!bordered()\"\n [class.lc-chat--width-narrow]=\"contentWidth() === 'narrow'\"\n [class.lc-chat--width-full]=\"contentWidth() === 'full'\"\n>\n @if (showHeader()) {\n <div class=\"lc-chat__header\">\n <span class=\"lc-chat__title\">{{ title() }}</span>\n @if (isStreaming()) {\n <span class=\"lc-chat__streaming-badge\">{{ streamingLabel() }}</span>\n }\n </div>\n }\n\n <div\n class=\"lc-chat__messages\"\n [class.lc-chat__messages--anchor-bottom]=\"messageAnchor() === 'bottom'\"\n #scrollContainer\n >\n <div class=\"lc-chat__thread\">\n @for (msg of formattedMessages(); track msg.id) {\n <div\n class=\"lc-chat__message\"\n [class.lc-chat__message--user]=\"msg.role === 'user'\"\n [class.lc-chat__message--agent]=\"msg.role === 'agent'\"\n [class.lc-chat__message--system]=\"msg.role === 'system'\"\n [class.lc-chat__message--avatar]=\"showUserAvatar(msg)\"\n [class.lc-chat__message--streaming]=\"msg.streaming\"\n [attr.role]=\"msg.status === 'error' ? 'alert' : null\"\n [attr.aria-live]=\"statusAriaLive(msg.status)\"\n >\n @if ((msg.role !== 'user' && (showAvatars() || isSemanticStatus(msg.status))) || showUserAvatar(msg)) {\n <div class=\"lc-chat__marker\" [class.lc-chat__marker--user]=\"msg.role === 'user'\">\n @if (isSemanticStatus(msg.status) && msg.role !== 'user') {\n <span class=\"lc-chat__status-icon\">\n <lc-icon [name]=\"statusIcon(msg.status)\" size=\"xs\" [color]=\"statusColor(msg.status)\" [decorative]=\"true\" />\n </span>\n } @else if (msg.avatar) {\n <img [src]=\"msg.avatar\" [alt]=\"msg.name || msg.role\" class=\"lc-chat__avatar-img\" />\n } @else if (msg.role === 'user') {\n <span class=\"lc-chat__monogram\" [attr.aria-label]=\"msg.name\">{{ initials(msg.name) }}</span>\n } @else {\n <span\n class=\"lc-chat__dot\"\n [class.lc-chat__dot--agent]=\"msg.role === 'agent'\"\n [class.lc-chat__dot--system]=\"msg.role === 'system'\"\n ></span>\n }\n </div>\n }\n\n <div class=\"lc-chat__bubble\" [class.lc-chat__bubble--streaming]=\"msg.streaming\">\n @if (msg.name && msg.role !== 'user') {\n @if (showTimestamps() && msg.timestamp) {\n <div class=\"lc-chat__meta lc-chat__meta--agent\">\n <span class=\"lc-chat__name\">{{ msg.name }}</span>\n <span class=\"lc-chat__time\">{{ formatTime(msg.timestamp) }}</span>\n </div>\n } @else {\n <div class=\"lc-chat__name\">{{ msg.name }}</div>\n }\n }\n <div class=\"lc-chat__content\">\n @if (isSemanticStatus(msg.status)) {\n <span class=\"lc-chat__sr-only\">{{ statusLabel(msg.status) }} </span>\n }\n @if (messageTemplate) {\n <ng-container *ngTemplateOutlet=\"messageTemplate; context: { $implicit: msg }\" />\n } @else if (shouldRenderMarkdown(msg.role)) {\n <lc-markdown [content]=\"msg.content\" variant=\"chat\" />\n } @else {\n {{ msg.content }}\n }\n <span class=\"lc-chat__cursor\" [class.lc-chat__cursor--visible]=\"msg.streaming\"></span>\n </div>\n @if (msg.attachments?.length) {\n <div class=\"lc-chat__attachments\">\n @for (att of msg.attachments; track att.id) {\n @if (isImage(att) && att.url) {\n <a class=\"lc-chat__attachment lc-chat__attachment--image\" [href]=\"att.url\" target=\"_blank\" rel=\"noopener\">\n <img [src]=\"att.url\" [alt]=\"att.name\" />\n </a>\n } @else {\n <a\n class=\"lc-chat__attachment lc-chat__attachment--file\"\n [href]=\"att.url || null\"\n [attr.download]=\"att.url ? att.name : null\"\n target=\"_blank\"\n rel=\"noopener\"\n >\n <svg class=\"lc-chat__attachment-icon\" width=\"16\" height=\"16\" viewBox=\"0 0 20 20\" fill=\"none\" aria-hidden=\"true\">\n <path d=\"M6 2.5h6L16 6.5v10A1.5 1.5 0 0 1 14.5 18h-9A1.5 1.5 0 0 1 4 16.5v-12A1.5 1.5 0 0 1 5.5 3H6V2.5Z\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linejoin=\"round\"/>\n <path d=\"M12 2.5V6.5H16\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linejoin=\"round\"/>\n </svg>\n <span class=\"lc-chat__attachment-name\">{{ att.name }}</span>\n @if (att.size) {\n <span class=\"lc-chat__attachment-size\">{{ formatBytes(att.size) }}</span>\n }\n </a>\n }\n }\n </div>\n }\n @if (showTimestamps() && msg.timestamp && msg.role !== 'user' && !msg.name) {\n <div class=\"lc-chat__time lc-chat__time--tight\">{{ formatTime(msg.timestamp) }}</div>\n }\n </div>\n @if (showTimestamps() && msg.timestamp && msg.role === 'user') {\n <div class=\"lc-chat__time lc-chat__time--user\">{{ formatTime(msg.timestamp) }}</div>\n }\n </div>\n }\n\n @if (isStreaming() && !(formattedMessages().length && formattedMessages()[formattedMessages().length - 1].streaming)) {\n <div class=\"lc-chat__message lc-chat__message--agent\">\n @if (showAvatars()) {\n <div class=\"lc-chat__marker\">\n <span class=\"lc-chat__dot lc-chat__dot--agent\"></span>\n </div>\n }\n <div class=\"lc-chat__bubble\">\n <div class=\"lc-chat__typing\">\n <span></span><span></span><span></span>\n </div>\n </div>\n </div>\n }\n </div>\n </div>\n\n <!-- Announces the latest completed non-user turn (see `announcement`). -->\n <div class=\"lc-chat__sr-only lc-chat__announcer\" aria-live=\"polite\" aria-atomic=\"true\">{{ announcement() }}</div>\n\n <div class=\"lc-chat__input-area\">\n <div class=\"lc-chat__composer\">\n @if (allowFileUpload() && pendingAttachments().length) {\n <div class=\"lc-chat__pending-attachments\">\n @for (att of pendingAttachments(); track att.id) {\n <div class=\"lc-chat__pending-attachment\" [class.lc-chat__pending-attachment--image]=\"isImage(att)\">\n @if (isImage(att) && att.url) {\n <img class=\"lc-chat__pending-thumb\" [src]=\"att.url\" [alt]=\"att.name\" />\n } @else {\n <svg class=\"lc-chat__attachment-icon\" width=\"16\" height=\"16\" viewBox=\"0 0 20 20\" fill=\"none\" aria-hidden=\"true\">\n <path d=\"M6 2.5h6L16 6.5v10A1.5 1.5 0 0 1 14.5 18h-9A1.5 1.5 0 0 1 4 16.5v-12A1.5 1.5 0 0 1 5.5 3H6V2.5Z\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linejoin=\"round\"/>\n <path d=\"M12 2.5V6.5H16\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linejoin=\"round\"/>\n </svg>\n }\n <span class=\"lc-chat__pending-name\">{{ att.name }}</span>\n @if (att.size) {\n <span class=\"lc-chat__pending-size\">{{ formatBytes(att.size) }}</span>\n }\n <button\n type=\"button\"\n class=\"lc-chat__pending-remove\"\n (click)=\"removeAttachment(att.id)\"\n [attr.aria-label]=\"removeAttachmentAriaLabel() + ' ' + att.name\"\n >\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\" aria-hidden=\"true\">\n <path d=\"M3 3l6 6M9 3l-6 6\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\"/>\n </svg>\n </button>\n </div>\n }\n </div>\n }\n\n <label class=\"lc-chat__sr-only\" [for]=\"inputId\">{{ inputLabel() }}</label>\n <textarea\n #composerInput\n [id]=\"inputId\"\n class=\"lc-chat__input\"\n [placeholder]=\"placeholder()\"\n [value]=\"inputValue()\"\n [disabled]=\"disabled()\"\n (input)=\"onInput($event)\"\n (keydown)=\"onKeydown($event)\"\n rows=\"1\"\n ></textarea>\n\n <div class=\"lc-chat__composer-actions\">\n @if (allowFileUpload()) {\n <input\n #fileInput\n type=\"file\"\n class=\"lc-chat__file-input\"\n [accept]=\"accept() || null\"\n [multiple]=\"multiple()\"\n (change)=\"onFilesSelected($event)\"\n />\n <button\n type=\"button\"\n class=\"lc-chat__attach-btn\"\n [disabled]=\"disabled()\"\n (click)=\"openFilePicker()\"\n [attr.aria-label]=\"attachAriaLabel()\"\n >\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" fill=\"none\" aria-hidden=\"true\">\n <path d=\"M14.5 9.5l-5 5a3 3 0 0 1-4.243-4.243l6.364-6.364a2 2 0 0 1 2.829 2.829l-6.364 6.364a1 1 0 1 1-1.415-1.415L11.5 6.5\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </button>\n }\n <button\n class=\"lc-chat__send-btn\"\n [disabled]=\"(!inputValue().trim() && !pendingAttachments().length) || disabled()\"\n (click)=\"send()\"\n [attr.aria-label]=\"sendAriaLabel()\"\n >\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" fill=\"none\">\n <path d=\"M3 10l7-7m0 0l7 7m-7-7v14\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" transform=\"rotate(90 10 10)\"/>\n </svg>\n </button>\n </div>\n </div>\n </div>\n</div>\n",
473
- styles: [".lc-chat{--lc-chat-content-width: 46rem;--lc-chat-thread-gap: var(--spacing-3, .75rem);--lc-chat-messages-pad-block: var(--spacing-4, 1rem);--lc-chat-messages-pad-inline: var(--spacing-3, .75rem);--lc-chat-bubble-font: var(--font-size-sm, .875rem);--lc-chat-bubble-line: var(--line-height-normal, 1.5);--lc-chat-bubble-pad-block: var(--spacing-2, .5rem);--lc-chat-bubble-pad-inline: var(--spacing-3, .75rem);--lc-chat-header-pad-block: var(--spacing-2, .5rem);--lc-chat-input-area-pad: var(--spacing-3, .75rem);--lc-chat-composer-pad: var(--spacing-2, .5rem);display:flex;flex-direction:column;height:100%;min-height:20rem;border:1px solid var(--color-border);border-radius:var(--border-radius-lg);overflow:hidden;background-color:var(--color-surface);color:var(--color-text-primary);font-family:var(--font-family-sans, sans-serif)}.lc-chat--borderless{border:none;border-radius:0}.lc-chat--width-full{--lc-chat-content-width: 100%}.lc-chat__header{display:flex;align-items:center;justify-content:space-between;padding:var(--lc-chat-header-pad-block) var(--spacing-4);border-bottom:1px solid var(--color-divider);background:var(--color-surface)}.lc-chat__title{font-size:var(--font-size-sm, .875rem);font-weight:var(--font-weight-semibold, 600);color:var(--color-text-primary)}.lc-chat__streaming-badge{font-size:var(--font-size-xs, .6875rem);padding:.125rem .5rem;background:color-mix(in srgb,var(--color-primary-500) 15%,transparent);color:var(--color-primary-500);border-radius:var(--border-radius-full, 1rem);font-weight:var(--font-weight-medium, 500);animation:pulse-badge 1.5s infinite}@keyframes pulse-badge{0%,to{opacity:1}50%{opacity:.6}}.lc-chat__messages{flex:1;overflow-y:auto;display:flex;flex-direction:column;padding-block:var(--lc-chat-messages-pad-block);padding-inline:var(--lc-chat-messages-pad-inline)}.lc-chat__thread{position:relative;width:100%;max-width:var(--lc-chat-content-width, 46rem);margin-inline:auto;flex:1 1 auto;min-height:0;display:flex;flex-direction:column;gap:var(--lc-chat-thread-gap)}.lc-chat__messages--anchor-bottom .lc-chat__thread>.lc-chat__message:first-child{margin-top:auto}.lc-chat__message{position:relative;display:flex;align-items:stretch;gap:var(--spacing-3, .75rem);align-self:stretch;max-width:100%}.lc-chat__message--user{flex-direction:column;align-items:flex-end;gap:var(--spacing-1, .25rem)}.lc-chat__message--user.lc-chat__message--avatar{display:grid;grid-template-columns:minmax(0,1fr) auto;grid-template-areas:\"bubble avatar\" \"time avatar\";column-gap:var(--spacing-2, .5rem);align-items:start}.lc-chat__message--user.lc-chat__message--avatar>.lc-chat__bubble{grid-area:bubble;justify-self:end}.lc-chat__message--user.lc-chat__message--avatar>.lc-chat__time--user{grid-area:time;justify-self:end}.lc-chat__message--user.lc-chat__message--avatar>.lc-chat__marker--user{grid-area:avatar}.lc-chat__marker{position:relative;z-index:1;flex-shrink:0;width:.875rem;display:flex;flex-direction:column;align-items:center}.lc-chat__marker:before{content:\"\";position:absolute;left:50%;top:.55rem;bottom:calc(-1 * var(--lc-chat-thread-gap));width:1.5px;transform:translate(-50%);background:var(--color-divider);z-index:-1}.lc-chat__message:last-child .lc-chat__marker:before{display:none}.lc-chat__dot{position:relative;z-index:1;width:.625rem;height:.625rem;margin-top:.25rem;border-radius:50%;background:var(--color-text-tertiary);box-shadow:0 0 0 3px var(--color-surface)}.lc-chat__dot--agent{background:var(--color-primary-500)}.lc-chat__dot--system{background:var(--color-text-tertiary);opacity:.6}.lc-chat__message--streaming .lc-chat__dot--agent{animation:dot-pulse 1.4s ease-out infinite}@keyframes dot-pulse{0%{box-shadow:0 0 0 3px var(--color-surface),0 0 0 3px color-mix(in srgb,var(--color-primary-500) 45%,transparent)}70%,to{box-shadow:0 0 0 3px var(--color-surface),0 0 0 9px color-mix(in srgb,var(--color-primary-500) 0%,transparent)}}.lc-chat__avatar-img{width:1.5rem;height:1.5rem;border-radius:50%;object-fit:cover;box-shadow:0 0 0 3px var(--color-surface)}.lc-chat__marker--user{width:auto}.lc-chat__marker--user:before{display:none}.lc-chat__monogram{display:inline-flex;align-items:center;justify-content:center;width:1.5rem;height:1.5rem;border-radius:50%;background:color-mix(in srgb,var(--color-primary-500) 18%,var(--color-surface-2));color:var(--color-on-primary-subtle);font-size:var(--font-size-xs, .75rem);font-weight:var(--font-weight-semibold, 600);line-height:1;box-shadow:0 0 0 3px var(--color-surface)}.lc-chat__status-icon{position:relative;z-index:1;display:inline-flex;align-items:center;justify-content:center;width:1rem;height:1rem;margin-top:.0625rem;border-radius:50%;background:var(--color-surface);box-shadow:0 0 0 2px var(--color-surface)}.lc-chat__sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}.lc-chat__bubble{flex:1;min-width:0;font-size:var(--lc-chat-bubble-font);line-height:var(--lc-chat-bubble-line);word-break:break-word;color:var(--color-text-primary)}.lc-chat__message--user .lc-chat__bubble{position:relative;z-index:1;flex:0 1 auto;max-width:min(85%,34rem);padding:var(--lc-chat-bubble-pad-block) var(--lc-chat-bubble-pad-inline);border:1px solid color-mix(in srgb,var(--color-primary-500) 22%,transparent);border-radius:var(--border-radius-lg);background:color-mix(in srgb,var(--color-primary-500) 10%,var(--color-surface-2))}.lc-chat__message--agent .lc-chat__bubble{padding:0;background:transparent}.lc-chat__message--system .lc-chat__bubble{padding:0;background:transparent;color:var(--color-text-tertiary);font-size:var(--font-size-sm, .8125rem)}.lc-chat__meta{display:flex;align-items:baseline;justify-content:space-between;gap:var(--spacing-2, .5rem);margin-bottom:var(--spacing-1, .25rem)}.lc-chat__meta .lc-chat__name{margin-bottom:0}.lc-chat__meta .lc-chat__time{margin-top:0}.lc-chat__name{font-size:var(--font-size-xs, .75rem);font-weight:var(--font-weight-semibold, 600);color:var(--color-text-secondary);margin-bottom:var(--spacing-1, .25rem)}.lc-chat__content{white-space:pre-wrap}.lc-chat__cursor{display:none}.lc-chat__cursor--visible{display:inline-block;width:2px;height:1em;background:currentColor;margin-left:1px;vertical-align:text-bottom;animation:blink-cursor .8s step-end infinite}@keyframes blink-cursor{0%,to{opacity:1}50%{opacity:0}}.lc-chat__time{font-size:var(--font-size-xs, .75rem);color:var(--color-text-tertiary);margin-top:var(--spacing-1, .25rem);flex-shrink:0}.lc-chat__time--tight{margin-top:0}.lc-chat__time--user{margin-top:0;padding-inline:var(--spacing-1, .25rem)}.lc-chat__typing{display:flex;gap:.25rem;padding:.25rem 0}.lc-chat__typing span{width:.375rem;height:.375rem;border-radius:50%;background:var(--color-text-tertiary);animation:typing-bounce 1.4s ease-in-out infinite}.lc-chat__typing span:nth-child(2){animation-delay:.2s}.lc-chat__typing span:nth-child(3){animation-delay:.4s}@keyframes typing-bounce{0%,60%,to{transform:translateY(0)}30%{transform:translateY(-.375rem)}}.lc-chat__input-area{padding:var(--lc-chat-input-area-pad);border-top:1px solid var(--color-divider);background:var(--color-surface)}.lc-chat__composer{width:100%;max-width:var(--lc-chat-content-width, 46rem);margin-inline:auto;display:flex;flex-direction:column;gap:var(--spacing-2, .5rem);padding:var(--lc-chat-composer-pad);background:var(--color-surface-2);border:1px solid var(--color-border);border-radius:var(--border-radius-xl);transition:border-color .15s,box-shadow .15s}.lc-chat__composer:focus-within{border-color:var(--color-primary-500);box-shadow:var(--elevation-1)}.lc-chat__input{display:block;width:100%;box-sizing:border-box;resize:none;border:none;background:transparent;padding:var(--spacing-1, .25rem) var(--spacing-2, .5rem);font-size:var(--font-size-base, .875rem);font-family:inherit;line-height:var(--line-height-normal, 1.4);color:var(--color-text-primary);outline:none;height:auto;max-height:12rem;overflow-y:auto}.lc-chat__input:disabled{opacity:.5;cursor:not-allowed}.lc-chat__input::placeholder{color:var(--color-text-tertiary)}.lc-chat__composer-actions{display:flex;align-items:center;gap:var(--spacing-2, .5rem)}.lc-chat__send-btn{position:relative;display:inline-flex;align-items:center;justify-content:center;width:2rem;height:2rem;margin-left:auto;border:none;border-radius:var(--border-radius-md);background:var(--color-primary-fill);color:var(--color-on-primary);cursor:pointer;flex-shrink:0;transition:background .15s,opacity .15s}.lc-chat__send-btn:before{content:\"\";position:absolute;inset:calc((2rem - var(--size-min-touch-height, 2.75rem)) / 2)}.lc-chat__send-btn:hover:not(:disabled){background:var(--color-primary-fill-hover)}.lc-chat__send-btn:disabled{opacity:.4;cursor:not-allowed}.lc-chat__send-btn:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:2px}.lc-chat__file-input{display:none}.lc-chat__attach-btn{position:relative;display:inline-flex;align-items:center;justify-content:center;width:2rem;height:2rem;border:none;border-radius:var(--border-radius-md);background:transparent;color:var(--color-text-tertiary);cursor:pointer;flex-shrink:0;transition:background .15s,color .15s}.lc-chat__attach-btn:before{content:\"\";position:absolute;inset:calc((2rem - var(--size-min-touch-height, 2.75rem)) / 2)}.lc-chat__attach-btn:hover:not(:disabled){background:var(--color-surface-hover);color:var(--color-text-primary)}.lc-chat__attach-btn:disabled{opacity:.4;cursor:not-allowed}.lc-chat__attach-btn:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:2px}.lc-chat__pending-attachments{display:flex;flex-wrap:wrap;gap:.375rem}.lc-chat__pending-attachment{display:inline-flex;align-items:center;gap:.375rem;padding:.25rem .375rem .25rem .5rem;background:var(--color-surface);border:1px solid var(--color-border);border-radius:var(--border-radius-md, .5rem);font-size:var(--font-size-xs, .75rem);color:var(--color-text-primary);max-width:16rem}.lc-chat__pending-thumb{width:1.75rem;height:1.75rem;object-fit:cover;border-radius:.25rem;flex-shrink:0}.lc-chat__pending-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:9rem}.lc-chat__pending-size{color:var(--color-text-tertiary);font-variant-numeric:tabular-nums}.lc-chat__pending-remove{display:inline-flex;align-items:center;justify-content:center;width:1.25rem;height:1.25rem;border:none;border-radius:50%;background:transparent;color:var(--color-text-tertiary);cursor:pointer;flex-shrink:0}.lc-chat__pending-remove:hover{background:var(--color-surface-hover);color:var(--color-text-primary)}.lc-chat__pending-remove:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:2px}.lc-chat__attachments{display:flex;flex-wrap:wrap;gap:.375rem;margin-top:.5rem}.lc-chat__attachment{display:inline-flex;align-items:center;gap:.375rem;text-decoration:none;color:inherit;font-size:var(--font-size-xs, .75rem)}.lc-chat__attachment--file{padding:.25rem .5rem;background:color-mix(in srgb,currentColor 8%,transparent);border-radius:var(--border-radius-md, .375rem);max-width:16rem}.lc-chat__attachment--file:hover{background:color-mix(in srgb,currentColor 16%,transparent)}.lc-chat__attachment--image img{max-width:12rem;max-height:8rem;border-radius:var(--border-radius-md, .375rem);object-fit:cover;display:block}.lc-chat__attachment:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:2px}.lc-chat__attachment-icon{flex-shrink:0}.lc-chat__attachment-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.lc-chat__attachment-size{opacity:.7;font-variant-numeric:tabular-nums}@media(forced-colors:active){.lc-chat__send-btn:focus-visible,.lc-chat__attach-btn:focus-visible,.lc-chat__pending-remove:focus-visible,.lc-chat__attachment:focus-visible{outline-color:Highlight}}\n"],
473
+ styles: [".lc-chat{--lc-chat-content-width: 46rem;--lc-chat-thread-gap: var(--spacing-3, .75rem);--lc-chat-messages-pad-block: var(--spacing-4, 1rem);--lc-chat-messages-pad-inline: var(--spacing-3, .75rem);--lc-chat-bubble-font: var(--font-size-sm, .875rem);--lc-chat-bubble-line: var(--line-height-normal, 1.5);--lc-chat-bubble-pad-block: var(--spacing-2, .5rem);--lc-chat-bubble-pad-inline: var(--spacing-3, .75rem);--lc-chat-header-pad-block: var(--spacing-2, .5rem);--lc-chat-input-area-pad: var(--spacing-3, .75rem);--lc-chat-composer-pad: var(--spacing-2, .5rem);display:flex;flex-direction:column;height:100%;min-height:20rem;border:1px solid var(--color-border);border-radius:var(--border-radius-lg);overflow:hidden;background-color:var(--color-surface);color:var(--color-text-primary);font-family:var(--font-family-sans, sans-serif)}.lc-chat--borderless{border:none;border-radius:0}.lc-chat--width-full{--lc-chat-content-width: 100%}.lc-chat__header{display:flex;align-items:center;justify-content:space-between;padding:var(--lc-chat-header-pad-block) var(--spacing-4);border-bottom:1px solid var(--color-divider);background:var(--color-surface)}.lc-chat__title{font-size:var(--font-size-sm, .875rem);font-weight:var(--font-weight-semibold, 600);color:var(--color-text-primary)}.lc-chat__streaming-badge{font-size:var(--font-size-xs, .6875rem);padding:.125rem .5rem;background:color-mix(in srgb,var(--color-primary-500) 15%,transparent);color:var(--color-primary-500);border-radius:var(--border-radius-full, 1rem);font-weight:var(--font-weight-medium, 500);animation:pulse-badge 1.5s infinite}@keyframes pulse-badge{0%,to{opacity:1}50%{opacity:.6}}.lc-chat__messages{flex:1;overflow-y:auto;display:flex;flex-direction:column;padding-block:var(--lc-chat-messages-pad-block);padding-inline:var(--lc-chat-messages-pad-inline)}.lc-chat__thread{position:relative;width:100%;max-width:var(--lc-chat-content-width, 46rem);margin-inline:auto;flex:1 1 auto;min-height:0;display:flex;flex-direction:column;gap:var(--lc-chat-thread-gap)}.lc-chat__messages--anchor-bottom .lc-chat__thread>.lc-chat__message:first-child{margin-top:auto}.lc-chat__message{position:relative;display:flex;align-items:stretch;gap:var(--spacing-3, .75rem);align-self:stretch;max-width:100%}.lc-chat__message--user{flex-direction:column;align-items:flex-end;gap:var(--spacing-1, .25rem)}.lc-chat__message--user.lc-chat__message--avatar{display:grid;grid-template-columns:minmax(0,1fr) auto;grid-template-areas:\"bubble avatar\" \"time avatar\";column-gap:var(--spacing-2, .5rem);align-items:start}.lc-chat__message--user.lc-chat__message--avatar>.lc-chat__bubble{grid-area:bubble;justify-self:end}.lc-chat__message--user.lc-chat__message--avatar>.lc-chat__time--user{grid-area:time;justify-self:end}.lc-chat__message--user.lc-chat__message--avatar>.lc-chat__marker--user{grid-area:avatar}.lc-chat__marker{position:relative;z-index:1;flex-shrink:0;width:.875rem;display:flex;flex-direction:column;align-items:center}.lc-chat__marker:before{content:\"\";position:absolute;left:50%;top:.55rem;bottom:calc(-1 * var(--lc-chat-thread-gap));width:1.5px;transform:translate(-50%);background:var(--color-divider);z-index:-1}.lc-chat__message:last-child .lc-chat__marker:before{display:none}.lc-chat__dot{position:relative;z-index:1;width:.625rem;height:.625rem;margin-top:.25rem;border-radius:50%;background:var(--color-text-tertiary);box-shadow:0 0 0 3px var(--color-surface)}.lc-chat__dot--agent{background:var(--color-primary-500)}.lc-chat__dot--system{background:var(--color-text-tertiary);opacity:.6}.lc-chat__message--streaming .lc-chat__dot--agent{animation:dot-pulse 1.4s ease-out infinite}@keyframes dot-pulse{0%{box-shadow:0 0 0 3px var(--color-surface),0 0 0 3px color-mix(in srgb,var(--color-primary-500) 45%,transparent)}70%,to{box-shadow:0 0 0 3px var(--color-surface),0 0 0 9px color-mix(in srgb,var(--color-primary-500) 0%,transparent)}}.lc-chat__avatar-img{width:1.5rem;height:1.5rem;border-radius:50%;object-fit:cover;box-shadow:0 0 0 3px var(--color-surface)}.lc-chat__marker--user{width:auto}.lc-chat__marker--user:before{display:none}.lc-chat__monogram{display:inline-flex;align-items:center;justify-content:center;width:1.5rem;height:1.5rem;border-radius:50%;background:color-mix(in srgb,var(--color-primary-500) 18%,var(--color-surface-2));color:var(--color-on-primary-subtle);font-size:var(--font-size-xs, .75rem);font-weight:var(--font-weight-semibold, 600);line-height:1;box-shadow:0 0 0 3px var(--color-surface)}.lc-chat__status-icon{position:relative;z-index:1;display:inline-flex;align-items:center;justify-content:center;width:1rem;height:1rem;margin-top:.0625rem;border-radius:50%;background:var(--color-surface);box-shadow:0 0 0 2px var(--color-surface)}.lc-chat__sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}.lc-chat__bubble{flex:1;min-width:0;font-size:var(--lc-chat-bubble-font);line-height:var(--lc-chat-bubble-line);word-break:break-word;color:var(--color-text-primary)}.lc-chat__message--user .lc-chat__bubble{position:relative;z-index:1;flex:0 1 auto;max-width:min(85%,34rem);padding:var(--lc-chat-bubble-pad-block) var(--lc-chat-bubble-pad-inline);border:1px solid color-mix(in srgb,var(--color-primary-500) 22%,transparent);border-radius:var(--border-radius-lg);background:color-mix(in srgb,var(--color-primary-500) 10%,var(--color-surface-2))}.lc-chat__message--agent .lc-chat__bubble{padding:0;background:transparent}.lc-chat__message--system .lc-chat__bubble{padding:0;background:transparent;color:var(--color-text-tertiary);font-size:var(--font-size-sm, .8125rem)}.lc-chat__meta{display:flex;align-items:baseline;justify-content:space-between;gap:var(--spacing-2, .5rem);margin-bottom:var(--spacing-1, .25rem)}.lc-chat__meta .lc-chat__name{margin-bottom:0}.lc-chat__meta .lc-chat__time{margin-top:0}.lc-chat__name{font-size:var(--font-size-xs, .75rem);font-weight:var(--font-weight-semibold, 600);color:var(--color-text-secondary);margin-bottom:var(--spacing-1, .25rem)}.lc-chat__content{white-space:pre-wrap}.lc-chat__cursor{display:none}.lc-chat__cursor--visible{display:inline-block;width:2px;height:1em;background:currentColor;margin-left:1px;vertical-align:text-bottom;animation:blink-cursor .8s step-end infinite}@keyframes blink-cursor{0%,to{opacity:1}50%{opacity:0}}.lc-chat__time{font-size:var(--font-size-xs, .75rem);color:var(--color-text-tertiary);margin-top:var(--spacing-1, .25rem);flex-shrink:0}.lc-chat__time--tight{margin-top:0}.lc-chat__time--user{margin-top:0;padding-inline:var(--spacing-1, .25rem)}.lc-chat__typing{display:flex;gap:.25rem;padding:.25rem 0}.lc-chat__typing span{width:.375rem;height:.375rem;border-radius:50%;background:var(--color-text-tertiary);animation:typing-bounce 1.4s ease-in-out infinite}.lc-chat__typing span:nth-child(2){animation-delay:.2s}.lc-chat__typing span:nth-child(3){animation-delay:.4s}@keyframes typing-bounce{0%,60%,to{transform:translateY(0)}30%{transform:translateY(-.375rem)}}.lc-chat__input-area{padding:var(--lc-chat-input-area-pad);border-top:1px solid var(--color-divider);background:var(--color-surface)}.lc-chat__composer{width:100%;max-width:var(--lc-chat-content-width, 46rem);margin-inline:auto;display:flex;flex-direction:column;gap:var(--spacing-2, .5rem);padding:var(--lc-chat-composer-pad);background:var(--color-surface-2);border:1px solid var(--color-border);border-radius:var(--border-radius-xl);transition:border-color .15s,box-shadow .15s}.lc-chat__composer:focus-within{border-color:var(--color-primary-500);box-shadow:var(--elevation-1)}.lc-chat__input{display:block;width:100%;box-sizing:border-box;resize:none;border:none;background:transparent;padding:var(--spacing-1, .25rem) var(--spacing-2, .5rem);font-size:var(--font-size-base, .875rem);font-family:inherit;line-height:var(--line-height-normal, 1.4);color:var(--color-text-primary);outline:none;height:auto;max-height:12rem;overflow-y:auto}.lc-chat__input:disabled{opacity:.5;cursor:not-allowed}.lc-chat__input::placeholder{color:var(--color-text-tertiary)}.lc-chat__composer-actions{display:flex;align-items:center;gap:var(--spacing-2, .5rem)}.lc-chat__send-btn{position:relative;display:inline-flex;align-items:center;justify-content:center;width:2rem;height:2rem;margin-left:auto;border:none;border-radius:var(--border-radius-md);background:var(--color-primary-fill);color:var(--color-on-primary);cursor:pointer;flex-shrink:0;transition:background .15s,opacity .15s}.lc-chat__send-btn:before{content:\"\";position:absolute;inset:calc((2rem - var(--size-min-touch-height, 2.75rem)) / 2)}.lc-chat__send-btn:hover:not(:disabled){background:var(--color-primary-fill-hover)}.lc-chat__send-btn:disabled{opacity:.4;cursor:not-allowed}.lc-chat__send-btn:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:2px}.lc-chat__file-input{display:none}.lc-chat__attach-btn{position:relative;display:inline-flex;align-items:center;justify-content:center;width:2rem;height:2rem;border:none;border-radius:var(--border-radius-md);background:transparent;color:var(--color-text-tertiary);cursor:pointer;flex-shrink:0;transition:background .15s,color .15s}.lc-chat__attach-btn:before{content:\"\";position:absolute;inset:calc((2rem - var(--size-min-touch-height, 2.75rem)) / 2)}.lc-chat__attach-btn:hover:not(:disabled){background:var(--color-surface-hover);color:var(--color-text-primary)}.lc-chat__attach-btn:disabled{opacity:.4;cursor:not-allowed}.lc-chat__attach-btn:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:2px}.lc-chat__pending-attachments{display:flex;flex-wrap:wrap;gap:.875rem .375rem}.lc-chat__pending-attachment{display:inline-flex;align-items:center;gap:.375rem;padding:.25rem .375rem .25rem .5rem;background:var(--color-surface);border:1px solid var(--color-border);border-radius:var(--border-radius-md, .5rem);font-size:var(--font-size-xs, .75rem);color:var(--color-text-primary);max-width:16rem}.lc-chat__pending-thumb{width:1.75rem;height:1.75rem;object-fit:cover;border-radius:.25rem;flex-shrink:0}.lc-chat__pending-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:9rem}.lc-chat__pending-size{color:var(--color-text-tertiary);font-variant-numeric:tabular-nums}.lc-chat__pending-remove{position:relative;display:inline-flex;align-items:center;justify-content:center;width:1.25rem;height:1.25rem;border:none;border-radius:50%;background:transparent;color:var(--color-text-tertiary);cursor:pointer;flex-shrink:0}.lc-chat__pending-remove:before{content:\"\";position:absolute;inset:calc((1.25rem - var(--size-min-touch-height, 2.75rem)) / 2)}.lc-chat__pending-remove:hover{background:var(--color-surface-hover);color:var(--color-text-primary)}.lc-chat__pending-remove:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:2px}.lc-chat__attachments{display:flex;flex-wrap:wrap;gap:.375rem;margin-top:.5rem}.lc-chat__attachment{display:inline-flex;align-items:center;gap:.375rem;text-decoration:none;color:inherit;font-size:var(--font-size-xs, .75rem)}.lc-chat__attachment--file{padding:.25rem .5rem;background:color-mix(in srgb,currentColor 8%,transparent);border-radius:var(--border-radius-md, .375rem);max-width:16rem}.lc-chat__attachment--file:hover{background:color-mix(in srgb,currentColor 16%,transparent)}.lc-chat__attachment--image img{max-width:12rem;max-height:8rem;border-radius:var(--border-radius-md, .375rem);object-fit:cover;display:block}.lc-chat__attachment:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:2px}.lc-chat__attachment-icon{flex-shrink:0}.lc-chat__attachment-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.lc-chat__attachment-size{opacity:.7;font-variant-numeric:tabular-nums}@media(forced-colors:active){.lc-chat__send-btn:focus-visible,.lc-chat__attach-btn:focus-visible,.lc-chat__pending-remove:focus-visible,.lc-chat__attachment:focus-visible{outline-color:Highlight}}\n"],
474
474
  dependencies: [
475
475
  {
476
476
  kind: "directive",
@@ -559,7 +559,7 @@ i0.ɵɵngDeclareClassMetadata({
559
559
  ])],
560
560
  changeDetection: ChangeDetectionStrategy.OnPush,
561
561
  template: "<div\n class=\"lc-chat\"\n [class.lc-chat--borderless]=\"!bordered()\"\n [class.lc-chat--width-narrow]=\"contentWidth() === 'narrow'\"\n [class.lc-chat--width-full]=\"contentWidth() === 'full'\"\n>\n @if (showHeader()) {\n <div class=\"lc-chat__header\">\n <span class=\"lc-chat__title\">{{ title() }}</span>\n @if (isStreaming()) {\n <span class=\"lc-chat__streaming-badge\">{{ streamingLabel() }}</span>\n }\n </div>\n }\n\n <div\n class=\"lc-chat__messages\"\n [class.lc-chat__messages--anchor-bottom]=\"messageAnchor() === 'bottom'\"\n #scrollContainer\n >\n <div class=\"lc-chat__thread\">\n @for (msg of formattedMessages(); track msg.id) {\n <div\n class=\"lc-chat__message\"\n [class.lc-chat__message--user]=\"msg.role === 'user'\"\n [class.lc-chat__message--agent]=\"msg.role === 'agent'\"\n [class.lc-chat__message--system]=\"msg.role === 'system'\"\n [class.lc-chat__message--avatar]=\"showUserAvatar(msg)\"\n [class.lc-chat__message--streaming]=\"msg.streaming\"\n [attr.role]=\"msg.status === 'error' ? 'alert' : null\"\n [attr.aria-live]=\"statusAriaLive(msg.status)\"\n >\n @if ((msg.role !== 'user' && (showAvatars() || isSemanticStatus(msg.status))) || showUserAvatar(msg)) {\n <div class=\"lc-chat__marker\" [class.lc-chat__marker--user]=\"msg.role === 'user'\">\n @if (isSemanticStatus(msg.status) && msg.role !== 'user') {\n <span class=\"lc-chat__status-icon\">\n <lc-icon [name]=\"statusIcon(msg.status)\" size=\"xs\" [color]=\"statusColor(msg.status)\" [decorative]=\"true\" />\n </span>\n } @else if (msg.avatar) {\n <img [src]=\"msg.avatar\" [alt]=\"msg.name || msg.role\" class=\"lc-chat__avatar-img\" />\n } @else if (msg.role === 'user') {\n <span class=\"lc-chat__monogram\" [attr.aria-label]=\"msg.name\">{{ initials(msg.name) }}</span>\n } @else {\n <span\n class=\"lc-chat__dot\"\n [class.lc-chat__dot--agent]=\"msg.role === 'agent'\"\n [class.lc-chat__dot--system]=\"msg.role === 'system'\"\n ></span>\n }\n </div>\n }\n\n <div class=\"lc-chat__bubble\" [class.lc-chat__bubble--streaming]=\"msg.streaming\">\n @if (msg.name && msg.role !== 'user') {\n @if (showTimestamps() && msg.timestamp) {\n <div class=\"lc-chat__meta lc-chat__meta--agent\">\n <span class=\"lc-chat__name\">{{ msg.name }}</span>\n <span class=\"lc-chat__time\">{{ formatTime(msg.timestamp) }}</span>\n </div>\n } @else {\n <div class=\"lc-chat__name\">{{ msg.name }}</div>\n }\n }\n <div class=\"lc-chat__content\">\n @if (isSemanticStatus(msg.status)) {\n <span class=\"lc-chat__sr-only\">{{ statusLabel(msg.status) }} </span>\n }\n @if (messageTemplate) {\n <ng-container *ngTemplateOutlet=\"messageTemplate; context: { $implicit: msg }\" />\n } @else if (shouldRenderMarkdown(msg.role)) {\n <lc-markdown [content]=\"msg.content\" variant=\"chat\" />\n } @else {\n {{ msg.content }}\n }\n <span class=\"lc-chat__cursor\" [class.lc-chat__cursor--visible]=\"msg.streaming\"></span>\n </div>\n @if (msg.attachments?.length) {\n <div class=\"lc-chat__attachments\">\n @for (att of msg.attachments; track att.id) {\n @if (isImage(att) && att.url) {\n <a class=\"lc-chat__attachment lc-chat__attachment--image\" [href]=\"att.url\" target=\"_blank\" rel=\"noopener\">\n <img [src]=\"att.url\" [alt]=\"att.name\" />\n </a>\n } @else {\n <a\n class=\"lc-chat__attachment lc-chat__attachment--file\"\n [href]=\"att.url || null\"\n [attr.download]=\"att.url ? att.name : null\"\n target=\"_blank\"\n rel=\"noopener\"\n >\n <svg class=\"lc-chat__attachment-icon\" width=\"16\" height=\"16\" viewBox=\"0 0 20 20\" fill=\"none\" aria-hidden=\"true\">\n <path d=\"M6 2.5h6L16 6.5v10A1.5 1.5 0 0 1 14.5 18h-9A1.5 1.5 0 0 1 4 16.5v-12A1.5 1.5 0 0 1 5.5 3H6V2.5Z\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linejoin=\"round\"/>\n <path d=\"M12 2.5V6.5H16\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linejoin=\"round\"/>\n </svg>\n <span class=\"lc-chat__attachment-name\">{{ att.name }}</span>\n @if (att.size) {\n <span class=\"lc-chat__attachment-size\">{{ formatBytes(att.size) }}</span>\n }\n </a>\n }\n }\n </div>\n }\n @if (showTimestamps() && msg.timestamp && msg.role !== 'user' && !msg.name) {\n <div class=\"lc-chat__time lc-chat__time--tight\">{{ formatTime(msg.timestamp) }}</div>\n }\n </div>\n @if (showTimestamps() && msg.timestamp && msg.role === 'user') {\n <div class=\"lc-chat__time lc-chat__time--user\">{{ formatTime(msg.timestamp) }}</div>\n }\n </div>\n }\n\n @if (isStreaming() && !(formattedMessages().length && formattedMessages()[formattedMessages().length - 1].streaming)) {\n <div class=\"lc-chat__message lc-chat__message--agent\">\n @if (showAvatars()) {\n <div class=\"lc-chat__marker\">\n <span class=\"lc-chat__dot lc-chat__dot--agent\"></span>\n </div>\n }\n <div class=\"lc-chat__bubble\">\n <div class=\"lc-chat__typing\">\n <span></span><span></span><span></span>\n </div>\n </div>\n </div>\n }\n </div>\n </div>\n\n <!-- Announces the latest completed non-user turn (see `announcement`). -->\n <div class=\"lc-chat__sr-only lc-chat__announcer\" aria-live=\"polite\" aria-atomic=\"true\">{{ announcement() }}</div>\n\n <div class=\"lc-chat__input-area\">\n <div class=\"lc-chat__composer\">\n @if (allowFileUpload() && pendingAttachments().length) {\n <div class=\"lc-chat__pending-attachments\">\n @for (att of pendingAttachments(); track att.id) {\n <div class=\"lc-chat__pending-attachment\" [class.lc-chat__pending-attachment--image]=\"isImage(att)\">\n @if (isImage(att) && att.url) {\n <img class=\"lc-chat__pending-thumb\" [src]=\"att.url\" [alt]=\"att.name\" />\n } @else {\n <svg class=\"lc-chat__attachment-icon\" width=\"16\" height=\"16\" viewBox=\"0 0 20 20\" fill=\"none\" aria-hidden=\"true\">\n <path d=\"M6 2.5h6L16 6.5v10A1.5 1.5 0 0 1 14.5 18h-9A1.5 1.5 0 0 1 4 16.5v-12A1.5 1.5 0 0 1 5.5 3H6V2.5Z\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linejoin=\"round\"/>\n <path d=\"M12 2.5V6.5H16\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linejoin=\"round\"/>\n </svg>\n }\n <span class=\"lc-chat__pending-name\">{{ att.name }}</span>\n @if (att.size) {\n <span class=\"lc-chat__pending-size\">{{ formatBytes(att.size) }}</span>\n }\n <button\n type=\"button\"\n class=\"lc-chat__pending-remove\"\n (click)=\"removeAttachment(att.id)\"\n [attr.aria-label]=\"removeAttachmentAriaLabel() + ' ' + att.name\"\n >\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\" aria-hidden=\"true\">\n <path d=\"M3 3l6 6M9 3l-6 6\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\"/>\n </svg>\n </button>\n </div>\n }\n </div>\n }\n\n <label class=\"lc-chat__sr-only\" [for]=\"inputId\">{{ inputLabel() }}</label>\n <textarea\n #composerInput\n [id]=\"inputId\"\n class=\"lc-chat__input\"\n [placeholder]=\"placeholder()\"\n [value]=\"inputValue()\"\n [disabled]=\"disabled()\"\n (input)=\"onInput($event)\"\n (keydown)=\"onKeydown($event)\"\n rows=\"1\"\n ></textarea>\n\n <div class=\"lc-chat__composer-actions\">\n @if (allowFileUpload()) {\n <input\n #fileInput\n type=\"file\"\n class=\"lc-chat__file-input\"\n [accept]=\"accept() || null\"\n [multiple]=\"multiple()\"\n (change)=\"onFilesSelected($event)\"\n />\n <button\n type=\"button\"\n class=\"lc-chat__attach-btn\"\n [disabled]=\"disabled()\"\n (click)=\"openFilePicker()\"\n [attr.aria-label]=\"attachAriaLabel()\"\n >\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" fill=\"none\" aria-hidden=\"true\">\n <path d=\"M14.5 9.5l-5 5a3 3 0 0 1-4.243-4.243l6.364-6.364a2 2 0 0 1 2.829 2.829l-6.364 6.364a1 1 0 1 1-1.415-1.415L11.5 6.5\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </button>\n }\n <button\n class=\"lc-chat__send-btn\"\n [disabled]=\"(!inputValue().trim() && !pendingAttachments().length) || disabled()\"\n (click)=\"send()\"\n [attr.aria-label]=\"sendAriaLabel()\"\n >\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" fill=\"none\">\n <path d=\"M3 10l7-7m0 0l7 7m-7-7v14\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" transform=\"rotate(90 10 10)\"/>\n </svg>\n </button>\n </div>\n </div>\n </div>\n</div>\n",
562
- styles: [".lc-chat{--lc-chat-content-width: 46rem;--lc-chat-thread-gap: var(--spacing-3, .75rem);--lc-chat-messages-pad-block: var(--spacing-4, 1rem);--lc-chat-messages-pad-inline: var(--spacing-3, .75rem);--lc-chat-bubble-font: var(--font-size-sm, .875rem);--lc-chat-bubble-line: var(--line-height-normal, 1.5);--lc-chat-bubble-pad-block: var(--spacing-2, .5rem);--lc-chat-bubble-pad-inline: var(--spacing-3, .75rem);--lc-chat-header-pad-block: var(--spacing-2, .5rem);--lc-chat-input-area-pad: var(--spacing-3, .75rem);--lc-chat-composer-pad: var(--spacing-2, .5rem);display:flex;flex-direction:column;height:100%;min-height:20rem;border:1px solid var(--color-border);border-radius:var(--border-radius-lg);overflow:hidden;background-color:var(--color-surface);color:var(--color-text-primary);font-family:var(--font-family-sans, sans-serif)}.lc-chat--borderless{border:none;border-radius:0}.lc-chat--width-full{--lc-chat-content-width: 100%}.lc-chat__header{display:flex;align-items:center;justify-content:space-between;padding:var(--lc-chat-header-pad-block) var(--spacing-4);border-bottom:1px solid var(--color-divider);background:var(--color-surface)}.lc-chat__title{font-size:var(--font-size-sm, .875rem);font-weight:var(--font-weight-semibold, 600);color:var(--color-text-primary)}.lc-chat__streaming-badge{font-size:var(--font-size-xs, .6875rem);padding:.125rem .5rem;background:color-mix(in srgb,var(--color-primary-500) 15%,transparent);color:var(--color-primary-500);border-radius:var(--border-radius-full, 1rem);font-weight:var(--font-weight-medium, 500);animation:pulse-badge 1.5s infinite}@keyframes pulse-badge{0%,to{opacity:1}50%{opacity:.6}}.lc-chat__messages{flex:1;overflow-y:auto;display:flex;flex-direction:column;padding-block:var(--lc-chat-messages-pad-block);padding-inline:var(--lc-chat-messages-pad-inline)}.lc-chat__thread{position:relative;width:100%;max-width:var(--lc-chat-content-width, 46rem);margin-inline:auto;flex:1 1 auto;min-height:0;display:flex;flex-direction:column;gap:var(--lc-chat-thread-gap)}.lc-chat__messages--anchor-bottom .lc-chat__thread>.lc-chat__message:first-child{margin-top:auto}.lc-chat__message{position:relative;display:flex;align-items:stretch;gap:var(--spacing-3, .75rem);align-self:stretch;max-width:100%}.lc-chat__message--user{flex-direction:column;align-items:flex-end;gap:var(--spacing-1, .25rem)}.lc-chat__message--user.lc-chat__message--avatar{display:grid;grid-template-columns:minmax(0,1fr) auto;grid-template-areas:\"bubble avatar\" \"time avatar\";column-gap:var(--spacing-2, .5rem);align-items:start}.lc-chat__message--user.lc-chat__message--avatar>.lc-chat__bubble{grid-area:bubble;justify-self:end}.lc-chat__message--user.lc-chat__message--avatar>.lc-chat__time--user{grid-area:time;justify-self:end}.lc-chat__message--user.lc-chat__message--avatar>.lc-chat__marker--user{grid-area:avatar}.lc-chat__marker{position:relative;z-index:1;flex-shrink:0;width:.875rem;display:flex;flex-direction:column;align-items:center}.lc-chat__marker:before{content:\"\";position:absolute;left:50%;top:.55rem;bottom:calc(-1 * var(--lc-chat-thread-gap));width:1.5px;transform:translate(-50%);background:var(--color-divider);z-index:-1}.lc-chat__message:last-child .lc-chat__marker:before{display:none}.lc-chat__dot{position:relative;z-index:1;width:.625rem;height:.625rem;margin-top:.25rem;border-radius:50%;background:var(--color-text-tertiary);box-shadow:0 0 0 3px var(--color-surface)}.lc-chat__dot--agent{background:var(--color-primary-500)}.lc-chat__dot--system{background:var(--color-text-tertiary);opacity:.6}.lc-chat__message--streaming .lc-chat__dot--agent{animation:dot-pulse 1.4s ease-out infinite}@keyframes dot-pulse{0%{box-shadow:0 0 0 3px var(--color-surface),0 0 0 3px color-mix(in srgb,var(--color-primary-500) 45%,transparent)}70%,to{box-shadow:0 0 0 3px var(--color-surface),0 0 0 9px color-mix(in srgb,var(--color-primary-500) 0%,transparent)}}.lc-chat__avatar-img{width:1.5rem;height:1.5rem;border-radius:50%;object-fit:cover;box-shadow:0 0 0 3px var(--color-surface)}.lc-chat__marker--user{width:auto}.lc-chat__marker--user:before{display:none}.lc-chat__monogram{display:inline-flex;align-items:center;justify-content:center;width:1.5rem;height:1.5rem;border-radius:50%;background:color-mix(in srgb,var(--color-primary-500) 18%,var(--color-surface-2));color:var(--color-on-primary-subtle);font-size:var(--font-size-xs, .75rem);font-weight:var(--font-weight-semibold, 600);line-height:1;box-shadow:0 0 0 3px var(--color-surface)}.lc-chat__status-icon{position:relative;z-index:1;display:inline-flex;align-items:center;justify-content:center;width:1rem;height:1rem;margin-top:.0625rem;border-radius:50%;background:var(--color-surface);box-shadow:0 0 0 2px var(--color-surface)}.lc-chat__sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}.lc-chat__bubble{flex:1;min-width:0;font-size:var(--lc-chat-bubble-font);line-height:var(--lc-chat-bubble-line);word-break:break-word;color:var(--color-text-primary)}.lc-chat__message--user .lc-chat__bubble{position:relative;z-index:1;flex:0 1 auto;max-width:min(85%,34rem);padding:var(--lc-chat-bubble-pad-block) var(--lc-chat-bubble-pad-inline);border:1px solid color-mix(in srgb,var(--color-primary-500) 22%,transparent);border-radius:var(--border-radius-lg);background:color-mix(in srgb,var(--color-primary-500) 10%,var(--color-surface-2))}.lc-chat__message--agent .lc-chat__bubble{padding:0;background:transparent}.lc-chat__message--system .lc-chat__bubble{padding:0;background:transparent;color:var(--color-text-tertiary);font-size:var(--font-size-sm, .8125rem)}.lc-chat__meta{display:flex;align-items:baseline;justify-content:space-between;gap:var(--spacing-2, .5rem);margin-bottom:var(--spacing-1, .25rem)}.lc-chat__meta .lc-chat__name{margin-bottom:0}.lc-chat__meta .lc-chat__time{margin-top:0}.lc-chat__name{font-size:var(--font-size-xs, .75rem);font-weight:var(--font-weight-semibold, 600);color:var(--color-text-secondary);margin-bottom:var(--spacing-1, .25rem)}.lc-chat__content{white-space:pre-wrap}.lc-chat__cursor{display:none}.lc-chat__cursor--visible{display:inline-block;width:2px;height:1em;background:currentColor;margin-left:1px;vertical-align:text-bottom;animation:blink-cursor .8s step-end infinite}@keyframes blink-cursor{0%,to{opacity:1}50%{opacity:0}}.lc-chat__time{font-size:var(--font-size-xs, .75rem);color:var(--color-text-tertiary);margin-top:var(--spacing-1, .25rem);flex-shrink:0}.lc-chat__time--tight{margin-top:0}.lc-chat__time--user{margin-top:0;padding-inline:var(--spacing-1, .25rem)}.lc-chat__typing{display:flex;gap:.25rem;padding:.25rem 0}.lc-chat__typing span{width:.375rem;height:.375rem;border-radius:50%;background:var(--color-text-tertiary);animation:typing-bounce 1.4s ease-in-out infinite}.lc-chat__typing span:nth-child(2){animation-delay:.2s}.lc-chat__typing span:nth-child(3){animation-delay:.4s}@keyframes typing-bounce{0%,60%,to{transform:translateY(0)}30%{transform:translateY(-.375rem)}}.lc-chat__input-area{padding:var(--lc-chat-input-area-pad);border-top:1px solid var(--color-divider);background:var(--color-surface)}.lc-chat__composer{width:100%;max-width:var(--lc-chat-content-width, 46rem);margin-inline:auto;display:flex;flex-direction:column;gap:var(--spacing-2, .5rem);padding:var(--lc-chat-composer-pad);background:var(--color-surface-2);border:1px solid var(--color-border);border-radius:var(--border-radius-xl);transition:border-color .15s,box-shadow .15s}.lc-chat__composer:focus-within{border-color:var(--color-primary-500);box-shadow:var(--elevation-1)}.lc-chat__input{display:block;width:100%;box-sizing:border-box;resize:none;border:none;background:transparent;padding:var(--spacing-1, .25rem) var(--spacing-2, .5rem);font-size:var(--font-size-base, .875rem);font-family:inherit;line-height:var(--line-height-normal, 1.4);color:var(--color-text-primary);outline:none;height:auto;max-height:12rem;overflow-y:auto}.lc-chat__input:disabled{opacity:.5;cursor:not-allowed}.lc-chat__input::placeholder{color:var(--color-text-tertiary)}.lc-chat__composer-actions{display:flex;align-items:center;gap:var(--spacing-2, .5rem)}.lc-chat__send-btn{position:relative;display:inline-flex;align-items:center;justify-content:center;width:2rem;height:2rem;margin-left:auto;border:none;border-radius:var(--border-radius-md);background:var(--color-primary-fill);color:var(--color-on-primary);cursor:pointer;flex-shrink:0;transition:background .15s,opacity .15s}.lc-chat__send-btn:before{content:\"\";position:absolute;inset:calc((2rem - var(--size-min-touch-height, 2.75rem)) / 2)}.lc-chat__send-btn:hover:not(:disabled){background:var(--color-primary-fill-hover)}.lc-chat__send-btn:disabled{opacity:.4;cursor:not-allowed}.lc-chat__send-btn:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:2px}.lc-chat__file-input{display:none}.lc-chat__attach-btn{position:relative;display:inline-flex;align-items:center;justify-content:center;width:2rem;height:2rem;border:none;border-radius:var(--border-radius-md);background:transparent;color:var(--color-text-tertiary);cursor:pointer;flex-shrink:0;transition:background .15s,color .15s}.lc-chat__attach-btn:before{content:\"\";position:absolute;inset:calc((2rem - var(--size-min-touch-height, 2.75rem)) / 2)}.lc-chat__attach-btn:hover:not(:disabled){background:var(--color-surface-hover);color:var(--color-text-primary)}.lc-chat__attach-btn:disabled{opacity:.4;cursor:not-allowed}.lc-chat__attach-btn:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:2px}.lc-chat__pending-attachments{display:flex;flex-wrap:wrap;gap:.375rem}.lc-chat__pending-attachment{display:inline-flex;align-items:center;gap:.375rem;padding:.25rem .375rem .25rem .5rem;background:var(--color-surface);border:1px solid var(--color-border);border-radius:var(--border-radius-md, .5rem);font-size:var(--font-size-xs, .75rem);color:var(--color-text-primary);max-width:16rem}.lc-chat__pending-thumb{width:1.75rem;height:1.75rem;object-fit:cover;border-radius:.25rem;flex-shrink:0}.lc-chat__pending-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:9rem}.lc-chat__pending-size{color:var(--color-text-tertiary);font-variant-numeric:tabular-nums}.lc-chat__pending-remove{display:inline-flex;align-items:center;justify-content:center;width:1.25rem;height:1.25rem;border:none;border-radius:50%;background:transparent;color:var(--color-text-tertiary);cursor:pointer;flex-shrink:0}.lc-chat__pending-remove:hover{background:var(--color-surface-hover);color:var(--color-text-primary)}.lc-chat__pending-remove:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:2px}.lc-chat__attachments{display:flex;flex-wrap:wrap;gap:.375rem;margin-top:.5rem}.lc-chat__attachment{display:inline-flex;align-items:center;gap:.375rem;text-decoration:none;color:inherit;font-size:var(--font-size-xs, .75rem)}.lc-chat__attachment--file{padding:.25rem .5rem;background:color-mix(in srgb,currentColor 8%,transparent);border-radius:var(--border-radius-md, .375rem);max-width:16rem}.lc-chat__attachment--file:hover{background:color-mix(in srgb,currentColor 16%,transparent)}.lc-chat__attachment--image img{max-width:12rem;max-height:8rem;border-radius:var(--border-radius-md, .375rem);object-fit:cover;display:block}.lc-chat__attachment:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:2px}.lc-chat__attachment-icon{flex-shrink:0}.lc-chat__attachment-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.lc-chat__attachment-size{opacity:.7;font-variant-numeric:tabular-nums}@media(forced-colors:active){.lc-chat__send-btn:focus-visible,.lc-chat__attach-btn:focus-visible,.lc-chat__pending-remove:focus-visible,.lc-chat__attachment:focus-visible{outline-color:Highlight}}\n"]
562
+ styles: [".lc-chat{--lc-chat-content-width: 46rem;--lc-chat-thread-gap: var(--spacing-3, .75rem);--lc-chat-messages-pad-block: var(--spacing-4, 1rem);--lc-chat-messages-pad-inline: var(--spacing-3, .75rem);--lc-chat-bubble-font: var(--font-size-sm, .875rem);--lc-chat-bubble-line: var(--line-height-normal, 1.5);--lc-chat-bubble-pad-block: var(--spacing-2, .5rem);--lc-chat-bubble-pad-inline: var(--spacing-3, .75rem);--lc-chat-header-pad-block: var(--spacing-2, .5rem);--lc-chat-input-area-pad: var(--spacing-3, .75rem);--lc-chat-composer-pad: var(--spacing-2, .5rem);display:flex;flex-direction:column;height:100%;min-height:20rem;border:1px solid var(--color-border);border-radius:var(--border-radius-lg);overflow:hidden;background-color:var(--color-surface);color:var(--color-text-primary);font-family:var(--font-family-sans, sans-serif)}.lc-chat--borderless{border:none;border-radius:0}.lc-chat--width-full{--lc-chat-content-width: 100%}.lc-chat__header{display:flex;align-items:center;justify-content:space-between;padding:var(--lc-chat-header-pad-block) var(--spacing-4);border-bottom:1px solid var(--color-divider);background:var(--color-surface)}.lc-chat__title{font-size:var(--font-size-sm, .875rem);font-weight:var(--font-weight-semibold, 600);color:var(--color-text-primary)}.lc-chat__streaming-badge{font-size:var(--font-size-xs, .6875rem);padding:.125rem .5rem;background:color-mix(in srgb,var(--color-primary-500) 15%,transparent);color:var(--color-primary-500);border-radius:var(--border-radius-full, 1rem);font-weight:var(--font-weight-medium, 500);animation:pulse-badge 1.5s infinite}@keyframes pulse-badge{0%,to{opacity:1}50%{opacity:.6}}.lc-chat__messages{flex:1;overflow-y:auto;display:flex;flex-direction:column;padding-block:var(--lc-chat-messages-pad-block);padding-inline:var(--lc-chat-messages-pad-inline)}.lc-chat__thread{position:relative;width:100%;max-width:var(--lc-chat-content-width, 46rem);margin-inline:auto;flex:1 1 auto;min-height:0;display:flex;flex-direction:column;gap:var(--lc-chat-thread-gap)}.lc-chat__messages--anchor-bottom .lc-chat__thread>.lc-chat__message:first-child{margin-top:auto}.lc-chat__message{position:relative;display:flex;align-items:stretch;gap:var(--spacing-3, .75rem);align-self:stretch;max-width:100%}.lc-chat__message--user{flex-direction:column;align-items:flex-end;gap:var(--spacing-1, .25rem)}.lc-chat__message--user.lc-chat__message--avatar{display:grid;grid-template-columns:minmax(0,1fr) auto;grid-template-areas:\"bubble avatar\" \"time avatar\";column-gap:var(--spacing-2, .5rem);align-items:start}.lc-chat__message--user.lc-chat__message--avatar>.lc-chat__bubble{grid-area:bubble;justify-self:end}.lc-chat__message--user.lc-chat__message--avatar>.lc-chat__time--user{grid-area:time;justify-self:end}.lc-chat__message--user.lc-chat__message--avatar>.lc-chat__marker--user{grid-area:avatar}.lc-chat__marker{position:relative;z-index:1;flex-shrink:0;width:.875rem;display:flex;flex-direction:column;align-items:center}.lc-chat__marker:before{content:\"\";position:absolute;left:50%;top:.55rem;bottom:calc(-1 * var(--lc-chat-thread-gap));width:1.5px;transform:translate(-50%);background:var(--color-divider);z-index:-1}.lc-chat__message:last-child .lc-chat__marker:before{display:none}.lc-chat__dot{position:relative;z-index:1;width:.625rem;height:.625rem;margin-top:.25rem;border-radius:50%;background:var(--color-text-tertiary);box-shadow:0 0 0 3px var(--color-surface)}.lc-chat__dot--agent{background:var(--color-primary-500)}.lc-chat__dot--system{background:var(--color-text-tertiary);opacity:.6}.lc-chat__message--streaming .lc-chat__dot--agent{animation:dot-pulse 1.4s ease-out infinite}@keyframes dot-pulse{0%{box-shadow:0 0 0 3px var(--color-surface),0 0 0 3px color-mix(in srgb,var(--color-primary-500) 45%,transparent)}70%,to{box-shadow:0 0 0 3px var(--color-surface),0 0 0 9px color-mix(in srgb,var(--color-primary-500) 0%,transparent)}}.lc-chat__avatar-img{width:1.5rem;height:1.5rem;border-radius:50%;object-fit:cover;box-shadow:0 0 0 3px var(--color-surface)}.lc-chat__marker--user{width:auto}.lc-chat__marker--user:before{display:none}.lc-chat__monogram{display:inline-flex;align-items:center;justify-content:center;width:1.5rem;height:1.5rem;border-radius:50%;background:color-mix(in srgb,var(--color-primary-500) 18%,var(--color-surface-2));color:var(--color-on-primary-subtle);font-size:var(--font-size-xs, .75rem);font-weight:var(--font-weight-semibold, 600);line-height:1;box-shadow:0 0 0 3px var(--color-surface)}.lc-chat__status-icon{position:relative;z-index:1;display:inline-flex;align-items:center;justify-content:center;width:1rem;height:1rem;margin-top:.0625rem;border-radius:50%;background:var(--color-surface);box-shadow:0 0 0 2px var(--color-surface)}.lc-chat__sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}.lc-chat__bubble{flex:1;min-width:0;font-size:var(--lc-chat-bubble-font);line-height:var(--lc-chat-bubble-line);word-break:break-word;color:var(--color-text-primary)}.lc-chat__message--user .lc-chat__bubble{position:relative;z-index:1;flex:0 1 auto;max-width:min(85%,34rem);padding:var(--lc-chat-bubble-pad-block) var(--lc-chat-bubble-pad-inline);border:1px solid color-mix(in srgb,var(--color-primary-500) 22%,transparent);border-radius:var(--border-radius-lg);background:color-mix(in srgb,var(--color-primary-500) 10%,var(--color-surface-2))}.lc-chat__message--agent .lc-chat__bubble{padding:0;background:transparent}.lc-chat__message--system .lc-chat__bubble{padding:0;background:transparent;color:var(--color-text-tertiary);font-size:var(--font-size-sm, .8125rem)}.lc-chat__meta{display:flex;align-items:baseline;justify-content:space-between;gap:var(--spacing-2, .5rem);margin-bottom:var(--spacing-1, .25rem)}.lc-chat__meta .lc-chat__name{margin-bottom:0}.lc-chat__meta .lc-chat__time{margin-top:0}.lc-chat__name{font-size:var(--font-size-xs, .75rem);font-weight:var(--font-weight-semibold, 600);color:var(--color-text-secondary);margin-bottom:var(--spacing-1, .25rem)}.lc-chat__content{white-space:pre-wrap}.lc-chat__cursor{display:none}.lc-chat__cursor--visible{display:inline-block;width:2px;height:1em;background:currentColor;margin-left:1px;vertical-align:text-bottom;animation:blink-cursor .8s step-end infinite}@keyframes blink-cursor{0%,to{opacity:1}50%{opacity:0}}.lc-chat__time{font-size:var(--font-size-xs, .75rem);color:var(--color-text-tertiary);margin-top:var(--spacing-1, .25rem);flex-shrink:0}.lc-chat__time--tight{margin-top:0}.lc-chat__time--user{margin-top:0;padding-inline:var(--spacing-1, .25rem)}.lc-chat__typing{display:flex;gap:.25rem;padding:.25rem 0}.lc-chat__typing span{width:.375rem;height:.375rem;border-radius:50%;background:var(--color-text-tertiary);animation:typing-bounce 1.4s ease-in-out infinite}.lc-chat__typing span:nth-child(2){animation-delay:.2s}.lc-chat__typing span:nth-child(3){animation-delay:.4s}@keyframes typing-bounce{0%,60%,to{transform:translateY(0)}30%{transform:translateY(-.375rem)}}.lc-chat__input-area{padding:var(--lc-chat-input-area-pad);border-top:1px solid var(--color-divider);background:var(--color-surface)}.lc-chat__composer{width:100%;max-width:var(--lc-chat-content-width, 46rem);margin-inline:auto;display:flex;flex-direction:column;gap:var(--spacing-2, .5rem);padding:var(--lc-chat-composer-pad);background:var(--color-surface-2);border:1px solid var(--color-border);border-radius:var(--border-radius-xl);transition:border-color .15s,box-shadow .15s}.lc-chat__composer:focus-within{border-color:var(--color-primary-500);box-shadow:var(--elevation-1)}.lc-chat__input{display:block;width:100%;box-sizing:border-box;resize:none;border:none;background:transparent;padding:var(--spacing-1, .25rem) var(--spacing-2, .5rem);font-size:var(--font-size-base, .875rem);font-family:inherit;line-height:var(--line-height-normal, 1.4);color:var(--color-text-primary);outline:none;height:auto;max-height:12rem;overflow-y:auto}.lc-chat__input:disabled{opacity:.5;cursor:not-allowed}.lc-chat__input::placeholder{color:var(--color-text-tertiary)}.lc-chat__composer-actions{display:flex;align-items:center;gap:var(--spacing-2, .5rem)}.lc-chat__send-btn{position:relative;display:inline-flex;align-items:center;justify-content:center;width:2rem;height:2rem;margin-left:auto;border:none;border-radius:var(--border-radius-md);background:var(--color-primary-fill);color:var(--color-on-primary);cursor:pointer;flex-shrink:0;transition:background .15s,opacity .15s}.lc-chat__send-btn:before{content:\"\";position:absolute;inset:calc((2rem - var(--size-min-touch-height, 2.75rem)) / 2)}.lc-chat__send-btn:hover:not(:disabled){background:var(--color-primary-fill-hover)}.lc-chat__send-btn:disabled{opacity:.4;cursor:not-allowed}.lc-chat__send-btn:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:2px}.lc-chat__file-input{display:none}.lc-chat__attach-btn{position:relative;display:inline-flex;align-items:center;justify-content:center;width:2rem;height:2rem;border:none;border-radius:var(--border-radius-md);background:transparent;color:var(--color-text-tertiary);cursor:pointer;flex-shrink:0;transition:background .15s,color .15s}.lc-chat__attach-btn:before{content:\"\";position:absolute;inset:calc((2rem - var(--size-min-touch-height, 2.75rem)) / 2)}.lc-chat__attach-btn:hover:not(:disabled){background:var(--color-surface-hover);color:var(--color-text-primary)}.lc-chat__attach-btn:disabled{opacity:.4;cursor:not-allowed}.lc-chat__attach-btn:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:2px}.lc-chat__pending-attachments{display:flex;flex-wrap:wrap;gap:.875rem .375rem}.lc-chat__pending-attachment{display:inline-flex;align-items:center;gap:.375rem;padding:.25rem .375rem .25rem .5rem;background:var(--color-surface);border:1px solid var(--color-border);border-radius:var(--border-radius-md, .5rem);font-size:var(--font-size-xs, .75rem);color:var(--color-text-primary);max-width:16rem}.lc-chat__pending-thumb{width:1.75rem;height:1.75rem;object-fit:cover;border-radius:.25rem;flex-shrink:0}.lc-chat__pending-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:9rem}.lc-chat__pending-size{color:var(--color-text-tertiary);font-variant-numeric:tabular-nums}.lc-chat__pending-remove{position:relative;display:inline-flex;align-items:center;justify-content:center;width:1.25rem;height:1.25rem;border:none;border-radius:50%;background:transparent;color:var(--color-text-tertiary);cursor:pointer;flex-shrink:0}.lc-chat__pending-remove:before{content:\"\";position:absolute;inset:calc((1.25rem - var(--size-min-touch-height, 2.75rem)) / 2)}.lc-chat__pending-remove:hover{background:var(--color-surface-hover);color:var(--color-text-primary)}.lc-chat__pending-remove:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:2px}.lc-chat__attachments{display:flex;flex-wrap:wrap;gap:.375rem;margin-top:.5rem}.lc-chat__attachment{display:inline-flex;align-items:center;gap:.375rem;text-decoration:none;color:inherit;font-size:var(--font-size-xs, .75rem)}.lc-chat__attachment--file{padding:.25rem .5rem;background:color-mix(in srgb,currentColor 8%,transparent);border-radius:var(--border-radius-md, .375rem);max-width:16rem}.lc-chat__attachment--file:hover{background:color-mix(in srgb,currentColor 16%,transparent)}.lc-chat__attachment--image img{max-width:12rem;max-height:8rem;border-radius:var(--border-radius-md, .375rem);object-fit:cover;display:block}.lc-chat__attachment:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:2px}.lc-chat__attachment-icon{flex-shrink:0}.lc-chat__attachment-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.lc-chat__attachment-size{opacity:.7;font-variant-numeric:tabular-nums}@media(forced-colors:active){.lc-chat__send-btn:focus-visible,.lc-chat__attach-btn:focus-visible,.lc-chat__pending-remove:focus-visible,.lc-chat__attachment:focus-visible{outline-color:Highlight}}\n"]
563
563
  }]
564
564
  }],
565
565
  ctorParameters: () => [],