@camp2gether/c2g-ui 0.0.7

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.
Files changed (56) hide show
  1. package/README.md +95 -0
  2. package/charts/index.d.ts +199 -0
  3. package/fesm2022/camp2gether-c2g-ui-beach-animation-ipi3OoKW.mjs +54156 -0
  4. package/fesm2022/camp2gether-c2g-ui-beach-animation-ipi3OoKW.mjs.map +1 -0
  5. package/fesm2022/camp2gether-c2g-ui-camping-animation-DY6XWXyF.mjs +35807 -0
  6. package/fesm2022/camp2gether-c2g-ui-camping-animation-DY6XWXyF.mjs.map +1 -0
  7. package/fesm2022/camp2gether-c2g-ui-car-animation-DnDp7WfG.mjs +45189 -0
  8. package/fesm2022/camp2gether-c2g-ui-car-animation-DnDp7WfG.mjs.map +1 -0
  9. package/fesm2022/camp2gether-c2g-ui-car-driving-landscape-animation-CawNeMKD.mjs +43833 -0
  10. package/fesm2022/camp2gether-c2g-ui-car-driving-landscape-animation-CawNeMKD.mjs.map +1 -0
  11. package/fesm2022/camp2gether-c2g-ui-cat-love-animation-ewC7fZyY.mjs +30789 -0
  12. package/fesm2022/camp2gether-c2g-ui-cat-love-animation-ewC7fZyY.mjs.map +1 -0
  13. package/fesm2022/camp2gether-c2g-ui-charts.mjs +404 -0
  14. package/fesm2022/camp2gether-c2g-ui-charts.mjs.map +1 -0
  15. package/fesm2022/camp2gether-c2g-ui-checklist-animation-DqUkcLqI.mjs +19868 -0
  16. package/fesm2022/camp2gether-c2g-ui-checklist-animation-DqUkcLqI.mjs.map +1 -0
  17. package/fesm2022/camp2gether-c2g-ui-coffee-time-animation-DQilaE0A.mjs +6816 -0
  18. package/fesm2022/camp2gether-c2g-ui-coffee-time-animation-DQilaE0A.mjs.map +1 -0
  19. package/fesm2022/camp2gether-c2g-ui-error-404-pdjg-EHb.mjs +49742 -0
  20. package/fesm2022/camp2gether-c2g-ui-error-404-pdjg-EHb.mjs.map +1 -0
  21. package/fesm2022/camp2gether-c2g-ui-fishing-animation-DwE3IF-V.mjs +38941 -0
  22. package/fesm2022/camp2gether-c2g-ui-fishing-animation-DwE3IF-V.mjs.map +1 -0
  23. package/fesm2022/camp2gether-c2g-ui-layout.mjs +768 -0
  24. package/fesm2022/camp2gether-c2g-ui-layout.mjs.map +1 -0
  25. package/fesm2022/camp2gether-c2g-ui-maps.mjs +223 -0
  26. package/fesm2022/camp2gether-c2g-ui-maps.mjs.map +1 -0
  27. package/fesm2022/camp2gether-c2g-ui-mountain-search-animation-TebM1gS4.mjs +69245 -0
  28. package/fesm2022/camp2gether-c2g-ui-mountain-search-animation-TebM1gS4.mjs.map +1 -0
  29. package/fesm2022/camp2gether-c2g-ui-planning-animation-D8QSsZk6.mjs +28330 -0
  30. package/fesm2022/camp2gether-c2g-ui-planning-animation-D8QSsZk6.mjs.map +1 -0
  31. package/fesm2022/camp2gether-c2g-ui-presets.mjs +2855 -0
  32. package/fesm2022/camp2gether-c2g-ui-presets.mjs.map +1 -0
  33. package/fesm2022/camp2gether-c2g-ui-share-animation-qgqs-k59.mjs +59129 -0
  34. package/fesm2022/camp2gether-c2g-ui-share-animation-qgqs-k59.mjs.map +1 -0
  35. package/fesm2022/camp2gether-c2g-ui-summer-camp-animation-DPzirVNH.mjs +89317 -0
  36. package/fesm2022/camp2gether-c2g-ui-summer-camp-animation-DPzirVNH.mjs.map +1 -0
  37. package/fesm2022/camp2gether-c2g-ui-theme.mjs +479 -0
  38. package/fesm2022/camp2gether-c2g-ui-theme.mjs.map +1 -0
  39. package/fesm2022/camp2gether-c2g-ui-thinking-animation--X3er_pf.mjs +27929 -0
  40. package/fesm2022/camp2gether-c2g-ui-thinking-animation--X3er_pf.mjs.map +1 -0
  41. package/fesm2022/camp2gether-c2g-ui-walking-avocado-animation-CQMU2C9-.mjs +4064 -0
  42. package/fesm2022/camp2gether-c2g-ui-walking-avocado-animation-CQMU2C9-.mjs.map +1 -0
  43. package/fesm2022/camp2gether-c2g-ui-walking-orange-animation-CTJniCsF.mjs +3113 -0
  44. package/fesm2022/camp2gether-c2g-ui-walking-orange-animation-CTJniCsF.mjs.map +1 -0
  45. package/fesm2022/camp2gether-c2g-ui-weather-partly-cloudy-animation-Cnw3W4cS.mjs +1731 -0
  46. package/fesm2022/camp2gether-c2g-ui-weather-partly-cloudy-animation-Cnw3W4cS.mjs.map +1 -0
  47. package/fesm2022/camp2gether-c2g-ui.mjs +2099 -0
  48. package/fesm2022/camp2gether-c2g-ui.mjs.map +1 -0
  49. package/index.d.ts +578 -0
  50. package/layout/index.d.ts +443 -0
  51. package/maps/index.d.ts +62 -0
  52. package/package.json +51 -0
  53. package/presets/index.d.ts +1437 -0
  54. package/src/lib/styles/design-tokens.css +153 -0
  55. package/src/lib/styles/themes.scss +346 -0
  56. package/theme/index.d.ts +63 -0
@@ -0,0 +1,2855 @@
1
+ import * as i0 from '@angular/core';
2
+ import { input, output, signal, computed, ChangeDetectionStrategy, Component, effect, HostListener } from '@angular/core';
3
+ import * as i1 from '@angular/material/icon';
4
+ import { MatIconModule } from '@angular/material/icon';
5
+ import { AvatarComponent, BadgeComponent, ButtonComponent, RadioGroupComponent, CheckboxComponent, SelectComponent, InputComponent, TextareaComponent } from '@humbeldore/c2g-ui';
6
+ import * as i1$2 from '@angular/common';
7
+ import { CommonModule } from '@angular/common';
8
+ import * as i1$1 from '@angular/forms';
9
+ import { FormsModule } from '@angular/forms';
10
+ import { CdkMenu, CdkMenuItem, CdkMenuTrigger } from '@angular/cdk/menu';
11
+ import { LottieComponent } from 'ngx-lottie';
12
+
13
+ const DEFAULT_PACKING_LIST_LABEL_KEYS = {
14
+ searchPlaceholderKey: 'packingList.search.placeholder',
15
+ essentialsOnlyKey: 'packingList.filters.essentialsOnly',
16
+ showAllVisibilityKey: 'packingList.filters.visibility.all',
17
+ sharedVisibilityKey: 'packingList.filters.visibility.shared',
18
+ personalVisibilityKey: 'packingList.filters.visibility.personal',
19
+ privateVisibilityKey: 'packingList.filters.visibility.private',
20
+ privateSectionTitleKey: 'packingList.private.title',
21
+ emptyStateKey: 'packingList.empty',
22
+ categoryStatsKey: 'packingList.category.stats',
23
+ deleteConfirmKey: 'packingList.delete.confirm',
24
+ addItemKey: 'packingList.addItem',
25
+ createItemKey: 'packingList.createItem',
26
+ itemNameKey: 'packingList.itemName',
27
+ categoryKey: 'packingList.category',
28
+ visibilityKey: 'packingList.visibility',
29
+ essentialKey: 'packingList.essential',
30
+ quantityKey: 'packingList.quantity',
31
+ weightKey: 'packingList.weight',
32
+ volumeKey: 'packingList.volume',
33
+ hintKey: 'packingList.hint',
34
+ cancelKey: 'packingList.cancel',
35
+ createKey: 'packingList.create'
36
+ };
37
+ const DEFAULT_PACKING_LIST_CONFIG = {
38
+ features: {
39
+ search: true,
40
+ filters: true,
41
+ stats: true,
42
+ create: false,
43
+ assignments: true,
44
+ privateSection: false,
45
+ expandAllOnLoad: false,
46
+ },
47
+ defaultExpandedCount: 3,
48
+ };
49
+
50
+ const C2G_PACKING_CATEGORY_INFO = {
51
+ shelter: { key: 'shelter', labelKey: 'packingList.categories.shelter', label: 'Unterkunft', icon: 'home' },
52
+ sleeping: { key: 'sleeping', labelKey: 'packingList.categories.sleeping', label: 'Schlafen', icon: 'bed' },
53
+ cookingEating: { key: 'cookingEating', labelKey: 'packingList.categories.cookingEating', label: 'Kochen & Essen', icon: 'restaurant' },
54
+ clothing: { key: 'clothing', labelKey: 'packingList.categories.clothing', label: 'Kleidung', icon: 'checkroom' },
55
+ navigation: { key: 'navigation', labelKey: 'packingList.categories.navigation', label: 'Navigation', icon: 'explore' },
56
+ lighting: { key: 'lighting', labelKey: 'packingList.categories.lighting', label: 'Beleuchtung', icon: 'light_mode' },
57
+ safety: { key: 'safety', labelKey: 'packingList.categories.safety', label: 'Sicherheit', icon: 'medical_services' },
58
+ tools: { key: 'tools', labelKey: 'packingList.categories.tools', label: 'Werkzeug', icon: 'build' },
59
+ hygiene: { key: 'hygiene', labelKey: 'packingList.categories.hygiene', label: 'Hygiene', icon: 'wash' },
60
+ furniture: { key: 'furniture', labelKey: 'packingList.categories.furniture', label: 'Möbel & Ausstattung', icon: 'chair' },
61
+ hydration: { key: 'hydration', labelKey: 'packingList.categories.hydration', label: 'Getränke', icon: 'water_drop' },
62
+ mobility: { key: 'mobility', labelKey: 'packingList.categories.mobility', label: 'Transport', icon: 'backpack' },
63
+ activity: { key: 'activity', labelKey: 'packingList.categories.activity', label: 'Aktivitäten', icon: 'sports' },
64
+ documents: { key: 'documents', labelKey: 'packingList.categories.documents', label: 'Dokumente', icon: 'description' },
65
+ other: { key: 'other', labelKey: 'packingList.categories.other', label: 'Sonstiges', icon: 'category' }
66
+ };
67
+ function resolvePackingCategory(categoryKey) {
68
+ return (C2G_PACKING_CATEGORY_INFO[categoryKey] ?? {
69
+ key: categoryKey,
70
+ labelKey: `packingList.categories.${categoryKey}`,
71
+ icon: 'inventory_2'
72
+ });
73
+ }
74
+
75
+ class PackingListItemComponent {
76
+ item = input.required(...(ngDevMode ? [{ debugName: "item" }] : []));
77
+ members = input.required(...(ngDevMode ? [{ debugName: "members" }] : []));
78
+ currentUserId = input.required(...(ngDevMode ? [{ debugName: "currentUserId" }] : []));
79
+ permissions = input.required(...(ngDevMode ? [{ debugName: "permissions" }] : []));
80
+ selectedMemberIds = input([], ...(ngDevMode ? [{ debugName: "selectedMemberIds" }] : []));
81
+ itemChecked = output();
82
+ itemAssigned = output();
83
+ itemDeleted = output();
84
+ itemEditRequested = output();
85
+ personalItemToggled = output();
86
+ memberOverlayRequested = output();
87
+ overlayOpen = signal(false, ...(ngDevMode ? [{ debugName: "overlayOpen" }] : []));
88
+ overlaySearch = signal('', ...(ngDevMode ? [{ debugName: "overlaySearch" }] : []));
89
+ ctaMenuOpen = signal(false, ...(ngDevMode ? [{ debugName: "ctaMenuOpen" }] : []));
90
+ quantityPickerOpen = signal(false, ...(ngDevMode ? [{ debugName: "quantityPickerOpen" }] : []));
91
+ quantityPickerValue = signal(1, ...(ngDevMode ? [{ debugName: "quantityPickerValue" }] : []));
92
+ delegateDialogOpen = signal(false, ...(ngDevMode ? [{ debugName: "delegateDialogOpen" }] : []));
93
+ delegateMemberId = signal(null, ...(ngDevMode ? [{ debugName: "delegateMemberId" }] : []));
94
+ delegateQuantity = signal(1, ...(ngDevMode ? [{ debugName: "delegateQuantity" }] : []));
95
+ avatarDialogOpen = signal(false, ...(ngDevMode ? [{ debugName: "avatarDialogOpen" }] : []));
96
+ avatarDialogMemberId = signal(null, ...(ngDevMode ? [{ debugName: "avatarDialogMemberId" }] : []));
97
+ avatarDialogQuantity = signal(1, ...(ngDevMode ? [{ debugName: "avatarDialogQuantity" }] : []));
98
+ personalAssignDialogOpen = signal(false, ...(ngDevMode ? [{ debugName: "personalAssignDialogOpen" }] : []));
99
+ personalAssignSearch = signal('', ...(ngDevMode ? [{ debugName: "personalAssignSearch" }] : []));
100
+ personalAssignMemberId = signal(null, ...(ngDevMode ? [{ debugName: "personalAssignMemberId" }] : []));
101
+ applicableMembers = computed(() => {
102
+ const item = this.item();
103
+ if (item.visibility === 'personal') {
104
+ return this.members().filter(m => m.type !== 'pet');
105
+ }
106
+ return this.members().filter(m => m.type !== 'child' && m.type !== 'pet');
107
+ }, ...(ngDevMode ? [{ debugName: "applicableMembers" }] : []));
108
+ visibleMembers = computed(() => {
109
+ const selected = this.selectedMemberIds();
110
+ if (selected.length === 0) {
111
+ return this.applicableMembers();
112
+ }
113
+ const allowed = new Set(selected);
114
+ return this.applicableMembers().filter(member => allowed.has(member.id));
115
+ }, ...(ngDevMode ? [{ debugName: "visibleMembers" }] : []));
116
+ packedCount = computed(() => {
117
+ const assignments = this.item().assignments ?? [];
118
+ return assignments
119
+ .filter(a => a.status === 'packed' || a.status === 'confirmed')
120
+ .reduce((sum, a) => sum + Math.max(1, a.quantity ?? 1), 0);
121
+ }, ...(ngDevMode ? [{ debugName: "packedCount" }] : []));
122
+ isPacked = computed(() => this.packedCount() > 0 || !!this.item().confirmed, ...(ngDevMode ? [{ debugName: "isPacked" }] : []));
123
+ requiredQuantity = computed(() => Math.max(1, this.item().quantity ?? 1), ...(ngDevMode ? [{ debugName: "requiredQuantity" }] : []));
124
+ checkedMembers = computed(() => {
125
+ const currentUserId = this.currentUserId();
126
+ const checked = this.visibleMembers().filter(member => this.isMemberChecked(member.id));
127
+ return checked.sort((a, b) => {
128
+ if (a.id === currentUserId)
129
+ return -1;
130
+ if (b.id === currentUserId)
131
+ return 1;
132
+ return 0;
133
+ });
134
+ }, ...(ngDevMode ? [{ debugName: "checkedMembers" }] : []));
135
+ personalAssignedMembers = computed(() => {
136
+ if (this.item().visibility !== 'personal') {
137
+ return [];
138
+ }
139
+ const currentUserId = this.currentUserId();
140
+ const assigned = this.visibleMembers().filter(member => this.hasAnyAssignment(member.id));
141
+ return assigned.sort((a, b) => {
142
+ if (a.id === currentUserId)
143
+ return -1;
144
+ if (b.id === currentUserId)
145
+ return 1;
146
+ return 0;
147
+ });
148
+ }, ...(ngDevMode ? [{ debugName: "personalAssignedMembers" }] : []));
149
+ missingMembers = computed(() => this.visibleMembers().filter(member => !this.isMemberChecked(member.id)), ...(ngDevMode ? [{ debugName: "missingMembers" }] : []));
150
+ checkedPreview = computed(() => this.checkedMembers().slice(0, 3), ...(ngDevMode ? [{ debugName: "checkedPreview" }] : []));
151
+ hiddenCheckedCount = computed(() => Math.max(0, this.checkedMembers().length - this.checkedPreview().length), ...(ngDevMode ? [{ debugName: "hiddenCheckedCount" }] : []));
152
+ personalAssignedPreview = computed(() => this.personalAssignedMembers().slice(0, 3), ...(ngDevMode ? [{ debugName: "personalAssignedPreview" }] : []));
153
+ personalHiddenAssignedCount = computed(() => Math.max(0, this.personalAssignedMembers().length - this.personalAssignedPreview().length), ...(ngDevMode ? [{ debugName: "personalHiddenAssignedCount" }] : []));
154
+ missingPreview = computed(() => this.missingMembers().slice(0, 3), ...(ngDevMode ? [{ debugName: "missingPreview" }] : []));
155
+ hiddenMissingCount = computed(() => Math.max(0, this.missingMembers().length - this.missingPreview().length), ...(ngDevMode ? [{ debugName: "hiddenMissingCount" }] : []));
156
+ currentUserMember = computed(() => this.members().find(member => member.id === this.currentUserId()) ?? null, ...(ngDevMode ? [{ debugName: "currentUserMember" }] : []));
157
+ isItemOwner = computed(() => {
158
+ const ownerId = this.item().createdBy;
159
+ if (!ownerId) {
160
+ // Legacy items may not carry ownership metadata.
161
+ return true;
162
+ }
163
+ return ownerId === this.currentUserId();
164
+ }, ...(ngDevMode ? [{ debugName: "isItemOwner" }] : []));
165
+ canEditOrDeleteItem = computed(() => {
166
+ const permissions = this.permissions();
167
+ if (permissions.readOnly) {
168
+ return false;
169
+ }
170
+ const item = this.item();
171
+ if (item.visibility === 'shared') {
172
+ return permissions.isOrganizer || !!permissions.canMembersManageSharedItems || this.isItemOwner();
173
+ }
174
+ return permissions.isOrganizer || this.isItemOwner();
175
+ }, ...(ngDevMode ? [{ debugName: "canEditOrDeleteItem" }] : []));
176
+ canShowAssignCta = computed(() => {
177
+ const permissions = this.permissions();
178
+ if (permissions.readOnly) {
179
+ return false;
180
+ }
181
+ if (permissions.isSolo) {
182
+ return false;
183
+ }
184
+ return permissions.isOrganizer || !!permissions.canManageAssignments;
185
+ }, ...(ngDevMode ? [{ debugName: "canShowAssignCta" }] : []));
186
+ sharedAssignmentsCount = computed(() => {
187
+ const assignments = this.item().assignments ?? [];
188
+ return assignments
189
+ .filter(a => a.status === 'confirmed' || a.status === 'packed')
190
+ .reduce((sum, a) => sum + Math.max(1, a.quantity ?? 1), 0);
191
+ }, ...(ngDevMode ? [{ debugName: "sharedAssignmentsCount" }] : []));
192
+ sharedTotalAssignedCount = computed(() => {
193
+ const assignments = this.item().assignments ?? [];
194
+ return assignments.reduce((sum, a) => sum + Math.max(1, a.quantity ?? 1), 0);
195
+ }, ...(ngDevMode ? [{ debugName: "sharedTotalAssignedCount" }] : []));
196
+ sharedMissingSlots = computed(() => Math.max(0, this.requiredQuantity() - this.sharedTotalAssignedCount()), ...(ngDevMode ? [{ debugName: "sharedMissingSlots" }] : []));
197
+ selfAssignableMaxQuantity = computed(() => Math.max(1, this.sharedMissingSlots()), ...(ngDevMode ? [{ debugName: "selfAssignableMaxQuantity" }] : []));
198
+ delegateCandidates = computed(() => this.visibleMembers().filter(member => this.canAssignShared(member.id)), ...(ngDevMode ? [{ debugName: "delegateCandidates" }] : []));
199
+ selfAssignedToShared = computed(() => this.isSharedAssigned(this.currentUserId()), ...(ngDevMode ? [{ debugName: "selfAssignedToShared" }] : []));
200
+ isPlanner = computed(() => {
201
+ const p = this.permissions();
202
+ return p.isOrganizer || !!p.canManageAssignments;
203
+ }, ...(ngDevMode ? [{ debugName: "isPlanner" }] : []));
204
+ // Label for the "join / adjust" button on shared items
205
+ joinBtnLabel = computed(() => {
206
+ if (!this.selfAssignedToShared())
207
+ return '+ Eintragen';
208
+ return this.isPlanner() ? 'Menge anpassen' : 'Meine Menge anpassen';
209
+ }, ...(ngDevMode ? [{ debugName: "joinBtnLabel" }] : []));
210
+ // Context label inside the quantity picker
211
+ pickerLabel = computed(() => {
212
+ if (this.isPlanner())
213
+ return 'Wie viel wird mitgenommen?';
214
+ return 'Wie viel nimmst du mit?';
215
+ }, ...(ngDevMode ? [{ debugName: "pickerLabel" }] : []));
216
+ // Context label inside the delegate dialog
217
+ delegatePickerLabel = computed(() => 'Wer bringt es mit? Menge festlegen:', ...(ngDevMode ? [{ debugName: "delegatePickerLabel" }] : []));
218
+ canSelfAssignShared = computed(() => {
219
+ const currentUserId = this.currentUserId();
220
+ if (!this.canAssignShared(currentUserId)) {
221
+ return false;
222
+ }
223
+ if (this.selfAssignedToShared()) {
224
+ return true;
225
+ }
226
+ return this.sharedMissingSlots() > 0;
227
+ }, ...(ngDevMode ? [{ debugName: "canSelfAssignShared" }] : []));
228
+ selectedDelegateMember = computed(() => {
229
+ const memberId = this.delegateMemberId();
230
+ if (!memberId) {
231
+ return null;
232
+ }
233
+ return this.members().find(member => member.id === memberId) ?? null;
234
+ }, ...(ngDevMode ? [{ debugName: "selectedDelegateMember" }] : []));
235
+ canManagePersonalAssignments = computed(() => {
236
+ const permissions = this.permissions();
237
+ if (permissions.readOnly || permissions.isSolo) {
238
+ return false;
239
+ }
240
+ return permissions.isOrganizer || !!permissions.canManageAssignments || this.isItemOwner();
241
+ }, ...(ngDevMode ? [{ debugName: "canManagePersonalAssignments" }] : []));
242
+ personalAssignableMembers = computed(() => {
243
+ if (this.item().visibility !== 'personal' || !this.canManagePersonalAssignments()) {
244
+ return [];
245
+ }
246
+ return this.visibleMembers().filter(member => !this.hasAnyAssignment(member.id));
247
+ }, ...(ngDevMode ? [{ debugName: "personalAssignableMembers" }] : []));
248
+ filteredPersonalAssignableMembers = computed(() => {
249
+ const query = this.personalAssignSearch().trim().toLowerCase();
250
+ if (!query) {
251
+ return this.personalAssignableMembers();
252
+ }
253
+ return this.personalAssignableMembers().filter(member => {
254
+ const searchable = `${member.name} ${member.initials ?? ''}`.toLowerCase();
255
+ return searchable.includes(query);
256
+ });
257
+ }, ...(ngDevMode ? [{ debugName: "filteredPersonalAssignableMembers" }] : []));
258
+ selectedPersonalAssignMember = computed(() => {
259
+ const memberId = this.personalAssignMemberId();
260
+ if (!memberId) {
261
+ return null;
262
+ }
263
+ return this.members().find(member => member.id === memberId) ?? null;
264
+ }, ...(ngDevMode ? [{ debugName: "selectedPersonalAssignMember" }] : []));
265
+ completionText = computed(() => {
266
+ if (this.item().visibility === 'shared') {
267
+ return `${this.sharedAssignmentsCount()}/${this.requiredQuantity()} bereit`;
268
+ }
269
+ if (this.item().visibility === 'personal') {
270
+ return `${this.checkedMembers().length}/${this.visibleMembers().length} bereit`;
271
+ }
272
+ return this.isPacked() ? 'bereit' : 'offen';
273
+ }, ...(ngDevMode ? [{ debugName: "completionText" }] : []));
274
+ progressNumerator = computed(() => {
275
+ if (this.item().visibility === 'shared') {
276
+ return this.sharedAssignmentsCount();
277
+ }
278
+ if (this.item().visibility === 'personal') {
279
+ return this.checkedMembers().length;
280
+ }
281
+ return this.isPacked() ? 1 : 0;
282
+ }, ...(ngDevMode ? [{ debugName: "progressNumerator" }] : []));
283
+ progressDenominator = computed(() => {
284
+ if (this.item().visibility === 'shared') {
285
+ return this.requiredQuantity();
286
+ }
287
+ if (this.item().visibility === 'personal') {
288
+ return Math.max(1, this.visibleMembers().length);
289
+ }
290
+ return 1;
291
+ }, ...(ngDevMode ? [{ debugName: "progressDenominator" }] : []));
292
+ progressRatioText = computed(() => `${this.progressNumerator()}/${this.progressDenominator()}`, ...(ngDevMode ? [{ debugName: "progressRatioText" }] : []));
293
+ // Badge shown top-right: "x/y" packed — only for group items
294
+ quantityBadge = computed(() => {
295
+ const vis = this.item().visibility;
296
+ if (this.permissions().isSolo || vis === 'private')
297
+ return null;
298
+ const n = this.progressNumerator();
299
+ const d = this.progressDenominator();
300
+ if (d <= 1 && vis === 'shared')
301
+ return null; // single shared item, dot is enough
302
+ return { value: `${n}/${d}`, tone: this.progressTone() };
303
+ }, ...(ngDevMode ? [{ debugName: "quantityBadge" }] : []));
304
+ progressPercentage = computed(() => {
305
+ const denominator = this.progressDenominator();
306
+ if (denominator <= 0) {
307
+ return 0;
308
+ }
309
+ return Math.min(100, Math.round((this.progressNumerator() / denominator) * 100));
310
+ }, ...(ngDevMode ? [{ debugName: "progressPercentage" }] : []));
311
+ progressTone = computed(() => {
312
+ const progress = this.progressPercentage();
313
+ if (progress === 100) {
314
+ return 'success';
315
+ }
316
+ if (progress >= 50) {
317
+ return 'warning';
318
+ }
319
+ return 'danger';
320
+ }, ...(ngDevMode ? [{ debugName: "progressTone" }] : []));
321
+ needsPackLabel = computed(() => {
322
+ if (this.item().visibility === 'shared') {
323
+ return `${this.sharedMissingSlots()} offen`;
324
+ }
325
+ return `${this.missingMembers().length} müssen packen`;
326
+ }, ...(ngDevMode ? [{ debugName: "needsPackLabel" }] : []));
327
+ overlayMembers = computed(() => this.visibleMembers().map(member => ({
328
+ memberId: member.id,
329
+ memberName: member.name,
330
+ initials: member.initials,
331
+ checked: this.isMemberChecked(member.id),
332
+ canToggle: this.item().visibility === 'shared'
333
+ ? this.canAssignShared(member.id)
334
+ : this.canPackForMember(member.id)
335
+ })), ...(ngDevMode ? [{ debugName: "overlayMembers" }] : []));
336
+ filteredOverlayMembers = computed(() => {
337
+ const query = this.overlaySearch().trim().toLowerCase();
338
+ if (!query) {
339
+ return this.overlayMembers();
340
+ }
341
+ return this.overlayMembers().filter(member => {
342
+ const searchable = `${member.memberName} ${member.initials ?? ''}`.toLowerCase();
343
+ return searchable.includes(query);
344
+ });
345
+ }, ...(ngDevMode ? [{ debugName: "filteredOverlayMembers" }] : []));
346
+ personalStatusBadges = computed(() => {
347
+ if (this.item().visibility !== 'personal') {
348
+ return [];
349
+ }
350
+ const badges = [];
351
+ for (const assignment of this.item().assignments ?? []) {
352
+ const targetMember = this.members().find(m => m.id === assignment.memberId);
353
+ const targetName = targetMember?.name ?? assignment.memberName ?? assignment.memberId;
354
+ const sourceMember = assignment.packedBy ? this.members().find(m => m.id === assignment.packedBy) : null;
355
+ const sourceName = sourceMember?.name ?? assignment.packedByName ?? assignment.packedBy;
356
+ const isTakeover = !!assignment.packedBy && assignment.packedBy !== assignment.memberId;
357
+ badges.push({
358
+ key: `${assignment.memberId}:${assignment.packedBy ?? assignment.memberId}:${assignment.status}`,
359
+ text: isTakeover ? `${sourceName} -> ${targetName}` : targetName,
360
+ tone: assignment.status === 'assigned' ? 'warning' : 'success',
361
+ dotColor: this.memberRingColor(assignment.memberId)
362
+ });
363
+ }
364
+ return badges.sort((a, b) => {
365
+ const aIsCurrent = a.key.startsWith(`${this.currentUserId()}:`);
366
+ const bIsCurrent = b.key.startsWith(`${this.currentUserId()}:`);
367
+ if (aIsCurrent && !bIsCurrent)
368
+ return -1;
369
+ if (!aIsCurrent && bIsCurrent)
370
+ return 1;
371
+ return a.text.localeCompare(b.text);
372
+ });
373
+ }, ...(ngDevMode ? [{ debugName: "personalStatusBadges" }] : []));
374
+ sharedCountChips = computed(() => {
375
+ if (this.item().visibility !== 'shared') {
376
+ return [];
377
+ }
378
+ const byMember = new Map();
379
+ for (const assignment of this.item().assignments ?? []) {
380
+ const quantity = Math.max(1, assignment.quantity ?? 1);
381
+ const prev = byMember.get(assignment.memberId) ?? { quantity: 0, hasPacked: false };
382
+ byMember.set(assignment.memberId, {
383
+ quantity: prev.quantity + quantity,
384
+ hasPacked: prev.hasPacked || assignment.status === 'packed' || assignment.status === 'confirmed'
385
+ });
386
+ }
387
+ return Array.from(byMember.entries())
388
+ .map(([memberId, value]) => {
389
+ const member = this.members().find(m => m.id === memberId);
390
+ return {
391
+ key: memberId,
392
+ text: `${member?.name ?? memberId}: ${value.quantity}x`,
393
+ tone: (value.hasPacked ? 'success' : 'warning')
394
+ };
395
+ })
396
+ .sort((a, b) => {
397
+ const aIsCurrent = a.key === this.currentUserId();
398
+ const bIsCurrent = b.key === this.currentUserId();
399
+ if (aIsCurrent && !bIsCurrent)
400
+ return -1;
401
+ if (!aIsCurrent && bIsCurrent)
402
+ return 1;
403
+ return a.text.localeCompare(b.text);
404
+ });
405
+ }, ...(ngDevMode ? [{ debugName: "sharedCountChips" }] : []));
406
+ memberAssignmentStatus(memberId) {
407
+ const assignments = this.item().assignments ?? [];
408
+ const a = assignments.find(a => a.memberId === memberId);
409
+ if (!a)
410
+ return 'none';
411
+ if (a.status === 'confirmed')
412
+ return 'confirmed';
413
+ if (a.status === 'packed')
414
+ return 'packed';
415
+ return 'assigned';
416
+ }
417
+ memberAssignedQuantity(memberId) {
418
+ const assignments = this.item().assignments ?? [];
419
+ const assignment = assignments.find(a => a.memberId === memberId);
420
+ if (!assignment) {
421
+ return 0;
422
+ }
423
+ return Math.max(1, assignment.quantity ?? 1);
424
+ }
425
+ memberRingTone(memberId) {
426
+ return 'custom';
427
+ }
428
+ memberRingColor(memberId) {
429
+ const status = this.memberAssignmentStatus(memberId);
430
+ if (status === 'confirmed' || status === 'packed')
431
+ return '#4caf50';
432
+ if (status === 'assigned')
433
+ return '#f1c84a';
434
+ return '#cad8d0';
435
+ }
436
+ memberBadge(memberId) {
437
+ const status = this.memberAssignmentStatus(memberId);
438
+ if (status === 'confirmed' || status === 'packed') {
439
+ return { icon: '✓', tone: 'success', ariaLabel: 'Bestätigt' };
440
+ }
441
+ if (status === 'assigned') {
442
+ return { icon: '?', tone: 'neutral', ariaLabel: 'Zugewiesen' };
443
+ }
444
+ return null;
445
+ }
446
+ memberBackground(member) {
447
+ switch (member.type) {
448
+ case 'child':
449
+ case 'baby':
450
+ return '#fdf2d9';
451
+ case 'pet':
452
+ return '#efe6fb';
453
+ default:
454
+ return '#e8f0ea';
455
+ }
456
+ }
457
+ isMemberChecked(memberId) {
458
+ return this.item().visibility === 'shared'
459
+ ? this.isSharedAssigned(memberId)
460
+ : this.isAssignmentChecked(memberId);
461
+ }
462
+ hasAnyAssignment(memberId) {
463
+ const assignments = this.item().assignments ?? [];
464
+ return assignments.some(a => a.memberId === memberId);
465
+ }
466
+ canPackForMember(memberId) {
467
+ const permissions = this.permissions();
468
+ if (permissions.readOnly) {
469
+ return false;
470
+ }
471
+ return memberId === this.currentUserId() || permissions.isOrganizer;
472
+ }
473
+ isAssignmentChecked(memberId) {
474
+ const assignments = this.item().assignments ?? [];
475
+ return assignments.some(a => a.memberId === memberId && (a.status === 'packed' || a.status === 'confirmed'));
476
+ }
477
+ isSharedAssigned(memberId) {
478
+ const assignments = this.item().assignments ?? [];
479
+ return assignments.some(a => a.memberId === memberId);
480
+ }
481
+ canAssignShared(memberId) {
482
+ const permissions = this.permissions();
483
+ if (permissions.readOnly) {
484
+ return false;
485
+ }
486
+ if (permissions.isGuest && memberId !== this.currentUserId()) {
487
+ return false;
488
+ }
489
+ return true;
490
+ }
491
+ onSoloToggle(checked) {
492
+ this.itemChecked.emit({ itemId: this.item().id, checked });
493
+ }
494
+ onPrivateToggle(checked) {
495
+ this.itemChecked.emit({ itemId: this.item().id, checked });
496
+ }
497
+ onSharedToggle(memberId, quantity = 1) {
498
+ const assigned = !this.isSharedAssigned(memberId);
499
+ const safeQuantity = Math.max(1, quantity);
500
+ const label = assigned
501
+ ? `Willst du dich mit ${safeQuantity}x fuer dieses Shared-Item eintragen?`
502
+ : 'Willst du deine Zuordnung fuer dieses Shared-Item entfernen?';
503
+ if (!globalThis.confirm(label)) {
504
+ return;
505
+ }
506
+ this.itemAssigned.emit({ itemId: this.item().id, memberId, assigned, quantity: assigned ? safeQuantity : undefined });
507
+ }
508
+ setSharedAssignment(memberId, assigned, quantity) {
509
+ const safeQuantity = quantity !== undefined ? Math.max(1, quantity) : undefined;
510
+ this.itemAssigned.emit({
511
+ itemId: this.item().id,
512
+ memberId,
513
+ assigned,
514
+ quantity: assigned ? safeQuantity : undefined
515
+ });
516
+ }
517
+ setPersonalAssignment(memberId, assigned) {
518
+ this.itemAssigned.emit({
519
+ itemId: this.item().id,
520
+ memberId,
521
+ assigned
522
+ });
523
+ }
524
+ onPersonalToggle(memberId) {
525
+ const checked = !this.isAssignmentChecked(memberId);
526
+ this.personalItemToggled.emit({ itemId: this.item().id, memberId, checked });
527
+ }
528
+ deleteItem() {
529
+ if (!this.canEditOrDeleteItem()) {
530
+ return;
531
+ }
532
+ this.itemDeleted.emit(this.item().id);
533
+ }
534
+ requestEdit() {
535
+ if (!this.canEditOrDeleteItem()) {
536
+ return;
537
+ }
538
+ this.itemEditRequested.emit(this.item().id);
539
+ }
540
+ requestAssign() {
541
+ if (!this.canShowAssignCta()) {
542
+ return;
543
+ }
544
+ if (this.item().visibility === 'personal') {
545
+ this.openPersonalAssignDialog();
546
+ return;
547
+ }
548
+ this.openOverlay();
549
+ }
550
+ openPersonalAssignDialog() {
551
+ if (this.item().visibility !== 'personal') {
552
+ return;
553
+ }
554
+ const candidates = this.personalAssignableMembers();
555
+ if (candidates.length === 0) {
556
+ return;
557
+ }
558
+ this.closeCtaMenu();
559
+ this.closeOverlay();
560
+ this.closeDelegateDialog();
561
+ this.closeAvatarDialog();
562
+ this.quantityPickerOpen.set(false);
563
+ this.personalAssignSearch.set('');
564
+ this.personalAssignMemberId.set(candidates[0].id);
565
+ this.personalAssignDialogOpen.set(true);
566
+ }
567
+ closePersonalAssignDialog() {
568
+ this.personalAssignDialogOpen.set(false);
569
+ this.personalAssignSearch.set('');
570
+ this.personalAssignMemberId.set(null);
571
+ }
572
+ onPersonalAssignSearch(event) {
573
+ this.personalAssignSearch.set(event.target.value);
574
+ const filtered = this.filteredPersonalAssignableMembers();
575
+ const selectedMemberId = this.personalAssignMemberId();
576
+ if (!selectedMemberId || !filtered.some(member => member.id === selectedMemberId)) {
577
+ this.personalAssignMemberId.set(filtered[0]?.id ?? null);
578
+ }
579
+ }
580
+ selectPersonalAssignMember(memberId) {
581
+ this.personalAssignMemberId.set(memberId);
582
+ }
583
+ confirmPersonalAssignment() {
584
+ const member = this.selectedPersonalAssignMember();
585
+ if (!member) {
586
+ return;
587
+ }
588
+ if (!globalThis.confirm(`${member.name} diesem Personal-Item zuweisen?`)) {
589
+ return;
590
+ }
591
+ this.setPersonalAssignment(member.id, true);
592
+ this.closePersonalAssignDialog();
593
+ }
594
+ onPersonalAvatarClick(memberId) {
595
+ if (this.item().visibility !== 'personal' || !this.canManagePersonalAssignments() || !this.hasAnyAssignment(memberId)) {
596
+ return;
597
+ }
598
+ const member = this.members().find(entry => entry.id === memberId);
599
+ if (!globalThis.confirm(`${member?.name ?? memberId} von diesem Personal-Item entfernen?`)) {
600
+ return;
601
+ }
602
+ this.setPersonalAssignment(memberId, false);
603
+ }
604
+ onAssignMeToggle() {
605
+ if (this.selfAssignedToShared()) {
606
+ this.openDelegateDialog();
607
+ return;
608
+ }
609
+ if (this.requiredQuantity() <= 1) {
610
+ this.onSharedToggle(this.currentUserId(), 1);
611
+ return;
612
+ }
613
+ const missing = this.sharedMissingSlots();
614
+ if (missing <= 0) {
615
+ return;
616
+ }
617
+ this.quantityPickerValue.set(Math.min(this.quantityPickerValue(), missing));
618
+ this.quantityPickerOpen.update(open => !open);
619
+ }
620
+ openDelegateDialog() {
621
+ if (this.item().visibility !== 'shared') {
622
+ return;
623
+ }
624
+ const candidates = this.delegateCandidates();
625
+ if (candidates.length === 0) {
626
+ return;
627
+ }
628
+ this.closeAvatarDialog();
629
+ this.quantityPickerOpen.set(false);
630
+ this.delegateMemberId.set(candidates[0].id);
631
+ this.delegateQuantity.set(1);
632
+ this.delegateDialogOpen.set(true);
633
+ }
634
+ closeDelegateDialog() {
635
+ this.delegateDialogOpen.set(false);
636
+ this.delegateMemberId.set(null);
637
+ this.delegateQuantity.set(1);
638
+ }
639
+ onDelegateMemberChange(event) {
640
+ this.delegateMemberId.set(event.target.value || null);
641
+ }
642
+ increaseDelegateQuantity() {
643
+ this.delegateQuantity.update(value => Math.min(this.requiredQuantity(), value + 1));
644
+ }
645
+ decreaseDelegateQuantity() {
646
+ this.delegateQuantity.update(value => Math.max(1, value - 1));
647
+ }
648
+ confirmDelegateAssignment() {
649
+ const memberId = this.delegateMemberId();
650
+ if (!memberId) {
651
+ return;
652
+ }
653
+ const target = this.members().find(member => member.id === memberId);
654
+ const quantity = Math.max(1, this.delegateQuantity());
655
+ const confirmationText = `Auch User mit Account können von anderen übernommen werden.`;
656
+ if (!globalThis.confirm(`Zuordnung setzen: ${target?.name ?? memberId} (${quantity}x)?\n${confirmationText}`)) {
657
+ return;
658
+ }
659
+ this.setSharedAssignment(memberId, true, quantity);
660
+ this.closeDelegateDialog();
661
+ }
662
+ onSharedAvatarClick(memberId) {
663
+ if (this.item().visibility !== 'shared') {
664
+ return;
665
+ }
666
+ const quantity = this.memberAssignedQuantity(memberId);
667
+ if (quantity <= 0) {
668
+ return;
669
+ }
670
+ this.closeDelegateDialog();
671
+ this.quantityPickerOpen.set(false);
672
+ this.avatarDialogMemberId.set(memberId);
673
+ this.avatarDialogQuantity.set(quantity);
674
+ this.avatarDialogOpen.set(true);
675
+ }
676
+ closeAvatarDialog() {
677
+ this.avatarDialogOpen.set(false);
678
+ this.avatarDialogMemberId.set(null);
679
+ this.avatarDialogQuantity.set(1);
680
+ }
681
+ increaseAvatarDialogQuantity() {
682
+ this.avatarDialogQuantity.update(value => Math.min(this.requiredQuantity(), value + 1));
683
+ }
684
+ decreaseAvatarDialogQuantity() {
685
+ this.avatarDialogQuantity.update(value => Math.max(0, value - 1));
686
+ }
687
+ confirmAvatarDialogUpdate() {
688
+ const memberId = this.avatarDialogMemberId();
689
+ if (!memberId) {
690
+ return;
691
+ }
692
+ const quantity = this.avatarDialogQuantity();
693
+ const member = this.members().find(m => m.id === memberId);
694
+ if (quantity === 0) {
695
+ if (!globalThis.confirm(`Zuordnung fuer ${member?.name ?? memberId} entfernen?`)) {
696
+ return;
697
+ }
698
+ this.setSharedAssignment(memberId, false);
699
+ this.closeAvatarDialog();
700
+ return;
701
+ }
702
+ if (!globalThis.confirm(`Menge fuer ${member?.name ?? memberId} auf ${quantity} setzen?`)) {
703
+ return;
704
+ }
705
+ this.setSharedAssignment(memberId, true, quantity);
706
+ this.closeAvatarDialog();
707
+ }
708
+ increaseSelfAssignQuantity() {
709
+ const max = this.selfAssignableMaxQuantity();
710
+ this.quantityPickerValue.update(value => Math.min(max, value + 1));
711
+ }
712
+ decreaseSelfAssignQuantity() {
713
+ this.quantityPickerValue.update(value => Math.max(1, value - 1));
714
+ }
715
+ cancelSelfAssignQuantity() {
716
+ this.quantityPickerOpen.set(false);
717
+ this.quantityPickerValue.set(1);
718
+ }
719
+ confirmSelfAssignQuantity() {
720
+ const quantity = Math.max(1, Math.min(this.quantityPickerValue(), this.selfAssignableMaxQuantity()));
721
+ this.quantityPickerOpen.set(false);
722
+ if (!globalThis.confirm(`Willst du dich mit ${quantity}x fuer dieses Shared-Item eintragen?`)) {
723
+ return;
724
+ }
725
+ this.setSharedAssignment(this.currentUserId(), true, quantity);
726
+ }
727
+ toggleCtaMenu() {
728
+ this.ctaMenuOpen.update(open => !open);
729
+ }
730
+ closeCtaMenu() {
731
+ this.ctaMenuOpen.set(false);
732
+ }
733
+ onMenuAssign() {
734
+ this.closeCtaMenu();
735
+ this.requestAssign();
736
+ }
737
+ onMenuEdit() {
738
+ this.closeCtaMenu();
739
+ this.requestEdit();
740
+ }
741
+ onMenuDelete() {
742
+ this.closeCtaMenu();
743
+ this.deleteItem();
744
+ }
745
+ openOverlay() {
746
+ this.closeCtaMenu();
747
+ this.overlaySearch.set('');
748
+ this.quantityPickerOpen.set(false);
749
+ this.closeDelegateDialog();
750
+ this.closeAvatarDialog();
751
+ this.closePersonalAssignDialog();
752
+ this.overlayOpen.set(true);
753
+ this.memberOverlayRequested.emit({
754
+ itemId: this.item().id,
755
+ itemName: this.item().name,
756
+ members: this.overlayMembers()
757
+ });
758
+ }
759
+ closeOverlay() {
760
+ this.overlayOpen.set(false);
761
+ this.overlaySearch.set('');
762
+ }
763
+ onOverlaySearch(event) {
764
+ this.overlaySearch.set(event.target.value);
765
+ }
766
+ toggleFromOverlay(memberId) {
767
+ if (this.item().visibility === 'shared') {
768
+ this.onSharedToggle(memberId);
769
+ return;
770
+ }
771
+ if (this.item().visibility === 'personal') {
772
+ this.onPersonalToggle(memberId);
773
+ }
774
+ }
775
+ privateItemOwnerLabel() {
776
+ if (!this.item().privateOwnerVisible) {
777
+ return 'Privat';
778
+ }
779
+ const ownerId = this.item().createdBy ?? this.item().assignments?.[0]?.memberId;
780
+ const owner = this.members().find(member => member.id === ownerId);
781
+ return owner?.name ?? 'Privat';
782
+ }
783
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: PackingListItemComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
784
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: PackingListItemComponent, isStandalone: true, selector: "c2g-packing-list-item", inputs: { item: { classPropertyName: "item", publicName: "item", isSignal: true, isRequired: true, transformFunction: null }, members: { classPropertyName: "members", publicName: "members", isSignal: true, isRequired: true, transformFunction: null }, currentUserId: { classPropertyName: "currentUserId", publicName: "currentUserId", isSignal: true, isRequired: true, transformFunction: null }, permissions: { classPropertyName: "permissions", publicName: "permissions", isSignal: true, isRequired: true, transformFunction: null }, selectedMemberIds: { classPropertyName: "selectedMemberIds", publicName: "selectedMemberIds", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { itemChecked: "itemChecked", itemAssigned: "itemAssigned", itemDeleted: "itemDeleted", itemEditRequested: "itemEditRequested", personalItemToggled: "personalItemToggled", memberOverlayRequested: "memberOverlayRequested" }, ngImport: i0, template: "<div class=\"c2g-pl-item\" [class.c2g-pl-item--packed]=\"isPacked()\">\n\n <div class=\"c2g-pl-item__row\">\n\n <!-- Solo: echte Checkbox -->\n @if (permissions().isSolo) {\n <button\n class=\"c2g-pl-item__check\"\n [class.c2g-pl-item__check--done]=\"isPacked()\"\n type=\"button\"\n [disabled]=\"permissions().readOnly\"\n [attr.aria-pressed]=\"isPacked()\"\n [attr.aria-label]=\"isPacked() ? 'Als ungepackt markieren' : 'Als gepackt markieren'\"\n (click)=\"onSoloToggle(!isPacked())\">\n @if (isPacked()) {\n <span class=\"c2g-pl-item__check-mark\" aria-hidden=\"true\">\u2713</span>\n }\n </button>\n } @else {\n <!-- Gruppen-Item: farbiger Fortschritts-Dot -->\n <span\n class=\"c2g-pl-item__dot\"\n [class.c2g-pl-item__dot--danger]=\"progressTone() === 'danger'\"\n [class.c2g-pl-item__dot--warning]=\"progressTone() === 'warning'\"\n [class.c2g-pl-item__dot--success]=\"progressTone() === 'success'\"\n [attr.title]=\"progressRatioText() + ' bereit'\"\n aria-hidden=\"true\">\n </span>\n }\n\n <!-- Body -->\n <div class=\"c2g-pl-item__body\">\n\n <!-- Zeile 1: Name + Tags + Mengen-Badge -->\n <div class=\"c2g-pl-item__title-row\">\n <span class=\"c2g-pl-item__name\">{{ item().name }}</span>\n <div class=\"c2g-pl-item__tags\">\n @if (item().essential) {\n <span class=\"c2g-pl-item__tag c2g-pl-item__tag--essential\">Pflicht</span>\n }\n @if (item().weather) {\n <span class=\"c2g-pl-item__tag c2g-pl-item__tag--weather\">Wetter</span>\n }\n @if (item().visibility === 'private') {\n <span class=\"c2g-pl-item__tag c2g-pl-item__tag--private\">\uD83D\uDD12 {{ privateItemOwnerLabel() }}</span>\n }\n </div>\n\n @if (quantityBadge(); as badge) {\n <c2g-badge\n class=\"c2g-pl-item__qty-badge\"\n [value]=\"badge.value\"\n [tone]=\"badge.tone\"\n variant=\"subtle\"\n size=\"sm\"\n [attr.aria-label]=\"'Gepackt: ' + badge.value\">\n </c2g-badge>\n }\n </div>\n\n <!-- Zeile 2: Mitglieder / Avatare -->\n @if (!permissions().isSolo) {\n <div class=\"c2g-pl-item__members-row\">\n\n @if (item().visibility === 'shared') {\n <!-- Assigned-Avatare -->\n @for (member of checkedPreview(); track member.id) {\n <button\n class=\"c2g-pl-item__avatar-btn\"\n type=\"button\"\n [disabled]=\"permissions().readOnly\"\n [attr.aria-label]=\"member.name + ' \u2013 antippen zum Bearbeiten'\"\n (click)=\"onSharedAvatarClick(member.id)\">\n <c2g-avatar\n size=\"sm\"\n [name]=\"member.name\"\n [initials]=\"member.initials || ''\"\n [backgroundColor]=\"memberBackground(member)\"\n [ringTone]=\"memberRingTone(member.id)\"\n [ringColor]=\"memberRingColor(member.id)\"\n [badge]=\"memberBadge(member.id)\">\n </c2g-avatar>\n </button>\n }\n\n @if (hiddenCheckedCount() > 0) {\n <div class=\"c2g-pl-item__more-wrap\">\n <button class=\"c2g-pl-item__more\" type=\"button\" (click)=\"openOverlay()\">\n +{{ hiddenCheckedCount() }}\n </button>\n @if (overlayOpen()) {\n <div class=\"c2g-pl-item__overlay\" role=\"dialog\" aria-label=\"Alle Mitglieder\">\n <div class=\"c2g-pl-item__overlay-head\">\n <strong>{{ item().name }}</strong>\n <button type=\"button\" class=\"c2g-pl-item__overlay-close\" (click)=\"closeOverlay()\">\u2715</button>\n </div>\n <input class=\"c2g-pl-item__overlay-search\" type=\"search\" [value]=\"overlaySearch()\" placeholder=\"Mitglied suchen...\" (input)=\"onOverlaySearch($event)\" />\n <div class=\"c2g-pl-item__overlay-list\">\n @for (member of filteredOverlayMembers(); track member.memberId) {\n <button class=\"c2g-pl-item__overlay-row\" type=\"button\" [disabled]=\"!member.canToggle\" (click)=\"toggleFromOverlay(member.memberId)\">\n <span>{{ member.memberName }}</span>\n <span class=\"c2g-pl-item__overlay-status\" [class.c2g-pl-item__overlay-status--done]=\"member.checked\">{{ member.checked ? '\u2713 bereit' : 'ausstehend' }}</span>\n </button>\n }\n </div>\n </div>\n }\n </div>\n }\n\n <!-- Empty state -->\n @if (checkedMembers().length === 0) {\n <span class=\"c2g-pl-item__empty\">Noch niemand eingetragen</span>\n }\n\n <!-- + Eintragen Button -->\n @if (canSelfAssignShared()) {\n <button\n class=\"c2g-pl-item__join-btn\"\n [class.c2g-pl-item__join-btn--active]=\"selfAssignedToShared()\"\n type=\"button\"\n (click)=\"onAssignMeToggle()\">\n {{ joinBtnLabel() }}\n </button>\n }\n\n } @else if (item().visibility === 'personal') {\n <!-- Personal: wer hat es f\u00FCr sich -->\n @for (member of personalAssignedPreview(); track member.id) {\n <button\n class=\"c2g-pl-item__avatar-btn\"\n type=\"button\"\n [disabled]=\"!canManagePersonalAssignments()\"\n [attr.aria-label]=\"member.name + ' \u2013 antippen zum Entfernen'\"\n (click)=\"onPersonalAvatarClick(member.id)\">\n <c2g-avatar\n size=\"sm\"\n [name]=\"member.name\"\n [initials]=\"member.initials || ''\"\n [backgroundColor]=\"memberBackground(member)\"\n [ringTone]=\"memberRingTone(member.id)\"\n [ringColor]=\"memberRingColor(member.id)\"\n [badge]=\"memberBadge(member.id)\">\n </c2g-avatar>\n </button>\n }\n\n @if (personalHiddenAssignedCount() > 0) {\n <div class=\"c2g-pl-item__more-wrap\">\n <button class=\"c2g-pl-item__more\" type=\"button\" (click)=\"openOverlay()\">\n +{{ personalHiddenAssignedCount() }}\n </button>\n @if (overlayOpen()) {\n <div class=\"c2g-pl-item__overlay\" role=\"dialog\" aria-label=\"Alle Mitglieder\">\n <div class=\"c2g-pl-item__overlay-head\">\n <strong>{{ item().name }}</strong>\n <button type=\"button\" class=\"c2g-pl-item__overlay-close\" (click)=\"closeOverlay()\">\u2715</button>\n </div>\n <input class=\"c2g-pl-item__overlay-search\" type=\"search\" [value]=\"overlaySearch()\" placeholder=\"Mitglied suchen...\" (input)=\"onOverlaySearch($event)\" />\n <div class=\"c2g-pl-item__overlay-list\">\n @for (member of filteredOverlayMembers(); track member.memberId) {\n <button class=\"c2g-pl-item__overlay-row\" type=\"button\" [disabled]=\"!member.canToggle\" (click)=\"toggleFromOverlay(member.memberId)\">\n <span>{{ member.memberName }}</span>\n <span class=\"c2g-pl-item__overlay-status\" [class.c2g-pl-item__overlay-status--done]=\"member.checked\">{{ member.checked ? '\u2713 bereit' : 'ausstehend' }}</span>\n </button>\n }\n </div>\n </div>\n }\n </div>\n }\n\n @if (personalAssignedMembers().length === 0) {\n <span class=\"c2g-pl-item__empty\">Nicht zugewiesen</span>\n }\n\n @if (canManagePersonalAssignments()) {\n <button class=\"c2g-pl-item__join-btn\" type=\"button\" (click)=\"openPersonalAssignDialog()\">\n + Zuweisen\n </button>\n }\n }\n\n </div>\n }\n\n </div>\n\n <!-- Aktions-Spalte: \u22EF Men\u00FC -->\n @if (canShowAssignCta() || canEditOrDeleteItem()) {\n <div class=\"c2g-pl-item__cta\">\n <button\n class=\"c2g-pl-item__menu-trigger\"\n type=\"button\"\n aria-label=\"Aktionen\"\n [attr.aria-expanded]=\"ctaMenuOpen()\"\n (click)=\"toggleCtaMenu()\">\n \u22EF\n </button>\n\n @if (ctaMenuOpen()) {\n <div class=\"c2g-pl-item__menu\" role=\"menu\">\n @if (canShowAssignCta()) {\n <button class=\"c2g-pl-item__menu-item\" type=\"button\" role=\"menuitem\" (click)=\"onMenuAssign()\">\n <span class=\"c2g-pl-item__menu-icon\">\uD83D\uDC64</span> {{ isPlanner() ? 'Zuweisen' : 'Einpacken' }}\n </button>\n }\n @if (canEditOrDeleteItem()) {\n <button class=\"c2g-pl-item__menu-item\" type=\"button\" role=\"menuitem\" (click)=\"onMenuEdit()\">\n <span class=\"c2g-pl-item__menu-icon\">\u270F\uFE0F</span> Bearbeiten\n </button>\n <div class=\"c2g-pl-item__menu-divider\"></div>\n <button class=\"c2g-pl-item__menu-item c2g-pl-item__menu-item--danger\" type=\"button\" role=\"menuitem\" (click)=\"onMenuDelete()\">\n <span class=\"c2g-pl-item__menu-icon\">\uD83D\uDDD1</span> L\u00F6schen\n </button>\n }\n </div>\n }\n </div>\n }\n\n </div>\n\n <!-- Quantity Picker (Shared: eigene Menge) -->\n @if (quantityPickerOpen()) {\n <div class=\"c2g-pl-item__picker\" role=\"group\" aria-label=\"Menge w\u00E4hlen\">\n <span class=\"c2g-pl-item__picker-label\">{{ pickerLabel() }}</span>\n <button class=\"c2g-pl-item__qty-btn\" type=\"button\" (click)=\"decreaseSelfAssignQuantity()\">\u2212</button>\n <span class=\"c2g-pl-item__qty-val\">{{ quantityPickerValue() }}x</span>\n <button class=\"c2g-pl-item__qty-btn\" type=\"button\" (click)=\"increaseSelfAssignQuantity()\">+</button>\n <button class=\"c2g-pl-item__qty-ok\" type=\"button\" (click)=\"confirmSelfAssignQuantity()\">Best\u00E4tigen</button>\n <button class=\"c2g-pl-item__qty-cancel\" type=\"button\" (click)=\"cancelSelfAssignQuantity()\">Abbrechen</button>\n </div>\n }\n\n <!-- Delegate Dialog (Organizer weist anderem zu) -->\n @if (delegateDialogOpen()) {\n <div class=\"c2g-pl-item__picker\" role=\"dialog\" aria-label=\"Mitglied zuweisen\">\n <span class=\"c2g-pl-item__picker-label\">{{ delegatePickerLabel() }}</span>\n <select class=\"c2g-pl-item__select\" [value]=\"delegateMemberId() ?? ''\" (change)=\"onDelegateMemberChange($event)\">\n @for (member of delegateCandidates(); track member.id) {\n <option [value]=\"member.id\">{{ member.name }}</option>\n }\n </select>\n <button class=\"c2g-pl-item__qty-btn\" type=\"button\" (click)=\"decreaseDelegateQuantity()\">\u2212</button>\n <span class=\"c2g-pl-item__qty-val\">{{ delegateQuantity() }}x</span>\n <button class=\"c2g-pl-item__qty-btn\" type=\"button\" (click)=\"increaseDelegateQuantity()\">+</button>\n <button class=\"c2g-pl-item__qty-ok\" type=\"button\" (click)=\"confirmDelegateAssignment()\">Best\u00E4tigen</button>\n <button class=\"c2g-pl-item__qty-cancel\" type=\"button\" (click)=\"closeDelegateDialog()\">Abbrechen</button>\n </div>\n }\n\n <!-- Avatar Dialog (Menge eines Zugewiesenen \u00E4ndern) -->\n @if (avatarDialogOpen()) {\n <div class=\"c2g-pl-item__picker\" role=\"dialog\" aria-label=\"Zuteilung bearbeiten\">\n <span class=\"c2g-pl-item__picker-label\">Menge anpassen \u2013 0 zum Entfernen</span>\n <button class=\"c2g-pl-item__qty-btn\" type=\"button\" (click)=\"decreaseAvatarDialogQuantity()\">\u2212</button>\n <span class=\"c2g-pl-item__qty-val\">{{ avatarDialogQuantity() }}x</span>\n <button class=\"c2g-pl-item__qty-btn\" type=\"button\" (click)=\"increaseAvatarDialogQuantity()\">+</button>\n <button class=\"c2g-pl-item__qty-ok\" type=\"button\" (click)=\"confirmAvatarDialogUpdate()\">Best\u00E4tigen</button>\n <button class=\"c2g-pl-item__qty-cancel\" type=\"button\" (click)=\"closeAvatarDialog()\">Abbrechen</button>\n </div>\n }\n\n <!-- Personal Assign Panel -->\n @if (personalAssignDialogOpen()) {\n <div class=\"c2g-pl-item__assign-panel\" role=\"dialog\" aria-label=\"Mitglied zuweisen\">\n <input\n class=\"c2g-pl-item__assign-search\"\n type=\"search\"\n [value]=\"personalAssignSearch()\"\n placeholder=\"Mitglied suchen...\"\n (input)=\"onPersonalAssignSearch($event)\" />\n <div class=\"c2g-pl-item__assign-list\">\n @for (member of filteredPersonalAssignableMembers(); track member.id) {\n <button\n class=\"c2g-pl-item__assign-option\"\n [class.c2g-pl-item__assign-option--active]=\"personalAssignMemberId() === member.id\"\n type=\"button\"\n (click)=\"selectPersonalAssignMember(member.id)\">\n <c2g-avatar\n size=\"sm\"\n [name]=\"member.name\"\n [initials]=\"member.initials || ''\"\n [backgroundColor]=\"memberBackground(member)\">\n </c2g-avatar>\n <span>{{ member.name }}</span>\n </button>\n }\n </div>\n <div class=\"c2g-pl-item__assign-footer\">\n <button class=\"c2g-pl-item__qty-ok\" type=\"button\" [disabled]=\"!selectedPersonalAssignMember()\" (click)=\"confirmPersonalAssignment()\">Zuweisen</button>\n <button class=\"c2g-pl-item__qty-cancel\" type=\"button\" (click)=\"closePersonalAssignDialog()\">Abbrechen</button>\n </div>\n </div>\n }\n\n <!-- Hinweis -->\n @if (item().hint) {\n <p class=\"c2g-pl-item__hint\">{{ item().hint }}</p>\n }\n\n <!-- Shared: Mengen-Chips -->\n @if (sharedCountChips().length > 0) {\n <div class=\"c2g-pl-item__chip-row\">\n @for (chip of sharedCountChips(); track chip.key) {\n <c2g-badge [value]=\"chip.text\" [tone]=\"chip.tone\" variant=\"subtle\" size=\"sm\"></c2g-badge>\n }\n </div>\n }\n\n <!-- Personal: Status-Chips -->\n @if (personalStatusBadges().length > 0) {\n <div class=\"c2g-pl-item__chip-row\">\n @for (badge of personalStatusBadges(); track badge.key) {\n <c2g-badge\n [value]=\"badge.text\"\n [tone]=\"badge.tone\"\n variant=\"subtle\"\n size=\"sm\"\n [dot]=\"true\"\n [dotColor]=\"badge.dotColor\">\n </c2g-badge>\n }\n </div>\n }\n\n\n</div>\n", styles: [".c2g-pl-item{border:1px solid var(--c2g-color-outline-variant);border-radius:.625rem;padding:.65rem .75rem;background:var(--c2g-color-surface);display:grid;gap:.45rem;position:relative;transition:background .15s ease,border-color .15s ease}.c2g-pl-item--packed{background:color-mix(in srgb,#16a34a 6%,var(--c2g-color-surface));border-color:color-mix(in srgb,#16a34a 25%,transparent)}.c2g-pl-item--packed .c2g-pl-item__name{color:var(--c2g-color-text-muted);text-decoration:line-through;text-decoration-color:color-mix(in srgb,#16a34a 50%,transparent)}.c2g-pl-item__row{display:grid;grid-template-columns:.875rem minmax(0,1fr) auto;gap:.6rem;align-items:start}.c2g-pl-item__check{width:1.1rem;height:1.1rem;border:2px solid var(--c2g-color-outline);border-radius:.25rem;background:var(--c2g-color-surface);cursor:pointer;display:inline-flex;align-items:center;justify-content:center;padding:0;margin-top:.15rem;flex-shrink:0;transition:background .12s,border-color .12s}.c2g-pl-item__check:hover:not(:disabled){border-color:var(--c2g-color-secondary-dark)}.c2g-pl-item__check--done{background:var(--c2g-color-secondary-dark, #2d6a4f);border-color:var(--c2g-color-secondary-dark, #2d6a4f)}.c2g-pl-item__check-mark{color:#fff;font-size:.65rem;font-weight:800;line-height:1}.c2g-pl-item__dot{width:.5rem;height:.5rem;border-radius:50%;margin-top:.35rem;flex-shrink:0;background:var(--c2g-color-outline)}.c2g-pl-item__dot--danger{background:#ef4444}.c2g-pl-item__dot--warning{background:#f59e0b}.c2g-pl-item__dot--success{background:#16a34a}.c2g-pl-item__body{display:grid;gap:.4rem;min-width:0}.c2g-pl-item__title-row{display:flex;align-items:center;gap:.4rem;flex-wrap:wrap;min-width:0}.c2g-pl-item__qty-badge{margin-left:auto;flex-shrink:0}.c2g-pl-item__name{font-weight:600;font-size:.875rem;color:var(--c2g-color-text-primary);min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;transition:color .15s}.c2g-pl-item__tags{display:inline-flex;align-items:center;gap:.25rem;flex-wrap:wrap;flex-shrink:0}.c2g-pl-item__tag{font-size:.65rem;font-weight:500;border-radius:99px;padding:.1rem .4rem;background:var(--c2g-color-neutral-100);color:var(--c2g-color-text-muted);white-space:nowrap}.c2g-pl-item__tag--essential{background:color-mix(in srgb,#f59e0b 15%,transparent);color:#92400e}.c2g-pl-item__tag--weather{background:color-mix(in srgb,#3b82f6 12%,transparent);color:#1d4ed8}.c2g-pl-item__tag--private{background:var(--c2g-color-primary-container);color:var(--c2g-color-on-primary-container)}.c2g-pl-item__members-row{display:flex;align-items:center;flex-wrap:wrap;gap:.35rem}.c2g-pl-item__avatar-btn{border:0;background:transparent;padding:0;cursor:pointer;border-radius:50%;display:inline-flex}.c2g-pl-item__avatar-btn:disabled{cursor:default;opacity:.85}.c2g-pl-item__avatar-btn:not(:disabled):hover{transform:translateY(-1px);transition:transform .1s}.c2g-pl-item__more-wrap{position:relative;display:inline-flex}.c2g-pl-item__more{height:1.75rem;min-width:1.75rem;padding:0 .4rem;border-radius:99px;border:1px dashed var(--c2g-color-outline);background:transparent;color:var(--c2g-color-text-muted);font-size:.72rem;font-weight:600;cursor:pointer}.c2g-pl-item__more:hover{background:var(--c2g-color-neutral-100)}.c2g-pl-item__empty{font-size:.75rem;color:var(--c2g-color-text-muted);font-style:italic}.c2g-pl-item__join-btn{display:inline-flex;align-items:center;height:1.75rem;padding:0 .6rem;border-radius:99px;border:1.5px dashed var(--c2g-color-secondary-dark);background:transparent;color:var(--c2g-color-secondary-dark);font-size:.72rem;font-weight:600;cursor:pointer;white-space:nowrap;transition:background .1s}.c2g-pl-item__join-btn:hover{background:var(--c2g-color-secondary-container)}.c2g-pl-item__join-btn--active{border-style:solid;background:var(--c2g-color-secondary-container)}.c2g-pl-item__cta{position:relative;display:inline-grid;justify-items:end}.c2g-pl-item__menu-trigger{width:1.75rem;height:1.75rem;border:1px solid var(--c2g-color-outline-variant);border-radius:.4rem;background:transparent;color:var(--c2g-color-text-muted);font-size:1rem;line-height:1;cursor:pointer;display:inline-flex;align-items:center;justify-content:center;padding:0}.c2g-pl-item__menu-trigger:hover{background:var(--c2g-color-neutral-100);color:var(--c2g-color-text-primary)}.c2g-pl-item__menu{position:absolute;top:calc(100% + .3rem);right:0;min-width:10rem;border:1px solid var(--c2g-color-outline-variant);border-radius:.65rem;background:var(--c2g-color-surface);box-shadow:0 8px 24px #152b2124;padding:.3rem;display:grid;gap:.1rem;z-index:20}.c2g-pl-item__menu-item{display:flex;align-items:center;gap:.45rem;border:0;background:transparent;color:var(--c2g-color-text-primary);border-radius:.45rem;min-height:2rem;padding:.25rem .55rem;font-size:.82rem;text-align:left;cursor:pointer;width:100%}.c2g-pl-item__menu-item:hover{background:var(--c2g-color-neutral-100)}.c2g-pl-item__menu-item--danger{color:var(--c2g-color-error)}.c2g-pl-item__menu-icon{font-size:.85rem;line-height:1;flex-shrink:0}.c2g-pl-item__menu-divider{height:1px;background:var(--c2g-color-outline-variant);margin:.15rem .3rem}.c2g-pl-item__picker{display:flex;align-items:center;flex-wrap:wrap;gap:.3rem;padding:.45rem .6rem;border:1px solid var(--c2g-color-outline-variant);border-radius:.5rem;background:var(--c2g-color-neutral-50)}.c2g-pl-item__picker-label{font-size:.75rem;color:var(--c2g-color-text-muted);width:100%}.c2g-pl-item__qty-btn{width:1.6rem;height:1.6rem;border:1px solid var(--c2g-color-outline);border-radius:.35rem;background:var(--c2g-color-surface);color:var(--c2g-color-text-primary);font-size:1.1rem;line-height:1;cursor:pointer;display:inline-flex;align-items:center;justify-content:center;padding:0}.c2g-pl-item__qty-val{min-width:2rem;text-align:center;font-weight:700;font-size:.85rem}.c2g-pl-item__select{height:1.7rem;border:1px solid var(--c2g-color-outline);border-radius:.35rem;background:var(--c2g-color-surface);color:var(--c2g-color-text-primary);font-size:.78rem;padding:0 .5rem}.c2g-pl-item__qty-ok{height:1.7rem;padding:0 .65rem;border-radius:.35rem;border:1px solid var(--c2g-color-secondary-dark);background:var(--c2g-color-secondary-container);color:var(--c2g-color-secondary-dark);font-size:.76rem;font-weight:600;cursor:pointer}.c2g-pl-item__qty-ok:disabled{opacity:.45;cursor:not-allowed}.c2g-pl-item__qty-cancel{height:1.7rem;padding:0 .5rem;border-radius:.35rem;border:1px solid transparent;background:transparent;color:var(--c2g-color-text-muted);font-size:.76rem;cursor:pointer}.c2g-pl-item__qty-cancel:hover{background:var(--c2g-color-neutral-100)}.c2g-pl-item__assign-panel{display:grid;gap:.35rem;padding:.55rem;border:1px solid var(--c2g-color-outline-variant);border-radius:.65rem;background:var(--c2g-color-neutral-50)}.c2g-pl-item__assign-search{height:2rem;border:1px solid var(--c2g-color-outline);border-radius:.4rem;background:var(--c2g-color-surface);color:var(--c2g-color-text-primary);font-size:.82rem;padding:0 .65rem}.c2g-pl-item__assign-list{display:grid;gap:.2rem;max-height:10rem;overflow:auto}.c2g-pl-item__assign-option{display:flex;align-items:center;gap:.55rem;border:1px solid var(--c2g-color-outline-variant);background:var(--c2g-color-surface);color:var(--c2g-color-text-primary);border-radius:.45rem;min-height:2.2rem;padding:.3rem .6rem;font-size:.82rem;cursor:pointer;text-align:left}.c2g-pl-item__assign-option:hover{background:var(--c2g-color-neutral-100)}.c2g-pl-item__assign-option--active{border-color:var(--c2g-color-secondary-dark);background:var(--c2g-color-secondary-container)}.c2g-pl-item__assign-footer{display:flex;gap:.35rem}.c2g-pl-item__hint{margin:0;font-size:.78rem;color:var(--c2g-color-text-muted)}.c2g-pl-item__chip-row{display:flex;flex-wrap:wrap;gap:.3rem}.c2g-pl-item__overlay{position:absolute;top:calc(100% + .35rem);left:0;width:min(22rem,92vw);border:1px solid var(--c2g-color-outline);background:var(--c2g-color-surface);border-radius:.7rem;box-shadow:0 12px 32px #152b212e;padding:.6rem;display:grid;gap:.4rem;z-index:30}.c2g-pl-item__overlay-head{display:flex;align-items:center;justify-content:space-between;font-size:.88rem;font-weight:600}.c2g-pl-item__overlay-close{border:0;background:transparent;cursor:pointer;color:var(--c2g-color-text-secondary);font-size:.9rem;padding:.1rem .25rem;border-radius:.3rem}.c2g-pl-item__overlay-close:hover{background:var(--c2g-color-neutral-100)}.c2g-pl-item__overlay-search{height:2rem;border:1px solid var(--c2g-color-outline);border-radius:.4rem;padding:0 .6rem;font-size:.82rem}.c2g-pl-item__overlay-list{max-height:12rem;overflow:auto;display:grid;gap:.2rem}.c2g-pl-item__overlay-row{border:1px solid var(--c2g-color-outline-variant);background:var(--c2g-color-surface);border-radius:.45rem;padding:.4rem .55rem;display:flex;justify-content:space-between;align-items:center;font-size:.82rem;cursor:pointer;text-align:left}.c2g-pl-item__overlay-row:hover:not(:disabled){background:var(--c2g-color-neutral-100)}.c2g-pl-item__overlay-row:disabled{cursor:not-allowed;opacity:.55}.c2g-pl-item__overlay-status{font-size:.7rem;border-radius:99px;padding:.1rem .45rem;background:var(--c2g-color-neutral-100);color:var(--c2g-color-text-muted);white-space:nowrap}.c2g-pl-item__overlay-status--done{background:color-mix(in srgb,#16a34a 12%,transparent);color:#15803d}@media(max-width:480px){.c2g-pl-item__overlay{left:0;right:auto;width:calc(100vw - 2rem)}}\n"], dependencies: [{ kind: "component", type: AvatarComponent, selector: "c2g-avatar", inputs: ["name", "initials", "imageUrl", "ariaLabel", "size", "backgroundColor", "textColor", "ringTone", "ringColor", "clickable", "disabled", "badge"], outputs: ["avatarClick"] }, { kind: "component", type: BadgeComponent, selector: "c2g-badge", inputs: ["value", "tone", "variant", "size", "max", "dot", "dotOnly", "dotRing", "dotPulse", "dotColor", "ariaLabel"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
785
+ }
786
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: PackingListItemComponent, decorators: [{
787
+ type: Component,
788
+ args: [{ selector: 'c2g-packing-list-item', standalone: true, imports: [AvatarComponent, BadgeComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"c2g-pl-item\" [class.c2g-pl-item--packed]=\"isPacked()\">\n\n <div class=\"c2g-pl-item__row\">\n\n <!-- Solo: echte Checkbox -->\n @if (permissions().isSolo) {\n <button\n class=\"c2g-pl-item__check\"\n [class.c2g-pl-item__check--done]=\"isPacked()\"\n type=\"button\"\n [disabled]=\"permissions().readOnly\"\n [attr.aria-pressed]=\"isPacked()\"\n [attr.aria-label]=\"isPacked() ? 'Als ungepackt markieren' : 'Als gepackt markieren'\"\n (click)=\"onSoloToggle(!isPacked())\">\n @if (isPacked()) {\n <span class=\"c2g-pl-item__check-mark\" aria-hidden=\"true\">\u2713</span>\n }\n </button>\n } @else {\n <!-- Gruppen-Item: farbiger Fortschritts-Dot -->\n <span\n class=\"c2g-pl-item__dot\"\n [class.c2g-pl-item__dot--danger]=\"progressTone() === 'danger'\"\n [class.c2g-pl-item__dot--warning]=\"progressTone() === 'warning'\"\n [class.c2g-pl-item__dot--success]=\"progressTone() === 'success'\"\n [attr.title]=\"progressRatioText() + ' bereit'\"\n aria-hidden=\"true\">\n </span>\n }\n\n <!-- Body -->\n <div class=\"c2g-pl-item__body\">\n\n <!-- Zeile 1: Name + Tags + Mengen-Badge -->\n <div class=\"c2g-pl-item__title-row\">\n <span class=\"c2g-pl-item__name\">{{ item().name }}</span>\n <div class=\"c2g-pl-item__tags\">\n @if (item().essential) {\n <span class=\"c2g-pl-item__tag c2g-pl-item__tag--essential\">Pflicht</span>\n }\n @if (item().weather) {\n <span class=\"c2g-pl-item__tag c2g-pl-item__tag--weather\">Wetter</span>\n }\n @if (item().visibility === 'private') {\n <span class=\"c2g-pl-item__tag c2g-pl-item__tag--private\">\uD83D\uDD12 {{ privateItemOwnerLabel() }}</span>\n }\n </div>\n\n @if (quantityBadge(); as badge) {\n <c2g-badge\n class=\"c2g-pl-item__qty-badge\"\n [value]=\"badge.value\"\n [tone]=\"badge.tone\"\n variant=\"subtle\"\n size=\"sm\"\n [attr.aria-label]=\"'Gepackt: ' + badge.value\">\n </c2g-badge>\n }\n </div>\n\n <!-- Zeile 2: Mitglieder / Avatare -->\n @if (!permissions().isSolo) {\n <div class=\"c2g-pl-item__members-row\">\n\n @if (item().visibility === 'shared') {\n <!-- Assigned-Avatare -->\n @for (member of checkedPreview(); track member.id) {\n <button\n class=\"c2g-pl-item__avatar-btn\"\n type=\"button\"\n [disabled]=\"permissions().readOnly\"\n [attr.aria-label]=\"member.name + ' \u2013 antippen zum Bearbeiten'\"\n (click)=\"onSharedAvatarClick(member.id)\">\n <c2g-avatar\n size=\"sm\"\n [name]=\"member.name\"\n [initials]=\"member.initials || ''\"\n [backgroundColor]=\"memberBackground(member)\"\n [ringTone]=\"memberRingTone(member.id)\"\n [ringColor]=\"memberRingColor(member.id)\"\n [badge]=\"memberBadge(member.id)\">\n </c2g-avatar>\n </button>\n }\n\n @if (hiddenCheckedCount() > 0) {\n <div class=\"c2g-pl-item__more-wrap\">\n <button class=\"c2g-pl-item__more\" type=\"button\" (click)=\"openOverlay()\">\n +{{ hiddenCheckedCount() }}\n </button>\n @if (overlayOpen()) {\n <div class=\"c2g-pl-item__overlay\" role=\"dialog\" aria-label=\"Alle Mitglieder\">\n <div class=\"c2g-pl-item__overlay-head\">\n <strong>{{ item().name }}</strong>\n <button type=\"button\" class=\"c2g-pl-item__overlay-close\" (click)=\"closeOverlay()\">\u2715</button>\n </div>\n <input class=\"c2g-pl-item__overlay-search\" type=\"search\" [value]=\"overlaySearch()\" placeholder=\"Mitglied suchen...\" (input)=\"onOverlaySearch($event)\" />\n <div class=\"c2g-pl-item__overlay-list\">\n @for (member of filteredOverlayMembers(); track member.memberId) {\n <button class=\"c2g-pl-item__overlay-row\" type=\"button\" [disabled]=\"!member.canToggle\" (click)=\"toggleFromOverlay(member.memberId)\">\n <span>{{ member.memberName }}</span>\n <span class=\"c2g-pl-item__overlay-status\" [class.c2g-pl-item__overlay-status--done]=\"member.checked\">{{ member.checked ? '\u2713 bereit' : 'ausstehend' }}</span>\n </button>\n }\n </div>\n </div>\n }\n </div>\n }\n\n <!-- Empty state -->\n @if (checkedMembers().length === 0) {\n <span class=\"c2g-pl-item__empty\">Noch niemand eingetragen</span>\n }\n\n <!-- + Eintragen Button -->\n @if (canSelfAssignShared()) {\n <button\n class=\"c2g-pl-item__join-btn\"\n [class.c2g-pl-item__join-btn--active]=\"selfAssignedToShared()\"\n type=\"button\"\n (click)=\"onAssignMeToggle()\">\n {{ joinBtnLabel() }}\n </button>\n }\n\n } @else if (item().visibility === 'personal') {\n <!-- Personal: wer hat es f\u00FCr sich -->\n @for (member of personalAssignedPreview(); track member.id) {\n <button\n class=\"c2g-pl-item__avatar-btn\"\n type=\"button\"\n [disabled]=\"!canManagePersonalAssignments()\"\n [attr.aria-label]=\"member.name + ' \u2013 antippen zum Entfernen'\"\n (click)=\"onPersonalAvatarClick(member.id)\">\n <c2g-avatar\n size=\"sm\"\n [name]=\"member.name\"\n [initials]=\"member.initials || ''\"\n [backgroundColor]=\"memberBackground(member)\"\n [ringTone]=\"memberRingTone(member.id)\"\n [ringColor]=\"memberRingColor(member.id)\"\n [badge]=\"memberBadge(member.id)\">\n </c2g-avatar>\n </button>\n }\n\n @if (personalHiddenAssignedCount() > 0) {\n <div class=\"c2g-pl-item__more-wrap\">\n <button class=\"c2g-pl-item__more\" type=\"button\" (click)=\"openOverlay()\">\n +{{ personalHiddenAssignedCount() }}\n </button>\n @if (overlayOpen()) {\n <div class=\"c2g-pl-item__overlay\" role=\"dialog\" aria-label=\"Alle Mitglieder\">\n <div class=\"c2g-pl-item__overlay-head\">\n <strong>{{ item().name }}</strong>\n <button type=\"button\" class=\"c2g-pl-item__overlay-close\" (click)=\"closeOverlay()\">\u2715</button>\n </div>\n <input class=\"c2g-pl-item__overlay-search\" type=\"search\" [value]=\"overlaySearch()\" placeholder=\"Mitglied suchen...\" (input)=\"onOverlaySearch($event)\" />\n <div class=\"c2g-pl-item__overlay-list\">\n @for (member of filteredOverlayMembers(); track member.memberId) {\n <button class=\"c2g-pl-item__overlay-row\" type=\"button\" [disabled]=\"!member.canToggle\" (click)=\"toggleFromOverlay(member.memberId)\">\n <span>{{ member.memberName }}</span>\n <span class=\"c2g-pl-item__overlay-status\" [class.c2g-pl-item__overlay-status--done]=\"member.checked\">{{ member.checked ? '\u2713 bereit' : 'ausstehend' }}</span>\n </button>\n }\n </div>\n </div>\n }\n </div>\n }\n\n @if (personalAssignedMembers().length === 0) {\n <span class=\"c2g-pl-item__empty\">Nicht zugewiesen</span>\n }\n\n @if (canManagePersonalAssignments()) {\n <button class=\"c2g-pl-item__join-btn\" type=\"button\" (click)=\"openPersonalAssignDialog()\">\n + Zuweisen\n </button>\n }\n }\n\n </div>\n }\n\n </div>\n\n <!-- Aktions-Spalte: \u22EF Men\u00FC -->\n @if (canShowAssignCta() || canEditOrDeleteItem()) {\n <div class=\"c2g-pl-item__cta\">\n <button\n class=\"c2g-pl-item__menu-trigger\"\n type=\"button\"\n aria-label=\"Aktionen\"\n [attr.aria-expanded]=\"ctaMenuOpen()\"\n (click)=\"toggleCtaMenu()\">\n \u22EF\n </button>\n\n @if (ctaMenuOpen()) {\n <div class=\"c2g-pl-item__menu\" role=\"menu\">\n @if (canShowAssignCta()) {\n <button class=\"c2g-pl-item__menu-item\" type=\"button\" role=\"menuitem\" (click)=\"onMenuAssign()\">\n <span class=\"c2g-pl-item__menu-icon\">\uD83D\uDC64</span> {{ isPlanner() ? 'Zuweisen' : 'Einpacken' }}\n </button>\n }\n @if (canEditOrDeleteItem()) {\n <button class=\"c2g-pl-item__menu-item\" type=\"button\" role=\"menuitem\" (click)=\"onMenuEdit()\">\n <span class=\"c2g-pl-item__menu-icon\">\u270F\uFE0F</span> Bearbeiten\n </button>\n <div class=\"c2g-pl-item__menu-divider\"></div>\n <button class=\"c2g-pl-item__menu-item c2g-pl-item__menu-item--danger\" type=\"button\" role=\"menuitem\" (click)=\"onMenuDelete()\">\n <span class=\"c2g-pl-item__menu-icon\">\uD83D\uDDD1</span> L\u00F6schen\n </button>\n }\n </div>\n }\n </div>\n }\n\n </div>\n\n <!-- Quantity Picker (Shared: eigene Menge) -->\n @if (quantityPickerOpen()) {\n <div class=\"c2g-pl-item__picker\" role=\"group\" aria-label=\"Menge w\u00E4hlen\">\n <span class=\"c2g-pl-item__picker-label\">{{ pickerLabel() }}</span>\n <button class=\"c2g-pl-item__qty-btn\" type=\"button\" (click)=\"decreaseSelfAssignQuantity()\">\u2212</button>\n <span class=\"c2g-pl-item__qty-val\">{{ quantityPickerValue() }}x</span>\n <button class=\"c2g-pl-item__qty-btn\" type=\"button\" (click)=\"increaseSelfAssignQuantity()\">+</button>\n <button class=\"c2g-pl-item__qty-ok\" type=\"button\" (click)=\"confirmSelfAssignQuantity()\">Best\u00E4tigen</button>\n <button class=\"c2g-pl-item__qty-cancel\" type=\"button\" (click)=\"cancelSelfAssignQuantity()\">Abbrechen</button>\n </div>\n }\n\n <!-- Delegate Dialog (Organizer weist anderem zu) -->\n @if (delegateDialogOpen()) {\n <div class=\"c2g-pl-item__picker\" role=\"dialog\" aria-label=\"Mitglied zuweisen\">\n <span class=\"c2g-pl-item__picker-label\">{{ delegatePickerLabel() }}</span>\n <select class=\"c2g-pl-item__select\" [value]=\"delegateMemberId() ?? ''\" (change)=\"onDelegateMemberChange($event)\">\n @for (member of delegateCandidates(); track member.id) {\n <option [value]=\"member.id\">{{ member.name }}</option>\n }\n </select>\n <button class=\"c2g-pl-item__qty-btn\" type=\"button\" (click)=\"decreaseDelegateQuantity()\">\u2212</button>\n <span class=\"c2g-pl-item__qty-val\">{{ delegateQuantity() }}x</span>\n <button class=\"c2g-pl-item__qty-btn\" type=\"button\" (click)=\"increaseDelegateQuantity()\">+</button>\n <button class=\"c2g-pl-item__qty-ok\" type=\"button\" (click)=\"confirmDelegateAssignment()\">Best\u00E4tigen</button>\n <button class=\"c2g-pl-item__qty-cancel\" type=\"button\" (click)=\"closeDelegateDialog()\">Abbrechen</button>\n </div>\n }\n\n <!-- Avatar Dialog (Menge eines Zugewiesenen \u00E4ndern) -->\n @if (avatarDialogOpen()) {\n <div class=\"c2g-pl-item__picker\" role=\"dialog\" aria-label=\"Zuteilung bearbeiten\">\n <span class=\"c2g-pl-item__picker-label\">Menge anpassen \u2013 0 zum Entfernen</span>\n <button class=\"c2g-pl-item__qty-btn\" type=\"button\" (click)=\"decreaseAvatarDialogQuantity()\">\u2212</button>\n <span class=\"c2g-pl-item__qty-val\">{{ avatarDialogQuantity() }}x</span>\n <button class=\"c2g-pl-item__qty-btn\" type=\"button\" (click)=\"increaseAvatarDialogQuantity()\">+</button>\n <button class=\"c2g-pl-item__qty-ok\" type=\"button\" (click)=\"confirmAvatarDialogUpdate()\">Best\u00E4tigen</button>\n <button class=\"c2g-pl-item__qty-cancel\" type=\"button\" (click)=\"closeAvatarDialog()\">Abbrechen</button>\n </div>\n }\n\n <!-- Personal Assign Panel -->\n @if (personalAssignDialogOpen()) {\n <div class=\"c2g-pl-item__assign-panel\" role=\"dialog\" aria-label=\"Mitglied zuweisen\">\n <input\n class=\"c2g-pl-item__assign-search\"\n type=\"search\"\n [value]=\"personalAssignSearch()\"\n placeholder=\"Mitglied suchen...\"\n (input)=\"onPersonalAssignSearch($event)\" />\n <div class=\"c2g-pl-item__assign-list\">\n @for (member of filteredPersonalAssignableMembers(); track member.id) {\n <button\n class=\"c2g-pl-item__assign-option\"\n [class.c2g-pl-item__assign-option--active]=\"personalAssignMemberId() === member.id\"\n type=\"button\"\n (click)=\"selectPersonalAssignMember(member.id)\">\n <c2g-avatar\n size=\"sm\"\n [name]=\"member.name\"\n [initials]=\"member.initials || ''\"\n [backgroundColor]=\"memberBackground(member)\">\n </c2g-avatar>\n <span>{{ member.name }}</span>\n </button>\n }\n </div>\n <div class=\"c2g-pl-item__assign-footer\">\n <button class=\"c2g-pl-item__qty-ok\" type=\"button\" [disabled]=\"!selectedPersonalAssignMember()\" (click)=\"confirmPersonalAssignment()\">Zuweisen</button>\n <button class=\"c2g-pl-item__qty-cancel\" type=\"button\" (click)=\"closePersonalAssignDialog()\">Abbrechen</button>\n </div>\n </div>\n }\n\n <!-- Hinweis -->\n @if (item().hint) {\n <p class=\"c2g-pl-item__hint\">{{ item().hint }}</p>\n }\n\n <!-- Shared: Mengen-Chips -->\n @if (sharedCountChips().length > 0) {\n <div class=\"c2g-pl-item__chip-row\">\n @for (chip of sharedCountChips(); track chip.key) {\n <c2g-badge [value]=\"chip.text\" [tone]=\"chip.tone\" variant=\"subtle\" size=\"sm\"></c2g-badge>\n }\n </div>\n }\n\n <!-- Personal: Status-Chips -->\n @if (personalStatusBadges().length > 0) {\n <div class=\"c2g-pl-item__chip-row\">\n @for (badge of personalStatusBadges(); track badge.key) {\n <c2g-badge\n [value]=\"badge.text\"\n [tone]=\"badge.tone\"\n variant=\"subtle\"\n size=\"sm\"\n [dot]=\"true\"\n [dotColor]=\"badge.dotColor\">\n </c2g-badge>\n }\n </div>\n }\n\n\n</div>\n", styles: [".c2g-pl-item{border:1px solid var(--c2g-color-outline-variant);border-radius:.625rem;padding:.65rem .75rem;background:var(--c2g-color-surface);display:grid;gap:.45rem;position:relative;transition:background .15s ease,border-color .15s ease}.c2g-pl-item--packed{background:color-mix(in srgb,#16a34a 6%,var(--c2g-color-surface));border-color:color-mix(in srgb,#16a34a 25%,transparent)}.c2g-pl-item--packed .c2g-pl-item__name{color:var(--c2g-color-text-muted);text-decoration:line-through;text-decoration-color:color-mix(in srgb,#16a34a 50%,transparent)}.c2g-pl-item__row{display:grid;grid-template-columns:.875rem minmax(0,1fr) auto;gap:.6rem;align-items:start}.c2g-pl-item__check{width:1.1rem;height:1.1rem;border:2px solid var(--c2g-color-outline);border-radius:.25rem;background:var(--c2g-color-surface);cursor:pointer;display:inline-flex;align-items:center;justify-content:center;padding:0;margin-top:.15rem;flex-shrink:0;transition:background .12s,border-color .12s}.c2g-pl-item__check:hover:not(:disabled){border-color:var(--c2g-color-secondary-dark)}.c2g-pl-item__check--done{background:var(--c2g-color-secondary-dark, #2d6a4f);border-color:var(--c2g-color-secondary-dark, #2d6a4f)}.c2g-pl-item__check-mark{color:#fff;font-size:.65rem;font-weight:800;line-height:1}.c2g-pl-item__dot{width:.5rem;height:.5rem;border-radius:50%;margin-top:.35rem;flex-shrink:0;background:var(--c2g-color-outline)}.c2g-pl-item__dot--danger{background:#ef4444}.c2g-pl-item__dot--warning{background:#f59e0b}.c2g-pl-item__dot--success{background:#16a34a}.c2g-pl-item__body{display:grid;gap:.4rem;min-width:0}.c2g-pl-item__title-row{display:flex;align-items:center;gap:.4rem;flex-wrap:wrap;min-width:0}.c2g-pl-item__qty-badge{margin-left:auto;flex-shrink:0}.c2g-pl-item__name{font-weight:600;font-size:.875rem;color:var(--c2g-color-text-primary);min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;transition:color .15s}.c2g-pl-item__tags{display:inline-flex;align-items:center;gap:.25rem;flex-wrap:wrap;flex-shrink:0}.c2g-pl-item__tag{font-size:.65rem;font-weight:500;border-radius:99px;padding:.1rem .4rem;background:var(--c2g-color-neutral-100);color:var(--c2g-color-text-muted);white-space:nowrap}.c2g-pl-item__tag--essential{background:color-mix(in srgb,#f59e0b 15%,transparent);color:#92400e}.c2g-pl-item__tag--weather{background:color-mix(in srgb,#3b82f6 12%,transparent);color:#1d4ed8}.c2g-pl-item__tag--private{background:var(--c2g-color-primary-container);color:var(--c2g-color-on-primary-container)}.c2g-pl-item__members-row{display:flex;align-items:center;flex-wrap:wrap;gap:.35rem}.c2g-pl-item__avatar-btn{border:0;background:transparent;padding:0;cursor:pointer;border-radius:50%;display:inline-flex}.c2g-pl-item__avatar-btn:disabled{cursor:default;opacity:.85}.c2g-pl-item__avatar-btn:not(:disabled):hover{transform:translateY(-1px);transition:transform .1s}.c2g-pl-item__more-wrap{position:relative;display:inline-flex}.c2g-pl-item__more{height:1.75rem;min-width:1.75rem;padding:0 .4rem;border-radius:99px;border:1px dashed var(--c2g-color-outline);background:transparent;color:var(--c2g-color-text-muted);font-size:.72rem;font-weight:600;cursor:pointer}.c2g-pl-item__more:hover{background:var(--c2g-color-neutral-100)}.c2g-pl-item__empty{font-size:.75rem;color:var(--c2g-color-text-muted);font-style:italic}.c2g-pl-item__join-btn{display:inline-flex;align-items:center;height:1.75rem;padding:0 .6rem;border-radius:99px;border:1.5px dashed var(--c2g-color-secondary-dark);background:transparent;color:var(--c2g-color-secondary-dark);font-size:.72rem;font-weight:600;cursor:pointer;white-space:nowrap;transition:background .1s}.c2g-pl-item__join-btn:hover{background:var(--c2g-color-secondary-container)}.c2g-pl-item__join-btn--active{border-style:solid;background:var(--c2g-color-secondary-container)}.c2g-pl-item__cta{position:relative;display:inline-grid;justify-items:end}.c2g-pl-item__menu-trigger{width:1.75rem;height:1.75rem;border:1px solid var(--c2g-color-outline-variant);border-radius:.4rem;background:transparent;color:var(--c2g-color-text-muted);font-size:1rem;line-height:1;cursor:pointer;display:inline-flex;align-items:center;justify-content:center;padding:0}.c2g-pl-item__menu-trigger:hover{background:var(--c2g-color-neutral-100);color:var(--c2g-color-text-primary)}.c2g-pl-item__menu{position:absolute;top:calc(100% + .3rem);right:0;min-width:10rem;border:1px solid var(--c2g-color-outline-variant);border-radius:.65rem;background:var(--c2g-color-surface);box-shadow:0 8px 24px #152b2124;padding:.3rem;display:grid;gap:.1rem;z-index:20}.c2g-pl-item__menu-item{display:flex;align-items:center;gap:.45rem;border:0;background:transparent;color:var(--c2g-color-text-primary);border-radius:.45rem;min-height:2rem;padding:.25rem .55rem;font-size:.82rem;text-align:left;cursor:pointer;width:100%}.c2g-pl-item__menu-item:hover{background:var(--c2g-color-neutral-100)}.c2g-pl-item__menu-item--danger{color:var(--c2g-color-error)}.c2g-pl-item__menu-icon{font-size:.85rem;line-height:1;flex-shrink:0}.c2g-pl-item__menu-divider{height:1px;background:var(--c2g-color-outline-variant);margin:.15rem .3rem}.c2g-pl-item__picker{display:flex;align-items:center;flex-wrap:wrap;gap:.3rem;padding:.45rem .6rem;border:1px solid var(--c2g-color-outline-variant);border-radius:.5rem;background:var(--c2g-color-neutral-50)}.c2g-pl-item__picker-label{font-size:.75rem;color:var(--c2g-color-text-muted);width:100%}.c2g-pl-item__qty-btn{width:1.6rem;height:1.6rem;border:1px solid var(--c2g-color-outline);border-radius:.35rem;background:var(--c2g-color-surface);color:var(--c2g-color-text-primary);font-size:1.1rem;line-height:1;cursor:pointer;display:inline-flex;align-items:center;justify-content:center;padding:0}.c2g-pl-item__qty-val{min-width:2rem;text-align:center;font-weight:700;font-size:.85rem}.c2g-pl-item__select{height:1.7rem;border:1px solid var(--c2g-color-outline);border-radius:.35rem;background:var(--c2g-color-surface);color:var(--c2g-color-text-primary);font-size:.78rem;padding:0 .5rem}.c2g-pl-item__qty-ok{height:1.7rem;padding:0 .65rem;border-radius:.35rem;border:1px solid var(--c2g-color-secondary-dark);background:var(--c2g-color-secondary-container);color:var(--c2g-color-secondary-dark);font-size:.76rem;font-weight:600;cursor:pointer}.c2g-pl-item__qty-ok:disabled{opacity:.45;cursor:not-allowed}.c2g-pl-item__qty-cancel{height:1.7rem;padding:0 .5rem;border-radius:.35rem;border:1px solid transparent;background:transparent;color:var(--c2g-color-text-muted);font-size:.76rem;cursor:pointer}.c2g-pl-item__qty-cancel:hover{background:var(--c2g-color-neutral-100)}.c2g-pl-item__assign-panel{display:grid;gap:.35rem;padding:.55rem;border:1px solid var(--c2g-color-outline-variant);border-radius:.65rem;background:var(--c2g-color-neutral-50)}.c2g-pl-item__assign-search{height:2rem;border:1px solid var(--c2g-color-outline);border-radius:.4rem;background:var(--c2g-color-surface);color:var(--c2g-color-text-primary);font-size:.82rem;padding:0 .65rem}.c2g-pl-item__assign-list{display:grid;gap:.2rem;max-height:10rem;overflow:auto}.c2g-pl-item__assign-option{display:flex;align-items:center;gap:.55rem;border:1px solid var(--c2g-color-outline-variant);background:var(--c2g-color-surface);color:var(--c2g-color-text-primary);border-radius:.45rem;min-height:2.2rem;padding:.3rem .6rem;font-size:.82rem;cursor:pointer;text-align:left}.c2g-pl-item__assign-option:hover{background:var(--c2g-color-neutral-100)}.c2g-pl-item__assign-option--active{border-color:var(--c2g-color-secondary-dark);background:var(--c2g-color-secondary-container)}.c2g-pl-item__assign-footer{display:flex;gap:.35rem}.c2g-pl-item__hint{margin:0;font-size:.78rem;color:var(--c2g-color-text-muted)}.c2g-pl-item__chip-row{display:flex;flex-wrap:wrap;gap:.3rem}.c2g-pl-item__overlay{position:absolute;top:calc(100% + .35rem);left:0;width:min(22rem,92vw);border:1px solid var(--c2g-color-outline);background:var(--c2g-color-surface);border-radius:.7rem;box-shadow:0 12px 32px #152b212e;padding:.6rem;display:grid;gap:.4rem;z-index:30}.c2g-pl-item__overlay-head{display:flex;align-items:center;justify-content:space-between;font-size:.88rem;font-weight:600}.c2g-pl-item__overlay-close{border:0;background:transparent;cursor:pointer;color:var(--c2g-color-text-secondary);font-size:.9rem;padding:.1rem .25rem;border-radius:.3rem}.c2g-pl-item__overlay-close:hover{background:var(--c2g-color-neutral-100)}.c2g-pl-item__overlay-search{height:2rem;border:1px solid var(--c2g-color-outline);border-radius:.4rem;padding:0 .6rem;font-size:.82rem}.c2g-pl-item__overlay-list{max-height:12rem;overflow:auto;display:grid;gap:.2rem}.c2g-pl-item__overlay-row{border:1px solid var(--c2g-color-outline-variant);background:var(--c2g-color-surface);border-radius:.45rem;padding:.4rem .55rem;display:flex;justify-content:space-between;align-items:center;font-size:.82rem;cursor:pointer;text-align:left}.c2g-pl-item__overlay-row:hover:not(:disabled){background:var(--c2g-color-neutral-100)}.c2g-pl-item__overlay-row:disabled{cursor:not-allowed;opacity:.55}.c2g-pl-item__overlay-status{font-size:.7rem;border-radius:99px;padding:.1rem .45rem;background:var(--c2g-color-neutral-100);color:var(--c2g-color-text-muted);white-space:nowrap}.c2g-pl-item__overlay-status--done{background:color-mix(in srgb,#16a34a 12%,transparent);color:#15803d}@media(max-width:480px){.c2g-pl-item__overlay{left:0;right:auto;width:calc(100vw - 2rem)}}\n"] }]
789
+ }], propDecorators: { item: [{ type: i0.Input, args: [{ isSignal: true, alias: "item", required: true }] }], members: [{ type: i0.Input, args: [{ isSignal: true, alias: "members", required: true }] }], currentUserId: [{ type: i0.Input, args: [{ isSignal: true, alias: "currentUserId", required: true }] }], permissions: [{ type: i0.Input, args: [{ isSignal: true, alias: "permissions", required: true }] }], selectedMemberIds: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedMemberIds", required: false }] }], itemChecked: [{ type: i0.Output, args: ["itemChecked"] }], itemAssigned: [{ type: i0.Output, args: ["itemAssigned"] }], itemDeleted: [{ type: i0.Output, args: ["itemDeleted"] }], itemEditRequested: [{ type: i0.Output, args: ["itemEditRequested"] }], personalItemToggled: [{ type: i0.Output, args: ["personalItemToggled"] }], memberOverlayRequested: [{ type: i0.Output, args: ["memberOverlayRequested"] }] } });
790
+
791
+ class PackingListCategoryComponent {
792
+ categoryKey = input.required(...(ngDevMode ? [{ debugName: "categoryKey" }] : []));
793
+ items = input.required(...(ngDevMode ? [{ debugName: "items" }] : []));
794
+ members = input.required(...(ngDevMode ? [{ debugName: "members" }] : []));
795
+ selectedMemberIds = input([], ...(ngDevMode ? [{ debugName: "selectedMemberIds" }] : []));
796
+ currentUserId = input.required(...(ngDevMode ? [{ debugName: "currentUserId" }] : []));
797
+ permissions = input.required(...(ngDevMode ? [{ debugName: "permissions" }] : []));
798
+ expanded = input(true, ...(ngDevMode ? [{ debugName: "expanded" }] : []));
799
+ toggle = output();
800
+ itemChecked = output();
801
+ itemAssigned = output();
802
+ itemDeleted = output();
803
+ itemEditRequested = output();
804
+ personalItemToggled = output();
805
+ memberOverlayRequested = output();
806
+ category = computed(() => resolvePackingCategory(this.categoryKey()), ...(ngDevMode ? [{ debugName: "category" }] : []));
807
+ stats = computed(() => {
808
+ const list = this.items();
809
+ return {
810
+ total: list.length,
811
+ essential: list.filter(item => !!item.essential).length,
812
+ packed: list.filter(item => (item.assignments ?? []).some(a => a.status === 'packed' || a.status === 'confirmed')).length
813
+ };
814
+ }, ...(ngDevMode ? [{ debugName: "stats" }] : []));
815
+ onToggle() {
816
+ this.toggle.emit(this.categoryKey());
817
+ }
818
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: PackingListCategoryComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
819
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: PackingListCategoryComponent, isStandalone: true, selector: "c2g-packing-list-category", inputs: { categoryKey: { classPropertyName: "categoryKey", publicName: "categoryKey", isSignal: true, isRequired: true, transformFunction: null }, items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: true, transformFunction: null }, members: { classPropertyName: "members", publicName: "members", isSignal: true, isRequired: true, transformFunction: null }, selectedMemberIds: { classPropertyName: "selectedMemberIds", publicName: "selectedMemberIds", isSignal: true, isRequired: false, transformFunction: null }, currentUserId: { classPropertyName: "currentUserId", publicName: "currentUserId", isSignal: true, isRequired: true, transformFunction: null }, permissions: { classPropertyName: "permissions", publicName: "permissions", isSignal: true, isRequired: true, transformFunction: null }, expanded: { classPropertyName: "expanded", publicName: "expanded", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { toggle: "toggle", itemChecked: "itemChecked", itemAssigned: "itemAssigned", itemDeleted: "itemDeleted", itemEditRequested: "itemEditRequested", personalItemToggled: "personalItemToggled", memberOverlayRequested: "memberOverlayRequested" }, ngImport: i0, template: "<section class=\"c2g-pl-category\">\n <button type=\"button\" class=\"c2g-pl-category__header\" [class.c2g-pl-category__header--done]=\"stats().packed === stats().total && stats().total > 0\" (click)=\"onToggle()\">\n <mat-icon class=\"c2g-pl-category__icon\" aria-hidden=\"true\">{{ category().icon }}</mat-icon>\n <span class=\"c2g-pl-category__label\">{{ category().label ?? category().labelKey }}</span>\n <span class=\"c2g-pl-category__meta\">{{ stats().packed }}/{{ stats().total }}</span>\n <span class=\"c2g-pl-category__chevron\" [class.c2g-pl-category__chevron--open]=\"expanded()\" aria-hidden=\"true\">\u25BE</span>\n </button>\n\n @if (expanded()) {\n <div class=\"c2g-pl-category__items\">\n @for (item of items(); track item.id) {\n <c2g-packing-list-item\n [item]=\"item\"\n [members]=\"members()\"\n [selectedMemberIds]=\"selectedMemberIds()\"\n [currentUserId]=\"currentUserId()\"\n [permissions]=\"permissions()\"\n (itemChecked)=\"itemChecked.emit($event)\"\n (itemAssigned)=\"itemAssigned.emit($event)\"\n (itemDeleted)=\"itemDeleted.emit($event)\"\n (itemEditRequested)=\"itemEditRequested.emit($event)\"\n (personalItemToggled)=\"personalItemToggled.emit($event)\"\n (memberOverlayRequested)=\"memberOverlayRequested.emit($event)\">\n </c2g-packing-list-item>\n }\n </div>\n }\n</section>\n", styles: [".c2g-pl-category{border:1px solid var(--c2g-color-outline-variant);border-radius:.75rem;overflow:hidden;background:var(--c2g-color-surface)}.c2g-pl-category__header{width:100%;border:0;background:var(--c2g-color-neutral-50);padding:.6rem .75rem;display:grid;grid-template-columns:auto 1fr auto auto;gap:.45rem;align-items:center;text-align:left;cursor:pointer;font-weight:600;color:var(--c2g-color-text-primary)}.c2g-pl-category__header--done{background:var(--c2g-color-secondary-container);color:var(--c2g-color-secondary-dark)}.c2g-pl-category__label{font-size:.88rem}.c2g-pl-category__icon{font-size:1.1rem!important;width:1.1rem!important;height:1.1rem!important;line-height:1!important;color:var(--c2g-color-text-muted);flex-shrink:0}.c2g-pl-category__meta{font-size:.78rem;color:var(--c2g-color-text-muted);font-weight:500}.c2g-pl-category__chevron{font-size:.8rem;color:var(--c2g-color-text-muted);transition:transform .2s ease;line-height:1}.c2g-pl-category__chevron--open{transform:rotate(180deg)}.c2g-pl-category__items{display:grid;gap:.55rem;padding:.6rem}\n"], dependencies: [{ kind: "component", type: PackingListItemComponent, selector: "c2g-packing-list-item", inputs: ["item", "members", "currentUserId", "permissions", "selectedMemberIds"], outputs: ["itemChecked", "itemAssigned", "itemDeleted", "itemEditRequested", "personalItemToggled", "memberOverlayRequested"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
820
+ }
821
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: PackingListCategoryComponent, decorators: [{
822
+ type: Component,
823
+ args: [{ selector: 'c2g-packing-list-category', standalone: true, imports: [PackingListItemComponent, MatIconModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<section class=\"c2g-pl-category\">\n <button type=\"button\" class=\"c2g-pl-category__header\" [class.c2g-pl-category__header--done]=\"stats().packed === stats().total && stats().total > 0\" (click)=\"onToggle()\">\n <mat-icon class=\"c2g-pl-category__icon\" aria-hidden=\"true\">{{ category().icon }}</mat-icon>\n <span class=\"c2g-pl-category__label\">{{ category().label ?? category().labelKey }}</span>\n <span class=\"c2g-pl-category__meta\">{{ stats().packed }}/{{ stats().total }}</span>\n <span class=\"c2g-pl-category__chevron\" [class.c2g-pl-category__chevron--open]=\"expanded()\" aria-hidden=\"true\">\u25BE</span>\n </button>\n\n @if (expanded()) {\n <div class=\"c2g-pl-category__items\">\n @for (item of items(); track item.id) {\n <c2g-packing-list-item\n [item]=\"item\"\n [members]=\"members()\"\n [selectedMemberIds]=\"selectedMemberIds()\"\n [currentUserId]=\"currentUserId()\"\n [permissions]=\"permissions()\"\n (itemChecked)=\"itemChecked.emit($event)\"\n (itemAssigned)=\"itemAssigned.emit($event)\"\n (itemDeleted)=\"itemDeleted.emit($event)\"\n (itemEditRequested)=\"itemEditRequested.emit($event)\"\n (personalItemToggled)=\"personalItemToggled.emit($event)\"\n (memberOverlayRequested)=\"memberOverlayRequested.emit($event)\">\n </c2g-packing-list-item>\n }\n </div>\n }\n</section>\n", styles: [".c2g-pl-category{border:1px solid var(--c2g-color-outline-variant);border-radius:.75rem;overflow:hidden;background:var(--c2g-color-surface)}.c2g-pl-category__header{width:100%;border:0;background:var(--c2g-color-neutral-50);padding:.6rem .75rem;display:grid;grid-template-columns:auto 1fr auto auto;gap:.45rem;align-items:center;text-align:left;cursor:pointer;font-weight:600;color:var(--c2g-color-text-primary)}.c2g-pl-category__header--done{background:var(--c2g-color-secondary-container);color:var(--c2g-color-secondary-dark)}.c2g-pl-category__label{font-size:.88rem}.c2g-pl-category__icon{font-size:1.1rem!important;width:1.1rem!important;height:1.1rem!important;line-height:1!important;color:var(--c2g-color-text-muted);flex-shrink:0}.c2g-pl-category__meta{font-size:.78rem;color:var(--c2g-color-text-muted);font-weight:500}.c2g-pl-category__chevron{font-size:.8rem;color:var(--c2g-color-text-muted);transition:transform .2s ease;line-height:1}.c2g-pl-category__chevron--open{transform:rotate(180deg)}.c2g-pl-category__items{display:grid;gap:.55rem;padding:.6rem}\n"] }]
824
+ }], propDecorators: { categoryKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "categoryKey", required: true }] }], items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: true }] }], members: [{ type: i0.Input, args: [{ isSignal: true, alias: "members", required: true }] }], selectedMemberIds: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedMemberIds", required: false }] }], currentUserId: [{ type: i0.Input, args: [{ isSignal: true, alias: "currentUserId", required: true }] }], permissions: [{ type: i0.Input, args: [{ isSignal: true, alias: "permissions", required: true }] }], expanded: [{ type: i0.Input, args: [{ isSignal: true, alias: "expanded", required: false }] }], toggle: [{ type: i0.Output, args: ["toggle"] }], itemChecked: [{ type: i0.Output, args: ["itemChecked"] }], itemAssigned: [{ type: i0.Output, args: ["itemAssigned"] }], itemDeleted: [{ type: i0.Output, args: ["itemDeleted"] }], itemEditRequested: [{ type: i0.Output, args: ["itemEditRequested"] }], personalItemToggled: [{ type: i0.Output, args: ["personalItemToggled"] }], memberOverlayRequested: [{ type: i0.Output, args: ["memberOverlayRequested"] }] } });
825
+
826
+ class PackingListFiltersComponent {
827
+ filter = input.required(...(ngDevMode ? [{ debugName: "filter" }] : []));
828
+ members = input([], ...(ngDevMode ? [{ debugName: "members" }] : []));
829
+ labels = input(DEFAULT_PACKING_LIST_LABEL_KEYS, ...(ngDevMode ? [{ debugName: "labels" }] : []));
830
+ disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
831
+ filterChange = output();
832
+ overlayRequested = output();
833
+ membersPanelOpen = signal(false, ...(ngDevMode ? [{ debugName: "membersPanelOpen" }] : []));
834
+ memberQuery = signal('', ...(ngDevMode ? [{ debugName: "memberQuery" }] : []));
835
+ memberSelectionLabel = computed(() => {
836
+ const selected = this.filter().memberIds.length;
837
+ if (selected === 0) {
838
+ return 'Alle User';
839
+ }
840
+ if (selected === 1) {
841
+ return '1 User';
842
+ }
843
+ return `${selected} User`;
844
+ }, ...(ngDevMode ? [{ debugName: "memberSelectionLabel" }] : []));
845
+ filteredMembers = computed(() => {
846
+ const query = this.memberQuery().trim().toLowerCase();
847
+ if (!query) {
848
+ return this.members();
849
+ }
850
+ return this.members().filter(member => {
851
+ const searchable = `${member.name} ${member.initials ?? ''}`.toLowerCase();
852
+ return searchable.includes(query);
853
+ });
854
+ }, ...(ngDevMode ? [{ debugName: "filteredMembers" }] : []));
855
+ onQueryChange(event) {
856
+ const query = event.target.value;
857
+ this.filterChange.emit({ ...this.filter(), query });
858
+ }
859
+ onVisibilityChange(event) {
860
+ const visibility = event.target.value;
861
+ this.filterChange.emit({ ...this.filter(), visibility });
862
+ }
863
+ onEssentialsOnlyToggle(event) {
864
+ const essentialsOnly = event.target.checked;
865
+ this.filterChange.emit({ ...this.filter(), essentialsOnly });
866
+ }
867
+ toggleMembersPanel() {
868
+ if (this.disabled()) {
869
+ return;
870
+ }
871
+ this.membersPanelOpen.update(open => !open);
872
+ }
873
+ onMemberSearch(event) {
874
+ this.memberQuery.set(event.target.value);
875
+ }
876
+ isMemberSelected(memberId) {
877
+ return this.filter().memberIds.includes(memberId);
878
+ }
879
+ toggleMember(memberId) {
880
+ if (this.disabled()) {
881
+ return;
882
+ }
883
+ const selected = new Set(this.filter().memberIds);
884
+ if (selected.has(memberId)) {
885
+ selected.delete(memberId);
886
+ }
887
+ else {
888
+ selected.add(memberId);
889
+ }
890
+ this.filterChange.emit({ ...this.filter(), memberIds: Array.from(selected) });
891
+ }
892
+ clearMemberSelection() {
893
+ this.filterChange.emit({ ...this.filter(), memberIds: [] });
894
+ }
895
+ selectAllMembers() {
896
+ this.filterChange.emit({ ...this.filter(), memberIds: this.members().map(member => member.id) });
897
+ }
898
+ requestExternalOverlay() {
899
+ this.overlayRequested.emit();
900
+ }
901
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: PackingListFiltersComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
902
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: PackingListFiltersComponent, isStandalone: true, selector: "c2g-packing-list-filters", inputs: { filter: { classPropertyName: "filter", publicName: "filter", isSignal: true, isRequired: true, transformFunction: null }, members: { classPropertyName: "members", publicName: "members", isSignal: true, isRequired: false, transformFunction: null }, labels: { classPropertyName: "labels", publicName: "labels", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { filterChange: "filterChange", overlayRequested: "overlayRequested" }, ngImport: i0, template: "<div class=\"c2g-pl-filters\">\n <input\n class=\"c2g-pl-filters__search\"\n type=\"search\"\n [value]=\"filter().query\"\n [placeholder]=\"labels().searchPlaceholderKey\"\n [disabled]=\"disabled()\"\n (input)=\"onQueryChange($event)\" />\n\n <select\n class=\"c2g-pl-filters__visibility\"\n [value]=\"filter().visibility\"\n [disabled]=\"disabled()\"\n (change)=\"onVisibilityChange($event)\">\n <option value=\"all\">{{ labels().showAllVisibilityKey }}</option>\n <option value=\"shared\">{{ labels().sharedVisibilityKey }}</option>\n <option value=\"personal\">{{ labels().personalVisibilityKey }}</option>\n <option value=\"private\">{{ labels().privateVisibilityKey }}</option>\n </select>\n\n <label class=\"c2g-pl-filters__essential\">\n <input\n type=\"checkbox\"\n [checked]=\"filter().essentialsOnly\"\n [disabled]=\"disabled()\"\n (change)=\"onEssentialsOnlyToggle($event)\" />\n <span>{{ labels().essentialsOnlyKey }}</span>\n </label>\n\n <div class=\"c2g-pl-filters__member-filter\">\n <button\n type=\"button\"\n class=\"c2g-pl-filters__member-trigger\"\n [disabled]=\"disabled()\"\n [attr.aria-expanded]=\"membersPanelOpen()\"\n (click)=\"toggleMembersPanel()\">\n <span>{{ memberSelectionLabel() }}</span>\n <span>{{ membersPanelOpen() ? '\u25B4' : '\u25BE' }}</span>\n </button>\n\n @if (membersPanelOpen()) {\n <div class=\"c2g-pl-filters__member-panel\" role=\"dialog\" aria-label=\"User-Filter\">\n <input\n class=\"c2g-pl-filters__member-search\"\n type=\"search\"\n [value]=\"memberQuery()\"\n placeholder=\"User suchen\"\n (input)=\"onMemberSearch($event)\" />\n\n <div class=\"c2g-pl-filters__member-actions\">\n <button type=\"button\" (click)=\"selectAllMembers()\">Alle</button>\n <button type=\"button\" (click)=\"clearMemberSelection()\">Zuruecksetzen</button>\n <button type=\"button\" (click)=\"requestExternalOverlay()\">Externe View</button>\n </div>\n\n <div class=\"c2g-pl-filters__member-list\">\n @for (member of filteredMembers(); track member.id) {\n <label class=\"c2g-pl-filters__member-option\">\n <input\n type=\"checkbox\"\n [checked]=\"isMemberSelected(member.id)\"\n (change)=\"toggleMember(member.id)\" />\n <span>{{ member.name }}</span>\n </label>\n }\n </div>\n </div>\n }\n </div>\n</div>\n", styles: [".c2g-pl-filters{display:grid;gap:.5rem;grid-template-columns:1fr auto auto auto;align-items:center}.c2g-pl-filters__search,.c2g-pl-filters__visibility{min-height:2rem;border:1px solid var(--c2g-color-outline);border-radius:.5rem;padding:.35rem .6rem;background:var(--c2g-color-surface)}.c2g-pl-filters__essential{display:inline-flex;align-items:center;gap:.35rem;font-size:.85rem;color:var(--c2g-color-text-primary)}.c2g-pl-filters__member-filter{position:relative}.c2g-pl-filters__member-trigger{min-height:2rem;border:1px solid var(--c2g-color-outline);border-radius:.5rem;padding:.35rem .6rem;background:var(--c2g-color-surface);color:var(--c2g-color-text-primary);display:inline-flex;gap:.5rem;align-items:center;cursor:pointer}.c2g-pl-filters__member-panel{position:absolute;z-index:20;top:calc(100% + .35rem);right:0;width:min(20rem,80vw);border:1px solid var(--c2g-color-outline);border-radius:.6rem;background:var(--c2g-color-surface);box-shadow:0 10px 26px #142d2124;padding:.55rem;display:grid;gap:.45rem}.c2g-pl-filters__member-search{min-height:1.9rem;border:1px solid var(--c2g-color-outline);border-radius:.45rem;padding:.3rem .55rem}.c2g-pl-filters__member-actions{display:flex;gap:.35rem;flex-wrap:wrap}.c2g-pl-filters__member-actions button{border:1px solid var(--c2g-color-outline);background:var(--c2g-color-neutral-50);border-radius:999px;font-size:.75rem;padding:.18rem .55rem;cursor:pointer}.c2g-pl-filters__member-list{max-height:12rem;overflow:auto;display:grid;gap:.25rem;padding-right:.15rem}.c2g-pl-filters__member-option{display:flex;align-items:center;gap:.45rem;font-size:.82rem;color:var(--c2g-color-text-primary)}@media(max-width:720px){.c2g-pl-filters{grid-template-columns:1fr}.c2g-pl-filters__member-panel{right:auto;left:0;width:100%}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
903
+ }
904
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: PackingListFiltersComponent, decorators: [{
905
+ type: Component,
906
+ args: [{ selector: 'c2g-packing-list-filters', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"c2g-pl-filters\">\n <input\n class=\"c2g-pl-filters__search\"\n type=\"search\"\n [value]=\"filter().query\"\n [placeholder]=\"labels().searchPlaceholderKey\"\n [disabled]=\"disabled()\"\n (input)=\"onQueryChange($event)\" />\n\n <select\n class=\"c2g-pl-filters__visibility\"\n [value]=\"filter().visibility\"\n [disabled]=\"disabled()\"\n (change)=\"onVisibilityChange($event)\">\n <option value=\"all\">{{ labels().showAllVisibilityKey }}</option>\n <option value=\"shared\">{{ labels().sharedVisibilityKey }}</option>\n <option value=\"personal\">{{ labels().personalVisibilityKey }}</option>\n <option value=\"private\">{{ labels().privateVisibilityKey }}</option>\n </select>\n\n <label class=\"c2g-pl-filters__essential\">\n <input\n type=\"checkbox\"\n [checked]=\"filter().essentialsOnly\"\n [disabled]=\"disabled()\"\n (change)=\"onEssentialsOnlyToggle($event)\" />\n <span>{{ labels().essentialsOnlyKey }}</span>\n </label>\n\n <div class=\"c2g-pl-filters__member-filter\">\n <button\n type=\"button\"\n class=\"c2g-pl-filters__member-trigger\"\n [disabled]=\"disabled()\"\n [attr.aria-expanded]=\"membersPanelOpen()\"\n (click)=\"toggleMembersPanel()\">\n <span>{{ memberSelectionLabel() }}</span>\n <span>{{ membersPanelOpen() ? '\u25B4' : '\u25BE' }}</span>\n </button>\n\n @if (membersPanelOpen()) {\n <div class=\"c2g-pl-filters__member-panel\" role=\"dialog\" aria-label=\"User-Filter\">\n <input\n class=\"c2g-pl-filters__member-search\"\n type=\"search\"\n [value]=\"memberQuery()\"\n placeholder=\"User suchen\"\n (input)=\"onMemberSearch($event)\" />\n\n <div class=\"c2g-pl-filters__member-actions\">\n <button type=\"button\" (click)=\"selectAllMembers()\">Alle</button>\n <button type=\"button\" (click)=\"clearMemberSelection()\">Zuruecksetzen</button>\n <button type=\"button\" (click)=\"requestExternalOverlay()\">Externe View</button>\n </div>\n\n <div class=\"c2g-pl-filters__member-list\">\n @for (member of filteredMembers(); track member.id) {\n <label class=\"c2g-pl-filters__member-option\">\n <input\n type=\"checkbox\"\n [checked]=\"isMemberSelected(member.id)\"\n (change)=\"toggleMember(member.id)\" />\n <span>{{ member.name }}</span>\n </label>\n }\n </div>\n </div>\n }\n </div>\n</div>\n", styles: [".c2g-pl-filters{display:grid;gap:.5rem;grid-template-columns:1fr auto auto auto;align-items:center}.c2g-pl-filters__search,.c2g-pl-filters__visibility{min-height:2rem;border:1px solid var(--c2g-color-outline);border-radius:.5rem;padding:.35rem .6rem;background:var(--c2g-color-surface)}.c2g-pl-filters__essential{display:inline-flex;align-items:center;gap:.35rem;font-size:.85rem;color:var(--c2g-color-text-primary)}.c2g-pl-filters__member-filter{position:relative}.c2g-pl-filters__member-trigger{min-height:2rem;border:1px solid var(--c2g-color-outline);border-radius:.5rem;padding:.35rem .6rem;background:var(--c2g-color-surface);color:var(--c2g-color-text-primary);display:inline-flex;gap:.5rem;align-items:center;cursor:pointer}.c2g-pl-filters__member-panel{position:absolute;z-index:20;top:calc(100% + .35rem);right:0;width:min(20rem,80vw);border:1px solid var(--c2g-color-outline);border-radius:.6rem;background:var(--c2g-color-surface);box-shadow:0 10px 26px #142d2124;padding:.55rem;display:grid;gap:.45rem}.c2g-pl-filters__member-search{min-height:1.9rem;border:1px solid var(--c2g-color-outline);border-radius:.45rem;padding:.3rem .55rem}.c2g-pl-filters__member-actions{display:flex;gap:.35rem;flex-wrap:wrap}.c2g-pl-filters__member-actions button{border:1px solid var(--c2g-color-outline);background:var(--c2g-color-neutral-50);border-radius:999px;font-size:.75rem;padding:.18rem .55rem;cursor:pointer}.c2g-pl-filters__member-list{max-height:12rem;overflow:auto;display:grid;gap:.25rem;padding-right:.15rem}.c2g-pl-filters__member-option{display:flex;align-items:center;gap:.45rem;font-size:.82rem;color:var(--c2g-color-text-primary)}@media(max-width:720px){.c2g-pl-filters{grid-template-columns:1fr}.c2g-pl-filters__member-panel{right:auto;left:0;width:100%}}\n"] }]
907
+ }], propDecorators: { filter: [{ type: i0.Input, args: [{ isSignal: true, alias: "filter", required: true }] }], members: [{ type: i0.Input, args: [{ isSignal: true, alias: "members", required: false }] }], labels: [{ type: i0.Input, args: [{ isSignal: true, alias: "labels", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], filterChange: [{ type: i0.Output, args: ["filterChange"] }], overlayRequested: [{ type: i0.Output, args: ["overlayRequested"] }] } });
908
+
909
+ class PackingListPrivateListComponent {
910
+ items = input.required(...(ngDevMode ? [{ debugName: "items" }] : []));
911
+ members = input.required(...(ngDevMode ? [{ debugName: "members" }] : []));
912
+ selectedMemberIds = input([], ...(ngDevMode ? [{ debugName: "selectedMemberIds" }] : []));
913
+ currentUserId = input.required(...(ngDevMode ? [{ debugName: "currentUserId" }] : []));
914
+ permissions = input.required(...(ngDevMode ? [{ debugName: "permissions" }] : []));
915
+ labels = input(DEFAULT_PACKING_LIST_LABEL_KEYS, ...(ngDevMode ? [{ debugName: "labels" }] : []));
916
+ privateItems = computed(() => this.items().filter(item => item.visibility === 'private'), ...(ngDevMode ? [{ debugName: "privateItems" }] : []));
917
+ itemChecked = output();
918
+ itemAssigned = output();
919
+ itemDeleted = output();
920
+ itemEditRequested = output();
921
+ personalItemToggled = output();
922
+ memberOverlayRequested = output();
923
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: PackingListPrivateListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
924
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: PackingListPrivateListComponent, isStandalone: true, selector: "c2g-packing-list-private-list", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: true, transformFunction: null }, members: { classPropertyName: "members", publicName: "members", isSignal: true, isRequired: true, transformFunction: null }, selectedMemberIds: { classPropertyName: "selectedMemberIds", publicName: "selectedMemberIds", isSignal: true, isRequired: false, transformFunction: null }, currentUserId: { classPropertyName: "currentUserId", publicName: "currentUserId", isSignal: true, isRequired: true, transformFunction: null }, permissions: { classPropertyName: "permissions", publicName: "permissions", isSignal: true, isRequired: true, transformFunction: null }, labels: { classPropertyName: "labels", publicName: "labels", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { itemChecked: "itemChecked", itemAssigned: "itemAssigned", itemDeleted: "itemDeleted", itemEditRequested: "itemEditRequested", personalItemToggled: "personalItemToggled", memberOverlayRequested: "memberOverlayRequested" }, ngImport: i0, template: "@if (privateItems().length > 0) {\n <section class=\"c2g-pl-private\">\n <h3>{{ labels().privateSectionTitleKey }}</h3>\n <div class=\"c2g-pl-private__items\">\n @for (item of privateItems(); track item.id) {\n <c2g-packing-list-item\n [item]=\"item\"\n [members]=\"members()\"\n [selectedMemberIds]=\"selectedMemberIds()\"\n [currentUserId]=\"currentUserId()\"\n [permissions]=\"permissions()\"\n (itemChecked)=\"itemChecked.emit($event)\"\n (itemAssigned)=\"itemAssigned.emit($event)\"\n (itemDeleted)=\"itemDeleted.emit($event)\"\n (itemEditRequested)=\"itemEditRequested.emit($event)\"\n (personalItemToggled)=\"personalItemToggled.emit($event)\"\n (memberOverlayRequested)=\"memberOverlayRequested.emit($event)\">\n </c2g-packing-list-item>\n }\n </div>\n </section>\n}\n", styles: [".c2g-pl-private{display:grid;gap:.5rem}.c2g-pl-private h3{margin:0;font-size:.95rem;color:var(--c2g-color-text-primary)}.c2g-pl-private__items{display:grid;gap:.55rem}\n"], dependencies: [{ kind: "component", type: PackingListItemComponent, selector: "c2g-packing-list-item", inputs: ["item", "members", "currentUserId", "permissions", "selectedMemberIds"], outputs: ["itemChecked", "itemAssigned", "itemDeleted", "itemEditRequested", "personalItemToggled", "memberOverlayRequested"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
925
+ }
926
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: PackingListPrivateListComponent, decorators: [{
927
+ type: Component,
928
+ args: [{ selector: 'c2g-packing-list-private-list', standalone: true, imports: [PackingListItemComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (privateItems().length > 0) {\n <section class=\"c2g-pl-private\">\n <h3>{{ labels().privateSectionTitleKey }}</h3>\n <div class=\"c2g-pl-private__items\">\n @for (item of privateItems(); track item.id) {\n <c2g-packing-list-item\n [item]=\"item\"\n [members]=\"members()\"\n [selectedMemberIds]=\"selectedMemberIds()\"\n [currentUserId]=\"currentUserId()\"\n [permissions]=\"permissions()\"\n (itemChecked)=\"itemChecked.emit($event)\"\n (itemAssigned)=\"itemAssigned.emit($event)\"\n (itemDeleted)=\"itemDeleted.emit($event)\"\n (itemEditRequested)=\"itemEditRequested.emit($event)\"\n (personalItemToggled)=\"personalItemToggled.emit($event)\"\n (memberOverlayRequested)=\"memberOverlayRequested.emit($event)\">\n </c2g-packing-list-item>\n }\n </div>\n </section>\n}\n", styles: [".c2g-pl-private{display:grid;gap:.5rem}.c2g-pl-private h3{margin:0;font-size:.95rem;color:var(--c2g-color-text-primary)}.c2g-pl-private__items{display:grid;gap:.55rem}\n"] }]
929
+ }], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: true }] }], members: [{ type: i0.Input, args: [{ isSignal: true, alias: "members", required: true }] }], selectedMemberIds: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedMemberIds", required: false }] }], currentUserId: [{ type: i0.Input, args: [{ isSignal: true, alias: "currentUserId", required: true }] }], permissions: [{ type: i0.Input, args: [{ isSignal: true, alias: "permissions", required: true }] }], labels: [{ type: i0.Input, args: [{ isSignal: true, alias: "labels", required: false }] }], itemChecked: [{ type: i0.Output, args: ["itemChecked"] }], itemAssigned: [{ type: i0.Output, args: ["itemAssigned"] }], itemDeleted: [{ type: i0.Output, args: ["itemDeleted"] }], itemEditRequested: [{ type: i0.Output, args: ["itemEditRequested"] }], personalItemToggled: [{ type: i0.Output, args: ["personalItemToggled"] }], memberOverlayRequested: [{ type: i0.Output, args: ["memberOverlayRequested"] }] } });
930
+
931
+ class PackingListItemCreateComponent {
932
+ permissions = input({
933
+ isOrganizer: false,
934
+ isGuest: false,
935
+ isSolo: false,
936
+ readOnly: false
937
+ }, ...(ngDevMode ? [{ debugName: "permissions" }] : []));
938
+ labels = input(DEFAULT_PACKING_LIST_LABEL_KEYS, ...(ngDevMode ? [{ debugName: "labels" }] : []));
939
+ readOnly = input(false, ...(ngDevMode ? [{ debugName: "readOnly" }] : []));
940
+ categories = input(Object.values(C2G_PACKING_CATEGORY_INFO), ...(ngDevMode ? [{ debugName: "categories" }] : []));
941
+ itemCreated = output();
942
+ dialogOpen = signal(false, ...(ngDevMode ? [{ debugName: "dialogOpen" }] : []));
943
+ formData = signal({
944
+ name: '',
945
+ category: Object.values(C2G_PACKING_CATEGORY_INFO)[0]?.key ?? 'other',
946
+ visibility: 'private',
947
+ essential: false,
948
+ quantity: 1,
949
+ weightKg: undefined,
950
+ packedVolumeL: undefined,
951
+ hint: ''
952
+ }, ...(ngDevMode ? [{ debugName: "formData" }] : []));
953
+ availableVisibilities = computed(() => {
954
+ const perms = this.permissions();
955
+ const labels = this.labels();
956
+ const visibilities = [];
957
+ // Private is always available
958
+ visibilities.push({
959
+ value: 'private',
960
+ label: labels.privateVisibilityKey ?? 'Private'
961
+ });
962
+ // Personal is available if not a guest
963
+ if (!perms.isGuest) {
964
+ visibilities.push({
965
+ value: 'personal',
966
+ label: labels.personalVisibilityKey ?? 'Personal'
967
+ });
968
+ }
969
+ // Shared is available for organizers or if tour allows members
970
+ if (perms.isOrganizer || perms.canMembersAddSharedItems) {
971
+ visibilities.push({
972
+ value: 'shared',
973
+ label: labels.sharedVisibilityKey ?? 'Shared'
974
+ });
975
+ }
976
+ return visibilities;
977
+ }, ...(ngDevMode ? [{ debugName: "availableVisibilities" }] : []));
978
+ categoryOptions = computed(() => {
979
+ return this.categories().map(cat => ({
980
+ value: cat.key,
981
+ label: cat.label || cat.key
982
+ }));
983
+ }, ...(ngDevMode ? [{ debugName: "categoryOptions" }] : []));
984
+ openDialog() {
985
+ this.dialogOpen.set(true);
986
+ }
987
+ closeDialog() {
988
+ this.dialogOpen.set(false);
989
+ this.resetForm();
990
+ }
991
+ resetForm() {
992
+ this.formData.set({
993
+ name: '',
994
+ category: Object.values(C2G_PACKING_CATEGORY_INFO)[0]?.key ?? 'other',
995
+ visibility: this.availableVisibilities()[0]?.value ?? 'private',
996
+ essential: false,
997
+ quantity: 1,
998
+ weightKg: undefined,
999
+ packedVolumeL: undefined,
1000
+ hint: ''
1001
+ });
1002
+ }
1003
+ submit() {
1004
+ const data = this.formData();
1005
+ if (!data.name.trim()) {
1006
+ return;
1007
+ }
1008
+ const newItem = {
1009
+ name: data.name.trim(),
1010
+ category: data.category,
1011
+ visibility: data.visibility,
1012
+ essential: data.essential,
1013
+ quantity: data.quantity > 0 ? data.quantity : undefined,
1014
+ weightKg: data.weightKg && data.weightKg > 0 ? data.weightKg : undefined,
1015
+ packedVolumeL: data.packedVolumeL && data.packedVolumeL > 0 ? data.packedVolumeL : undefined,
1016
+ hint: data.hint.trim() || undefined
1017
+ };
1018
+ this.itemCreated.emit(newItem);
1019
+ this.closeDialog();
1020
+ }
1021
+ updateVisibility(visibility) {
1022
+ this.formData.update(data => ({ ...data, visibility }));
1023
+ }
1024
+ getCategoryLabel(categoryKey) {
1025
+ return this.categories().find(c => c.key === categoryKey)?.label ?? categoryKey;
1026
+ }
1027
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: PackingListItemCreateComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1028
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: PackingListItemCreateComponent, isStandalone: true, selector: "c2g-packing-list-item-create", inputs: { permissions: { classPropertyName: "permissions", publicName: "permissions", isSignal: true, isRequired: false, transformFunction: null }, labels: { classPropertyName: "labels", publicName: "labels", isSignal: true, isRequired: false, transformFunction: null }, readOnly: { classPropertyName: "readOnly", publicName: "readOnly", isSignal: true, isRequired: false, transformFunction: null }, categories: { classPropertyName: "categories", publicName: "categories", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { itemCreated: "itemCreated" }, ngImport: i0, template: "<c2g-button\n variant=\"secondary\"\n size=\"md\"\n icon=\"+\"\n [disabled]=\"readOnly()\"\n (clicked)=\"openDialog()\">\n {{ labels().addItemKey || 'Item hinzuf\u00FCgen' }}\n</c2g-button>\n\n@if (dialogOpen()) {\n <div class=\"c2g-pl-item-create__overlay\" (click)=\"closeDialog()\"></div>\n <dialog class=\"c2g-pl-item-create__dialog\" open>\n <div class=\"c2g-pl-item-create__header\">\n <h2>{{ labels().createItemKey || 'Neues Item' }}</h2>\n <c2g-button\n variant=\"icon\"\n size=\"sm\"\n icon=\"\u2715\"\n aria-label=\"Schlie\u00DFen\"\n (clicked)=\"closeDialog()\">\n </c2g-button>\n </div>\n\n <form class=\"c2g-pl-item-create__form\" (ngSubmit)=\"submit()\">\n <!-- Name Input -->\n <div class=\"c2g-pl-item-create__field\">\n <c2g-input\n [label]=\"labels().itemNameKey || 'Name'\"\n [required]=\"true\"\n [(ngModel)]=\"formData().name\"\n [ngModelOptions]=\"{ updateOn: 'blur' }\"\n name=\"name\"\n placeholder=\"z.B. Zelt, Schlafsack...\">\n </c2g-input>\n </div>\n\n <!-- Category Select -->\n <div class=\"c2g-pl-item-create__field\">\n <c2g-select\n [label]=\"(labels().categoryKey || 'Kategorie') + ' *'\"\n [options]=\"categoryOptions()\"\n [required]=\"true\"\n [(ngModel)]=\"formData().category\"\n name=\"category\">\n </c2g-select>\n </div>\n\n <!-- Visibility Radio -->\n @if (availableVisibilities().length > 1) {\n <div class=\"c2g-pl-item-create__field\">\n <c2g-radio-group\n [label]=\"(labels().visibilityKey || 'Sichtbarkeit') + ' *'\"\n [options]=\"availableVisibilities()\"\n [(ngModel)]=\"formData().visibility\"\n name=\"visibility\"\n orientation=\"vertical\">\n </c2g-radio-group>\n </div>\n }\n\n <!-- Essential Checkbox -->\n <div class=\"c2g-pl-item-create__field\">\n <c2g-checkbox\n [label]=\"labels().essentialKey || 'Essentiell'\"\n [(ngModel)]=\"formData().essential\"\n name=\"essential\">\n </c2g-checkbox>\n </div>\n\n <!-- Quantity -->\n <div class=\"c2g-pl-item-create__field\">\n <c2g-input\n [label]=\"labels().quantityKey || 'Menge'\"\n [(ngModel)]=\"formData().quantity\"\n name=\"quantity\"\n placeholder=\"z.B. 1\">\n </c2g-input>\n </div>\n\n <!-- Weight -->\n <div class=\"c2g-pl-item-create__field\">\n <c2g-input\n [label]=\"labels().weightKey || 'Gewicht (kg)'\"\n [(ngModel)]=\"formData().weightKg\"\n name=\"weightKg\"\n placeholder=\"z.B. 0.5\">\n </c2g-input>\n </div>\n\n <!-- Volume -->\n <div class=\"c2g-pl-item-create__field\">\n <c2g-input\n [label]=\"labels().volumeKey || 'Volumen (l)'\"\n [(ngModel)]=\"formData().packedVolumeL\"\n name=\"packedVolumeL\"\n placeholder=\"z.B. 1.5\">\n </c2g-input>\n </div>\n\n <!-- Hint -->\n <div class=\"c2g-pl-item-create__field\">\n <c2g-textarea\n [label]=\"labels().hintKey || 'Notiz'\"\n [(ngModel)]=\"formData().hint\"\n name=\"hint\"\n [rows]=\"2\"\n placeholder=\"z.B. Schlafsack f\u00FCr Kinder, Wetterschutz...\">\n </c2g-textarea>\n </div>\n\n <!-- Buttons -->\n <div class=\"c2g-pl-item-create__actions\">\n <c2g-button\n type=\"button\"\n variant=\"secondary\"\n size=\"md\"\n (clicked)=\"closeDialog()\">\n {{ labels().cancelKey || 'Abbrechen' }}\n </c2g-button>\n <c2g-button\n type=\"submit\"\n variant=\"primary\"\n size=\"md\"\n [disabled]=\"!formData().name.trim()\">\n {{ labels().createKey || 'Erstellen' }}\n </c2g-button>\n </div>\n </form>\n </dialog>\n}\n", styles: [".c2g-pl-item-create__btn{border:none;background:var(--c2g-color-surface);color:var(--c2g-color-text-primary);border-radius:.5rem;padding:.45rem .9rem;font-size:.9rem;font-weight:500;cursor:pointer;display:inline-flex;align-items:center;gap:.4rem;border:1px solid var(--c2g-color-outline);transition:all .2s ease}.c2g-pl-item-create__btn:hover:not(:disabled){background:var(--c2g-color-neutral-100);border-color:var(--c2g-color-text-primary)}.c2g-pl-item-create__btn:disabled{opacity:.5;cursor:not-allowed}.c2g-pl-item-create__icon{font-size:1.2rem;font-weight:600;line-height:1}.c2g-pl-item-create__overlay{position:fixed;inset:0;background:#152b2166;z-index:99}.c2g-pl-item-create__dialog{position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);z-index:100;border:none;border-radius:.75rem;background:var(--c2g-color-surface);box-shadow:0 20px 40px #152b2133;padding:1.5rem;max-width:500px;width:90%;max-height:90vh;overflow-y:auto}@media(max-width:600px){.c2g-pl-item-create__dialog{width:95%;padding:1.2rem}}.c2g-pl-item-create__header{display:flex;justify-content:space-between;align-items:center;margin-bottom:1.5rem}.c2g-pl-item-create__header h2{margin:0;font-size:1.3rem;font-weight:600;color:var(--c2g-color-text-primary)}.c2g-pl-item-create__close{border:none;background:transparent;color:var(--c2g-color-text-muted);font-size:1.8rem;line-height:1;padding:0;cursor:pointer;width:2rem;height:2rem;display:flex;align-items:center;justify-content:center;transition:color .2s ease}.c2g-pl-item-create__close:hover{color:var(--c2g-color-text-primary)}.c2g-pl-item-create__form{display:grid;gap:1rem}.c2g-pl-item-create__field{display:grid;gap:.4rem}.c2g-pl-item-create__field label{font-weight:500;color:var(--c2g-color-text-primary);font-size:.9rem}.c2g-pl-item-create__field input[type=text],.c2g-pl-item-create__field input[type=number],.c2g-pl-item-create__field textarea,.c2g-pl-item-create__field select{border:1px solid var(--c2g-color-outline-variant);border-radius:.4rem;padding:.5rem .6rem;font-size:.9rem;font-family:inherit;color:var(--c2g-color-text-primary);background:var(--c2g-color-surface);transition:border-color .2s ease}.c2g-pl-item-create__field input[type=text]:focus,.c2g-pl-item-create__field input[type=number]:focus,.c2g-pl-item-create__field textarea:focus,.c2g-pl-item-create__field select:focus{outline:none;border-color:var(--c2g-color-text-primary);box-shadow:0 0 0 2px var(--c2g-color-border-soft)}.c2g-pl-item-create__field input[type=text]::placeholder,.c2g-pl-item-create__field input[type=number]::placeholder,.c2g-pl-item-create__field textarea::placeholder,.c2g-pl-item-create__field select::placeholder{color:var(--c2g-color-text-muted)}.c2g-pl-item-create__field textarea{resize:vertical;line-height:1.4}.c2g-pl-item-create__field select{cursor:pointer}.c2g-pl-item-create__checkbox-label{display:flex;align-items:center;gap:.5rem;cursor:pointer;-webkit-user-select:none;user-select:none}.c2g-pl-item-create__checkbox-label input[type=checkbox]{width:1.1rem;height:1.1rem;cursor:pointer}.c2g-pl-item-create__checkbox-label span{color:var(--c2g-color-text-primary);font-size:.9rem}.c2g-pl-item-create__visibility-options{display:flex;flex-direction:column;gap:.5rem}.c2g-pl-item-create__visibility-label{display:flex;align-items:center;gap:.5rem;cursor:pointer;-webkit-user-select:none;user-select:none}.c2g-pl-item-create__visibility-label input[type=radio]{width:1.1rem;height:1.1rem;cursor:pointer}.c2g-pl-item-create__visibility-label span{color:var(--c2g-color-text-primary);font-size:.9rem}.c2g-pl-item-create__actions{display:flex;gap:.8rem;margin-top:1.5rem;justify-content:flex-end}.c2g-pl-item-create__btn-primary{border:none;background:var(--c2g-color-text-primary);color:var(--c2g-color-surface);border-radius:.4rem;padding:.6rem 1.2rem;font-size:.9rem;font-weight:500;cursor:pointer;transition:all .2s ease}.c2g-pl-item-create__btn-primary:hover:not(:disabled){background:var(--c2g-color-text-secondary)}.c2g-pl-item-create__btn-primary:disabled{opacity:.5;cursor:not-allowed}.c2g-pl-item-create__btn-secondary{border:1px solid var(--c2g-color-outline);background:var(--c2g-color-surface);color:var(--c2g-color-text-primary);border-radius:.4rem;padding:.6rem 1.2rem;font-size:.9rem;font-weight:500;cursor:pointer;transition:all .2s ease}.c2g-pl-item-create__btn-secondary:hover{background:var(--c2g-color-neutral-100);border-color:var(--c2g-color-text-primary)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i1$1.NgForm, selector: "form:not([ngNoForm]):not([formGroup]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: ButtonComponent, selector: "c2g-button", inputs: ["variant", "size", "disabled", "loading", "icon", "iconPosition", "iconOnly", "ariaLabel", "loadingAriaLabel", "type"], outputs: ["clicked"] }, { kind: "component", type: RadioGroupComponent, selector: "c2g-radio-group", inputs: ["label", "hint", "disabled", "orientation", "options", "name"], outputs: ["valueChange"] }, { kind: "component", type: CheckboxComponent, selector: "c2g-checkbox", inputs: ["id", "label", "hint", "disabled"], outputs: ["checkedChange"] }, { kind: "component", type: SelectComponent, selector: "c2g-select", inputs: ["label", "placeholder", "hint", "error", "options", "disabled", "required", "id"], outputs: ["valueChanged"] }, { kind: "component", type: InputComponent, selector: "c2g-input", inputs: ["label", "hint", "error", "placeholder", "prefix", "suffix", "loading", "disabled", "required", "maxLength", "id", "type"], outputs: ["valueChanged"] }, { kind: "component", type: TextareaComponent, selector: "c2g-textarea", inputs: ["label", "hint", "error", "placeholder", "prefix", "suffix", "loading", "disabled", "required", "maxLength", "rows", "id"], outputs: ["valueChanged"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1029
+ }
1030
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: PackingListItemCreateComponent, decorators: [{
1031
+ type: Component,
1032
+ args: [{ selector: 'c2g-packing-list-item-create', standalone: true, imports: [CommonModule, FormsModule, ButtonComponent, RadioGroupComponent, CheckboxComponent, SelectComponent, InputComponent, TextareaComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<c2g-button\n variant=\"secondary\"\n size=\"md\"\n icon=\"+\"\n [disabled]=\"readOnly()\"\n (clicked)=\"openDialog()\">\n {{ labels().addItemKey || 'Item hinzuf\u00FCgen' }}\n</c2g-button>\n\n@if (dialogOpen()) {\n <div class=\"c2g-pl-item-create__overlay\" (click)=\"closeDialog()\"></div>\n <dialog class=\"c2g-pl-item-create__dialog\" open>\n <div class=\"c2g-pl-item-create__header\">\n <h2>{{ labels().createItemKey || 'Neues Item' }}</h2>\n <c2g-button\n variant=\"icon\"\n size=\"sm\"\n icon=\"\u2715\"\n aria-label=\"Schlie\u00DFen\"\n (clicked)=\"closeDialog()\">\n </c2g-button>\n </div>\n\n <form class=\"c2g-pl-item-create__form\" (ngSubmit)=\"submit()\">\n <!-- Name Input -->\n <div class=\"c2g-pl-item-create__field\">\n <c2g-input\n [label]=\"labels().itemNameKey || 'Name'\"\n [required]=\"true\"\n [(ngModel)]=\"formData().name\"\n [ngModelOptions]=\"{ updateOn: 'blur' }\"\n name=\"name\"\n placeholder=\"z.B. Zelt, Schlafsack...\">\n </c2g-input>\n </div>\n\n <!-- Category Select -->\n <div class=\"c2g-pl-item-create__field\">\n <c2g-select\n [label]=\"(labels().categoryKey || 'Kategorie') + ' *'\"\n [options]=\"categoryOptions()\"\n [required]=\"true\"\n [(ngModel)]=\"formData().category\"\n name=\"category\">\n </c2g-select>\n </div>\n\n <!-- Visibility Radio -->\n @if (availableVisibilities().length > 1) {\n <div class=\"c2g-pl-item-create__field\">\n <c2g-radio-group\n [label]=\"(labels().visibilityKey || 'Sichtbarkeit') + ' *'\"\n [options]=\"availableVisibilities()\"\n [(ngModel)]=\"formData().visibility\"\n name=\"visibility\"\n orientation=\"vertical\">\n </c2g-radio-group>\n </div>\n }\n\n <!-- Essential Checkbox -->\n <div class=\"c2g-pl-item-create__field\">\n <c2g-checkbox\n [label]=\"labels().essentialKey || 'Essentiell'\"\n [(ngModel)]=\"formData().essential\"\n name=\"essential\">\n </c2g-checkbox>\n </div>\n\n <!-- Quantity -->\n <div class=\"c2g-pl-item-create__field\">\n <c2g-input\n [label]=\"labels().quantityKey || 'Menge'\"\n [(ngModel)]=\"formData().quantity\"\n name=\"quantity\"\n placeholder=\"z.B. 1\">\n </c2g-input>\n </div>\n\n <!-- Weight -->\n <div class=\"c2g-pl-item-create__field\">\n <c2g-input\n [label]=\"labels().weightKey || 'Gewicht (kg)'\"\n [(ngModel)]=\"formData().weightKg\"\n name=\"weightKg\"\n placeholder=\"z.B. 0.5\">\n </c2g-input>\n </div>\n\n <!-- Volume -->\n <div class=\"c2g-pl-item-create__field\">\n <c2g-input\n [label]=\"labels().volumeKey || 'Volumen (l)'\"\n [(ngModel)]=\"formData().packedVolumeL\"\n name=\"packedVolumeL\"\n placeholder=\"z.B. 1.5\">\n </c2g-input>\n </div>\n\n <!-- Hint -->\n <div class=\"c2g-pl-item-create__field\">\n <c2g-textarea\n [label]=\"labels().hintKey || 'Notiz'\"\n [(ngModel)]=\"formData().hint\"\n name=\"hint\"\n [rows]=\"2\"\n placeholder=\"z.B. Schlafsack f\u00FCr Kinder, Wetterschutz...\">\n </c2g-textarea>\n </div>\n\n <!-- Buttons -->\n <div class=\"c2g-pl-item-create__actions\">\n <c2g-button\n type=\"button\"\n variant=\"secondary\"\n size=\"md\"\n (clicked)=\"closeDialog()\">\n {{ labels().cancelKey || 'Abbrechen' }}\n </c2g-button>\n <c2g-button\n type=\"submit\"\n variant=\"primary\"\n size=\"md\"\n [disabled]=\"!formData().name.trim()\">\n {{ labels().createKey || 'Erstellen' }}\n </c2g-button>\n </div>\n </form>\n </dialog>\n}\n", styles: [".c2g-pl-item-create__btn{border:none;background:var(--c2g-color-surface);color:var(--c2g-color-text-primary);border-radius:.5rem;padding:.45rem .9rem;font-size:.9rem;font-weight:500;cursor:pointer;display:inline-flex;align-items:center;gap:.4rem;border:1px solid var(--c2g-color-outline);transition:all .2s ease}.c2g-pl-item-create__btn:hover:not(:disabled){background:var(--c2g-color-neutral-100);border-color:var(--c2g-color-text-primary)}.c2g-pl-item-create__btn:disabled{opacity:.5;cursor:not-allowed}.c2g-pl-item-create__icon{font-size:1.2rem;font-weight:600;line-height:1}.c2g-pl-item-create__overlay{position:fixed;inset:0;background:#152b2166;z-index:99}.c2g-pl-item-create__dialog{position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);z-index:100;border:none;border-radius:.75rem;background:var(--c2g-color-surface);box-shadow:0 20px 40px #152b2133;padding:1.5rem;max-width:500px;width:90%;max-height:90vh;overflow-y:auto}@media(max-width:600px){.c2g-pl-item-create__dialog{width:95%;padding:1.2rem}}.c2g-pl-item-create__header{display:flex;justify-content:space-between;align-items:center;margin-bottom:1.5rem}.c2g-pl-item-create__header h2{margin:0;font-size:1.3rem;font-weight:600;color:var(--c2g-color-text-primary)}.c2g-pl-item-create__close{border:none;background:transparent;color:var(--c2g-color-text-muted);font-size:1.8rem;line-height:1;padding:0;cursor:pointer;width:2rem;height:2rem;display:flex;align-items:center;justify-content:center;transition:color .2s ease}.c2g-pl-item-create__close:hover{color:var(--c2g-color-text-primary)}.c2g-pl-item-create__form{display:grid;gap:1rem}.c2g-pl-item-create__field{display:grid;gap:.4rem}.c2g-pl-item-create__field label{font-weight:500;color:var(--c2g-color-text-primary);font-size:.9rem}.c2g-pl-item-create__field input[type=text],.c2g-pl-item-create__field input[type=number],.c2g-pl-item-create__field textarea,.c2g-pl-item-create__field select{border:1px solid var(--c2g-color-outline-variant);border-radius:.4rem;padding:.5rem .6rem;font-size:.9rem;font-family:inherit;color:var(--c2g-color-text-primary);background:var(--c2g-color-surface);transition:border-color .2s ease}.c2g-pl-item-create__field input[type=text]:focus,.c2g-pl-item-create__field input[type=number]:focus,.c2g-pl-item-create__field textarea:focus,.c2g-pl-item-create__field select:focus{outline:none;border-color:var(--c2g-color-text-primary);box-shadow:0 0 0 2px var(--c2g-color-border-soft)}.c2g-pl-item-create__field input[type=text]::placeholder,.c2g-pl-item-create__field input[type=number]::placeholder,.c2g-pl-item-create__field textarea::placeholder,.c2g-pl-item-create__field select::placeholder{color:var(--c2g-color-text-muted)}.c2g-pl-item-create__field textarea{resize:vertical;line-height:1.4}.c2g-pl-item-create__field select{cursor:pointer}.c2g-pl-item-create__checkbox-label{display:flex;align-items:center;gap:.5rem;cursor:pointer;-webkit-user-select:none;user-select:none}.c2g-pl-item-create__checkbox-label input[type=checkbox]{width:1.1rem;height:1.1rem;cursor:pointer}.c2g-pl-item-create__checkbox-label span{color:var(--c2g-color-text-primary);font-size:.9rem}.c2g-pl-item-create__visibility-options{display:flex;flex-direction:column;gap:.5rem}.c2g-pl-item-create__visibility-label{display:flex;align-items:center;gap:.5rem;cursor:pointer;-webkit-user-select:none;user-select:none}.c2g-pl-item-create__visibility-label input[type=radio]{width:1.1rem;height:1.1rem;cursor:pointer}.c2g-pl-item-create__visibility-label span{color:var(--c2g-color-text-primary);font-size:.9rem}.c2g-pl-item-create__actions{display:flex;gap:.8rem;margin-top:1.5rem;justify-content:flex-end}.c2g-pl-item-create__btn-primary{border:none;background:var(--c2g-color-text-primary);color:var(--c2g-color-surface);border-radius:.4rem;padding:.6rem 1.2rem;font-size:.9rem;font-weight:500;cursor:pointer;transition:all .2s ease}.c2g-pl-item-create__btn-primary:hover:not(:disabled){background:var(--c2g-color-text-secondary)}.c2g-pl-item-create__btn-primary:disabled{opacity:.5;cursor:not-allowed}.c2g-pl-item-create__btn-secondary{border:1px solid var(--c2g-color-outline);background:var(--c2g-color-surface);color:var(--c2g-color-text-primary);border-radius:.4rem;padding:.6rem 1.2rem;font-size:.9rem;font-weight:500;cursor:pointer;transition:all .2s ease}.c2g-pl-item-create__btn-secondary:hover{background:var(--c2g-color-neutral-100);border-color:var(--c2g-color-text-primary)}\n"] }]
1033
+ }], propDecorators: { permissions: [{ type: i0.Input, args: [{ isSignal: true, alias: "permissions", required: false }] }], labels: [{ type: i0.Input, args: [{ isSignal: true, alias: "labels", required: false }] }], readOnly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readOnly", required: false }] }], categories: [{ type: i0.Input, args: [{ isSignal: true, alias: "categories", required: false }] }], itemCreated: [{ type: i0.Output, args: ["itemCreated"] }] } });
1034
+
1035
+ class PackingListComponent {
1036
+ items = input.required(...(ngDevMode ? [{ debugName: "items" }] : []));
1037
+ members = input.required(...(ngDevMode ? [{ debugName: "members" }] : []));
1038
+ currentUserId = input.required(...(ngDevMode ? [{ debugName: "currentUserId" }] : []));
1039
+ permissions = input({
1040
+ isOrganizer: false,
1041
+ isGuest: false,
1042
+ isSolo: false,
1043
+ readOnly: false
1044
+ }, ...(ngDevMode ? [{ debugName: "permissions" }] : []));
1045
+ labels = input(DEFAULT_PACKING_LIST_LABEL_KEYS, ...(ngDevMode ? [{ debugName: "labels" }] : []));
1046
+ categories = input(Object.values(C2G_PACKING_CATEGORY_INFO), ...(ngDevMode ? [{ debugName: "categories" }] : []));
1047
+ config = input(DEFAULT_PACKING_LIST_CONFIG, ...(ngDevMode ? [{ debugName: "config" }] : []));
1048
+ // Compat layer for deprecated inputs (showStats, showPrivateAsSeparateList)
1049
+ showPrivateAsSeparateList = input(false, ...(ngDevMode ? [{ debugName: "showPrivateAsSeparateList" }] : []));
1050
+ showStats = input(true, ...(ngDevMode ? [{ debugName: "showStats" }] : []));
1051
+ itemChecked = output();
1052
+ itemAssigned = output();
1053
+ itemDeleted = output();
1054
+ itemEditRequested = output();
1055
+ itemCreated = output();
1056
+ personalItemToggled = output();
1057
+ memberOverlayRequested = output();
1058
+ externalMemberViewRequested = output();
1059
+ filterChanged = output();
1060
+ sortChanged = output();
1061
+ rowActionTriggered = output();
1062
+ // Merged config: config input takes precedence over deprecated inputs
1063
+ mergedConfig = computed(() => {
1064
+ const cfg = this.config();
1065
+ const features = cfg.features ?? {};
1066
+ // Apply deprecated inputs if config doesn't override
1067
+ return {
1068
+ ...cfg,
1069
+ features: {
1070
+ ...features,
1071
+ stats: features.stats !== undefined ? features.stats : this.showStats(),
1072
+ privateSection: features.privateSection !== undefined ? features.privateSection : this.showPrivateAsSeparateList(),
1073
+ }
1074
+ };
1075
+ }, ...(ngDevMode ? [{ debugName: "mergedConfig" }] : []));
1076
+ filter = signal({
1077
+ query: '',
1078
+ visibility: 'all',
1079
+ essentialsOnly: false,
1080
+ memberIds: []
1081
+ }, ...(ngDevMode ? [{ debugName: "filter" }] : []));
1082
+ expandedCategories = signal(new Set(), ...(ngDevMode ? [{ debugName: "expandedCategories" }] : []));
1083
+ hasUserToggled = signal(false, ...(ngDevMode ? [{ debugName: "hasUserToggled" }] : []));
1084
+ filteredItems = computed(() => {
1085
+ const filter = this.filter();
1086
+ const q = filter.query.trim().toLowerCase();
1087
+ return this.items().filter(item => {
1088
+ if (filter.visibility !== 'all' && item.visibility !== filter.visibility) {
1089
+ return false;
1090
+ }
1091
+ if (filter.essentialsOnly && !item.essential) {
1092
+ return false;
1093
+ }
1094
+ if (filter.memberIds.length > 0) {
1095
+ const selected = new Set(filter.memberIds);
1096
+ const assignments = item.assignments ?? [];
1097
+ const hasSelectedAssignment = assignments.some(assignment => selected.has(assignment.memberId));
1098
+ if (!hasSelectedAssignment) {
1099
+ return false;
1100
+ }
1101
+ }
1102
+ if (!q) {
1103
+ return true;
1104
+ }
1105
+ const searchable = `${item.name} ${item.hint ?? ''} ${item.reason ?? ''}`.toLowerCase();
1106
+ return searchable.includes(q);
1107
+ });
1108
+ }, ...(ngDevMode ? [{ debugName: "filteredItems" }] : []));
1109
+ categoryGroups = computed(() => {
1110
+ const grouped = new Map();
1111
+ for (const item of this.filteredItems()) {
1112
+ const key = item.category || 'other';
1113
+ if (!grouped.has(key)) {
1114
+ grouped.set(key, []);
1115
+ }
1116
+ grouped.get(key).push(item);
1117
+ }
1118
+ // Category order: follow C2G_PACKING_CATEGORY_INFO definition, unknowns at end.
1119
+ // A category sinks to the bottom only when ALL its items are packed/confirmed.
1120
+ const knownOrder = Object.keys(C2G_PACKING_CATEGORY_INFO);
1121
+ const isPacked = (i) => !!i.assignments?.some(a => a.status === 'packed' || a.status === 'confirmed');
1122
+ const entries = Array.from(grouped.entries());
1123
+ entries.sort(([a, aItems], [b, bItems]) => {
1124
+ const aDone = aItems.every(isPacked) ? 1 : 0;
1125
+ const bDone = bItems.every(isPacked) ? 1 : 0;
1126
+ if (aDone !== bDone)
1127
+ return aDone - bDone;
1128
+ const ai = knownOrder.indexOf(a);
1129
+ const bi = knownOrder.indexOf(b);
1130
+ return (ai === -1 ? knownOrder.length : ai) - (bi === -1 ? knownOrder.length : bi);
1131
+ });
1132
+ return entries.map(([key, items]) => ({ key, items }));
1133
+ }, ...(ngDevMode ? [{ debugName: "categoryGroups" }] : []));
1134
+ constructor() {
1135
+ effect(() => {
1136
+ if (this.hasUserToggled()) {
1137
+ return;
1138
+ }
1139
+ const defaults = this.categoryGroups().slice(0, 3).map(group => group.key);
1140
+ if (defaults.length === 0) {
1141
+ return;
1142
+ }
1143
+ if (this.expandedCategories().size === 0) {
1144
+ this.expandedCategories.set(new Set(defaults));
1145
+ }
1146
+ });
1147
+ }
1148
+ onFilterChange(next) {
1149
+ this.filter.set(next);
1150
+ this.filterChanged.emit(next);
1151
+ }
1152
+ onExternalMemberViewRequested() {
1153
+ this.externalMemberViewRequested.emit();
1154
+ }
1155
+ onItemCreated(item) {
1156
+ this.itemCreated.emit(item);
1157
+ }
1158
+ isCategoryExpanded(category) {
1159
+ return this.expandedCategories().has(category);
1160
+ }
1161
+ toggleCategory(category) {
1162
+ this.hasUserToggled.set(true);
1163
+ const next = new Set(this.expandedCategories());
1164
+ if (next.has(category)) {
1165
+ next.delete(category);
1166
+ }
1167
+ else {
1168
+ next.add(category);
1169
+ }
1170
+ this.expandedCategories.set(next);
1171
+ }
1172
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: PackingListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1173
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: PackingListComponent, isStandalone: true, selector: "c2g-packing-list", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: true, transformFunction: null }, members: { classPropertyName: "members", publicName: "members", isSignal: true, isRequired: true, transformFunction: null }, currentUserId: { classPropertyName: "currentUserId", publicName: "currentUserId", isSignal: true, isRequired: true, transformFunction: null }, permissions: { classPropertyName: "permissions", publicName: "permissions", isSignal: true, isRequired: false, transformFunction: null }, labels: { classPropertyName: "labels", publicName: "labels", isSignal: true, isRequired: false, transformFunction: null }, categories: { classPropertyName: "categories", publicName: "categories", isSignal: true, isRequired: false, transformFunction: null }, config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null }, showPrivateAsSeparateList: { classPropertyName: "showPrivateAsSeparateList", publicName: "showPrivateAsSeparateList", isSignal: true, isRequired: false, transformFunction: null }, showStats: { classPropertyName: "showStats", publicName: "showStats", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { itemChecked: "itemChecked", itemAssigned: "itemAssigned", itemDeleted: "itemDeleted", itemEditRequested: "itemEditRequested", itemCreated: "itemCreated", personalItemToggled: "personalItemToggled", memberOverlayRequested: "memberOverlayRequested", externalMemberViewRequested: "externalMemberViewRequested", filterChanged: "filterChanged", sortChanged: "sortChanged", rowActionTriggered: "rowActionTriggered" }, ngImport: i0, template: "<section class=\"c2g-packing-list\">\n <header class=\"c2g-packing-list__header\">\n <c2g-packing-list-filters\n [filter]=\"filter()\"\n [members]=\"members()\"\n [labels]=\"labels()\"\n [disabled]=\"permissions().readOnly\"\n (filterChange)=\"onFilterChange($event)\"\n (overlayRequested)=\"onExternalMemberViewRequested()\">\n </c2g-packing-list-filters>\n\n <div class=\"c2g-packing-list__header-actions\">\n <c2g-packing-list-item-create\n [permissions]=\"permissions()\"\n [labels]=\"labels()\"\n [readOnly]=\"permissions().readOnly\"\n [categories]=\"categories()\"\n (itemCreated)=\"onItemCreated($event)\">\n </c2g-packing-list-item-create>\n </div>\n </header>\n\n @if (filteredItems().length === 0) {\n <p class=\"c2g-packing-list__empty\">{{ labels().emptyStateKey }}</p>\n }\n\n <div class=\"c2g-packing-list__categories\">\n @for (group of categoryGroups(); track group.key) {\n <c2g-packing-list-category\n [categoryKey]=\"group.key\"\n [items]=\"group.items\"\n [members]=\"members()\"\n [selectedMemberIds]=\"filter().memberIds\"\n [currentUserId]=\"currentUserId()\"\n [permissions]=\"permissions()\"\n [expanded]=\"isCategoryExpanded(group.key)\"\n (toggle)=\"toggleCategory($event)\"\n (itemChecked)=\"itemChecked.emit($event)\"\n (itemAssigned)=\"itemAssigned.emit($event)\"\n (itemDeleted)=\"itemDeleted.emit($event)\"\n (itemEditRequested)=\"itemEditRequested.emit($event)\"\n (personalItemToggled)=\"personalItemToggled.emit($event)\"\n (memberOverlayRequested)=\"memberOverlayRequested.emit($event)\">\n </c2g-packing-list-category>\n }\n </div>\n\n @if (showPrivateAsSeparateList()) {\n <c2g-packing-list-private-list\n [items]=\"filteredItems()\"\n [members]=\"members()\"\n [selectedMemberIds]=\"filter().memberIds\"\n [currentUserId]=\"currentUserId()\"\n [permissions]=\"permissions()\"\n [labels]=\"labels()\"\n (itemChecked)=\"itemChecked.emit($event)\"\n (itemAssigned)=\"itemAssigned.emit($event)\"\n (itemDeleted)=\"itemDeleted.emit($event)\"\n (itemEditRequested)=\"itemEditRequested.emit($event)\"\n (personalItemToggled)=\"personalItemToggled.emit($event)\"\n (memberOverlayRequested)=\"memberOverlayRequested.emit($event)\">\n </c2g-packing-list-private-list>\n }\n</section>\n", styles: [".c2g-packing-list{display:grid;gap:.9rem}.c2g-packing-list__header{display:flex;justify-content:space-between;align-items:center;gap:.8rem;flex-wrap:wrap}.c2g-packing-list__header-actions{display:flex;align-items:center;gap:.8rem;flex-wrap:wrap}.c2g-packing-list__categories{display:grid;gap:.65rem}.c2g-packing-list__empty{margin:0;border:1px dashed var(--c2g-color-outline);border-radius:.75rem;background:var(--c2g-color-neutral-50);color:var(--c2g-color-text-muted);padding:.85rem;font-size:.9rem}\n"], dependencies: [{ kind: "component", type: PackingListFiltersComponent, selector: "c2g-packing-list-filters", inputs: ["filter", "members", "labels", "disabled"], outputs: ["filterChange", "overlayRequested"] }, { kind: "component", type: PackingListCategoryComponent, selector: "c2g-packing-list-category", inputs: ["categoryKey", "items", "members", "selectedMemberIds", "currentUserId", "permissions", "expanded"], outputs: ["toggle", "itemChecked", "itemAssigned", "itemDeleted", "itemEditRequested", "personalItemToggled", "memberOverlayRequested"] }, { kind: "component", type: PackingListPrivateListComponent, selector: "c2g-packing-list-private-list", inputs: ["items", "members", "selectedMemberIds", "currentUserId", "permissions", "labels"], outputs: ["itemChecked", "itemAssigned", "itemDeleted", "itemEditRequested", "personalItemToggled", "memberOverlayRequested"] }, { kind: "component", type: PackingListItemCreateComponent, selector: "c2g-packing-list-item-create", inputs: ["permissions", "labels", "readOnly", "categories"], outputs: ["itemCreated"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1174
+ }
1175
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: PackingListComponent, decorators: [{
1176
+ type: Component,
1177
+ args: [{ selector: 'c2g-packing-list', standalone: true, imports: [
1178
+ PackingListFiltersComponent,
1179
+ PackingListCategoryComponent,
1180
+ PackingListPrivateListComponent,
1181
+ PackingListItemCreateComponent
1182
+ ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<section class=\"c2g-packing-list\">\n <header class=\"c2g-packing-list__header\">\n <c2g-packing-list-filters\n [filter]=\"filter()\"\n [members]=\"members()\"\n [labels]=\"labels()\"\n [disabled]=\"permissions().readOnly\"\n (filterChange)=\"onFilterChange($event)\"\n (overlayRequested)=\"onExternalMemberViewRequested()\">\n </c2g-packing-list-filters>\n\n <div class=\"c2g-packing-list__header-actions\">\n <c2g-packing-list-item-create\n [permissions]=\"permissions()\"\n [labels]=\"labels()\"\n [readOnly]=\"permissions().readOnly\"\n [categories]=\"categories()\"\n (itemCreated)=\"onItemCreated($event)\">\n </c2g-packing-list-item-create>\n </div>\n </header>\n\n @if (filteredItems().length === 0) {\n <p class=\"c2g-packing-list__empty\">{{ labels().emptyStateKey }}</p>\n }\n\n <div class=\"c2g-packing-list__categories\">\n @for (group of categoryGroups(); track group.key) {\n <c2g-packing-list-category\n [categoryKey]=\"group.key\"\n [items]=\"group.items\"\n [members]=\"members()\"\n [selectedMemberIds]=\"filter().memberIds\"\n [currentUserId]=\"currentUserId()\"\n [permissions]=\"permissions()\"\n [expanded]=\"isCategoryExpanded(group.key)\"\n (toggle)=\"toggleCategory($event)\"\n (itemChecked)=\"itemChecked.emit($event)\"\n (itemAssigned)=\"itemAssigned.emit($event)\"\n (itemDeleted)=\"itemDeleted.emit($event)\"\n (itemEditRequested)=\"itemEditRequested.emit($event)\"\n (personalItemToggled)=\"personalItemToggled.emit($event)\"\n (memberOverlayRequested)=\"memberOverlayRequested.emit($event)\">\n </c2g-packing-list-category>\n }\n </div>\n\n @if (showPrivateAsSeparateList()) {\n <c2g-packing-list-private-list\n [items]=\"filteredItems()\"\n [members]=\"members()\"\n [selectedMemberIds]=\"filter().memberIds\"\n [currentUserId]=\"currentUserId()\"\n [permissions]=\"permissions()\"\n [labels]=\"labels()\"\n (itemChecked)=\"itemChecked.emit($event)\"\n (itemAssigned)=\"itemAssigned.emit($event)\"\n (itemDeleted)=\"itemDeleted.emit($event)\"\n (itemEditRequested)=\"itemEditRequested.emit($event)\"\n (personalItemToggled)=\"personalItemToggled.emit($event)\"\n (memberOverlayRequested)=\"memberOverlayRequested.emit($event)\">\n </c2g-packing-list-private-list>\n }\n</section>\n", styles: [".c2g-packing-list{display:grid;gap:.9rem}.c2g-packing-list__header{display:flex;justify-content:space-between;align-items:center;gap:.8rem;flex-wrap:wrap}.c2g-packing-list__header-actions{display:flex;align-items:center;gap:.8rem;flex-wrap:wrap}.c2g-packing-list__categories{display:grid;gap:.65rem}.c2g-packing-list__empty{margin:0;border:1px dashed var(--c2g-color-outline);border-radius:.75rem;background:var(--c2g-color-neutral-50);color:var(--c2g-color-text-muted);padding:.85rem;font-size:.9rem}\n"] }]
1183
+ }], ctorParameters: () => [], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: true }] }], members: [{ type: i0.Input, args: [{ isSignal: true, alias: "members", required: true }] }], currentUserId: [{ type: i0.Input, args: [{ isSignal: true, alias: "currentUserId", required: true }] }], permissions: [{ type: i0.Input, args: [{ isSignal: true, alias: "permissions", required: false }] }], labels: [{ type: i0.Input, args: [{ isSignal: true, alias: "labels", required: false }] }], categories: [{ type: i0.Input, args: [{ isSignal: true, alias: "categories", required: false }] }], config: [{ type: i0.Input, args: [{ isSignal: true, alias: "config", required: false }] }], showPrivateAsSeparateList: [{ type: i0.Input, args: [{ isSignal: true, alias: "showPrivateAsSeparateList", required: false }] }], showStats: [{ type: i0.Input, args: [{ isSignal: true, alias: "showStats", required: false }] }], itemChecked: [{ type: i0.Output, args: ["itemChecked"] }], itemAssigned: [{ type: i0.Output, args: ["itemAssigned"] }], itemDeleted: [{ type: i0.Output, args: ["itemDeleted"] }], itemEditRequested: [{ type: i0.Output, args: ["itemEditRequested"] }], itemCreated: [{ type: i0.Output, args: ["itemCreated"] }], personalItemToggled: [{ type: i0.Output, args: ["personalItemToggled"] }], memberOverlayRequested: [{ type: i0.Output, args: ["memberOverlayRequested"] }], externalMemberViewRequested: [{ type: i0.Output, args: ["externalMemberViewRequested"] }], filterChanged: [{ type: i0.Output, args: ["filterChanged"] }], sortChanged: [{ type: i0.Output, args: ["sortChanged"] }], rowActionTriggered: [{ type: i0.Output, args: ["rowActionTriggered"] }] } });
1184
+
1185
+ class PackingListStatsComponent {
1186
+ items = input.required(...(ngDevMode ? [{ debugName: "items" }] : []));
1187
+ stats = computed(() => {
1188
+ const items = this.items();
1189
+ const packed = items.filter(item => (item.assignments ?? []).some(a => a.status === 'packed' || a.status === 'confirmed')).length;
1190
+ const essential = items.filter(item => !!item.essential).length;
1191
+ return { total: items.length, packed, essential };
1192
+ }, ...(ngDevMode ? [{ debugName: "stats" }] : []));
1193
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: PackingListStatsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1194
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.19", type: PackingListStatsComponent, isStandalone: true, selector: "c2g-packing-list-stats", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<div class=\"c2g-pl-stats\">\n <span>{{ stats().packed }}/{{ stats().total }}</span>\n <span>essential: {{ stats().essential }}</span>\n</div>\n", styles: [".c2g-pl-stats{display:inline-flex;gap:.8rem;align-items:center;font-size:.8rem;color:var(--c2g-color-text-secondary);border:1px solid var(--c2g-color-outline);border-radius:999px;padding:.25rem .6rem}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1195
+ }
1196
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: PackingListStatsComponent, decorators: [{
1197
+ type: Component,
1198
+ args: [{ selector: 'c2g-packing-list-stats', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"c2g-pl-stats\">\n <span>{{ stats().packed }}/{{ stats().total }}</span>\n <span>essential: {{ stats().essential }}</span>\n</div>\n", styles: [".c2g-pl-stats{display:inline-flex;gap:.8rem;align-items:center;font-size:.8rem;color:var(--c2g-color-text-secondary);border:1px solid var(--c2g-color-outline);border-radius:999px;padding:.25rem .6rem}\n"] }]
1199
+ }], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: true }] }] } });
1200
+
1201
+ const WEATHER_ICON_MAP = {
1202
+ 'sunny': '☀️',
1203
+ 'clear': '☀️',
1204
+ 'partly-cloudy': '⛅',
1205
+ 'partly_cloudy': '⛅',
1206
+ 'cloudy': '☁️',
1207
+ 'overcast': '☁️',
1208
+ 'light-rain': '🌦️',
1209
+ 'light_rain': '🌦️',
1210
+ 'rain': '🌧️',
1211
+ 'heavy-rain': '⛈️',
1212
+ 'heavy_rain': '⛈️',
1213
+ 'snow': '❄️',
1214
+ 'fog': '🌫️',
1215
+ 'thunder': '⛈️',
1216
+ 'wind': '💨',
1217
+ };
1218
+ /**
1219
+ * Resolves a backend weather icon string to an emoji.
1220
+ * @param icon Raw icon string from the API (e.g. "partly-cloudy")
1221
+ * @param fallback Emoji to return for unrecognised keys. Defaults to '🌤️'.
1222
+ * Pass `icon` as fallback to preserve the raw string (useful
1223
+ * for debugging in the full weather widget).
1224
+ */
1225
+ function resolveWeatherIcon(icon, fallback = '🌤️') {
1226
+ if (!icon)
1227
+ return fallback;
1228
+ return WEATHER_ICON_MAP[icon.toLowerCase()] ?? fallback;
1229
+ }
1230
+
1231
+ class WeatherWidgetComponent {
1232
+ currentDay = input(null, ...(ngDevMode ? [{ debugName: "currentDay" }] : []));
1233
+ forecastSlots = input([], ...(ngDevMode ? [{ debugName: "forecastSlots" }] : []));
1234
+ destination = input('', ...(ngDevMode ? [{ debugName: "destination" }] : []));
1235
+ dates = input(null, ...(ngDevMode ? [{ debugName: "dates" }] : []));
1236
+ getWeatherIcon(icon) {
1237
+ return resolveWeatherIcon(icon, icon);
1238
+ }
1239
+ formatDate(date) {
1240
+ return new Date(date).toLocaleDateString('de-DE', {
1241
+ weekday: 'short',
1242
+ day: 'numeric',
1243
+ month: 'short'
1244
+ });
1245
+ }
1246
+ formatShortDate(date) {
1247
+ return new Date(date).toLocaleDateString('de-DE', { day: 'numeric', month: 'short' });
1248
+ }
1249
+ getSlotLabel(index, total) {
1250
+ if (total === 1)
1251
+ return 'Reise';
1252
+ if (index === 0)
1253
+ return 'Anreise';
1254
+ if (index === total - 1)
1255
+ return 'Abreise';
1256
+ return 'Mitte';
1257
+ }
1258
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: WeatherWidgetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1259
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: WeatherWidgetComponent, isStandalone: true, selector: "c2g-weather-widget", inputs: { currentDay: { classPropertyName: "currentDay", publicName: "currentDay", isSignal: true, isRequired: false, transformFunction: null }, forecastSlots: { classPropertyName: "forecastSlots", publicName: "forecastSlots", isSignal: true, isRequired: false, transformFunction: null }, destination: { classPropertyName: "destination", publicName: "destination", isSignal: true, isRequired: false, transformFunction: null }, dates: { classPropertyName: "dates", publicName: "dates", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@if (currentDay()) {\n <div class=\"wx-widget\">\n <!-- Hero: current/start-day weather -->\n <div class=\"wx-hero\">\n <span class=\"wx-hero__icon\">{{ getWeatherIcon(currentDay()!.icon) }}</span>\n <div class=\"wx-hero__body\">\n <div class=\"wx-hero__temp\">{{ currentDay()!.temperature.max }}<sup>\u00B0</sup></div>\n <div class=\"wx-hero__condition\">{{ currentDay()!.description }}</div>\n @if (destination()) {\n <div class=\"wx-hero__meta\">\n <span class=\"wx-hero__location\">\uD83D\uDCCD {{ destination() }}</span>\n @if (dates()) {\n <span class=\"wx-hero__daterange\">\n {{ formatShortDate(dates()!.from) }} \u2013 {{ formatShortDate(dates()!.to) }}\n </span>\n }\n </div>\n }\n </div>\n <div class=\"wx-hero__range\">\n <span class=\"wx-range__high\">\u2191 {{ currentDay()!.temperature.max }}\u00B0</span>\n <span class=\"wx-range__low\">\u2193 {{ currentDay()!.temperature.min }}\u00B0</span>\n </div>\n </div>\n\n <!-- Forecast slots -->\n @if (forecastSlots().length > 1) {\n <div class=\"wx-forecast\" [attr.data-slots]=\"forecastSlots().length\">\n @for (slot of forecastSlots(); track $index) {\n <div class=\"wx-slot\">\n <span class=\"wx-slot__label\">{{ getSlotLabel($index, forecastSlots().length) }}</span>\n <span class=\"wx-slot__date\">{{ formatDate(slot.date) }}</span>\n <span class=\"wx-slot__icon\">{{ getWeatherIcon(slot.icon) }}</span>\n <div class=\"wx-slot__temps\">\n <span class=\"wx-slot__max\">{{ slot.temperature.max }}\u00B0</span>\n <span class=\"wx-slot__min\">{{ slot.temperature.min }}\u00B0</span>\n </div>\n </div>\n }\n </div>\n }\n </div>\n} @else {\n <div class=\"wx-empty\">Wetter erscheint nach Ziel- und Datumsauswahl.</div>\n}\n", styles: [".wx-widget{display:flex;flex-direction:column;gap:.75rem;font-family:inherit}.wx-hero{display:flex;align-items:center;gap:.85rem;padding:.85rem 1rem;border-radius:14px;background:linear-gradient(135deg,var(--c2g-color-primary-light) 0%,var(--c2g-color-primary-container) 100%);border:1px solid var(--c2g-color-border-subtle)}.wx-hero__icon{font-size:2.6rem;line-height:1;flex-shrink:0}.wx-hero__body{flex:1;min-width:0}.wx-hero__temp{font-size:2rem;font-weight:700;color:var(--c2g-color-text-primary);line-height:1;letter-spacing:-.03em}.wx-hero__temp sup{font-size:1rem;font-weight:500;vertical-align:super}.wx-hero__condition{font-size:.82rem;color:var(--c2g-color-text-secondary);margin-top:.15rem;font-weight:500}.wx-hero__meta{display:flex;flex-wrap:wrap;gap:.3rem .5rem;margin-top:.3rem;font-size:.75rem;color:var(--c2g-color-text-muted)}.wx-hero__location{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:22ch}.wx-hero__daterange{opacity:.75;white-space:nowrap}.wx-range__high{display:block;font-size:.82rem;font-weight:700;color:var(--c2g-color-primary-dark)}.wx-range__low{display:block;font-size:.78rem;color:var(--c2g-color-info);margin-top:.1rem}.wx-forecast{display:grid;grid-template-columns:repeat(2,1fr);gap:.5rem}.wx-forecast[data-slots=\"3\"]{grid-template-columns:repeat(3,1fr)}.wx-slot{display:flex;flex-direction:column;align-items:center;gap:.18rem;padding:.6rem .4rem .55rem;border-radius:10px;border:1px solid var(--c2g-color-border-soft);background:var(--c2g-color-surface);text-align:center}.wx-slot__label{font-size:.62rem;font-weight:700;color:var(--c2g-color-primary-dark);text-transform:uppercase;letter-spacing:.06em}.wx-slot__date{font-size:.67rem;color:var(--c2g-color-text-muted);line-height:1.2}.wx-slot__icon{font-size:1.5rem;margin:.15rem 0;line-height:1}.wx-slot__temps{display:flex;gap:.3rem;align-items:baseline}.wx-slot__max{font-size:.88rem;font-weight:700;color:var(--c2g-color-text-primary)}.wx-slot__min{font-size:.75rem;color:var(--c2g-color-info)}.wx-empty{padding:.75rem;font-size:.85rem;color:var(--c2g-color-text-muted);text-align:center}@media(max-width:480px){.wx-hero__icon{font-size:2.1rem}.wx-hero__temp{font-size:1.7rem}.wx-slot{padding:.5rem .25rem}.wx-slot__icon{font-size:1.25rem}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1260
+ }
1261
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: WeatherWidgetComponent, decorators: [{
1262
+ type: Component,
1263
+ args: [{ selector: 'c2g-weather-widget', standalone: true, imports: [], changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (currentDay()) {\n <div class=\"wx-widget\">\n <!-- Hero: current/start-day weather -->\n <div class=\"wx-hero\">\n <span class=\"wx-hero__icon\">{{ getWeatherIcon(currentDay()!.icon) }}</span>\n <div class=\"wx-hero__body\">\n <div class=\"wx-hero__temp\">{{ currentDay()!.temperature.max }}<sup>\u00B0</sup></div>\n <div class=\"wx-hero__condition\">{{ currentDay()!.description }}</div>\n @if (destination()) {\n <div class=\"wx-hero__meta\">\n <span class=\"wx-hero__location\">\uD83D\uDCCD {{ destination() }}</span>\n @if (dates()) {\n <span class=\"wx-hero__daterange\">\n {{ formatShortDate(dates()!.from) }} \u2013 {{ formatShortDate(dates()!.to) }}\n </span>\n }\n </div>\n }\n </div>\n <div class=\"wx-hero__range\">\n <span class=\"wx-range__high\">\u2191 {{ currentDay()!.temperature.max }}\u00B0</span>\n <span class=\"wx-range__low\">\u2193 {{ currentDay()!.temperature.min }}\u00B0</span>\n </div>\n </div>\n\n <!-- Forecast slots -->\n @if (forecastSlots().length > 1) {\n <div class=\"wx-forecast\" [attr.data-slots]=\"forecastSlots().length\">\n @for (slot of forecastSlots(); track $index) {\n <div class=\"wx-slot\">\n <span class=\"wx-slot__label\">{{ getSlotLabel($index, forecastSlots().length) }}</span>\n <span class=\"wx-slot__date\">{{ formatDate(slot.date) }}</span>\n <span class=\"wx-slot__icon\">{{ getWeatherIcon(slot.icon) }}</span>\n <div class=\"wx-slot__temps\">\n <span class=\"wx-slot__max\">{{ slot.temperature.max }}\u00B0</span>\n <span class=\"wx-slot__min\">{{ slot.temperature.min }}\u00B0</span>\n </div>\n </div>\n }\n </div>\n }\n </div>\n} @else {\n <div class=\"wx-empty\">Wetter erscheint nach Ziel- und Datumsauswahl.</div>\n}\n", styles: [".wx-widget{display:flex;flex-direction:column;gap:.75rem;font-family:inherit}.wx-hero{display:flex;align-items:center;gap:.85rem;padding:.85rem 1rem;border-radius:14px;background:linear-gradient(135deg,var(--c2g-color-primary-light) 0%,var(--c2g-color-primary-container) 100%);border:1px solid var(--c2g-color-border-subtle)}.wx-hero__icon{font-size:2.6rem;line-height:1;flex-shrink:0}.wx-hero__body{flex:1;min-width:0}.wx-hero__temp{font-size:2rem;font-weight:700;color:var(--c2g-color-text-primary);line-height:1;letter-spacing:-.03em}.wx-hero__temp sup{font-size:1rem;font-weight:500;vertical-align:super}.wx-hero__condition{font-size:.82rem;color:var(--c2g-color-text-secondary);margin-top:.15rem;font-weight:500}.wx-hero__meta{display:flex;flex-wrap:wrap;gap:.3rem .5rem;margin-top:.3rem;font-size:.75rem;color:var(--c2g-color-text-muted)}.wx-hero__location{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:22ch}.wx-hero__daterange{opacity:.75;white-space:nowrap}.wx-range__high{display:block;font-size:.82rem;font-weight:700;color:var(--c2g-color-primary-dark)}.wx-range__low{display:block;font-size:.78rem;color:var(--c2g-color-info);margin-top:.1rem}.wx-forecast{display:grid;grid-template-columns:repeat(2,1fr);gap:.5rem}.wx-forecast[data-slots=\"3\"]{grid-template-columns:repeat(3,1fr)}.wx-slot{display:flex;flex-direction:column;align-items:center;gap:.18rem;padding:.6rem .4rem .55rem;border-radius:10px;border:1px solid var(--c2g-color-border-soft);background:var(--c2g-color-surface);text-align:center}.wx-slot__label{font-size:.62rem;font-weight:700;color:var(--c2g-color-primary-dark);text-transform:uppercase;letter-spacing:.06em}.wx-slot__date{font-size:.67rem;color:var(--c2g-color-text-muted);line-height:1.2}.wx-slot__icon{font-size:1.5rem;margin:.15rem 0;line-height:1}.wx-slot__temps{display:flex;gap:.3rem;align-items:baseline}.wx-slot__max{font-size:.88rem;font-weight:700;color:var(--c2g-color-text-primary)}.wx-slot__min{font-size:.75rem;color:var(--c2g-color-info)}.wx-empty{padding:.75rem;font-size:.85rem;color:var(--c2g-color-text-muted);text-align:center}@media(max-width:480px){.wx-hero__icon{font-size:2.1rem}.wx-hero__temp{font-size:1.7rem}.wx-slot{padding:.5rem .25rem}.wx-slot__icon{font-size:1.25rem}}\n"] }]
1264
+ }], propDecorators: { currentDay: [{ type: i0.Input, args: [{ isSignal: true, alias: "currentDay", required: false }] }], forecastSlots: [{ type: i0.Input, args: [{ isSignal: true, alias: "forecastSlots", required: false }] }], destination: [{ type: i0.Input, args: [{ isSignal: true, alias: "destination", required: false }] }], dates: [{ type: i0.Input, args: [{ isSignal: true, alias: "dates", required: false }] }] } });
1265
+
1266
+ class MemberTagsComponent {
1267
+ isCurrentUser = input(false, ...(ngDevMode ? [{ debugName: "isCurrentUser" }] : []));
1268
+ isRegistered = input(true, ...(ngDevMode ? [{ debugName: "isRegistered" }] : []));
1269
+ roleKey = input(null, ...(ngDevMode ? [{ debugName: "roleKey" }] : []));
1270
+ getRoleLabel(roleKey) {
1271
+ switch (roleKey) {
1272
+ case 'organizer':
1273
+ return '🧭 Organisator';
1274
+ case 'treasurer':
1275
+ return '💰 Kassenwart';
1276
+ case 'transport':
1277
+ return '🚙 Fahrkoordination';
1278
+ case 'cook':
1279
+ return '👨‍🍳 Kochen';
1280
+ case 'firstaid':
1281
+ return '🩺 Erste Hilfe';
1282
+ case 'equipment':
1283
+ return '🎒 Ausrüstung';
1284
+ default:
1285
+ return '';
1286
+ }
1287
+ }
1288
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: MemberTagsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1289
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: MemberTagsComponent, isStandalone: true, selector: "c2g-member-tags", inputs: { isCurrentUser: { classPropertyName: "isCurrentUser", publicName: "isCurrentUser", isSignal: true, isRequired: false, transformFunction: null }, isRegistered: { classPropertyName: "isRegistered", publicName: "isRegistered", isSignal: true, isRequired: false, transformFunction: null }, roleKey: { classPropertyName: "roleKey", publicName: "roleKey", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@if (isCurrentUser()) {\n <span class=\"tw-member__you-badge\">Du</span>\n}\n\n@if (!isRegistered()) {\n <span class=\"tw-member__unreg-badge\">Ohne Account</span>\n}\n\n@if (roleKey()) {\n <span class=\"tw-member__role\">{{ getRoleLabel(roleKey()) }}</span>\n}\n", styles: [".tw-member__you-badge{font-size:.62rem;font-weight:700;padding:.1rem .45rem;border-radius:999px;background:var(--c2g-color-secondary-dark);color:var(--c2g-color-surface);text-transform:uppercase;letter-spacing:.06em}.tw-member__unreg-badge{font-size:.62rem;font-weight:700;padding:.1rem .45rem;border-radius:999px;background:var(--c2g-color-primary-container);color:var(--c2g-color-on-primary-container);text-transform:uppercase;letter-spacing:.06em}.tw-member__role{font-size:.78rem;font-weight:600;color:var(--c2g-color-secondary-dark);padding:.25rem .65rem;border-radius:999px;background:var(--c2g-color-secondary-container);white-space:nowrap}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1290
+ }
1291
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: MemberTagsComponent, decorators: [{
1292
+ type: Component,
1293
+ args: [{ selector: 'c2g-member-tags', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (isCurrentUser()) {\n <span class=\"tw-member__you-badge\">Du</span>\n}\n\n@if (!isRegistered()) {\n <span class=\"tw-member__unreg-badge\">Ohne Account</span>\n}\n\n@if (roleKey()) {\n <span class=\"tw-member__role\">{{ getRoleLabel(roleKey()) }}</span>\n}\n", styles: [".tw-member__you-badge{font-size:.62rem;font-weight:700;padding:.1rem .45rem;border-radius:999px;background:var(--c2g-color-secondary-dark);color:var(--c2g-color-surface);text-transform:uppercase;letter-spacing:.06em}.tw-member__unreg-badge{font-size:.62rem;font-weight:700;padding:.1rem .45rem;border-radius:999px;background:var(--c2g-color-primary-container);color:var(--c2g-color-on-primary-container);text-transform:uppercase;letter-spacing:.06em}.tw-member__role{font-size:.78rem;font-weight:600;color:var(--c2g-color-secondary-dark);padding:.25rem .65rem;border-radius:999px;background:var(--c2g-color-secondary-container);white-space:nowrap}\n"] }]
1294
+ }], propDecorators: { isCurrentUser: [{ type: i0.Input, args: [{ isSignal: true, alias: "isCurrentUser", required: false }] }], isRegistered: [{ type: i0.Input, args: [{ isSignal: true, alias: "isRegistered", required: false }] }], roleKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "roleKey", required: false }] }] } });
1295
+
1296
+ class ActionMenuComponent {
1297
+ items = input.required(...(ngDevMode ? [{ debugName: "items" }] : []));
1298
+ triggerLabel = input('...', ...(ngDevMode ? [{ debugName: "triggerLabel" }] : []));
1299
+ ariaLabel = input('Aktionen', ...(ngDevMode ? [{ debugName: "ariaLabel" }] : []));
1300
+ itemSelected = output();
1301
+ select(item) {
1302
+ if (item.disabled)
1303
+ return;
1304
+ this.itemSelected.emit(item);
1305
+ }
1306
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: ActionMenuComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1307
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: ActionMenuComponent, isStandalone: true, selector: "c2g-action-menu", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: true, transformFunction: null }, triggerLabel: { classPropertyName: "triggerLabel", publicName: "triggerLabel", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { itemSelected: "itemSelected" }, ngImport: i0, template: "<div class=\"c2g-action-menu\">\n <button\n class=\"c2g-action-menu__trigger\"\n type=\"button\"\n [attr.aria-label]=\"ariaLabel()\"\n [cdkMenuTriggerFor]=\"menuPanel\">\n {{ triggerLabel() }}\n </button>\n\n <ng-template #menuPanel>\n <ul class=\"c2g-action-menu__list\" cdkMenu>\n @for (item of items(); track item.key) {\n <li role=\"none\">\n <button\n class=\"c2g-action-menu__item\"\n [class.c2g-action-menu__item--danger]=\"item.variant === 'danger'\"\n [class.c2g-action-menu__item--disabled]=\"item.disabled\"\n [disabled]=\"item.disabled ?? false\"\n cdkMenuItem\n type=\"button\"\n (cdkMenuItemTriggered)=\"select(item)\">\n @if (item.icon) {\n <span class=\"c2g-action-menu__item-icon\" aria-hidden=\"true\">{{ item.icon }}</span>\n }\n <span>{{ item.label }}</span>\n </button>\n </li>\n }\n </ul>\n </ng-template>\n</div>\n", styles: [".c2g-action-menu{position:relative;display:inline-flex}.c2g-action-menu__trigger{display:inline-flex;align-items:center;justify-content:center;width:32px;height:32px;border-radius:8px;border:1px solid transparent;background:transparent;color:var(--c2g-color-text-muted);font-size:1.1rem;font-weight:700;letter-spacing:.05em;cursor:pointer;transition:background .15s,border-color .15s,color .15s}.c2g-action-menu__trigger:hover{background:var(--c2g-color-neutral-100);border-color:var(--c2g-color-outline);color:var(--c2g-color-text-primary)}.c2g-action-menu__trigger[aria-expanded=true]{background:var(--c2g-color-secondary-container);border-color:var(--c2g-color-outline-variant);color:var(--c2g-color-secondary-dark)}.c2g-action-menu__list{position:absolute;top:calc(100% + 4px);right:0;z-index:200;min-width:160px;margin:0;padding:.3rem;list-style:none;background:var(--c2g-color-surface);border:1px solid var(--c2g-color-outline-variant);border-radius:10px;box-shadow:0 4px 16px #0000001a,0 1px 4px #0000000f}.c2g-action-menu__item{display:flex;align-items:center;gap:.5rem;width:100%;padding:.5rem .75rem;border:none;border-radius:7px;background:transparent;font-size:.85rem;font-weight:500;color:var(--c2g-color-text-primary);cursor:pointer;text-align:left;transition:background .1s}.c2g-action-menu__item:hover:not([disabled]){background:var(--c2g-color-neutral-100)}.c2g-action-menu__item--danger{color:var(--c2g-color-error)}.c2g-action-menu__item--danger:hover:not([disabled]){background:var(--c2g-color-primary-light)}.c2g-action-menu__item--disabled,.c2g-action-menu__item[disabled]{opacity:.4;cursor:not-allowed}.c2g-action-menu__item-icon{font-size:1rem;line-height:1;flex-shrink:0}\n"], dependencies: [{ kind: "directive", type: CdkMenu, selector: "[cdkMenu]", outputs: ["closed"], exportAs: ["cdkMenu"] }, { kind: "directive", type: CdkMenuItem, selector: "[cdkMenuItem]", inputs: ["cdkMenuItemDisabled", "cdkMenuitemTypeaheadLabel"], outputs: ["cdkMenuItemTriggered"], exportAs: ["cdkMenuItem"] }, { kind: "directive", type: CdkMenuTrigger, selector: "[cdkMenuTriggerFor]", inputs: ["cdkMenuTriggerFor", "cdkMenuPosition", "cdkMenuTriggerData"], outputs: ["cdkMenuOpened", "cdkMenuClosed"], exportAs: ["cdkMenuTriggerFor"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1308
+ }
1309
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: ActionMenuComponent, decorators: [{
1310
+ type: Component,
1311
+ args: [{ selector: 'c2g-action-menu', standalone: true, imports: [CdkMenu, CdkMenuItem, CdkMenuTrigger], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"c2g-action-menu\">\n <button\n class=\"c2g-action-menu__trigger\"\n type=\"button\"\n [attr.aria-label]=\"ariaLabel()\"\n [cdkMenuTriggerFor]=\"menuPanel\">\n {{ triggerLabel() }}\n </button>\n\n <ng-template #menuPanel>\n <ul class=\"c2g-action-menu__list\" cdkMenu>\n @for (item of items(); track item.key) {\n <li role=\"none\">\n <button\n class=\"c2g-action-menu__item\"\n [class.c2g-action-menu__item--danger]=\"item.variant === 'danger'\"\n [class.c2g-action-menu__item--disabled]=\"item.disabled\"\n [disabled]=\"item.disabled ?? false\"\n cdkMenuItem\n type=\"button\"\n (cdkMenuItemTriggered)=\"select(item)\">\n @if (item.icon) {\n <span class=\"c2g-action-menu__item-icon\" aria-hidden=\"true\">{{ item.icon }}</span>\n }\n <span>{{ item.label }}</span>\n </button>\n </li>\n }\n </ul>\n </ng-template>\n</div>\n", styles: [".c2g-action-menu{position:relative;display:inline-flex}.c2g-action-menu__trigger{display:inline-flex;align-items:center;justify-content:center;width:32px;height:32px;border-radius:8px;border:1px solid transparent;background:transparent;color:var(--c2g-color-text-muted);font-size:1.1rem;font-weight:700;letter-spacing:.05em;cursor:pointer;transition:background .15s,border-color .15s,color .15s}.c2g-action-menu__trigger:hover{background:var(--c2g-color-neutral-100);border-color:var(--c2g-color-outline);color:var(--c2g-color-text-primary)}.c2g-action-menu__trigger[aria-expanded=true]{background:var(--c2g-color-secondary-container);border-color:var(--c2g-color-outline-variant);color:var(--c2g-color-secondary-dark)}.c2g-action-menu__list{position:absolute;top:calc(100% + 4px);right:0;z-index:200;min-width:160px;margin:0;padding:.3rem;list-style:none;background:var(--c2g-color-surface);border:1px solid var(--c2g-color-outline-variant);border-radius:10px;box-shadow:0 4px 16px #0000001a,0 1px 4px #0000000f}.c2g-action-menu__item{display:flex;align-items:center;gap:.5rem;width:100%;padding:.5rem .75rem;border:none;border-radius:7px;background:transparent;font-size:.85rem;font-weight:500;color:var(--c2g-color-text-primary);cursor:pointer;text-align:left;transition:background .1s}.c2g-action-menu__item:hover:not([disabled]){background:var(--c2g-color-neutral-100)}.c2g-action-menu__item--danger{color:var(--c2g-color-error)}.c2g-action-menu__item--danger:hover:not([disabled]){background:var(--c2g-color-primary-light)}.c2g-action-menu__item--disabled,.c2g-action-menu__item[disabled]{opacity:.4;cursor:not-allowed}.c2g-action-menu__item-icon{font-size:1rem;line-height:1;flex-shrink:0}\n"] }]
1312
+ }], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: true }] }], triggerLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "triggerLabel", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], itemSelected: [{ type: i0.Output, args: ["itemSelected"] }] } });
1313
+
1314
+ class MemberItemComponent {
1315
+ member = input.required(...(ngDevMode ? [{ debugName: "member" }] : []));
1316
+ remove = output();
1317
+ invite = output();
1318
+ edit = output();
1319
+ avatarBackgroundColor = computed(() => this.member().isCurrentUser ? '#1a6044' : '#e8f0ea', ...(ngDevMode ? [{ debugName: "avatarBackgroundColor" }] : []));
1320
+ avatarTextColor = computed(() => this.member().isCurrentUser ? '#ffffff' : '#1a6044', ...(ngDevMode ? [{ debugName: "avatarTextColor" }] : []));
1321
+ menuItems = computed(() => {
1322
+ const m = this.member();
1323
+ const items = [];
1324
+ if (m.isRegistered !== false) {
1325
+ items.push({ key: 'invite', label: 'Einladen', icon: '✉️' });
1326
+ }
1327
+ else {
1328
+ items.push({ key: 'edit', label: 'Bearbeiten', icon: '✏️' });
1329
+ }
1330
+ items.push({ key: 'remove', label: 'Entfernen', icon: '🗑️', variant: 'danger' });
1331
+ return items;
1332
+ }, ...(ngDevMode ? [{ debugName: "menuItems" }] : []));
1333
+ onMenuItemSelected(item) {
1334
+ const m = this.member();
1335
+ if (item.key === 'remove')
1336
+ this.remove.emit(m);
1337
+ else if (item.key === 'invite')
1338
+ this.invite.emit(m);
1339
+ else if (item.key === 'edit')
1340
+ this.edit.emit(m);
1341
+ }
1342
+ getMemberTypeLabel(type) {
1343
+ switch (type) {
1344
+ case 'adult':
1345
+ return 'Erwachsener';
1346
+ case 'child':
1347
+ return 'Kind';
1348
+ case 'pet':
1349
+ return 'Haustier';
1350
+ default:
1351
+ return type;
1352
+ }
1353
+ }
1354
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: MemberItemComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1355
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.19", type: MemberItemComponent, isStandalone: true, selector: "c2g-member-item", inputs: { member: { classPropertyName: "member", publicName: "member", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { remove: "remove", invite: "invite", edit: "edit" }, ngImport: i0, template: "<c2g-avatar\n [initials]=\"member().avatarInitials\"\n [name]=\"member().name\"\n [backgroundColor]=\"avatarBackgroundColor()\"\n [textColor]=\"avatarTextColor()\"\n ringTone=\"neutral\">\n</c2g-avatar>\n\n<div class=\"tw-member__info\">\n <span class=\"tw-member__name\">\n {{ member().name }}\n <c2g-member-tags\n [isCurrentUser]=\"member().isCurrentUser ?? false\"\n [isRegistered]=\"member().isRegistered ?? true\">\n </c2g-member-tags>\n </span>\n <span class=\"tw-member__type\">{{ getMemberTypeLabel(member().type) }}</span>\n</div>\n\n<c2g-member-tags\n [isCurrentUser]=\"false\"\n [isRegistered]=\"true\"\n [roleKey]=\"member().roleKey\">\n</c2g-member-tags>\n\n<c2g-action-menu\n [items]=\"menuItems()\"\n ariaLabel=\"Mitglied-Aktionen\"\n (itemSelected)=\"onMenuItemSelected($event)\">\n</c2g-action-menu>\n", styles: [":host{display:contents}.tw-member__info{display:flex;flex-direction:column;flex:1;min-width:0}.tw-member__name{font-size:.9rem;font-weight:700;color:var(--c2g-color-text-primary);display:flex;align-items:center;gap:.4rem}.tw-member__type{font-size:.76rem;color:var(--c2g-color-text-muted)}\n"], dependencies: [{ kind: "component", type: MemberTagsComponent, selector: "c2g-member-tags", inputs: ["isCurrentUser", "isRegistered", "roleKey"] }, { kind: "component", type: ActionMenuComponent, selector: "c2g-action-menu", inputs: ["items", "triggerLabel", "ariaLabel"], outputs: ["itemSelected"] }, { kind: "component", type: AvatarComponent, selector: "c2g-avatar", inputs: ["name", "initials", "imageUrl", "ariaLabel", "size", "backgroundColor", "textColor", "ringTone", "ringColor", "clickable", "disabled", "badge"], outputs: ["avatarClick"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1356
+ }
1357
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: MemberItemComponent, decorators: [{
1358
+ type: Component,
1359
+ args: [{ selector: 'c2g-member-item', standalone: true, imports: [MemberTagsComponent, ActionMenuComponent, AvatarComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<c2g-avatar\n [initials]=\"member().avatarInitials\"\n [name]=\"member().name\"\n [backgroundColor]=\"avatarBackgroundColor()\"\n [textColor]=\"avatarTextColor()\"\n ringTone=\"neutral\">\n</c2g-avatar>\n\n<div class=\"tw-member__info\">\n <span class=\"tw-member__name\">\n {{ member().name }}\n <c2g-member-tags\n [isCurrentUser]=\"member().isCurrentUser ?? false\"\n [isRegistered]=\"member().isRegistered ?? true\">\n </c2g-member-tags>\n </span>\n <span class=\"tw-member__type\">{{ getMemberTypeLabel(member().type) }}</span>\n</div>\n\n<c2g-member-tags\n [isCurrentUser]=\"false\"\n [isRegistered]=\"true\"\n [roleKey]=\"member().roleKey\">\n</c2g-member-tags>\n\n<c2g-action-menu\n [items]=\"menuItems()\"\n ariaLabel=\"Mitglied-Aktionen\"\n (itemSelected)=\"onMenuItemSelected($event)\">\n</c2g-action-menu>\n", styles: [":host{display:contents}.tw-member__info{display:flex;flex-direction:column;flex:1;min-width:0}.tw-member__name{font-size:.9rem;font-weight:700;color:var(--c2g-color-text-primary);display:flex;align-items:center;gap:.4rem}.tw-member__type{font-size:.76rem;color:var(--c2g-color-text-muted)}\n"] }]
1360
+ }], propDecorators: { member: [{ type: i0.Input, args: [{ isSignal: true, alias: "member", required: true }] }], remove: [{ type: i0.Output, args: ["remove"] }], invite: [{ type: i0.Output, args: ["invite"] }], edit: [{ type: i0.Output, args: ["edit"] }] } });
1361
+
1362
+ class MemberListComponent {
1363
+ members = input.required(...(ngDevMode ? [{ debugName: "members" }] : []));
1364
+ memberRemove = output();
1365
+ memberInvite = output();
1366
+ memberEdit = output();
1367
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: MemberListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1368
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: MemberListComponent, isStandalone: true, selector: "c2g-member-list", inputs: { members: { classPropertyName: "members", publicName: "members", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { memberRemove: "memberRemove", memberInvite: "memberInvite", memberEdit: "memberEdit" }, ngImport: i0, template: "<ul class=\"tw-member-list\">\n @for (member of members(); track member.id) {\n <li class=\"tw-member\">\n <c2g-member-item\n [member]=\"member\"\n (remove)=\"memberRemove.emit($event)\"\n (invite)=\"memberInvite.emit($event)\"\n (edit)=\"memberEdit.emit($event)\">\n </c2g-member-item>\n </li>\n }\n</ul>\n", styles: [".tw-member-list{list-style:none;margin:0;padding:0}.tw-member{display:flex;align-items:center;gap:1rem;padding:.9rem 1.4rem;border-bottom:1px solid var(--c2g-color-neutral-100)}.tw-member:last-child{border-bottom:none}\n"], dependencies: [{ kind: "component", type: MemberItemComponent, selector: "c2g-member-item", inputs: ["member"], outputs: ["remove", "invite", "edit"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1369
+ }
1370
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: MemberListComponent, decorators: [{
1371
+ type: Component,
1372
+ args: [{ selector: 'c2g-member-list', standalone: true, imports: [MemberItemComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<ul class=\"tw-member-list\">\n @for (member of members(); track member.id) {\n <li class=\"tw-member\">\n <c2g-member-item\n [member]=\"member\"\n (remove)=\"memberRemove.emit($event)\"\n (invite)=\"memberInvite.emit($event)\"\n (edit)=\"memberEdit.emit($event)\">\n </c2g-member-item>\n </li>\n }\n</ul>\n", styles: [".tw-member-list{list-style:none;margin:0;padding:0}.tw-member{display:flex;align-items:center;gap:1rem;padding:.9rem 1.4rem;border-bottom:1px solid var(--c2g-color-neutral-100)}.tw-member:last-child{border-bottom:none}\n"] }]
1373
+ }], propDecorators: { members: [{ type: i0.Input, args: [{ isSignal: true, alias: "members", required: true }] }], memberRemove: [{ type: i0.Output, args: ["memberRemove"] }], memberInvite: [{ type: i0.Output, args: ["memberInvite"] }], memberEdit: [{ type: i0.Output, args: ["memberEdit"] }] } });
1374
+
1375
+ class MemberPanelComponent {
1376
+ members = input.required(...(ngDevMode ? [{ debugName: "members" }] : []));
1377
+ memberRemove = output();
1378
+ memberInvite = output();
1379
+ memberEdit = output();
1380
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: MemberPanelComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1381
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.19", type: MemberPanelComponent, isStandalone: true, selector: "c2g-member-panel", inputs: { members: { classPropertyName: "members", publicName: "members", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { memberRemove: "memberRemove", memberInvite: "memberInvite", memberEdit: "memberEdit" }, ngImport: i0, template: "<div class=\"tw-card\">\n <div class=\"tw-card__header\">\n <h2 class=\"tw-card__title\">Teilnehmer ({{ members().length }})</h2>\n <ng-content select=\"[slot=header-actions]\"></ng-content>\n </div>\n\n <c2g-member-list\n [members]=\"members()\"\n (memberRemove)=\"memberRemove.emit($event)\"\n (memberInvite)=\"memberInvite.emit($event)\"\n (memberEdit)=\"memberEdit.emit($event)\">\n </c2g-member-list>\n</div>\n", styles: [".tw-card{background:var(--c2g-color-surface);border-radius:12px;border:1px solid var(--c2g-color-outline-variant);overflow:hidden}.tw-card__header{display:flex;align-items:center;justify-content:space-between;padding:1.2rem 1.4rem;border-bottom:1px solid var(--c2g-color-neutral-100)}.tw-card__title{margin:0;font-size:.96rem;font-weight:700;color:var(--c2g-color-text-primary)}\n"], dependencies: [{ kind: "component", type: MemberListComponent, selector: "c2g-member-list", inputs: ["members"], outputs: ["memberRemove", "memberInvite", "memberEdit"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1382
+ }
1383
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: MemberPanelComponent, decorators: [{
1384
+ type: Component,
1385
+ args: [{ selector: 'c2g-member-panel', standalone: true, imports: [MemberListComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"tw-card\">\n <div class=\"tw-card__header\">\n <h2 class=\"tw-card__title\">Teilnehmer ({{ members().length }})</h2>\n <ng-content select=\"[slot=header-actions]\"></ng-content>\n </div>\n\n <c2g-member-list\n [members]=\"members()\"\n (memberRemove)=\"memberRemove.emit($event)\"\n (memberInvite)=\"memberInvite.emit($event)\"\n (memberEdit)=\"memberEdit.emit($event)\">\n </c2g-member-list>\n</div>\n", styles: [".tw-card{background:var(--c2g-color-surface);border-radius:12px;border:1px solid var(--c2g-color-outline-variant);overflow:hidden}.tw-card__header{display:flex;align-items:center;justify-content:space-between;padding:1.2rem 1.4rem;border-bottom:1px solid var(--c2g-color-neutral-100)}.tw-card__title{margin:0;font-size:.96rem;font-weight:700;color:var(--c2g-color-text-primary)}\n"] }]
1386
+ }], propDecorators: { members: [{ type: i0.Input, args: [{ isSignal: true, alias: "members", required: true }] }], memberRemove: [{ type: i0.Output, args: ["memberRemove"] }], memberInvite: [{ type: i0.Output, args: ["memberInvite"] }], memberEdit: [{ type: i0.Output, args: ["memberEdit"] }] } });
1387
+
1388
+ class MenuComponent {
1389
+ items = input.required(...(ngDevMode ? [{ debugName: "items" }] : []));
1390
+ triggerLabel = input('Menü', ...(ngDevMode ? [{ debugName: "triggerLabel" }] : []));
1391
+ triggerAriaLabel = input('Menü öffnen', ...(ngDevMode ? [{ debugName: "triggerAriaLabel" }] : []));
1392
+ itemSelected = output();
1393
+ flatItems = computed(() => this.items(), ...(ngDevMode ? [{ debugName: "flatItems" }] : []));
1394
+ select(item) {
1395
+ if (item.disabled || (item.children?.length ?? 0) > 0)
1396
+ return;
1397
+ this.itemSelected.emit({ item });
1398
+ }
1399
+ selectChild(parent, child) {
1400
+ if (child.disabled)
1401
+ return;
1402
+ this.itemSelected.emit({ item: child, parent });
1403
+ }
1404
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: MenuComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1405
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: MenuComponent, isStandalone: true, selector: "c2g-menu", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: true, transformFunction: null }, triggerLabel: { classPropertyName: "triggerLabel", publicName: "triggerLabel", isSignal: true, isRequired: false, transformFunction: null }, triggerAriaLabel: { classPropertyName: "triggerAriaLabel", publicName: "triggerAriaLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { itemSelected: "itemSelected" }, ngImport: i0, template: "<div class=\"c2g-menu\">\n <button\n class=\"c2g-menu__trigger\"\n type=\"button\"\n [attr.aria-label]=\"triggerAriaLabel()\"\n [cdkMenuTriggerFor]=\"menuPanel\">\n {{ triggerLabel() }}\n </button>\n\n <ng-template #menuPanel>\n <ul class=\"c2g-menu__list\" cdkMenu>\n @for (item of flatItems(); track item.key) {\n <li\n class=\"c2g-menu__entry\"\n [class.c2g-menu__entry--has-children]=\"(item.children?.length ?? 0) > 0\">\n\n @if ((item.children?.length ?? 0) > 0) {\n <button\n class=\"c2g-menu__item\"\n cdkMenuItem\n [cdkMenuTriggerFor]=\"subMenu\"\n [disabled]=\"item.disabled ?? false\"\n type=\"button\">\n @if (item.icon) {\n <span class=\"c2g-menu__icon\" aria-hidden=\"true\">{{ item.icon }}</span>\n }\n <span>{{ item.label }}</span>\n <span class=\"c2g-menu__caret\" aria-hidden=\"true\">\u203A</span>\n </button>\n\n <ng-template #subMenu>\n <ul class=\"c2g-menu__submenu\" cdkMenu>\n @for (child of item.children ?? []; track child.key) {\n <li role=\"none\">\n <button\n class=\"c2g-menu__item\"\n [class.c2g-menu__item--danger]=\"child.variant === 'danger'\"\n [disabled]=\"child.disabled ?? false\"\n cdkMenuItem\n type=\"button\"\n (cdkMenuItemTriggered)=\"selectChild(item, child)\">\n @if (child.icon) {\n <span class=\"c2g-menu__icon\" aria-hidden=\"true\">{{ child.icon }}</span>\n }\n <span>{{ child.label }}</span>\n </button>\n </li>\n }\n </ul>\n </ng-template>\n } @else {\n <button\n class=\"c2g-menu__item\"\n [class.c2g-menu__item--danger]=\"item.variant === 'danger'\"\n [disabled]=\"item.disabled ?? false\"\n cdkMenuItem\n type=\"button\"\n (cdkMenuItemTriggered)=\"select(item)\">\n @if (item.icon) {\n <span class=\"c2g-menu__icon\" aria-hidden=\"true\">{{ item.icon }}</span>\n }\n <span>{{ item.label }}</span>\n </button>\n }\n </li>\n }\n </ul>\n </ng-template>\n</div>\n", styles: [".c2g-menu{position:relative;display:inline-flex}.c2g-menu__trigger{display:inline-flex;align-items:center;justify-content:center;min-height:2rem;padding:.35rem .75rem;border:1px solid var(--c2g-color-outline);border-radius:.5rem;background:var(--c2g-color-surface);color:var(--c2g-color-text-primary);font-size:.875rem;font-weight:600;cursor:pointer}.c2g-menu__trigger:hover{background:var(--c2g-color-neutral-100)}.c2g-menu__trigger:focus-visible{outline:2px solid var(--c2g-color-secondary);outline-offset:2px}.c2g-menu__list,.c2g-menu__submenu{margin:0;padding:.25rem;list-style:none;background:var(--c2g-color-surface);border:1px solid var(--c2g-color-outline-variant);border-radius:.625rem;box-shadow:0 8px 22px #1018281f}.c2g-menu__list{position:absolute;top:calc(100% + .35rem);left:0;min-width:13rem;z-index:100}.c2g-menu__entry{position:relative}.c2g-menu__entry--active>.c2g-menu__item,.c2g-menu__item:hover:not([disabled]){background:var(--c2g-color-secondary-container)}.c2g-menu__item{width:100%;display:flex;align-items:center;gap:.5rem;border:0;border-radius:.45rem;background:transparent;color:var(--c2g-color-text-primary);font-size:.84rem;font-weight:500;padding:.5rem .65rem;text-align:left;cursor:pointer}.c2g-menu__item:focus-visible{outline:2px solid var(--c2g-color-secondary);outline-offset:-2px}.c2g-menu__item[disabled]{opacity:.45;cursor:not-allowed}.c2g-menu__icon{font-size:.95rem;line-height:1}.c2g-menu__caret{margin-left:auto;color:var(--c2g-color-text-muted)}.c2g-menu__item--danger{color:var(--c2g-color-error)}.c2g-menu__item--danger:hover:not([disabled]){background:var(--c2g-color-primary-light)}.c2g-menu__submenu{position:absolute;top:-.25rem;left:calc(100% + .2rem);min-width:11rem;z-index:110;display:none}.c2g-menu__entry--has-children:hover>.c2g-menu__submenu,.c2g-menu__entry--has-children.c2g-menu__entry--active>.c2g-menu__submenu{display:block}\n"], dependencies: [{ kind: "directive", type: CdkMenu, selector: "[cdkMenu]", outputs: ["closed"], exportAs: ["cdkMenu"] }, { kind: "directive", type: CdkMenuItem, selector: "[cdkMenuItem]", inputs: ["cdkMenuItemDisabled", "cdkMenuitemTypeaheadLabel"], outputs: ["cdkMenuItemTriggered"], exportAs: ["cdkMenuItem"] }, { kind: "directive", type: CdkMenuTrigger, selector: "[cdkMenuTriggerFor]", inputs: ["cdkMenuTriggerFor", "cdkMenuPosition", "cdkMenuTriggerData"], outputs: ["cdkMenuOpened", "cdkMenuClosed"], exportAs: ["cdkMenuTriggerFor"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1406
+ }
1407
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: MenuComponent, decorators: [{
1408
+ type: Component,
1409
+ args: [{ selector: 'c2g-menu', standalone: true, imports: [CdkMenu, CdkMenuItem, CdkMenuTrigger], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"c2g-menu\">\n <button\n class=\"c2g-menu__trigger\"\n type=\"button\"\n [attr.aria-label]=\"triggerAriaLabel()\"\n [cdkMenuTriggerFor]=\"menuPanel\">\n {{ triggerLabel() }}\n </button>\n\n <ng-template #menuPanel>\n <ul class=\"c2g-menu__list\" cdkMenu>\n @for (item of flatItems(); track item.key) {\n <li\n class=\"c2g-menu__entry\"\n [class.c2g-menu__entry--has-children]=\"(item.children?.length ?? 0) > 0\">\n\n @if ((item.children?.length ?? 0) > 0) {\n <button\n class=\"c2g-menu__item\"\n cdkMenuItem\n [cdkMenuTriggerFor]=\"subMenu\"\n [disabled]=\"item.disabled ?? false\"\n type=\"button\">\n @if (item.icon) {\n <span class=\"c2g-menu__icon\" aria-hidden=\"true\">{{ item.icon }}</span>\n }\n <span>{{ item.label }}</span>\n <span class=\"c2g-menu__caret\" aria-hidden=\"true\">\u203A</span>\n </button>\n\n <ng-template #subMenu>\n <ul class=\"c2g-menu__submenu\" cdkMenu>\n @for (child of item.children ?? []; track child.key) {\n <li role=\"none\">\n <button\n class=\"c2g-menu__item\"\n [class.c2g-menu__item--danger]=\"child.variant === 'danger'\"\n [disabled]=\"child.disabled ?? false\"\n cdkMenuItem\n type=\"button\"\n (cdkMenuItemTriggered)=\"selectChild(item, child)\">\n @if (child.icon) {\n <span class=\"c2g-menu__icon\" aria-hidden=\"true\">{{ child.icon }}</span>\n }\n <span>{{ child.label }}</span>\n </button>\n </li>\n }\n </ul>\n </ng-template>\n } @else {\n <button\n class=\"c2g-menu__item\"\n [class.c2g-menu__item--danger]=\"item.variant === 'danger'\"\n [disabled]=\"item.disabled ?? false\"\n cdkMenuItem\n type=\"button\"\n (cdkMenuItemTriggered)=\"select(item)\">\n @if (item.icon) {\n <span class=\"c2g-menu__icon\" aria-hidden=\"true\">{{ item.icon }}</span>\n }\n <span>{{ item.label }}</span>\n </button>\n }\n </li>\n }\n </ul>\n </ng-template>\n</div>\n", styles: [".c2g-menu{position:relative;display:inline-flex}.c2g-menu__trigger{display:inline-flex;align-items:center;justify-content:center;min-height:2rem;padding:.35rem .75rem;border:1px solid var(--c2g-color-outline);border-radius:.5rem;background:var(--c2g-color-surface);color:var(--c2g-color-text-primary);font-size:.875rem;font-weight:600;cursor:pointer}.c2g-menu__trigger:hover{background:var(--c2g-color-neutral-100)}.c2g-menu__trigger:focus-visible{outline:2px solid var(--c2g-color-secondary);outline-offset:2px}.c2g-menu__list,.c2g-menu__submenu{margin:0;padding:.25rem;list-style:none;background:var(--c2g-color-surface);border:1px solid var(--c2g-color-outline-variant);border-radius:.625rem;box-shadow:0 8px 22px #1018281f}.c2g-menu__list{position:absolute;top:calc(100% + .35rem);left:0;min-width:13rem;z-index:100}.c2g-menu__entry{position:relative}.c2g-menu__entry--active>.c2g-menu__item,.c2g-menu__item:hover:not([disabled]){background:var(--c2g-color-secondary-container)}.c2g-menu__item{width:100%;display:flex;align-items:center;gap:.5rem;border:0;border-radius:.45rem;background:transparent;color:var(--c2g-color-text-primary);font-size:.84rem;font-weight:500;padding:.5rem .65rem;text-align:left;cursor:pointer}.c2g-menu__item:focus-visible{outline:2px solid var(--c2g-color-secondary);outline-offset:-2px}.c2g-menu__item[disabled]{opacity:.45;cursor:not-allowed}.c2g-menu__icon{font-size:.95rem;line-height:1}.c2g-menu__caret{margin-left:auto;color:var(--c2g-color-text-muted)}.c2g-menu__item--danger{color:var(--c2g-color-error)}.c2g-menu__item--danger:hover:not([disabled]){background:var(--c2g-color-primary-light)}.c2g-menu__submenu{position:absolute;top:-.25rem;left:calc(100% + .2rem);min-width:11rem;z-index:110;display:none}.c2g-menu__entry--has-children:hover>.c2g-menu__submenu,.c2g-menu__entry--has-children.c2g-menu__entry--active>.c2g-menu__submenu{display:block}\n"] }]
1410
+ }], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: true }] }], triggerLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "triggerLabel", required: false }] }], triggerAriaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "triggerAriaLabel", required: false }] }], itemSelected: [{ type: i0.Output, args: ["itemSelected"] }] } });
1411
+
1412
+ class SubmenuItemComponent {
1413
+ item = input.required(...(ngDevMode ? [{ debugName: "item" }] : []));
1414
+ active = input(false, ...(ngDevMode ? [{ debugName: "active" }] : []));
1415
+ selected = output();
1416
+ mouseenter = output();
1417
+ onClick() {
1418
+ if (this.item().disabled) {
1419
+ return;
1420
+ }
1421
+ this.selected.emit(this.item());
1422
+ }
1423
+ onMouseEnter() {
1424
+ this.mouseenter.emit();
1425
+ }
1426
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: SubmenuItemComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1427
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.19", type: SubmenuItemComponent, isStandalone: true, selector: "c2g-submenu-item", inputs: { item: { classPropertyName: "item", publicName: "item", isSignal: true, isRequired: true, transformFunction: null }, active: { classPropertyName: "active", publicName: "active", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selected: "selected", mouseenter: "mouseenter" }, host: { listeners: { "mouseenter": "onMouseEnter()" } }, ngImport: i0, template: "<li role=\"none\">\n <button\n class=\"c2g-submenu-item\"\n [class.c2g-submenu-item--active]=\"active() || item().active\"\n [disabled]=\"item().disabled ?? false\"\n role=\"menuitem\"\n type=\"button\"\n (click)=\"onClick()\">\n {{ item().label }}\n </button>\n</li>\n", styles: [".c2g-submenu-item{width:100%;display:block;border:0;border-radius:.5rem;padding:.45rem .65rem;background:transparent;color:var(--c2g-color-text-primary);text-align:left;font-size:.84rem;font-weight:500;cursor:pointer}.c2g-submenu-item:hover:not([disabled]),.c2g-submenu-item.c2g-submenu-item--active{background:var(--c2g-color-secondary-container)}.c2g-submenu-item:focus-visible{outline:2px solid var(--c2g-color-secondary);outline-offset:-2px}.c2g-submenu-item[disabled]{opacity:.45;cursor:not-allowed}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1428
+ }
1429
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: SubmenuItemComponent, decorators: [{
1430
+ type: Component,
1431
+ args: [{ selector: 'c2g-submenu-item', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "<li role=\"none\">\n <button\n class=\"c2g-submenu-item\"\n [class.c2g-submenu-item--active]=\"active() || item().active\"\n [disabled]=\"item().disabled ?? false\"\n role=\"menuitem\"\n type=\"button\"\n (click)=\"onClick()\">\n {{ item().label }}\n </button>\n</li>\n", styles: [".c2g-submenu-item{width:100%;display:block;border:0;border-radius:.5rem;padding:.45rem .65rem;background:transparent;color:var(--c2g-color-text-primary);text-align:left;font-size:.84rem;font-weight:500;cursor:pointer}.c2g-submenu-item:hover:not([disabled]),.c2g-submenu-item.c2g-submenu-item--active{background:var(--c2g-color-secondary-container)}.c2g-submenu-item:focus-visible{outline:2px solid var(--c2g-color-secondary);outline-offset:-2px}.c2g-submenu-item[disabled]{opacity:.45;cursor:not-allowed}\n"] }]
1432
+ }], propDecorators: { item: [{ type: i0.Input, args: [{ isSignal: true, alias: "item", required: true }] }], active: [{ type: i0.Input, args: [{ isSignal: true, alias: "active", required: false }] }], selected: [{ type: i0.Output, args: ["selected"] }], mouseenter: [{ type: i0.Output, args: ["mouseenter"] }], onMouseEnter: [{
1433
+ type: HostListener,
1434
+ args: ['mouseenter']
1435
+ }] } });
1436
+
1437
+ class SubmenuComponent {
1438
+ items = input.required(...(ngDevMode ? [{ debugName: "items" }] : []));
1439
+ open = input(false, ...(ngDevMode ? [{ debugName: "open" }] : []));
1440
+ itemSelected = output();
1441
+ activeIndex = signal(0, ...(ngDevMode ? [{ debugName: "activeIndex" }] : []));
1442
+ onItemSelected(item) {
1443
+ if (item.disabled) {
1444
+ return;
1445
+ }
1446
+ this.itemSelected.emit(item);
1447
+ }
1448
+ setActiveIndex(index) {
1449
+ this.activeIndex.set(index);
1450
+ }
1451
+ onKeydown(event) {
1452
+ const list = this.items();
1453
+ if (!list.length) {
1454
+ return;
1455
+ }
1456
+ if (event.key === 'ArrowDown') {
1457
+ event.preventDefault();
1458
+ this.activeIndex.set((this.activeIndex() + 1) % list.length);
1459
+ return;
1460
+ }
1461
+ if (event.key === 'ArrowUp') {
1462
+ event.preventDefault();
1463
+ this.activeIndex.set((this.activeIndex() - 1 + list.length) % list.length);
1464
+ return;
1465
+ }
1466
+ if (event.key === 'Enter' || event.key === ' ') {
1467
+ event.preventDefault();
1468
+ const selected = list[this.activeIndex()];
1469
+ this.onItemSelected(selected);
1470
+ }
1471
+ }
1472
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: SubmenuComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1473
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: SubmenuComponent, isStandalone: true, selector: "c2g-submenu", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: true, transformFunction: null }, open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { itemSelected: "itemSelected" }, ngImport: i0, template: "@if (open()) {\n <ul class=\"c2g-submenu\" role=\"menu\" (keydown)=\"onKeydown($event)\">\n @for (item of items(); track item.key; let index = $index) {\n <c2g-submenu-item\n [item]=\"item\"\n [active]=\"activeIndex() === index\"\n (mouseenter)=\"setActiveIndex(index)\"\n (selected)=\"onItemSelected($event)\">\n </c2g-submenu-item>\n }\n </ul>\n}\n", styles: [".c2g-submenu{position:absolute;top:calc(100% + .35rem);left:0;min-width:12rem;margin:0;padding:.25rem;list-style:none;border:1px solid var(--c2g-color-outline-variant);border-radius:.7rem;background:var(--c2g-color-surface);box-shadow:0 10px 25px #10182824;z-index:120}\n"], dependencies: [{ kind: "component", type: SubmenuItemComponent, selector: "c2g-submenu-item", inputs: ["item", "active"], outputs: ["selected", "mouseenter"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1474
+ }
1475
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: SubmenuComponent, decorators: [{
1476
+ type: Component,
1477
+ args: [{ selector: 'c2g-submenu', standalone: true, imports: [SubmenuItemComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (open()) {\n <ul class=\"c2g-submenu\" role=\"menu\" (keydown)=\"onKeydown($event)\">\n @for (item of items(); track item.key; let index = $index) {\n <c2g-submenu-item\n [item]=\"item\"\n [active]=\"activeIndex() === index\"\n (mouseenter)=\"setActiveIndex(index)\"\n (selected)=\"onItemSelected($event)\">\n </c2g-submenu-item>\n }\n </ul>\n}\n", styles: [".c2g-submenu{position:absolute;top:calc(100% + .35rem);left:0;min-width:12rem;margin:0;padding:.25rem;list-style:none;border:1px solid var(--c2g-color-outline-variant);border-radius:.7rem;background:var(--c2g-color-surface);box-shadow:0 10px 25px #10182824;z-index:120}\n"] }]
1478
+ }], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: true }] }], open: [{ type: i0.Input, args: [{ isSignal: true, alias: "open", required: false }] }], itemSelected: [{ type: i0.Output, args: ["itemSelected"] }] } });
1479
+
1480
+ class MainNavigationItemComponent {
1481
+ item = input.required(...(ngDevMode ? [{ debugName: "item" }] : []));
1482
+ itemSelected = output();
1483
+ subItemSelected = output();
1484
+ submenuOpen = signal(false, ...(ngDevMode ? [{ debugName: "submenuOpen" }] : []));
1485
+ hasSubmenu = computed(() => (this.item().subItems?.length ?? 0) > 0, ...(ngDevMode ? [{ debugName: "hasSubmenu" }] : []));
1486
+ onItemClick() {
1487
+ if (this.item().disabled) {
1488
+ return;
1489
+ }
1490
+ if (this.hasSubmenu()) {
1491
+ this.submenuOpen.update(open => !open);
1492
+ return;
1493
+ }
1494
+ this.itemSelected.emit(this.item());
1495
+ }
1496
+ onMouseEnter() {
1497
+ if (this.hasSubmenu()) {
1498
+ this.submenuOpen.set(true);
1499
+ }
1500
+ }
1501
+ onMouseLeave() {
1502
+ this.submenuOpen.set(false);
1503
+ }
1504
+ onSubItemSelected(sub) {
1505
+ this.subItemSelected.emit({ main: this.item(), sub });
1506
+ this.submenuOpen.set(false);
1507
+ }
1508
+ onItemKeydown(event) {
1509
+ if (event.key === 'Enter' || event.key === ' ') {
1510
+ event.preventDefault();
1511
+ this.onItemClick();
1512
+ return;
1513
+ }
1514
+ if (event.key === 'ArrowDown' && this.hasSubmenu()) {
1515
+ event.preventDefault();
1516
+ this.submenuOpen.set(true);
1517
+ return;
1518
+ }
1519
+ if (event.key === 'Escape') {
1520
+ event.preventDefault();
1521
+ this.submenuOpen.set(false);
1522
+ }
1523
+ }
1524
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: MainNavigationItemComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1525
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: MainNavigationItemComponent, isStandalone: true, selector: "c2g-main-navigation-item", inputs: { item: { classPropertyName: "item", publicName: "item", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { itemSelected: "itemSelected", subItemSelected: "subItemSelected" }, ngImport: i0, template: "<li class=\"c2g-main-nav-item\" (mouseenter)=\"onMouseEnter()\" (mouseleave)=\"onMouseLeave()\">\n <button\n class=\"c2g-main-nav-item__button\"\n [class.c2g-main-nav-item__button--active]=\"item().active\"\n [disabled]=\"item().disabled ?? false\"\n [attr.aria-haspopup]=\"hasSubmenu() ? 'menu' : null\"\n [attr.aria-expanded]=\"hasSubmenu() ? submenuOpen() : null\"\n type=\"button\"\n (click)=\"onItemClick()\"\n (keydown)=\"onItemKeydown($event)\">\n <span>{{ item().label }}</span>\n @if (hasSubmenu()) {\n <span class=\"c2g-main-nav-item__caret\" aria-hidden=\"true\">\u25BE</span>\n }\n </button>\n\n @if (hasSubmenu()) {\n <c2g-submenu\n [items]=\"item().subItems ?? []\"\n [open]=\"submenuOpen()\"\n (itemSelected)=\"onSubItemSelected($event)\">\n </c2g-submenu>\n }\n</li>\n", styles: [".c2g-main-nav-item{position:relative}.c2g-main-nav-item__button{display:inline-flex;align-items:center;gap:.35rem;min-height:2.2rem;padding:.4rem .8rem;border:1px solid transparent;border-radius:.6rem;background:transparent;color:var(--c2g-color-text-primary);font-size:.9rem;font-weight:600;cursor:pointer}.c2g-main-nav-item__button:hover:not([disabled]){background:var(--c2g-color-neutral-100);border-color:var(--c2g-color-outline-variant)}.c2g-main-nav-item__button:focus-visible{outline:2px solid var(--c2g-color-secondary);outline-offset:2px}.c2g-main-nav-item__button[disabled]{opacity:.5;cursor:not-allowed}.c2g-main-nav-item__button--active{background:var(--c2g-color-secondary-container);border-color:var(--c2g-color-outline);color:var(--c2g-color-secondary-dark)}.c2g-main-nav-item__caret{font-size:.7rem;color:var(--c2g-color-text-muted)}\n"], dependencies: [{ kind: "component", type: SubmenuComponent, selector: "c2g-submenu", inputs: ["items", "open"], outputs: ["itemSelected"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1526
+ }
1527
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: MainNavigationItemComponent, decorators: [{
1528
+ type: Component,
1529
+ args: [{ selector: 'c2g-main-navigation-item', standalone: true, imports: [SubmenuComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<li class=\"c2g-main-nav-item\" (mouseenter)=\"onMouseEnter()\" (mouseleave)=\"onMouseLeave()\">\n <button\n class=\"c2g-main-nav-item__button\"\n [class.c2g-main-nav-item__button--active]=\"item().active\"\n [disabled]=\"item().disabled ?? false\"\n [attr.aria-haspopup]=\"hasSubmenu() ? 'menu' : null\"\n [attr.aria-expanded]=\"hasSubmenu() ? submenuOpen() : null\"\n type=\"button\"\n (click)=\"onItemClick()\"\n (keydown)=\"onItemKeydown($event)\">\n <span>{{ item().label }}</span>\n @if (hasSubmenu()) {\n <span class=\"c2g-main-nav-item__caret\" aria-hidden=\"true\">\u25BE</span>\n }\n </button>\n\n @if (hasSubmenu()) {\n <c2g-submenu\n [items]=\"item().subItems ?? []\"\n [open]=\"submenuOpen()\"\n (itemSelected)=\"onSubItemSelected($event)\">\n </c2g-submenu>\n }\n</li>\n", styles: [".c2g-main-nav-item{position:relative}.c2g-main-nav-item__button{display:inline-flex;align-items:center;gap:.35rem;min-height:2.2rem;padding:.4rem .8rem;border:1px solid transparent;border-radius:.6rem;background:transparent;color:var(--c2g-color-text-primary);font-size:.9rem;font-weight:600;cursor:pointer}.c2g-main-nav-item__button:hover:not([disabled]){background:var(--c2g-color-neutral-100);border-color:var(--c2g-color-outline-variant)}.c2g-main-nav-item__button:focus-visible{outline:2px solid var(--c2g-color-secondary);outline-offset:2px}.c2g-main-nav-item__button[disabled]{opacity:.5;cursor:not-allowed}.c2g-main-nav-item__button--active{background:var(--c2g-color-secondary-container);border-color:var(--c2g-color-outline);color:var(--c2g-color-secondary-dark)}.c2g-main-nav-item__caret{font-size:.7rem;color:var(--c2g-color-text-muted)}\n"] }]
1530
+ }], propDecorators: { item: [{ type: i0.Input, args: [{ isSignal: true, alias: "item", required: true }] }], itemSelected: [{ type: i0.Output, args: ["itemSelected"] }], subItemSelected: [{ type: i0.Output, args: ["subItemSelected"] }] } });
1531
+
1532
+ class MainNavigationComponent {
1533
+ items = input.required(...(ngDevMode ? [{ debugName: "items" }] : []));
1534
+ ariaLabel = input('Hauptnavigation', ...(ngDevMode ? [{ debugName: "ariaLabel" }] : []));
1535
+ mainItemSelected = output();
1536
+ subItemSelected = output();
1537
+ onMainItemSelected(item) {
1538
+ this.mainItemSelected.emit(item);
1539
+ }
1540
+ onSubItemSelected(selection) {
1541
+ this.subItemSelected.emit(selection);
1542
+ }
1543
+ trackByKey = (_index, item) => item.key;
1544
+ trackSubByKey = (_index, item) => item.key;
1545
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: MainNavigationComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1546
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: MainNavigationComponent, isStandalone: true, selector: "c2g-main-navigation", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: true, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { mainItemSelected: "mainItemSelected", subItemSelected: "subItemSelected" }, ngImport: i0, template: "<nav class=\"c2g-main-navigation\" [attr.aria-label]=\"ariaLabel()\">\n <ul class=\"c2g-main-navigation__list\">\n @for (item of items(); track trackByKey($index, item)) {\n <c2g-main-navigation-item\n [item]=\"item\"\n (itemSelected)=\"onMainItemSelected($event)\"\n (subItemSelected)=\"onSubItemSelected($event)\">\n </c2g-main-navigation-item>\n }\n </ul>\n</nav>\n", styles: [".c2g-main-navigation{width:100%}.c2g-main-navigation__list{display:flex;align-items:center;gap:.5rem;list-style:none;margin:0;padding:0;flex-wrap:wrap}\n"], dependencies: [{ kind: "component", type: MainNavigationItemComponent, selector: "c2g-main-navigation-item", inputs: ["item"], outputs: ["itemSelected", "subItemSelected"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1547
+ }
1548
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: MainNavigationComponent, decorators: [{
1549
+ type: Component,
1550
+ args: [{ selector: 'c2g-main-navigation', standalone: true, imports: [MainNavigationItemComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<nav class=\"c2g-main-navigation\" [attr.aria-label]=\"ariaLabel()\">\n <ul class=\"c2g-main-navigation__list\">\n @for (item of items(); track trackByKey($index, item)) {\n <c2g-main-navigation-item\n [item]=\"item\"\n (itemSelected)=\"onMainItemSelected($event)\"\n (subItemSelected)=\"onSubItemSelected($event)\">\n </c2g-main-navigation-item>\n }\n </ul>\n</nav>\n", styles: [".c2g-main-navigation{width:100%}.c2g-main-navigation__list{display:flex;align-items:center;gap:.5rem;list-style:none;margin:0;padding:0;flex-wrap:wrap}\n"] }]
1551
+ }], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: true }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], mainItemSelected: [{ type: i0.Output, args: ["mainItemSelected"] }], subItemSelected: [{ type: i0.Output, args: ["subItemSelected"] }] } });
1552
+
1553
+ const WEATHER_ICONS = {
1554
+ sunny: '☀️', 'partly-cloudy': '⛅', cloudy: '☁️',
1555
+ rain: '🌧️', storm: '⛈️', snow: '❄️', wind: '💨', fog: '🌫️'
1556
+ };
1557
+ const TOUR_TYPE_ICONS = {
1558
+ hiking: '🥾', camping: '⛺', cycling: '🚴', climbing: '🧗',
1559
+ kayaking: '🚣', skiing: '⛷️', backpacking: '🎒', road_trip: '🚗'
1560
+ };
1561
+ class NextAdventureWidgetComponent {
1562
+ data = input.required(...(ngDevMode ? [{ debugName: "data" }] : []));
1563
+ countdown = computed(() => {
1564
+ const from = new Date(this.data().fromDate);
1565
+ from.setHours(0, 0, 0, 0);
1566
+ const today = new Date();
1567
+ today.setHours(0, 0, 0, 0);
1568
+ return Math.max(0, Math.ceil((from.getTime() - today.getTime()) / 86400000));
1569
+ }, ...(ngDevMode ? [{ debugName: "countdown" }] : []));
1570
+ duration = computed(() => {
1571
+ const from = new Date(this.data().fromDate);
1572
+ const to = new Date(this.data().toDate);
1573
+ return Math.ceil((to.getTime() - from.getTime()) / 86400000) + 1;
1574
+ }, ...(ngDevMode ? [{ debugName: "duration" }] : []));
1575
+ countdownLabel = computed(() => {
1576
+ const d = this.countdown();
1577
+ if (d === 0)
1578
+ return 'Heute gehts los!';
1579
+ if (d === 1)
1580
+ return 'Morgen gehts los!';
1581
+ return `Noch ${d} Tage`;
1582
+ }, ...(ngDevMode ? [{ debugName: "countdownLabel" }] : []));
1583
+ dateRange = computed(() => {
1584
+ const fmt = (s) => new Date(s).toLocaleDateString('de-DE', { day: '2-digit', month: 'short' });
1585
+ return `${fmt(this.data().fromDate)} – ${fmt(this.data().toDate)}`;
1586
+ }, ...(ngDevMode ? [{ debugName: "dateRange" }] : []));
1587
+ tourTypeIcon = computed(() => TOUR_TYPE_ICONS[this.data().tourType ?? ''] ?? '🏕️', ...(ngDevMode ? [{ debugName: "tourTypeIcon" }] : []));
1588
+ weatherSlots = computed(() => (this.data().weather ?? []).slice(0, 4), ...(ngDevMode ? [{ debugName: "weatherSlots" }] : []));
1589
+ urgencyClass = computed(() => {
1590
+ const d = this.countdown();
1591
+ if (d <= 1)
1592
+ return 'c2g-next-adventure--now';
1593
+ if (d <= 7)
1594
+ return 'c2g-next-adventure--soon';
1595
+ return '';
1596
+ }, ...(ngDevMode ? [{ debugName: "urgencyClass" }] : []));
1597
+ weatherIcon(icon) {
1598
+ return WEATHER_ICONS[icon] ?? '🌤️';
1599
+ }
1600
+ formatWeatherDate(date) {
1601
+ return new Date(date).toLocaleDateString('de-DE', { weekday: 'short', day: 'numeric' });
1602
+ }
1603
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: NextAdventureWidgetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1604
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: NextAdventureWidgetComponent, isStandalone: true, selector: "c2g-next-adventure-widget", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<div class=\"c2g-next-adventure\" [class]=\"urgencyClass()\">\n\n <!-- Row 1: type icon + meta + optional pulse orb -->\n <div class=\"c2g-next-adventure__header\">\n <span class=\"c2g-next-adventure__type-icon\" aria-hidden=\"true\">{{ tourTypeIcon() }}</span>\n\n <div class=\"c2g-next-adventure__meta\">\n <span class=\"c2g-next-adventure__label\">N\u00E4chstes Abenteuer</span>\n <span class=\"c2g-next-adventure__dates\">{{ dateRange() }} \u00B7 {{ duration() }} Tage</span>\n </div>\n\n @if (data().showPulse) {\n <div class=\"c2g-next-adventure__pulse-orb\" aria-hidden=\"true\">\n <span class=\"c2g-next-adventure__pulse-ring c2g-next-adventure__pulse-ring--1\"></span>\n <span class=\"c2g-next-adventure__pulse-ring c2g-next-adventure__pulse-ring--2\"></span>\n <span class=\"c2g-next-adventure__pulse-ring c2g-next-adventure__pulse-ring--3\"></span>\n <span class=\"c2g-next-adventure__pulse-core\">\uD83D\uDD34</span>\n </div>\n }\n </div>\n\n <!-- Tour name + destination -->\n <div class=\"c2g-next-adventure__body\">\n <h2 class=\"c2g-next-adventure__name\">{{ data().tourName }}</h2>\n <p class=\"c2g-next-adventure__destination\">\uD83D\uDCCD {{ data().destination }}</p>\n </div>\n\n <!-- Countdown -->\n <div class=\"c2g-next-adventure__countdown\">\n <span class=\"c2g-next-adventure__countdown-number\">{{ countdown() }}</span>\n <span class=\"c2g-next-adventure__countdown-label\">{{ countdownLabel() }}</span>\n </div>\n\n <!-- Weather strip -->\n @if (weatherSlots().length > 0) {\n <div class=\"c2g-next-adventure__weather\">\n @for (day of weatherSlots(); track day.date) {\n <div class=\"c2g-next-adventure__weather-day\">\n <span class=\"c2g-next-adventure__weather-date\">{{ formatWeatherDate(day.date) }}</span>\n <span class=\"c2g-next-adventure__weather-icon\" aria-hidden=\"true\">{{ weatherIcon(day.icon) }}</span>\n <span class=\"c2g-next-adventure__weather-temp\">\n {{ day.tempMax }}\u00B0 <span class=\"c2g-next-adventure__weather-min\">{{ day.tempMin }}\u00B0</span>\n </span>\n </div>\n }\n </div>\n }\n\n</div>\n", styles: [":host{display:block}.c2g-next-adventure{--_bg-from: var(--c2g-theme-primary, #ff6b35);--_bg-to: var(--c2g-theme-primary-dark, #c0391a);--_shadow-color: var(--c2g-theme-primary-shadow, rgba(255, 107, 53, .35));--_shadow-hover: var(--c2g-theme-primary-shadow-lg, rgba(255, 107, 53, .45));position:relative;overflow:hidden;border-radius:var(--c2g-radius-xl, 20px);padding:22px 22px 0;background:linear-gradient(135deg,var(--_bg-from) 0%,var(--_bg-to) 100%);color:var(--c2g-theme-on-primary, #fff);font-family:var(--c2g-font-family-base, \"Quicksand\", sans-serif);box-shadow:0 8px 32px var(--_shadow-color),0 1px #ffffff1a inset;min-height:260px;display:flex;flex-direction:column;gap:14px;transition:box-shadow .25s ease,transform .2s ease}.c2g-next-adventure:hover{box-shadow:0 12px 48px var(--_shadow-hover),0 1px #ffffff1f inset;transform:translateY(-2px)}.c2g-next-adventure:before{content:\"\";position:absolute;top:-50px;right:-50px;width:220px;height:220px;border-radius:50%;background:#ffffff12;pointer-events:none;animation:c2g-adv-blob 6s ease-in-out infinite}.c2g-next-adventure:after{content:\"\";position:absolute;bottom:-70px;left:30px;width:180px;height:180px;border-radius:50%;background:#ffffff0a;pointer-events:none;animation:c2g-adv-blob 8s ease-in-out infinite reverse}.c2g-next-adventure--soon{--_bg-from: var(--c2g-theme-primary-soon, #ff8c42);--_bg-to: var(--c2g-theme-primary-soon-dark, #e05a10);--_shadow-color: var(--c2g-theme-primary-soon-shadow, rgba(255, 140, 66, .4))}.c2g-next-adventure--now{--_bg-from: var(--c2g-theme-tertiary, #4ecdc4);--_bg-to: var(--c2g-theme-tertiary-dark, #2d9e96);--_shadow-color: var(--c2g-theme-tertiary-shadow, rgba(78, 205, 196, .45));animation:c2g-adv-now-pulse 2.5s ease-in-out infinite}@keyframes c2g-adv-blob{0%,to{transform:scale(1) translate(0)}50%{transform:scale(1.1) translate(-8px,8px)}}@keyframes c2g-adv-now-pulse{0%,to{box-shadow:0 8px 32px var(--_shadow-color)}50%{box-shadow:0 12px 48px var(--_shadow-hover, var(--_shadow-color))}}.c2g-next-adventure__header{display:flex;align-items:center;gap:10px;position:relative;z-index:1}.c2g-next-adventure__type-icon{font-size:2.2rem;line-height:1;filter:drop-shadow(0 2px 6px rgba(0,0,0,.25));flex-shrink:0}.c2g-next-adventure__meta{flex:1;display:flex;flex-direction:column;gap:2px}.c2g-next-adventure__label{font-size:.68rem;font-weight:700;text-transform:uppercase;letter-spacing:.1em;opacity:.75}.c2g-next-adventure__dates{font-size:.82rem;font-weight:500;opacity:.9}.c2g-next-adventure__pulse-orb{position:relative;width:36px;height:36px;flex-shrink:0;display:flex;align-items:center;justify-content:center}.c2g-next-adventure__pulse-ring{position:absolute;border-radius:50%;border:2px solid color-mix(in srgb,var(--c2g-theme-on-primary, #fff) 80%,transparent);animation:c2g-pulse-ring 2.4s ease-out infinite}.c2g-next-adventure__pulse-ring--1{width:12px;height:12px;animation-delay:0s}.c2g-next-adventure__pulse-ring--2{width:12px;height:12px;animation-delay:.6s}.c2g-next-adventure__pulse-ring--3{width:12px;height:12px;animation-delay:1.2s}.c2g-next-adventure__pulse-core{font-size:.85rem;line-height:1;position:relative;z-index:1}@keyframes c2g-pulse-ring{0%{transform:scale(1);opacity:.9}to{transform:scale(3.2);opacity:0}}.c2g-next-adventure__body{position:relative;z-index:1;flex:1}.c2g-next-adventure__name{font-size:1.55rem;font-weight:900;margin:0 0 5px;line-height:1.15;text-shadow:0 1px 4px rgba(0,0,0,.15);letter-spacing:-.01em}.c2g-next-adventure__destination{font-size:.875rem;margin:0;opacity:.88}.c2g-next-adventure__countdown{position:relative;z-index:1;display:flex;align-items:baseline;gap:8px}.c2g-next-adventure__countdown-number{font-size:3.2rem;font-weight:900;line-height:1;letter-spacing:-.03em;text-shadow:0 3px 12px rgba(0,0,0,.2)}.c2g-next-adventure--now .c2g-next-adventure__countdown-number{font-size:1.6rem}.c2g-next-adventure__countdown-label{font-size:.9rem;font-weight:600;opacity:.88}.c2g-next-adventure__weather{position:relative;z-index:1;display:flex;gap:0;background:color-mix(in srgb,var(--c2g-theme-on-primary, #fff) 13%,transparent);border-top:1px solid color-mix(in srgb,var(--c2g-theme-on-primary, #fff) 12%,transparent);-webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px);margin:0 -22px}.c2g-next-adventure__weather-day{flex:1;display:flex;flex-direction:column;align-items:center;gap:4px;padding:11px 8px;border-right:1px solid color-mix(in srgb,var(--c2g-theme-on-primary, #fff) 10%,transparent);transition:background .15s ease}.c2g-next-adventure__weather-day:last-child{border-right:none}.c2g-next-adventure__weather-day:hover{background:color-mix(in srgb,var(--c2g-theme-on-primary, #fff) 7%,transparent)}.c2g-next-adventure__weather-date{font-size:.62rem;font-weight:700;text-transform:uppercase;letter-spacing:.05em;opacity:.75}.c2g-next-adventure__weather-icon{font-size:1.3rem;line-height:1}.c2g-next-adventure__weather-temp{font-size:.8rem;font-weight:700}.c2g-next-adventure__weather-min{font-weight:400;opacity:.65}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1605
+ }
1606
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: NextAdventureWidgetComponent, decorators: [{
1607
+ type: Component,
1608
+ args: [{ selector: 'c2g-next-adventure-widget', standalone: true, imports: [], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"c2g-next-adventure\" [class]=\"urgencyClass()\">\n\n <!-- Row 1: type icon + meta + optional pulse orb -->\n <div class=\"c2g-next-adventure__header\">\n <span class=\"c2g-next-adventure__type-icon\" aria-hidden=\"true\">{{ tourTypeIcon() }}</span>\n\n <div class=\"c2g-next-adventure__meta\">\n <span class=\"c2g-next-adventure__label\">N\u00E4chstes Abenteuer</span>\n <span class=\"c2g-next-adventure__dates\">{{ dateRange() }} \u00B7 {{ duration() }} Tage</span>\n </div>\n\n @if (data().showPulse) {\n <div class=\"c2g-next-adventure__pulse-orb\" aria-hidden=\"true\">\n <span class=\"c2g-next-adventure__pulse-ring c2g-next-adventure__pulse-ring--1\"></span>\n <span class=\"c2g-next-adventure__pulse-ring c2g-next-adventure__pulse-ring--2\"></span>\n <span class=\"c2g-next-adventure__pulse-ring c2g-next-adventure__pulse-ring--3\"></span>\n <span class=\"c2g-next-adventure__pulse-core\">\uD83D\uDD34</span>\n </div>\n }\n </div>\n\n <!-- Tour name + destination -->\n <div class=\"c2g-next-adventure__body\">\n <h2 class=\"c2g-next-adventure__name\">{{ data().tourName }}</h2>\n <p class=\"c2g-next-adventure__destination\">\uD83D\uDCCD {{ data().destination }}</p>\n </div>\n\n <!-- Countdown -->\n <div class=\"c2g-next-adventure__countdown\">\n <span class=\"c2g-next-adventure__countdown-number\">{{ countdown() }}</span>\n <span class=\"c2g-next-adventure__countdown-label\">{{ countdownLabel() }}</span>\n </div>\n\n <!-- Weather strip -->\n @if (weatherSlots().length > 0) {\n <div class=\"c2g-next-adventure__weather\">\n @for (day of weatherSlots(); track day.date) {\n <div class=\"c2g-next-adventure__weather-day\">\n <span class=\"c2g-next-adventure__weather-date\">{{ formatWeatherDate(day.date) }}</span>\n <span class=\"c2g-next-adventure__weather-icon\" aria-hidden=\"true\">{{ weatherIcon(day.icon) }}</span>\n <span class=\"c2g-next-adventure__weather-temp\">\n {{ day.tempMax }}\u00B0 <span class=\"c2g-next-adventure__weather-min\">{{ day.tempMin }}\u00B0</span>\n </span>\n </div>\n }\n </div>\n }\n\n</div>\n", styles: [":host{display:block}.c2g-next-adventure{--_bg-from: var(--c2g-theme-primary, #ff6b35);--_bg-to: var(--c2g-theme-primary-dark, #c0391a);--_shadow-color: var(--c2g-theme-primary-shadow, rgba(255, 107, 53, .35));--_shadow-hover: var(--c2g-theme-primary-shadow-lg, rgba(255, 107, 53, .45));position:relative;overflow:hidden;border-radius:var(--c2g-radius-xl, 20px);padding:22px 22px 0;background:linear-gradient(135deg,var(--_bg-from) 0%,var(--_bg-to) 100%);color:var(--c2g-theme-on-primary, #fff);font-family:var(--c2g-font-family-base, \"Quicksand\", sans-serif);box-shadow:0 8px 32px var(--_shadow-color),0 1px #ffffff1a inset;min-height:260px;display:flex;flex-direction:column;gap:14px;transition:box-shadow .25s ease,transform .2s ease}.c2g-next-adventure:hover{box-shadow:0 12px 48px var(--_shadow-hover),0 1px #ffffff1f inset;transform:translateY(-2px)}.c2g-next-adventure:before{content:\"\";position:absolute;top:-50px;right:-50px;width:220px;height:220px;border-radius:50%;background:#ffffff12;pointer-events:none;animation:c2g-adv-blob 6s ease-in-out infinite}.c2g-next-adventure:after{content:\"\";position:absolute;bottom:-70px;left:30px;width:180px;height:180px;border-radius:50%;background:#ffffff0a;pointer-events:none;animation:c2g-adv-blob 8s ease-in-out infinite reverse}.c2g-next-adventure--soon{--_bg-from: var(--c2g-theme-primary-soon, #ff8c42);--_bg-to: var(--c2g-theme-primary-soon-dark, #e05a10);--_shadow-color: var(--c2g-theme-primary-soon-shadow, rgba(255, 140, 66, .4))}.c2g-next-adventure--now{--_bg-from: var(--c2g-theme-tertiary, #4ecdc4);--_bg-to: var(--c2g-theme-tertiary-dark, #2d9e96);--_shadow-color: var(--c2g-theme-tertiary-shadow, rgba(78, 205, 196, .45));animation:c2g-adv-now-pulse 2.5s ease-in-out infinite}@keyframes c2g-adv-blob{0%,to{transform:scale(1) translate(0)}50%{transform:scale(1.1) translate(-8px,8px)}}@keyframes c2g-adv-now-pulse{0%,to{box-shadow:0 8px 32px var(--_shadow-color)}50%{box-shadow:0 12px 48px var(--_shadow-hover, var(--_shadow-color))}}.c2g-next-adventure__header{display:flex;align-items:center;gap:10px;position:relative;z-index:1}.c2g-next-adventure__type-icon{font-size:2.2rem;line-height:1;filter:drop-shadow(0 2px 6px rgba(0,0,0,.25));flex-shrink:0}.c2g-next-adventure__meta{flex:1;display:flex;flex-direction:column;gap:2px}.c2g-next-adventure__label{font-size:.68rem;font-weight:700;text-transform:uppercase;letter-spacing:.1em;opacity:.75}.c2g-next-adventure__dates{font-size:.82rem;font-weight:500;opacity:.9}.c2g-next-adventure__pulse-orb{position:relative;width:36px;height:36px;flex-shrink:0;display:flex;align-items:center;justify-content:center}.c2g-next-adventure__pulse-ring{position:absolute;border-radius:50%;border:2px solid color-mix(in srgb,var(--c2g-theme-on-primary, #fff) 80%,transparent);animation:c2g-pulse-ring 2.4s ease-out infinite}.c2g-next-adventure__pulse-ring--1{width:12px;height:12px;animation-delay:0s}.c2g-next-adventure__pulse-ring--2{width:12px;height:12px;animation-delay:.6s}.c2g-next-adventure__pulse-ring--3{width:12px;height:12px;animation-delay:1.2s}.c2g-next-adventure__pulse-core{font-size:.85rem;line-height:1;position:relative;z-index:1}@keyframes c2g-pulse-ring{0%{transform:scale(1);opacity:.9}to{transform:scale(3.2);opacity:0}}.c2g-next-adventure__body{position:relative;z-index:1;flex:1}.c2g-next-adventure__name{font-size:1.55rem;font-weight:900;margin:0 0 5px;line-height:1.15;text-shadow:0 1px 4px rgba(0,0,0,.15);letter-spacing:-.01em}.c2g-next-adventure__destination{font-size:.875rem;margin:0;opacity:.88}.c2g-next-adventure__countdown{position:relative;z-index:1;display:flex;align-items:baseline;gap:8px}.c2g-next-adventure__countdown-number{font-size:3.2rem;font-weight:900;line-height:1;letter-spacing:-.03em;text-shadow:0 3px 12px rgba(0,0,0,.2)}.c2g-next-adventure--now .c2g-next-adventure__countdown-number{font-size:1.6rem}.c2g-next-adventure__countdown-label{font-size:.9rem;font-weight:600;opacity:.88}.c2g-next-adventure__weather{position:relative;z-index:1;display:flex;gap:0;background:color-mix(in srgb,var(--c2g-theme-on-primary, #fff) 13%,transparent);border-top:1px solid color-mix(in srgb,var(--c2g-theme-on-primary, #fff) 12%,transparent);-webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px);margin:0 -22px}.c2g-next-adventure__weather-day{flex:1;display:flex;flex-direction:column;align-items:center;gap:4px;padding:11px 8px;border-right:1px solid color-mix(in srgb,var(--c2g-theme-on-primary, #fff) 10%,transparent);transition:background .15s ease}.c2g-next-adventure__weather-day:last-child{border-right:none}.c2g-next-adventure__weather-day:hover{background:color-mix(in srgb,var(--c2g-theme-on-primary, #fff) 7%,transparent)}.c2g-next-adventure__weather-date{font-size:.62rem;font-weight:700;text-transform:uppercase;letter-spacing:.05em;opacity:.75}.c2g-next-adventure__weather-icon{font-size:1.3rem;line-height:1}.c2g-next-adventure__weather-temp{font-size:.8rem;font-weight:700}.c2g-next-adventure__weather-min{font-weight:400;opacity:.65}\n"] }]
1609
+ }], propDecorators: { data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: true }] }] } });
1610
+
1611
+ class PackStatusWidgetComponent {
1612
+ data = input.required(...(ngDevMode ? [{ debugName: "data" }] : []));
1613
+ percent = computed(() => {
1614
+ const d = this.data();
1615
+ if (d.totalItems === 0)
1616
+ return 0;
1617
+ return Math.round((d.completedItems / d.totalItems) * 100);
1618
+ }, ...(ngDevMode ? [{ debugName: "percent" }] : []));
1619
+ criticalOpen = computed(() => this.data().criticalTotal - this.data().criticalCompleted, ...(ngDevMode ? [{ debugName: "criticalOpen" }] : []));
1620
+ statusColor = computed(() => {
1621
+ if (this.percent() === 100)
1622
+ return 'success';
1623
+ if (this.criticalOpen() > 0)
1624
+ return 'warning';
1625
+ return 'primary';
1626
+ }, ...(ngDevMode ? [{ debugName: "statusColor" }] : []));
1627
+ statusLabel = computed(() => {
1628
+ const p = this.percent();
1629
+ if (p === 100)
1630
+ return 'Alles gepackt!';
1631
+ if (p >= 80)
1632
+ return 'Fast fertig';
1633
+ if (p >= 50)
1634
+ return 'Gut dabei';
1635
+ if (p > 0)
1636
+ return 'Packen gestartet';
1637
+ return 'Noch nicht gepackt';
1638
+ }, ...(ngDevMode ? [{ debugName: "statusLabel" }] : []));
1639
+ // SVG ring
1640
+ radius = 44;
1641
+ strokeWidth = 8;
1642
+ circumference = 2 * Math.PI * this.radius;
1643
+ strokeDashoffset = computed(() => this.circumference * (1 - this.percent() / 100), ...(ngDevMode ? [{ debugName: "strokeDashoffset" }] : []));
1644
+ // Segment tick marks (every 10%)
1645
+ ticks = Array.from({ length: 10 }, (_, i) => {
1646
+ const angle = (i / 10) * 360 - 90;
1647
+ const rad = (angle * Math.PI) / 180;
1648
+ const r1 = this.radius + this.strokeWidth / 2 + 3;
1649
+ const r2 = r1 + 4;
1650
+ const cx = 56, cy = 56;
1651
+ return {
1652
+ x1: cx + r1 * Math.cos(rad),
1653
+ y1: cy + r1 * Math.sin(rad),
1654
+ x2: cx + r2 * Math.cos(rad),
1655
+ y2: cy + r2 * Math.sin(rad),
1656
+ };
1657
+ });
1658
+ // Packed items as individual visual "dots" (up to 20 shown)
1659
+ itemDots = computed(() => {
1660
+ const total = Math.min(this.data().totalItems, 20);
1661
+ const done = Math.round((this.data().completedItems / Math.max(this.data().totalItems, 1)) * total);
1662
+ return Array.from({ length: total }, (_, i) => i < done);
1663
+ }, ...(ngDevMode ? [{ debugName: "itemDots" }] : []));
1664
+ // Count-up for percent display
1665
+ displayPercent = signal(0, ...(ngDevMode ? [{ debugName: "displayPercent" }] : []));
1666
+ raf = 0;
1667
+ constructor() {
1668
+ effect(() => {
1669
+ const target = this.percent();
1670
+ cancelAnimationFrame(this.raf);
1671
+ const start = performance.now();
1672
+ const duration = 800;
1673
+ const tick = (now) => {
1674
+ const t = Math.min((now - start) / duration, 1);
1675
+ const ease = 1 - Math.pow(1 - t, 3);
1676
+ this.displayPercent.set(Math.round(ease * target));
1677
+ if (t < 1)
1678
+ this.raf = requestAnimationFrame(tick);
1679
+ };
1680
+ this.raf = requestAnimationFrame(tick);
1681
+ });
1682
+ }
1683
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: PackStatusWidgetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1684
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: PackStatusWidgetComponent, isStandalone: true, selector: "c2g-pack-status-widget", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<div class=\"c2g-ps\" [class]=\"'c2g-ps--' + statusColor()\">\n\n <!-- Header -->\n <div class=\"c2g-ps__header\">\n <div class=\"c2g-ps__title-row\">\n <span class=\"c2g-ps__label\">\uD83C\uDF92 Packstatus</span>\n @if (data().tourName) {\n <span class=\"c2g-ps__tour\">{{ data().tourName }}</span>\n }\n </div>\n <span class=\"c2g-ps__status-badge\">{{ statusLabel() }}</span>\n </div>\n\n <!-- Main: ring + info side by side -->\n <div class=\"c2g-ps__body\">\n\n <!-- SVG Ring -->\n <div class=\"c2g-ps__ring-wrap\">\n <svg class=\"c2g-ps__ring\" viewBox=\"0 0 112 112\" aria-hidden=\"true\">\n <!-- Track -->\n <circle class=\"c2g-ps__ring-track\"\n cx=\"56\" cy=\"56\" [attr.r]=\"radius\"\n fill=\"none\" [attr.stroke-width]=\"strokeWidth\" />\n <!-- Fill -->\n <circle class=\"c2g-ps__ring-fill\"\n cx=\"56\" cy=\"56\" [attr.r]=\"radius\"\n fill=\"none\" [attr.stroke-width]=\"strokeWidth\"\n stroke-linecap=\"round\"\n [attr.stroke-dasharray]=\"circumference\"\n [attr.stroke-dashoffset]=\"strokeDashoffset()\"\n transform=\"rotate(-90 56 56)\" />\n <!-- Tick marks -->\n @for (t of ticks; track $index) {\n <line class=\"c2g-ps__tick\"\n [attr.x1]=\"t.x1\" [attr.y1]=\"t.y1\"\n [attr.x2]=\"t.x2\" [attr.y2]=\"t.y2\" />\n }\n </svg>\n <!-- Center content -->\n <div class=\"c2g-ps__ring-center\">\n <span class=\"c2g-ps__percent\">{{ displayPercent() }}<span class=\"c2g-ps__percent-unit\">%</span></span>\n @if (statusColor() === 'success') {\n <span class=\"c2g-ps__ring-emoji\">\uD83C\uDF89</span>\n }\n </div>\n </div>\n\n <!-- Info panel -->\n <div class=\"c2g-ps__info\">\n\n <!-- Item count -->\n <div class=\"c2g-ps__count-row\">\n <span class=\"c2g-ps__count-main\">{{ data().completedItems }}</span>\n <span class=\"c2g-ps__count-sep\">/</span>\n <span class=\"c2g-ps__count-total\">{{ data().totalItems }}</span>\n <span class=\"c2g-ps__count-unit\">Items</span>\n </div>\n\n <!-- Item dots grid -->\n @if (itemDots().length > 0) {\n <div class=\"c2g-ps__dots\">\n @for (done of itemDots(); track $index) {\n <span class=\"c2g-ps__dot\" [class.c2g-ps__dot--done]=\"done\"></span>\n }\n </div>\n }\n\n <!-- Critical alert / all clear -->\n @if (criticalOpen() > 0) {\n <div class=\"c2g-ps__alert\">\n <span class=\"c2g-ps__alert-icon\">\u26A0\uFE0F</span>\n <span class=\"c2g-ps__alert-text\">\n {{ criticalOpen() }} kritische{{ criticalOpen() === 1 ? 's' : '' }} fehlt{{ criticalOpen() === 1 ? '' : 'en' }}\n </span>\n </div>\n } @else if (data().criticalTotal > 0) {\n <div class=\"c2g-ps__all-clear\">\n <span>\u2713 Alle kritischen Items gepackt</span>\n </div>\n }\n\n </div>\n </div>\n\n <!-- Progress bar strip at bottom -->\n <div class=\"c2g-ps__strip-track\">\n <div class=\"c2g-ps__strip-fill\" [style.width.%]=\"percent()\"></div>\n </div>\n\n</div>\n", styles: [":host{display:block;font-family:var(--c2g-font-family-base, \"Quicksand\", sans-serif)}.c2g-ps{border-radius:var(--c2g-radius-xl, 20px);background:var(--c2g-theme-surface, var(--c2g-color-surface));border:1px solid var(--c2g-theme-outline-variant, var(--c2g-color-outline));box-shadow:var(--c2g-shadow-sm, 0 1px 4px rgba(0, 0, 0, .06));overflow:hidden;display:flex;flex-direction:column;gap:0;transition:box-shadow .2s ease,transform .2s ease}.c2g-ps:hover{box-shadow:var(--c2g-shadow-lg, 0 8px 28px rgba(0, 0, 0, .12));transform:translateY(-2px)}.c2g-ps--primary{--ps-accent: var(--c2g-theme-primary, #ff6b35);--ps-accent-soft: rgba(255, 107, 53, .12);--ps-glow: rgba(255, 107, 53, .25);--ps-badge-bg: rgba(255, 107, 53, .1);--ps-badge-color: var(--c2g-theme-primary, #ff6b35)}.c2g-ps--success{--ps-accent: var(--c2g-theme-success, #22c55e);--ps-accent-soft: rgba(34, 197, 94, .1);--ps-glow: rgba(34, 197, 94, .3);--ps-badge-bg: rgba(34, 197, 94, .1);--ps-badge-color: var(--c2g-theme-success, #22c55e)}.c2g-ps--warning{--ps-accent: var(--c2g-theme-warning, #f59e0b);--ps-accent-soft: rgba(245, 158, 11, .1);--ps-glow: rgba(245, 158, 11, .3);--ps-badge-bg: rgba(245, 158, 11, .12);--ps-badge-color: var(--c2g-theme-warning, #f59e0b)}.c2g-ps__header{display:flex;align-items:center;justify-content:space-between;padding:16px 18px 0;gap:8px}.c2g-ps__title-row{display:flex;flex-direction:column;gap:1px}.c2g-ps__label{font-size:.72rem;font-weight:700;text-transform:uppercase;letter-spacing:.08em;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted))}.c2g-ps__tour{font-size:.8rem;font-weight:600;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary));max-width:160px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.c2g-ps__status-badge{font-size:.72rem;font-weight:700;padding:3px 10px;border-radius:20px;background:var(--ps-badge-bg);color:var(--ps-badge-color);white-space:nowrap;flex-shrink:0}.c2g-ps__body{display:flex;align-items:center;gap:16px;padding:14px 18px 16px}.c2g-ps__ring-wrap{position:relative;width:108px;height:108px;flex-shrink:0}.c2g-ps__ring{width:100%;height:100%;filter:drop-shadow(0 0 8px var(--ps-glow, transparent))}.c2g-ps__ring-track{stroke:var(--c2g-theme-outline-variant, rgba(0, 0, 0, .08))}.c2g-ps__ring-fill{stroke:var(--ps-accent);transition:stroke-dashoffset .9s cubic-bezier(.4,0,.2,1)}.c2g-ps__tick{stroke:var(--c2g-theme-outline-variant, rgba(0, 0, 0, .1));stroke-width:1.5;stroke-linecap:round}.c2g-ps__ring-center{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:0}.c2g-ps__percent{font-size:1.6rem;font-weight:900;line-height:1;color:var(--ps-accent);letter-spacing:-.02em}.c2g-ps__percent-unit{font-size:.9rem;font-weight:700;opacity:.7}.c2g-ps__ring-emoji{font-size:1rem;line-height:1;margin-top:2px}.c2g-ps__info{flex:1;min-width:0;display:flex;flex-direction:column;gap:10px}.c2g-ps__count-row{display:flex;align-items:baseline;gap:3px}.c2g-ps__count-main{font-size:2rem;font-weight:900;line-height:1;color:var(--ps-accent)}.c2g-ps__count-sep{font-size:1.1rem;font-weight:400;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));margin:0 1px}.c2g-ps__count-total{font-size:1.1rem;font-weight:700;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary))}.c2g-ps__count-unit{font-size:.75rem;font-weight:500;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));margin-left:3px}.c2g-ps__dots{display:flex;flex-wrap:wrap;gap:4px}.c2g-ps__dot{width:10px;height:10px;border-radius:3px;background:var(--c2g-theme-outline-variant, rgba(0, 0, 0, .1));transition:background .3s ease,transform .2s ease}.c2g-ps__dot--done{background:var(--ps-accent);transform:scale(1.05)}.c2g-ps__dot--done:last-child{box-shadow:0 0 0 2px var(--ps-accent-soft)}.c2g-ps__alert{display:flex;align-items:center;gap:5px;font-size:.78rem;font-weight:700;color:var(--c2g-theme-warning, #f59e0b);background:#f59e0b14;border-radius:8px;padding:5px 8px}.c2g-ps__all-clear{font-size:.78rem;font-weight:700;color:var(--c2g-theme-success, #22c55e);background:#22c55e14;border-radius:8px;padding:5px 8px}.c2g-ps__strip-track{height:4px;background:var(--c2g-theme-outline-variant, rgba(0, 0, 0, .06))}.c2g-ps__strip-fill{height:100%;background:var(--ps-accent);transition:width .9s cubic-bezier(.4,0,.2,1);border-radius:0 2px 2px 0}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1685
+ }
1686
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: PackStatusWidgetComponent, decorators: [{
1687
+ type: Component,
1688
+ args: [{ selector: 'c2g-pack-status-widget', standalone: true, imports: [], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"c2g-ps\" [class]=\"'c2g-ps--' + statusColor()\">\n\n <!-- Header -->\n <div class=\"c2g-ps__header\">\n <div class=\"c2g-ps__title-row\">\n <span class=\"c2g-ps__label\">\uD83C\uDF92 Packstatus</span>\n @if (data().tourName) {\n <span class=\"c2g-ps__tour\">{{ data().tourName }}</span>\n }\n </div>\n <span class=\"c2g-ps__status-badge\">{{ statusLabel() }}</span>\n </div>\n\n <!-- Main: ring + info side by side -->\n <div class=\"c2g-ps__body\">\n\n <!-- SVG Ring -->\n <div class=\"c2g-ps__ring-wrap\">\n <svg class=\"c2g-ps__ring\" viewBox=\"0 0 112 112\" aria-hidden=\"true\">\n <!-- Track -->\n <circle class=\"c2g-ps__ring-track\"\n cx=\"56\" cy=\"56\" [attr.r]=\"radius\"\n fill=\"none\" [attr.stroke-width]=\"strokeWidth\" />\n <!-- Fill -->\n <circle class=\"c2g-ps__ring-fill\"\n cx=\"56\" cy=\"56\" [attr.r]=\"radius\"\n fill=\"none\" [attr.stroke-width]=\"strokeWidth\"\n stroke-linecap=\"round\"\n [attr.stroke-dasharray]=\"circumference\"\n [attr.stroke-dashoffset]=\"strokeDashoffset()\"\n transform=\"rotate(-90 56 56)\" />\n <!-- Tick marks -->\n @for (t of ticks; track $index) {\n <line class=\"c2g-ps__tick\"\n [attr.x1]=\"t.x1\" [attr.y1]=\"t.y1\"\n [attr.x2]=\"t.x2\" [attr.y2]=\"t.y2\" />\n }\n </svg>\n <!-- Center content -->\n <div class=\"c2g-ps__ring-center\">\n <span class=\"c2g-ps__percent\">{{ displayPercent() }}<span class=\"c2g-ps__percent-unit\">%</span></span>\n @if (statusColor() === 'success') {\n <span class=\"c2g-ps__ring-emoji\">\uD83C\uDF89</span>\n }\n </div>\n </div>\n\n <!-- Info panel -->\n <div class=\"c2g-ps__info\">\n\n <!-- Item count -->\n <div class=\"c2g-ps__count-row\">\n <span class=\"c2g-ps__count-main\">{{ data().completedItems }}</span>\n <span class=\"c2g-ps__count-sep\">/</span>\n <span class=\"c2g-ps__count-total\">{{ data().totalItems }}</span>\n <span class=\"c2g-ps__count-unit\">Items</span>\n </div>\n\n <!-- Item dots grid -->\n @if (itemDots().length > 0) {\n <div class=\"c2g-ps__dots\">\n @for (done of itemDots(); track $index) {\n <span class=\"c2g-ps__dot\" [class.c2g-ps__dot--done]=\"done\"></span>\n }\n </div>\n }\n\n <!-- Critical alert / all clear -->\n @if (criticalOpen() > 0) {\n <div class=\"c2g-ps__alert\">\n <span class=\"c2g-ps__alert-icon\">\u26A0\uFE0F</span>\n <span class=\"c2g-ps__alert-text\">\n {{ criticalOpen() }} kritische{{ criticalOpen() === 1 ? 's' : '' }} fehlt{{ criticalOpen() === 1 ? '' : 'en' }}\n </span>\n </div>\n } @else if (data().criticalTotal > 0) {\n <div class=\"c2g-ps__all-clear\">\n <span>\u2713 Alle kritischen Items gepackt</span>\n </div>\n }\n\n </div>\n </div>\n\n <!-- Progress bar strip at bottom -->\n <div class=\"c2g-ps__strip-track\">\n <div class=\"c2g-ps__strip-fill\" [style.width.%]=\"percent()\"></div>\n </div>\n\n</div>\n", styles: [":host{display:block;font-family:var(--c2g-font-family-base, \"Quicksand\", sans-serif)}.c2g-ps{border-radius:var(--c2g-radius-xl, 20px);background:var(--c2g-theme-surface, var(--c2g-color-surface));border:1px solid var(--c2g-theme-outline-variant, var(--c2g-color-outline));box-shadow:var(--c2g-shadow-sm, 0 1px 4px rgba(0, 0, 0, .06));overflow:hidden;display:flex;flex-direction:column;gap:0;transition:box-shadow .2s ease,transform .2s ease}.c2g-ps:hover{box-shadow:var(--c2g-shadow-lg, 0 8px 28px rgba(0, 0, 0, .12));transform:translateY(-2px)}.c2g-ps--primary{--ps-accent: var(--c2g-theme-primary, #ff6b35);--ps-accent-soft: rgba(255, 107, 53, .12);--ps-glow: rgba(255, 107, 53, .25);--ps-badge-bg: rgba(255, 107, 53, .1);--ps-badge-color: var(--c2g-theme-primary, #ff6b35)}.c2g-ps--success{--ps-accent: var(--c2g-theme-success, #22c55e);--ps-accent-soft: rgba(34, 197, 94, .1);--ps-glow: rgba(34, 197, 94, .3);--ps-badge-bg: rgba(34, 197, 94, .1);--ps-badge-color: var(--c2g-theme-success, #22c55e)}.c2g-ps--warning{--ps-accent: var(--c2g-theme-warning, #f59e0b);--ps-accent-soft: rgba(245, 158, 11, .1);--ps-glow: rgba(245, 158, 11, .3);--ps-badge-bg: rgba(245, 158, 11, .12);--ps-badge-color: var(--c2g-theme-warning, #f59e0b)}.c2g-ps__header{display:flex;align-items:center;justify-content:space-between;padding:16px 18px 0;gap:8px}.c2g-ps__title-row{display:flex;flex-direction:column;gap:1px}.c2g-ps__label{font-size:.72rem;font-weight:700;text-transform:uppercase;letter-spacing:.08em;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted))}.c2g-ps__tour{font-size:.8rem;font-weight:600;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary));max-width:160px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.c2g-ps__status-badge{font-size:.72rem;font-weight:700;padding:3px 10px;border-radius:20px;background:var(--ps-badge-bg);color:var(--ps-badge-color);white-space:nowrap;flex-shrink:0}.c2g-ps__body{display:flex;align-items:center;gap:16px;padding:14px 18px 16px}.c2g-ps__ring-wrap{position:relative;width:108px;height:108px;flex-shrink:0}.c2g-ps__ring{width:100%;height:100%;filter:drop-shadow(0 0 8px var(--ps-glow, transparent))}.c2g-ps__ring-track{stroke:var(--c2g-theme-outline-variant, rgba(0, 0, 0, .08))}.c2g-ps__ring-fill{stroke:var(--ps-accent);transition:stroke-dashoffset .9s cubic-bezier(.4,0,.2,1)}.c2g-ps__tick{stroke:var(--c2g-theme-outline-variant, rgba(0, 0, 0, .1));stroke-width:1.5;stroke-linecap:round}.c2g-ps__ring-center{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:0}.c2g-ps__percent{font-size:1.6rem;font-weight:900;line-height:1;color:var(--ps-accent);letter-spacing:-.02em}.c2g-ps__percent-unit{font-size:.9rem;font-weight:700;opacity:.7}.c2g-ps__ring-emoji{font-size:1rem;line-height:1;margin-top:2px}.c2g-ps__info{flex:1;min-width:0;display:flex;flex-direction:column;gap:10px}.c2g-ps__count-row{display:flex;align-items:baseline;gap:3px}.c2g-ps__count-main{font-size:2rem;font-weight:900;line-height:1;color:var(--ps-accent)}.c2g-ps__count-sep{font-size:1.1rem;font-weight:400;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));margin:0 1px}.c2g-ps__count-total{font-size:1.1rem;font-weight:700;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary))}.c2g-ps__count-unit{font-size:.75rem;font-weight:500;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));margin-left:3px}.c2g-ps__dots{display:flex;flex-wrap:wrap;gap:4px}.c2g-ps__dot{width:10px;height:10px;border-radius:3px;background:var(--c2g-theme-outline-variant, rgba(0, 0, 0, .1));transition:background .3s ease,transform .2s ease}.c2g-ps__dot--done{background:var(--ps-accent);transform:scale(1.05)}.c2g-ps__dot--done:last-child{box-shadow:0 0 0 2px var(--ps-accent-soft)}.c2g-ps__alert{display:flex;align-items:center;gap:5px;font-size:.78rem;font-weight:700;color:var(--c2g-theme-warning, #f59e0b);background:#f59e0b14;border-radius:8px;padding:5px 8px}.c2g-ps__all-clear{font-size:.78rem;font-weight:700;color:var(--c2g-theme-success, #22c55e);background:#22c55e14;border-radius:8px;padding:5px 8px}.c2g-ps__strip-track{height:4px;background:var(--c2g-theme-outline-variant, rgba(0, 0, 0, .06))}.c2g-ps__strip-fill{height:100%;background:var(--ps-accent);transition:width .9s cubic-bezier(.4,0,.2,1);border-radius:0 2px 2px 0}\n"] }]
1689
+ }], ctorParameters: () => [], propDecorators: { data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: true }] }] } });
1690
+
1691
+ const SCALE_MAX_G = 30_000;
1692
+ const ZONES = [
1693
+ { label: 'Ultraleicht', maxG: 7_000, color: '#22c55e', bgColor: 'rgba(34,197,94,0.18)' },
1694
+ { label: 'Leicht', maxG: 12_000, color: '#84cc16', bgColor: 'rgba(132,204,22,0.15)' },
1695
+ { label: 'Mittel', maxG: 18_000, color: '#f59e0b', bgColor: 'rgba(245,158,11,0.14)' },
1696
+ { label: 'Schwer', maxG: 25_000, color: '#f97316', bgColor: 'rgba(249,115,22,0.14)' },
1697
+ { label: 'Sehr schwer', maxG: 30_000, color: '#ef4444', bgColor: 'rgba(239,68,68,0.15)' },
1698
+ ];
1699
+ class PackWeightWidgetComponent {
1700
+ data = input.required(...(ngDevMode ? [{ debugName: "data" }] : []));
1701
+ zone = computed(() => ZONES.find(z => this.data().currentWeightG <= z.maxG) ?? ZONES[ZONES.length - 1], ...(ngDevMode ? [{ debugName: "zone" }] : []));
1702
+ scalePercent = computed(() => Math.min(100, (this.data().currentWeightG / SCALE_MAX_G) * 100), ...(ngDevMode ? [{ debugName: "scalePercent" }] : []));
1703
+ prevScalePercent = computed(() => {
1704
+ const prev = this.data().previousWeightG;
1705
+ if (prev == null)
1706
+ return null;
1707
+ return Math.min(100, (prev / SCALE_MAX_G) * 100);
1708
+ }, ...(ngDevMode ? [{ debugName: "prevScalePercent" }] : []));
1709
+ diffG = computed(() => {
1710
+ const prev = this.data().previousWeightG;
1711
+ if (prev == null)
1712
+ return null;
1713
+ return this.data().currentWeightG - prev;
1714
+ }, ...(ngDevMode ? [{ debugName: "diffG" }] : []));
1715
+ diffKg = computed(() => {
1716
+ const d = this.diffG();
1717
+ if (d == null)
1718
+ return null;
1719
+ return (Math.abs(d) / 1000).toFixed(1);
1720
+ }, ...(ngDevMode ? [{ debugName: "diffKg" }] : []));
1721
+ diffTrend = computed(() => {
1722
+ const d = this.diffG();
1723
+ if (d == null)
1724
+ return null;
1725
+ if (d < 0)
1726
+ return 'better';
1727
+ if (d > 0)
1728
+ return 'worse';
1729
+ return 'same';
1730
+ }, ...(ngDevMode ? [{ debugName: "diffTrend" }] : []));
1731
+ // Animated values
1732
+ animatedPercent = signal(0, ...(ngDevMode ? [{ debugName: "animatedPercent" }] : []));
1733
+ displayKg = signal('0.0', ...(ngDevMode ? [{ debugName: "displayKg" }] : []));
1734
+ rafMarker = 0;
1735
+ rafKg = 0;
1736
+ constructor() {
1737
+ effect(() => {
1738
+ const targetPct = this.scalePercent();
1739
+ const targetKg = this.data().currentWeightG / 1000;
1740
+ // Marker animation
1741
+ cancelAnimationFrame(this.rafMarker);
1742
+ const fromPct = this.animatedPercent();
1743
+ const startM = performance.now();
1744
+ const tickMarker = (now) => {
1745
+ const t = Math.min((now - startM) / 900, 1);
1746
+ const e = 1 - Math.pow(1 - t, 4);
1747
+ this.animatedPercent.set(fromPct + (targetPct - fromPct) * e);
1748
+ if (t < 1)
1749
+ this.rafMarker = requestAnimationFrame(tickMarker);
1750
+ };
1751
+ this.rafMarker = requestAnimationFrame(tickMarker);
1752
+ // Count-up kg
1753
+ cancelAnimationFrame(this.rafKg);
1754
+ const startK = performance.now();
1755
+ const tickKg = (now) => {
1756
+ const t = Math.min((now - startK) / 900, 1);
1757
+ const e = 1 - Math.pow(1 - t, 3);
1758
+ this.displayKg.set((e * targetKg).toFixed(1));
1759
+ if (t < 1)
1760
+ this.rafKg = requestAnimationFrame(tickKg);
1761
+ };
1762
+ this.rafKg = requestAnimationFrame(tickKg);
1763
+ });
1764
+ }
1765
+ // Zone segments for colour gradient bar
1766
+ zoneSegments = computed(() => {
1767
+ let prev = 0;
1768
+ return ZONES.map(z => {
1769
+ const right = (z.maxG / SCALE_MAX_G) * 100;
1770
+ const seg = { left: prev, width: right - prev, color: z.color, bgColor: z.bgColor, label: z.label };
1771
+ prev = right;
1772
+ return seg;
1773
+ });
1774
+ }, ...(ngDevMode ? [{ debugName: "zoneSegments" }] : []));
1775
+ // Tick marks: 0 5 10 15 20 25 30 kg
1776
+ ticks = Array.from({ length: 7 }, (_, i) => ({
1777
+ pct: (i * 5_000 / SCALE_MAX_G) * 100,
1778
+ label: `${i * 5}`,
1779
+ }));
1780
+ ngOnDestroy() {
1781
+ cancelAnimationFrame(this.rafMarker);
1782
+ cancelAnimationFrame(this.rafKg);
1783
+ }
1784
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: PackWeightWidgetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1785
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: PackWeightWidgetComponent, isStandalone: true, selector: "c2g-pack-weight-widget", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<div class=\"c2g-pw\">\n\n <!-- Header -->\n <div class=\"c2g-pw__header\">\n <div class=\"c2g-pw__title-col\">\n <span class=\"c2g-pw__label\">Packgewicht</span>\n @if (data().tourName) {\n <span class=\"c2g-pw__tour\">{{ data().tourName }}</span>\n }\n </div>\n <!-- Zone badge -->\n <span class=\"c2g-pw__zone-badge\"\n [style.background]=\"zone().bgColor\"\n [style.color]=\"zone().color\">\n {{ zone().label }}\n </span>\n </div>\n\n <!-- Big value -->\n <div class=\"c2g-pw__value-row\">\n <span class=\"c2g-pw__value\" [style.color]=\"zone().color\">{{ displayKg() }}</span>\n <span class=\"c2g-pw__unit\">kg</span>\n\n <!-- Diff pill -->\n @if (diffG() != null) {\n <span class=\"c2g-pw__diff-pill\"\n [class.c2g-pw__diff-pill--better]=\"diffTrend() === 'better'\"\n [class.c2g-pw__diff-pill--worse]=\"diffTrend() === 'worse'\">\n @if (diffTrend() === 'better') { \u2193 {{ diffKg() }} kg }\n @else if (diffTrend() === 'worse') { \u2191 {{ diffKg() }} kg }\n @else { \u2192 gleich }\n </span>\n }\n </div>\n\n <!-- Scale bar -->\n <div class=\"c2g-pw__scale\">\n\n <!-- Colour zone segments -->\n <div class=\"c2g-pw__zones\">\n @for (seg of zoneSegments(); track seg.label) {\n <div class=\"c2g-pw__zone-seg\"\n [style.width.%]=\"seg.width\"\n [style.background]=\"seg.bgColor\"\n [style.border-right]=\"'1px solid ' + seg.color + '22'\">\n </div>\n }\n </div>\n\n <!-- Gradient fill up to current value -->\n <div class=\"c2g-pw__fill-track\">\n <div class=\"c2g-pw__fill\"\n [style.width.%]=\"animatedPercent()\"\n [style.background]=\"'linear-gradient(90deg, #22c55e, ' + zone().color + ')'\">\n </div>\n </div>\n\n <!-- Previous marker -->\n @if (prevScalePercent() != null) {\n <div class=\"c2g-pw__marker c2g-pw__marker--prev\"\n [style.left.%]=\"prevScalePercent()\">\n <div class=\"c2g-pw__marker-line\"></div>\n <span class=\"c2g-pw__marker-label\">Letzte Tour</span>\n </div>\n }\n\n <!-- Current marker -->\n <div class=\"c2g-pw__marker c2g-pw__marker--current\"\n [style.left.%]=\"animatedPercent()\"\n [style.--marker-color]=\"zone().color\">\n <div class=\"c2g-pw__marker-pin\"></div>\n <div class=\"c2g-pw__marker-line\"></div>\n </div>\n\n <!-- Tick marks -->\n <div class=\"c2g-pw__ticks\">\n @for (tick of ticks; track tick.pct) {\n <div class=\"c2g-pw__tick\" [style.left.%]=\"tick.pct\">\n <div class=\"c2g-pw__tick-line\"></div>\n <span class=\"c2g-pw__tick-label\">{{ tick.label }}</span>\n </div>\n }\n </div>\n\n </div>\n\n <!-- Zone legend -->\n <div class=\"c2g-pw__legend\">\n @for (seg of zoneSegments(); track seg.label) {\n <div class=\"c2g-pw__legend-item\"\n [class.c2g-pw__legend-item--active]=\"seg.label === zone().label\">\n <span class=\"c2g-pw__legend-dot\" [style.background]=\"seg.color\"></span>\n <span class=\"c2g-pw__legend-label\">{{ seg.label }}</span>\n </div>\n }\n </div>\n\n</div>\n", styles: [":host{display:block;font-family:var(--c2g-font-family-base, \"Quicksand\", sans-serif)}.c2g-pw{border-radius:var(--c2g-radius-xl, 20px);background:var(--c2g-theme-surface, var(--c2g-color-surface));border:1px solid var(--c2g-theme-outline-variant, var(--c2g-color-outline));box-shadow:var(--c2g-shadow-sm, 0 1px 4px rgba(0, 0, 0, .06));padding:20px 20px 16px;display:flex;flex-direction:column;gap:12px;transition:box-shadow .2s ease,transform .2s ease}.c2g-pw:hover{box-shadow:var(--c2g-shadow-lg, 0 8px 28px rgba(0, 0, 0, .11));transform:translateY(-2px)}.c2g-pw__header{display:flex;align-items:flex-start;justify-content:space-between;gap:10px}.c2g-pw__title-col{display:flex;flex-direction:column;gap:2px}.c2g-pw__label{font-size:.72rem;font-weight:700;text-transform:uppercase;letter-spacing:.09em;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted))}.c2g-pw__tour{font-size:.82rem;font-weight:600;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary));max-width:180px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.c2g-pw__zone-badge{font-size:.72rem;font-weight:800;padding:3px 10px;border-radius:20px;white-space:nowrap;flex-shrink:0}.c2g-pw__value-row{display:flex;align-items:baseline;gap:5px}.c2g-pw__value{font-size:3.2rem;font-weight:900;line-height:1;letter-spacing:-.03em;transition:color .4s ease}.c2g-pw__unit{font-size:1.3rem;font-weight:600;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));margin-bottom:3px}.c2g-pw__diff-pill{margin-left:8px;font-size:.78rem;font-weight:700;padding:3px 9px;border-radius:20px;background:var(--c2g-theme-surface-container, rgba(0, 0, 0, .05));color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));align-self:center;white-space:nowrap}.c2g-pw__diff-pill--better{background:#22c55e1f;color:#22c55e}.c2g-pw__diff-pill--worse{background:#f973161f;color:#f97316}.c2g-pw__scale{position:relative;height:52px;margin:4px 0 8px}.c2g-pw__zones{position:absolute;top:0;left:0;right:0;height:12px;border-radius:6px;overflow:hidden;display:flex}.c2g-pw__zone-seg{height:100%}.c2g-pw__fill-track{position:absolute;top:0;left:0;right:0;height:12px;border-radius:6px;overflow:hidden}.c2g-pw__fill{height:100%;border-radius:6px;transition:width .9s cubic-bezier(.4,0,.2,1);opacity:.85}.c2g-pw__marker{position:absolute;top:0;transform:translate(-50%);display:flex;flex-direction:column;align-items:center;pointer-events:none}.c2g-pw__marker--current{transition:left .9s cubic-bezier(.4,0,.2,1);z-index:2}.c2g-pw__marker--prev{z-index:1;opacity:.5}.c2g-pw__marker-pin{width:14px;height:14px;border-radius:50%;border:2.5px solid #fff;background:var(--marker-color, #ff6b35);box-shadow:0 0 0 2px var(--marker-color, #ff6b35),0 2px 8px #0003;margin-top:-1px;position:relative;z-index:1}.c2g-pw__marker-line{width:1.5px;height:10px;background:currentColor;opacity:.4;margin-top:1px}.c2g-pw__marker-label{font-size:.58rem;font-weight:700;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));white-space:nowrap;margin-top:1px;text-transform:uppercase;letter-spacing:.04em}.c2g-pw__ticks{position:absolute;top:14px;left:0;right:0}.c2g-pw__tick{position:absolute;transform:translate(-50%);display:flex;flex-direction:column;align-items:center;gap:1px}.c2g-pw__tick:first-child{transform:translate(0)}.c2g-pw__tick:last-child{transform:translate(-100%)}.c2g-pw__tick-line{width:1px;height:5px;background:var(--c2g-theme-outline-variant, rgba(0, 0, 0, .15))}.c2g-pw__tick-label{font-size:.6rem;font-weight:600;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));white-space:nowrap}.c2g-pw__legend{display:flex;flex-wrap:wrap;gap:6px 10px;padding-top:2px}.c2g-pw__legend-item{display:flex;align-items:center;gap:4px;opacity:.45;transition:opacity .2s ease}.c2g-pw__legend-item--active{opacity:1}.c2g-pw__legend-dot{width:7px;height:7px;border-radius:50%;flex-shrink:0}.c2g-pw__legend-label{font-size:.7rem;font-weight:700;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary))}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1786
+ }
1787
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: PackWeightWidgetComponent, decorators: [{
1788
+ type: Component,
1789
+ args: [{ selector: 'c2g-pack-weight-widget', standalone: true, imports: [], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"c2g-pw\">\n\n <!-- Header -->\n <div class=\"c2g-pw__header\">\n <div class=\"c2g-pw__title-col\">\n <span class=\"c2g-pw__label\">Packgewicht</span>\n @if (data().tourName) {\n <span class=\"c2g-pw__tour\">{{ data().tourName }}</span>\n }\n </div>\n <!-- Zone badge -->\n <span class=\"c2g-pw__zone-badge\"\n [style.background]=\"zone().bgColor\"\n [style.color]=\"zone().color\">\n {{ zone().label }}\n </span>\n </div>\n\n <!-- Big value -->\n <div class=\"c2g-pw__value-row\">\n <span class=\"c2g-pw__value\" [style.color]=\"zone().color\">{{ displayKg() }}</span>\n <span class=\"c2g-pw__unit\">kg</span>\n\n <!-- Diff pill -->\n @if (diffG() != null) {\n <span class=\"c2g-pw__diff-pill\"\n [class.c2g-pw__diff-pill--better]=\"diffTrend() === 'better'\"\n [class.c2g-pw__diff-pill--worse]=\"diffTrend() === 'worse'\">\n @if (diffTrend() === 'better') { \u2193 {{ diffKg() }} kg }\n @else if (diffTrend() === 'worse') { \u2191 {{ diffKg() }} kg }\n @else { \u2192 gleich }\n </span>\n }\n </div>\n\n <!-- Scale bar -->\n <div class=\"c2g-pw__scale\">\n\n <!-- Colour zone segments -->\n <div class=\"c2g-pw__zones\">\n @for (seg of zoneSegments(); track seg.label) {\n <div class=\"c2g-pw__zone-seg\"\n [style.width.%]=\"seg.width\"\n [style.background]=\"seg.bgColor\"\n [style.border-right]=\"'1px solid ' + seg.color + '22'\">\n </div>\n }\n </div>\n\n <!-- Gradient fill up to current value -->\n <div class=\"c2g-pw__fill-track\">\n <div class=\"c2g-pw__fill\"\n [style.width.%]=\"animatedPercent()\"\n [style.background]=\"'linear-gradient(90deg, #22c55e, ' + zone().color + ')'\">\n </div>\n </div>\n\n <!-- Previous marker -->\n @if (prevScalePercent() != null) {\n <div class=\"c2g-pw__marker c2g-pw__marker--prev\"\n [style.left.%]=\"prevScalePercent()\">\n <div class=\"c2g-pw__marker-line\"></div>\n <span class=\"c2g-pw__marker-label\">Letzte Tour</span>\n </div>\n }\n\n <!-- Current marker -->\n <div class=\"c2g-pw__marker c2g-pw__marker--current\"\n [style.left.%]=\"animatedPercent()\"\n [style.--marker-color]=\"zone().color\">\n <div class=\"c2g-pw__marker-pin\"></div>\n <div class=\"c2g-pw__marker-line\"></div>\n </div>\n\n <!-- Tick marks -->\n <div class=\"c2g-pw__ticks\">\n @for (tick of ticks; track tick.pct) {\n <div class=\"c2g-pw__tick\" [style.left.%]=\"tick.pct\">\n <div class=\"c2g-pw__tick-line\"></div>\n <span class=\"c2g-pw__tick-label\">{{ tick.label }}</span>\n </div>\n }\n </div>\n\n </div>\n\n <!-- Zone legend -->\n <div class=\"c2g-pw__legend\">\n @for (seg of zoneSegments(); track seg.label) {\n <div class=\"c2g-pw__legend-item\"\n [class.c2g-pw__legend-item--active]=\"seg.label === zone().label\">\n <span class=\"c2g-pw__legend-dot\" [style.background]=\"seg.color\"></span>\n <span class=\"c2g-pw__legend-label\">{{ seg.label }}</span>\n </div>\n }\n </div>\n\n</div>\n", styles: [":host{display:block;font-family:var(--c2g-font-family-base, \"Quicksand\", sans-serif)}.c2g-pw{border-radius:var(--c2g-radius-xl, 20px);background:var(--c2g-theme-surface, var(--c2g-color-surface));border:1px solid var(--c2g-theme-outline-variant, var(--c2g-color-outline));box-shadow:var(--c2g-shadow-sm, 0 1px 4px rgba(0, 0, 0, .06));padding:20px 20px 16px;display:flex;flex-direction:column;gap:12px;transition:box-shadow .2s ease,transform .2s ease}.c2g-pw:hover{box-shadow:var(--c2g-shadow-lg, 0 8px 28px rgba(0, 0, 0, .11));transform:translateY(-2px)}.c2g-pw__header{display:flex;align-items:flex-start;justify-content:space-between;gap:10px}.c2g-pw__title-col{display:flex;flex-direction:column;gap:2px}.c2g-pw__label{font-size:.72rem;font-weight:700;text-transform:uppercase;letter-spacing:.09em;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted))}.c2g-pw__tour{font-size:.82rem;font-weight:600;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary));max-width:180px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.c2g-pw__zone-badge{font-size:.72rem;font-weight:800;padding:3px 10px;border-radius:20px;white-space:nowrap;flex-shrink:0}.c2g-pw__value-row{display:flex;align-items:baseline;gap:5px}.c2g-pw__value{font-size:3.2rem;font-weight:900;line-height:1;letter-spacing:-.03em;transition:color .4s ease}.c2g-pw__unit{font-size:1.3rem;font-weight:600;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));margin-bottom:3px}.c2g-pw__diff-pill{margin-left:8px;font-size:.78rem;font-weight:700;padding:3px 9px;border-radius:20px;background:var(--c2g-theme-surface-container, rgba(0, 0, 0, .05));color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));align-self:center;white-space:nowrap}.c2g-pw__diff-pill--better{background:#22c55e1f;color:#22c55e}.c2g-pw__diff-pill--worse{background:#f973161f;color:#f97316}.c2g-pw__scale{position:relative;height:52px;margin:4px 0 8px}.c2g-pw__zones{position:absolute;top:0;left:0;right:0;height:12px;border-radius:6px;overflow:hidden;display:flex}.c2g-pw__zone-seg{height:100%}.c2g-pw__fill-track{position:absolute;top:0;left:0;right:0;height:12px;border-radius:6px;overflow:hidden}.c2g-pw__fill{height:100%;border-radius:6px;transition:width .9s cubic-bezier(.4,0,.2,1);opacity:.85}.c2g-pw__marker{position:absolute;top:0;transform:translate(-50%);display:flex;flex-direction:column;align-items:center;pointer-events:none}.c2g-pw__marker--current{transition:left .9s cubic-bezier(.4,0,.2,1);z-index:2}.c2g-pw__marker--prev{z-index:1;opacity:.5}.c2g-pw__marker-pin{width:14px;height:14px;border-radius:50%;border:2.5px solid #fff;background:var(--marker-color, #ff6b35);box-shadow:0 0 0 2px var(--marker-color, #ff6b35),0 2px 8px #0003;margin-top:-1px;position:relative;z-index:1}.c2g-pw__marker-line{width:1.5px;height:10px;background:currentColor;opacity:.4;margin-top:1px}.c2g-pw__marker-label{font-size:.58rem;font-weight:700;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));white-space:nowrap;margin-top:1px;text-transform:uppercase;letter-spacing:.04em}.c2g-pw__ticks{position:absolute;top:14px;left:0;right:0}.c2g-pw__tick{position:absolute;transform:translate(-50%);display:flex;flex-direction:column;align-items:center;gap:1px}.c2g-pw__tick:first-child{transform:translate(0)}.c2g-pw__tick:last-child{transform:translate(-100%)}.c2g-pw__tick-line{width:1px;height:5px;background:var(--c2g-theme-outline-variant, rgba(0, 0, 0, .15))}.c2g-pw__tick-label{font-size:.6rem;font-weight:600;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));white-space:nowrap}.c2g-pw__legend{display:flex;flex-wrap:wrap;gap:6px 10px;padding-top:2px}.c2g-pw__legend-item{display:flex;align-items:center;gap:4px;opacity:.45;transition:opacity .2s ease}.c2g-pw__legend-item--active{opacity:1}.c2g-pw__legend-dot{width:7px;height:7px;border-radius:50%;flex-shrink:0}.c2g-pw__legend-label{font-size:.7rem;font-weight:700;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary))}\n"] }]
1790
+ }], ctorParameters: () => [], propDecorators: { data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: true }] }] } });
1791
+
1792
+ class MemberReadinessWidgetComponent {
1793
+ members = input.required(...(ngDevMode ? [{ debugName: "members" }] : []));
1794
+ tourName = input(undefined, ...(ngDevMode ? [{ debugName: "tourName" }] : []));
1795
+ overallPercent = computed(() => {
1796
+ const m = this.members();
1797
+ if (!m.length)
1798
+ return 0;
1799
+ const total = m.reduce((s, e) => s + e.totalItems, 0);
1800
+ if (total === 0)
1801
+ return 0;
1802
+ return Math.round((m.reduce((s, e) => s + e.completedItems, 0) / total) * 100);
1803
+ }, ...(ngDevMode ? [{ debugName: "overallPercent" }] : []));
1804
+ fullyReady = computed(() => this.members().filter(m => this.readyPercent(m) === 100).length, ...(ngDevMode ? [{ debugName: "fullyReady" }] : []));
1805
+ // Groups only shown when >= 6 members, otherwise flat list
1806
+ useGrouped = computed(() => this.members().length >= 6, ...(ngDevMode ? [{ debugName: "useGrouped" }] : []));
1807
+ groups = computed(() => {
1808
+ const buckets = [
1809
+ { label: 'Bereit', emoji: '✅', color: 'success', min: 100, max: 100, members: [] },
1810
+ { label: 'Fast fertig', emoji: '🔜', color: 'warning', min: 75, max: 99, members: [] },
1811
+ { label: 'Unterwegs', emoji: '📦', color: 'warning', min: 40, max: 74, members: [] },
1812
+ { label: 'Kaum gepackt', emoji: '😴', color: 'danger', min: 1, max: 39, members: [] },
1813
+ { label: 'Nicht gestartet', emoji: '❌', color: 'neutral', min: 0, max: 0, members: [] },
1814
+ ];
1815
+ for (const m of this.members()) {
1816
+ const p = this.readyPercent(m);
1817
+ const bucket = buckets.find(b => p >= b.min && p <= b.max) ?? buckets[buckets.length - 1];
1818
+ bucket.members.push(m);
1819
+ }
1820
+ return buckets.filter(b => b.members.length > 0);
1821
+ }, ...(ngDevMode ? [{ debugName: "groups" }] : []));
1822
+ flatSorted = computed(() => [...this.members()].sort((a, b) => this.readyPercent(b) - this.readyPercent(a)), ...(ngDevMode ? [{ debugName: "flatSorted" }] : []));
1823
+ readyPercent(entry) {
1824
+ if (entry.totalItems === 0)
1825
+ return 100;
1826
+ return Math.round((entry.completedItems / entry.totalItems) * 100);
1827
+ }
1828
+ readyColor(entry) {
1829
+ const p = this.readyPercent(entry);
1830
+ if (p === 100)
1831
+ return 'success';
1832
+ if (p >= 75)
1833
+ return 'warning';
1834
+ if (p >= 40)
1835
+ return 'warning';
1836
+ if (p > 0)
1837
+ return 'danger';
1838
+ return 'neutral';
1839
+ }
1840
+ // Collapse state per group index
1841
+ collapsed = new Map();
1842
+ toggleGroup(index) {
1843
+ this.collapsed.set(index, !this.collapsed.get(index));
1844
+ }
1845
+ isCollapsed(index) {
1846
+ // Collapse groups with only-ready members by default if many groups
1847
+ return this.collapsed.get(index) ?? false;
1848
+ }
1849
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: MemberReadinessWidgetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1850
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: MemberReadinessWidgetComponent, isStandalone: true, selector: "c2g-member-readiness-widget", inputs: { members: { classPropertyName: "members", publicName: "members", isSignal: true, isRequired: true, transformFunction: null }, tourName: { classPropertyName: "tourName", publicName: "tourName", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div class=\"c2g-mr\">\n\n <!-- Header -->\n <div class=\"c2g-mr__header\">\n <div class=\"c2g-mr__title-col\">\n <span class=\"c2g-mr__label\">\uD83D\uDC65 Gruppenbereitschaft</span>\n @if (tourName()) {\n <span class=\"c2g-mr__tour\">{{ tourName() }}</span>\n }\n </div>\n <div class=\"c2g-mr__summary-pill\">\n <span class=\"c2g-mr__summary-ready\">{{ fullyReady() }}</span>\n <span class=\"c2g-mr__summary-sep\">/</span>\n <span class=\"c2g-mr__summary-total\">{{ members().length }}</span>\n <span class=\"c2g-mr__summary-unit\">bereit</span>\n </div>\n </div>\n\n <!-- Overall progress bar -->\n <div class=\"c2g-mr__overall-track\" [attr.aria-valuenow]=\"overallPercent()\" aria-valuemin=\"0\" aria-valuemax=\"100\">\n <div class=\"c2g-mr__overall-fill\"\n [style.width.%]=\"overallPercent()\"\n [class.c2g-mr__overall-fill--success]=\"overallPercent() === 100\">\n </div>\n <span class=\"c2g-mr__overall-pct\">{{ overallPercent() }}%</span>\n </div>\n\n <!-- GROUPED layout (6+ members) -->\n @if (useGrouped()) {\n <div class=\"c2g-mr__groups\">\n @for (group of groups(); track group.label; let gi = $index) {\n <div class=\"c2g-mr__group\" [class]=\"'c2g-mr__group--' + group.color\">\n\n <!-- Group header (clickable to toggle) -->\n <button class=\"c2g-mr__group-header\" (click)=\"toggleGroup(gi)\" type=\"button\">\n <span class=\"c2g-mr__group-emoji\">{{ group.emoji }}</span>\n <span class=\"c2g-mr__group-name\">{{ group.label }}</span>\n <span class=\"c2g-mr__group-count\">{{ group.members.length }}</span>\n <!-- Avatar stack preview (max 4) -->\n <div class=\"c2g-mr__avatar-stack\">\n @for (m of group.members.slice(0, 4); track m.name) {\n <span class=\"c2g-mr__avatar-tiny\" [class]=\"'c2g-mr__avatar-tiny--' + group.color\"\n [title]=\"m.name\">{{ m.initials }}</span>\n }\n @if (group.members.length > 4) {\n <span class=\"c2g-mr__avatar-tiny c2g-mr__avatar-tiny--more\">+{{ group.members.length - 4 }}</span>\n }\n </div>\n <span class=\"c2g-mr__group-chevron\" [class.c2g-mr__group-chevron--open]=\"!isCollapsed(gi)\">\u203A</span>\n </button>\n\n <!-- Member rows (collapsible) -->\n @if (!isCollapsed(gi)) {\n <ul class=\"c2g-mr__member-list\">\n @for (m of group.members; track m.name) {\n <li class=\"c2g-mr__member\" [class.c2g-mr__member--self]=\"m.isSelf\">\n <span class=\"c2g-mr__avatar-sm\" [class]=\"'c2g-mr__avatar-sm--' + group.color\">\n {{ m.initials }}\n </span>\n <span class=\"c2g-mr__member-name\">\n {{ m.name }}\n @if (m.isSelf) { <span class=\"c2g-mr__self-tag\">Du</span> }\n </span>\n <div class=\"c2g-mr__mini-track\">\n <div class=\"c2g-mr__mini-fill\"\n [class]=\"'c2g-mr__mini-fill--' + group.color\"\n [style.width.%]=\"readyPercent(m)\">\n </div>\n </div>\n <span class=\"c2g-mr__member-pct\" [class]=\"'c2g-mr__member-pct--' + group.color\">\n {{ readyPercent(m) }}%\n </span>\n </li>\n }\n </ul>\n }\n </div>\n }\n </div>\n\n } @else {\n <!-- FLAT layout (< 6 members) -->\n <ul class=\"c2g-mr__flat-list\">\n @for (m of flatSorted(); track m.name) {\n <li class=\"c2g-mr__member\" [class.c2g-mr__member--self]=\"m.isSelf\">\n <span class=\"c2g-mr__avatar-sm\" [class]=\"'c2g-mr__avatar-sm--' + readyColor(m)\">\n {{ m.initials }}\n </span>\n <span class=\"c2g-mr__member-name\">\n {{ m.name }}\n @if (m.isSelf) { <span class=\"c2g-mr__self-tag\">Du</span> }\n </span>\n <div class=\"c2g-mr__mini-track\">\n <div class=\"c2g-mr__mini-fill\"\n [class]=\"'c2g-mr__mini-fill--' + readyColor(m)\"\n [style.width.%]=\"readyPercent(m)\">\n </div>\n </div>\n <span class=\"c2g-mr__member-pct\" [class]=\"'c2g-mr__member-pct--' + readyColor(m)\">\n {{ readyPercent(m) }}%\n </span>\n </li>\n }\n </ul>\n }\n\n</div>\n", styles: [":host{display:block;font-family:var(--c2g-font-family-base, \"Quicksand\", sans-serif)}.c2g-mr{border-radius:var(--c2g-radius-xl, 20px);background:var(--c2g-theme-surface, var(--c2g-color-surface));border:1px solid var(--c2g-theme-outline-variant, var(--c2g-color-outline));box-shadow:var(--c2g-shadow-sm, 0 1px 4px rgba(0, 0, 0, .06));overflow:hidden;transition:box-shadow .2s ease,transform .2s ease}.c2g-mr:hover{box-shadow:var(--c2g-shadow-lg, 0 8px 28px rgba(0, 0, 0, .12));transform:translateY(-2px)}.c2g-mr__header{display:flex;align-items:center;justify-content:space-between;padding:16px 18px 10px;gap:10px}.c2g-mr__title-col{display:flex;flex-direction:column;gap:2px;min-width:0}.c2g-mr__label{font-size:.72rem;font-weight:700;text-transform:uppercase;letter-spacing:.08em;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted))}.c2g-mr__tour{font-size:.85rem;font-weight:600;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary));overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.c2g-mr__summary-pill{display:flex;align-items:baseline;gap:3px;background:var(--c2g-theme-surface-container, rgba(0, 0, 0, .04));border-radius:20px;padding:4px 12px;flex-shrink:0}.c2g-mr__summary-ready{font-size:1.1rem;font-weight:900;color:var(--c2g-theme-primary, #ff6b35);line-height:1}.c2g-mr__summary-sep{font-size:.8rem;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted))}.c2g-mr__summary-total{font-size:.9rem;font-weight:700;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary))}.c2g-mr__summary-unit{font-size:.7rem;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));margin-left:2px}.c2g-mr__overall-track{position:relative;margin:0 18px 12px;height:7px;border-radius:4px;background:var(--c2g-theme-outline-variant, rgba(0, 0, 0, .08));overflow:visible}.c2g-mr__overall-fill{height:100%;border-radius:4px;background:var(--c2g-theme-primary, #ff6b35);transition:width .7s cubic-bezier(.4,0,.2,1)}.c2g-mr__overall-fill--success{background:var(--c2g-theme-success, #22c55e)}.c2g-mr__overall-pct{position:absolute;right:0;top:-18px;font-size:.7rem;font-weight:700;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted))}.c2g-mr__groups{display:flex;flex-direction:column;gap:2px;padding:0 10px 12px}.c2g-mr__group{border-radius:12px;overflow:hidden;transition:background .15s ease;background:var(--mr-group-bg)}.c2g-mr__group--success{--mr-accent: #22c55e;--mr-accent-bg: rgba(34, 197, 94, .12);--mr-group-bg: rgba(34, 197, 94, .08)}.c2g-mr__group--warning{--mr-accent: #f59e0b;--mr-accent-bg: rgba(245, 158, 11, .15);--mr-group-bg: rgba(245, 158, 11, .06)}.c2g-mr__group--danger{--mr-accent: #ef4444;--mr-accent-bg: rgba(239, 68, 68, .15);--mr-group-bg: rgba(239, 68, 68, .06)}.c2g-mr__group--neutral{--mr-accent: #9ca3af;--mr-accent-bg: rgba(156, 163, 175, .15);--mr-group-bg: rgba(156, 163, 175, .05)}.c2g-mr__group-header{width:100%;display:flex;align-items:center;gap:6px;padding:8px 10px;background:transparent;border:none;cursor:pointer;text-align:left;border-radius:12px;transition:background .15s ease}.c2g-mr__group-header:hover{background:var(--mr-accent-bg)}.c2g-mr__group-emoji{font-size:1rem;line-height:1;flex-shrink:0}.c2g-mr__group-name{font-size:.8rem;font-weight:700;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary));flex:1}.c2g-mr__group-count{font-size:.72rem;font-weight:800;min-width:18px;height:18px;border-radius:9px;background:var(--mr-accent-bg);color:var(--mr-accent);display:flex;align-items:center;justify-content:center;padding:0 5px}.c2g-mr__avatar-stack{display:flex;margin-left:4px}.c2g-mr__avatar-tiny{width:22px;height:22px;border-radius:50%;font-size:.55rem;font-weight:800;display:flex;align-items:center;justify-content:center;margin-left:-6px;border:2px solid var(--c2g-theme-surface, #fff);background:var(--mr-accent-bg);color:var(--mr-accent)}.c2g-mr__avatar-tiny:first-child{margin-left:0}.c2g-mr__avatar-tiny--more{background:var(--c2g-theme-outline-variant, rgba(0, 0, 0, .1));color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));font-size:.5rem}.c2g-mr__group-chevron{font-size:1.1rem;font-weight:700;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));transform:rotate(90deg);transition:transform .2s ease;line-height:1;margin-left:2px}.c2g-mr__group-chevron--open{transform:rotate(-90deg)}.c2g-mr__member-list,.c2g-mr__flat-list{list-style:none;margin:0;padding:0 10px 4px;display:flex;flex-direction:column;gap:2px}.c2g-mr__flat-list{padding:0 10px 14px}.c2g-mr__member{display:flex;align-items:center;gap:8px;padding:5px 6px;border-radius:8px;transition:background .15s ease}.c2g-mr__member:hover{background:var(--c2g-theme-surface-container, rgba(0, 0, 0, .03))}.c2g-mr__member--self{background:#ff6b350f}.c2g-mr__member--self:hover{background:#ff6b351a}.c2g-mr__avatar-sm{width:28px;height:28px;border-radius:50%;font-size:.65rem;font-weight:800;display:flex;align-items:center;justify-content:center;flex-shrink:0}.c2g-mr__avatar-sm--success{background:#22c55e1f;color:#22c55e}.c2g-mr__avatar-sm--warning{background:#f59e0b26;color:#f59e0b}.c2g-mr__avatar-sm--danger{background:#ef444426;color:#ef4444}.c2g-mr__avatar-sm--neutral{background:#9ca3af26;color:#9ca3af}.c2g-mr__member-name{font-size:.8rem;font-weight:600;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary));flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:flex;align-items:center;gap:4px}.c2g-mr__self-tag{font-size:.6rem;font-weight:800;text-transform:uppercase;padding:1px 5px;border-radius:4px;background:var(--c2g-theme-primary, #ff6b35);color:#fff;flex-shrink:0}.c2g-mr__mini-track{width:52px;height:4px;border-radius:2px;background:var(--c2g-theme-outline-variant, rgba(0, 0, 0, .08));overflow:hidden;flex-shrink:0}.c2g-mr__mini-fill{height:100%;border-radius:2px;transition:width .6s cubic-bezier(.4,0,.2,1)}.c2g-mr__mini-fill--success{background:#22c55e}.c2g-mr__mini-fill--warning{background:#f59e0b}.c2g-mr__mini-fill--danger{background:#ef4444}.c2g-mr__mini-fill--neutral{background:#9ca3af}.c2g-mr__member-pct{font-size:.72rem;font-weight:700;min-width:32px;text-align:right;flex-shrink:0}.c2g-mr__member-pct--success{color:#22c55e}.c2g-mr__member-pct--warning{color:#f59e0b}.c2g-mr__member-pct--danger{color:#ef4444}.c2g-mr__member-pct--neutral{color:#9ca3af}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1851
+ }
1852
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: MemberReadinessWidgetComponent, decorators: [{
1853
+ type: Component,
1854
+ args: [{ selector: 'c2g-member-readiness-widget', standalone: true, imports: [], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"c2g-mr\">\n\n <!-- Header -->\n <div class=\"c2g-mr__header\">\n <div class=\"c2g-mr__title-col\">\n <span class=\"c2g-mr__label\">\uD83D\uDC65 Gruppenbereitschaft</span>\n @if (tourName()) {\n <span class=\"c2g-mr__tour\">{{ tourName() }}</span>\n }\n </div>\n <div class=\"c2g-mr__summary-pill\">\n <span class=\"c2g-mr__summary-ready\">{{ fullyReady() }}</span>\n <span class=\"c2g-mr__summary-sep\">/</span>\n <span class=\"c2g-mr__summary-total\">{{ members().length }}</span>\n <span class=\"c2g-mr__summary-unit\">bereit</span>\n </div>\n </div>\n\n <!-- Overall progress bar -->\n <div class=\"c2g-mr__overall-track\" [attr.aria-valuenow]=\"overallPercent()\" aria-valuemin=\"0\" aria-valuemax=\"100\">\n <div class=\"c2g-mr__overall-fill\"\n [style.width.%]=\"overallPercent()\"\n [class.c2g-mr__overall-fill--success]=\"overallPercent() === 100\">\n </div>\n <span class=\"c2g-mr__overall-pct\">{{ overallPercent() }}%</span>\n </div>\n\n <!-- GROUPED layout (6+ members) -->\n @if (useGrouped()) {\n <div class=\"c2g-mr__groups\">\n @for (group of groups(); track group.label; let gi = $index) {\n <div class=\"c2g-mr__group\" [class]=\"'c2g-mr__group--' + group.color\">\n\n <!-- Group header (clickable to toggle) -->\n <button class=\"c2g-mr__group-header\" (click)=\"toggleGroup(gi)\" type=\"button\">\n <span class=\"c2g-mr__group-emoji\">{{ group.emoji }}</span>\n <span class=\"c2g-mr__group-name\">{{ group.label }}</span>\n <span class=\"c2g-mr__group-count\">{{ group.members.length }}</span>\n <!-- Avatar stack preview (max 4) -->\n <div class=\"c2g-mr__avatar-stack\">\n @for (m of group.members.slice(0, 4); track m.name) {\n <span class=\"c2g-mr__avatar-tiny\" [class]=\"'c2g-mr__avatar-tiny--' + group.color\"\n [title]=\"m.name\">{{ m.initials }}</span>\n }\n @if (group.members.length > 4) {\n <span class=\"c2g-mr__avatar-tiny c2g-mr__avatar-tiny--more\">+{{ group.members.length - 4 }}</span>\n }\n </div>\n <span class=\"c2g-mr__group-chevron\" [class.c2g-mr__group-chevron--open]=\"!isCollapsed(gi)\">\u203A</span>\n </button>\n\n <!-- Member rows (collapsible) -->\n @if (!isCollapsed(gi)) {\n <ul class=\"c2g-mr__member-list\">\n @for (m of group.members; track m.name) {\n <li class=\"c2g-mr__member\" [class.c2g-mr__member--self]=\"m.isSelf\">\n <span class=\"c2g-mr__avatar-sm\" [class]=\"'c2g-mr__avatar-sm--' + group.color\">\n {{ m.initials }}\n </span>\n <span class=\"c2g-mr__member-name\">\n {{ m.name }}\n @if (m.isSelf) { <span class=\"c2g-mr__self-tag\">Du</span> }\n </span>\n <div class=\"c2g-mr__mini-track\">\n <div class=\"c2g-mr__mini-fill\"\n [class]=\"'c2g-mr__mini-fill--' + group.color\"\n [style.width.%]=\"readyPercent(m)\">\n </div>\n </div>\n <span class=\"c2g-mr__member-pct\" [class]=\"'c2g-mr__member-pct--' + group.color\">\n {{ readyPercent(m) }}%\n </span>\n </li>\n }\n </ul>\n }\n </div>\n }\n </div>\n\n } @else {\n <!-- FLAT layout (< 6 members) -->\n <ul class=\"c2g-mr__flat-list\">\n @for (m of flatSorted(); track m.name) {\n <li class=\"c2g-mr__member\" [class.c2g-mr__member--self]=\"m.isSelf\">\n <span class=\"c2g-mr__avatar-sm\" [class]=\"'c2g-mr__avatar-sm--' + readyColor(m)\">\n {{ m.initials }}\n </span>\n <span class=\"c2g-mr__member-name\">\n {{ m.name }}\n @if (m.isSelf) { <span class=\"c2g-mr__self-tag\">Du</span> }\n </span>\n <div class=\"c2g-mr__mini-track\">\n <div class=\"c2g-mr__mini-fill\"\n [class]=\"'c2g-mr__mini-fill--' + readyColor(m)\"\n [style.width.%]=\"readyPercent(m)\">\n </div>\n </div>\n <span class=\"c2g-mr__member-pct\" [class]=\"'c2g-mr__member-pct--' + readyColor(m)\">\n {{ readyPercent(m) }}%\n </span>\n </li>\n }\n </ul>\n }\n\n</div>\n", styles: [":host{display:block;font-family:var(--c2g-font-family-base, \"Quicksand\", sans-serif)}.c2g-mr{border-radius:var(--c2g-radius-xl, 20px);background:var(--c2g-theme-surface, var(--c2g-color-surface));border:1px solid var(--c2g-theme-outline-variant, var(--c2g-color-outline));box-shadow:var(--c2g-shadow-sm, 0 1px 4px rgba(0, 0, 0, .06));overflow:hidden;transition:box-shadow .2s ease,transform .2s ease}.c2g-mr:hover{box-shadow:var(--c2g-shadow-lg, 0 8px 28px rgba(0, 0, 0, .12));transform:translateY(-2px)}.c2g-mr__header{display:flex;align-items:center;justify-content:space-between;padding:16px 18px 10px;gap:10px}.c2g-mr__title-col{display:flex;flex-direction:column;gap:2px;min-width:0}.c2g-mr__label{font-size:.72rem;font-weight:700;text-transform:uppercase;letter-spacing:.08em;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted))}.c2g-mr__tour{font-size:.85rem;font-weight:600;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary));overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.c2g-mr__summary-pill{display:flex;align-items:baseline;gap:3px;background:var(--c2g-theme-surface-container, rgba(0, 0, 0, .04));border-radius:20px;padding:4px 12px;flex-shrink:0}.c2g-mr__summary-ready{font-size:1.1rem;font-weight:900;color:var(--c2g-theme-primary, #ff6b35);line-height:1}.c2g-mr__summary-sep{font-size:.8rem;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted))}.c2g-mr__summary-total{font-size:.9rem;font-weight:700;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary))}.c2g-mr__summary-unit{font-size:.7rem;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));margin-left:2px}.c2g-mr__overall-track{position:relative;margin:0 18px 12px;height:7px;border-radius:4px;background:var(--c2g-theme-outline-variant, rgba(0, 0, 0, .08));overflow:visible}.c2g-mr__overall-fill{height:100%;border-radius:4px;background:var(--c2g-theme-primary, #ff6b35);transition:width .7s cubic-bezier(.4,0,.2,1)}.c2g-mr__overall-fill--success{background:var(--c2g-theme-success, #22c55e)}.c2g-mr__overall-pct{position:absolute;right:0;top:-18px;font-size:.7rem;font-weight:700;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted))}.c2g-mr__groups{display:flex;flex-direction:column;gap:2px;padding:0 10px 12px}.c2g-mr__group{border-radius:12px;overflow:hidden;transition:background .15s ease;background:var(--mr-group-bg)}.c2g-mr__group--success{--mr-accent: #22c55e;--mr-accent-bg: rgba(34, 197, 94, .12);--mr-group-bg: rgba(34, 197, 94, .08)}.c2g-mr__group--warning{--mr-accent: #f59e0b;--mr-accent-bg: rgba(245, 158, 11, .15);--mr-group-bg: rgba(245, 158, 11, .06)}.c2g-mr__group--danger{--mr-accent: #ef4444;--mr-accent-bg: rgba(239, 68, 68, .15);--mr-group-bg: rgba(239, 68, 68, .06)}.c2g-mr__group--neutral{--mr-accent: #9ca3af;--mr-accent-bg: rgba(156, 163, 175, .15);--mr-group-bg: rgba(156, 163, 175, .05)}.c2g-mr__group-header{width:100%;display:flex;align-items:center;gap:6px;padding:8px 10px;background:transparent;border:none;cursor:pointer;text-align:left;border-radius:12px;transition:background .15s ease}.c2g-mr__group-header:hover{background:var(--mr-accent-bg)}.c2g-mr__group-emoji{font-size:1rem;line-height:1;flex-shrink:0}.c2g-mr__group-name{font-size:.8rem;font-weight:700;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary));flex:1}.c2g-mr__group-count{font-size:.72rem;font-weight:800;min-width:18px;height:18px;border-radius:9px;background:var(--mr-accent-bg);color:var(--mr-accent);display:flex;align-items:center;justify-content:center;padding:0 5px}.c2g-mr__avatar-stack{display:flex;margin-left:4px}.c2g-mr__avatar-tiny{width:22px;height:22px;border-radius:50%;font-size:.55rem;font-weight:800;display:flex;align-items:center;justify-content:center;margin-left:-6px;border:2px solid var(--c2g-theme-surface, #fff);background:var(--mr-accent-bg);color:var(--mr-accent)}.c2g-mr__avatar-tiny:first-child{margin-left:0}.c2g-mr__avatar-tiny--more{background:var(--c2g-theme-outline-variant, rgba(0, 0, 0, .1));color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));font-size:.5rem}.c2g-mr__group-chevron{font-size:1.1rem;font-weight:700;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));transform:rotate(90deg);transition:transform .2s ease;line-height:1;margin-left:2px}.c2g-mr__group-chevron--open{transform:rotate(-90deg)}.c2g-mr__member-list,.c2g-mr__flat-list{list-style:none;margin:0;padding:0 10px 4px;display:flex;flex-direction:column;gap:2px}.c2g-mr__flat-list{padding:0 10px 14px}.c2g-mr__member{display:flex;align-items:center;gap:8px;padding:5px 6px;border-radius:8px;transition:background .15s ease}.c2g-mr__member:hover{background:var(--c2g-theme-surface-container, rgba(0, 0, 0, .03))}.c2g-mr__member--self{background:#ff6b350f}.c2g-mr__member--self:hover{background:#ff6b351a}.c2g-mr__avatar-sm{width:28px;height:28px;border-radius:50%;font-size:.65rem;font-weight:800;display:flex;align-items:center;justify-content:center;flex-shrink:0}.c2g-mr__avatar-sm--success{background:#22c55e1f;color:#22c55e}.c2g-mr__avatar-sm--warning{background:#f59e0b26;color:#f59e0b}.c2g-mr__avatar-sm--danger{background:#ef444426;color:#ef4444}.c2g-mr__avatar-sm--neutral{background:#9ca3af26;color:#9ca3af}.c2g-mr__member-name{font-size:.8rem;font-weight:600;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary));flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:flex;align-items:center;gap:4px}.c2g-mr__self-tag{font-size:.6rem;font-weight:800;text-transform:uppercase;padding:1px 5px;border-radius:4px;background:var(--c2g-theme-primary, #ff6b35);color:#fff;flex-shrink:0}.c2g-mr__mini-track{width:52px;height:4px;border-radius:2px;background:var(--c2g-theme-outline-variant, rgba(0, 0, 0, .08));overflow:hidden;flex-shrink:0}.c2g-mr__mini-fill{height:100%;border-radius:2px;transition:width .6s cubic-bezier(.4,0,.2,1)}.c2g-mr__mini-fill--success{background:#22c55e}.c2g-mr__mini-fill--warning{background:#f59e0b}.c2g-mr__mini-fill--danger{background:#ef4444}.c2g-mr__mini-fill--neutral{background:#9ca3af}.c2g-mr__member-pct{font-size:.72rem;font-weight:700;min-width:32px;text-align:right;flex-shrink:0}.c2g-mr__member-pct--success{color:#22c55e}.c2g-mr__member-pct--warning{color:#f59e0b}.c2g-mr__member-pct--danger{color:#ef4444}.c2g-mr__member-pct--neutral{color:#9ca3af}\n"] }]
1855
+ }], propDecorators: { members: [{ type: i0.Input, args: [{ isSignal: true, alias: "members", required: true }] }], tourName: [{ type: i0.Input, args: [{ isSignal: true, alias: "tourName", required: false }] }] } });
1856
+
1857
+ class StreakWidgetComponent {
1858
+ data = input.required(...(ngDevMode ? [{ debugName: "data" }] : []));
1859
+ xpPercent = computed(() => {
1860
+ const d = this.data();
1861
+ if (d.nextLevelXp === 0)
1862
+ return 100;
1863
+ return Math.min(100, Math.round((d.experiencePoints / d.nextLevelXp) * 100));
1864
+ }, ...(ngDevMode ? [{ debugName: "xpPercent" }] : []));
1865
+ streakTier = computed(() => {
1866
+ const s = this.data().streakDays;
1867
+ if (s >= 365)
1868
+ return 'legendary';
1869
+ if (s >= 30)
1870
+ return 'hot';
1871
+ if (s >= 7)
1872
+ return 'warm';
1873
+ return 'cold';
1874
+ }, ...(ngDevMode ? [{ debugName: "streakTier" }] : []));
1875
+ streakEmoji = computed(() => {
1876
+ switch (this.streakTier()) {
1877
+ case 'legendary': return '🏆';
1878
+ case 'hot': return '🔥';
1879
+ case 'warm': return '⚡';
1880
+ default: return '🌱';
1881
+ }
1882
+ }, ...(ngDevMode ? [{ debugName: "streakEmoji" }] : []));
1883
+ levelLabel = computed(() => {
1884
+ const lvl = this.data().level;
1885
+ if (lvl >= 50)
1886
+ return 'Legende';
1887
+ if (lvl >= 30)
1888
+ return 'Experte';
1889
+ if (lvl >= 15)
1890
+ return 'Erfahren';
1891
+ if (lvl >= 5)
1892
+ return 'Fortgeschritten';
1893
+ return 'Einsteiger';
1894
+ }, ...(ngDevMode ? [{ debugName: "levelLabel" }] : []));
1895
+ streakLabel = computed(() => {
1896
+ const s = this.data().streakDays;
1897
+ if (s === 0)
1898
+ return 'Noch kein Streak';
1899
+ if (s === 1)
1900
+ return '1 Tag Streak';
1901
+ return `${s} Tage Streak`;
1902
+ }, ...(ngDevMode ? [{ debugName: "streakLabel" }] : []));
1903
+ xpToNext = computed(() => Math.max(0, this.data().nextLevelXp - this.data().experiencePoints), ...(ngDevMode ? [{ debugName: "xpToNext" }] : []));
1904
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: StreakWidgetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1905
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: StreakWidgetComponent, isStandalone: true, selector: "c2g-streak-widget", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<div class=\"c2g-streak\" [class]=\"'c2g-streak--' + streakTier()\">\n\n <div class=\"c2g-streak__header\">\n <span class=\"c2g-streak__title\">Abenteurer-Level</span>\n <span class=\"c2g-streak__level-badge\">Lvl {{ data().level }}</span>\n </div>\n\n <div class=\"c2g-streak__hero\">\n <span class=\"c2g-streak__emoji\">{{ streakEmoji() }}</span>\n <div class=\"c2g-streak__streak-info\">\n <span class=\"c2g-streak__streak-count\">{{ data().streakDays }}</span>\n <span class=\"c2g-streak__streak-unit\">{{ data().streakDays === 1 ? 'Tag' : 'Tage' }}</span>\n </div>\n </div>\n\n <div class=\"c2g-streak__level-row\">\n <span class=\"c2g-streak__level-label\">{{ levelLabel() }}</span>\n <span class=\"c2g-streak__xp-label\">{{ data().experiencePoints }} / {{ data().nextLevelXp }} XP</span>\n </div>\n\n <div class=\"c2g-streak__xp-track\">\n <div class=\"c2g-streak__xp-fill\" [style.width.%]=\"xpPercent()\"></div>\n </div>\n\n <div class=\"c2g-streak__stats\">\n @if (data().totalDistanceKm != null) {\n <div class=\"c2g-streak__stat\">\n <span class=\"c2g-streak__stat-value\">{{ data().totalDistanceKm }}</span>\n <span class=\"c2g-streak__stat-label\">km</span>\n </div>\n }\n @if (data().totalNightsCamped != null) {\n <div class=\"c2g-streak__stat\">\n <span class=\"c2g-streak__stat-value\">{{ data().totalNightsCamped }}</span>\n <span class=\"c2g-streak__stat-label\">N\u00E4chte</span>\n </div>\n }\n @if (data().favoriteSeason) {\n <div class=\"c2g-streak__stat\">\n <span class=\"c2g-streak__stat-value\">\n @switch (data().favoriteSeason) {\n @case ('spring') { \uD83C\uDF38 }\n @case ('summer') { \u2600\uFE0F }\n @case ('autumn') { \uD83C\uDF42 }\n @case ('winter') { \u2744\uFE0F }\n @default { \uD83C\uDFD5\uFE0F }\n }\n </span>\n <span class=\"c2g-streak__stat-label\">Lieblingszeit</span>\n </div>\n }\n </div>\n\n @if (xpToNext() > 0) {\n <div class=\"c2g-streak__next-level\">\n Noch {{ xpToNext() }} XP bis Level {{ data().level + 1 }}\n </div>\n } @else {\n <div class=\"c2g-streak__next-level c2g-streak__next-level--ready\">\n Level Up bereit! \uD83C\uDF89\n </div>\n }\n\n</div>\n", styles: [":host{display:block;transition:background-color var(--c2g-transition-medium, .25s ease),color var(--c2g-transition-medium, .25s ease)}.c2g-streak{border-radius:var(--c2g-radius-lg, 16px);padding:20px;background:var(--c2g-theme-surface, var(--c2g-color-surface));border:1px solid var(--c2g-theme-outline-variant, var(--c2g-color-outline));box-shadow:var(--c2g-shadow-sm, 0 1px 4px rgba(0, 0, 0, .06));font-family:var(--c2g-font-family-base, \"Quicksand\", sans-serif);transition:box-shadow .2s ease;position:relative;overflow:hidden}.c2g-streak:hover{box-shadow:var(--c2g-shadow-md, 0 4px 12px rgba(0, 0, 0, .1))}.c2g-streak:before{content:\"\";position:absolute;top:0;left:0;right:0;height:3px;background:var(--c2g-theme-outline-variant, var(--c2g-color-outline));transition:background .3s ease}.c2g-streak--warm:before{background:#f59e0b}.c2g-streak--hot:before{background:linear-gradient(90deg,#f97316,#ef4444)}.c2g-streak--legendary:before{background:linear-gradient(90deg,#a855f7,#ec4899,#f59e0b)}.c2g-streak__header{display:flex;align-items:center;justify-content:space-between;margin-bottom:12px}.c2g-streak__title{font-size:var(--c2g-font-size-sm, .875rem);font-weight:700;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary))}.c2g-streak__level-badge{font-size:.7rem;font-weight:800;padding:2px 8px;border-radius:20px;background:var(--c2g-theme-primary, var(--c2g-color-primary));color:#fff;letter-spacing:.02em}.c2g-streak--hot .c2g-streak__level-badge{background:#f97316}.c2g-streak--legendary .c2g-streak__level-badge{background:linear-gradient(135deg,#a855f7,#ec4899)}.c2g-streak__hero{display:flex;align-items:center;gap:12px;margin-bottom:12px}.c2g-streak__emoji{font-size:2.5rem;line-height:1;filter:drop-shadow(0 2px 6px rgba(0,0,0,.15))}.c2g-streak__streak-info{display:flex;align-items:baseline;gap:4px}.c2g-streak__streak-count{font-size:3rem;font-weight:900;line-height:1;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary));transition:color .3s ease}.c2g-streak--warm .c2g-streak__streak-count{color:#f59e0b}.c2g-streak--hot .c2g-streak__streak-count{color:#f97316}.c2g-streak--legendary .c2g-streak__streak-count{color:#a855f7}.c2g-streak__streak-unit{font-size:1rem;font-weight:600;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));margin-bottom:4px}.c2g-streak__level-row{display:flex;align-items:center;justify-content:space-between;margin-bottom:6px}.c2g-streak__level-label{font-size:.8rem;font-weight:700;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary))}.c2g-streak__xp-label{font-size:.72rem;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted))}.c2g-streak__xp-track{height:8px;border-radius:4px;background:var(--c2g-theme-outline-variant, var(--c2g-color-outline));overflow:hidden;margin-bottom:16px}.c2g-streak__xp-fill{height:100%;border-radius:4px;background:var(--c2g-theme-primary, var(--c2g-color-primary));transition:width .7s cubic-bezier(.4,0,.2,1)}.c2g-streak--warm .c2g-streak__xp-fill{background:#f59e0b}.c2g-streak--hot .c2g-streak__xp-fill{background:linear-gradient(90deg,#f97316,#ef4444)}.c2g-streak--legendary .c2g-streak__xp-fill{background:linear-gradient(90deg,#a855f7,#ec4899)}.c2g-streak__stats{display:flex;gap:0;border-radius:var(--c2g-radius-md, 10px);background:var(--c2g-theme-surface-container, rgba(0, 0, 0, .04));overflow:hidden;margin-bottom:12px}.c2g-streak__stat{flex:1;display:flex;flex-direction:column;align-items:center;gap:2px;padding:10px 8px;border-right:1px solid var(--c2g-theme-outline-variant, var(--c2g-color-outline))}.c2g-streak__stat:last-child{border-right:none}.c2g-streak__stat-value{font-size:1.1rem;font-weight:800;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary));line-height:1}.c2g-streak__stat-label{font-size:.65rem;font-weight:600;text-transform:uppercase;letter-spacing:.04em;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted))}.c2g-streak__next-level{font-size:.75rem;font-weight:600;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));text-align:center}.c2g-streak__next-level--ready{color:var(--c2g-theme-success, var(--c2g-color-success));font-weight:700}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1906
+ }
1907
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: StreakWidgetComponent, decorators: [{
1908
+ type: Component,
1909
+ args: [{ selector: 'c2g-streak-widget', standalone: true, imports: [], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"c2g-streak\" [class]=\"'c2g-streak--' + streakTier()\">\n\n <div class=\"c2g-streak__header\">\n <span class=\"c2g-streak__title\">Abenteurer-Level</span>\n <span class=\"c2g-streak__level-badge\">Lvl {{ data().level }}</span>\n </div>\n\n <div class=\"c2g-streak__hero\">\n <span class=\"c2g-streak__emoji\">{{ streakEmoji() }}</span>\n <div class=\"c2g-streak__streak-info\">\n <span class=\"c2g-streak__streak-count\">{{ data().streakDays }}</span>\n <span class=\"c2g-streak__streak-unit\">{{ data().streakDays === 1 ? 'Tag' : 'Tage' }}</span>\n </div>\n </div>\n\n <div class=\"c2g-streak__level-row\">\n <span class=\"c2g-streak__level-label\">{{ levelLabel() }}</span>\n <span class=\"c2g-streak__xp-label\">{{ data().experiencePoints }} / {{ data().nextLevelXp }} XP</span>\n </div>\n\n <div class=\"c2g-streak__xp-track\">\n <div class=\"c2g-streak__xp-fill\" [style.width.%]=\"xpPercent()\"></div>\n </div>\n\n <div class=\"c2g-streak__stats\">\n @if (data().totalDistanceKm != null) {\n <div class=\"c2g-streak__stat\">\n <span class=\"c2g-streak__stat-value\">{{ data().totalDistanceKm }}</span>\n <span class=\"c2g-streak__stat-label\">km</span>\n </div>\n }\n @if (data().totalNightsCamped != null) {\n <div class=\"c2g-streak__stat\">\n <span class=\"c2g-streak__stat-value\">{{ data().totalNightsCamped }}</span>\n <span class=\"c2g-streak__stat-label\">N\u00E4chte</span>\n </div>\n }\n @if (data().favoriteSeason) {\n <div class=\"c2g-streak__stat\">\n <span class=\"c2g-streak__stat-value\">\n @switch (data().favoriteSeason) {\n @case ('spring') { \uD83C\uDF38 }\n @case ('summer') { \u2600\uFE0F }\n @case ('autumn') { \uD83C\uDF42 }\n @case ('winter') { \u2744\uFE0F }\n @default { \uD83C\uDFD5\uFE0F }\n }\n </span>\n <span class=\"c2g-streak__stat-label\">Lieblingszeit</span>\n </div>\n }\n </div>\n\n @if (xpToNext() > 0) {\n <div class=\"c2g-streak__next-level\">\n Noch {{ xpToNext() }} XP bis Level {{ data().level + 1 }}\n </div>\n } @else {\n <div class=\"c2g-streak__next-level c2g-streak__next-level--ready\">\n Level Up bereit! \uD83C\uDF89\n </div>\n }\n\n</div>\n", styles: [":host{display:block;transition:background-color var(--c2g-transition-medium, .25s ease),color var(--c2g-transition-medium, .25s ease)}.c2g-streak{border-radius:var(--c2g-radius-lg, 16px);padding:20px;background:var(--c2g-theme-surface, var(--c2g-color-surface));border:1px solid var(--c2g-theme-outline-variant, var(--c2g-color-outline));box-shadow:var(--c2g-shadow-sm, 0 1px 4px rgba(0, 0, 0, .06));font-family:var(--c2g-font-family-base, \"Quicksand\", sans-serif);transition:box-shadow .2s ease;position:relative;overflow:hidden}.c2g-streak:hover{box-shadow:var(--c2g-shadow-md, 0 4px 12px rgba(0, 0, 0, .1))}.c2g-streak:before{content:\"\";position:absolute;top:0;left:0;right:0;height:3px;background:var(--c2g-theme-outline-variant, var(--c2g-color-outline));transition:background .3s ease}.c2g-streak--warm:before{background:#f59e0b}.c2g-streak--hot:before{background:linear-gradient(90deg,#f97316,#ef4444)}.c2g-streak--legendary:before{background:linear-gradient(90deg,#a855f7,#ec4899,#f59e0b)}.c2g-streak__header{display:flex;align-items:center;justify-content:space-between;margin-bottom:12px}.c2g-streak__title{font-size:var(--c2g-font-size-sm, .875rem);font-weight:700;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary))}.c2g-streak__level-badge{font-size:.7rem;font-weight:800;padding:2px 8px;border-radius:20px;background:var(--c2g-theme-primary, var(--c2g-color-primary));color:#fff;letter-spacing:.02em}.c2g-streak--hot .c2g-streak__level-badge{background:#f97316}.c2g-streak--legendary .c2g-streak__level-badge{background:linear-gradient(135deg,#a855f7,#ec4899)}.c2g-streak__hero{display:flex;align-items:center;gap:12px;margin-bottom:12px}.c2g-streak__emoji{font-size:2.5rem;line-height:1;filter:drop-shadow(0 2px 6px rgba(0,0,0,.15))}.c2g-streak__streak-info{display:flex;align-items:baseline;gap:4px}.c2g-streak__streak-count{font-size:3rem;font-weight:900;line-height:1;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary));transition:color .3s ease}.c2g-streak--warm .c2g-streak__streak-count{color:#f59e0b}.c2g-streak--hot .c2g-streak__streak-count{color:#f97316}.c2g-streak--legendary .c2g-streak__streak-count{color:#a855f7}.c2g-streak__streak-unit{font-size:1rem;font-weight:600;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));margin-bottom:4px}.c2g-streak__level-row{display:flex;align-items:center;justify-content:space-between;margin-bottom:6px}.c2g-streak__level-label{font-size:.8rem;font-weight:700;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary))}.c2g-streak__xp-label{font-size:.72rem;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted))}.c2g-streak__xp-track{height:8px;border-radius:4px;background:var(--c2g-theme-outline-variant, var(--c2g-color-outline));overflow:hidden;margin-bottom:16px}.c2g-streak__xp-fill{height:100%;border-radius:4px;background:var(--c2g-theme-primary, var(--c2g-color-primary));transition:width .7s cubic-bezier(.4,0,.2,1)}.c2g-streak--warm .c2g-streak__xp-fill{background:#f59e0b}.c2g-streak--hot .c2g-streak__xp-fill{background:linear-gradient(90deg,#f97316,#ef4444)}.c2g-streak--legendary .c2g-streak__xp-fill{background:linear-gradient(90deg,#a855f7,#ec4899)}.c2g-streak__stats{display:flex;gap:0;border-radius:var(--c2g-radius-md, 10px);background:var(--c2g-theme-surface-container, rgba(0, 0, 0, .04));overflow:hidden;margin-bottom:12px}.c2g-streak__stat{flex:1;display:flex;flex-direction:column;align-items:center;gap:2px;padding:10px 8px;border-right:1px solid var(--c2g-theme-outline-variant, var(--c2g-color-outline))}.c2g-streak__stat:last-child{border-right:none}.c2g-streak__stat-value{font-size:1.1rem;font-weight:800;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary));line-height:1}.c2g-streak__stat-label{font-size:.65rem;font-weight:600;text-transform:uppercase;letter-spacing:.04em;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted))}.c2g-streak__next-level{font-size:.75rem;font-weight:600;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));text-align:center}.c2g-streak__next-level--ready{color:var(--c2g-theme-success, var(--c2g-color-success));font-weight:700}\n"] }]
1910
+ }], propDecorators: { data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: true }] }] } });
1911
+
1912
+ class CampingScoreWidgetComponent {
1913
+ data = input.required(...(ngDevMode ? [{ debugName: "data" }] : []));
1914
+ tier = computed(() => {
1915
+ const s = this.data().score;
1916
+ if (s >= 8)
1917
+ return 'great';
1918
+ if (s >= 6)
1919
+ return 'good';
1920
+ if (s >= 4)
1921
+ return 'ok';
1922
+ return 'bad';
1923
+ }, ...(ngDevMode ? [{ debugName: "tier" }] : []));
1924
+ tierLabel = computed(() => {
1925
+ if (this.data().label)
1926
+ return this.data().label;
1927
+ switch (this.tier()) {
1928
+ case 'great': return 'Perfektes Camping-Wetter';
1929
+ case 'good': return 'Gute Bedingungen';
1930
+ case 'ok': return 'Akzeptables Wetter';
1931
+ default: return 'Schwierige Bedingungen';
1932
+ }
1933
+ }, ...(ngDevMode ? [{ debugName: "tierLabel" }] : []));
1934
+ tierEmoji = computed(() => {
1935
+ switch (this.tier()) {
1936
+ case 'great': return '☀️';
1937
+ case 'good': return '⛅';
1938
+ case 'ok': return '🌤';
1939
+ default: return '🌧️';
1940
+ }
1941
+ }, ...(ngDevMode ? [{ debugName: "tierEmoji" }] : []));
1942
+ factors = computed(() => this.data().factors ?? [], ...(ngDevMode ? [{ debugName: "factors" }] : []));
1943
+ factorBarPct(score) {
1944
+ return Math.min(score / 10, 1) * 100;
1945
+ }
1946
+ factorTier(score, inverted = false) {
1947
+ const s = inverted ? 10 - score : score;
1948
+ if (s >= 6.5)
1949
+ return 'good';
1950
+ if (s >= 3.5)
1951
+ return 'mid';
1952
+ return 'bad';
1953
+ }
1954
+ // Count-up animation
1955
+ displayScore = signal('0.0', ...(ngDevMode ? [{ debugName: "displayScore" }] : []));
1956
+ raf = 0;
1957
+ constructor() {
1958
+ effect(() => {
1959
+ const target = this.data().score;
1960
+ cancelAnimationFrame(this.raf);
1961
+ const start = performance.now();
1962
+ const tick = (now) => {
1963
+ const t = Math.min((now - start) / 900, 1);
1964
+ const e = 1 - Math.pow(1 - t, 3);
1965
+ this.displayScore.set((e * target).toFixed(1));
1966
+ if (t < 1)
1967
+ this.raf = requestAnimationFrame(tick);
1968
+ };
1969
+ this.raf = requestAnimationFrame(tick);
1970
+ });
1971
+ }
1972
+ ngOnDestroy() { cancelAnimationFrame(this.raf); }
1973
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: CampingScoreWidgetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1974
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: CampingScoreWidgetComponent, isStandalone: true, selector: "c2g-camping-score-widget", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<article class=\"c2g-cs\" [class]=\"'c2g-cs--' + tier()\">\n\n <!-- Ambient glow orb behind score -->\n <div class=\"c2g-cs__glow-orb\" aria-hidden=\"true\"></div>\n\n <div class=\"c2g-cs__header\">\n <div class=\"c2g-cs__title-col\">\n <span class=\"c2g-cs__label\">Camping-Score</span>\n @if (data().tourName) {\n <span class=\"c2g-cs__tour\">{{ data().tourName }}</span>\n }\n </div>\n <span class=\"c2g-cs__tier-badge\">\n {{ tierEmoji() }} {{ tierLabel() }}\n </span>\n </div>\n\n <!-- Score hero -->\n <div class=\"c2g-cs__score-hero\">\n <span class=\"c2g-cs__score-value\">{{ displayScore() }}</span>\n <div class=\"c2g-cs__score-meta\">\n <span class=\"c2g-cs__score-max\">/10</span>\n <!-- Progress bar -->\n <div class=\"c2g-cs__progress-track\">\n <div class=\"c2g-cs__progress-fill\"\n [style.width.%]=\"(data().score / 10) * 100\">\n </div>\n </div>\n </div>\n </div>\n\n <!-- Factor tiles (optional) -->\n @if (factors().length > 0) {\n <div class=\"c2g-cs__factors\">\n @for (f of factors(); track f.label) {\n <div class=\"c2g-cs__factor\"\n [class]=\"'c2g-cs__factor--' + factorTier(f.score, f.inverted)\"\n [class.c2g-cs__factor--inverted]=\"f.inverted\">\n <span class=\"c2g-cs__factor-direction\">{{ f.inverted ? '\u2193' : '\u2191' }}</span>\n <span class=\"c2g-cs__factor-icon\">{{ f.icon }}</span>\n <span class=\"c2g-cs__factor-label\">{{ f.label }}</span>\n <div class=\"c2g-cs__factor-bar-track\">\n <div class=\"c2g-cs__factor-bar-fill\"\n [style.width.%]=\"factorBarPct(f.score)\">\n </div>\n </div>\n <span class=\"c2g-cs__factor-score\">{{ f.score.toFixed(0) }}</span>\n </div>\n }\n </div>\n }\n\n <!-- Highlights -->\n @if (data().highlights?.length) {\n <ul class=\"c2g-cs__highlights\">\n @for (h of data().highlights!.slice(0, 3); track h) {\n <li class=\"c2g-cs__highlight\">\n <span class=\"c2g-cs__highlight-dot\"></span>\n {{ h }}\n </li>\n }\n </ul>\n }\n\n <!-- Warnings -->\n @if (data().warnings?.length) {\n <div class=\"c2g-cs__warnings\">\n @for (w of data().warnings!.slice(0, 2); track w) {\n <div class=\"c2g-cs__warning\">\u26A0\uFE0F {{ w }}</div>\n }\n </div>\n }\n\n</article>\n", styles: [":host{display:block}.c2g-cs{background:color-mix(in srgb,var(--cs-color, #94a3b8) 6%,var(--c2g-theme-surface, var(--c2g-color-surface)));border:1.5px solid color-mix(in srgb,var(--cs-color, #94a3b8) 35%,transparent);border-radius:var(--c2g-radius-xl, 20px);padding:1.25rem 1.5rem 1.125rem;display:flex;flex-direction:column;gap:.875rem;position:relative;overflow:hidden;transition:box-shadow .2s ease,transform .2s ease}.c2g-cs:hover{transform:translateY(-2px);box-shadow:0 8px 32px var(--cs-glow, rgba(0, 0, 0, .12))}.c2g-cs--great{--cs-color: #22c55e;--cs-glow: rgba(34,197,94,.35);--cs-glow-soft: rgba(34,197,94,.1)}.c2g-cs--good{--cs-color: #84cc16;--cs-glow: rgba(132,204,22,.3);--cs-glow-soft: rgba(132,204,22,.08)}.c2g-cs--ok{--cs-color: #f59e0b;--cs-glow: rgba(245,158,11,.3);--cs-glow-soft: rgba(245,158,11,.08)}.c2g-cs--bad{--cs-color: #ef4444;--cs-glow: rgba(239,68,68,.3);--cs-glow-soft: rgba(239,68,68,.08)}.c2g-cs__glow-orb{position:absolute;top:-40px;right:-40px;width:160px;height:160px;border-radius:50%;background:radial-gradient(circle,var(--cs-glow-soft, transparent) 0%,transparent 70%);pointer-events:none}.c2g-cs__header{display:flex;align-items:flex-start;justify-content:space-between;gap:.75rem}.c2g-cs__title-col{display:flex;flex-direction:column;gap:2px}.c2g-cs__label{font-size:.72rem;font-weight:700;text-transform:uppercase;letter-spacing:.09em;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-secondary))}.c2g-cs__tour{font-size:.8125rem;font-weight:600;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary));max-width:180px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.c2g-cs__tier-badge{display:inline-flex;align-items:center;gap:4px;font-size:.72rem;font-weight:700;color:var(--cs-color);background:color-mix(in srgb,var(--cs-color) 12%,transparent);border:1px solid color-mix(in srgb,var(--cs-color) 28%,transparent);border-radius:20px;padding:3px 10px;white-space:nowrap;flex-shrink:0}.c2g-cs__score-hero{display:flex;align-items:center;gap:1rem}.c2g-cs__score-value{font-size:4rem;font-weight:900;line-height:1;letter-spacing:-.04em;color:var(--cs-color);font-variant-numeric:tabular-nums;text-shadow:0 0 40px var(--cs-glow, transparent);flex-shrink:0}.c2g-cs__score-meta{flex:1;display:flex;flex-direction:column;gap:6px}.c2g-cs__score-max{font-size:1rem;font-weight:700;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));line-height:1}.c2g-cs__progress-track{height:8px;background:var(--c2g-theme-surface-container, rgba(0, 0, 0, .07));border-radius:4px;overflow:hidden}.c2g-cs__progress-fill{height:100%;background:var(--cs-color);border-radius:4px;transition:width .9s cubic-bezier(.4,0,.2,1);box-shadow:0 0 8px var(--cs-glow, transparent)}.c2g-cs__factors{display:grid;grid-template-columns:repeat(3,1fr);gap:6px}.c2g-cs__factor{display:flex;flex-direction:column;align-items:center;gap:4px;padding:8px 6px 7px;border-radius:12px;border:1px solid color-mix(in srgb,var(--ft-color) 30%,transparent);background:color-mix(in srgb,var(--ft-color) 8%,var(--c2g-theme-surface, var(--c2g-color-surface)));text-align:center;position:relative;--ft-color: #94a3b8}.c2g-cs__factor--good{--ft-color: #22c55e}.c2g-cs__factor--mid{--ft-color: #f59e0b}.c2g-cs__factor--bad{--ft-color: #ef4444}.c2g-cs__factor-direction{position:absolute;top:5px;right:6px;font-size:.6rem;font-weight:900;line-height:1;color:var(--ft-color);opacity:.75}.c2g-cs__factor-icon{font-size:1.2rem;line-height:1}.c2g-cs__factor-label{font-size:.64rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted))}.c2g-cs__factor-bar-track{width:100%;height:4px;background:var(--c2g-theme-outline-variant, var(--c2g-color-outline-variant));border-radius:2px;overflow:hidden}.c2g-cs__factor-bar-fill{height:100%;background:var(--ft-color);border-radius:2px;transition:width .8s cubic-bezier(.4,0,.2,1)}.c2g-cs__factor-score{font-size:.8rem;font-weight:900;color:var(--ft-color);line-height:1}.c2g-cs__highlights{list-style:none;margin:0;padding:.625rem 0 0;border-top:1px solid var(--c2g-theme-outline-variant, var(--c2g-color-outline-variant));display:flex;flex-direction:column;gap:.375rem}.c2g-cs__highlight{display:flex;align-items:center;gap:.5rem;font-size:.8rem;font-weight:600;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary))}.c2g-cs__highlight-dot{width:6px;height:6px;border-radius:50%;flex-shrink:0;background:var(--cs-color);box-shadow:0 0 6px var(--cs-glow, transparent)}.c2g-cs__warnings{display:flex;flex-direction:column;gap:.375rem}.c2g-cs__warning{font-size:.75rem;font-weight:600;color:#f59e0b;background:#f59e0b1a;border:1px solid rgba(245,158,11,.2);border-radius:8px;padding:.3rem .625rem}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1975
+ }
1976
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: CampingScoreWidgetComponent, decorators: [{
1977
+ type: Component,
1978
+ args: [{ selector: 'c2g-camping-score-widget', standalone: true, imports: [], changeDetection: ChangeDetectionStrategy.OnPush, template: "<article class=\"c2g-cs\" [class]=\"'c2g-cs--' + tier()\">\n\n <!-- Ambient glow orb behind score -->\n <div class=\"c2g-cs__glow-orb\" aria-hidden=\"true\"></div>\n\n <div class=\"c2g-cs__header\">\n <div class=\"c2g-cs__title-col\">\n <span class=\"c2g-cs__label\">Camping-Score</span>\n @if (data().tourName) {\n <span class=\"c2g-cs__tour\">{{ data().tourName }}</span>\n }\n </div>\n <span class=\"c2g-cs__tier-badge\">\n {{ tierEmoji() }} {{ tierLabel() }}\n </span>\n </div>\n\n <!-- Score hero -->\n <div class=\"c2g-cs__score-hero\">\n <span class=\"c2g-cs__score-value\">{{ displayScore() }}</span>\n <div class=\"c2g-cs__score-meta\">\n <span class=\"c2g-cs__score-max\">/10</span>\n <!-- Progress bar -->\n <div class=\"c2g-cs__progress-track\">\n <div class=\"c2g-cs__progress-fill\"\n [style.width.%]=\"(data().score / 10) * 100\">\n </div>\n </div>\n </div>\n </div>\n\n <!-- Factor tiles (optional) -->\n @if (factors().length > 0) {\n <div class=\"c2g-cs__factors\">\n @for (f of factors(); track f.label) {\n <div class=\"c2g-cs__factor\"\n [class]=\"'c2g-cs__factor--' + factorTier(f.score, f.inverted)\"\n [class.c2g-cs__factor--inverted]=\"f.inverted\">\n <span class=\"c2g-cs__factor-direction\">{{ f.inverted ? '\u2193' : '\u2191' }}</span>\n <span class=\"c2g-cs__factor-icon\">{{ f.icon }}</span>\n <span class=\"c2g-cs__factor-label\">{{ f.label }}</span>\n <div class=\"c2g-cs__factor-bar-track\">\n <div class=\"c2g-cs__factor-bar-fill\"\n [style.width.%]=\"factorBarPct(f.score)\">\n </div>\n </div>\n <span class=\"c2g-cs__factor-score\">{{ f.score.toFixed(0) }}</span>\n </div>\n }\n </div>\n }\n\n <!-- Highlights -->\n @if (data().highlights?.length) {\n <ul class=\"c2g-cs__highlights\">\n @for (h of data().highlights!.slice(0, 3); track h) {\n <li class=\"c2g-cs__highlight\">\n <span class=\"c2g-cs__highlight-dot\"></span>\n {{ h }}\n </li>\n }\n </ul>\n }\n\n <!-- Warnings -->\n @if (data().warnings?.length) {\n <div class=\"c2g-cs__warnings\">\n @for (w of data().warnings!.slice(0, 2); track w) {\n <div class=\"c2g-cs__warning\">\u26A0\uFE0F {{ w }}</div>\n }\n </div>\n }\n\n</article>\n", styles: [":host{display:block}.c2g-cs{background:color-mix(in srgb,var(--cs-color, #94a3b8) 6%,var(--c2g-theme-surface, var(--c2g-color-surface)));border:1.5px solid color-mix(in srgb,var(--cs-color, #94a3b8) 35%,transparent);border-radius:var(--c2g-radius-xl, 20px);padding:1.25rem 1.5rem 1.125rem;display:flex;flex-direction:column;gap:.875rem;position:relative;overflow:hidden;transition:box-shadow .2s ease,transform .2s ease}.c2g-cs:hover{transform:translateY(-2px);box-shadow:0 8px 32px var(--cs-glow, rgba(0, 0, 0, .12))}.c2g-cs--great{--cs-color: #22c55e;--cs-glow: rgba(34,197,94,.35);--cs-glow-soft: rgba(34,197,94,.1)}.c2g-cs--good{--cs-color: #84cc16;--cs-glow: rgba(132,204,22,.3);--cs-glow-soft: rgba(132,204,22,.08)}.c2g-cs--ok{--cs-color: #f59e0b;--cs-glow: rgba(245,158,11,.3);--cs-glow-soft: rgba(245,158,11,.08)}.c2g-cs--bad{--cs-color: #ef4444;--cs-glow: rgba(239,68,68,.3);--cs-glow-soft: rgba(239,68,68,.08)}.c2g-cs__glow-orb{position:absolute;top:-40px;right:-40px;width:160px;height:160px;border-radius:50%;background:radial-gradient(circle,var(--cs-glow-soft, transparent) 0%,transparent 70%);pointer-events:none}.c2g-cs__header{display:flex;align-items:flex-start;justify-content:space-between;gap:.75rem}.c2g-cs__title-col{display:flex;flex-direction:column;gap:2px}.c2g-cs__label{font-size:.72rem;font-weight:700;text-transform:uppercase;letter-spacing:.09em;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-secondary))}.c2g-cs__tour{font-size:.8125rem;font-weight:600;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary));max-width:180px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.c2g-cs__tier-badge{display:inline-flex;align-items:center;gap:4px;font-size:.72rem;font-weight:700;color:var(--cs-color);background:color-mix(in srgb,var(--cs-color) 12%,transparent);border:1px solid color-mix(in srgb,var(--cs-color) 28%,transparent);border-radius:20px;padding:3px 10px;white-space:nowrap;flex-shrink:0}.c2g-cs__score-hero{display:flex;align-items:center;gap:1rem}.c2g-cs__score-value{font-size:4rem;font-weight:900;line-height:1;letter-spacing:-.04em;color:var(--cs-color);font-variant-numeric:tabular-nums;text-shadow:0 0 40px var(--cs-glow, transparent);flex-shrink:0}.c2g-cs__score-meta{flex:1;display:flex;flex-direction:column;gap:6px}.c2g-cs__score-max{font-size:1rem;font-weight:700;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));line-height:1}.c2g-cs__progress-track{height:8px;background:var(--c2g-theme-surface-container, rgba(0, 0, 0, .07));border-radius:4px;overflow:hidden}.c2g-cs__progress-fill{height:100%;background:var(--cs-color);border-radius:4px;transition:width .9s cubic-bezier(.4,0,.2,1);box-shadow:0 0 8px var(--cs-glow, transparent)}.c2g-cs__factors{display:grid;grid-template-columns:repeat(3,1fr);gap:6px}.c2g-cs__factor{display:flex;flex-direction:column;align-items:center;gap:4px;padding:8px 6px 7px;border-radius:12px;border:1px solid color-mix(in srgb,var(--ft-color) 30%,transparent);background:color-mix(in srgb,var(--ft-color) 8%,var(--c2g-theme-surface, var(--c2g-color-surface)));text-align:center;position:relative;--ft-color: #94a3b8}.c2g-cs__factor--good{--ft-color: #22c55e}.c2g-cs__factor--mid{--ft-color: #f59e0b}.c2g-cs__factor--bad{--ft-color: #ef4444}.c2g-cs__factor-direction{position:absolute;top:5px;right:6px;font-size:.6rem;font-weight:900;line-height:1;color:var(--ft-color);opacity:.75}.c2g-cs__factor-icon{font-size:1.2rem;line-height:1}.c2g-cs__factor-label{font-size:.64rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted))}.c2g-cs__factor-bar-track{width:100%;height:4px;background:var(--c2g-theme-outline-variant, var(--c2g-color-outline-variant));border-radius:2px;overflow:hidden}.c2g-cs__factor-bar-fill{height:100%;background:var(--ft-color);border-radius:2px;transition:width .8s cubic-bezier(.4,0,.2,1)}.c2g-cs__factor-score{font-size:.8rem;font-weight:900;color:var(--ft-color);line-height:1}.c2g-cs__highlights{list-style:none;margin:0;padding:.625rem 0 0;border-top:1px solid var(--c2g-theme-outline-variant, var(--c2g-color-outline-variant));display:flex;flex-direction:column;gap:.375rem}.c2g-cs__highlight{display:flex;align-items:center;gap:.5rem;font-size:.8rem;font-weight:600;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary))}.c2g-cs__highlight-dot{width:6px;height:6px;border-radius:50%;flex-shrink:0;background:var(--cs-color);box-shadow:0 0 6px var(--cs-glow, transparent)}.c2g-cs__warnings{display:flex;flex-direction:column;gap:.375rem}.c2g-cs__warning{font-size:.75rem;font-weight:600;color:#f59e0b;background:#f59e0b1a;border:1px solid rgba(245,158,11,.2);border-radius:8px;padding:.3rem .625rem}\n"] }]
1979
+ }], ctorParameters: () => [], propDecorators: { data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: true }] }] } });
1980
+
1981
+ class RainVisualizationWidgetComponent {
1982
+ data = input.required(...(ngDevMode ? [{ debugName: "data" }] : []));
1983
+ enriched = computed(() => {
1984
+ const raw = this.data().days.slice(0, 7);
1985
+ const maxPrecip = Math.max(...raw.map(d => d.precipitation), 5);
1986
+ return raw.map(d => {
1987
+ const prob = d.precipitationProbability;
1988
+ const level = prob < 0.2 ? 'none' :
1989
+ prob < 0.5 ? 'light' :
1990
+ prob < 0.75 ? 'moderate' : 'heavy';
1991
+ return {
1992
+ ...d,
1993
+ dayLabel: new Date(d.date).toLocaleDateString('de-DE', { weekday: 'short', day: 'numeric' }),
1994
+ probPct: Math.round(prob * 100),
1995
+ barPct: Math.round((d.precipitation / maxPrecip) * 100),
1996
+ level,
1997
+ icon: d.icon ?? (level === 'none' ? '☀️' : level === 'light' ? '🌦' : level === 'moderate' ? '🌧' : '⛈'),
1998
+ };
1999
+ });
2000
+ }, ...(ngDevMode ? [{ debugName: "enriched" }] : []));
2001
+ overallRisk = computed(() => {
2002
+ const days = this.enriched();
2003
+ const avg = days.reduce((s, d) => s + d.precipitationProbability, 0) / (days.length || 1);
2004
+ return avg >= 0.6 ? 'high' : avg >= 0.3 ? 'medium' : 'low';
2005
+ }, ...(ngDevMode ? [{ debugName: "overallRisk" }] : []));
2006
+ riskLabel = computed(() => {
2007
+ const days = this.enriched();
2008
+ const rainyDays = days.filter(d => d.precipitationProbability >= 0.4).length;
2009
+ const totalMm = days.reduce((s, d) => s + d.precipitation, 0);
2010
+ if (this.overallRisk() === 'high')
2011
+ return `${rainyDays} Regentage · ${totalMm.toFixed(0)} mm gesamt`;
2012
+ if (this.overallRisk() === 'medium')
2013
+ return `${rainyDays} Schauertag${rainyDays !== 1 ? 'e' : ''} möglich`;
2014
+ return 'Kaum Niederschlag erwartet';
2015
+ }, ...(ngDevMode ? [{ debugName: "riskLabel" }] : []));
2016
+ summaryIcon = computed(() => {
2017
+ switch (this.overallRisk()) {
2018
+ case 'high': return '⛈';
2019
+ case 'medium': return '🌦';
2020
+ default: return '☀️';
2021
+ }
2022
+ }, ...(ngDevMode ? [{ debugName: "summaryIcon" }] : []));
2023
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: RainVisualizationWidgetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2024
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: RainVisualizationWidgetComponent, isStandalone: true, selector: "c2g-rain-visualization-widget", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<article class=\"c2g-rain\" [class]=\"'c2g-rain--' + overallRisk()\">\n\n <header class=\"c2g-rain__header\">\n <div class=\"c2g-rain__title-col\">\n <span class=\"c2g-rain__label\">\uD83C\uDF27 Niederschlag</span>\n @if (data().tourName) {\n <span class=\"c2g-rain__tour\">{{ data().tourName }}</span>\n }\n </div>\n <div class=\"c2g-rain__summary\">\n <span class=\"c2g-rain__summary-icon\">{{ summaryIcon() }}</span>\n <span class=\"c2g-rain__summary-text\">{{ riskLabel() }}</span>\n </div>\n </header>\n\n <!-- Bar chart grid -->\n <div class=\"c2g-rain__grid\" aria-label=\"Niederschlagsvorhersage\" role=\"list\">\n @for (day of enriched(); track day.date) {\n <div class=\"c2g-rain__day c2g-rain__day--{{ day.level }}\" role=\"listitem\">\n\n <!-- Weather icon -->\n <span class=\"c2g-rain__day-icon\">{{ day.icon }}</span>\n\n <!-- Probability badge -->\n <span class=\"c2g-rain__prob c2g-rain__prob--{{ day.level }}\">\n {{ day.probPct }}%\n </span>\n\n <!-- Bar (precipitation mm) -->\n <div class=\"c2g-rain__bar-wrap\" [title]=\"day.precipitation + ' mm'\">\n <div\n class=\"c2g-rain__bar c2g-rain__bar--{{ day.level }}\"\n [style.height.%]=\"day.barPct\"\n ></div>\n </div>\n\n @if (day.precipitation > 0) {\n <span class=\"c2g-rain__mm\">{{ day.precipitation.toFixed(1) }}<small>mm</small></span>\n } @else {\n <span class=\"c2g-rain__mm c2g-rain__mm--dry\">\u2013</span>\n }\n\n <!-- Day label -->\n <span class=\"c2g-rain__date\">{{ day.dayLabel }}</span>\n </div>\n }\n </div>\n\n</article>\n", styles: [":host{display:block}.c2g-rain{background:var(--c2g-theme-surface, var(--c2g-color-surface));border:1px solid var(--c2g-theme-outline-variant, var(--c2g-color-outline-variant));border-radius:var(--c2g-radius-xl, 20px);padding:1.25rem 1.5rem 1rem;display:flex;flex-direction:column;gap:1rem;position:relative;overflow:hidden;transition:box-shadow .2s ease,transform .2s ease}.c2g-rain:hover{transform:translateY(-2px);box-shadow:0 8px 32px #0000003d}.c2g-rain--low{--rain-color: #60a5fa;--rain-glow: rgba(96,165,250,.25)}.c2g-rain--medium{--rain-color: #3b82f6;--rain-glow: rgba(59,130,246,.3)}.c2g-rain--high{--rain-color: #1d4ed8;--rain-glow: rgba(29,78,216,.35)}.c2g-rain:before{content:\"\";position:absolute;inset:0;background:radial-gradient(ellipse 80% 50% at 50% 0%,rgba(59,130,246,.06) 0%,transparent 70%);pointer-events:none}.c2g-rain__header{display:flex;align-items:flex-start;justify-content:space-between;gap:.75rem}.c2g-rain__title-col{display:flex;flex-direction:column;gap:.125rem}.c2g-rain__label{font-size:.75rem;font-weight:700;text-transform:uppercase;letter-spacing:.08em;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-secondary))}.c2g-rain__tour{font-size:.8125rem;font-weight:600;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary));max-width:160px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.c2g-rain__summary{display:flex;flex-direction:column;align-items:flex-end;gap:.125rem}.c2g-rain__summary-icon{font-size:1.5rem;line-height:1}.c2g-rain__summary-text{font-size:.6875rem;font-weight:600;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));text-align:right;max-width:140px}.c2g-rain__grid{display:flex;gap:.375rem;align-items:flex-end}.c2g-rain__day{flex:1;display:flex;flex-direction:column;align-items:center;gap:.25rem}.c2g-rain__day-icon{font-size:1.125rem;line-height:1}.c2g-rain__prob{font-size:.6875rem;font-weight:800;font-variant-numeric:tabular-nums;border-radius:6px;padding:.1rem .3rem}.c2g-rain__prob--none{color:#ffffff4d;background:#ffffff0a}.c2g-rain__prob--light{color:#93c5fd;background:#93c5fd1f}.c2g-rain__prob--moderate{color:#60a5fa;background:#60a5fa26}.c2g-rain__prob--heavy{color:#3b82f6;background:#3b82f633;box-shadow:0 0 8px #3b82f64d}.c2g-rain__bar-wrap{width:100%;height:72px;display:flex;align-items:flex-end;background:var(--c2g-theme-surface-container-low, var(--c2g-color-bg-base));border-radius:6px 6px 4px 4px;overflow:hidden}.c2g-rain__bar{width:100%;min-height:3px;border-radius:4px 4px 0 0;transition:height .7s cubic-bezier(.4,0,.2,1)}.c2g-rain__bar--none{background:#ffffff14}.c2g-rain__bar--light{background:linear-gradient(180deg,#93c5fd,#bfdbfe)}.c2g-rain__bar--moderate{background:linear-gradient(180deg,#3b82f6,#60a5fa)}.c2g-rain__bar--heavy{background:linear-gradient(180deg,#1d4ed8,#3b82f6);box-shadow:0 0 12px #3b82f666}.c2g-rain__mm{font-size:.6875rem;font-weight:700;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary));font-variant-numeric:tabular-nums;text-align:center}.c2g-rain__mm small{font-size:.5625rem;font-weight:600;opacity:.6;margin-left:1px}.c2g-rain__mm--dry{color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted))}.c2g-rain__date{font-size:.625rem;font-weight:700;text-transform:uppercase;letter-spacing:.03em;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));white-space:nowrap;text-align:center}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2025
+ }
2026
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: RainVisualizationWidgetComponent, decorators: [{
2027
+ type: Component,
2028
+ args: [{ selector: 'c2g-rain-visualization-widget', standalone: true, imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<article class=\"c2g-rain\" [class]=\"'c2g-rain--' + overallRisk()\">\n\n <header class=\"c2g-rain__header\">\n <div class=\"c2g-rain__title-col\">\n <span class=\"c2g-rain__label\">\uD83C\uDF27 Niederschlag</span>\n @if (data().tourName) {\n <span class=\"c2g-rain__tour\">{{ data().tourName }}</span>\n }\n </div>\n <div class=\"c2g-rain__summary\">\n <span class=\"c2g-rain__summary-icon\">{{ summaryIcon() }}</span>\n <span class=\"c2g-rain__summary-text\">{{ riskLabel() }}</span>\n </div>\n </header>\n\n <!-- Bar chart grid -->\n <div class=\"c2g-rain__grid\" aria-label=\"Niederschlagsvorhersage\" role=\"list\">\n @for (day of enriched(); track day.date) {\n <div class=\"c2g-rain__day c2g-rain__day--{{ day.level }}\" role=\"listitem\">\n\n <!-- Weather icon -->\n <span class=\"c2g-rain__day-icon\">{{ day.icon }}</span>\n\n <!-- Probability badge -->\n <span class=\"c2g-rain__prob c2g-rain__prob--{{ day.level }}\">\n {{ day.probPct }}%\n </span>\n\n <!-- Bar (precipitation mm) -->\n <div class=\"c2g-rain__bar-wrap\" [title]=\"day.precipitation + ' mm'\">\n <div\n class=\"c2g-rain__bar c2g-rain__bar--{{ day.level }}\"\n [style.height.%]=\"day.barPct\"\n ></div>\n </div>\n\n @if (day.precipitation > 0) {\n <span class=\"c2g-rain__mm\">{{ day.precipitation.toFixed(1) }}<small>mm</small></span>\n } @else {\n <span class=\"c2g-rain__mm c2g-rain__mm--dry\">\u2013</span>\n }\n\n <!-- Day label -->\n <span class=\"c2g-rain__date\">{{ day.dayLabel }}</span>\n </div>\n }\n </div>\n\n</article>\n", styles: [":host{display:block}.c2g-rain{background:var(--c2g-theme-surface, var(--c2g-color-surface));border:1px solid var(--c2g-theme-outline-variant, var(--c2g-color-outline-variant));border-radius:var(--c2g-radius-xl, 20px);padding:1.25rem 1.5rem 1rem;display:flex;flex-direction:column;gap:1rem;position:relative;overflow:hidden;transition:box-shadow .2s ease,transform .2s ease}.c2g-rain:hover{transform:translateY(-2px);box-shadow:0 8px 32px #0000003d}.c2g-rain--low{--rain-color: #60a5fa;--rain-glow: rgba(96,165,250,.25)}.c2g-rain--medium{--rain-color: #3b82f6;--rain-glow: rgba(59,130,246,.3)}.c2g-rain--high{--rain-color: #1d4ed8;--rain-glow: rgba(29,78,216,.35)}.c2g-rain:before{content:\"\";position:absolute;inset:0;background:radial-gradient(ellipse 80% 50% at 50% 0%,rgba(59,130,246,.06) 0%,transparent 70%);pointer-events:none}.c2g-rain__header{display:flex;align-items:flex-start;justify-content:space-between;gap:.75rem}.c2g-rain__title-col{display:flex;flex-direction:column;gap:.125rem}.c2g-rain__label{font-size:.75rem;font-weight:700;text-transform:uppercase;letter-spacing:.08em;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-secondary))}.c2g-rain__tour{font-size:.8125rem;font-weight:600;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary));max-width:160px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.c2g-rain__summary{display:flex;flex-direction:column;align-items:flex-end;gap:.125rem}.c2g-rain__summary-icon{font-size:1.5rem;line-height:1}.c2g-rain__summary-text{font-size:.6875rem;font-weight:600;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));text-align:right;max-width:140px}.c2g-rain__grid{display:flex;gap:.375rem;align-items:flex-end}.c2g-rain__day{flex:1;display:flex;flex-direction:column;align-items:center;gap:.25rem}.c2g-rain__day-icon{font-size:1.125rem;line-height:1}.c2g-rain__prob{font-size:.6875rem;font-weight:800;font-variant-numeric:tabular-nums;border-radius:6px;padding:.1rem .3rem}.c2g-rain__prob--none{color:#ffffff4d;background:#ffffff0a}.c2g-rain__prob--light{color:#93c5fd;background:#93c5fd1f}.c2g-rain__prob--moderate{color:#60a5fa;background:#60a5fa26}.c2g-rain__prob--heavy{color:#3b82f6;background:#3b82f633;box-shadow:0 0 8px #3b82f64d}.c2g-rain__bar-wrap{width:100%;height:72px;display:flex;align-items:flex-end;background:var(--c2g-theme-surface-container-low, var(--c2g-color-bg-base));border-radius:6px 6px 4px 4px;overflow:hidden}.c2g-rain__bar{width:100%;min-height:3px;border-radius:4px 4px 0 0;transition:height .7s cubic-bezier(.4,0,.2,1)}.c2g-rain__bar--none{background:#ffffff14}.c2g-rain__bar--light{background:linear-gradient(180deg,#93c5fd,#bfdbfe)}.c2g-rain__bar--moderate{background:linear-gradient(180deg,#3b82f6,#60a5fa)}.c2g-rain__bar--heavy{background:linear-gradient(180deg,#1d4ed8,#3b82f6);box-shadow:0 0 12px #3b82f666}.c2g-rain__mm{font-size:.6875rem;font-weight:700;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary));font-variant-numeric:tabular-nums;text-align:center}.c2g-rain__mm small{font-size:.5625rem;font-weight:600;opacity:.6;margin-left:1px}.c2g-rain__mm--dry{color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted))}.c2g-rain__date{font-size:.625rem;font-weight:700;text-transform:uppercase;letter-spacing:.03em;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));white-space:nowrap;text-align:center}\n"] }]
2029
+ }], propDecorators: { data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: true }] }] } });
2030
+
2031
+ const TYPE_CONFIG$1 = {
2032
+ adult: { emoji: '🧑', label: 'Erwachsene', color: '#ff6b35' },
2033
+ senior: { emoji: '👴', label: 'Senioren', color: '#a855f7' },
2034
+ teen: { emoji: '🧒', label: 'Jugendliche', color: '#f59e0b' },
2035
+ child: { emoji: '👧', label: 'Kinder', color: '#84cc16' },
2036
+ toddler: { emoji: '👶', label: 'Kleinkinder', color: '#06b6d4' },
2037
+ dog: { emoji: '🐕', label: 'Hunde', color: '#f97316' },
2038
+ cat: { emoji: '🐈', label: 'Katzen', color: '#ec4899' },
2039
+ pet: { emoji: '🐾', label: 'Haustiere', color: '#6b7280' },
2040
+ };
2041
+ const TYPE_ORDER = ['adult', 'senior', 'teen', 'child', 'toddler', 'dog', 'cat', 'pet'];
2042
+ class GroupCompositionWidgetComponent {
2043
+ data = input.required(...(ngDevMode ? [{ debugName: "data" }] : []));
2044
+ sorted = computed(() => [...this.data().members]
2045
+ .filter(m => m.count > 0)
2046
+ .sort((a, b) => TYPE_ORDER.indexOf(a.type) - TYPE_ORDER.indexOf(b.type)), ...(ngDevMode ? [{ debugName: "sorted" }] : []));
2047
+ totalPeople = computed(() => this.data().members
2048
+ .filter(m => ['adult', 'teen', 'child', 'toddler', 'senior'].includes(m.type))
2049
+ .reduce((s, m) => s + m.count, 0), ...(ngDevMode ? [{ debugName: "totalPeople" }] : []));
2050
+ totalPets = computed(() => this.data().members
2051
+ .filter(m => ['dog', 'cat', 'pet'].includes(m.type))
2052
+ .reduce((s, m) => s + m.count, 0), ...(ngDevMode ? [{ debugName: "totalPets" }] : []));
2053
+ maxCount = computed(() => Math.max(...this.data().members.map(m => m.count), 1), ...(ngDevMode ? [{ debugName: "maxCount" }] : []));
2054
+ // Avatar cluster: up to 12 individual icons for the visual summary strip
2055
+ avatars = computed(() => {
2056
+ const result = [];
2057
+ for (const entry of this.sorted()) {
2058
+ const cfg = TYPE_CONFIG$1[entry.type];
2059
+ const n = Math.min(entry.count, 6);
2060
+ for (let i = 0; i < n; i++) {
2061
+ result.push({ emoji: cfg.emoji, color: cfg.color, key: `${entry.type}-${i}` });
2062
+ }
2063
+ }
2064
+ return result.slice(0, 14);
2065
+ }, ...(ngDevMode ? [{ debugName: "avatars" }] : []));
2066
+ configFor(type) {
2067
+ return TYPE_CONFIG$1[type];
2068
+ }
2069
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: GroupCompositionWidgetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2070
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: GroupCompositionWidgetComponent, isStandalone: true, selector: "c2g-group-composition-widget", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<div class=\"c2g-gc\">\n\n <div class=\"c2g-gc__header\">\n <div class=\"c2g-gc__title-col\">\n <span class=\"c2g-gc__label\">Gruppenkomposition</span>\n @if (data().groupName) {\n <span class=\"c2g-gc__name\">{{ data().groupName }}</span>\n }\n </div>\n <div class=\"c2g-gc__summary-pills\">\n <span class=\"c2g-gc__pill\">\n <span class=\"c2g-gc__pill-num\">{{ totalPeople() }}</span>\n <span class=\"c2g-gc__pill-sub\">Personen</span>\n </span>\n @if (totalPets() > 0) {\n <span class=\"c2g-gc__pill c2g-gc__pill--pets\">\n <span class=\"c2g-gc__pill-num\">{{ totalPets() }}</span>\n <span class=\"c2g-gc__pill-sub\">Tiere</span>\n </span>\n }\n </div>\n </div>\n\n <!-- Avatar cluster strip -->\n <div class=\"c2g-gc__avatars\">\n @for (a of avatars(); track a.key) {\n <span class=\"c2g-gc__avatar\" [style.--av-color]=\"a.color\">{{ a.emoji }}</span>\n }\n @if (totalPeople() + totalPets() > avatars().length) {\n <span class=\"c2g-gc__avatar-more\">+{{ totalPeople() + totalPets() - avatars().length }}</span>\n }\n </div>\n\n <!-- Bar chart breakdown -->\n <div class=\"c2g-gc__bars\">\n @for (entry of sorted(); track entry.type) {\n <div class=\"c2g-gc__bar-row\">\n <span class=\"c2g-gc__bar-emoji\">{{ configFor(entry.type).emoji }}</span>\n <span class=\"c2g-gc__bar-label\">{{ configFor(entry.type).label }}</span>\n <div class=\"c2g-gc__bar-track\">\n <div class=\"c2g-gc__bar-fill\"\n [style.width.%]=\"(entry.count / maxCount()) * 100\"\n [style.background]=\"configFor(entry.type).color\">\n </div>\n </div>\n <span class=\"c2g-gc__bar-count\" [style.color]=\"configFor(entry.type).color\">\n {{ entry.count }}\n </span>\n @if (entry.names?.length) {\n <span class=\"c2g-gc__bar-names\">{{ entry.names!.join(', ') }}</span>\n }\n </div>\n }\n </div>\n\n</div>\n", styles: [":host{display:block;font-family:var(--c2g-font-family-base, \"Quicksand\", sans-serif)}.c2g-gc{border-radius:var(--c2g-radius-xl, 20px);background:var(--c2g-theme-surface, var(--c2g-color-surface));border:1px solid var(--c2g-theme-outline-variant, var(--c2g-color-outline-variant));padding:18px 20px 16px;display:flex;flex-direction:column;gap:14px;transition:box-shadow .2s ease,transform .2s ease}.c2g-gc:hover{box-shadow:0 8px 28px #0000001c;transform:translateY(-2px)}.c2g-gc__header{display:flex;align-items:flex-start;justify-content:space-between;gap:10px}.c2g-gc__title-col{display:flex;flex-direction:column;gap:2px}.c2g-gc__label{font-size:.72rem;font-weight:700;text-transform:uppercase;letter-spacing:.09em;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted))}.c2g-gc__name{font-size:.9rem;font-weight:700;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary))}.c2g-gc__summary-pills{display:flex;gap:6px;align-items:center}.c2g-gc__pill{display:flex;flex-direction:column;align-items:center;background:var(--c2g-theme-surface-container, rgba(0, 0, 0, .04));border:1px solid var(--c2g-theme-outline-variant, var(--c2g-color-outline-variant));border-radius:10px;padding:4px 10px;min-width:44px}.c2g-gc__pill--pets{background:#f9731614;border-color:#f9731633}.c2g-gc__pill-num{font-size:1.1rem;font-weight:900;line-height:1;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary))}.c2g-gc__pill-sub{font-size:.6rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted))}.c2g-gc__avatars{display:flex;flex-wrap:wrap;gap:0;padding:10px 12px;background:var(--c2g-theme-surface-container, rgba(0, 0, 0, .025));border:1px solid var(--c2g-theme-outline-variant, var(--c2g-color-outline-variant));border-radius:var(--c2g-radius-lg, 14px);min-height:48px;align-items:center}.c2g-gc__avatar{font-size:1.5rem;line-height:1;display:inline-block;margin-right:-4px;filter:drop-shadow(0 1px 3px color-mix(in srgb,var(--av-color, #000) 40%,transparent));transition:transform .15s ease,z-index 0ms;cursor:default;position:relative;z-index:1}.c2g-gc__avatar:hover{transform:translateY(-4px) scale(1.2);z-index:10}.c2g-gc__avatar-more{font-size:.75rem;font-weight:800;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));background:var(--c2g-theme-outline-variant, var(--c2g-color-outline-variant));border-radius:20px;padding:2px 7px;margin-left:6px}.c2g-gc__bars{display:flex;flex-direction:column;gap:6px}.c2g-gc__bar-row{display:grid;grid-template-columns:20px 90px 1fr 24px;grid-template-rows:auto auto;column-gap:8px;align-items:center}.c2g-gc__bar-emoji{font-size:1rem;line-height:1;grid-column:1;grid-row:1;text-align:center}.c2g-gc__bar-label{font-size:.78rem;font-weight:600;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary));grid-column:2;grid-row:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.c2g-gc__bar-track{grid-column:3;grid-row:1;height:8px;background:var(--c2g-theme-surface-container, rgba(0, 0, 0, .06));border-radius:4px;overflow:hidden}.c2g-gc__bar-fill{height:100%;border-radius:4px;transition:width .6s cubic-bezier(.4,0,.2,1);opacity:.85}.c2g-gc__bar-count{grid-column:4;grid-row:1;font-size:.85rem;font-weight:900;text-align:right;line-height:1}.c2g-gc__bar-names{grid-column:2/5;grid-row:2;font-size:.68rem;font-weight:500;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));padding-top:1px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2071
+ }
2072
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: GroupCompositionWidgetComponent, decorators: [{
2073
+ type: Component,
2074
+ args: [{ selector: 'c2g-group-composition-widget', standalone: true, imports: [], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"c2g-gc\">\n\n <div class=\"c2g-gc__header\">\n <div class=\"c2g-gc__title-col\">\n <span class=\"c2g-gc__label\">Gruppenkomposition</span>\n @if (data().groupName) {\n <span class=\"c2g-gc__name\">{{ data().groupName }}</span>\n }\n </div>\n <div class=\"c2g-gc__summary-pills\">\n <span class=\"c2g-gc__pill\">\n <span class=\"c2g-gc__pill-num\">{{ totalPeople() }}</span>\n <span class=\"c2g-gc__pill-sub\">Personen</span>\n </span>\n @if (totalPets() > 0) {\n <span class=\"c2g-gc__pill c2g-gc__pill--pets\">\n <span class=\"c2g-gc__pill-num\">{{ totalPets() }}</span>\n <span class=\"c2g-gc__pill-sub\">Tiere</span>\n </span>\n }\n </div>\n </div>\n\n <!-- Avatar cluster strip -->\n <div class=\"c2g-gc__avatars\">\n @for (a of avatars(); track a.key) {\n <span class=\"c2g-gc__avatar\" [style.--av-color]=\"a.color\">{{ a.emoji }}</span>\n }\n @if (totalPeople() + totalPets() > avatars().length) {\n <span class=\"c2g-gc__avatar-more\">+{{ totalPeople() + totalPets() - avatars().length }}</span>\n }\n </div>\n\n <!-- Bar chart breakdown -->\n <div class=\"c2g-gc__bars\">\n @for (entry of sorted(); track entry.type) {\n <div class=\"c2g-gc__bar-row\">\n <span class=\"c2g-gc__bar-emoji\">{{ configFor(entry.type).emoji }}</span>\n <span class=\"c2g-gc__bar-label\">{{ configFor(entry.type).label }}</span>\n <div class=\"c2g-gc__bar-track\">\n <div class=\"c2g-gc__bar-fill\"\n [style.width.%]=\"(entry.count / maxCount()) * 100\"\n [style.background]=\"configFor(entry.type).color\">\n </div>\n </div>\n <span class=\"c2g-gc__bar-count\" [style.color]=\"configFor(entry.type).color\">\n {{ entry.count }}\n </span>\n @if (entry.names?.length) {\n <span class=\"c2g-gc__bar-names\">{{ entry.names!.join(', ') }}</span>\n }\n </div>\n }\n </div>\n\n</div>\n", styles: [":host{display:block;font-family:var(--c2g-font-family-base, \"Quicksand\", sans-serif)}.c2g-gc{border-radius:var(--c2g-radius-xl, 20px);background:var(--c2g-theme-surface, var(--c2g-color-surface));border:1px solid var(--c2g-theme-outline-variant, var(--c2g-color-outline-variant));padding:18px 20px 16px;display:flex;flex-direction:column;gap:14px;transition:box-shadow .2s ease,transform .2s ease}.c2g-gc:hover{box-shadow:0 8px 28px #0000001c;transform:translateY(-2px)}.c2g-gc__header{display:flex;align-items:flex-start;justify-content:space-between;gap:10px}.c2g-gc__title-col{display:flex;flex-direction:column;gap:2px}.c2g-gc__label{font-size:.72rem;font-weight:700;text-transform:uppercase;letter-spacing:.09em;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted))}.c2g-gc__name{font-size:.9rem;font-weight:700;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary))}.c2g-gc__summary-pills{display:flex;gap:6px;align-items:center}.c2g-gc__pill{display:flex;flex-direction:column;align-items:center;background:var(--c2g-theme-surface-container, rgba(0, 0, 0, .04));border:1px solid var(--c2g-theme-outline-variant, var(--c2g-color-outline-variant));border-radius:10px;padding:4px 10px;min-width:44px}.c2g-gc__pill--pets{background:#f9731614;border-color:#f9731633}.c2g-gc__pill-num{font-size:1.1rem;font-weight:900;line-height:1;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary))}.c2g-gc__pill-sub{font-size:.6rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted))}.c2g-gc__avatars{display:flex;flex-wrap:wrap;gap:0;padding:10px 12px;background:var(--c2g-theme-surface-container, rgba(0, 0, 0, .025));border:1px solid var(--c2g-theme-outline-variant, var(--c2g-color-outline-variant));border-radius:var(--c2g-radius-lg, 14px);min-height:48px;align-items:center}.c2g-gc__avatar{font-size:1.5rem;line-height:1;display:inline-block;margin-right:-4px;filter:drop-shadow(0 1px 3px color-mix(in srgb,var(--av-color, #000) 40%,transparent));transition:transform .15s ease,z-index 0ms;cursor:default;position:relative;z-index:1}.c2g-gc__avatar:hover{transform:translateY(-4px) scale(1.2);z-index:10}.c2g-gc__avatar-more{font-size:.75rem;font-weight:800;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));background:var(--c2g-theme-outline-variant, var(--c2g-color-outline-variant));border-radius:20px;padding:2px 7px;margin-left:6px}.c2g-gc__bars{display:flex;flex-direction:column;gap:6px}.c2g-gc__bar-row{display:grid;grid-template-columns:20px 90px 1fr 24px;grid-template-rows:auto auto;column-gap:8px;align-items:center}.c2g-gc__bar-emoji{font-size:1rem;line-height:1;grid-column:1;grid-row:1;text-align:center}.c2g-gc__bar-label{font-size:.78rem;font-weight:600;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary));grid-column:2;grid-row:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.c2g-gc__bar-track{grid-column:3;grid-row:1;height:8px;background:var(--c2g-theme-surface-container, rgba(0, 0, 0, .06));border-radius:4px;overflow:hidden}.c2g-gc__bar-fill{height:100%;border-radius:4px;transition:width .6s cubic-bezier(.4,0,.2,1);opacity:.85}.c2g-gc__bar-count{grid-column:4;grid-row:1;font-size:.85rem;font-weight:900;text-align:right;line-height:1}.c2g-gc__bar-names{grid-column:2/5;grid-row:2;font-size:.68rem;font-weight:500;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));padding-top:1px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n"] }]
2075
+ }], propDecorators: { data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: true }] }] } });
2076
+
2077
+ // Minimal hand-crafted Lottie confetti animation.
2078
+ // 6 colored rectangles fall from top with rotation — ~3KB, no external dependency.
2079
+ const CONFETTI_ANIMATION_DATA = {
2080
+ v: '5.7.4',
2081
+ fr: 30,
2082
+ ip: 0,
2083
+ op: 60,
2084
+ w: 200,
2085
+ h: 160,
2086
+ nm: 'confetti',
2087
+ ddd: 0,
2088
+ assets: [],
2089
+ layers: [
2090
+ makeRect(0, '#22c55e', 40, -10, 140, 150, 120, 0),
2091
+ makeRect(1, '#f59e0b', 80, -10, 160, 145, 90, 5),
2092
+ makeRect(2, '#3b82f6', 120, -10, 120, 155, 80, -5),
2093
+ makeRect(3, '#ef4444', 60, -10, 150, 148, 140, 10),
2094
+ makeRect(4, '#a855f7', 100, -10, 130, 152, 60, -8),
2095
+ makeRect(5, '#f97316', 140, -10, 110, 146, 100, 6),
2096
+ makeRect(6, '#22c55e', 30, -10, 145, 153, 110, -12),
2097
+ makeRect(7, '#3b82f6', 170, -10, 155, 149, 70, 15),
2098
+ ],
2099
+ };
2100
+ function makeRect(ind, color, startX, startY, endX, endY, startRot, rotSpeed) {
2101
+ const hex = color.replace('#', '');
2102
+ const r = parseInt(hex.slice(0, 2), 16) / 255;
2103
+ const g = parseInt(hex.slice(2, 4), 16) / 255;
2104
+ const b = parseInt(hex.slice(4, 6), 16) / 255;
2105
+ return {
2106
+ ddd: 0,
2107
+ ind,
2108
+ ty: 4,
2109
+ nm: `confetti-${ind}`,
2110
+ sr: 1,
2111
+ ks: {
2112
+ o: { a: 0, k: 100 },
2113
+ r: {
2114
+ a: 1,
2115
+ k: [
2116
+ { t: 0, s: [startRot], e: [startRot + rotSpeed * 60], i: { x: [0.5], y: [1] }, o: { x: [0.5], y: [0] } },
2117
+ { t: 60, s: [startRot + rotSpeed * 60] },
2118
+ ],
2119
+ },
2120
+ p: {
2121
+ a: 1,
2122
+ k: [
2123
+ { t: 0, s: [startX, startY, 0], e: [endX, endY, 0], i: { x: [0.5], y: [1] }, o: { x: [0.5], y: [0] } },
2124
+ { t: 60, s: [endX, endY, 0] },
2125
+ ],
2126
+ },
2127
+ a: { a: 0, k: [0, 0, 0] },
2128
+ s: { a: 0, k: [100, 100, 100] },
2129
+ },
2130
+ ao: 0,
2131
+ shapes: [
2132
+ {
2133
+ ty: 'rc',
2134
+ d: 1,
2135
+ s: { a: 0, k: [8, 8] },
2136
+ p: { a: 0, k: [0, 0] },
2137
+ r: { a: 0, k: 1 },
2138
+ nm: 'rect',
2139
+ },
2140
+ {
2141
+ ty: 'fl',
2142
+ c: { a: 0, k: [r, g, b, 1] },
2143
+ o: { a: 0, k: 100 },
2144
+ r: 1,
2145
+ nm: 'fill',
2146
+ },
2147
+ ],
2148
+ ip: 0,
2149
+ op: 60,
2150
+ st: 0,
2151
+ bm: 0,
2152
+ };
2153
+ }
2154
+
2155
+ class CriticalItemsAlertWidgetComponent {
2156
+ data = input.required(...(ngDevMode ? [{ debugName: "data" }] : []));
2157
+ daysUntil = computed(() => {
2158
+ const from = new Date(this.data().tourFromDate);
2159
+ from.setHours(0, 0, 0, 0);
2160
+ const today = new Date();
2161
+ today.setHours(0, 0, 0, 0);
2162
+ return Math.max(0, Math.ceil((from.getTime() - today.getTime()) / 86400000));
2163
+ }, ...(ngDevMode ? [{ debugName: "daysUntil" }] : []));
2164
+ urgency = computed(() => {
2165
+ const open = this.data().openItems.length;
2166
+ const days = this.daysUntil();
2167
+ if (open === 0)
2168
+ return 'ok';
2169
+ if (days <= 2 || (days <= 5 && open > 3))
2170
+ return 'critical';
2171
+ return 'warning';
2172
+ }, ...(ngDevMode ? [{ debugName: "urgency" }] : []));
2173
+ urgencyLabel = computed(() => {
2174
+ const d = this.daysUntil();
2175
+ if (d === 0)
2176
+ return 'Heute gehts los!';
2177
+ if (d === 1)
2178
+ return 'Morgen gehts los!';
2179
+ return `Noch ${d} Tage`;
2180
+ }, ...(ngDevMode ? [{ debugName: "urgencyLabel" }] : []));
2181
+ allClear = computed(() => this.data().openItems.length === 0, ...(ngDevMode ? [{ debugName: "allClear" }] : []));
2182
+ personalItems = computed(() => this.data().openItems.filter(i => i.scope === 'personal').slice(0, 4), ...(ngDevMode ? [{ debugName: "personalItems" }] : []));
2183
+ sharedItems = computed(() => this.data().openItems.filter(i => i.scope === 'shared').slice(0, 4), ...(ngDevMode ? [{ debugName: "sharedItems" }] : []));
2184
+ personalHidden = computed(() => Math.max(0, this.data().openItems.filter(i => i.scope === 'personal').length - 4), ...(ngDevMode ? [{ debugName: "personalHidden" }] : []));
2185
+ sharedHidden = computed(() => Math.max(0, this.data().openItems.filter(i => i.scope === 'shared').length - 4), ...(ngDevMode ? [{ debugName: "sharedHidden" }] : []));
2186
+ // Resolved visual type for the all-clear state
2187
+ successVisualType = computed(() => this.data().successVisual?.type ?? 'lottie', ...(ngDevMode ? [{ debugName: "successVisualType" }] : []));
2188
+ lottieOptions = computed(() => {
2189
+ const v = this.data().successVisual;
2190
+ return {
2191
+ animationData: v?.type === 'lottie' ? v.value : CONFETTI_ANIMATION_DATA,
2192
+ loop: false,
2193
+ autoplay: true,
2194
+ };
2195
+ }, ...(ngDevMode ? [{ debugName: "lottieOptions" }] : []));
2196
+ imageValue = computed(() => {
2197
+ const v = this.data().successVisual;
2198
+ return v?.type === 'image' ? v.value : null;
2199
+ }, ...(ngDevMode ? [{ debugName: "imageValue" }] : []));
2200
+ imageAlt = computed(() => this.data().successVisual?.alt ?? 'Erfolg', ...(ngDevMode ? [{ debugName: "imageAlt" }] : []));
2201
+ iconValue = computed(() => {
2202
+ const v = this.data().successVisual;
2203
+ return v?.type === 'icon' ? v.value : '🎉';
2204
+ }, ...(ngDevMode ? [{ debugName: "iconValue" }] : []));
2205
+ sharedProgress(item) {
2206
+ if (!item.neededCount)
2207
+ return 0;
2208
+ return Math.min((item.coveredCount ?? 0) / item.neededCount, 1) * 100;
2209
+ }
2210
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: CriticalItemsAlertWidgetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2211
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: CriticalItemsAlertWidgetComponent, isStandalone: true, selector: "c2g-critical-items-alert-widget", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<div class=\"c2g-cia\" [class]=\"'c2g-cia--' + urgency()\">\n\n <div class=\"c2g-cia__header\">\n <div class=\"c2g-cia__title-col\">\n <span class=\"c2g-cia__label\">\n @if (urgency() === 'critical') { \uD83D\uDEA8 }\n @else if (urgency() === 'warning') { \u26A0\uFE0F }\n @else { \u2705 }\n Kritische Items\n </span>\n @if (data().tourName) {\n <span class=\"c2g-cia__tour\">{{ data().tourName }}</span>\n }\n </div>\n <div class=\"c2g-cia__countdown\">\n <span class=\"c2g-cia__countdown-number\">{{ daysUntil() }}</span>\n <span class=\"c2g-cia__countdown-unit\">{{ daysUntil() === 1 ? 'Tag' : 'Tage' }}</span>\n </div>\n </div>\n\n @if (allClear()) {\n <div class=\"c2g-cia__all-clear\">\n\n <!-- Visual slot -->\n <div class=\"c2g-cia__success-visual\" aria-hidden=\"true\">\n @switch (successVisualType()) {\n @case ('lottie') {\n <ng-lottie [options]=\"lottieOptions()\" width=\"100px\" height=\"80px\" />\n }\n @case ('image') {\n <img class=\"c2g-cia__success-img\"\n [src]=\"imageValue()\"\n [alt]=\"imageAlt()\" />\n }\n @case ('icon') {\n <span class=\"c2g-cia__success-icon\">{{ iconValue() }}</span>\n }\n }\n </div>\n\n <div class=\"c2g-cia__all-clear-text-block\">\n <span class=\"c2g-cia__all-clear-headline\">Alles dabei! \uD83C\uDF89</span>\n <span class=\"c2g-cia__all-clear-sub\">Alle kritischen Items sind gepackt \u2014 bereit f\u00FCr das Abenteuer.</span>\n </div>\n </div>\n } @else {\n\n <!-- Progress summary -->\n <div class=\"c2g-cia__summary\">\n <span class=\"c2g-cia__open-count\">{{ data().openItems.length }}</span>\n <span class=\"c2g-cia__summary-text\">\n von {{ data().totalCritical }} kritischen\n {{ data().totalCritical === 1 ? 'Item fehlt' : 'Items fehlen' }}\n </span>\n </div>\n <div class=\"c2g-cia__progress-track\">\n <div class=\"c2g-cia__progress-fill\"\n [style.width.%]=\"((data().totalCritical - data().openItems.length) / data().totalCritical) * 100\">\n </div>\n </div>\n\n <!-- Side-by-side sections -->\n <div class=\"c2g-cia__sections\">\n\n <!-- Personal items -->\n @if (personalItems().length > 0) {\n <div class=\"c2g-cia__section c2g-cia__section--personal\">\n <div class=\"c2g-cia__section-header\">\n <span class=\"c2g-cia__section-icon c2g-cia__section-icon--personal\">\uD83D\uDC64</span>\n <div class=\"c2g-cia__section-titles\">\n <span class=\"c2g-cia__section-title\">Pers\u00F6nlich</span>\n <span class=\"c2g-cia__section-hint\">Jeder braucht es selbst</span>\n </div>\n </div>\n <ul class=\"c2g-cia__list\">\n @for (item of personalItems(); track item.name) {\n <li class=\"c2g-cia__item c2g-cia__item--personal\">\n <span class=\"c2g-cia__item-dot\"></span>\n <span class=\"c2g-cia__item-name\">{{ item.name }}</span>\n @if (item.missingFor?.length) {\n <span class=\"c2g-cia__item-missing\">{{ item.missingFor!.join(', ') }}</span>\n }\n </li>\n }\n @if (personalHidden() > 0) {\n <li class=\"c2g-cia__item c2g-cia__item--more\">+ {{ personalHidden() }} weitere</li>\n }\n </ul>\n </div>\n }\n\n <!-- Shared items -->\n @if (sharedItems().length > 0) {\n <div class=\"c2g-cia__section c2g-cia__section--shared\">\n <div class=\"c2g-cia__section-header\">\n <span class=\"c2g-cia__section-icon c2g-cia__section-icon--shared\">\uD83D\uDC65</span>\n <div class=\"c2g-cia__section-titles\">\n <span class=\"c2g-cia__section-title\">Geteilt</span>\n <span class=\"c2g-cia__section-hint\">Mindestmenge muss gedeckt sein</span>\n </div>\n </div>\n <ul class=\"c2g-cia__list\">\n @for (item of sharedItems(); track item.name) {\n <li class=\"c2g-cia__item c2g-cia__item--shared\">\n <div class=\"c2g-cia__shared-top\">\n <span class=\"c2g-cia__item-dot\"></span>\n <span class=\"c2g-cia__item-name\">{{ item.name }}</span>\n @if (item.neededCount) {\n <span class=\"c2g-cia__shared-ratio\">\n {{ item.coveredCount ?? 0 }}/{{ item.neededCount }}\n </span>\n }\n </div>\n @if (item.neededCount && item.neededCount > 1) {\n <div class=\"c2g-cia__shared-bar-track\">\n <div class=\"c2g-cia__shared-bar-fill\" [style.width.%]=\"sharedProgress(item)\"></div>\n </div>\n }\n @if (item.coveredBy?.length) {\n <span class=\"c2g-cia__shared-covered\">\u2713 {{ item.coveredBy!.join(', ') }}</span>\n }\n </li>\n }\n @if (sharedHidden() > 0) {\n <li class=\"c2g-cia__item c2g-cia__item--more\">+ {{ sharedHidden() }} weitere</li>\n }\n </ul>\n </div>\n }\n\n </div>\n }\n\n <div class=\"c2g-cia__footer\">{{ urgencyLabel() }}</div>\n\n</div>\n", styles: [":host{display:block;font-family:var(--c2g-font-family-base, \"Quicksand\", sans-serif)}.c2g-cia{border-radius:var(--c2g-radius-xl, 20px);background:var(--c2g-theme-surface, var(--c2g-color-surface));border:1.5px solid var(--c2g-theme-outline-variant, var(--c2g-color-outline-variant));overflow:hidden;display:flex;flex-direction:column;transition:box-shadow .2s ease,transform .2s ease}.c2g-cia:hover{box-shadow:0 8px 28px #0000001a;transform:translateY(-2px)}.c2g-cia--ok{--cia-accent: #22c55e;--cia-bg: rgba(34, 197, 94, .06);border-color:#22c55e4d}.c2g-cia--warning{--cia-accent: #f59e0b;--cia-bg: rgba(245, 158, 11, .06);border-color:#f59e0b59}.c2g-cia--critical{--cia-accent: #ef4444;--cia-bg: rgba(239, 68, 68, .06);border-color:#ef444466;animation:c2g-cia-pulse 2s ease-in-out infinite}@keyframes c2g-cia-pulse{0%,to{box-shadow:none}50%{box-shadow:0 0 0 4px #ef444426}}.c2g-cia__header{display:flex;align-items:flex-start;justify-content:space-between;padding:16px 18px 12px;gap:10px;background:var(--cia-bg)}.c2g-cia__title-col{display:flex;flex-direction:column;gap:2px}.c2g-cia__label{font-size:.8rem;font-weight:700;color:var(--cia-accent)}.c2g-cia__tour{font-size:.82rem;font-weight:600;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary));max-width:180px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.c2g-cia__countdown{display:flex;flex-direction:column;align-items:center;background:var(--cia-accent);border-radius:12px;padding:6px 12px;flex-shrink:0}.c2g-cia__countdown-number{font-size:1.6rem;font-weight:900;line-height:1;color:#fff}.c2g-cia__countdown-unit{font-size:.62rem;font-weight:700;color:#fffc;text-transform:uppercase;letter-spacing:.06em}.c2g-cia__all-clear{display:flex;align-items:center;gap:12px;padding:16px 18px 18px}.c2g-cia__success-visual{flex-shrink:0;width:100px;height:80px;overflow:hidden;display:flex;align-items:center;justify-content:center}.c2g-cia__success-img{width:100%;height:100%;object-fit:contain;border-radius:8px}.c2g-cia__success-icon{font-size:3.5rem;line-height:1;animation:c2g-icon-pop .6s cubic-bezier(.34,1.56,.64,1) both}@keyframes c2g-icon-pop{0%{transform:scale(0) rotate(-20deg);opacity:0}70%{transform:scale(1.15) rotate(8deg);opacity:1}to{transform:scale(1) rotate(0);opacity:1}}.c2g-cia__all-clear-text-block{display:flex;flex-direction:column;gap:4px}.c2g-cia__all-clear-headline{font-size:1.2rem;font-weight:900;color:#22c55e;letter-spacing:-.02em;line-height:1}.c2g-cia__all-clear-sub{font-size:.78rem;font-weight:600;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));line-height:1.3}.c2g-cia__summary{display:flex;align-items:baseline;gap:6px;padding:12px 18px 0}.c2g-cia__open-count{font-size:2rem;font-weight:900;line-height:1;color:var(--cia-accent)}.c2g-cia__summary-text{font-size:.82rem;font-weight:600;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted))}.c2g-cia__progress-track{height:4px;background:var(--c2g-theme-outline-variant, rgba(0, 0, 0, .08));margin:8px 18px 0;border-radius:2px;overflow:hidden}.c2g-cia__progress-fill{height:100%;background:var(--cia-accent);border-radius:2px;transition:width .7s cubic-bezier(.4,0,.2,1)}.c2g-cia__sections{display:grid;grid-template-columns:1fr;gap:0;margin-top:10px}@media(min-width:480px){.c2g-cia__sections{grid-template-columns:1fr 1fr;gap:0}}.c2g-cia__section{padding:0 18px 4px}.c2g-cia__section+.c2g-cia__section{padding-top:10px;border-top:1px solid var(--c2g-theme-outline-variant, var(--c2g-color-outline-variant))}@media(min-width:480px){.c2g-cia__section+.c2g-cia__section{padding-top:0;border-top:none;border-left:1px solid var(--c2g-theme-outline-variant, var(--c2g-color-outline-variant))}}.c2g-cia__section--personal{--sec-accent: #f97316}.c2g-cia__section--shared{--sec-accent: #3b82f6}.c2g-cia__section-header{display:flex;align-items:flex-start;gap:6px;margin-bottom:7px}.c2g-cia__section-titles{display:flex;flex-direction:column;gap:1px}.c2g-cia__section-icon{font-size:.85rem;line-height:1;width:22px;height:22px;border-radius:6px;display:flex;align-items:center;justify-content:center;flex-shrink:0}.c2g-cia__section-icon--personal{background:#f973161f}.c2g-cia__section-icon--shared{background:#3b82f61f}.c2g-cia__section-title{font-size:.72rem;font-weight:800;text-transform:uppercase;letter-spacing:.08em;color:var(--sec-accent, var(--c2g-theme-on-surface, var(--c2g-color-text-primary)))}.c2g-cia__section-hint{font-size:.62rem;font-weight:500;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted))}.c2g-cia__list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:5px}.c2g-cia__item{display:flex;align-items:center;gap:7px;font-size:.82rem;font-weight:600;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary))}.c2g-cia__item--personal .c2g-cia__item-dot{background:#f97316}.c2g-cia__item--shared .c2g-cia__item-dot{background:#3b82f6}.c2g-cia__item--shared{flex-direction:column;align-items:stretch;gap:3px}.c2g-cia__item--more{font-size:.72rem;font-weight:600;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted))}.c2g-cia__item-dot{width:6px;height:6px;border-radius:50%;flex-shrink:0;background:var(--cia-accent)}.c2g-cia__item-name{flex:1}.c2g-cia__item-missing{font-size:.68rem;font-weight:500;color:#f97316;background:#f973161a;border-radius:4px;padding:1px 5px;white-space:nowrap}.c2g-cia__shared-top{display:flex;align-items:center;gap:7px}.c2g-cia__shared-ratio{font-size:.72rem;font-weight:800;color:#3b82f6;background:#3b82f61a;border-radius:4px;padding:1px 6px;white-space:nowrap;margin-left:auto}.c2g-cia__shared-bar-track{height:3px;background:#3b82f626;border-radius:2px;overflow:hidden;margin-left:13px}.c2g-cia__shared-bar-fill{height:100%;background:#3b82f6;border-radius:2px;transition:width .6s cubic-bezier(.4,0,.2,1)}.c2g-cia__shared-covered{font-size:.68rem;font-weight:500;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));margin-left:13px}.c2g-cia__footer{margin-top:12px;padding:8px 18px;font-size:.72rem;font-weight:700;text-align:center;color:var(--cia-accent);background:var(--cia-bg);border-top:1px solid var(--c2g-theme-outline-variant, var(--c2g-color-outline-variant))}\n"], dependencies: [{ kind: "component", type: LottieComponent, selector: "ng-lottie", inputs: ["width", "height"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2212
+ }
2213
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: CriticalItemsAlertWidgetComponent, decorators: [{
2214
+ type: Component,
2215
+ args: [{ selector: 'c2g-critical-items-alert-widget', standalone: true, imports: [LottieComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"c2g-cia\" [class]=\"'c2g-cia--' + urgency()\">\n\n <div class=\"c2g-cia__header\">\n <div class=\"c2g-cia__title-col\">\n <span class=\"c2g-cia__label\">\n @if (urgency() === 'critical') { \uD83D\uDEA8 }\n @else if (urgency() === 'warning') { \u26A0\uFE0F }\n @else { \u2705 }\n Kritische Items\n </span>\n @if (data().tourName) {\n <span class=\"c2g-cia__tour\">{{ data().tourName }}</span>\n }\n </div>\n <div class=\"c2g-cia__countdown\">\n <span class=\"c2g-cia__countdown-number\">{{ daysUntil() }}</span>\n <span class=\"c2g-cia__countdown-unit\">{{ daysUntil() === 1 ? 'Tag' : 'Tage' }}</span>\n </div>\n </div>\n\n @if (allClear()) {\n <div class=\"c2g-cia__all-clear\">\n\n <!-- Visual slot -->\n <div class=\"c2g-cia__success-visual\" aria-hidden=\"true\">\n @switch (successVisualType()) {\n @case ('lottie') {\n <ng-lottie [options]=\"lottieOptions()\" width=\"100px\" height=\"80px\" />\n }\n @case ('image') {\n <img class=\"c2g-cia__success-img\"\n [src]=\"imageValue()\"\n [alt]=\"imageAlt()\" />\n }\n @case ('icon') {\n <span class=\"c2g-cia__success-icon\">{{ iconValue() }}</span>\n }\n }\n </div>\n\n <div class=\"c2g-cia__all-clear-text-block\">\n <span class=\"c2g-cia__all-clear-headline\">Alles dabei! \uD83C\uDF89</span>\n <span class=\"c2g-cia__all-clear-sub\">Alle kritischen Items sind gepackt \u2014 bereit f\u00FCr das Abenteuer.</span>\n </div>\n </div>\n } @else {\n\n <!-- Progress summary -->\n <div class=\"c2g-cia__summary\">\n <span class=\"c2g-cia__open-count\">{{ data().openItems.length }}</span>\n <span class=\"c2g-cia__summary-text\">\n von {{ data().totalCritical }} kritischen\n {{ data().totalCritical === 1 ? 'Item fehlt' : 'Items fehlen' }}\n </span>\n </div>\n <div class=\"c2g-cia__progress-track\">\n <div class=\"c2g-cia__progress-fill\"\n [style.width.%]=\"((data().totalCritical - data().openItems.length) / data().totalCritical) * 100\">\n </div>\n </div>\n\n <!-- Side-by-side sections -->\n <div class=\"c2g-cia__sections\">\n\n <!-- Personal items -->\n @if (personalItems().length > 0) {\n <div class=\"c2g-cia__section c2g-cia__section--personal\">\n <div class=\"c2g-cia__section-header\">\n <span class=\"c2g-cia__section-icon c2g-cia__section-icon--personal\">\uD83D\uDC64</span>\n <div class=\"c2g-cia__section-titles\">\n <span class=\"c2g-cia__section-title\">Pers\u00F6nlich</span>\n <span class=\"c2g-cia__section-hint\">Jeder braucht es selbst</span>\n </div>\n </div>\n <ul class=\"c2g-cia__list\">\n @for (item of personalItems(); track item.name) {\n <li class=\"c2g-cia__item c2g-cia__item--personal\">\n <span class=\"c2g-cia__item-dot\"></span>\n <span class=\"c2g-cia__item-name\">{{ item.name }}</span>\n @if (item.missingFor?.length) {\n <span class=\"c2g-cia__item-missing\">{{ item.missingFor!.join(', ') }}</span>\n }\n </li>\n }\n @if (personalHidden() > 0) {\n <li class=\"c2g-cia__item c2g-cia__item--more\">+ {{ personalHidden() }} weitere</li>\n }\n </ul>\n </div>\n }\n\n <!-- Shared items -->\n @if (sharedItems().length > 0) {\n <div class=\"c2g-cia__section c2g-cia__section--shared\">\n <div class=\"c2g-cia__section-header\">\n <span class=\"c2g-cia__section-icon c2g-cia__section-icon--shared\">\uD83D\uDC65</span>\n <div class=\"c2g-cia__section-titles\">\n <span class=\"c2g-cia__section-title\">Geteilt</span>\n <span class=\"c2g-cia__section-hint\">Mindestmenge muss gedeckt sein</span>\n </div>\n </div>\n <ul class=\"c2g-cia__list\">\n @for (item of sharedItems(); track item.name) {\n <li class=\"c2g-cia__item c2g-cia__item--shared\">\n <div class=\"c2g-cia__shared-top\">\n <span class=\"c2g-cia__item-dot\"></span>\n <span class=\"c2g-cia__item-name\">{{ item.name }}</span>\n @if (item.neededCount) {\n <span class=\"c2g-cia__shared-ratio\">\n {{ item.coveredCount ?? 0 }}/{{ item.neededCount }}\n </span>\n }\n </div>\n @if (item.neededCount && item.neededCount > 1) {\n <div class=\"c2g-cia__shared-bar-track\">\n <div class=\"c2g-cia__shared-bar-fill\" [style.width.%]=\"sharedProgress(item)\"></div>\n </div>\n }\n @if (item.coveredBy?.length) {\n <span class=\"c2g-cia__shared-covered\">\u2713 {{ item.coveredBy!.join(', ') }}</span>\n }\n </li>\n }\n @if (sharedHidden() > 0) {\n <li class=\"c2g-cia__item c2g-cia__item--more\">+ {{ sharedHidden() }} weitere</li>\n }\n </ul>\n </div>\n }\n\n </div>\n }\n\n <div class=\"c2g-cia__footer\">{{ urgencyLabel() }}</div>\n\n</div>\n", styles: [":host{display:block;font-family:var(--c2g-font-family-base, \"Quicksand\", sans-serif)}.c2g-cia{border-radius:var(--c2g-radius-xl, 20px);background:var(--c2g-theme-surface, var(--c2g-color-surface));border:1.5px solid var(--c2g-theme-outline-variant, var(--c2g-color-outline-variant));overflow:hidden;display:flex;flex-direction:column;transition:box-shadow .2s ease,transform .2s ease}.c2g-cia:hover{box-shadow:0 8px 28px #0000001a;transform:translateY(-2px)}.c2g-cia--ok{--cia-accent: #22c55e;--cia-bg: rgba(34, 197, 94, .06);border-color:#22c55e4d}.c2g-cia--warning{--cia-accent: #f59e0b;--cia-bg: rgba(245, 158, 11, .06);border-color:#f59e0b59}.c2g-cia--critical{--cia-accent: #ef4444;--cia-bg: rgba(239, 68, 68, .06);border-color:#ef444466;animation:c2g-cia-pulse 2s ease-in-out infinite}@keyframes c2g-cia-pulse{0%,to{box-shadow:none}50%{box-shadow:0 0 0 4px #ef444426}}.c2g-cia__header{display:flex;align-items:flex-start;justify-content:space-between;padding:16px 18px 12px;gap:10px;background:var(--cia-bg)}.c2g-cia__title-col{display:flex;flex-direction:column;gap:2px}.c2g-cia__label{font-size:.8rem;font-weight:700;color:var(--cia-accent)}.c2g-cia__tour{font-size:.82rem;font-weight:600;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary));max-width:180px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.c2g-cia__countdown{display:flex;flex-direction:column;align-items:center;background:var(--cia-accent);border-radius:12px;padding:6px 12px;flex-shrink:0}.c2g-cia__countdown-number{font-size:1.6rem;font-weight:900;line-height:1;color:#fff}.c2g-cia__countdown-unit{font-size:.62rem;font-weight:700;color:#fffc;text-transform:uppercase;letter-spacing:.06em}.c2g-cia__all-clear{display:flex;align-items:center;gap:12px;padding:16px 18px 18px}.c2g-cia__success-visual{flex-shrink:0;width:100px;height:80px;overflow:hidden;display:flex;align-items:center;justify-content:center}.c2g-cia__success-img{width:100%;height:100%;object-fit:contain;border-radius:8px}.c2g-cia__success-icon{font-size:3.5rem;line-height:1;animation:c2g-icon-pop .6s cubic-bezier(.34,1.56,.64,1) both}@keyframes c2g-icon-pop{0%{transform:scale(0) rotate(-20deg);opacity:0}70%{transform:scale(1.15) rotate(8deg);opacity:1}to{transform:scale(1) rotate(0);opacity:1}}.c2g-cia__all-clear-text-block{display:flex;flex-direction:column;gap:4px}.c2g-cia__all-clear-headline{font-size:1.2rem;font-weight:900;color:#22c55e;letter-spacing:-.02em;line-height:1}.c2g-cia__all-clear-sub{font-size:.78rem;font-weight:600;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));line-height:1.3}.c2g-cia__summary{display:flex;align-items:baseline;gap:6px;padding:12px 18px 0}.c2g-cia__open-count{font-size:2rem;font-weight:900;line-height:1;color:var(--cia-accent)}.c2g-cia__summary-text{font-size:.82rem;font-weight:600;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted))}.c2g-cia__progress-track{height:4px;background:var(--c2g-theme-outline-variant, rgba(0, 0, 0, .08));margin:8px 18px 0;border-radius:2px;overflow:hidden}.c2g-cia__progress-fill{height:100%;background:var(--cia-accent);border-radius:2px;transition:width .7s cubic-bezier(.4,0,.2,1)}.c2g-cia__sections{display:grid;grid-template-columns:1fr;gap:0;margin-top:10px}@media(min-width:480px){.c2g-cia__sections{grid-template-columns:1fr 1fr;gap:0}}.c2g-cia__section{padding:0 18px 4px}.c2g-cia__section+.c2g-cia__section{padding-top:10px;border-top:1px solid var(--c2g-theme-outline-variant, var(--c2g-color-outline-variant))}@media(min-width:480px){.c2g-cia__section+.c2g-cia__section{padding-top:0;border-top:none;border-left:1px solid var(--c2g-theme-outline-variant, var(--c2g-color-outline-variant))}}.c2g-cia__section--personal{--sec-accent: #f97316}.c2g-cia__section--shared{--sec-accent: #3b82f6}.c2g-cia__section-header{display:flex;align-items:flex-start;gap:6px;margin-bottom:7px}.c2g-cia__section-titles{display:flex;flex-direction:column;gap:1px}.c2g-cia__section-icon{font-size:.85rem;line-height:1;width:22px;height:22px;border-radius:6px;display:flex;align-items:center;justify-content:center;flex-shrink:0}.c2g-cia__section-icon--personal{background:#f973161f}.c2g-cia__section-icon--shared{background:#3b82f61f}.c2g-cia__section-title{font-size:.72rem;font-weight:800;text-transform:uppercase;letter-spacing:.08em;color:var(--sec-accent, var(--c2g-theme-on-surface, var(--c2g-color-text-primary)))}.c2g-cia__section-hint{font-size:.62rem;font-weight:500;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted))}.c2g-cia__list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:5px}.c2g-cia__item{display:flex;align-items:center;gap:7px;font-size:.82rem;font-weight:600;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary))}.c2g-cia__item--personal .c2g-cia__item-dot{background:#f97316}.c2g-cia__item--shared .c2g-cia__item-dot{background:#3b82f6}.c2g-cia__item--shared{flex-direction:column;align-items:stretch;gap:3px}.c2g-cia__item--more{font-size:.72rem;font-weight:600;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted))}.c2g-cia__item-dot{width:6px;height:6px;border-radius:50%;flex-shrink:0;background:var(--cia-accent)}.c2g-cia__item-name{flex:1}.c2g-cia__item-missing{font-size:.68rem;font-weight:500;color:#f97316;background:#f973161a;border-radius:4px;padding:1px 5px;white-space:nowrap}.c2g-cia__shared-top{display:flex;align-items:center;gap:7px}.c2g-cia__shared-ratio{font-size:.72rem;font-weight:800;color:#3b82f6;background:#3b82f61a;border-radius:4px;padding:1px 6px;white-space:nowrap;margin-left:auto}.c2g-cia__shared-bar-track{height:3px;background:#3b82f626;border-radius:2px;overflow:hidden;margin-left:13px}.c2g-cia__shared-bar-fill{height:100%;background:#3b82f6;border-radius:2px;transition:width .6s cubic-bezier(.4,0,.2,1)}.c2g-cia__shared-covered{font-size:.68rem;font-weight:500;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));margin-left:13px}.c2g-cia__footer{margin-top:12px;padding:8px 18px;font-size:.72rem;font-weight:700;text-align:center;color:var(--cia-accent);background:var(--cia-bg);border-top:1px solid var(--c2g-theme-outline-variant, var(--c2g-color-outline-variant))}\n"] }]
2216
+ }], propDecorators: { data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: true }] }] } });
2217
+
2218
+ const BEAUFORT = [
2219
+ { max: 1, label: 'Windstille', emoji: '🌬️', color: '#22c55e' },
2220
+ { max: 5, label: 'Leichte Brise', emoji: '🌬️', color: '#84cc16' },
2221
+ { max: 11, label: 'Schwache Brise', emoji: '💨', color: '#84cc16' },
2222
+ { max: 19, label: 'Schwacher Wind', emoji: '💨', color: '#f59e0b' },
2223
+ { max: 28, label: 'Mäßiger Wind', emoji: '💨', color: '#f59e0b' },
2224
+ { max: 38, label: 'Frischer Wind', emoji: '🌀', color: '#f97316' },
2225
+ { max: 49, label: 'Starker Wind', emoji: '🌀', color: '#f97316' },
2226
+ { max: 61, label: 'Stürmisch', emoji: '⛈️', color: '#ef4444' },
2227
+ { max: 74, label: 'Sturm', emoji: '⛈️', color: '#ef4444' },
2228
+ { max: 88, label: 'Schwerer Sturm', emoji: '🌪️', color: '#dc2626' },
2229
+ { max: 102, label: 'Orkan', emoji: '🌪️', color: '#dc2626' },
2230
+ { max: 999, label: 'Schwerer Orkan', emoji: '🌪️', color: '#dc2626' },
2231
+ ];
2232
+ function beaufortFor(kmh) {
2233
+ return BEAUFORT.find(b => kmh <= b.max) ?? BEAUFORT[BEAUFORT.length - 1];
2234
+ }
2235
+ function directionLabel(deg) {
2236
+ const dirs = ['N', 'NO', 'O', 'SO', 'S', 'SW', 'W', 'NW'];
2237
+ return dirs[Math.round(deg / 45) % 8];
2238
+ }
2239
+ class WindIndicatorWidgetComponent {
2240
+ data = input.required(...(ngDevMode ? [{ debugName: "data" }] : []));
2241
+ days = computed(() => this.data().days.slice(0, 7), ...(ngDevMode ? [{ debugName: "days" }] : []));
2242
+ peak = computed(() => this.days().reduce((max, d) => d.windSpeed > max.windSpeed ? d : max, this.days()[0]), ...(ngDevMode ? [{ debugName: "peak" }] : []));
2243
+ peakBeaufort = computed(() => beaufortFor(this.peak()?.windSpeed ?? 0), ...(ngDevMode ? [{ debugName: "peakBeaufort" }] : []));
2244
+ overallRisk = computed(() => {
2245
+ const avg = this.days().reduce((s, d) => s + d.windSpeed, 0) / (this.days().length || 1);
2246
+ if (avg >= 50)
2247
+ return 'stormy';
2248
+ if (avg >= 28)
2249
+ return 'windy';
2250
+ if (avg >= 11)
2251
+ return 'breezy';
2252
+ return 'calm';
2253
+ }, ...(ngDevMode ? [{ debugName: "overallRisk" }] : []));
2254
+ enriched = computed(() => this.days().map(d => ({
2255
+ ...d,
2256
+ bf: beaufortFor(d.windSpeed),
2257
+ dirLabel: directionLabel(d.windDirection),
2258
+ // Arrow rotation: wind direction = where it comes FROM → arrow points that way
2259
+ arrowDeg: d.windDirection,
2260
+ barPct: Math.min(100, (d.windSpeed / 100) * 100),
2261
+ })), ...(ngDevMode ? [{ debugName: "enriched" }] : []));
2262
+ formatDate(iso) {
2263
+ return new Date(iso).toLocaleDateString('de-DE', { weekday: 'short', day: 'numeric' });
2264
+ }
2265
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: WindIndicatorWidgetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2266
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: WindIndicatorWidgetComponent, isStandalone: true, selector: "c2g-wind-indicator-widget", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<article class=\"c2g-wind\" [class]=\"'c2g-wind--' + overallRisk()\">\n\n <header class=\"c2g-wind__header\">\n <div class=\"c2g-wind__title-col\">\n <span class=\"c2g-wind__label\">\uD83D\uDCA8 Wind</span>\n @if (data().tourName) {\n <span class=\"c2g-wind__tour\">{{ data().tourName }}</span>\n }\n </div>\n @if (peak()) {\n <div class=\"c2g-wind__peak-badge\">\n <span class=\"c2g-wind__peak-emoji\">{{ peakBeaufort().emoji }}</span>\n <div class=\"c2g-wind__peak-text\">\n <span class=\"c2g-wind__peak-speed\">{{ peak().windSpeed }}<small>km/h</small></span>\n <span class=\"c2g-wind__peak-sublabel\">Spitze</span>\n </div>\n </div>\n }\n </header>\n\n <div class=\"c2g-wind__days\">\n @for (day of enriched(); track day.date) {\n <div class=\"c2g-wind__day\">\n\n <!-- Compass rose -->\n <svg class=\"c2g-wind__compass\" viewBox=\"0 0 40 40\" aria-hidden=\"true\">\n <circle cx=\"20\" cy=\"20\" r=\"18\" class=\"c2g-wind__compass-ring\"/>\n <text class=\"c2g-wind__compass-n\" x=\"20\" y=\"7\">N</text>\n <g [style.transform-origin]=\"'20px 20px'\" [style.transform]=\"'rotate(' + day.arrowDeg + 'deg)'\">\n <polygon points=\"20,4 23,18 20,16 17,18\" [attr.fill]=\"day.bf.color\"/>\n <polygon points=\"20,36 17,22 20,24 23,22\" fill=\"rgba(255,255,255,0.18)\"/>\n </g>\n <circle cx=\"20\" cy=\"20\" r=\"2.5\" [attr.fill]=\"day.bf.color\"/>\n </svg>\n\n <!-- Date -->\n <span class=\"c2g-wind__date\">{{ formatDate(day.date) }}</span>\n\n <!-- Speed bar -->\n <div class=\"c2g-wind__bar-track\">\n <div class=\"c2g-wind__bar-fill\"\n [style.width.%]=\"day.barPct\"\n [style.background]=\"day.bf.color\">\n </div>\n </div>\n\n <!-- Speed value -->\n <span class=\"c2g-wind__speed\" [style.color]=\"day.bf.color\">\n {{ day.windSpeed }}<small>km/h</small>\n </span>\n\n <!-- Beaufort + direction -->\n <span class=\"c2g-wind__meta\">{{ day.dirLabel }} \u00B7 {{ day.bf.label }}</span>\n\n </div>\n }\n </div>\n\n</article>\n", styles: [":host{display:block}.c2g-wind{background:var(--c2g-theme-surface, var(--c2g-color-surface));border:1px solid var(--c2g-theme-outline-variant, var(--c2g-color-outline-variant));border-radius:var(--c2g-radius-xl, 20px);padding:1.25rem 1.5rem 1rem;display:flex;flex-direction:column;gap:1rem;position:relative;overflow:hidden;transition:box-shadow .2s ease,transform .2s ease}.c2g-wind:hover{transform:translateY(-2px);box-shadow:0 8px 32px #0000003d}.c2g-wind:before{content:\"\";position:absolute;inset:0;background:radial-gradient(ellipse 80% 50% at 100% 0%,rgba(148,163,184,.04) 0%,transparent 70%);pointer-events:none}.c2g-wind--stormy:before{background:radial-gradient(ellipse 80% 50% at 100% 0%,rgba(239,68,68,.06) 0%,transparent 70%)}.c2g-wind--windy:before{background:radial-gradient(ellipse 80% 50% at 100% 0%,rgba(249,115,22,.06) 0%,transparent 70%)}.c2g-wind__header{display:flex;align-items:flex-start;justify-content:space-between;gap:.75rem}.c2g-wind__title-col{display:flex;flex-direction:column;gap:.125rem}.c2g-wind__label{font-size:.75rem;font-weight:700;text-transform:uppercase;letter-spacing:.08em;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-secondary))}.c2g-wind__tour{font-size:.8125rem;font-weight:600;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary));max-width:160px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.c2g-wind__peak-badge{display:flex;align-items:center;gap:.5rem;background:var(--c2g-theme-surface-container-low, var(--c2g-color-bg-base));border:1px solid var(--c2g-theme-outline-variant, var(--c2g-color-outline-variant));border-radius:12px;padding:.375rem .75rem;flex-shrink:0}.c2g-wind__peak-emoji{font-size:1.25rem;line-height:1}.c2g-wind__peak-text{display:flex;flex-direction:column;gap:0}.c2g-wind__peak-speed{font-size:.9375rem;font-weight:900;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary));font-variant-numeric:tabular-nums;line-height:1.1}.c2g-wind__peak-speed small{font-size:.5625rem;font-weight:600;opacity:.55;margin-left:1px}.c2g-wind__peak-sublabel{font-size:.5625rem;font-weight:700;text-transform:uppercase;letter-spacing:.07em;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted))}.c2g-wind__days{display:flex;flex-direction:column;gap:.5rem}.c2g-wind__day{display:grid;grid-template-columns:40px 72px 1fr 56px;grid-template-rows:auto auto;column-gap:.625rem;align-items:center}.c2g-wind__compass{grid-column:1;grid-row:1/3;width:40px;height:40px;display:block}.c2g-wind__compass-ring{fill:var(--c2g-theme-surface-container, var(--c2g-color-bg-secondary));stroke:var(--c2g-theme-outline-variant, var(--c2g-color-outline-variant));stroke-width:1}.c2g-wind__compass-n{fill:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));font-size:5.5px;font-weight:800;font-family:inherit;text-anchor:middle;dominant-baseline:middle}.c2g-wind__date{grid-column:2;grid-row:1;font-size:.6875rem;font-weight:700;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary));white-space:nowrap}.c2g-wind__bar-track{grid-column:3;grid-row:1;height:6px;border-radius:3px;background:var(--c2g-theme-outline-variant, var(--c2g-color-outline-variant));overflow:hidden}.c2g-wind__bar-fill{height:100%;min-width:3px;border-radius:3px;transition:width .7s cubic-bezier(.4,0,.2,1)}.c2g-wind__speed{grid-column:4;grid-row:1;font-size:.875rem;font-weight:800;text-align:right;white-space:nowrap;font-variant-numeric:tabular-nums}.c2g-wind__speed small{font-size:.5625rem;font-weight:600;opacity:.6;margin-left:1px}.c2g-wind__meta{grid-column:2/5;grid-row:2;font-size:.6875rem;font-weight:600;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2267
+ }
2268
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: WindIndicatorWidgetComponent, decorators: [{
2269
+ type: Component,
2270
+ args: [{ selector: 'c2g-wind-indicator-widget', standalone: true, imports: [], changeDetection: ChangeDetectionStrategy.OnPush, template: "<article class=\"c2g-wind\" [class]=\"'c2g-wind--' + overallRisk()\">\n\n <header class=\"c2g-wind__header\">\n <div class=\"c2g-wind__title-col\">\n <span class=\"c2g-wind__label\">\uD83D\uDCA8 Wind</span>\n @if (data().tourName) {\n <span class=\"c2g-wind__tour\">{{ data().tourName }}</span>\n }\n </div>\n @if (peak()) {\n <div class=\"c2g-wind__peak-badge\">\n <span class=\"c2g-wind__peak-emoji\">{{ peakBeaufort().emoji }}</span>\n <div class=\"c2g-wind__peak-text\">\n <span class=\"c2g-wind__peak-speed\">{{ peak().windSpeed }}<small>km/h</small></span>\n <span class=\"c2g-wind__peak-sublabel\">Spitze</span>\n </div>\n </div>\n }\n </header>\n\n <div class=\"c2g-wind__days\">\n @for (day of enriched(); track day.date) {\n <div class=\"c2g-wind__day\">\n\n <!-- Compass rose -->\n <svg class=\"c2g-wind__compass\" viewBox=\"0 0 40 40\" aria-hidden=\"true\">\n <circle cx=\"20\" cy=\"20\" r=\"18\" class=\"c2g-wind__compass-ring\"/>\n <text class=\"c2g-wind__compass-n\" x=\"20\" y=\"7\">N</text>\n <g [style.transform-origin]=\"'20px 20px'\" [style.transform]=\"'rotate(' + day.arrowDeg + 'deg)'\">\n <polygon points=\"20,4 23,18 20,16 17,18\" [attr.fill]=\"day.bf.color\"/>\n <polygon points=\"20,36 17,22 20,24 23,22\" fill=\"rgba(255,255,255,0.18)\"/>\n </g>\n <circle cx=\"20\" cy=\"20\" r=\"2.5\" [attr.fill]=\"day.bf.color\"/>\n </svg>\n\n <!-- Date -->\n <span class=\"c2g-wind__date\">{{ formatDate(day.date) }}</span>\n\n <!-- Speed bar -->\n <div class=\"c2g-wind__bar-track\">\n <div class=\"c2g-wind__bar-fill\"\n [style.width.%]=\"day.barPct\"\n [style.background]=\"day.bf.color\">\n </div>\n </div>\n\n <!-- Speed value -->\n <span class=\"c2g-wind__speed\" [style.color]=\"day.bf.color\">\n {{ day.windSpeed }}<small>km/h</small>\n </span>\n\n <!-- Beaufort + direction -->\n <span class=\"c2g-wind__meta\">{{ day.dirLabel }} \u00B7 {{ day.bf.label }}</span>\n\n </div>\n }\n </div>\n\n</article>\n", styles: [":host{display:block}.c2g-wind{background:var(--c2g-theme-surface, var(--c2g-color-surface));border:1px solid var(--c2g-theme-outline-variant, var(--c2g-color-outline-variant));border-radius:var(--c2g-radius-xl, 20px);padding:1.25rem 1.5rem 1rem;display:flex;flex-direction:column;gap:1rem;position:relative;overflow:hidden;transition:box-shadow .2s ease,transform .2s ease}.c2g-wind:hover{transform:translateY(-2px);box-shadow:0 8px 32px #0000003d}.c2g-wind:before{content:\"\";position:absolute;inset:0;background:radial-gradient(ellipse 80% 50% at 100% 0%,rgba(148,163,184,.04) 0%,transparent 70%);pointer-events:none}.c2g-wind--stormy:before{background:radial-gradient(ellipse 80% 50% at 100% 0%,rgba(239,68,68,.06) 0%,transparent 70%)}.c2g-wind--windy:before{background:radial-gradient(ellipse 80% 50% at 100% 0%,rgba(249,115,22,.06) 0%,transparent 70%)}.c2g-wind__header{display:flex;align-items:flex-start;justify-content:space-between;gap:.75rem}.c2g-wind__title-col{display:flex;flex-direction:column;gap:.125rem}.c2g-wind__label{font-size:.75rem;font-weight:700;text-transform:uppercase;letter-spacing:.08em;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-secondary))}.c2g-wind__tour{font-size:.8125rem;font-weight:600;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary));max-width:160px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.c2g-wind__peak-badge{display:flex;align-items:center;gap:.5rem;background:var(--c2g-theme-surface-container-low, var(--c2g-color-bg-base));border:1px solid var(--c2g-theme-outline-variant, var(--c2g-color-outline-variant));border-radius:12px;padding:.375rem .75rem;flex-shrink:0}.c2g-wind__peak-emoji{font-size:1.25rem;line-height:1}.c2g-wind__peak-text{display:flex;flex-direction:column;gap:0}.c2g-wind__peak-speed{font-size:.9375rem;font-weight:900;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary));font-variant-numeric:tabular-nums;line-height:1.1}.c2g-wind__peak-speed small{font-size:.5625rem;font-weight:600;opacity:.55;margin-left:1px}.c2g-wind__peak-sublabel{font-size:.5625rem;font-weight:700;text-transform:uppercase;letter-spacing:.07em;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted))}.c2g-wind__days{display:flex;flex-direction:column;gap:.5rem}.c2g-wind__day{display:grid;grid-template-columns:40px 72px 1fr 56px;grid-template-rows:auto auto;column-gap:.625rem;align-items:center}.c2g-wind__compass{grid-column:1;grid-row:1/3;width:40px;height:40px;display:block}.c2g-wind__compass-ring{fill:var(--c2g-theme-surface-container, var(--c2g-color-bg-secondary));stroke:var(--c2g-theme-outline-variant, var(--c2g-color-outline-variant));stroke-width:1}.c2g-wind__compass-n{fill:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));font-size:5.5px;font-weight:800;font-family:inherit;text-anchor:middle;dominant-baseline:middle}.c2g-wind__date{grid-column:2;grid-row:1;font-size:.6875rem;font-weight:700;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary));white-space:nowrap}.c2g-wind__bar-track{grid-column:3;grid-row:1;height:6px;border-radius:3px;background:var(--c2g-theme-outline-variant, var(--c2g-color-outline-variant));overflow:hidden}.c2g-wind__bar-fill{height:100%;min-width:3px;border-radius:3px;transition:width .7s cubic-bezier(.4,0,.2,1)}.c2g-wind__speed{grid-column:4;grid-row:1;font-size:.875rem;font-weight:800;text-align:right;white-space:nowrap;font-variant-numeric:tabular-nums}.c2g-wind__speed small{font-size:.5625rem;font-weight:600;opacity:.6;margin-left:1px}.c2g-wind__meta{grid-column:2/5;grid-row:2;font-size:.6875rem;font-weight:600;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n"] }]
2271
+ }], propDecorators: { data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: true }] }] } });
2272
+
2273
+ class TotalKmWidgetComponent {
2274
+ data = input.required(...(ngDevMode ? [{ debugName: "data" }] : []));
2275
+ displayKm = signal(0, ...(ngDevMode ? [{ debugName: "displayKm" }] : []));
2276
+ displayYearKm = signal(0, ...(ngDevMode ? [{ debugName: "displayYearKm" }] : []));
2277
+ rafId = 0;
2278
+ rafYearId = 0;
2279
+ constructor() {
2280
+ effect(() => {
2281
+ const target = this.data().totalKm;
2282
+ this.animateCount(target, this.displayKm, 'rafId');
2283
+ });
2284
+ effect(() => {
2285
+ const target = this.data().yearKm ?? 0;
2286
+ this.animateCount(target, this.displayYearKm, 'rafYearId');
2287
+ });
2288
+ }
2289
+ animateCount(target, sig, rafKey) {
2290
+ cancelAnimationFrame(this[rafKey]);
2291
+ const start = performance.now();
2292
+ const duration = 1400;
2293
+ const step = (now) => {
2294
+ const t = Math.min((now - start) / duration, 1);
2295
+ const eased = 1 - Math.pow(1 - t, 4);
2296
+ sig.set(Math.round(eased * target));
2297
+ if (t < 1)
2298
+ this[rafKey] = requestAnimationFrame(step);
2299
+ };
2300
+ this[rafKey] = requestAnimationFrame(step);
2301
+ }
2302
+ sparklinePath = computed(() => {
2303
+ const points = this.data().sparkline;
2304
+ if (!points || points.length < 2)
2305
+ return null;
2306
+ const W = 200, H = 48;
2307
+ const maxKm = Math.max(...points.map(p => p.km));
2308
+ const minKm = Math.min(...points.map(p => p.km));
2309
+ const range = maxKm - minKm || 1;
2310
+ const xs = points.map((_, i) => (i / (points.length - 1)) * W);
2311
+ const ys = points.map(p => H - ((p.km - minKm) / range) * (H - 8) - 2);
2312
+ let line = `M ${xs[0]} ${ys[0]}`;
2313
+ for (let i = 1; i < points.length; i++) {
2314
+ const cpx = (xs[i - 1] + xs[i]) / 2;
2315
+ line += ` C ${cpx} ${ys[i - 1]}, ${cpx} ${ys[i]}, ${xs[i]} ${ys[i]}`;
2316
+ }
2317
+ const area = `${line} L ${xs[xs.length - 1]} ${H} L ${xs[0]} ${H} Z`;
2318
+ return { line, area, lastX: xs[xs.length - 1], lastY: ys[ys.length - 1] };
2319
+ }, ...(ngDevMode ? [{ debugName: "sparklinePath" }] : []));
2320
+ ngOnDestroy() {
2321
+ cancelAnimationFrame(this.rafId);
2322
+ cancelAnimationFrame(this.rafYearId);
2323
+ }
2324
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: TotalKmWidgetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2325
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: TotalKmWidgetComponent, isStandalone: true, selector: "c2g-total-km-widget", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<article class=\"c2g-tkm\">\n <header class=\"c2g-tkm__header\">\n <span class=\"c2g-tkm__icon\" aria-hidden=\"true\">\uD83D\uDDFA\uFE0F</span>\n <div class=\"c2g-tkm__titles\">\n <h3 class=\"c2g-tkm__title\">Gesamt-Kilometer</h3>\n @if (data().tourCount) {\n <span class=\"c2g-tkm__sub\">{{ data().tourCount }} Touren</span>\n }\n </div>\n </header>\n\n <div class=\"c2g-tkm__hero\">\n <span class=\"c2g-tkm__value\">{{ displayKm() | number:'1.0-0' }}</span>\n <span class=\"c2g-tkm__unit\">km</span>\n </div>\n\n @if (data().yearKm) {\n <div class=\"c2g-tkm__year-row\">\n <span class=\"c2g-tkm__year-label\">Dieses Jahr</span>\n <span class=\"c2g-tkm__year-value\">{{ displayYearKm() | number:'1.0-0' }} km</span>\n </div>\n }\n\n @if (sparklinePath()) {\n <div class=\"c2g-tkm__chart\" aria-hidden=\"true\">\n <svg viewBox=\"0 0 200 48\" preserveAspectRatio=\"none\" class=\"c2g-tkm__svg\">\n <defs>\n <linearGradient id=\"tkm-area-grad\" x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\">\n <stop offset=\"0%\" stop-color=\"var(--c2g-theme-primary, #ff6b35)\" stop-opacity=\"0.35\"/>\n <stop offset=\"100%\" stop-color=\"var(--c2g-theme-primary, #ff6b35)\" stop-opacity=\"0\"/>\n </linearGradient>\n </defs>\n <path class=\"c2g-tkm__area\" [attr.d]=\"sparklinePath()!.area\" fill=\"url(#tkm-area-grad)\" />\n <path class=\"c2g-tkm__line\" [attr.d]=\"sparklinePath()!.line\" />\n <circle\n class=\"c2g-tkm__dot\"\n [attr.cx]=\"sparklinePath()!.lastX\"\n [attr.cy]=\"sparklinePath()!.lastY\"\n r=\"3\"\n />\n </svg>\n </div>\n }\n</article>\n", styles: [":host{display:block;font-family:var(--c2g-font-family-base, \"Quicksand\", sans-serif)}.c2g-tkm{background:var(--c2g-theme-surface, var(--c2g-color-surface));border:1px solid var(--c2g-theme-outline-variant, var(--c2g-color-outline-variant));box-shadow:var(--c2g-shadow-sm, 0 1px 4px rgba(0, 0, 0, .06));border-radius:var(--c2g-radius-xl, 20px);padding:18px 20px 0;display:flex;flex-direction:column;gap:10px;position:relative;overflow:hidden;transition:box-shadow .2s ease,transform .2s ease}.c2g-tkm:hover{box-shadow:var(--c2g-shadow-lg, 0 8px 28px rgba(0, 0, 0, .11));transform:translateY(-2px)}.c2g-tkm:before{content:\"\";position:absolute;inset:0;background:radial-gradient(ellipse 80% 60% at 100% 0%,rgba(255,107,53,.05) 0%,transparent 70%);pointer-events:none}.c2g-tkm__header{display:flex;align-items:center;gap:8px}.c2g-tkm__icon{font-size:1.25rem;line-height:1}.c2g-tkm__titles{display:flex;flex-direction:column;gap:2px}.c2g-tkm__title{margin:0;font-size:.72rem;font-weight:700;text-transform:uppercase;letter-spacing:.09em;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted))}.c2g-tkm__sub{font-size:.75rem;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));opacity:.7}.c2g-tkm__hero{display:flex;align-items:baseline;gap:5px}.c2g-tkm__value{font-size:3rem;font-weight:800;line-height:1;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary));font-variant-numeric:tabular-nums;letter-spacing:-.02em}.c2g-tkm__unit{font-size:1.25rem;font-weight:700;color:var(--c2g-theme-primary, var(--c2g-color-primary))}.c2g-tkm__year-row{display:flex;align-items:center;justify-content:space-between;padding:8px 12px;background:var(--c2g-theme-surface-container, var(--c2g-color-bg-secondary));border-radius:var(--c2g-radius-md, 10px)}.c2g-tkm__year-label{font-size:.75rem;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted))}.c2g-tkm__year-value{font-size:.875rem;font-weight:700;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary));font-variant-numeric:tabular-nums}.c2g-tkm__chart{height:52px;margin:0 -20px}.c2g-tkm__svg{width:100%;height:100%;display:block}.c2g-tkm__line{fill:none;stroke:var(--c2g-theme-primary, var(--c2g-color-primary));stroke-width:2;stroke-linecap:round;stroke-linejoin:round}.c2g-tkm__dot{fill:var(--c2g-theme-primary, var(--c2g-color-primary))}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "pipe", type: i1$2.DecimalPipe, name: "number" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2326
+ }
2327
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: TotalKmWidgetComponent, decorators: [{
2328
+ type: Component,
2329
+ args: [{ selector: 'c2g-total-km-widget', standalone: true, imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<article class=\"c2g-tkm\">\n <header class=\"c2g-tkm__header\">\n <span class=\"c2g-tkm__icon\" aria-hidden=\"true\">\uD83D\uDDFA\uFE0F</span>\n <div class=\"c2g-tkm__titles\">\n <h3 class=\"c2g-tkm__title\">Gesamt-Kilometer</h3>\n @if (data().tourCount) {\n <span class=\"c2g-tkm__sub\">{{ data().tourCount }} Touren</span>\n }\n </div>\n </header>\n\n <div class=\"c2g-tkm__hero\">\n <span class=\"c2g-tkm__value\">{{ displayKm() | number:'1.0-0' }}</span>\n <span class=\"c2g-tkm__unit\">km</span>\n </div>\n\n @if (data().yearKm) {\n <div class=\"c2g-tkm__year-row\">\n <span class=\"c2g-tkm__year-label\">Dieses Jahr</span>\n <span class=\"c2g-tkm__year-value\">{{ displayYearKm() | number:'1.0-0' }} km</span>\n </div>\n }\n\n @if (sparklinePath()) {\n <div class=\"c2g-tkm__chart\" aria-hidden=\"true\">\n <svg viewBox=\"0 0 200 48\" preserveAspectRatio=\"none\" class=\"c2g-tkm__svg\">\n <defs>\n <linearGradient id=\"tkm-area-grad\" x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\">\n <stop offset=\"0%\" stop-color=\"var(--c2g-theme-primary, #ff6b35)\" stop-opacity=\"0.35\"/>\n <stop offset=\"100%\" stop-color=\"var(--c2g-theme-primary, #ff6b35)\" stop-opacity=\"0\"/>\n </linearGradient>\n </defs>\n <path class=\"c2g-tkm__area\" [attr.d]=\"sparklinePath()!.area\" fill=\"url(#tkm-area-grad)\" />\n <path class=\"c2g-tkm__line\" [attr.d]=\"sparklinePath()!.line\" />\n <circle\n class=\"c2g-tkm__dot\"\n [attr.cx]=\"sparklinePath()!.lastX\"\n [attr.cy]=\"sparklinePath()!.lastY\"\n r=\"3\"\n />\n </svg>\n </div>\n }\n</article>\n", styles: [":host{display:block;font-family:var(--c2g-font-family-base, \"Quicksand\", sans-serif)}.c2g-tkm{background:var(--c2g-theme-surface, var(--c2g-color-surface));border:1px solid var(--c2g-theme-outline-variant, var(--c2g-color-outline-variant));box-shadow:var(--c2g-shadow-sm, 0 1px 4px rgba(0, 0, 0, .06));border-radius:var(--c2g-radius-xl, 20px);padding:18px 20px 0;display:flex;flex-direction:column;gap:10px;position:relative;overflow:hidden;transition:box-shadow .2s ease,transform .2s ease}.c2g-tkm:hover{box-shadow:var(--c2g-shadow-lg, 0 8px 28px rgba(0, 0, 0, .11));transform:translateY(-2px)}.c2g-tkm:before{content:\"\";position:absolute;inset:0;background:radial-gradient(ellipse 80% 60% at 100% 0%,rgba(255,107,53,.05) 0%,transparent 70%);pointer-events:none}.c2g-tkm__header{display:flex;align-items:center;gap:8px}.c2g-tkm__icon{font-size:1.25rem;line-height:1}.c2g-tkm__titles{display:flex;flex-direction:column;gap:2px}.c2g-tkm__title{margin:0;font-size:.72rem;font-weight:700;text-transform:uppercase;letter-spacing:.09em;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted))}.c2g-tkm__sub{font-size:.75rem;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));opacity:.7}.c2g-tkm__hero{display:flex;align-items:baseline;gap:5px}.c2g-tkm__value{font-size:3rem;font-weight:800;line-height:1;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary));font-variant-numeric:tabular-nums;letter-spacing:-.02em}.c2g-tkm__unit{font-size:1.25rem;font-weight:700;color:var(--c2g-theme-primary, var(--c2g-color-primary))}.c2g-tkm__year-row{display:flex;align-items:center;justify-content:space-between;padding:8px 12px;background:var(--c2g-theme-surface-container, var(--c2g-color-bg-secondary));border-radius:var(--c2g-radius-md, 10px)}.c2g-tkm__year-label{font-size:.75rem;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted))}.c2g-tkm__year-value{font-size:.875rem;font-weight:700;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary));font-variant-numeric:tabular-nums}.c2g-tkm__chart{height:52px;margin:0 -20px}.c2g-tkm__svg{width:100%;height:100%;display:block}.c2g-tkm__line{fill:none;stroke:var(--c2g-theme-primary, var(--c2g-color-primary));stroke-width:2;stroke-linecap:round;stroke-linejoin:round}.c2g-tkm__dot{fill:var(--c2g-theme-primary, var(--c2g-color-primary))}\n"] }]
2330
+ }], ctorParameters: () => [], propDecorators: { data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: true }] }] } });
2331
+
2332
+ const TYPE_CONFIG = {
2333
+ hiking: { label: 'Wandern', emoji: '🥾', color: '#ff6b35' },
2334
+ cycling: { label: 'Radfahren', emoji: '🚵', color: '#22c55e' },
2335
+ paddling: { label: 'Paddeln', emoji: '🛶', color: '#3b82f6' },
2336
+ climbing: { label: 'Klettern', emoji: '🧗', color: '#a855f7' },
2337
+ skiing: { label: 'Skifahren', emoji: '⛷️', color: '#06b6d4' },
2338
+ other: { label: 'Sonstige', emoji: '🏕️', color: '#94a3b8' },
2339
+ };
2340
+ const CIRCUMFERENCE = 2 * Math.PI * 52; // r=52
2341
+ class TourTypeSplitWidgetComponent {
2342
+ data = input.required(...(ngDevMode ? [{ debugName: "data" }] : []));
2343
+ segments = computed(() => {
2344
+ const entries = this.data().entries.filter(e => e.count > 0);
2345
+ const total = entries.reduce((s, e) => s + e.count, 0) || 1;
2346
+ const GAP = CIRCUMFERENCE * 0.012;
2347
+ let offset = 0;
2348
+ return entries.map(e => {
2349
+ const pct = e.count / total;
2350
+ const dash = Math.max(0, pct * CIRCUMFERENCE - GAP);
2351
+ const cfg = TYPE_CONFIG[e.type];
2352
+ const seg = {
2353
+ type: e.type,
2354
+ label: cfg.label,
2355
+ emoji: cfg.emoji,
2356
+ color: cfg.color,
2357
+ count: e.count,
2358
+ km: e.km ?? 0,
2359
+ pct,
2360
+ offset,
2361
+ dash,
2362
+ };
2363
+ offset += pct * CIRCUMFERENCE;
2364
+ return seg;
2365
+ });
2366
+ }, ...(ngDevMode ? [{ debugName: "segments" }] : []));
2367
+ dominantSegment = computed(() => {
2368
+ const segs = this.segments();
2369
+ return segs.length > 0 ? segs.reduce((a, b) => (a.count > b.count ? a : b)) : null;
2370
+ }, ...(ngDevMode ? [{ debugName: "dominantSegment" }] : []));
2371
+ circumference = CIRCUMFERENCE;
2372
+ trackByType(_, seg) {
2373
+ return seg.type;
2374
+ }
2375
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: TourTypeSplitWidgetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2376
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: TourTypeSplitWidgetComponent, isStandalone: true, selector: "c2g-tour-type-split-widget", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<article class=\"c2g-tts\">\n <header class=\"c2g-tts__header\">\n <span class=\"c2g-tts__icon\" aria-hidden=\"true\">\uD83E\uDDED</span>\n <div class=\"c2g-tts__titles\">\n <h3 class=\"c2g-tts__title\">Tour-Typen</h3>\n <span class=\"c2g-tts__sub\">{{ data().totalTours }} Touren gesamt</span>\n </div>\n </header>\n\n <div class=\"c2g-tts__body\">\n <div class=\"c2g-tts__donut-wrap\" aria-hidden=\"true\">\n <svg viewBox=\"0 0 128 128\" class=\"c2g-tts__donut\">\n <circle cx=\"64\" cy=\"64\" r=\"52\" class=\"c2g-tts__track\"/>\n @for (seg of segments(); track trackByType($index, seg)) {\n <circle\n cx=\"64\" cy=\"64\" r=\"52\"\n class=\"c2g-tts__arc\"\n [style.stroke]=\"seg.color\"\n [style.stroke-dasharray]=\"seg.dash + ' ' + circumference\"\n [style.stroke-dashoffset]=\"-seg.offset\"\n />\n }\n </svg>\n @if (dominantSegment(); as dom) {\n <div class=\"c2g-tts__center\">\n <span class=\"c2g-tts__center-emoji\">{{ dom.emoji }}</span>\n <span class=\"c2g-tts__center-label\">{{ dom.label }}</span>\n </div>\n }\n </div>\n\n <ul class=\"c2g-tts__legend\" role=\"list\">\n @for (seg of segments(); track trackByType($index, seg)) {\n <li class=\"c2g-tts__legend-item\">\n <span class=\"c2g-tts__legend-dot\" [style.background]=\"seg.color\"></span>\n <span class=\"c2g-tts__legend-emoji\">{{ seg.emoji }}</span>\n <span class=\"c2g-tts__legend-name\">{{ seg.label }}</span>\n <span class=\"c2g-tts__legend-count\">{{ seg.count }}</span>\n <span class=\"c2g-tts__legend-pct\">{{ (seg.pct * 100) | number:'1.0-0' }}%</span>\n </li>\n }\n </ul>\n </div>\n</article>\n", styles: [":host{display:block;font-family:var(--c2g-font-family-base, \"Quicksand\", sans-serif)}.c2g-tts{background:var(--c2g-theme-surface, var(--c2g-color-surface));border:1px solid var(--c2g-theme-outline-variant, var(--c2g-color-outline-variant));box-shadow:var(--c2g-shadow-sm, 0 1px 4px rgba(0, 0, 0, .06));border-radius:var(--c2g-radius-xl, 20px);padding:18px 20px;display:flex;flex-direction:column;gap:14px;transition:box-shadow .2s ease,transform .2s ease}.c2g-tts:hover{box-shadow:var(--c2g-shadow-lg, 0 8px 28px rgba(0, 0, 0, .11));transform:translateY(-2px)}.c2g-tts__header{display:flex;align-items:center;gap:8px}.c2g-tts__icon{font-size:1.25rem;line-height:1}.c2g-tts__titles{display:flex;flex-direction:column;gap:2px}.c2g-tts__title{margin:0;font-size:.72rem;font-weight:700;text-transform:uppercase;letter-spacing:.09em;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted))}.c2g-tts__sub{font-size:.75rem;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));opacity:.7}.c2g-tts__body{display:flex;gap:16px;align-items:center}.c2g-tts__donut-wrap{position:relative;flex-shrink:0;width:120px;height:120px}.c2g-tts__donut{width:100%;height:100%;transform:rotate(-90deg)}.c2g-tts__track{fill:none;stroke:var(--c2g-theme-outline-variant, var(--c2g-color-outline-variant));stroke-width:18}.c2g-tts__arc{fill:none;stroke-width:18;stroke-linecap:butt;transition:stroke-dasharray .6s cubic-bezier(.4,0,.2,1)}.c2g-tts__center{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:2px}.c2g-tts__center-emoji{font-size:1.5rem;line-height:1}.c2g-tts__center-label{font-size:.6rem;font-weight:700;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));text-align:center;text-transform:uppercase;letter-spacing:.05em}.c2g-tts__legend{list-style:none;margin:0;padding:0;flex:1;display:flex;flex-direction:column;gap:6px}.c2g-tts__legend-item{display:flex;align-items:center;gap:6px}.c2g-tts__legend-dot{width:8px;height:8px;border-radius:50%;flex-shrink:0}.c2g-tts__legend-emoji{font-size:.875rem;line-height:1;flex-shrink:0}.c2g-tts__legend-name{font-size:.8125rem;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary));flex:1}.c2g-tts__legend-count{font-size:.8125rem;font-weight:700;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary));font-variant-numeric:tabular-nums}.c2g-tts__legend-pct{font-size:.75rem;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));font-variant-numeric:tabular-nums;min-width:2.5rem;text-align:right}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "pipe", type: i1$2.DecimalPipe, name: "number" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2377
+ }
2378
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: TourTypeSplitWidgetComponent, decorators: [{
2379
+ type: Component,
2380
+ args: [{ selector: 'c2g-tour-type-split-widget', standalone: true, imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<article class=\"c2g-tts\">\n <header class=\"c2g-tts__header\">\n <span class=\"c2g-tts__icon\" aria-hidden=\"true\">\uD83E\uDDED</span>\n <div class=\"c2g-tts__titles\">\n <h3 class=\"c2g-tts__title\">Tour-Typen</h3>\n <span class=\"c2g-tts__sub\">{{ data().totalTours }} Touren gesamt</span>\n </div>\n </header>\n\n <div class=\"c2g-tts__body\">\n <div class=\"c2g-tts__donut-wrap\" aria-hidden=\"true\">\n <svg viewBox=\"0 0 128 128\" class=\"c2g-tts__donut\">\n <circle cx=\"64\" cy=\"64\" r=\"52\" class=\"c2g-tts__track\"/>\n @for (seg of segments(); track trackByType($index, seg)) {\n <circle\n cx=\"64\" cy=\"64\" r=\"52\"\n class=\"c2g-tts__arc\"\n [style.stroke]=\"seg.color\"\n [style.stroke-dasharray]=\"seg.dash + ' ' + circumference\"\n [style.stroke-dashoffset]=\"-seg.offset\"\n />\n }\n </svg>\n @if (dominantSegment(); as dom) {\n <div class=\"c2g-tts__center\">\n <span class=\"c2g-tts__center-emoji\">{{ dom.emoji }}</span>\n <span class=\"c2g-tts__center-label\">{{ dom.label }}</span>\n </div>\n }\n </div>\n\n <ul class=\"c2g-tts__legend\" role=\"list\">\n @for (seg of segments(); track trackByType($index, seg)) {\n <li class=\"c2g-tts__legend-item\">\n <span class=\"c2g-tts__legend-dot\" [style.background]=\"seg.color\"></span>\n <span class=\"c2g-tts__legend-emoji\">{{ seg.emoji }}</span>\n <span class=\"c2g-tts__legend-name\">{{ seg.label }}</span>\n <span class=\"c2g-tts__legend-count\">{{ seg.count }}</span>\n <span class=\"c2g-tts__legend-pct\">{{ (seg.pct * 100) | number:'1.0-0' }}%</span>\n </li>\n }\n </ul>\n </div>\n</article>\n", styles: [":host{display:block;font-family:var(--c2g-font-family-base, \"Quicksand\", sans-serif)}.c2g-tts{background:var(--c2g-theme-surface, var(--c2g-color-surface));border:1px solid var(--c2g-theme-outline-variant, var(--c2g-color-outline-variant));box-shadow:var(--c2g-shadow-sm, 0 1px 4px rgba(0, 0, 0, .06));border-radius:var(--c2g-radius-xl, 20px);padding:18px 20px;display:flex;flex-direction:column;gap:14px;transition:box-shadow .2s ease,transform .2s ease}.c2g-tts:hover{box-shadow:var(--c2g-shadow-lg, 0 8px 28px rgba(0, 0, 0, .11));transform:translateY(-2px)}.c2g-tts__header{display:flex;align-items:center;gap:8px}.c2g-tts__icon{font-size:1.25rem;line-height:1}.c2g-tts__titles{display:flex;flex-direction:column;gap:2px}.c2g-tts__title{margin:0;font-size:.72rem;font-weight:700;text-transform:uppercase;letter-spacing:.09em;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted))}.c2g-tts__sub{font-size:.75rem;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));opacity:.7}.c2g-tts__body{display:flex;gap:16px;align-items:center}.c2g-tts__donut-wrap{position:relative;flex-shrink:0;width:120px;height:120px}.c2g-tts__donut{width:100%;height:100%;transform:rotate(-90deg)}.c2g-tts__track{fill:none;stroke:var(--c2g-theme-outline-variant, var(--c2g-color-outline-variant));stroke-width:18}.c2g-tts__arc{fill:none;stroke-width:18;stroke-linecap:butt;transition:stroke-dasharray .6s cubic-bezier(.4,0,.2,1)}.c2g-tts__center{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:2px}.c2g-tts__center-emoji{font-size:1.5rem;line-height:1}.c2g-tts__center-label{font-size:.6rem;font-weight:700;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));text-align:center;text-transform:uppercase;letter-spacing:.05em}.c2g-tts__legend{list-style:none;margin:0;padding:0;flex:1;display:flex;flex-direction:column;gap:6px}.c2g-tts__legend-item{display:flex;align-items:center;gap:6px}.c2g-tts__legend-dot{width:8px;height:8px;border-radius:50%;flex-shrink:0}.c2g-tts__legend-emoji{font-size:.875rem;line-height:1;flex-shrink:0}.c2g-tts__legend-name{font-size:.8125rem;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary));flex:1}.c2g-tts__legend-count{font-size:.8125rem;font-weight:700;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary));font-variant-numeric:tabular-nums}.c2g-tts__legend-pct{font-size:.75rem;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));font-variant-numeric:tabular-nums;min-width:2.5rem;text-align:right}\n"] }]
2381
+ }], propDecorators: { data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: true }] }] } });
2382
+
2383
+ const MONTH_LABELS = ['Jan', 'Feb', 'Mär', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez'];
2384
+ class TourRhythmWidgetComponent {
2385
+ data = input.required(...(ngDevMode ? [{ debugName: "data" }] : []));
2386
+ cells = computed(() => {
2387
+ const weeks = this.data().weeks;
2388
+ let prevMonth = -1;
2389
+ return weeks.map((w, i) => {
2390
+ const d = new Date(w.weekStart);
2391
+ const month = d.getMonth();
2392
+ const monthLabel = month !== prevMonth ? MONTH_LABELS[month] : null;
2393
+ prevMonth = month;
2394
+ return { ...w, col: i, monthLabel };
2395
+ });
2396
+ }, ...(ngDevMode ? [{ debugName: "cells" }] : []));
2397
+ totalCols = computed(() => this.data().weeks.length, ...(ngDevMode ? [{ debugName: "totalCols" }] : []));
2398
+ levelColors = ['#1e293b', '#166534', '#16a34a', '#4ade80', '#86efac'];
2399
+ levelColor(level) {
2400
+ return this.levelColors[level];
2401
+ }
2402
+ trackByCol(_, cell) {
2403
+ return cell.col;
2404
+ }
2405
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: TourRhythmWidgetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2406
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: TourRhythmWidgetComponent, isStandalone: true, selector: "c2g-tour-rhythm-widget", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<article class=\"c2g-trh\">\n <header class=\"c2g-trh__header\">\n <span class=\"c2g-trh__icon\" aria-hidden=\"true\">\uD83D\uDCC5</span>\n <div class=\"c2g-trh__titles\">\n <h3 class=\"c2g-trh__title\">Tour-Rhythmus</h3>\n <span class=\"c2g-trh__sub\">Letzte 52 Wochen</span>\n </div>\n <div class=\"c2g-trh__stats\">\n @if (data().currentStreakWeeks) {\n <span class=\"c2g-trh__streak\">\uD83D\uDD25 {{ data().currentStreakWeeks }} Wochen-Streak</span>\n }\n </div>\n </header>\n\n <div class=\"c2g-trh__grid-wrap\" aria-label=\"Aktivit\u00E4ts-Heatmap der letzten 52 Wochen\" role=\"img\">\n <div class=\"c2g-trh__month-labels\" aria-hidden=\"true\">\n @for (cell of cells(); track cell.col) {\n @if (cell.monthLabel) {\n <span class=\"c2g-trh__month-label\" [style.grid-column]=\"cell.col + 1\">\n {{ cell.monthLabel }}\n </span>\n }\n }\n </div>\n <div class=\"c2g-trh__grid\">\n @for (cell of cells(); track trackByCol($index, cell)) {\n <div\n class=\"c2g-trh__cell c2g-trh__cell--level-{{ cell.level }}\"\n [style.background]=\"levelColor(cell.level)\"\n [title]=\"cell.tourName ? cell.tourName + (cell.km ? ' \u00B7 ' + cell.km + ' km' : '') : cell.weekStart\"\n ></div>\n }\n </div>\n </div>\n\n <div class=\"c2g-trh__legend\" aria-hidden=\"true\">\n <span class=\"c2g-trh__legend-label\">Weniger</span>\n @for (l of [0, 1, 2, 3, 4]; track l) {\n <div class=\"c2g-trh__legend-cell\" [style.background]=\"levelColors[l]\"></div>\n }\n <span class=\"c2g-trh__legend-label\">Mehr</span>\n </div>\n</article>\n", styles: [":host{display:block;font-family:var(--c2g-font-family-base, \"Quicksand\", sans-serif)}.c2g-trh{background:var(--c2g-theme-surface, var(--c2g-color-surface));border:1px solid var(--c2g-theme-outline-variant, var(--c2g-color-outline-variant));box-shadow:var(--c2g-shadow-sm, 0 1px 4px rgba(0, 0, 0, .06));border-radius:var(--c2g-radius-xl, 20px);padding:18px 20px 14px;display:flex;flex-direction:column;gap:12px;transition:box-shadow .2s ease,transform .2s ease}.c2g-trh:hover{box-shadow:var(--c2g-shadow-lg, 0 8px 28px rgba(0, 0, 0, .11));transform:translateY(-2px)}.c2g-trh__header{display:flex;align-items:center;gap:8px}.c2g-trh__icon{font-size:1.25rem;line-height:1}.c2g-trh__titles{flex:1;display:flex;flex-direction:column;gap:2px}.c2g-trh__title{margin:0;font-size:.72rem;font-weight:700;text-transform:uppercase;letter-spacing:.09em;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted))}.c2g-trh__sub{font-size:.75rem;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));opacity:.7}.c2g-trh__streak{font-size:.72rem;font-weight:700;color:var(--c2g-color-warning, #f59e0b);background:#f59e0b1a;border:1px solid rgba(245,158,11,.2);padding:3px 8px;border-radius:999px;white-space:nowrap}.c2g-trh__grid-wrap{overflow-x:auto;overflow-y:hidden;scrollbar-width:none}.c2g-trh__grid-wrap::-webkit-scrollbar{display:none}.c2g-trh__month-labels{display:grid;grid-template-columns:repeat(52,12px);gap:2px;margin-bottom:4px;min-width:max-content}.c2g-trh__month-label{font-size:.6rem;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));white-space:nowrap;opacity:.6}.c2g-trh__grid{display:grid;grid-template-columns:repeat(52,12px);gap:2px;min-width:max-content}.c2g-trh__cell{width:12px;height:12px;border-radius:2px;transition:transform .15s ease,filter .15s ease;cursor:default}.c2g-trh__cell:hover{transform:scale(1.3);filter:brightness(1.2);z-index:1;position:relative}.c2g-trh__legend{display:flex;align-items:center;gap:4px}.c2g-trh__legend-label{font-size:.65rem;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));opacity:.6}.c2g-trh__legend-cell{width:10px;height:10px;border-radius:2px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2407
+ }
2408
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: TourRhythmWidgetComponent, decorators: [{
2409
+ type: Component,
2410
+ args: [{ selector: 'c2g-tour-rhythm-widget', standalone: true, imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<article class=\"c2g-trh\">\n <header class=\"c2g-trh__header\">\n <span class=\"c2g-trh__icon\" aria-hidden=\"true\">\uD83D\uDCC5</span>\n <div class=\"c2g-trh__titles\">\n <h3 class=\"c2g-trh__title\">Tour-Rhythmus</h3>\n <span class=\"c2g-trh__sub\">Letzte 52 Wochen</span>\n </div>\n <div class=\"c2g-trh__stats\">\n @if (data().currentStreakWeeks) {\n <span class=\"c2g-trh__streak\">\uD83D\uDD25 {{ data().currentStreakWeeks }} Wochen-Streak</span>\n }\n </div>\n </header>\n\n <div class=\"c2g-trh__grid-wrap\" aria-label=\"Aktivit\u00E4ts-Heatmap der letzten 52 Wochen\" role=\"img\">\n <div class=\"c2g-trh__month-labels\" aria-hidden=\"true\">\n @for (cell of cells(); track cell.col) {\n @if (cell.monthLabel) {\n <span class=\"c2g-trh__month-label\" [style.grid-column]=\"cell.col + 1\">\n {{ cell.monthLabel }}\n </span>\n }\n }\n </div>\n <div class=\"c2g-trh__grid\">\n @for (cell of cells(); track trackByCol($index, cell)) {\n <div\n class=\"c2g-trh__cell c2g-trh__cell--level-{{ cell.level }}\"\n [style.background]=\"levelColor(cell.level)\"\n [title]=\"cell.tourName ? cell.tourName + (cell.km ? ' \u00B7 ' + cell.km + ' km' : '') : cell.weekStart\"\n ></div>\n }\n </div>\n </div>\n\n <div class=\"c2g-trh__legend\" aria-hidden=\"true\">\n <span class=\"c2g-trh__legend-label\">Weniger</span>\n @for (l of [0, 1, 2, 3, 4]; track l) {\n <div class=\"c2g-trh__legend-cell\" [style.background]=\"levelColors[l]\"></div>\n }\n <span class=\"c2g-trh__legend-label\">Mehr</span>\n </div>\n</article>\n", styles: [":host{display:block;font-family:var(--c2g-font-family-base, \"Quicksand\", sans-serif)}.c2g-trh{background:var(--c2g-theme-surface, var(--c2g-color-surface));border:1px solid var(--c2g-theme-outline-variant, var(--c2g-color-outline-variant));box-shadow:var(--c2g-shadow-sm, 0 1px 4px rgba(0, 0, 0, .06));border-radius:var(--c2g-radius-xl, 20px);padding:18px 20px 14px;display:flex;flex-direction:column;gap:12px;transition:box-shadow .2s ease,transform .2s ease}.c2g-trh:hover{box-shadow:var(--c2g-shadow-lg, 0 8px 28px rgba(0, 0, 0, .11));transform:translateY(-2px)}.c2g-trh__header{display:flex;align-items:center;gap:8px}.c2g-trh__icon{font-size:1.25rem;line-height:1}.c2g-trh__titles{flex:1;display:flex;flex-direction:column;gap:2px}.c2g-trh__title{margin:0;font-size:.72rem;font-weight:700;text-transform:uppercase;letter-spacing:.09em;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted))}.c2g-trh__sub{font-size:.75rem;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));opacity:.7}.c2g-trh__streak{font-size:.72rem;font-weight:700;color:var(--c2g-color-warning, #f59e0b);background:#f59e0b1a;border:1px solid rgba(245,158,11,.2);padding:3px 8px;border-radius:999px;white-space:nowrap}.c2g-trh__grid-wrap{overflow-x:auto;overflow-y:hidden;scrollbar-width:none}.c2g-trh__grid-wrap::-webkit-scrollbar{display:none}.c2g-trh__month-labels{display:grid;grid-template-columns:repeat(52,12px);gap:2px;margin-bottom:4px;min-width:max-content}.c2g-trh__month-label{font-size:.6rem;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));white-space:nowrap;opacity:.6}.c2g-trh__grid{display:grid;grid-template-columns:repeat(52,12px);gap:2px;min-width:max-content}.c2g-trh__cell{width:12px;height:12px;border-radius:2px;transition:transform .15s ease,filter .15s ease;cursor:default}.c2g-trh__cell:hover{transform:scale(1.3);filter:brightness(1.2);z-index:1;position:relative}.c2g-trh__legend{display:flex;align-items:center;gap:4px}.c2g-trh__legend-label{font-size:.65rem;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));opacity:.6}.c2g-trh__legend-cell{width:10px;height:10px;border-radius:2px}\n"] }]
2411
+ }], propDecorators: { data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: true }] }] } });
2412
+
2413
+ const SEASON_CONFIG = {
2414
+ spring: { label: 'Frühling', emoji: '🌸', color: '#84cc16' },
2415
+ summer: { label: 'Sommer', emoji: '☀️', color: '#f59e0b' },
2416
+ autumn: { label: 'Herbst', emoji: '🍂', color: '#ef4444' },
2417
+ winter: { label: 'Winter', emoji: '❄️', color: '#3b82f6' },
2418
+ };
2419
+ const CX = 64, CY = 64, R_OUTER = 56, R_INNER = 28;
2420
+ function polarToXY(cx, cy, r, angleDeg) {
2421
+ const rad = ((angleDeg - 90) * Math.PI) / 180;
2422
+ return [cx + r * Math.cos(rad), cy + r * Math.sin(rad)];
2423
+ }
2424
+ function donutSegmentPath(cx, cy, ro, ri, start, end) {
2425
+ const [ox1, oy1] = polarToXY(cx, cy, ro, start);
2426
+ const [ox2, oy2] = polarToXY(cx, cy, ro, end);
2427
+ const [ix1, iy1] = polarToXY(cx, cy, ri, end);
2428
+ const [ix2, iy2] = polarToXY(cx, cy, ri, start);
2429
+ const large = end - start > 180 ? 1 : 0;
2430
+ return [
2431
+ `M ${ox1} ${oy1}`,
2432
+ `A ${ro} ${ro} 0 ${large} 1 ${ox2} ${oy2}`,
2433
+ `L ${ix1} ${iy1}`,
2434
+ `A ${ri} ${ri} 0 ${large} 0 ${ix2} ${iy2}`,
2435
+ 'Z',
2436
+ ].join(' ');
2437
+ }
2438
+ const SEASON_ORDER = ['spring', 'summer', 'autumn', 'winter'];
2439
+ class SeasonDnaWidgetComponent {
2440
+ data = input.required(...(ngDevMode ? [{ debugName: "data" }] : []));
2441
+ segments = computed(() => {
2442
+ const entries = this.data().entries;
2443
+ const total = entries.reduce((s, e) => s + e.tourCount, 0) || 1;
2444
+ const GAP = 3;
2445
+ let angle = 0;
2446
+ return SEASON_ORDER.map(season => {
2447
+ const entry = entries.find(e => e.season === season);
2448
+ const count = entry?.tourCount ?? 0;
2449
+ const pct = count / total;
2450
+ const span = Math.max(0, pct * 360 - GAP);
2451
+ const start = angle;
2452
+ const end = angle + span;
2453
+ angle += pct * 360;
2454
+ const cfg = SEASON_CONFIG[season];
2455
+ const mid = (start + end) / 2;
2456
+ const [lx, ly] = polarToXY(CX, CY, (R_OUTER + R_INNER) / 2, mid);
2457
+ return {
2458
+ season,
2459
+ label: cfg.label,
2460
+ emoji: cfg.emoji,
2461
+ color: cfg.color,
2462
+ tourCount: count,
2463
+ km: entry?.km ?? 0,
2464
+ nights: entry?.nights ?? 0,
2465
+ pct,
2466
+ startAngle: start,
2467
+ endAngle: end,
2468
+ pathD: span > 2 ? donutSegmentPath(CX, CY, R_OUTER, R_INNER, start, end) : '',
2469
+ labelX: lx,
2470
+ labelY: ly,
2471
+ };
2472
+ }).filter(s => s.pct > 0);
2473
+ }, ...(ngDevMode ? [{ debugName: "segments" }] : []));
2474
+ dominantSeason = computed(() => {
2475
+ const segs = this.segments();
2476
+ if (segs.length === 0)
2477
+ return null;
2478
+ const dom = segs.reduce((a, b) => (a.tourCount > b.tourCount ? a : b));
2479
+ return SEASON_CONFIG[dom.season];
2480
+ }, ...(ngDevMode ? [{ debugName: "dominantSeason" }] : []));
2481
+ trackBySeason(_, seg) {
2482
+ return seg.season;
2483
+ }
2484
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: SeasonDnaWidgetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2485
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: SeasonDnaWidgetComponent, isStandalone: true, selector: "c2g-season-dna-widget", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<article class=\"c2g-sdn\">\n <header class=\"c2g-sdn__header\">\n <span class=\"c2g-sdn__icon\" aria-hidden=\"true\">\uD83C\uDF0D</span>\n <div class=\"c2g-sdn__titles\">\n <h3 class=\"c2g-sdn__title\">Saison-DNA</h3>\n <span class=\"c2g-sdn__sub\">{{ data().totalTours }} Touren analysiert</span>\n </div>\n </header>\n\n <div class=\"c2g-sdn__body\">\n <div class=\"c2g-sdn__chart-wrap\" aria-hidden=\"true\">\n <svg viewBox=\"0 0 128 128\" class=\"c2g-sdn__svg\">\n @for (seg of segments(); track trackBySeason($index, seg)) {\n @if (seg.pathD) {\n <path\n class=\"c2g-sdn__segment\"\n [attr.d]=\"seg.pathD\"\n [style.fill]=\"seg.color\"\n />\n }\n }\n </svg>\n @if (dominantSeason(); as dom) {\n <div class=\"c2g-sdn__center\">\n <span class=\"c2g-sdn__center-emoji\">{{ dom.emoji }}</span>\n <span class=\"c2g-sdn__center-label\">{{ dom.label }}</span>\n </div>\n }\n </div>\n\n <ul class=\"c2g-sdn__legend\" role=\"list\">\n @for (seg of segments(); track trackBySeason($index, seg)) {\n <li class=\"c2g-sdn__legend-item\">\n <span class=\"c2g-sdn__legend-dot\" [style.background]=\"seg.color\"></span>\n <span class=\"c2g-sdn__legend-emoji\">{{ seg.emoji }}</span>\n <div class=\"c2g-sdn__legend-text\">\n <span class=\"c2g-sdn__legend-name\">{{ seg.label }}</span>\n <span class=\"c2g-sdn__legend-detail\">\n {{ seg.tourCount }} Tour{{ seg.tourCount !== 1 ? 'en' : '' }}\n @if (seg.km) { \u00B7 {{ seg.km | number:'1.0-0' }} km }\n </span>\n </div>\n <span class=\"c2g-sdn__legend-pct\">{{ (seg.pct * 100) | number:'1.0-0' }}%</span>\n </li>\n }\n </ul>\n </div>\n</article>\n", styles: [":host{display:block;font-family:var(--c2g-font-family-base, \"Quicksand\", sans-serif)}.c2g-sdn{background:var(--c2g-theme-surface, var(--c2g-color-surface));border:1px solid var(--c2g-theme-outline-variant, var(--c2g-color-outline-variant));box-shadow:var(--c2g-shadow-sm, 0 1px 4px rgba(0, 0, 0, .06));border-radius:var(--c2g-radius-xl, 20px);padding:18px 20px;display:flex;flex-direction:column;gap:14px;transition:box-shadow .2s ease,transform .2s ease}.c2g-sdn:hover{box-shadow:var(--c2g-shadow-lg, 0 8px 28px rgba(0, 0, 0, .11));transform:translateY(-2px)}.c2g-sdn__header{display:flex;align-items:center;gap:8px}.c2g-sdn__icon{font-size:1.25rem;line-height:1}.c2g-sdn__titles{display:flex;flex-direction:column;gap:2px}.c2g-sdn__title{margin:0;font-size:.72rem;font-weight:700;text-transform:uppercase;letter-spacing:.09em;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted))}.c2g-sdn__sub{font-size:.75rem;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));opacity:.7}.c2g-sdn__body{display:flex;gap:16px;align-items:center}.c2g-sdn__chart-wrap{position:relative;flex-shrink:0;width:120px;height:120px}.c2g-sdn__svg{width:100%;height:100%;display:block}.c2g-sdn__segment{transition:opacity .2s ease;opacity:.9}.c2g-sdn__segment:hover{opacity:1;filter:brightness(1.1)}.c2g-sdn__center{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:2px;pointer-events:none}.c2g-sdn__center-emoji{font-size:1.5rem;line-height:1}.c2g-sdn__center-label{font-size:.6rem;font-weight:700;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));text-align:center;text-transform:uppercase;letter-spacing:.05em}.c2g-sdn__legend{list-style:none;margin:0;padding:0;flex:1;display:flex;flex-direction:column;gap:8px}.c2g-sdn__legend-item{display:flex;align-items:center;gap:6px}.c2g-sdn__legend-dot{width:8px;height:8px;border-radius:50%;flex-shrink:0}.c2g-sdn__legend-emoji{font-size:.875rem;line-height:1;flex-shrink:0}.c2g-sdn__legend-text{flex:1;display:flex;flex-direction:column;gap:1px}.c2g-sdn__legend-name{font-size:.8125rem;font-weight:600;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary))}.c2g-sdn__legend-detail{font-size:.6875rem;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));opacity:.7}.c2g-sdn__legend-pct{font-size:.75rem;font-weight:700;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));font-variant-numeric:tabular-nums;min-width:2.25rem;text-align:right}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "pipe", type: i1$2.DecimalPipe, name: "number" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2486
+ }
2487
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: SeasonDnaWidgetComponent, decorators: [{
2488
+ type: Component,
2489
+ args: [{ selector: 'c2g-season-dna-widget', standalone: true, imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<article class=\"c2g-sdn\">\n <header class=\"c2g-sdn__header\">\n <span class=\"c2g-sdn__icon\" aria-hidden=\"true\">\uD83C\uDF0D</span>\n <div class=\"c2g-sdn__titles\">\n <h3 class=\"c2g-sdn__title\">Saison-DNA</h3>\n <span class=\"c2g-sdn__sub\">{{ data().totalTours }} Touren analysiert</span>\n </div>\n </header>\n\n <div class=\"c2g-sdn__body\">\n <div class=\"c2g-sdn__chart-wrap\" aria-hidden=\"true\">\n <svg viewBox=\"0 0 128 128\" class=\"c2g-sdn__svg\">\n @for (seg of segments(); track trackBySeason($index, seg)) {\n @if (seg.pathD) {\n <path\n class=\"c2g-sdn__segment\"\n [attr.d]=\"seg.pathD\"\n [style.fill]=\"seg.color\"\n />\n }\n }\n </svg>\n @if (dominantSeason(); as dom) {\n <div class=\"c2g-sdn__center\">\n <span class=\"c2g-sdn__center-emoji\">{{ dom.emoji }}</span>\n <span class=\"c2g-sdn__center-label\">{{ dom.label }}</span>\n </div>\n }\n </div>\n\n <ul class=\"c2g-sdn__legend\" role=\"list\">\n @for (seg of segments(); track trackBySeason($index, seg)) {\n <li class=\"c2g-sdn__legend-item\">\n <span class=\"c2g-sdn__legend-dot\" [style.background]=\"seg.color\"></span>\n <span class=\"c2g-sdn__legend-emoji\">{{ seg.emoji }}</span>\n <div class=\"c2g-sdn__legend-text\">\n <span class=\"c2g-sdn__legend-name\">{{ seg.label }}</span>\n <span class=\"c2g-sdn__legend-detail\">\n {{ seg.tourCount }} Tour{{ seg.tourCount !== 1 ? 'en' : '' }}\n @if (seg.km) { \u00B7 {{ seg.km | number:'1.0-0' }} km }\n </span>\n </div>\n <span class=\"c2g-sdn__legend-pct\">{{ (seg.pct * 100) | number:'1.0-0' }}%</span>\n </li>\n }\n </ul>\n </div>\n</article>\n", styles: [":host{display:block;font-family:var(--c2g-font-family-base, \"Quicksand\", sans-serif)}.c2g-sdn{background:var(--c2g-theme-surface, var(--c2g-color-surface));border:1px solid var(--c2g-theme-outline-variant, var(--c2g-color-outline-variant));box-shadow:var(--c2g-shadow-sm, 0 1px 4px rgba(0, 0, 0, .06));border-radius:var(--c2g-radius-xl, 20px);padding:18px 20px;display:flex;flex-direction:column;gap:14px;transition:box-shadow .2s ease,transform .2s ease}.c2g-sdn:hover{box-shadow:var(--c2g-shadow-lg, 0 8px 28px rgba(0, 0, 0, .11));transform:translateY(-2px)}.c2g-sdn__header{display:flex;align-items:center;gap:8px}.c2g-sdn__icon{font-size:1.25rem;line-height:1}.c2g-sdn__titles{display:flex;flex-direction:column;gap:2px}.c2g-sdn__title{margin:0;font-size:.72rem;font-weight:700;text-transform:uppercase;letter-spacing:.09em;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted))}.c2g-sdn__sub{font-size:.75rem;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));opacity:.7}.c2g-sdn__body{display:flex;gap:16px;align-items:center}.c2g-sdn__chart-wrap{position:relative;flex-shrink:0;width:120px;height:120px}.c2g-sdn__svg{width:100%;height:100%;display:block}.c2g-sdn__segment{transition:opacity .2s ease;opacity:.9}.c2g-sdn__segment:hover{opacity:1;filter:brightness(1.1)}.c2g-sdn__center{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:2px;pointer-events:none}.c2g-sdn__center-emoji{font-size:1.5rem;line-height:1}.c2g-sdn__center-label{font-size:.6rem;font-weight:700;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));text-align:center;text-transform:uppercase;letter-spacing:.05em}.c2g-sdn__legend{list-style:none;margin:0;padding:0;flex:1;display:flex;flex-direction:column;gap:8px}.c2g-sdn__legend-item{display:flex;align-items:center;gap:6px}.c2g-sdn__legend-dot{width:8px;height:8px;border-radius:50%;flex-shrink:0}.c2g-sdn__legend-emoji{font-size:.875rem;line-height:1;flex-shrink:0}.c2g-sdn__legend-text{flex:1;display:flex;flex-direction:column;gap:1px}.c2g-sdn__legend-name{font-size:.8125rem;font-weight:600;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary))}.c2g-sdn__legend-detail{font-size:.6875rem;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));opacity:.7}.c2g-sdn__legend-pct{font-size:.75rem;font-weight:700;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));font-variant-numeric:tabular-nums;min-width:2.25rem;text-align:right}\n"] }]
2490
+ }], propDecorators: { data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: true }] }] } });
2491
+
2492
+ class WeightHistoryWidgetComponent {
2493
+ data = input.required(...(ngDevMode ? [{ debugName: "data" }] : []));
2494
+ points = computed(() => this.data().points.slice(-12), ...(ngDevMode ? [{ debugName: "points" }] : []));
2495
+ sparklinePath = computed(() => {
2496
+ const pts = this.points();
2497
+ if (pts.length < 2)
2498
+ return null;
2499
+ const W = 200, H = 48;
2500
+ const weights = pts.map(p => p.weightG);
2501
+ const maxW = Math.max(...weights);
2502
+ const minW = Math.min(...weights);
2503
+ const range = maxW - minW || 1;
2504
+ const xs = pts.map((_, i) => (i / (pts.length - 1)) * W);
2505
+ const ys = pts.map(p => H - ((p.weightG - minW) / range) * (H - 8) - 2);
2506
+ let line = `M ${xs[0]} ${ys[0]}`;
2507
+ for (let i = 1; i < pts.length; i++) {
2508
+ const cpx = (xs[i - 1] + xs[i]) / 2;
2509
+ line += ` C ${cpx} ${ys[i - 1]}, ${cpx} ${ys[i]}, ${xs[i]} ${ys[i]}`;
2510
+ }
2511
+ const area = `${line} L ${xs[xs.length - 1]} ${H} L ${xs[0]} ${H} Z`;
2512
+ const improving = pts[pts.length - 1].weightG <= pts[0].weightG;
2513
+ return { line, area, lastX: xs[xs.length - 1], lastY: ys[ys.length - 1], improving };
2514
+ }, ...(ngDevMode ? [{ debugName: "sparklinePath" }] : []));
2515
+ trend = computed(() => {
2516
+ const pts = this.points();
2517
+ if (pts.length < 2)
2518
+ return null;
2519
+ const first = pts[0].weightG;
2520
+ const last = pts[pts.length - 1].weightG;
2521
+ const diffG = last - first;
2522
+ const pct = Math.round((diffG / first) * 100);
2523
+ return { diffG, pct, improving: diffG < 0 };
2524
+ }, ...(ngDevMode ? [{ debugName: "trend" }] : []));
2525
+ formatKg(g) {
2526
+ return (g / 1000).toFixed(2);
2527
+ }
2528
+ formatDate(iso) {
2529
+ return new Date(iso).toLocaleDateString('de-DE', { month: 'short', year: '2-digit' });
2530
+ }
2531
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: WeightHistoryWidgetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2532
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: WeightHistoryWidgetComponent, isStandalone: true, selector: "c2g-weight-history-widget", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<article class=\"c2g-wh\">\n <header class=\"c2g-wh__header\">\n <span class=\"c2g-wh__icon\">\u2696\uFE0F</span>\n <div class=\"c2g-wh__titles\">\n <h3 class=\"c2g-wh__title\">Gewichts-Historie</h3>\n @if (data().points.length) {\n <span class=\"c2g-wh__sub\">{{ data().points.length }} Touren</span>\n }\n </div>\n @if (trend(); as t) {\n <span class=\"c2g-wh__trend\" [class.c2g-wh__trend--good]=\"t.improving\" [class.c2g-wh__trend--bad]=\"!t.improving\">\n {{ t.improving ? '\u2193' : '\u2191' }} {{ t.pct | number:'1.0-0' }}%\n </span>\n }\n </header>\n\n <div class=\"c2g-wh__hero\">\n @if (data().latestG) {\n <span class=\"c2g-wh__value\">{{ formatKg(data().latestG!) }}</span>\n <span class=\"c2g-wh__unit\">kg</span>\n <span class=\"c2g-wh__label\">aktuell</span>\n }\n @if (data().bestG) {\n <div class=\"c2g-wh__best\">\n <span class=\"c2g-wh__best-icon\">\uD83C\uDFC6</span>\n <span class=\"c2g-wh__best-val\">{{ formatKg(data().bestG!) }} kg</span>\n <span class=\"c2g-wh__best-label\">Rekord</span>\n </div>\n }\n </div>\n\n @if (sparklinePath(); as sp) {\n <div class=\"c2g-wh__chart\" aria-hidden=\"true\">\n <svg viewBox=\"0 0 200 48\" preserveAspectRatio=\"none\" class=\"c2g-wh__svg\">\n <defs>\n <linearGradient id=\"wh-grad\" x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\">\n <stop offset=\"0%\" [attr.stop-color]=\"sp.improving ? '#22c55e' : '#f97316'\" stop-opacity=\"0.3\"/>\n <stop offset=\"100%\" [attr.stop-color]=\"sp.improving ? '#22c55e' : '#f97316'\" stop-opacity=\"0\"/>\n </linearGradient>\n </defs>\n <path [attr.d]=\"sp.area\" fill=\"url(#wh-grad)\"/>\n <path class=\"c2g-wh__line\" [attr.d]=\"sp.line\"\n [style.stroke]=\"sp.improving ? '#22c55e' : '#f97316'\"/>\n <circle class=\"c2g-wh__dot\" [attr.cx]=\"sp.lastX\" [attr.cy]=\"sp.lastY\" r=\"3\"\n [style.fill]=\"sp.improving ? '#22c55e' : '#f97316'\"/>\n </svg>\n </div>\n }\n\n <div class=\"c2g-wh__dates\">\n @if (points().length >= 2) {\n <span>{{ formatDate(points()[0].date) }}</span>\n <span>{{ formatDate(points()[points().length - 1].date) }}</span>\n }\n </div>\n</article>\n", styles: [":host{display:block;font-family:var(--c2g-font-family-base, \"Quicksand\", sans-serif)}.c2g-wh{background:var(--c2g-theme-surface, var(--c2g-color-surface));border:1px solid var(--c2g-theme-outline-variant, var(--c2g-color-outline-variant));box-shadow:var(--c2g-shadow-sm, 0 1px 4px rgba(0, 0, 0, .06));border-radius:var(--c2g-radius-xl, 20px);padding:18px 20px 0;display:flex;flex-direction:column;gap:10px;overflow:hidden;transition:box-shadow .2s ease,transform .2s ease}.c2g-wh:hover{box-shadow:var(--c2g-shadow-lg, 0 8px 28px rgba(0, 0, 0, .11));transform:translateY(-2px)}.c2g-wh__header{display:flex;align-items:center;gap:8px}.c2g-wh__icon{font-size:1.25rem;line-height:1}.c2g-wh__titles{flex:1;display:flex;flex-direction:column;gap:2px}.c2g-wh__title{margin:0;font-size:.72rem;font-weight:700;text-transform:uppercase;letter-spacing:.09em;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted))}.c2g-wh__sub{font-size:.75rem;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));opacity:.7}.c2g-wh__trend{font-size:.8rem;font-weight:800;padding:3px 8px;border-radius:999px}.c2g-wh__trend--good{color:#22c55e;background:#22c55e1a}.c2g-wh__trend--bad{color:#f97316;background:#f973161a}.c2g-wh__hero{display:flex;align-items:baseline;gap:6px}.c2g-wh__value{font-size:2.5rem;font-weight:800;line-height:1;letter-spacing:-.02em;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary));font-variant-numeric:tabular-nums}.c2g-wh__unit{font-size:1.125rem;font-weight:700;color:var(--c2g-theme-primary, var(--c2g-color-primary))}.c2g-wh__label{font-size:.75rem;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted))}.c2g-wh__best{display:flex;align-items:center;gap:5px;margin-left:auto;padding:4px 10px;border-radius:var(--c2g-radius-md, 10px);background:var(--c2g-theme-surface-container, var(--c2g-color-bg-secondary))}.c2g-wh__best-icon{font-size:.875rem}.c2g-wh__best-val{font-size:.8125rem;font-weight:700;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary))}.c2g-wh__best-label{font-size:.6875rem;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted))}.c2g-wh__chart{height:52px;margin:0 -20px}.c2g-wh__svg{width:100%;height:100%;display:block}.c2g-wh__line{fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}.c2g-wh__dates{display:flex;justify-content:space-between;padding:0 0 10px;font-size:.625rem;font-weight:700;text-transform:uppercase;letter-spacing:.04em;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));opacity:.6}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "pipe", type: i1$2.DecimalPipe, name: "number" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2533
+ }
2534
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: WeightHistoryWidgetComponent, decorators: [{
2535
+ type: Component,
2536
+ args: [{ selector: 'c2g-weight-history-widget', standalone: true, imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<article class=\"c2g-wh\">\n <header class=\"c2g-wh__header\">\n <span class=\"c2g-wh__icon\">\u2696\uFE0F</span>\n <div class=\"c2g-wh__titles\">\n <h3 class=\"c2g-wh__title\">Gewichts-Historie</h3>\n @if (data().points.length) {\n <span class=\"c2g-wh__sub\">{{ data().points.length }} Touren</span>\n }\n </div>\n @if (trend(); as t) {\n <span class=\"c2g-wh__trend\" [class.c2g-wh__trend--good]=\"t.improving\" [class.c2g-wh__trend--bad]=\"!t.improving\">\n {{ t.improving ? '\u2193' : '\u2191' }} {{ t.pct | number:'1.0-0' }}%\n </span>\n }\n </header>\n\n <div class=\"c2g-wh__hero\">\n @if (data().latestG) {\n <span class=\"c2g-wh__value\">{{ formatKg(data().latestG!) }}</span>\n <span class=\"c2g-wh__unit\">kg</span>\n <span class=\"c2g-wh__label\">aktuell</span>\n }\n @if (data().bestG) {\n <div class=\"c2g-wh__best\">\n <span class=\"c2g-wh__best-icon\">\uD83C\uDFC6</span>\n <span class=\"c2g-wh__best-val\">{{ formatKg(data().bestG!) }} kg</span>\n <span class=\"c2g-wh__best-label\">Rekord</span>\n </div>\n }\n </div>\n\n @if (sparklinePath(); as sp) {\n <div class=\"c2g-wh__chart\" aria-hidden=\"true\">\n <svg viewBox=\"0 0 200 48\" preserveAspectRatio=\"none\" class=\"c2g-wh__svg\">\n <defs>\n <linearGradient id=\"wh-grad\" x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\">\n <stop offset=\"0%\" [attr.stop-color]=\"sp.improving ? '#22c55e' : '#f97316'\" stop-opacity=\"0.3\"/>\n <stop offset=\"100%\" [attr.stop-color]=\"sp.improving ? '#22c55e' : '#f97316'\" stop-opacity=\"0\"/>\n </linearGradient>\n </defs>\n <path [attr.d]=\"sp.area\" fill=\"url(#wh-grad)\"/>\n <path class=\"c2g-wh__line\" [attr.d]=\"sp.line\"\n [style.stroke]=\"sp.improving ? '#22c55e' : '#f97316'\"/>\n <circle class=\"c2g-wh__dot\" [attr.cx]=\"sp.lastX\" [attr.cy]=\"sp.lastY\" r=\"3\"\n [style.fill]=\"sp.improving ? '#22c55e' : '#f97316'\"/>\n </svg>\n </div>\n }\n\n <div class=\"c2g-wh__dates\">\n @if (points().length >= 2) {\n <span>{{ formatDate(points()[0].date) }}</span>\n <span>{{ formatDate(points()[points().length - 1].date) }}</span>\n }\n </div>\n</article>\n", styles: [":host{display:block;font-family:var(--c2g-font-family-base, \"Quicksand\", sans-serif)}.c2g-wh{background:var(--c2g-theme-surface, var(--c2g-color-surface));border:1px solid var(--c2g-theme-outline-variant, var(--c2g-color-outline-variant));box-shadow:var(--c2g-shadow-sm, 0 1px 4px rgba(0, 0, 0, .06));border-radius:var(--c2g-radius-xl, 20px);padding:18px 20px 0;display:flex;flex-direction:column;gap:10px;overflow:hidden;transition:box-shadow .2s ease,transform .2s ease}.c2g-wh:hover{box-shadow:var(--c2g-shadow-lg, 0 8px 28px rgba(0, 0, 0, .11));transform:translateY(-2px)}.c2g-wh__header{display:flex;align-items:center;gap:8px}.c2g-wh__icon{font-size:1.25rem;line-height:1}.c2g-wh__titles{flex:1;display:flex;flex-direction:column;gap:2px}.c2g-wh__title{margin:0;font-size:.72rem;font-weight:700;text-transform:uppercase;letter-spacing:.09em;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted))}.c2g-wh__sub{font-size:.75rem;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));opacity:.7}.c2g-wh__trend{font-size:.8rem;font-weight:800;padding:3px 8px;border-radius:999px}.c2g-wh__trend--good{color:#22c55e;background:#22c55e1a}.c2g-wh__trend--bad{color:#f97316;background:#f973161a}.c2g-wh__hero{display:flex;align-items:baseline;gap:6px}.c2g-wh__value{font-size:2.5rem;font-weight:800;line-height:1;letter-spacing:-.02em;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary));font-variant-numeric:tabular-nums}.c2g-wh__unit{font-size:1.125rem;font-weight:700;color:var(--c2g-theme-primary, var(--c2g-color-primary))}.c2g-wh__label{font-size:.75rem;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted))}.c2g-wh__best{display:flex;align-items:center;gap:5px;margin-left:auto;padding:4px 10px;border-radius:var(--c2g-radius-md, 10px);background:var(--c2g-theme-surface-container, var(--c2g-color-bg-secondary))}.c2g-wh__best-icon{font-size:.875rem}.c2g-wh__best-val{font-size:.8125rem;font-weight:700;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary))}.c2g-wh__best-label{font-size:.6875rem;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted))}.c2g-wh__chart{height:52px;margin:0 -20px}.c2g-wh__svg{width:100%;height:100%;display:block}.c2g-wh__line{fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}.c2g-wh__dates{display:flex;justify-content:space-between;padding:0 0 10px;font-size:.625rem;font-weight:700;text-transform:uppercase;letter-spacing:.04em;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));opacity:.6}\n"] }]
2537
+ }], propDecorators: { data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: true }] }] } });
2538
+
2539
+ class GearValueWidgetComponent {
2540
+ data = input.required(...(ngDevMode ? [{ debugName: "data" }] : []));
2541
+ topCategories = computed(() => [...(this.data().categories ?? [])]
2542
+ .sort((a, b) => b.value - a.value)
2543
+ .slice(0, 5), ...(ngDevMode ? [{ debugName: "topCategories" }] : []));
2544
+ maxCatValue = computed(() => Math.max(...(this.data().categories ?? []).map(c => c.value), 1), ...(ngDevMode ? [{ debugName: "maxCatValue" }] : []));
2545
+ formattedTotal = computed(() => {
2546
+ const v = this.data().totalValue;
2547
+ if (v >= 1000)
2548
+ return `${(v / 1000).toFixed(1)}k`;
2549
+ return v.toFixed(0);
2550
+ }, ...(ngDevMode ? [{ debugName: "formattedTotal" }] : []));
2551
+ formatValue(v) {
2552
+ if (v >= 1000)
2553
+ return `${(v / 1000).toFixed(1)}k`;
2554
+ return v.toFixed(0);
2555
+ }
2556
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: GearValueWidgetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2557
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: GearValueWidgetComponent, isStandalone: true, selector: "c2g-gear-value-widget", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<article class=\"c2g-gv\">\n <header class=\"c2g-gv__header\">\n <span class=\"c2g-gv__icon\">\uD83D\uDCB0</span>\n <div class=\"c2g-gv__titles\">\n <h3 class=\"c2g-gv__title\">Gear-Wert</h3>\n <span class=\"c2g-gv__sub\">{{ data().itemCount }} Items</span>\n </div>\n </header>\n\n <div class=\"c2g-gv__hero\">\n <span class=\"c2g-gv__value\">{{ formattedTotal() }}</span>\n <span class=\"c2g-gv__currency\">{{ data().currency }}</span>\n </div>\n\n @if (topCategories().length) {\n <ul class=\"c2g-gv__cats\" role=\"list\">\n @for (cat of topCategories(); track cat.label) {\n <li class=\"c2g-gv__cat\">\n <div class=\"c2g-gv__cat-header\">\n <span class=\"c2g-gv__cat-name\">{{ cat.label }}</span>\n <span class=\"c2g-gv__cat-value\">{{ formatValue(cat.value) }} {{ data().currency }}</span>\n </div>\n <div class=\"c2g-gv__bar-track\">\n <div class=\"c2g-gv__bar-fill\"\n [style.width.%]=\"(cat.value / maxCatValue()) * 100\">\n </div>\n </div>\n </li>\n }\n </ul>\n }\n</article>\n", styles: [":host{display:block;font-family:var(--c2g-font-family-base, \"Quicksand\", sans-serif)}.c2g-gv{background:var(--c2g-theme-surface, var(--c2g-color-surface));border:1px solid var(--c2g-theme-outline-variant, var(--c2g-color-outline-variant));box-shadow:var(--c2g-shadow-sm, 0 1px 4px rgba(0, 0, 0, .06));border-radius:var(--c2g-radius-xl, 20px);padding:18px 20px 16px;display:flex;flex-direction:column;gap:12px;transition:box-shadow .2s ease,transform .2s ease}.c2g-gv:hover{box-shadow:var(--c2g-shadow-lg, 0 8px 28px rgba(0, 0, 0, .11));transform:translateY(-2px)}.c2g-gv__header{display:flex;align-items:center;gap:8px}.c2g-gv__icon{font-size:1.25rem;line-height:1}.c2g-gv__titles{display:flex;flex-direction:column;gap:2px}.c2g-gv__title{margin:0;font-size:.72rem;font-weight:700;text-transform:uppercase;letter-spacing:.09em;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted))}.c2g-gv__sub{font-size:.75rem;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));opacity:.7}.c2g-gv__hero{display:flex;align-items:baseline;gap:5px}.c2g-gv__value{font-size:2.75rem;font-weight:800;line-height:1;letter-spacing:-.02em;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary));font-variant-numeric:tabular-nums}.c2g-gv__currency{font-size:1.125rem;font-weight:700;color:var(--c2g-theme-primary, var(--c2g-color-primary))}.c2g-gv__cats{list-style:none;margin:0;padding:10px 0 0;display:flex;flex-direction:column;gap:8px;border-top:1px solid var(--c2g-theme-outline-variant, var(--c2g-color-outline-variant))}.c2g-gv__cat{display:flex;flex-direction:column;gap:4px}.c2g-gv__cat-header{display:flex;justify-content:space-between}.c2g-gv__cat-name{font-size:.8rem;font-weight:600;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary))}.c2g-gv__cat-value{font-size:.8rem;font-weight:700;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));font-variant-numeric:tabular-nums}.c2g-gv__bar-track{height:6px;border-radius:3px;background:var(--c2g-theme-outline-variant, var(--c2g-color-outline-variant));overflow:hidden}.c2g-gv__bar-fill{height:100%;border-radius:3px;background:var(--c2g-theme-primary, var(--c2g-color-primary));transition:width .7s cubic-bezier(.4,0,.2,1)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2558
+ }
2559
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: GearValueWidgetComponent, decorators: [{
2560
+ type: Component,
2561
+ args: [{ selector: 'c2g-gear-value-widget', standalone: true, imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<article class=\"c2g-gv\">\n <header class=\"c2g-gv__header\">\n <span class=\"c2g-gv__icon\">\uD83D\uDCB0</span>\n <div class=\"c2g-gv__titles\">\n <h3 class=\"c2g-gv__title\">Gear-Wert</h3>\n <span class=\"c2g-gv__sub\">{{ data().itemCount }} Items</span>\n </div>\n </header>\n\n <div class=\"c2g-gv__hero\">\n <span class=\"c2g-gv__value\">{{ formattedTotal() }}</span>\n <span class=\"c2g-gv__currency\">{{ data().currency }}</span>\n </div>\n\n @if (topCategories().length) {\n <ul class=\"c2g-gv__cats\" role=\"list\">\n @for (cat of topCategories(); track cat.label) {\n <li class=\"c2g-gv__cat\">\n <div class=\"c2g-gv__cat-header\">\n <span class=\"c2g-gv__cat-name\">{{ cat.label }}</span>\n <span class=\"c2g-gv__cat-value\">{{ formatValue(cat.value) }} {{ data().currency }}</span>\n </div>\n <div class=\"c2g-gv__bar-track\">\n <div class=\"c2g-gv__bar-fill\"\n [style.width.%]=\"(cat.value / maxCatValue()) * 100\">\n </div>\n </div>\n </li>\n }\n </ul>\n }\n</article>\n", styles: [":host{display:block;font-family:var(--c2g-font-family-base, \"Quicksand\", sans-serif)}.c2g-gv{background:var(--c2g-theme-surface, var(--c2g-color-surface));border:1px solid var(--c2g-theme-outline-variant, var(--c2g-color-outline-variant));box-shadow:var(--c2g-shadow-sm, 0 1px 4px rgba(0, 0, 0, .06));border-radius:var(--c2g-radius-xl, 20px);padding:18px 20px 16px;display:flex;flex-direction:column;gap:12px;transition:box-shadow .2s ease,transform .2s ease}.c2g-gv:hover{box-shadow:var(--c2g-shadow-lg, 0 8px 28px rgba(0, 0, 0, .11));transform:translateY(-2px)}.c2g-gv__header{display:flex;align-items:center;gap:8px}.c2g-gv__icon{font-size:1.25rem;line-height:1}.c2g-gv__titles{display:flex;flex-direction:column;gap:2px}.c2g-gv__title{margin:0;font-size:.72rem;font-weight:700;text-transform:uppercase;letter-spacing:.09em;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted))}.c2g-gv__sub{font-size:.75rem;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));opacity:.7}.c2g-gv__hero{display:flex;align-items:baseline;gap:5px}.c2g-gv__value{font-size:2.75rem;font-weight:800;line-height:1;letter-spacing:-.02em;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary));font-variant-numeric:tabular-nums}.c2g-gv__currency{font-size:1.125rem;font-weight:700;color:var(--c2g-theme-primary, var(--c2g-color-primary))}.c2g-gv__cats{list-style:none;margin:0;padding:10px 0 0;display:flex;flex-direction:column;gap:8px;border-top:1px solid var(--c2g-theme-outline-variant, var(--c2g-color-outline-variant))}.c2g-gv__cat{display:flex;flex-direction:column;gap:4px}.c2g-gv__cat-header{display:flex;justify-content:space-between}.c2g-gv__cat-name{font-size:.8rem;font-weight:600;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary))}.c2g-gv__cat-value{font-size:.8rem;font-weight:700;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));font-variant-numeric:tabular-nums}.c2g-gv__bar-track{height:6px;border-radius:3px;background:var(--c2g-theme-outline-variant, var(--c2g-color-outline-variant));overflow:hidden}.c2g-gv__bar-fill{height:100%;border-radius:3px;background:var(--c2g-theme-primary, var(--c2g-color-primary));transition:width .7s cubic-bezier(.4,0,.2,1)}\n"] }]
2562
+ }], propDecorators: { data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: true }] }] } });
2563
+
2564
+ const DEFAULT_COLORS = [
2565
+ '#ff6b35', '#22c55e', '#3b82f6', '#f59e0b', '#a855f7',
2566
+ '#ec4899', '#06b6d4', '#84cc16', '#f97316', '#6b7280',
2567
+ ];
2568
+ class WeightBreakdownWidgetComponent {
2569
+ data = input.required(...(ngDevMode ? [{ debugName: "data" }] : []));
2570
+ entries = computed(() => {
2571
+ const total = this.data().totalG || 1;
2572
+ let offset = 0;
2573
+ return [...this.data().entries]
2574
+ .sort((a, b) => b.weightG - a.weightG)
2575
+ .map((e, i) => {
2576
+ const pct = (e.weightG / total) * 100;
2577
+ const entry = {
2578
+ ...e,
2579
+ pct,
2580
+ color: e.color ?? DEFAULT_COLORS[i % DEFAULT_COLORS.length],
2581
+ barOffset: offset,
2582
+ };
2583
+ offset += pct;
2584
+ return entry;
2585
+ });
2586
+ }, ...(ngDevMode ? [{ debugName: "entries" }] : []));
2587
+ totalKg = computed(() => (this.data().totalG / 1000).toFixed(2), ...(ngDevMode ? [{ debugName: "totalKg" }] : []));
2588
+ // SVG stacked horizontal bar — single rect per entry using stroke-dasharray trick
2589
+ circumference = 100; // we work in percentage units
2590
+ formatKg(g) {
2591
+ if (g >= 1000)
2592
+ return `${(g / 1000).toFixed(2)} kg`;
2593
+ return `${g} g`;
2594
+ }
2595
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: WeightBreakdownWidgetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2596
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: WeightBreakdownWidgetComponent, isStandalone: true, selector: "c2g-weight-breakdown-widget", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<article class=\"c2g-wb\">\n <header class=\"c2g-wb__header\">\n <span class=\"c2g-wb__icon\">\uD83C\uDFCB\uFE0F</span>\n <div class=\"c2g-wb__titles\">\n <h3 class=\"c2g-wb__title\">Gewichts-Breakdown</h3>\n <span class=\"c2g-wb__sub\">{{ totalKg() }} kg gesamt</span>\n </div>\n </header>\n\n <!-- Stacked horizontal bar -->\n <div class=\"c2g-wb__stacked\" aria-hidden=\"true\">\n @for (e of entries(); track e.category) {\n <div\n class=\"c2g-wb__stack-seg\"\n [style.width.%]=\"e.pct\"\n [style.background]=\"e.color\"\n [title]=\"e.category + ': ' + (e.pct | number:'1.0-1') + '%'\"\n ></div>\n }\n </div>\n\n <!-- Legend rows -->\n <ul class=\"c2g-wb__legend\" role=\"list\">\n @for (e of entries(); track e.category) {\n <li class=\"c2g-wb__row\">\n <span class=\"c2g-wb__dot\" [style.background]=\"e.color\"></span>\n <span class=\"c2g-wb__cat\">{{ e.category }}</span>\n <div class=\"c2g-wb__bar-track\">\n <div class=\"c2g-wb__bar-fill\" [style.width.%]=\"e.pct\" [style.background]=\"e.color\"></div>\n </div>\n <span class=\"c2g-wb__pct\">{{ e.pct | number:'1.0-1' }}%</span>\n <span class=\"c2g-wb__weight\">{{ formatKg(e.weightG) }}</span>\n </li>\n }\n </ul>\n</article>\n", styles: [":host{display:block;font-family:var(--c2g-font-family-base, \"Quicksand\", sans-serif)}.c2g-wb{background:var(--c2g-theme-surface, var(--c2g-color-surface));border:1px solid var(--c2g-theme-outline-variant, var(--c2g-color-outline-variant));box-shadow:var(--c2g-shadow-sm, 0 1px 4px rgba(0, 0, 0, .06));border-radius:var(--c2g-radius-xl, 20px);padding:18px 20px 16px;display:flex;flex-direction:column;gap:12px;transition:box-shadow .2s ease,transform .2s ease}.c2g-wb:hover{box-shadow:var(--c2g-shadow-lg, 0 8px 28px rgba(0, 0, 0, .11));transform:translateY(-2px)}.c2g-wb__header{display:flex;align-items:center;gap:8px}.c2g-wb__icon{font-size:1.25rem;line-height:1}.c2g-wb__titles{display:flex;flex-direction:column;gap:2px}.c2g-wb__title{margin:0;font-size:.72rem;font-weight:700;text-transform:uppercase;letter-spacing:.09em;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted))}.c2g-wb__sub{font-size:.75rem;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));opacity:.7}.c2g-wb__stacked{display:flex;height:12px;border-radius:6px;overflow:hidden;gap:1px;background:var(--c2g-theme-outline-variant, var(--c2g-color-outline-variant))}.c2g-wb__stack-seg{height:100%;min-width:3px;transition:width .7s cubic-bezier(.4,0,.2,1)}.c2g-wb__legend{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:7px}.c2g-wb__row{display:grid;grid-template-columns:10px 100px 1fr 36px 72px;align-items:center;gap:8px}.c2g-wb__dot{width:10px;height:10px;border-radius:50%;flex-shrink:0}.c2g-wb__cat{font-size:.8rem;font-weight:600;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary));overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.c2g-wb__bar-track{height:5px;border-radius:3px;background:var(--c2g-theme-outline-variant, var(--c2g-color-outline-variant));overflow:hidden}.c2g-wb__bar-fill{height:100%;border-radius:3px;transition:width .7s cubic-bezier(.4,0,.2,1)}.c2g-wb__pct{font-size:.72rem;font-weight:700;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));font-variant-numeric:tabular-nums;text-align:right}.c2g-wb__weight{font-size:.72rem;font-weight:600;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));text-align:right;font-variant-numeric:tabular-nums}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "pipe", type: i1$2.DecimalPipe, name: "number" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2597
+ }
2598
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: WeightBreakdownWidgetComponent, decorators: [{
2599
+ type: Component,
2600
+ args: [{ selector: 'c2g-weight-breakdown-widget', standalone: true, imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<article class=\"c2g-wb\">\n <header class=\"c2g-wb__header\">\n <span class=\"c2g-wb__icon\">\uD83C\uDFCB\uFE0F</span>\n <div class=\"c2g-wb__titles\">\n <h3 class=\"c2g-wb__title\">Gewichts-Breakdown</h3>\n <span class=\"c2g-wb__sub\">{{ totalKg() }} kg gesamt</span>\n </div>\n </header>\n\n <!-- Stacked horizontal bar -->\n <div class=\"c2g-wb__stacked\" aria-hidden=\"true\">\n @for (e of entries(); track e.category) {\n <div\n class=\"c2g-wb__stack-seg\"\n [style.width.%]=\"e.pct\"\n [style.background]=\"e.color\"\n [title]=\"e.category + ': ' + (e.pct | number:'1.0-1') + '%'\"\n ></div>\n }\n </div>\n\n <!-- Legend rows -->\n <ul class=\"c2g-wb__legend\" role=\"list\">\n @for (e of entries(); track e.category) {\n <li class=\"c2g-wb__row\">\n <span class=\"c2g-wb__dot\" [style.background]=\"e.color\"></span>\n <span class=\"c2g-wb__cat\">{{ e.category }}</span>\n <div class=\"c2g-wb__bar-track\">\n <div class=\"c2g-wb__bar-fill\" [style.width.%]=\"e.pct\" [style.background]=\"e.color\"></div>\n </div>\n <span class=\"c2g-wb__pct\">{{ e.pct | number:'1.0-1' }}%</span>\n <span class=\"c2g-wb__weight\">{{ formatKg(e.weightG) }}</span>\n </li>\n }\n </ul>\n</article>\n", styles: [":host{display:block;font-family:var(--c2g-font-family-base, \"Quicksand\", sans-serif)}.c2g-wb{background:var(--c2g-theme-surface, var(--c2g-color-surface));border:1px solid var(--c2g-theme-outline-variant, var(--c2g-color-outline-variant));box-shadow:var(--c2g-shadow-sm, 0 1px 4px rgba(0, 0, 0, .06));border-radius:var(--c2g-radius-xl, 20px);padding:18px 20px 16px;display:flex;flex-direction:column;gap:12px;transition:box-shadow .2s ease,transform .2s ease}.c2g-wb:hover{box-shadow:var(--c2g-shadow-lg, 0 8px 28px rgba(0, 0, 0, .11));transform:translateY(-2px)}.c2g-wb__header{display:flex;align-items:center;gap:8px}.c2g-wb__icon{font-size:1.25rem;line-height:1}.c2g-wb__titles{display:flex;flex-direction:column;gap:2px}.c2g-wb__title{margin:0;font-size:.72rem;font-weight:700;text-transform:uppercase;letter-spacing:.09em;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted))}.c2g-wb__sub{font-size:.75rem;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));opacity:.7}.c2g-wb__stacked{display:flex;height:12px;border-radius:6px;overflow:hidden;gap:1px;background:var(--c2g-theme-outline-variant, var(--c2g-color-outline-variant))}.c2g-wb__stack-seg{height:100%;min-width:3px;transition:width .7s cubic-bezier(.4,0,.2,1)}.c2g-wb__legend{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:7px}.c2g-wb__row{display:grid;grid-template-columns:10px 100px 1fr 36px 72px;align-items:center;gap:8px}.c2g-wb__dot{width:10px;height:10px;border-radius:50%;flex-shrink:0}.c2g-wb__cat{font-size:.8rem;font-weight:600;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary));overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.c2g-wb__bar-track{height:5px;border-radius:3px;background:var(--c2g-theme-outline-variant, var(--c2g-color-outline-variant));overflow:hidden}.c2g-wb__bar-fill{height:100%;border-radius:3px;transition:width .7s cubic-bezier(.4,0,.2,1)}.c2g-wb__pct{font-size:.72rem;font-weight:700;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));font-variant-numeric:tabular-nums;text-align:right}.c2g-wb__weight{font-size:.72rem;font-weight:600;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));text-align:right;font-variant-numeric:tabular-nums}\n"] }]
2601
+ }], propDecorators: { data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: true }] }] } });
2602
+
2603
+ class AdventureScoreWidgetComponent {
2604
+ data = input.required(...(ngDevMode ? [{ debugName: "data" }] : []));
2605
+ displayScore = signal(0, ...(ngDevMode ? [{ debugName: "displayScore" }] : []));
2606
+ raf = 0;
2607
+ constructor() {
2608
+ effect(() => {
2609
+ const target = this.data().score;
2610
+ cancelAnimationFrame(this.raf);
2611
+ const start = performance.now();
2612
+ const tick = (now) => {
2613
+ const t = Math.min((now - start) / 1200, 1);
2614
+ const e = 1 - Math.pow(1 - t, 4);
2615
+ this.displayScore.set(Math.round(e * target));
2616
+ if (t < 1)
2617
+ this.raf = requestAnimationFrame(tick);
2618
+ };
2619
+ this.raf = requestAnimationFrame(tick);
2620
+ });
2621
+ }
2622
+ // Circular progress arc (0–100)
2623
+ arcPath = computed(() => {
2624
+ const pct = Math.min(this.data().score / 100, 1);
2625
+ const r = 52, cx = 60, cy = 60;
2626
+ const angle = pct * 360;
2627
+ if (angle >= 359.9) {
2628
+ return `M ${cx} ${cy - r} A ${r} ${r} 0 1 1 ${cx - 0.01} ${cy - r}`;
2629
+ }
2630
+ const rad = ((angle - 90) * Math.PI) / 180;
2631
+ const x = cx + r * Math.cos(rad);
2632
+ const y = cy + r * Math.sin(rad);
2633
+ const large = angle > 180 ? 1 : 0;
2634
+ return `M ${cx} ${cy - r} A ${r} ${r} 0 ${large} 1 ${x} ${y}`;
2635
+ }, ...(ngDevMode ? [{ debugName: "arcPath" }] : []));
2636
+ trackPath = `M 60 8 A 52 52 0 1 1 59.99 8`;
2637
+ levelColor = computed(() => {
2638
+ const l = this.data().level;
2639
+ if (l >= 80)
2640
+ return '#f59e0b';
2641
+ if (l >= 60)
2642
+ return '#ff6b35';
2643
+ if (l >= 40)
2644
+ return '#22c55e';
2645
+ if (l >= 20)
2646
+ return '#3b82f6';
2647
+ return '#94a3b8';
2648
+ }, ...(ngDevMode ? [{ debugName: "levelColor" }] : []));
2649
+ sparklinePath = computed(() => {
2650
+ const pts = this.data().sparkline;
2651
+ if (!pts || pts.length < 2)
2652
+ return null;
2653
+ const W = 120, H = 28;
2654
+ const maxS = Math.max(...pts.map(p => p.score));
2655
+ const minS = Math.min(...pts.map(p => p.score));
2656
+ const range = maxS - minS || 1;
2657
+ const xs = pts.map((_, i) => (i / (pts.length - 1)) * W);
2658
+ const ys = pts.map(p => H - ((p.score - minS) / range) * (H - 4) - 2);
2659
+ let d = `M ${xs[0]} ${ys[0]}`;
2660
+ for (let i = 1; i < pts.length; i++) {
2661
+ const cpx = (xs[i - 1] + xs[i]) / 2;
2662
+ d += ` C ${cpx} ${ys[i - 1]}, ${cpx} ${ys[i]}, ${xs[i]} ${ys[i]}`;
2663
+ }
2664
+ return d;
2665
+ }, ...(ngDevMode ? [{ debugName: "sparklinePath" }] : []));
2666
+ ngOnDestroy() { cancelAnimationFrame(this.raf); }
2667
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AdventureScoreWidgetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2668
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: AdventureScoreWidgetComponent, isStandalone: true, selector: "c2g-adventure-score-widget", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<article class=\"c2g-as\">\n <header class=\"c2g-as__header\">\n <span class=\"c2g-as__icon\">\uD83C\uDFC6</span>\n <div class=\"c2g-as__titles\">\n <h3 class=\"c2g-as__title\">Abenteuer-Score</h3>\n <span class=\"c2g-as__level-label\">{{ data().levelLabel }}</span>\n </div>\n @if (sparklinePath(); as sp) {\n <svg class=\"c2g-as__sparkline\" viewBox=\"0 0 120 28\" aria-hidden=\"true\">\n <path [attr.d]=\"sp\" [style.stroke]=\"levelColor()\" class=\"c2g-as__spark-line\"/>\n </svg>\n }\n </header>\n\n <div class=\"c2g-as__body\">\n <!-- Circular progress -->\n <div class=\"c2g-as__circle-wrap\" aria-hidden=\"true\">\n <svg class=\"c2g-as__circle\" viewBox=\"0 0 120 120\">\n <path class=\"c2g-as__track\" [attr.d]=\"trackPath\" fill=\"none\" stroke-width=\"10\" stroke-linecap=\"round\"/>\n <path class=\"c2g-as__arc\" [attr.d]=\"arcPath()\" fill=\"none\" stroke-width=\"10\" stroke-linecap=\"round\"\n [style.stroke]=\"levelColor()\"/>\n </svg>\n <div class=\"c2g-as__center\">\n <span class=\"c2g-as__score\" [style.color]=\"levelColor()\">{{ displayScore() }}</span>\n <span class=\"c2g-as__score-max\">/100</span>\n </div>\n </div>\n\n <!-- Stats -->\n <div class=\"c2g-as__stats\">\n <div class=\"c2g-as__stat\">\n <span class=\"c2g-as__stat-val\">{{ data().totalTours }}</span>\n <span class=\"c2g-as__stat-label\">Touren</span>\n </div>\n <div class=\"c2g-as__stat\">\n <span class=\"c2g-as__stat-val\">{{ data().totalKm | number:'1.0-0' }}</span>\n <span class=\"c2g-as__stat-label\">km</span>\n </div>\n <div class=\"c2g-as__stat\">\n <span class=\"c2g-as__stat-val\">{{ data().totalNights }}</span>\n <span class=\"c2g-as__stat-label\">N\u00E4chte</span>\n </div>\n <div class=\"c2g-as__stat\">\n <span class=\"c2g-as__stat-val\">{{ data().uniqueTypes }}</span>\n <span class=\"c2g-as__stat-label\">Typen</span>\n </div>\n </div>\n </div>\n</article>\n", styles: [":host{display:block;font-family:var(--c2g-font-family-base, \"Quicksand\", sans-serif)}.c2g-as{background:var(--c2g-theme-surface, var(--c2g-color-surface));border:1px solid var(--c2g-theme-outline-variant, var(--c2g-color-outline-variant));box-shadow:var(--c2g-shadow-sm, 0 1px 4px rgba(0, 0, 0, .06));border-radius:var(--c2g-radius-xl, 20px);padding:18px 20px 16px;display:flex;flex-direction:column;gap:14px;transition:box-shadow .2s ease,transform .2s ease}.c2g-as:hover{box-shadow:var(--c2g-shadow-lg, 0 8px 28px rgba(0, 0, 0, .11));transform:translateY(-2px)}.c2g-as__header{display:flex;align-items:flex-start;gap:8px}.c2g-as__icon{font-size:1.375rem;line-height:1}.c2g-as__titles{flex:1;display:flex;flex-direction:column;gap:2px}.c2g-as__title{margin:0;font-size:.72rem;font-weight:700;text-transform:uppercase;letter-spacing:.09em;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted))}.c2g-as__level-label{font-size:.8rem;font-weight:700;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary))}.c2g-as__sparkline{width:80px;height:28px;flex-shrink:0}.c2g-as__spark-line{fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;opacity:.7;stroke:var(--c2g-theme-primary, var(--c2g-color-primary))}.c2g-as__body{display:flex;gap:16px;align-items:center}.c2g-as__circle-wrap{position:relative;width:120px;height:120px;flex-shrink:0}.c2g-as__circle{width:100%;height:100%;display:block}.c2g-as__track{stroke:var(--c2g-theme-outline-variant, var(--c2g-color-outline-variant))}.c2g-as__arc{transition:d .9s cubic-bezier(.4,0,.2,1)}.c2g-as__center{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:2px}.c2g-as__score{font-size:2.25rem;font-weight:900;line-height:1;letter-spacing:-.03em;font-variant-numeric:tabular-nums}.c2g-as__score-max{font-size:.75rem;font-weight:600;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted))}.c2g-as__stats{display:grid;grid-template-columns:1fr 1fr;gap:10px;flex:1}.c2g-as__stat{display:flex;flex-direction:column;gap:2px;padding:8px 10px;background:var(--c2g-theme-surface-container, var(--c2g-color-bg-secondary));border-radius:var(--c2g-radius-md, 10px)}.c2g-as__stat-val{font-size:1.25rem;font-weight:800;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary));font-variant-numeric:tabular-nums;line-height:1}.c2g-as__stat-label{font-size:.65rem;font-weight:600;text-transform:uppercase;letter-spacing:.07em;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted))}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "pipe", type: i1$2.DecimalPipe, name: "number" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2669
+ }
2670
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AdventureScoreWidgetComponent, decorators: [{
2671
+ type: Component,
2672
+ args: [{ selector: 'c2g-adventure-score-widget', standalone: true, imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<article class=\"c2g-as\">\n <header class=\"c2g-as__header\">\n <span class=\"c2g-as__icon\">\uD83C\uDFC6</span>\n <div class=\"c2g-as__titles\">\n <h3 class=\"c2g-as__title\">Abenteuer-Score</h3>\n <span class=\"c2g-as__level-label\">{{ data().levelLabel }}</span>\n </div>\n @if (sparklinePath(); as sp) {\n <svg class=\"c2g-as__sparkline\" viewBox=\"0 0 120 28\" aria-hidden=\"true\">\n <path [attr.d]=\"sp\" [style.stroke]=\"levelColor()\" class=\"c2g-as__spark-line\"/>\n </svg>\n }\n </header>\n\n <div class=\"c2g-as__body\">\n <!-- Circular progress -->\n <div class=\"c2g-as__circle-wrap\" aria-hidden=\"true\">\n <svg class=\"c2g-as__circle\" viewBox=\"0 0 120 120\">\n <path class=\"c2g-as__track\" [attr.d]=\"trackPath\" fill=\"none\" stroke-width=\"10\" stroke-linecap=\"round\"/>\n <path class=\"c2g-as__arc\" [attr.d]=\"arcPath()\" fill=\"none\" stroke-width=\"10\" stroke-linecap=\"round\"\n [style.stroke]=\"levelColor()\"/>\n </svg>\n <div class=\"c2g-as__center\">\n <span class=\"c2g-as__score\" [style.color]=\"levelColor()\">{{ displayScore() }}</span>\n <span class=\"c2g-as__score-max\">/100</span>\n </div>\n </div>\n\n <!-- Stats -->\n <div class=\"c2g-as__stats\">\n <div class=\"c2g-as__stat\">\n <span class=\"c2g-as__stat-val\">{{ data().totalTours }}</span>\n <span class=\"c2g-as__stat-label\">Touren</span>\n </div>\n <div class=\"c2g-as__stat\">\n <span class=\"c2g-as__stat-val\">{{ data().totalKm | number:'1.0-0' }}</span>\n <span class=\"c2g-as__stat-label\">km</span>\n </div>\n <div class=\"c2g-as__stat\">\n <span class=\"c2g-as__stat-val\">{{ data().totalNights }}</span>\n <span class=\"c2g-as__stat-label\">N\u00E4chte</span>\n </div>\n <div class=\"c2g-as__stat\">\n <span class=\"c2g-as__stat-val\">{{ data().uniqueTypes }}</span>\n <span class=\"c2g-as__stat-label\">Typen</span>\n </div>\n </div>\n </div>\n</article>\n", styles: [":host{display:block;font-family:var(--c2g-font-family-base, \"Quicksand\", sans-serif)}.c2g-as{background:var(--c2g-theme-surface, var(--c2g-color-surface));border:1px solid var(--c2g-theme-outline-variant, var(--c2g-color-outline-variant));box-shadow:var(--c2g-shadow-sm, 0 1px 4px rgba(0, 0, 0, .06));border-radius:var(--c2g-radius-xl, 20px);padding:18px 20px 16px;display:flex;flex-direction:column;gap:14px;transition:box-shadow .2s ease,transform .2s ease}.c2g-as:hover{box-shadow:var(--c2g-shadow-lg, 0 8px 28px rgba(0, 0, 0, .11));transform:translateY(-2px)}.c2g-as__header{display:flex;align-items:flex-start;gap:8px}.c2g-as__icon{font-size:1.375rem;line-height:1}.c2g-as__titles{flex:1;display:flex;flex-direction:column;gap:2px}.c2g-as__title{margin:0;font-size:.72rem;font-weight:700;text-transform:uppercase;letter-spacing:.09em;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted))}.c2g-as__level-label{font-size:.8rem;font-weight:700;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary))}.c2g-as__sparkline{width:80px;height:28px;flex-shrink:0}.c2g-as__spark-line{fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;opacity:.7;stroke:var(--c2g-theme-primary, var(--c2g-color-primary))}.c2g-as__body{display:flex;gap:16px;align-items:center}.c2g-as__circle-wrap{position:relative;width:120px;height:120px;flex-shrink:0}.c2g-as__circle{width:100%;height:100%;display:block}.c2g-as__track{stroke:var(--c2g-theme-outline-variant, var(--c2g-color-outline-variant))}.c2g-as__arc{transition:d .9s cubic-bezier(.4,0,.2,1)}.c2g-as__center{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:2px}.c2g-as__score{font-size:2.25rem;font-weight:900;line-height:1;letter-spacing:-.03em;font-variant-numeric:tabular-nums}.c2g-as__score-max{font-size:.75rem;font-weight:600;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted))}.c2g-as__stats{display:grid;grid-template-columns:1fr 1fr;gap:10px;flex:1}.c2g-as__stat{display:flex;flex-direction:column;gap:2px;padding:8px 10px;background:var(--c2g-theme-surface-container, var(--c2g-color-bg-secondary));border-radius:var(--c2g-radius-md, 10px)}.c2g-as__stat-val{font-size:1.25rem;font-weight:800;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary));font-variant-numeric:tabular-nums;line-height:1}.c2g-as__stat-label{font-size:.65rem;font-weight:600;text-transform:uppercase;letter-spacing:.07em;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted))}\n"] }]
2673
+ }], ctorParameters: () => [], propDecorators: { data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: true }] }] } });
2674
+
2675
+ class TopGearWidgetComponent {
2676
+ data = input.required(...(ngDevMode ? [{ debugName: "data" }] : []));
2677
+ top = computed(() => this.data().entries.slice(0, 5), ...(ngDevMode ? [{ debugName: "top" }] : []));
2678
+ maxUsage = computed(() => Math.max(...this.data().entries.map(e => e.usageCount), 1), ...(ngDevMode ? [{ debugName: "maxUsage" }] : []));
2679
+ usagePct(count) {
2680
+ return Math.round((count / this.maxUsage()) * 100);
2681
+ }
2682
+ medal(index) {
2683
+ return ['🥇', '🥈', '🥉', '', ''][index] ?? '';
2684
+ }
2685
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: TopGearWidgetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2686
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: TopGearWidgetComponent, isStandalone: true, selector: "c2g-top-gear-widget", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<article class=\"c2g-tg\">\n <header class=\"c2g-tg__header\">\n <span class=\"c2g-tg__icon\">\uD83C\uDF92</span>\n <h3 class=\"c2g-tg__title\">Top-Gear</h3>\n </header>\n\n <ol class=\"c2g-tg__list\" role=\"list\">\n @for (entry of top(); track entry.name; let i = $index) {\n <li class=\"c2g-tg__item\" [class.c2g-tg__item--top3]=\"i < 3\">\n <span class=\"c2g-tg__rank\">\n @if (medal(i)) { {{ medal(i) }} } @else { {{ i + 1 }} }\n </span>\n <div class=\"c2g-tg__info\">\n <span class=\"c2g-tg__name\">{{ entry.name }}</span>\n @if (entry.category) {\n <span class=\"c2g-tg__cat\">{{ entry.category }}</span>\n }\n </div>\n <div class=\"c2g-tg__bar-track\">\n <div class=\"c2g-tg__bar-fill\" [style.width.%]=\"usagePct(entry.usageCount)\"></div>\n </div>\n <span class=\"c2g-tg__count\">{{ entry.usageCount }}\u00D7</span>\n </li>\n }\n </ol>\n</article>\n", styles: [":host{display:block;font-family:var(--c2g-font-family-base, \"Quicksand\", sans-serif)}.c2g-tg{background:var(--c2g-theme-surface, var(--c2g-color-surface));border:1px solid var(--c2g-theme-outline-variant, var(--c2g-color-outline-variant));box-shadow:var(--c2g-shadow-sm, 0 1px 4px rgba(0, 0, 0, .06));border-radius:var(--c2g-radius-xl, 20px);padding:18px 20px 16px;display:flex;flex-direction:column;gap:12px;transition:box-shadow .2s ease,transform .2s ease}.c2g-tg:hover{box-shadow:var(--c2g-shadow-lg, 0 8px 28px rgba(0, 0, 0, .11));transform:translateY(-2px)}.c2g-tg__header{display:flex;align-items:center;gap:8px}.c2g-tg__icon{font-size:1.25rem;line-height:1}.c2g-tg__title{margin:0;font-size:.72rem;font-weight:700;text-transform:uppercase;letter-spacing:.09em;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted))}.c2g-tg__list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:8px;counter-reset:gear}.c2g-tg__item{display:grid;grid-template-columns:28px 1fr 1fr 36px;align-items:center;gap:8px;padding:8px 10px;border-radius:var(--c2g-radius-md, 10px);background:var(--c2g-theme-surface-container-low, var(--c2g-color-bg-base))}.c2g-tg__item--top3{background:var(--c2g-theme-surface-container, var(--c2g-color-bg-secondary))}.c2g-tg__rank{font-size:1rem;text-align:center}.c2g-tg__info{display:flex;flex-direction:column;gap:1px;overflow:hidden}.c2g-tg__name{font-size:.8125rem;font-weight:700;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary));overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.c2g-tg__cat{font-size:.65rem;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted))}.c2g-tg__bar-track{height:6px;border-radius:3px;background:var(--c2g-theme-outline-variant, var(--c2g-color-outline-variant));overflow:hidden}.c2g-tg__bar-fill{height:100%;border-radius:3px;background:var(--c2g-theme-primary, var(--c2g-color-primary));transition:width .7s cubic-bezier(.4,0,.2,1)}.c2g-tg__count{font-size:.8rem;font-weight:800;text-align:right;color:var(--c2g-theme-primary, var(--c2g-color-primary));font-variant-numeric:tabular-nums}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2687
+ }
2688
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: TopGearWidgetComponent, decorators: [{
2689
+ type: Component,
2690
+ args: [{ selector: 'c2g-top-gear-widget', standalone: true, imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<article class=\"c2g-tg\">\n <header class=\"c2g-tg__header\">\n <span class=\"c2g-tg__icon\">\uD83C\uDF92</span>\n <h3 class=\"c2g-tg__title\">Top-Gear</h3>\n </header>\n\n <ol class=\"c2g-tg__list\" role=\"list\">\n @for (entry of top(); track entry.name; let i = $index) {\n <li class=\"c2g-tg__item\" [class.c2g-tg__item--top3]=\"i < 3\">\n <span class=\"c2g-tg__rank\">\n @if (medal(i)) { {{ medal(i) }} } @else { {{ i + 1 }} }\n </span>\n <div class=\"c2g-tg__info\">\n <span class=\"c2g-tg__name\">{{ entry.name }}</span>\n @if (entry.category) {\n <span class=\"c2g-tg__cat\">{{ entry.category }}</span>\n }\n </div>\n <div class=\"c2g-tg__bar-track\">\n <div class=\"c2g-tg__bar-fill\" [style.width.%]=\"usagePct(entry.usageCount)\"></div>\n </div>\n <span class=\"c2g-tg__count\">{{ entry.usageCount }}\u00D7</span>\n </li>\n }\n </ol>\n</article>\n", styles: [":host{display:block;font-family:var(--c2g-font-family-base, \"Quicksand\", sans-serif)}.c2g-tg{background:var(--c2g-theme-surface, var(--c2g-color-surface));border:1px solid var(--c2g-theme-outline-variant, var(--c2g-color-outline-variant));box-shadow:var(--c2g-shadow-sm, 0 1px 4px rgba(0, 0, 0, .06));border-radius:var(--c2g-radius-xl, 20px);padding:18px 20px 16px;display:flex;flex-direction:column;gap:12px;transition:box-shadow .2s ease,transform .2s ease}.c2g-tg:hover{box-shadow:var(--c2g-shadow-lg, 0 8px 28px rgba(0, 0, 0, .11));transform:translateY(-2px)}.c2g-tg__header{display:flex;align-items:center;gap:8px}.c2g-tg__icon{font-size:1.25rem;line-height:1}.c2g-tg__title{margin:0;font-size:.72rem;font-weight:700;text-transform:uppercase;letter-spacing:.09em;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted))}.c2g-tg__list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:8px;counter-reset:gear}.c2g-tg__item{display:grid;grid-template-columns:28px 1fr 1fr 36px;align-items:center;gap:8px;padding:8px 10px;border-radius:var(--c2g-radius-md, 10px);background:var(--c2g-theme-surface-container-low, var(--c2g-color-bg-base))}.c2g-tg__item--top3{background:var(--c2g-theme-surface-container, var(--c2g-color-bg-secondary))}.c2g-tg__rank{font-size:1rem;text-align:center}.c2g-tg__info{display:flex;flex-direction:column;gap:1px;overflow:hidden}.c2g-tg__name{font-size:.8125rem;font-weight:700;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary));overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.c2g-tg__cat{font-size:.65rem;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted))}.c2g-tg__bar-track{height:6px;border-radius:3px;background:var(--c2g-theme-outline-variant, var(--c2g-color-outline-variant));overflow:hidden}.c2g-tg__bar-fill{height:100%;border-radius:3px;background:var(--c2g-theme-primary, var(--c2g-color-primary));transition:width .7s cubic-bezier(.4,0,.2,1)}.c2g-tg__count{font-size:.8rem;font-weight:800;text-align:right;color:var(--c2g-theme-primary, var(--c2g-color-primary));font-variant-numeric:tabular-nums}\n"] }]
2691
+ }], propDecorators: { data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: true }] }] } });
2692
+
2693
+ class GroupActivityWidgetComponent {
2694
+ data = input.required(...(ngDevMode ? [{ debugName: "data" }] : []));
2695
+ ranked = computed(() => {
2696
+ const sorted = [...this.data().members]
2697
+ .sort((a, b) => b.completedItems - a.completedItems);
2698
+ const maxItems = Math.max(...sorted.map(m => m.completedItems), 1);
2699
+ return sorted.map((m, i) => ({
2700
+ ...m,
2701
+ rank: i + 1,
2702
+ pct: Math.round((m.completedItems / maxItems) * 100),
2703
+ }));
2704
+ }, ...(ngDevMode ? [{ debugName: "ranked" }] : []));
2705
+ medal(rank) {
2706
+ if (rank === 1)
2707
+ return '🥇';
2708
+ if (rank === 2)
2709
+ return '🥈';
2710
+ if (rank === 3)
2711
+ return '🥉';
2712
+ return '';
2713
+ }
2714
+ completionPct(m) {
2715
+ if (!m.totalItems)
2716
+ return 0;
2717
+ return Math.round((m.completedItems / m.totalItems) * 100);
2718
+ }
2719
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: GroupActivityWidgetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2720
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: GroupActivityWidgetComponent, isStandalone: true, selector: "c2g-group-activity-widget", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<article class=\"c2g-ga\">\n <header class=\"c2g-ga__header\">\n <span class=\"c2g-ga__icon\">\uD83C\uDFC5</span>\n <div class=\"c2g-ga__titles\">\n <h3 class=\"c2g-ga__title\">Aktivste Mitglieder</h3>\n @if (data().groupName) {\n <span class=\"c2g-ga__sub\">{{ data().groupName }}</span>\n }\n </div>\n </header>\n\n <ol class=\"c2g-ga__list\" role=\"list\">\n @for (m of ranked(); track m.name) {\n <li class=\"c2g-ga__item\" [class.c2g-ga__item--self]=\"m.isSelf\">\n <!-- Avatar -->\n <div class=\"c2g-ga__avatar\">\n @if (m.avatarUrl) {\n <img [src]=\"m.avatarUrl\" [alt]=\"m.name\" class=\"c2g-ga__avatar-img\"/>\n } @else {\n <span class=\"c2g-ga__initials\">{{ m.initials }}</span>\n }\n @if (medal(m.rank)) {\n <span class=\"c2g-ga__medal\">{{ medal(m.rank) }}</span>\n }\n </div>\n\n <div class=\"c2g-ga__info\">\n <span class=\"c2g-ga__name\">{{ m.name }}{{ m.isSelf ? ' (du)' : '' }}</span>\n <div class=\"c2g-ga__bar-track\">\n <div class=\"c2g-ga__bar-fill\" [style.width.%]=\"m.pct\"></div>\n </div>\n </div>\n\n <div class=\"c2g-ga__nums\">\n <span class=\"c2g-ga__completed\">{{ m.completedItems }}</span>\n @if (m.totalItems) {\n <span class=\"c2g-ga__total\">/ {{ m.totalItems }}</span>\n }\n </div>\n </li>\n }\n </ol>\n</article>\n", styles: [":host{display:block;font-family:var(--c2g-font-family-base, \"Quicksand\", sans-serif)}.c2g-ga{background:var(--c2g-theme-surface, var(--c2g-color-surface));border:1px solid var(--c2g-theme-outline-variant, var(--c2g-color-outline-variant));box-shadow:var(--c2g-shadow-sm, 0 1px 4px rgba(0, 0, 0, .06));border-radius:var(--c2g-radius-xl, 20px);padding:18px 20px 16px;display:flex;flex-direction:column;gap:12px;transition:box-shadow .2s ease,transform .2s ease}.c2g-ga:hover{box-shadow:var(--c2g-shadow-lg, 0 8px 28px rgba(0, 0, 0, .11));transform:translateY(-2px)}.c2g-ga__header{display:flex;align-items:center;gap:8px}.c2g-ga__icon{font-size:1.25rem;line-height:1}.c2g-ga__titles{display:flex;flex-direction:column;gap:2px}.c2g-ga__title{margin:0;font-size:.72rem;font-weight:700;text-transform:uppercase;letter-spacing:.09em;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted))}.c2g-ga__sub{font-size:.75rem;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));opacity:.7}.c2g-ga__list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:8px}.c2g-ga__item{display:grid;grid-template-columns:36px 1fr auto;align-items:center;gap:10px}.c2g-ga__item--self{background:var(--c2g-color-primary-light, #fff4f0);border-radius:var(--c2g-radius-md, 10px);padding:4px 8px}.c2g-ga__avatar{position:relative;width:36px;height:36px;flex-shrink:0;border-radius:50%;background:var(--c2g-theme-surface-container, var(--c2g-color-bg-secondary));display:flex;align-items:center;justify-content:center;overflow:visible}.c2g-ga__avatar-img{width:100%;height:100%;border-radius:50%;object-fit:cover}.c2g-ga__initials{font-size:.75rem;font-weight:800;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary))}.c2g-ga__medal{position:absolute;bottom:-4px;right:-4px;font-size:.75rem;line-height:1}.c2g-ga__info{display:flex;flex-direction:column;gap:4px;overflow:hidden}.c2g-ga__name{font-size:.8125rem;font-weight:700;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary));overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.c2g-ga__bar-track{height:5px;border-radius:3px;background:var(--c2g-theme-outline-variant, var(--c2g-color-outline-variant));overflow:hidden}.c2g-ga__bar-fill{height:100%;border-radius:3px;background:var(--c2g-theme-primary, var(--c2g-color-primary));transition:width .7s cubic-bezier(.4,0,.2,1)}.c2g-ga__nums{display:flex;align-items:baseline;gap:2px}.c2g-ga__completed{font-size:1rem;font-weight:900;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary));font-variant-numeric:tabular-nums}.c2g-ga__total{font-size:.75rem;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));font-variant-numeric:tabular-nums}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2721
+ }
2722
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: GroupActivityWidgetComponent, decorators: [{
2723
+ type: Component,
2724
+ args: [{ selector: 'c2g-group-activity-widget', standalone: true, imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<article class=\"c2g-ga\">\n <header class=\"c2g-ga__header\">\n <span class=\"c2g-ga__icon\">\uD83C\uDFC5</span>\n <div class=\"c2g-ga__titles\">\n <h3 class=\"c2g-ga__title\">Aktivste Mitglieder</h3>\n @if (data().groupName) {\n <span class=\"c2g-ga__sub\">{{ data().groupName }}</span>\n }\n </div>\n </header>\n\n <ol class=\"c2g-ga__list\" role=\"list\">\n @for (m of ranked(); track m.name) {\n <li class=\"c2g-ga__item\" [class.c2g-ga__item--self]=\"m.isSelf\">\n <!-- Avatar -->\n <div class=\"c2g-ga__avatar\">\n @if (m.avatarUrl) {\n <img [src]=\"m.avatarUrl\" [alt]=\"m.name\" class=\"c2g-ga__avatar-img\"/>\n } @else {\n <span class=\"c2g-ga__initials\">{{ m.initials }}</span>\n }\n @if (medal(m.rank)) {\n <span class=\"c2g-ga__medal\">{{ medal(m.rank) }}</span>\n }\n </div>\n\n <div class=\"c2g-ga__info\">\n <span class=\"c2g-ga__name\">{{ m.name }}{{ m.isSelf ? ' (du)' : '' }}</span>\n <div class=\"c2g-ga__bar-track\">\n <div class=\"c2g-ga__bar-fill\" [style.width.%]=\"m.pct\"></div>\n </div>\n </div>\n\n <div class=\"c2g-ga__nums\">\n <span class=\"c2g-ga__completed\">{{ m.completedItems }}</span>\n @if (m.totalItems) {\n <span class=\"c2g-ga__total\">/ {{ m.totalItems }}</span>\n }\n </div>\n </li>\n }\n </ol>\n</article>\n", styles: [":host{display:block;font-family:var(--c2g-font-family-base, \"Quicksand\", sans-serif)}.c2g-ga{background:var(--c2g-theme-surface, var(--c2g-color-surface));border:1px solid var(--c2g-theme-outline-variant, var(--c2g-color-outline-variant));box-shadow:var(--c2g-shadow-sm, 0 1px 4px rgba(0, 0, 0, .06));border-radius:var(--c2g-radius-xl, 20px);padding:18px 20px 16px;display:flex;flex-direction:column;gap:12px;transition:box-shadow .2s ease,transform .2s ease}.c2g-ga:hover{box-shadow:var(--c2g-shadow-lg, 0 8px 28px rgba(0, 0, 0, .11));transform:translateY(-2px)}.c2g-ga__header{display:flex;align-items:center;gap:8px}.c2g-ga__icon{font-size:1.25rem;line-height:1}.c2g-ga__titles{display:flex;flex-direction:column;gap:2px}.c2g-ga__title{margin:0;font-size:.72rem;font-weight:700;text-transform:uppercase;letter-spacing:.09em;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted))}.c2g-ga__sub{font-size:.75rem;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));opacity:.7}.c2g-ga__list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:8px}.c2g-ga__item{display:grid;grid-template-columns:36px 1fr auto;align-items:center;gap:10px}.c2g-ga__item--self{background:var(--c2g-color-primary-light, #fff4f0);border-radius:var(--c2g-radius-md, 10px);padding:4px 8px}.c2g-ga__avatar{position:relative;width:36px;height:36px;flex-shrink:0;border-radius:50%;background:var(--c2g-theme-surface-container, var(--c2g-color-bg-secondary));display:flex;align-items:center;justify-content:center;overflow:visible}.c2g-ga__avatar-img{width:100%;height:100%;border-radius:50%;object-fit:cover}.c2g-ga__initials{font-size:.75rem;font-weight:800;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary))}.c2g-ga__medal{position:absolute;bottom:-4px;right:-4px;font-size:.75rem;line-height:1}.c2g-ga__info{display:flex;flex-direction:column;gap:4px;overflow:hidden}.c2g-ga__name{font-size:.8125rem;font-weight:700;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary));overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.c2g-ga__bar-track{height:5px;border-radius:3px;background:var(--c2g-theme-outline-variant, var(--c2g-color-outline-variant));overflow:hidden}.c2g-ga__bar-fill{height:100%;border-radius:3px;background:var(--c2g-theme-primary, var(--c2g-color-primary));transition:width .7s cubic-bezier(.4,0,.2,1)}.c2g-ga__nums{display:flex;align-items:baseline;gap:2px}.c2g-ga__completed{font-size:1rem;font-weight:900;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary));font-variant-numeric:tabular-nums}.c2g-ga__total{font-size:.75rem;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));font-variant-numeric:tabular-nums}\n"] }]
2725
+ }], propDecorators: { data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: true }] }] } });
2726
+
2727
+ class GearSharingWidgetComponent {
2728
+ data = input.required(...(ngDevMode ? [{ debugName: "data" }] : []));
2729
+ displayPct = signal(0, ...(ngDevMode ? [{ debugName: "displayPct" }] : []));
2730
+ raf = 0;
2731
+ constructor() {
2732
+ effect(() => {
2733
+ const target = this.sharingPct();
2734
+ cancelAnimationFrame(this.raf);
2735
+ const start = performance.now();
2736
+ const tick = (now) => {
2737
+ const t = Math.min((now - start) / 1000, 1);
2738
+ const e = 1 - Math.pow(1 - t, 3);
2739
+ this.displayPct.set(Math.round(e * target));
2740
+ if (t < 1)
2741
+ this.raf = requestAnimationFrame(tick);
2742
+ };
2743
+ this.raf = requestAnimationFrame(tick);
2744
+ });
2745
+ }
2746
+ sharingPct = computed(() => {
2747
+ const d = this.data();
2748
+ if (!d.totalItems)
2749
+ return 0;
2750
+ return Math.round((d.sharedItems / d.totalItems) * 100);
2751
+ }, ...(ngDevMode ? [{ debugName: "sharingPct" }] : []));
2752
+ tier = computed(() => {
2753
+ const p = this.sharingPct();
2754
+ if (p >= 40)
2755
+ return 'high';
2756
+ if (p >= 20)
2757
+ return 'medium';
2758
+ return 'low';
2759
+ }, ...(ngDevMode ? [{ debugName: "tier" }] : []));
2760
+ arcPath = computed(() => {
2761
+ const pct = Math.min(this.sharingPct() / 100, 1);
2762
+ const r = 44, cx = 52, cy = 52;
2763
+ if (pct >= 0.999)
2764
+ return `M ${cx} ${cy - r} A ${r} ${r} 0 1 1 ${cx - 0.01} ${cy - r}`;
2765
+ const angle = pct * 360;
2766
+ const rad = ((angle - 90) * Math.PI) / 180;
2767
+ const x = cx + r * Math.cos(rad);
2768
+ const y = cy + r * Math.sin(rad);
2769
+ const large = angle > 180 ? 1 : 0;
2770
+ return `M ${cx} ${cy - r} A ${r} ${r} 0 ${large} 1 ${x} ${y}`;
2771
+ }, ...(ngDevMode ? [{ debugName: "arcPath" }] : []));
2772
+ ngOnDestroy() { cancelAnimationFrame(this.raf); }
2773
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: GearSharingWidgetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2774
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: GearSharingWidgetComponent, isStandalone: true, selector: "c2g-gear-sharing-widget", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<article class=\"c2g-gs\" [class]=\"'c2g-gs--' + tier()\">\n <header class=\"c2g-gs__header\">\n <span class=\"c2g-gs__icon\">\uD83E\uDD1D</span>\n <div class=\"c2g-gs__titles\">\n <h3 class=\"c2g-gs__title\">Gear-Sharing</h3>\n <span class=\"c2g-gs__sub\">{{ data().memberCount }} Mitglieder</span>\n </div>\n </header>\n\n <div class=\"c2g-gs__body\">\n <div class=\"c2g-gs__circle-wrap\" aria-hidden=\"true\">\n <svg class=\"c2g-gs__circle\" viewBox=\"0 0 104 104\">\n <circle cx=\"52\" cy=\"52\" r=\"44\" class=\"c2g-gs__track\" fill=\"none\" stroke-width=\"10\"/>\n <path class=\"c2g-gs__arc\" [attr.d]=\"arcPath()\" fill=\"none\" stroke-width=\"10\" stroke-linecap=\"round\"/>\n </svg>\n <div class=\"c2g-gs__center\">\n <span class=\"c2g-gs__pct\">{{ displayPct() }}%</span>\n <span class=\"c2g-gs__pct-label\">geteilt</span>\n </div>\n </div>\n\n <div class=\"c2g-gs__stats\">\n <div class=\"c2g-gs__stat\">\n <span class=\"c2g-gs__stat-val\">{{ data().sharedItems }}</span>\n <span class=\"c2g-gs__stat-label\">geteilt</span>\n </div>\n <div class=\"c2g-gs__stat\">\n <span class=\"c2g-gs__stat-val\">{{ data().totalItems - data().sharedItems }}</span>\n <span class=\"c2g-gs__stat-label\">eigene</span>\n </div>\n @if (data().savedWeightPerPersonG) {\n <div class=\"c2g-gs__stat c2g-gs__stat--highlight\">\n <span class=\"c2g-gs__stat-val\">{{ (data().savedWeightPerPersonG! / 1000) | number:'1.1-1' }} kg</span>\n <span class=\"c2g-gs__stat-label\">gespart/Person</span>\n </div>\n }\n </div>\n </div>\n</article>\n", styles: [":host{display:block;font-family:var(--c2g-font-family-base, \"Quicksand\", sans-serif)}.c2g-gs{background:var(--c2g-theme-surface, var(--c2g-color-surface));border:1px solid var(--c2g-theme-outline-variant, var(--c2g-color-outline-variant));box-shadow:var(--c2g-shadow-sm, 0 1px 4px rgba(0, 0, 0, .06));border-radius:var(--c2g-radius-xl, 20px);padding:18px 20px 16px;display:flex;flex-direction:column;gap:14px;transition:box-shadow .2s ease,transform .2s ease}.c2g-gs:hover{box-shadow:var(--c2g-shadow-lg, 0 8px 28px rgba(0, 0, 0, .11));transform:translateY(-2px)}.c2g-gs--high{--gs-color: #22c55e}.c2g-gs--medium{--gs-color: #f59e0b}.c2g-gs--low{--gs-color: #94a3b8}.c2g-gs__header{display:flex;align-items:center;gap:8px}.c2g-gs__icon{font-size:1.25rem;line-height:1}.c2g-gs__titles{display:flex;flex-direction:column;gap:2px}.c2g-gs__title{margin:0;font-size:.72rem;font-weight:700;text-transform:uppercase;letter-spacing:.09em;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted))}.c2g-gs__sub{font-size:.75rem;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));opacity:.7}.c2g-gs__body{display:flex;gap:16px;align-items:center}.c2g-gs__circle-wrap{position:relative;width:104px;height:104px;flex-shrink:0}.c2g-gs__circle{width:100%;height:100%;display:block}.c2g-gs__track{stroke:var(--c2g-theme-outline-variant, var(--c2g-color-outline-variant))}.c2g-gs__arc{stroke:var(--gs-color, var(--c2g-theme-primary, var(--c2g-color-primary)));transition:d .9s cubic-bezier(.4,0,.2,1)}.c2g-gs__center{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center}.c2g-gs__pct{font-size:1.75rem;font-weight:900;color:var(--gs-color, var(--c2g-theme-primary, var(--c2g-color-primary)));font-variant-numeric:tabular-nums;line-height:1}.c2g-gs__pct-label{font-size:.6rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted))}.c2g-gs__stats{flex:1;display:flex;flex-direction:column;gap:8px}.c2g-gs__stat{display:flex;flex-direction:column;gap:1px}.c2g-gs__stat-val{font-size:1.125rem;font-weight:800;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary));font-variant-numeric:tabular-nums;line-height:1}.c2g-gs__stat-label{font-size:.65rem;text-transform:uppercase;letter-spacing:.06em;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted))}.c2g-gs__stat--highlight .c2g-gs__stat-val{color:var(--gs-color, var(--c2g-theme-primary, var(--c2g-color-primary)))}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "pipe", type: i1$2.DecimalPipe, name: "number" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2775
+ }
2776
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: GearSharingWidgetComponent, decorators: [{
2777
+ type: Component,
2778
+ args: [{ selector: 'c2g-gear-sharing-widget', standalone: true, imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<article class=\"c2g-gs\" [class]=\"'c2g-gs--' + tier()\">\n <header class=\"c2g-gs__header\">\n <span class=\"c2g-gs__icon\">\uD83E\uDD1D</span>\n <div class=\"c2g-gs__titles\">\n <h3 class=\"c2g-gs__title\">Gear-Sharing</h3>\n <span class=\"c2g-gs__sub\">{{ data().memberCount }} Mitglieder</span>\n </div>\n </header>\n\n <div class=\"c2g-gs__body\">\n <div class=\"c2g-gs__circle-wrap\" aria-hidden=\"true\">\n <svg class=\"c2g-gs__circle\" viewBox=\"0 0 104 104\">\n <circle cx=\"52\" cy=\"52\" r=\"44\" class=\"c2g-gs__track\" fill=\"none\" stroke-width=\"10\"/>\n <path class=\"c2g-gs__arc\" [attr.d]=\"arcPath()\" fill=\"none\" stroke-width=\"10\" stroke-linecap=\"round\"/>\n </svg>\n <div class=\"c2g-gs__center\">\n <span class=\"c2g-gs__pct\">{{ displayPct() }}%</span>\n <span class=\"c2g-gs__pct-label\">geteilt</span>\n </div>\n </div>\n\n <div class=\"c2g-gs__stats\">\n <div class=\"c2g-gs__stat\">\n <span class=\"c2g-gs__stat-val\">{{ data().sharedItems }}</span>\n <span class=\"c2g-gs__stat-label\">geteilt</span>\n </div>\n <div class=\"c2g-gs__stat\">\n <span class=\"c2g-gs__stat-val\">{{ data().totalItems - data().sharedItems }}</span>\n <span class=\"c2g-gs__stat-label\">eigene</span>\n </div>\n @if (data().savedWeightPerPersonG) {\n <div class=\"c2g-gs__stat c2g-gs__stat--highlight\">\n <span class=\"c2g-gs__stat-val\">{{ (data().savedWeightPerPersonG! / 1000) | number:'1.1-1' }} kg</span>\n <span class=\"c2g-gs__stat-label\">gespart/Person</span>\n </div>\n }\n </div>\n </div>\n</article>\n", styles: [":host{display:block;font-family:var(--c2g-font-family-base, \"Quicksand\", sans-serif)}.c2g-gs{background:var(--c2g-theme-surface, var(--c2g-color-surface));border:1px solid var(--c2g-theme-outline-variant, var(--c2g-color-outline-variant));box-shadow:var(--c2g-shadow-sm, 0 1px 4px rgba(0, 0, 0, .06));border-radius:var(--c2g-radius-xl, 20px);padding:18px 20px 16px;display:flex;flex-direction:column;gap:14px;transition:box-shadow .2s ease,transform .2s ease}.c2g-gs:hover{box-shadow:var(--c2g-shadow-lg, 0 8px 28px rgba(0, 0, 0, .11));transform:translateY(-2px)}.c2g-gs--high{--gs-color: #22c55e}.c2g-gs--medium{--gs-color: #f59e0b}.c2g-gs--low{--gs-color: #94a3b8}.c2g-gs__header{display:flex;align-items:center;gap:8px}.c2g-gs__icon{font-size:1.25rem;line-height:1}.c2g-gs__titles{display:flex;flex-direction:column;gap:2px}.c2g-gs__title{margin:0;font-size:.72rem;font-weight:700;text-transform:uppercase;letter-spacing:.09em;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted))}.c2g-gs__sub{font-size:.75rem;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));opacity:.7}.c2g-gs__body{display:flex;gap:16px;align-items:center}.c2g-gs__circle-wrap{position:relative;width:104px;height:104px;flex-shrink:0}.c2g-gs__circle{width:100%;height:100%;display:block}.c2g-gs__track{stroke:var(--c2g-theme-outline-variant, var(--c2g-color-outline-variant))}.c2g-gs__arc{stroke:var(--gs-color, var(--c2g-theme-primary, var(--c2g-color-primary)));transition:d .9s cubic-bezier(.4,0,.2,1)}.c2g-gs__center{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center}.c2g-gs__pct{font-size:1.75rem;font-weight:900;color:var(--gs-color, var(--c2g-theme-primary, var(--c2g-color-primary)));font-variant-numeric:tabular-nums;line-height:1}.c2g-gs__pct-label{font-size:.6rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted))}.c2g-gs__stats{flex:1;display:flex;flex-direction:column;gap:8px}.c2g-gs__stat{display:flex;flex-direction:column;gap:1px}.c2g-gs__stat-val{font-size:1.125rem;font-weight:800;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary));font-variant-numeric:tabular-nums;line-height:1}.c2g-gs__stat-label{font-size:.65rem;text-transform:uppercase;letter-spacing:.06em;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted))}.c2g-gs__stat--highlight .c2g-gs__stat-val{color:var(--gs-color, var(--c2g-theme-primary, var(--c2g-color-primary)))}\n"] }]
2779
+ }], ctorParameters: () => [], propDecorators: { data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: true }] }] } });
2780
+
2781
+ class AdventureRadiusWidgetComponent {
2782
+ data = input.required(...(ngDevMode ? [{ debugName: "data" }] : []));
2783
+ buckets = computed(() => this.data().buckets ?? [], ...(ngDevMode ? [{ debugName: "buckets" }] : []));
2784
+ maxBucketCount = computed(() => Math.max(...this.buckets().map(b => b.count), 1), ...(ngDevMode ? [{ debugName: "maxBucketCount" }] : []));
2785
+ bucketPct(count) {
2786
+ return Math.round((count / this.maxBucketCount()) * 100);
2787
+ }
2788
+ radiusTier = computed(() => {
2789
+ const max = this.data().maxRadiusKm;
2790
+ if (max >= 1000)
2791
+ return 'international';
2792
+ if (max >= 300)
2793
+ return 'national';
2794
+ if (max >= 100)
2795
+ return 'regional';
2796
+ return 'local';
2797
+ }, ...(ngDevMode ? [{ debugName: "radiusTier" }] : []));
2798
+ tierEmoji = computed(() => {
2799
+ switch (this.radiusTier()) {
2800
+ case 'international': return '🌍';
2801
+ case 'national': return '🗺️';
2802
+ case 'regional': return '🏔️';
2803
+ default: return '🏡';
2804
+ }
2805
+ }, ...(ngDevMode ? [{ debugName: "tierEmoji" }] : []));
2806
+ tierLabel = computed(() => {
2807
+ switch (this.radiusTier()) {
2808
+ case 'international': return 'Weltenbummler';
2809
+ case 'national': return 'Deutschlandreisender';
2810
+ case 'regional': return 'Regionalentdecker';
2811
+ default: return 'Heimatverbunden';
2812
+ }
2813
+ }, ...(ngDevMode ? [{ debugName: "tierLabel" }] : []));
2814
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AdventureRadiusWidgetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2815
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: AdventureRadiusWidgetComponent, isStandalone: true, selector: "c2g-adventure-radius-widget", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<article class=\"c2g-ar\">\n <header class=\"c2g-ar__header\">\n <span class=\"c2g-ar__icon\">{{ tierEmoji() }}</span>\n <div class=\"c2g-ar__titles\">\n <h3 class=\"c2g-ar__title\">Abenteuer-Radius</h3>\n @if (data().homeLabel) {\n <span class=\"c2g-ar__sub\">ab {{ data().homeLabel }}</span>\n }\n </div>\n <span class=\"c2g-ar__tier-badge c2g-ar__tier-badge--{{ radiusTier() }}\">\n {{ tierLabel() }}\n </span>\n </header>\n\n <div class=\"c2g-ar__hero\">\n <div class=\"c2g-ar__stat\">\n <span class=\"c2g-ar__val\">{{ data().avgRadiusKm | number:'1.0-0' }}</span>\n <span class=\"c2g-ar__unit\">km</span>\n <span class=\"c2g-ar__label\">\u00D8 Radius</span>\n </div>\n <div class=\"c2g-ar__divider\"></div>\n <div class=\"c2g-ar__stat\">\n <span class=\"c2g-ar__val\">{{ data().maxRadiusKm | number:'1.0-0' }}</span>\n <span class=\"c2g-ar__unit\">km</span>\n <span class=\"c2g-ar__label\">Maximum</span>\n </div>\n </div>\n\n @if (data().maxTourName) {\n <div class=\"c2g-ar__max-tour\">\n <span class=\"c2g-ar__max-icon\">\uD83D\uDCCD</span>\n <span class=\"c2g-ar__max-name\">{{ data().maxTourName }}</span>\n </div>\n }\n\n @if (buckets().length) {\n <div class=\"c2g-ar__buckets\">\n @for (b of buckets(); track b.labelKm) {\n <div class=\"c2g-ar__bucket\">\n <div class=\"c2g-ar__bucket-bar-wrap\">\n <div class=\"c2g-ar__bucket-bar\" [style.height.%]=\"bucketPct(b.count)\"></div>\n </div>\n <span class=\"c2g-ar__bucket-label\">{{ b.labelKm }}</span>\n <span class=\"c2g-ar__bucket-count\">{{ b.count }}</span>\n </div>\n }\n </div>\n }\n</article>\n", styles: [":host{display:block;font-family:var(--c2g-font-family-base, \"Quicksand\", sans-serif)}.c2g-ar{background:var(--c2g-theme-surface, var(--c2g-color-surface));border:1px solid var(--c2g-theme-outline-variant, var(--c2g-color-outline-variant));box-shadow:var(--c2g-shadow-sm, 0 1px 4px rgba(0, 0, 0, .06));border-radius:var(--c2g-radius-xl, 20px);padding:18px 20px 16px;display:flex;flex-direction:column;gap:12px;transition:box-shadow .2s ease,transform .2s ease}.c2g-ar:hover{box-shadow:var(--c2g-shadow-lg, 0 8px 28px rgba(0, 0, 0, .11));transform:translateY(-2px)}.c2g-ar__header{display:flex;align-items:center;gap:8px}.c2g-ar__icon{font-size:1.5rem;line-height:1}.c2g-ar__titles{flex:1;display:flex;flex-direction:column;gap:2px}.c2g-ar__title{margin:0;font-size:.72rem;font-weight:700;text-transform:uppercase;letter-spacing:.09em;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted))}.c2g-ar__sub{font-size:.75rem;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));opacity:.7}.c2g-ar__tier-badge{font-size:.7rem;font-weight:700;padding:3px 8px;border-radius:999px;white-space:nowrap}.c2g-ar__tier-badge--international{color:#a855f7;background:#a855f71a}.c2g-ar__tier-badge--national{color:#3b82f6;background:#3b82f61a}.c2g-ar__tier-badge--regional{color:#22c55e;background:#22c55e1a}.c2g-ar__tier-badge--local{color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));background:var(--c2g-theme-surface-container, var(--c2g-color-bg-secondary))}.c2g-ar__hero{display:flex;align-items:center;gap:0}.c2g-ar__stat{flex:1;display:flex;flex-direction:column;align-items:center;gap:2px}.c2g-ar__val{font-size:2.25rem;font-weight:800;line-height:1;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary));font-variant-numeric:tabular-nums;letter-spacing:-.02em}.c2g-ar__unit{font-size:.875rem;font-weight:700;color:var(--c2g-theme-primary, var(--c2g-color-primary))}.c2g-ar__label{font-size:.65rem;text-transform:uppercase;letter-spacing:.07em;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted))}.c2g-ar__divider{width:1px;height:48px;background:var(--c2g-theme-outline-variant, var(--c2g-color-outline-variant))}.c2g-ar__max-tour{display:flex;align-items:center;gap:6px;padding:6px 10px;background:var(--c2g-theme-surface-container, var(--c2g-color-bg-secondary));border-radius:var(--c2g-radius-md, 10px)}.c2g-ar__max-icon{font-size:.875rem}.c2g-ar__max-name{font-size:.8rem;font-weight:600;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary));overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.c2g-ar__buckets{display:flex;align-items:flex-end;gap:6px;height:64px;padding-top:4px;border-top:1px solid var(--c2g-theme-outline-variant, var(--c2g-color-outline-variant))}.c2g-ar__bucket{flex:1;display:flex;flex-direction:column;align-items:center;gap:3px;height:100%;justify-content:flex-end}.c2g-ar__bucket-bar-wrap{flex:1;width:100%;display:flex;align-items:flex-end}.c2g-ar__bucket-bar{width:100%;border-radius:3px 3px 0 0;min-height:3px;background:var(--c2g-theme-primary, var(--c2g-color-primary));transition:height .7s cubic-bezier(.4,0,.2,1);opacity:.75}.c2g-ar__bucket-label{font-size:.55rem;font-weight:700;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));text-align:center;white-space:nowrap}.c2g-ar__bucket-count{font-size:.6rem;font-weight:800;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary))}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "pipe", type: i1$2.DecimalPipe, name: "number" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2816
+ }
2817
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AdventureRadiusWidgetComponent, decorators: [{
2818
+ type: Component,
2819
+ args: [{ selector: 'c2g-adventure-radius-widget', standalone: true, imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<article class=\"c2g-ar\">\n <header class=\"c2g-ar__header\">\n <span class=\"c2g-ar__icon\">{{ tierEmoji() }}</span>\n <div class=\"c2g-ar__titles\">\n <h3 class=\"c2g-ar__title\">Abenteuer-Radius</h3>\n @if (data().homeLabel) {\n <span class=\"c2g-ar__sub\">ab {{ data().homeLabel }}</span>\n }\n </div>\n <span class=\"c2g-ar__tier-badge c2g-ar__tier-badge--{{ radiusTier() }}\">\n {{ tierLabel() }}\n </span>\n </header>\n\n <div class=\"c2g-ar__hero\">\n <div class=\"c2g-ar__stat\">\n <span class=\"c2g-ar__val\">{{ data().avgRadiusKm | number:'1.0-0' }}</span>\n <span class=\"c2g-ar__unit\">km</span>\n <span class=\"c2g-ar__label\">\u00D8 Radius</span>\n </div>\n <div class=\"c2g-ar__divider\"></div>\n <div class=\"c2g-ar__stat\">\n <span class=\"c2g-ar__val\">{{ data().maxRadiusKm | number:'1.0-0' }}</span>\n <span class=\"c2g-ar__unit\">km</span>\n <span class=\"c2g-ar__label\">Maximum</span>\n </div>\n </div>\n\n @if (data().maxTourName) {\n <div class=\"c2g-ar__max-tour\">\n <span class=\"c2g-ar__max-icon\">\uD83D\uDCCD</span>\n <span class=\"c2g-ar__max-name\">{{ data().maxTourName }}</span>\n </div>\n }\n\n @if (buckets().length) {\n <div class=\"c2g-ar__buckets\">\n @for (b of buckets(); track b.labelKm) {\n <div class=\"c2g-ar__bucket\">\n <div class=\"c2g-ar__bucket-bar-wrap\">\n <div class=\"c2g-ar__bucket-bar\" [style.height.%]=\"bucketPct(b.count)\"></div>\n </div>\n <span class=\"c2g-ar__bucket-label\">{{ b.labelKm }}</span>\n <span class=\"c2g-ar__bucket-count\">{{ b.count }}</span>\n </div>\n }\n </div>\n }\n</article>\n", styles: [":host{display:block;font-family:var(--c2g-font-family-base, \"Quicksand\", sans-serif)}.c2g-ar{background:var(--c2g-theme-surface, var(--c2g-color-surface));border:1px solid var(--c2g-theme-outline-variant, var(--c2g-color-outline-variant));box-shadow:var(--c2g-shadow-sm, 0 1px 4px rgba(0, 0, 0, .06));border-radius:var(--c2g-radius-xl, 20px);padding:18px 20px 16px;display:flex;flex-direction:column;gap:12px;transition:box-shadow .2s ease,transform .2s ease}.c2g-ar:hover{box-shadow:var(--c2g-shadow-lg, 0 8px 28px rgba(0, 0, 0, .11));transform:translateY(-2px)}.c2g-ar__header{display:flex;align-items:center;gap:8px}.c2g-ar__icon{font-size:1.5rem;line-height:1}.c2g-ar__titles{flex:1;display:flex;flex-direction:column;gap:2px}.c2g-ar__title{margin:0;font-size:.72rem;font-weight:700;text-transform:uppercase;letter-spacing:.09em;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted))}.c2g-ar__sub{font-size:.75rem;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));opacity:.7}.c2g-ar__tier-badge{font-size:.7rem;font-weight:700;padding:3px 8px;border-radius:999px;white-space:nowrap}.c2g-ar__tier-badge--international{color:#a855f7;background:#a855f71a}.c2g-ar__tier-badge--national{color:#3b82f6;background:#3b82f61a}.c2g-ar__tier-badge--regional{color:#22c55e;background:#22c55e1a}.c2g-ar__tier-badge--local{color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));background:var(--c2g-theme-surface-container, var(--c2g-color-bg-secondary))}.c2g-ar__hero{display:flex;align-items:center;gap:0}.c2g-ar__stat{flex:1;display:flex;flex-direction:column;align-items:center;gap:2px}.c2g-ar__val{font-size:2.25rem;font-weight:800;line-height:1;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary));font-variant-numeric:tabular-nums;letter-spacing:-.02em}.c2g-ar__unit{font-size:.875rem;font-weight:700;color:var(--c2g-theme-primary, var(--c2g-color-primary))}.c2g-ar__label{font-size:.65rem;text-transform:uppercase;letter-spacing:.07em;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted))}.c2g-ar__divider{width:1px;height:48px;background:var(--c2g-theme-outline-variant, var(--c2g-color-outline-variant))}.c2g-ar__max-tour{display:flex;align-items:center;gap:6px;padding:6px 10px;background:var(--c2g-theme-surface-container, var(--c2g-color-bg-secondary));border-radius:var(--c2g-radius-md, 10px)}.c2g-ar__max-icon{font-size:.875rem}.c2g-ar__max-name{font-size:.8rem;font-weight:600;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary));overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.c2g-ar__buckets{display:flex;align-items:flex-end;gap:6px;height:64px;padding-top:4px;border-top:1px solid var(--c2g-theme-outline-variant, var(--c2g-color-outline-variant))}.c2g-ar__bucket{flex:1;display:flex;flex-direction:column;align-items:center;gap:3px;height:100%;justify-content:flex-end}.c2g-ar__bucket-bar-wrap{flex:1;width:100%;display:flex;align-items:flex-end}.c2g-ar__bucket-bar{width:100%;border-radius:3px 3px 0 0;min-height:3px;background:var(--c2g-theme-primary, var(--c2g-color-primary));transition:height .7s cubic-bezier(.4,0,.2,1);opacity:.75}.c2g-ar__bucket-label{font-size:.55rem;font-weight:700;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted));text-align:center;white-space:nowrap}.c2g-ar__bucket-count{font-size:.6rem;font-weight:800;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary))}\n"] }]
2820
+ }], propDecorators: { data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: true }] }] } });
2821
+
2822
+ class PackProgressWidgetComponent {
2823
+ data = input.required(...(ngDevMode ? [{ debugName: "data" }] : []));
2824
+ rows = computed(() => this.data().rows, ...(ngDevMode ? [{ debugName: "rows" }] : []));
2825
+ overallPacked = computed(() => this.rows().reduce((s, r) => s + r.packed, 0), ...(ngDevMode ? [{ debugName: "overallPacked" }] : []));
2826
+ overallTotal = computed(() => this.rows().reduce((s, r) => s + r.total, 0), ...(ngDevMode ? [{ debugName: "overallTotal" }] : []));
2827
+ overallPercent = computed(() => {
2828
+ const t = this.overallTotal();
2829
+ return t === 0 ? 0 : Math.round((this.overallPacked() / t) * 100);
2830
+ }, ...(ngDevMode ? [{ debugName: "overallPercent" }] : []));
2831
+ pct(row) {
2832
+ return row.total === 0 ? 0 : Math.round((row.packed / row.total) * 100);
2833
+ }
2834
+ tone(row) {
2835
+ const p = this.pct(row);
2836
+ if (p === 100)
2837
+ return 'success';
2838
+ if (p >= 50)
2839
+ return 'warning';
2840
+ return 'danger';
2841
+ }
2842
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: PackProgressWidgetComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2843
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: PackProgressWidgetComponent, isStandalone: true, selector: "c2g-pack-progress-widget", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<div class=\"c2g-pp\">\n\n <div class=\"c2g-pp__header\">\n <span class=\"c2g-pp__title\">\uD83D\uDCE6 Packfortschritt</span>\n @if (data().tourName) {\n <span class=\"c2g-pp__tour\">{{ data().tourName }}</span>\n }\n <span class=\"c2g-pp__overall\">{{ overallPacked() }}/{{ overallTotal() }}</span>\n </div>\n\n <div class=\"c2g-pp__rows\">\n @for (row of rows(); track row.label) {\n <div class=\"c2g-pp__row\" [class.c2g-pp__row--highlight]=\"row.highlight\">\n\n <div class=\"c2g-pp__row-label\">\n <span class=\"c2g-pp__row-icon\" aria-hidden=\"true\">{{ row.icon }}</span>\n <span class=\"c2g-pp__row-name\">{{ row.label }}</span>\n </div>\n\n <div class=\"c2g-pp__bar-wrap\" [attr.aria-label]=\"row.label + ': ' + row.packed + ' von ' + row.total + ' gepackt'\">\n <div\n class=\"c2g-pp__bar-fill\"\n [class.c2g-pp__bar-fill--success]=\"tone(row) === 'success'\"\n [class.c2g-pp__bar-fill--warning]=\"tone(row) === 'warning'\"\n [class.c2g-pp__bar-fill--danger]=\"tone(row) === 'danger'\"\n [style.width.%]=\"pct(row)\">\n </div>\n </div>\n\n <span\n class=\"c2g-pp__count\"\n [class.c2g-pp__count--success]=\"tone(row) === 'success'\"\n [class.c2g-pp__count--warning]=\"tone(row) === 'warning'\"\n [class.c2g-pp__count--danger]=\"tone(row) === 'danger'\">\n {{ row.packed }}/{{ row.total }}\n </span>\n\n </div>\n }\n </div>\n\n <!-- Overall strip -->\n <div class=\"c2g-pp__strip-track\">\n <div class=\"c2g-pp__strip-fill\" [style.width.%]=\"overallPercent()\"></div>\n </div>\n\n</div>\n", styles: [".c2g-pp{border:1px solid var(--c2g-theme-outline-variant, var(--c2g-color-outline-variant));border-radius:1rem;background:var(--c2g-theme-surface, var(--c2g-color-surface));overflow:hidden;display:grid;gap:0;transition:background var(--c2g-transition-medium, .25s ease),border-color var(--c2g-transition-medium, .25s ease)}.c2g-pp__header{display:flex;align-items:center;gap:.5rem;padding:.85rem 1rem .7rem}.c2g-pp__title{font-weight:700;font-size:.9rem;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary));flex:1}.c2g-pp__tour{font-size:.75rem;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted))}.c2g-pp__overall{font-size:.78rem;font-weight:600;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-secondary));background:var(--c2g-theme-surface-container, var(--c2g-color-neutral-100));border-radius:99px;padding:.1rem .5rem}.c2g-pp__rows{display:grid;gap:0;padding:0 1rem .75rem}.c2g-pp__row{display:grid;grid-template-columns:7rem 1fr 2.8rem;align-items:center;gap:.65rem;padding:.45rem 0;border-bottom:1px solid var(--c2g-color-outline-variant)}.c2g-pp__row:last-child{border-bottom:0}.c2g-pp__row--highlight{background:color-mix(in srgb,#f59e0b 5%,transparent);border-radius:.5rem;margin:0 -.5rem;padding:.45rem .5rem}.c2g-pp__row--highlight .c2g-pp__row-name{font-weight:600}.c2g-pp__row-label{display:flex;align-items:center;gap:.4rem;min-width:0}.c2g-pp__row-icon{font-size:1rem;line-height:1;flex-shrink:0}.c2g-pp__row-name{font-size:.82rem;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary));white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.c2g-pp__bar-wrap{height:.45rem;border-radius:99px;background:var(--c2g-theme-surface-container, var(--c2g-color-neutral-100));overflow:hidden}.c2g-pp__bar-fill{height:100%;border-radius:99px;transition:width .6s cubic-bezier(.4,0,.2,1)}.c2g-pp__bar-fill--success{background:#16a34a}.c2g-pp__bar-fill--warning{background:#f59e0b}.c2g-pp__bar-fill--danger{background:#ef4444}.c2g-pp__count{font-size:.75rem;font-weight:700;text-align:right;white-space:nowrap}.c2g-pp__count--success{color:#16a34a}.c2g-pp__count--warning{color:#d97706}.c2g-pp__count--danger{color:#dc2626}.c2g-pp__strip-track{height:3px;background:var(--c2g-theme-surface-container, var(--c2g-color-neutral-100))}.c2g-pp__strip-fill{height:100%;background:var(--c2g-color-secondary-dark, #2d6a4f);transition:width .7s cubic-bezier(.4,0,.2,1)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2844
+ }
2845
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: PackProgressWidgetComponent, decorators: [{
2846
+ type: Component,
2847
+ args: [{ selector: 'c2g-pack-progress-widget', standalone: true, imports: [], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"c2g-pp\">\n\n <div class=\"c2g-pp__header\">\n <span class=\"c2g-pp__title\">\uD83D\uDCE6 Packfortschritt</span>\n @if (data().tourName) {\n <span class=\"c2g-pp__tour\">{{ data().tourName }}</span>\n }\n <span class=\"c2g-pp__overall\">{{ overallPacked() }}/{{ overallTotal() }}</span>\n </div>\n\n <div class=\"c2g-pp__rows\">\n @for (row of rows(); track row.label) {\n <div class=\"c2g-pp__row\" [class.c2g-pp__row--highlight]=\"row.highlight\">\n\n <div class=\"c2g-pp__row-label\">\n <span class=\"c2g-pp__row-icon\" aria-hidden=\"true\">{{ row.icon }}</span>\n <span class=\"c2g-pp__row-name\">{{ row.label }}</span>\n </div>\n\n <div class=\"c2g-pp__bar-wrap\" [attr.aria-label]=\"row.label + ': ' + row.packed + ' von ' + row.total + ' gepackt'\">\n <div\n class=\"c2g-pp__bar-fill\"\n [class.c2g-pp__bar-fill--success]=\"tone(row) === 'success'\"\n [class.c2g-pp__bar-fill--warning]=\"tone(row) === 'warning'\"\n [class.c2g-pp__bar-fill--danger]=\"tone(row) === 'danger'\"\n [style.width.%]=\"pct(row)\">\n </div>\n </div>\n\n <span\n class=\"c2g-pp__count\"\n [class.c2g-pp__count--success]=\"tone(row) === 'success'\"\n [class.c2g-pp__count--warning]=\"tone(row) === 'warning'\"\n [class.c2g-pp__count--danger]=\"tone(row) === 'danger'\">\n {{ row.packed }}/{{ row.total }}\n </span>\n\n </div>\n }\n </div>\n\n <!-- Overall strip -->\n <div class=\"c2g-pp__strip-track\">\n <div class=\"c2g-pp__strip-fill\" [style.width.%]=\"overallPercent()\"></div>\n </div>\n\n</div>\n", styles: [".c2g-pp{border:1px solid var(--c2g-theme-outline-variant, var(--c2g-color-outline-variant));border-radius:1rem;background:var(--c2g-theme-surface, var(--c2g-color-surface));overflow:hidden;display:grid;gap:0;transition:background var(--c2g-transition-medium, .25s ease),border-color var(--c2g-transition-medium, .25s ease)}.c2g-pp__header{display:flex;align-items:center;gap:.5rem;padding:.85rem 1rem .7rem}.c2g-pp__title{font-weight:700;font-size:.9rem;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary));flex:1}.c2g-pp__tour{font-size:.75rem;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-muted))}.c2g-pp__overall{font-size:.78rem;font-weight:600;color:var(--c2g-theme-on-surface-variant, var(--c2g-color-text-secondary));background:var(--c2g-theme-surface-container, var(--c2g-color-neutral-100));border-radius:99px;padding:.1rem .5rem}.c2g-pp__rows{display:grid;gap:0;padding:0 1rem .75rem}.c2g-pp__row{display:grid;grid-template-columns:7rem 1fr 2.8rem;align-items:center;gap:.65rem;padding:.45rem 0;border-bottom:1px solid var(--c2g-color-outline-variant)}.c2g-pp__row:last-child{border-bottom:0}.c2g-pp__row--highlight{background:color-mix(in srgb,#f59e0b 5%,transparent);border-radius:.5rem;margin:0 -.5rem;padding:.45rem .5rem}.c2g-pp__row--highlight .c2g-pp__row-name{font-weight:600}.c2g-pp__row-label{display:flex;align-items:center;gap:.4rem;min-width:0}.c2g-pp__row-icon{font-size:1rem;line-height:1;flex-shrink:0}.c2g-pp__row-name{font-size:.82rem;color:var(--c2g-theme-on-surface, var(--c2g-color-text-primary));white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.c2g-pp__bar-wrap{height:.45rem;border-radius:99px;background:var(--c2g-theme-surface-container, var(--c2g-color-neutral-100));overflow:hidden}.c2g-pp__bar-fill{height:100%;border-radius:99px;transition:width .6s cubic-bezier(.4,0,.2,1)}.c2g-pp__bar-fill--success{background:#16a34a}.c2g-pp__bar-fill--warning{background:#f59e0b}.c2g-pp__bar-fill--danger{background:#ef4444}.c2g-pp__count{font-size:.75rem;font-weight:700;text-align:right;white-space:nowrap}.c2g-pp__count--success{color:#16a34a}.c2g-pp__count--warning{color:#d97706}.c2g-pp__count--danger{color:#dc2626}.c2g-pp__strip-track{height:3px;background:var(--c2g-theme-surface-container, var(--c2g-color-neutral-100))}.c2g-pp__strip-fill{height:100%;background:var(--c2g-color-secondary-dark, #2d6a4f);transition:width .7s cubic-bezier(.4,0,.2,1)}\n"] }]
2848
+ }], propDecorators: { data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: true }] }] } });
2849
+
2850
+ /**
2851
+ * Generated bundle index. Do not edit.
2852
+ */
2853
+
2854
+ export { ActionMenuComponent, AdventureRadiusWidgetComponent, AdventureScoreWidgetComponent, C2G_PACKING_CATEGORY_INFO, CampingScoreWidgetComponent, CriticalItemsAlertWidgetComponent, DEFAULT_PACKING_LIST_CONFIG, DEFAULT_PACKING_LIST_LABEL_KEYS, GearSharingWidgetComponent, GearValueWidgetComponent, GroupActivityWidgetComponent, GroupCompositionWidgetComponent, MainNavigationComponent, MainNavigationItemComponent, MemberItemComponent, MemberListComponent, MemberPanelComponent, MemberReadinessWidgetComponent, MemberTagsComponent, MenuComponent, NextAdventureWidgetComponent, PackProgressWidgetComponent, PackStatusWidgetComponent, PackWeightWidgetComponent, PackingListCategoryComponent, PackingListComponent, PackingListFiltersComponent, PackingListItemComponent, PackingListItemCreateComponent, PackingListPrivateListComponent, PackingListStatsComponent, RainVisualizationWidgetComponent, SeasonDnaWidgetComponent, StreakWidgetComponent, SubmenuComponent, SubmenuItemComponent, TopGearWidgetComponent, TotalKmWidgetComponent, TourRhythmWidgetComponent, TourTypeSplitWidgetComponent, WEATHER_ICON_MAP, WeatherWidgetComponent, WeightBreakdownWidgetComponent, WeightHistoryWidgetComponent, WindIndicatorWidgetComponent, resolvePackingCategory, resolveWeatherIcon };
2855
+ //# sourceMappingURL=camp2gether-c2g-ui-presets.mjs.map