PageSourceSearch

https://nomira-digital.webflow.io/privacy

html nomira-digital.webflow.io collected 2026-10-03 13:32:14 UTC 101,631 bytes, 2,433 lines download raw bytes

1<!DOCTYPE html><!-- This site was created in Webflow. https://webflow.com --><!-- Last Published: Sat Aug 22 2026 06:27:32 GMT+0000 (Coordinated Universal Time) --><html data-wf-domain="nomira-digital.webflow.io" data-wf-page="68ca7ac82e708712f7b3d802" data-wf-site="68ca7ac82e708712f7b3d78e" lang="en"><head><meta charset="utf-8"/><link href="https://cdn.prod.website-files.com" rel="preconnect" crossorigin="anonymous"/><title>nomíra | Legal Notice &amp; Privacy</title><meta content="Your privacy matters. This website collects only essential data to provide you with the best possible service and user experience." name="description"/><meta content="nomíra | Legal Notice &amp; Privacy" property="og:title"/><meta content="Your privacy matters. This website collects only essential data to provide you with the best possible service and user experience." property="og:description"/><meta content="https://cdn.prod.website-files.com/68ca7ac82e708712f7b3d78e/68cad7333f518a4ff3ed7d6e_og-EN.jpg" property="og:image"/><meta content="nomíra | Legal Notice &amp; Privacy" name="twitter:title"/><meta content="Your privacy matters. This website collects only essential data to provide you with the best possible service and user experience." name="twitter:description"/><meta property="og:type" content="website"/><meta content="summary_large_image" name="twitter:card"/><meta content="width=device-width, initial-scale=1" name="viewport"/><meta content="K4gNBmYpdEgu8Qikxa_cl6D_qjo1BJJGWEl2iznREn8" name="google-site-verification"/><meta content="Webflow" name="generator"/><meta content="noindex" name="robots"/><link href="https://cdn.prod.website-files.com/68ca7ac82e708712f7b3d78e/css/nomira-digital.webflow.shared.14ac27279.min.css" rel="stylesheet" type="text/css" integrity="sha384-FKwnJ52HchqX0euIjfNCUpYStEl+wQFmRQl6WABOuFpskTGTEv/Ew9NakbNzjhxU" crossorigin="anonymous"/>
1<script type="text/javascript">!function(o,c){var n=c.documentElement,t=" w-mod-";n.className+=t+"js",("ontouchstart"in o||o.DocumentTouch&&c instanceof DocumentTouch)&&(n.className+=t+"touch")}(window,document);</script>
1<link href="https://cdn.prod.website-files.com/68ca7ac82e708712f7b3d78e/68cae390c51bd1961ed7424a_favicon.svg" rel="icon" type="image/png" sizes="32x32" media="(prefers-color-scheme: light)"/><link href="https://cdn.prod.website-files.com/68ca7ac82e708712f7b3d78e/6a50c31af696bacd62c561fe_icon-black-purple.png" rel="icon" type="image/png" sizes="32x32" media="(prefers-color-scheme: dark)"/><link href="https://cdn.prod.website-files.com/68ca7ac82e708712f7b3d78e/68cae4becbb9ee8eb7e5665a_webclip.png" rel="apple-touch-icon"/>
1<script>(function(w,i,g){w[g]=w[g]||[];if(typeof w[g].push=='function')w[g].push.apply(w[g],Array.isArray(i)?i:[i]);})(window,['G-SC8C1J82JW'],'google_tags_first_party');</script>
1<script async="" src="/v2645sy3qzdjNjhjYTdhYzgyZTcwODcxMmY3YjNkNzhl/6LaLqsB0JJTTPErqcObpJbbyCMo"></script>
1<script type="text/javascript">window.dataLayer = window.dataLayer || [];function gtag(){dataLayer.push(arguments);}gtag('set', 'developer_id.dZGVlNj', true);gtag('set', 'developer_id.dYWYxNW', true);gtag('js', new Date());gtag('config', 'G-SC8C1J82JW');</script>
1<link rel="alternate" hreflang="en" href="https://nomira.digital" />
2<link rel="alternate" hreflang="de-CH" href="https://nomira.ch" />
3<link rel="alternate" hreflang="x-default" href="https://nomira.digital" />
4
5<script defer src="https://cloud.umami.is/script.js" data-website-id="b2edc94c-10c9-46bb-b9c8-15d51a9f1c9d"></script>
5
6
7<style>
8[data-initial-hidden] {
9  opacity: 0;
10  visibility: hidden;
11}
12</style>
13
14<script type="application/ld+json">
15{
16  "@context": "https://schema.org",
17  "@graph": [
18    {
19      "@type": "ProfessionalService",
20      "@id": "https://www.nomira.digital/#organization",
21      "name": "nomíra",
22      "alternateName": "nomíra by Damian Müller",
23      "url": "https://www.nomira.digital/",
24      "logo": {
25        "@type": "ImageObject",
26        "@id": "https://www.nomira.digital/#logo",
27        "url": "https://cdn.prod.website-files.com/67d92f01b6a76882209da7d7/67d939da653338dfb7a25f47_nomira-default.svg",
28        "contentUrl": "https://cdn.prod.website-files.com/67d92f01b6a76882209da7d7/67d939da653338dfb7a25f47_nomira-default.svg",
29        "caption": "nomíra"
30      },
31      "image": "https://cdn.prod.website-files.com/67d92f01b6a76882209da7d7/67f66e64bfe4a0b08f210f01_og-03.jpg",
32      "description": "nomíra is the UX and design studio of Damian Müller. Strategy, user experience, visual design and future-proof implementation following the Navigate. Craft. Evolve. approach — for digital experiences that truly move you forward. Simply Beyond.",
33      "slogan": "Simply Beyond",
34      "email": "[email protected]",
35      "founder": { "@id": "https://www.nomira.digital/#damianmueller" },
36      "knowsLanguage": ["en", "de"],
37      "address": {
38        "@type": "PostalAddress",
39        "streetAddress": "Walterhofstrasse 1",
40        "postalCode": "4656",
41        "addressLocality": "Starrkirch-Wil",
42        "addressRegion": "SO",
43        "addressCountry": "CH"
44      },
45      "areaServed": { "@type": "Place", "name": "Worldwide" },
46      "contactPoint": {
47        "@type": "ContactPoint",
48        "email": "[email protected]",
49        "contactType": "customer service",
50        "availableLanguage": ["en", "de"]
51      },
52      "sameAs": [
53        "https://www.nomira.ch/",
54        "https://ch.linkedin.com/in/damian-mueller-nomira",
55        "https://www.instagram.com/nomira_damianmueller/"
56      ],
57      "knowsAbout": [
58        "UX Design",
59        "User Experience",
60        "UI Design",
61        "Visual Design",
62        "Web Design",
63        "Digital Strategy",
64        "Webflow",
65        "Sanity CMS",
66        "Design Systems",
67        "Structured Content",
68        "Prototyping",
69        "User Testing",
70        "SEO",
71        "Answer Engine Optimization",
72        "Generative Engine Optimization"
73      ],
74      "hasOfferCatalog": {
75        "@type": "OfferCatalog",
76        "name": "Services & Formats",
77        "itemListElement": [
78          {
79            "@type": "Offer",
80            "itemOffered": {
81              "@type": "Service",
82              "name": "UX Design",
83              "description": "User-centered concept work: research, analysis, user testing, personas, user journeys and validated prototypes."
84            }
85          },
86          {
87            "@type": "Offer",
88            "itemOffered": {
89              "@type": "Service",
90              "name": "UI & Visual Design",
91              "description": "Visual design and interface craft: timeless, effective UI that brings brands to life."
92            }
93          },
94          {
95            "@type": "Offer",
96            "itemOffered": {
97              "@type": "Service",
98              "name": "Webflow Development",
99              "description": "Custom, maintenance-free and self-manageable Webflow websites — from implementation to continuous evolution."
100            }
101          },
102          {
103            "@type": "Offer",
104            "itemOffered": {
105              "@type": "Service",
106              "name": "Digital Strategy",
107              "description": "Digital sparring and strategy: question the status quo, uncover opportunities and sharpen direction."
108            }
109          },
110          {
111            "@type": "Offer",
112            "itemOffered": {
113              "@type": "Service",
114              "name": "Website Reality Check",
115              "description": "An honest outside view of your website in a compact analysis with concrete recommendations and clear next steps.",
116              "url": "https://www.nomira.digital/reality-check"
117            }
118          },
119          {
120            "@type": "Offer",
121            "itemOffered": {
122              "@type": "Service",
123              "name": "Prototype Sprint",
124              "description": "From idea to tested concept in three weeks — a clickable prototype with real user feedback and a clear direction for implementation.",
125              "url": "https://www.nomira.digital/prototype-sprint"
126            }
127          }
128        ]
129      }
130    },
131    {
132      "@type": "Person",
133      "@id": "https://www.nomira.digital/#damianmueller",
134      "name": "Damian Müller",
135      "jobTitle": "UX & Visual Designer, Founder",
136      "worksFor": { "@id": "https://www.nomira.digital/#organization" },
137      "url": "https://www.nomira.digital/",
138      "image": "https://cdn.prod.website-files.com/67d92f01b6a76882209da7d7/68caea30fdf9efd019f2cd0b_DM2503_0168_LowRes.webp",
139      "email": "[email protected]",
140      "knowsAbout": [
141        "UX Design",
142        "User Experience",
143        "Visual Design",
144        "UI Design",
145        "Digital Strategy",
146        "Webflow",
147        "Sanity CMS",
148        "Structured Content",
149        "Prototyping",
150        "User Testing"
151      ],
152      "sameAs": [
153        "https://ch.linkedin.com/in/damian-mueller-nomira",
154        "https://www.instagram.com/nomira_damianmueller/"
155      ]
156    },
157    {
158      "@type": "WebSite",
159      "@id": "https://www.nomira.digital/#website",
160      "url": "https://www.nomira.digital/",
161      "name": "nomíra",
162      "description": "Digital craftsmanship bridging strategy and design. Simply Beyond.",
163      "inLanguage": "en",
164      "publisher": { "@id": "https://www.nomira.digital/#organization" }
165    }
166  ]
167}
168</script>
168<style>
169[data-initial-hidden] {
170  opacity: 0;
171  visibility: hidden;
172}
173</style></head><body><div class="page-wrapper overflow-hidden"><div class="styles-wrapper"><div class="global-styles w-embed"><style>
174
175/* Make text look crisper and more legible in all browsers */
176body {
177  -webkit-font-smoothing: antialiased;
178  -moz-osx-font-smoothing: grayscale;
179  font-smoothing: antialiased;
180  text-rendering: optimizeLegibility;
181}
182
183/* Focus state style for keyboard navigation for the focusable elements */
184*[tabindex]:focus-visible,
185  input[type="file"]:focus-visible {
186   outline: 0.125rem solid #4d65ff;
187   outline-offset: 0.125rem;
188}
189
190/* Set color style to inherit */
191.inherit-color * {
192    color: inherit;
193}
194
195/* Get rid of top margin on first element in any rich text element */
196.w-richtext > :not(div):first-child, .w-richtext > div:first-child > :first-child {
197  margin-top: 0 !important;
198}
199
200/* Get rid of bottom margin on last element in any rich text element */
201.w-richtext>:last-child, .w-richtext ol li:last-child, .w-richtext ul li:last-child {
202	margin-bottom: 0 !important;
203}
204
205
206/* Make sure containers never lose their center alignment */
207.container-medium,.container-small, .container-large {
208	margin-right: auto !important;
209  margin-left: auto !important;
210}
211
212/* 
213Make the following elements inherit typography styles from the parent and not have hardcoded values. 
214Important: You will not be able to style for example "All Links" in Designer with this CSS applied.
215Uncomment this CSS to use it in the project. Leave this message for future hand-off.
216*/
217/*
218a,
219.w-input,
220.w-select,
221.w-tab-link,
222.w-nav-link,
223.w-dropdown-btn,
224.w-dropdown-toggle,
225.w-dropdown-link {
226  color: inherit;
227  text-decoration: inherit;
228  font-size: inherit;
229}
230*/
231
232/* Apply "..." after 3 lines of text */
233.text-style-3lines {
234	display: -webkit-box;
235	overflow: hidden;
236	-webkit-line-clamp: 3;
237	-webkit-box-orient: vertical;
238}
239
240/* Apply "..." after 2 lines of text */
241.text-style-2lines {
242	display: -webkit-box;
243	overflow: hidden;
244	-webkit-line-clamp: 2;
245	-webkit-box-orient: vertical;
246}
247
248/* These classes are never overwritten */
249.hide {
250  display: none !important;
251}
252
253@media screen and (max-width: 991px) {
254    .hide, .hide-tablet {
255        display: none !important;
256    }
257}
258  @media screen and (max-width: 767px) {
259    .hide-mobile-landscape{
260      display: none !important;
261    }
262}
263  @media screen and (max-width: 479px) {
264    .hide-mobile{
265      display: none !important;
266    }
267}
268 
269.margin-0 {
270  margin: 0rem !important;
271}
272  
273.padding-0 {
274  padding: 0rem !important;
275}
276
277.spacing-clean {
278padding: 0rem !important;
279margin: 0rem !important;
280}
281
282.margin-top {
283  margin-right: 0rem !important;
284  margin-bottom: 0rem !important;
285  margin-left: 0rem !important;
286}
287
288.padding-top {
289  padding-right: 0rem !important;
290  padding-bottom: 0rem !important;
291  padding-left: 0rem !important;
292}
293  
294.margin-right {
295  margin-top: 0rem !important;
296  margin-bottom: 0rem !important;
297  margin-left: 0rem !important;
298}
299
300.padding-right {
301  padding-top: 0rem !important;
302  padding-bottom: 0rem !important;
303  padding-left: 0rem !important;
304}
305
306.margin-bottom {
307  margin-top: 0rem !important;
308  margin-right: 0rem !important;
309  margin-left: 0rem !important;
310}
311
312.padding-bottom {
313  padding-top: 0rem !important;
314  padding-right: 0rem !important;
315  padding-left: 0rem !important;
316}
317
318.margin-left {
319  margin-top: 0rem !important;
320  margin-right: 0rem !important;
321  margin-bottom: 0rem !important;
322}
323  
324.padding-left {
325  padding-top: 0rem !important;
326  padding-right: 0rem !important;
327  padding-bottom: 0rem !important;
328}
329  
330.margin-horizontal {
331  margin-top: 0rem !important;
332  margin-bottom: 0rem !important;
333}
334
335.padding-horizontal {
336  padding-top: 0rem !important;
337  padding-bottom: 0rem !important;
338}
339
340.margin-vertical {
341  margin-right: 0rem !important;
342  margin-left: 0rem !important;
343}
344  
345.padding-vertical {
346  padding-right: 0rem !important;
347  padding-left: 0rem !important;
348}
349
350</style></div><div class="custom-styles w-embed"><style>
351/* Bouncing verhindern bei schnellen Scrollen zum Top oder Bottom der Seite */
352body {
353  overscroll-behavior: none;
354}
355
356section, header, footer {
357	position: relative;
358}
359
360/* Softe Übergänge bei Unterseiten-Wechsel */
361@view-transition {
362  navigation: auto;
363}
364
365/* Automatische Silbentrennung durch Vergabe von Attributen "data-hyphenate" ("true") und "lang" ("de", "en"...) */
366[data-hyphenate="true"] {
367    hyphens: auto;
368    overflow-wrap: break-word; /* oder word-wrap für ältere Browser */
369    -webkit-hyphens: auto;
370    -ms-hyphens: auto;
371}
372
373[data-hyphenate="true"] * {
374    hyphens: auto;
375    overflow-wrap: break-word;
376    -webkit-hyphens: auto;
377    -ms-hyphens: auto;
378}
379
380button {
381	background-color: unset;
382	padding: unset;
383	text-align: inherit;
384}
385button:not(:disabled) {
386	cursor: pointer;
387}
388
389a:not([class]) {
390	text-decoration: none !important;
391}
392
393/* Global / Clickable Component */
394.wf-design-mode .g_clickable_wrap {
395	z-index: 0;
396}
397.g_clickable_wrap a[href="#"] {
398	display: none;
399}
400.g_clickable_wrap a[href="#"] ~ button {
401	display: block;
402}
403
404.cta-icon {
405  transition: transform 300ms ease-out;
406}
407.cta-wrapper:has(.cta-link-wrapper:hover) .cta-icon {
408  transform: rotate(-35deg);
409}
410
411/* ---------------------
412CSS für WORK SECTION
413--------------------- */
414
415html:not(.wf-design-mode) .work_img-wrapper {
416	opacity: 0;
417}
418
419html:not(.wf-design-mode) .section_work .g_clickable_wrap a,
420html:not(.wf-design-mode) .section_work .g_clickable_wrap button {
421	cursor: none;
422}
423
424
425/* ---------------------
426CSS für HEADING ICONS	
427--------------------- */
428
429/* Das letzte Wort als Wrapper (relative Positionierung für die innere absolute Positionierung) */
430.last-word {
431  position: relative;
432  display: inline-block;
433}
434
435/* Positioniere das Icon relativ zum .last-word-Span */
436.last-word .heading-icon {
437  position: absolute;
438  bottom: 0;	
439  right: 0; 	
440  transform: translate(95%, 50%);
441}
442
443</style></div><div class="nav-styles w-embed"><style>
444
445body:has(.nav_component .w-nav-button.w--open) { 
446	overflow: hidden;
447}
448
449/* Standard: geschlossen */
450.nav_component:has(.w-nav-button:not(.w--open)) .w-nav-menu {
451 	display: block;
452  position: fixed !important;
453  opacity: 0;
454  pointer-events: none;
455  transition: opacity 0.4s ease-out;
456}
457
458/* Geöffnet: weicher Fade-In */
459.nav_component:has(.w-nav-button.w--open) .w-nav-menu {
460 	display: block;
461  opacity: 1;
462  position: fixed !important;
463  pointer-events: auto;
464}
465
466/* Menu Button: Menü geschlossen */
467.nav_menu-icon-text-close {
468  display: none; 
469}
470.nav_menu-icon-text {
471  display: block; 
472}
473.nav_menu-icon {
474  transform: rotate(0deg);
475}
476
477/* Menu Button: Menü geöffnet */
478
479.nav_component:has(.w-nav-button.w--open) .nav_menu-icon-text-close {
480  display: block; 
481}
482
483.nav_component:has(.w-nav-button.w--open) .nav_menu-icon-text {
484  display: none;
485}
486
487.nav_component:has(.w-nav-button.w--open) .nav_menu-icon {
488  transform: rotate(45deg);
489}
490
491.nav_component:has(.w-nav-button.w--open) .btn_wrap.is-nav {
492  visibility: hidden;
493  pointer-events: none;
494}
495
496/* Menu clip-paths*/
497@media (min-width: 992px) {
498	.nav_menu {
499	clip-path: polygon(0% 13%, 73% 0%, 100% 0%, 100% 100%, 0% 100%)
500	}
501}
502@media (min-width: 480px) and (max-width: 991px) {
503	.nav_menu {
504	clip-path: polygon(0% 9%, 73% 0%, 100% 0%, 100% 100%, 0% 100%)
505	}
506}
507@media (max-width: 479px) {
508	.nav_menu {
509	clip-path: polygon(0% 7%, 75% 0%, 100% 0%, 100% 100%, 0% 100%)
510	}
511}
512
513.cta-2-icon {
514  transition: transform 300ms ease-out;
515}
516.cta-2-wrapper:has(.cta-2-link-wrapper:hover) .cta-2-icon {
517  transform: rotate(-35deg);
518}
519
520
521</style></div><div class="accordion-styles w-embed"><style>
522/* 
523---------------
524ALL ACCORDIONS
525---------------
526*/
527html:not(.wf-design-mode) .services_item,
528html:not(.wf-design-mode) .approach_item,
529html:not(.wf-design-mode) .webflow-benefits_item,
530html:not(.wf-design-mode) .services_description,
531html:not(.wf-design-mode) .approach_description,
532html:not(.wf-design-mode) .webflow-benefits_description {
533	pointer-events: none;
534  user-select: none;
535}
536
537
538/* 
539---------------
540SERVICES
541---------------
542*/
543
544.wf-design-mode .services_dropdown-height {
545	grid-template-rows: 1fr;
546}
547.wf-design-mode .services_dropdown-checkbox {
548	pointer-events: none;
549}
550
551
552.wf-design-mode .services_description {
553  opacity: 1;
554}
555.services_dropdown:has(.services_dropdown-checkbox:checked) .services_description {
556  opacity: 1;
557}
558.services_dropdown:has(.services_dropdown-checkbox:checked) .services_icon {
559  opacity: 0;
560  visibility: hidden;
561}
562
563
564@media (min-width: 992px) {
565	.services_dropdown:has(.services_dropdown-checkbox:checked) .services_dropdown-height {
566	  grid-template-rows: 1fr;
567	  margin-top: -2.5rem;
568	}
569	.services_dropdown:has(.services_dropdown-checkbox:checked) .services_item.is-1 {
570	  transform: translateX(7rem);
571	}
572	.services_dropdown:has(.services_dropdown-checkbox:checked) .services_item.is-2 {
573	  transform: translateX(-7rem);
574	}
575	.services_dropdown:has(.services_dropdown-checkbox:checked) .services_item.is-3 {
576	  transform: translateX(4rem);
577	}
578	.services_dropdown:has(.services_dropdown-checkbox:checked) .services_item.is-4 {
579	  transform: translateX(-5rem);
580	}
581}
582
583@media (max-width: 991px) {
584	.services_dropdown:has(.services_dropdown-checkbox:checked) .services_dropdown-height {
585	  grid-template-rows: 1fr;
586	  margin-top: -1.5rem;
587	}
588}
589
590.services_dropdown:has(.services_dropdown-checkbox:checked) .services_border {
591	margin-left: 0 !important;
592  margin-right: 0 !important;
593}
594
595
596/* 
597---------------
598APPROACH
599---------------
600*/
601
602.wf-design-mode .approach_dropdown-height {
603	grid-template-rows: 1fr;
604}
605.wf-design-mode .approach_dropdown-checkbox {
606	pointer-events: none;
607}
608
609
610.wf-design-mode .approach_description {
611  opacity: 1;
612}
613.approach_dropdown:has(.approach_dropdown-checkbox:checked) .approach_description {
614  opacity: 1;
615}
616.approach_dropdown:has(.approach_dropdown-checkbox:checked) .approach_icon {
617  opacity: 0;
618  visibility: hidden;
619}
620
621@media (min-width: 992px) {
622	.approach_dropdown:has(.approach_dropdown-checkbox:checked) .approach_dropdown-height {
623	  grid-template-rows: 1fr;
624	  margin-top: -2.5rem;
625	}
626	.approach_dropdown:has(.approach_dropdown-checkbox:checked) .approach_item.is-1 {
627	  transform: translateX(-8vw);
628	}
629	.approach_dropdown:has(.approach_dropdown-checkbox:checked) .approach_item.is-2 {
630	  transform: translateX(-9vw);
631	}
632	.approach_dropdown:has(.approach_dropdown-checkbox:checked) .approach_item.is-3 {
633	  transform: translateX(15vw);
634	}
635}
636
637@media (max-width: 991px) {
638	.approach_dropdown:has(.approach_dropdown-checkbox:checked) .approach_dropdown-height {
639	  grid-template-rows: 1fr;
640	  margin-top: -1.5rem;
641	}
642}
643
644
645.approach_dropdown:has(.approach_dropdown-checkbox:checked) .approach_border {
646	margin-left: 0 !important;
647  margin-right: 0 !important;
648}
649
650/* 
651---------------
652Webflow Benefits
653---------------
654*/
655
656.wf-design-mode .webflow-benefits_dropdown-height {
657	grid-template-rows: 1fr;
658}
659.wf-design-mode .webflow-benefits_dropdown-checkbox {
660	pointer-events: none;
661}
662
663
664.wf-design-mode .webflow-benefits_description {
665  opacity: 1;
666}
667.webflow-benefits_dropdown:has(.webflow-benefits_dropdown-checkbox:checked) .webflow-benefits_description {
668  opacity: 1;
669}
670.webflow-benefits_dropdown:has(.webflow-benefits_dropdown-checkbox:checked) .webflow-benefits_icon {
671  opacity: 0;
672  visibility: hidden;
673}
674
675@media (min-width: 992px) {
676	.webflow-benefits_dropdown:has(.webflow-benefits_dropdown-checkbox:checked) .webflow-benefits_dropdown-height {
677	  grid-template-rows: 1fr;
678	  margin-top: -2.5rem;
679	}
680	.webflow-benefits_dropdown:has(.webflow-benefits_dropdown-checkbox:checked) .webflow-benefits_item.is-1 {
681	  transform: translateX(-8vw);
682	}
683	.webflow-benefits_dropdown:has(.webflow-benefits_dropdown-checkbox:checked) .webflow-benefits_item.is-2 {
684	  transform: translateX(-9vw);
685	}
686	.webflow-benefits_dropdown:has(.webflow-benefits_dropdown-checkbox:checked) .webflow-benefits_item.is-3 {
687	  transform: translateX(15vw);
688	}
689}
690
691@media (max-width: 991px) {
692	.webflow-benefits_dropdown:has(.webflow-benefits_dropdown-checkbox:checked) .webflow-benefits_dropdown-height {
693	  grid-template-rows: 1fr;
694	  margin-top: -1.5rem;
695	}
696}
697
698
699.webflow-benefits_dropdown:has(.webflow-benefits_dropdown-checkbox:checked) .webflow-benefits_border {
700	margin-left: 0 !important;
701  margin-right: 0 !important;
702}
703
704</style></div><div class="custom-cursor-styles w-embed"><style>
705/* Custom Cursor CSS für Desktop only */
706@media (max-width: 991px) {
707	.custom-cursor-dropdowns,
708  .custom-cursor-links,
709  .custom-cursor-offer {
710	  display: none;
711	}
712}
713
714@media (min-width: 992px) {
715	/* Basisstil für alle dropdown-bezogenen Elemente */
716	html:not(.wf-design-mode) .services_dropdown,
717	html:not(.wf-design-mode) .services_dropdown-checkbox,
718  html:not(.wf-design-mode) .approach_dropdown,
719	html:not(.wf-design-mode) .approach_dropdown-checkbox,
720  html:not(.wf-design-mode) .webflow-benefits_dropdown,
721	html:not(.wf-design-mode) .webflow-benefits_dropdown-checkbox,
722  html:not(.wf-design-mode) .work_item,
723  html:not(.wf-design-mode) .offer_card a {
724	  cursor: none !important;
725	}
726}
727
728html:not(.wf-design-mode) .custom-cursor-dropdowns,
729html:not(.wf-design-mode) .custom-cursor-links,
730html:not(.wf-design-mode) .custom-cursor-offer {
731  opacity: 0;
732}
733
734html:not(.wf-design-mode) .custom-cursor-dropdowns.active,
735html:not(.wf-design-mode) .custom-cursor-links.active,
736html:not(.wf-design-mode) .custom-cursor-offer.active {
737  opacity: 1;
738}
739
740</style></div><style>:root {--site--margin: clamp(2rem, 1.84375rem + 0.78125vw, 2.5rem);}</style></div><div class="styleguide_guide_wrap"><div class="w-embed"><style>
741html:not(.wf-design-mode) .styleguide_guide_wrap {
742	display: none;
743}
744.styleguide_guide_layout {
745	counter-reset: gridguides;
746}
747.styleguide_guide_layout > div::before {
748  counter-increment: gridguides;
749  content: counter(gridguides);
750}
751
752:root {
753    --site--max-width: min(var(--site--width), 100vw);
754    --container--main: calc(var(--site--max-width) - var(--site--margin) * 2);
755    --container--full: calc(100vw - var(--site--margin) * 2);
756    --site--gutter-total: calc(var(--site--gutter) * (var(--site--column-count) - 1));
757    --column-width--1: calc((var(--container--main) - var(--site--gutter-total)) / var(--site--column-count));
758    --column-width--plus-gutter: calc(var(--column-width--1) + var(--site--gutter));
759    --column-width--2: calc(var(--column-width--plus-gutter) * 2 - var(--site--gutter));
760    --column-width--3: calc(var(--column-width--plus-gutter) * 3 - var(--site--gutter));
761    --column-width--4: calc(var(--column-width--plus-gutter) * 4 - var(--site--gutter));
762    --column-width--5: calc(var(--column-width--plus-gutter) * 5 - var(--site--gutter));
763    --column-width--6: calc(var(--column-width--plus-gutter) * 6 - var(--site--gutter));
764    --column-width--7: calc(var(--column-width--plus-gutter) * 7 - var(--site--gutter));
765    --column-width--8: calc(var(--column-width--plus-gutter) * 8 - var(--site--gutter));
766    --column-width--9: calc(var(--column-width--plus-gutter) * 9 - var(--site--gutter));
767    --column-width--10: calc(var(--column-width--plus-gutter) * 10 - var(--site--gutter));
768    --column-width--11: calc(var(--column-width--plus-gutter) * 11 - var(--site--gutter));
769    --column-width--12: calc(var(--column-width--plus-gutter) * 12 - var(--site--gutter));
770    --column-margin--1: calc(var(--column-width--plus-gutter) * 1);
771    --column-margin--2: calc(var(--column-width--plus-gutter) * 2);
772    --column-margin--3: calc(var(--column-width--plus-gutter) * 3);
773    --column-margin--4: calc(var(--column-width--plus-gutter) * 4);
774    --column-margin--5: calc(var(--column-width--plus-gutter) * 5);
775    --column-margin--6: calc(var(--column-width--plus-gutter) * 6);
776    --column-margin--7: calc(var(--column-width--plus-gutter) * 7);
777    --column-margin--8: calc(var(--column-width--plus-gutter) * 8);
778    --column-margin--9: calc(var(--column-width--plus-gutter) * 9);
779    --column-margin--10: calc(var(--column-width--plus-gutter) * 10);
780    --column-margin--11: calc(var(--column-width--plus-gutter) * 11);
781    --column-margin--12: calc(var(--column-width--plus-gutter) * 12);
782    --breakout-start: [full-start] minmax(0, 1fr) [content-start];
783    --breakout-end: [content-end] minmax(0, 1fr) [full-end];
784    --grid-breakout-single: var(--breakout-start) minmax(0, var(--container--main)) var(--breakout-end);
785    --grid-breakout: var(--breakout-start) repeat(var(--site--column-count), minmax(0, var(--column-width--1))) var(--breakout-end);
786    --grid-main: repeat(var(--site--column-count), minmax(0, 1fr));
787    --grid-1: repeat(1, minmax(0, 1fr));
788    --grid-2: repeat(2, minmax(0, 1fr));
789    --grid-3: repeat(3, minmax(0, 1fr));
790    --grid-4: repeat(4, minmax(0, 1fr));
791    --grid-5: repeat(5, minmax(0, 1fr));
792    --grid-6: repeat(6, minmax(0, 1fr));
793    --grid-7: repeat(7, minmax(0, 1fr));
794    --grid-8: repeat(8, minmax(0, 1fr));
795    --grid-9: repeat(9, minmax(0, 1fr));
796    --grid-10: repeat(10, minmax(0, 1fr));
797    --grid-11: repeat(11, minmax(0, 1fr));
798    --grid-12: repeat(12, minmax(0, 1fr));
799}
800</style></div><div data-padding-bottom="none" data-padding-top="none" class="styleguide_guide_contain u-container"><div class="styleguide_guide_layout u-grid-custom"><div class="styleguide_guide_column u-vflex-center-bottom"></div><div class="styleguide_guide_column u-vflex-center-bottom"></div><div class="styleguide_guide_column u-vflex-center-bottom"></div><div class="styleguide_guide_column u-vflex-center-bottom"></div><div class="styleguide_guide_column u-vflex-center-bottom"></div><div class="styleguide_guide_column u-vflex-center-bottom"></div><div class="styleguide_guide_column u-vflex-center-bottom"></div><div class="styleguide_guide_column u-vflex-center-bottom"></div><div class="styleguide_guide_column u-vflex-center-bottom"></div><div class="styleguide_guide_column u-vflex-center-bottom"></div><div class="styleguide_guide_column u-vflex-center-bottom"></div><div class="styleguide_guide_column u-vflex-center-bottom"></div><div class="styleguide_guide_column u-vflex-center-bottom"></div><div class="styleguide_guide_column u-vflex-center-bottom"></div><div class="styleguide_guide_column u-vflex-center-bottom"></div><div class="styleguide_guide_column u-vflex-center-bottom"></div><div class="styleguide_guide_column u-vflex-center-bottom"></div><div class="styleguide_guide_column u-vflex-center-bottom"></div><div class="styleguide_guide_column u-vflex-center-bottom"></div><div class="styleguide_guide_column u-vflex-center-bottom"></div><div class="styleguide_guide_column u-vflex-center-bottom"></div><div class="styleguide_guide_column u-vflex-center-bottom"></div><div class="styleguide_guide_column u-vflex-center-bottom"></div><div class="styleguide_guide_column u-vflex-center-bottom"></div></div></div></div>
800<div data-animation="over-right" class="nav_component padding-global w-nav" data-easing2="ease" fs-scrolldisable-element="smart-nav" data-easing="ease" data-collapse="all" role="banner" data-initial-hidden="" data-duration="0" data-gsap-init="fade"><div class="nav_container"><div data-cal-config="{&quot;layout&quot;:&quot;month_view&quot;,&quot;theme&quot;:&quot;dark&quot;}" data-cal-link="nomira/lets-talk" data-cal-namespace="lets-talk" class="btn_wrap is-nav"><div class="g_clickable_wrap"><a target="" href="#" class="g_clickable_link w-inline-block"><span class="g_clickable_text screenreader-only">Let’s Talk</span></a><button type="button" class="g_clickable_btn"><span class="g_clickable_text screenreader-only">Let’s Talk</span></button></div><svg xmlns="http://www.w3.org/2000/svg" width="100%" viewBox="0 0 32 32" fill="none" class="btn-icon"><path d="M8 22C11.3137 22 14 19.3137 14 16C14 12.6863 11.3137 10 8 10C4.68629 10 2 12.6863 2 16C2 19.3137 4.68629 22 8 22Z" fill="currentColor"></path><path d="M24 22C27.3137 22 30 19.3137 30 16C30 12.6863 27.3137 10 24 10C20.6863 10 18 12.6863 18 16C18 19.3137 20.6863 22 24 22Z" fill="currentColor"></path></svg><div aria-hidden="true" class="btn_text">Let’s Talk</div></div><a href="/" class="nav_logo-link w-nav-brand"><img loading="lazy" src="https://cdn.prod.website-files.com/68ca7ac82e708712f7b3d78e/68ca7ac82e708712f7b3d7c1_nomira-default.svg" alt="nomíra by damian müller" class="nav_logo"/></a><div id="w-node-_8910e862-9853-9741-3b2f-84472168ecc2-2168ecbb" class="nav_menu-button w-nav-button"><div class="nav_menu-icon-wrapper"><div class="nav_menu-icon-text">Menu</div><div class="nav_menu-icon-text-close">close</div><svg xmlns="http://www.w3.org/2000/svg" width="100%" viewBox="0 0 32 32" fill="none" class="nav_menu-icon"><path d="M8 14C11.3137 14 14 11.3137 14 8C14 4.68629 11.3137 2 8 2C4.68629 2 2 4.68629 2 8C2 11.3137 4.68629 14 8 14Z" fill="currentColor"></path><path d="M24 14C27.3137 14 30 11.3137 30 8C30 4.68629 27.3137 2 24 2C20.6863 2 18 4.68629 18 8C18 11.3137 20.6863 14 24 14Z" fill="currentColor"></path><path d="M8 30C11.3137 30 14 27.3137 14 24C14 20.6863 11.3137 18 8 18C4.68629 18 2 20.6863 2 24C2 27.3137 4.68629 30 8 30Z" fill="currentColor"></path><path d="M24 30C27.3137 30 30 27.3137 30 24C30 20.6863 27.3137 18 24 18C20.6863 18 18 20.6863 18 24C18 27.3137 20.6863 30 24 30Z" fill="currentColor"></path></svg></div></div><nav role="navigation" class="nav_menu padding-global w-nav-menu"><div class="nav_menu-layout container-medium"><div class="nav_menu-layout-left"><div data-cal-link="nomira/lets-talk" data-cal-namespace="lets-talk" data-cal-config="{&quot;layout&quot;:&quot;month_view&quot;,&quot;theme&quot;:&quot;dark&quot;}" STYLE="max-width: min-content;" class="cta-2-wrapper"><div class="cta-2-link-wrapper"><svg xmlns="http://www.w3.org/2000/svg" width="100%" viewBox="0 0 54 54" fill="none" class="cta-2-icon icon-1x1-large"><g clip-path="url(#clip0_38_2261)"><path d="M27 52.3125C40.9797 52.3125 52.3125 40.9797 52.3125 27C52.3125 13.0203 40.9797 1.6875 27 1.6875C13.0203 1.6875 1.6875 13.0203 1.6875 27C1.6875 40.9797 13.0203 52.3125 27 52.3125Z" stroke="currentColor" stroke-width="3.375" stroke-linecap="round" stroke-linejoin="round"></path><path d="M13.5 27H28.6875" stroke="currentColor" stroke-width="3.375" stroke-linecap="round" stroke-linejoin="round"></path><path d="M28.6875 35.4375V18.5625L40.5 27L28.6875 35.4375Z" stroke="currentColor" stroke-width="3.375" stroke-linecap="round" stroke-linejoin="round"></path></g></svg><div class="g_clickable_wrap"><a target="" href="#" class="g_clickable_link w-inline-block"><span class="g_clickable_text screenreader-only">Let’s Talk</span></a><button type="button" class="g_clickable_btn"><span class="g_clickable_text screenreader-only">Let’s Talk</span></button></div></div><div class="cta-2-link-wrapper"><div aria-hidden="true" class="cta-2-text">Let’s Talk</div><div class="g_clickable_wrap"><a target="" href="#" class="g_clickable_link w-inline-block"><span class="g_clickable_text screenreader-only">Let’s Talk</span></a><button type="button" class="g_clickable_btn"><span class="g_clickable_text screenreader-only">Let’s Talk</span></button></div></div></div><div class="nav_menu-brand">
800<svg xmlns="http://www.w3.org/2000/svg" width="100%" viewBox="0 0 216 54" fill="none" class="nav_menu-brand-logo"><path d="M211.918 46.7743L210.341 44.4082L215.255 46.5923V52.6591L202.454 53.2658L200.937 47.5629L201.665 47.745C200.29 49.6459 198.713 51.1019 196.933 52.1131C195.194 53.0837 193.253 53.5691 191.109 53.5691C188.157 53.5691 185.811 52.6388 184.072 50.7784C182.332 48.9179 181.463 46.4305 181.463 43.3162C181.463 41.0917 181.948 39.2716 182.919 37.8561C183.89 36.4405 185.366 35.3889 187.348 34.7013C189.37 34.0137 191.938 33.67 195.053 33.67H200.391L199.785 34.2766V32.0926C199.785 30.5557 199.461 29.4636 198.814 28.8165C198.167 28.1289 197.115 27.7852 195.659 27.7852C195.053 27.7852 194.365 27.8256 193.597 27.9065C192.828 27.9874 192.019 28.1289 191.17 28.3312L192.08 27.2391L191.109 31.5466H183.829L183.344 21.415C186.498 20.6061 189.37 19.9994 191.958 19.595C194.587 19.1905 196.953 18.9883 199.057 18.9883C203.384 18.9883 206.6 19.8781 208.703 21.6577C210.846 23.4373 211.918 26.1673 211.918 29.8479V46.7743ZM193.597 41.8602C193.597 42.9926 193.839 43.8218 194.325 44.3475C194.85 44.8733 195.497 45.1362 196.266 45.1362C196.913 45.1362 197.58 44.9744 198.268 44.6509C198.956 44.2869 199.582 43.7813 200.149 43.1342L199.785 44.4689V38.4627L200.452 39.1301H197.055C195.801 39.1301 194.911 39.3323 194.385 39.7368C193.859 40.1412 193.597 40.849 193.597 41.8602Z" fill="currentColor"></path><path d="M153.152 52.6591V46.5923L157.52 44.8936L156.489 46.5923V26.1471L157.702 28.0278L153.152 26.2078V20.141L165.953 19.5343L167.409 25.1158L165.893 24.8124C167.794 22.9115 169.634 21.4757 171.413 20.505C173.193 19.4938 175.074 18.9883 177.056 18.9883C178.35 18.9883 179.745 19.1905 181.242 19.595L180.635 33.1846H173.719L172.687 26.3898L173.719 28.6345C173.557 28.5536 173.375 28.4929 173.173 28.4525C172.971 28.4121 172.768 28.3918 172.566 28.3918C171.676 28.3918 170.766 28.6952 169.836 29.3019C168.906 29.8681 168.198 30.5557 167.713 31.3646L168.623 28.2705V46.5923L167.349 44.8936L172.869 46.5923V52.6591H153.152Z" fill="currentColor"></path><path d="M148.123 45.8649L147.395 44.9548L151.459 46.5929V52.6597H132.652V46.5929L136.717 44.9548L135.989 45.8649V27.1184L136.596 27.7251L132.652 26.2084V20.1416L148.123 19.6562V45.8649Z" fill="currentColor"></path><path d="M108.014 24.1451L106.315 24.6911C108.216 22.7901 110.238 21.3746 112.382 20.4443C114.525 19.4736 116.568 18.9883 118.509 18.9883C121.138 18.9883 123.342 19.8579 125.122 21.597C126.942 23.3362 127.852 25.9853 127.852 29.5445V46.4103L126.881 44.8329L131.189 46.5923V52.6591H115.719V32.2139C115.719 30.7983 115.456 29.767 114.93 29.1199C114.445 28.4323 113.777 28.0885 112.928 28.0885C112.281 28.0885 111.532 28.2907 110.683 28.6952C109.874 29.0996 109.025 29.6861 108.135 30.4545L108.984 27.9065C109.025 28.2301 109.045 28.4929 109.045 28.6952C109.045 28.857 109.045 28.9783 109.045 29.0592V46.4103L108.074 44.8329L112.382 46.5923V52.6591H96.9114V32.2139C96.9114 30.7983 96.6485 29.767 96.1227 29.1199C95.597 28.4323 94.9296 28.0885 94.1207 28.0885C93.4736 28.0885 92.7456 28.2907 91.9366 28.6952C91.1277 29.0592 90.3188 29.585 89.5099 30.2725L90.2379 28.7558V46.6529L89.2673 45.0149L93.5747 46.5923V52.6591H74.7676V46.5923L79.439 44.7722L78.1043 46.4103V26.2078L79.439 28.0278L74.7676 26.2078V20.141L87.5685 19.5343L89.0246 25.1764L87.5079 24.6911C89.3684 22.871 91.3704 21.4757 93.514 20.505C95.6576 19.4938 97.7203 18.9883 99.7022 18.9883C101.482 18.9883 103.1 19.413 104.556 20.2623C106.012 21.0712 107.164 22.3655 108.014 24.1451Z" fill="currentColor"></path><path d="M56.4406 18.9883C61.6176 18.9883 65.6014 20.4241 68.3922 23.2957C71.2233 26.1673 72.6389 30.2928 72.6389 35.672C72.6389 39.4334 71.9311 42.6488 70.5155 45.3182C69.1404 47.9876 67.1586 50.0301 64.5701 51.4457C61.9816 52.8613 58.8875 53.5691 55.2879 53.5691C50.1108 53.5691 46.1472 52.1131 43.3969 49.201C40.6466 46.2889 39.2715 42.1635 39.2715 36.8247C39.2715 33.0633 39.9388 29.8681 41.2735 27.2391C42.6487 24.5697 44.6103 22.5272 47.1583 21.1117C49.7064 19.6961 52.8005 18.9883 56.4406 18.9883ZM55.8945 27.4818C54.3981 27.4818 53.3465 28.1289 52.7398 29.4232C52.1736 30.7174 51.8904 33.0026 51.8904 36.2787C51.8904 39.5548 52.1736 41.8399 52.7398 43.1342C53.3465 44.4284 54.3981 45.0756 55.8945 45.0756C56.9461 45.0756 57.755 44.7924 58.3213 44.2262C58.9279 43.6195 59.3526 42.6691 59.5953 41.3748C59.8784 40.0401 60.02 38.301 60.02 36.1574C60.02 32.9217 59.7166 30.677 59.1099 29.4232C58.5033 28.1289 57.4315 27.4818 55.8945 27.4818Z" fill="currentColor"></path><path d="M0 52.6591V46.5923L4.67144 44.7722L3.33675 46.4103V26.2078L4.67144 28.0278L0 26.2078V20.141L12.801 19.5343L14.257 25.1764L12.7403 24.6911C14.6817 22.7901 16.7242 21.3746 18.8678 20.4443C21.0518 19.4736 23.1348 18.9883 25.1166 18.9883C27.8669 18.9883 30.1723 19.8781 32.0328 21.6577C33.9337 23.4373 34.8842 26.1269 34.8842 29.7265V46.4103L33.9135 44.8329L38.2209 46.5923V52.6591H22.7505V32.2746C22.7505 30.8186 22.4472 29.767 21.8405 29.1199C21.2743 28.4323 20.526 28.0885 19.5958 28.0885C18.8678 28.0885 18.0791 28.2907 17.2297 28.6952C16.4208 29.0592 15.5917 29.585 14.7423 30.2725L15.4704 28.6952V46.6529L14.4997 45.0149L18.2004 46.5923V52.6591H0Z" fill="currentColor"></path><path d="M133.139 10.9809L137.203 16.7444L153.159 7.94752L147.274 0L133.139 10.9809Z" fill="var(--base-color-brand--offwhite)"></path></svg><div class="spacer-small"></div><div>Digital craftsman bridging <br/>strategy and design. <br/>Simply Beyond.<br/></div><div class="spacer-medium"></div><div class="text-weight-xbold">nomíra by damian müller</div><div class="spacer-xsmall"></div><div>Digital Design &amp; Strategy<br/>Switzerland<br/><a href="mailto:[email protected]?subject=Website%20Request">[email protected]</a></div></div></div><ul role="list" class="nav_menu-list"><li class="nav_menu-list-item"><a href="/#services" class="nav_menu-link w-nav-link">Services</a></li><li class="nav_menu-list-item"><a href="/#process" class="nav_menu-link w-nav-link">Approach</a></li><li class="nav_menu-list-item"><a href="/#why" class="nav_menu-link w-nav-link">Core Values</a></li><li class="nav_menu-list-item"><a href="/#cases" class="nav_menu-link w-nav-link">Cases</a></li><li class="nav_menu-list-item is-last"><div class="spacer-medium"></div><a href="https://www.nomira.ch/" target="_blank" class="nav_menu-link is-secondary w-nav-link">Switch to German.</a></li></ul></div></nav></div></div><div class="custom-cursor-wrapper"><div class="custom-cursor-dropdowns">
800<svg xmlns="http://www.w3.org/2000/svg" width="100%" viewBox="0 0 33 33" fill="none" class="cursor-icon icon-1x1-small text-color-alternate"><g clip-path="url(#clip0_54_3766)"><path d="M16.7266 9.24219V23.2422" stroke="currentColor" stroke-width="2" stroke-miterlimit="10" stroke-linecap="square" class="cursor-icon-vertical-line"></path><path d="M23.7266 16.2422H9.72656" stroke="currentColor" stroke-width="2" stroke-miterlimit="10" stroke-linecap="square"></path><path d="M16.7266 31.2422C25.0108 31.2422 31.7266 24.5265 31.7266 16.2422C31.7266 7.95792 25.0108 1.24219 16.7266 1.24219C8.44229 1.24219 1.72656 7.95792 1.72656 16.2422C1.72656 24.5265 8.44229 31.2422 16.7266 31.2422Z" stroke="currentColor" stroke-width="2" stroke-miterlimit="10" stroke-linecap="square"></path></g></svg><div class="cursor-text-wrapper-dropdowns"><div class="cursor-text-dropdowns">more</div><div class="cursor-text-dropdowns">less</div></div></div><div class="custom-cursor-links"><div class="cursor-text-wrapper-links"><div class="cursor-text-link">view Website</div></div></div><div class="custom-cursor-offer"><div class="cursor-text-wrapper-offer"><div class="cursor-text-offer">jetzt
anfragen</div></div></div></div><main class="main-wrapper"><header class="section_hero"><div class="padding-global"><div class="container-large"><div class="hero_component u-grid-custom"><div data-gsap-trigger=".section_hero" data-gsap-parallax="strong" class="hero_heading-wrapper u-column-custom"><div class="heading-icon-wrapper position-relativ"><h1 data-initial-hidden="" data-gsap-words="up" data-heading-icon="" class="hero_heading">Imprint.<br/>Privacy</h1><svg xmlns="http://www.w3.org/2000/svg" width="100%" viewBox="0 0 51 43" fill="none" data-initial-hidden="" class="heading-icon icon-1x1-large text-color-secondary"><path d="M9.4525 42.6658L0 29.2333L36.4833 0.709961L50.4133 19.4491L9.4525 42.6658Z" fill="currentColor"></path></svg></div></div><div class="hero_bg-img-wrapper"><img class="hero_bg-img" src="https://cdn.prod.website-files.com/68ca7ac82e708712f7b3d78e/68ca7ac82e708712f7b3d7c2_header-webflow.webp" data-gsap-parallax="bg" data-gsap-trigger=".section_hero" alt="" sizes="(max-width: 3440px) 100vw, 3440px" loading="eager" srcset="https://cdn.prod.website-files.com/68ca7ac82e708712f7b3d78e/68ca7ac82e708712f7b3d7c2_header-webflow.webp 500w, https://cdn.prod.website-files.com/68ca7ac82e708712f7b3d78e/68ca7ac82e708712f7b3d7c2_header-webflow.webp 800w, https://cdn.prod.website-files.com/68ca7ac82e708712f7b3d78e/68ca7ac82e708712f7b3d7c2_header-webflow.webp 1080w, https://cdn.prod.website-files.com/68ca7ac82e708712f7b3d78e/68ca7ac82e708712f7b3d7c2_header-webflow.webp 1600w, https://cdn.prod.website-files.com/68ca7ac82e708712f7b3d78e/68ca7ac82e708712f7b3d7c2_header-webflow.webp 2000w, https://cdn.prod.website-files.com/68ca7ac82e708712f7b3d78e/68ca7ac82e708712f7b3d7c2_header-webflow.webp 2600w, https://cdn.prod.website-files.com/68ca7ac82e708712f7b3d78e/68ca7ac82e708712f7b3d7c2_header-webflow.webp 3440w"/></div></div></div></div></header><section class="section_privacy-text"><div class="padding-global padding-section-small"><div class="container-large"><div class="privacy-text_component u-grid-custom"><div class="privacy-text_content-wrapper u-column-custom"><h3 class="heading-style-h3">Imprint.</h3><div class="text-rich-text w-richtext"><p>nomíra by damian müller<br/>Digital Design &amp; Development<br/>Switzerland<br/>E-Mail: <a href="mailto:[email protected]?subject=Anfrage%20via%20Website">[email protected]</a></p><p>‍</p><p><strong>Privacy Policy</strong></p><p>Your privacy matters. This website collects only essential data to provide you with the best possible service and user experience.<br/>‍</p><p>What we collect:</p><ul role="list"><li>Information you provide through contact forms (name, email, message)</li><li>Analytics data to improve our services (via privacy-friendly tools)</li><li>Technical data necessary for website functionality</li></ul><p>Your rights:<br/>You have the right to access, correct, or delete your personal data at any time. We never sell or share your information with third parties without your explicit consent.</p><p>‍<br/>Contact:<br/>For any privacy-related questions or requests, please contact: <a href="mailto:[email protected]">[email protected]</a>‍</p><p>For our comprehensive privacy policy and cookie information, please see below and please refer also to our <a href="https://www.nomira.ch/impressum" target="_blank">German legal notice</a>.</p></div><div class="spacer-large"></div><div><div class="w-embed w-script">
800<script src="https://app.privacybee.io/widget.js" defer></script>
800
801<privacybee-widget website-id="cm9oaqy3o001wv4nbirv59mfk" type="dsg" lang="en"></privacybee-widget></div></div></div></div></div></div></section></main><footer class="footer overflow-hidden"><div class="footer_cta-wrapper"><div STYLE="clip-path: polygon(18% 17%, 100% 0%, 100% 100%, 25% 100%)" class="footer_bg-layer background-color-mint"></div><div class="padding-global heigth-100"><div class="container-large heigth-100"><div class="footer_cta-content-wrapper u-grid-custom"><div class="footer_cta-content u-column-custom"><div class="cta-element-wrapper"><div data-gsap-view="left" data-cal-link="nomira/lets-talk" data-cal-namespace="lets-talk" data-cal-config="{&quot;layout&quot;:&quot;month_view&quot;,&quot;theme&quot;:&quot;dark&quot;}" class="cta-wrapper"><div class="cta-link-wrapper"><svg xmlns="http://www.w3.org/2000/svg" width="100%" viewBox="0 0 54 54" fill="none" class="cta-icon"><g clip-path="url(#clip0_38_2261)"><path d="M27 52.3125C40.9797 52.3125 52.3125 40.9797 52.3125 27C52.3125 13.0203 40.9797 1.6875 27 1.6875C13.0203 1.6875 1.6875 13.0203 1.6875 27C1.6875 40.9797 13.0203 52.3125 27 52.3125Z" stroke="currentColor" stroke-width="3.375" stroke-linecap="round" stroke-linejoin="round"></path><path d="M13.5 27H28.6875" stroke="currentColor" stroke-width="3.375" stroke-linecap="round" stroke-linejoin="round"></path><path d="M28.6875 35.4375V18.5625L40.5 27L28.6875 35.4375Z" stroke="currentColor" stroke-width="3.375" stroke-linecap="round" stroke-linejoin="round"></path></g></svg><div class="g_clickable_wrap"><a target="" href="#" class="g_clickable_link w-inline-block"><span class="g_clickable_text screenreader-only">Get in Touch</span></a><button type="button" class="g_clickable_btn"><span class="g_clickable_text screenreader-only">Get in Touch</span></button></div></div><div STYLE="max-width: 12rem;" class="cta-link-wrapper"><div aria-hidden="true" class="cta-text">Get in Touch</div><div class="g_clickable_wrap"><a target="" href="#" class="g_clickable_link w-inline-block"><span class="g_clickable_text screenreader-only">Get in Touch</span></a><button type="button" class="g_clickable_btn"><span class="g_clickable_text screenreader-only">Get in Touch</span></button></div></div></div></div><div class="cta-text-divider background-color-alternate"></div><div class="footer_cta-heading-wrapper"><div class="heading-icon-wrapper position-relativ"><div data-gsap-scrollWords="up" data-heading-icon="" class="cta-heading">Let’s create something extraordinary together.</div><svg xmlns="http://www.w3.org/2000/svg" width="100%" viewBox="0 0 51 43" fill="none" class="heading-icon icon-1x1-large text-color-primary"><path d="M9.4525 42.6658L0 29.2333L36.4833 0.709961L50.4133 19.4491L9.4525 42.6658Z" fill="currentColor"></path></svg></div></div></div></div></div></div></div></footer></div>
801<script src="https://d3e54v103j8qbb.cloudfront.net/js/jquery-3.5.1.min.dc5e7f18c8.js?site=68ca7ac82e708712f7b3d78e" type="text/javascript" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>
801<script src="https://cdn.prod.website-files.com/68ca7ac82e708712f7b3d78e/js/webflow.schunk.47d6c6fda17ce6cd.js" type="text/javascript" integrity="sha384-Lir0RD5ekpd2MnGnYAQgABmR5JLlqnk+1yuFajhbYJ1UEeYeLoiw4y8/3V7XPtBu" crossorigin="anonymous"></script>
801<script src="https://cdn.prod.website-files.com/68ca7ac82e708712f7b3d78e/js/webflow.a9ba356d.d2f30196489a2709.js" type="text/javascript" integrity="sha384-csGkhjFGgkSz8t16Ud75ydCbjLPF/KwVXVDchd4zvLDKt8Bf0NTemUS5BXjXjjmC" crossorigin="anonymous"></script>
801<!-- Cal element-click embed code begins -->
802<script type="text/javascript">
803  (function (C, A, L) { let p = function (a, ar) { a.q.push(ar); }; let d = C.document; C.Cal = C.Cal || function () { let cal = C.Cal; let ar = arguments; if (!cal.loaded) { cal.ns = {}; cal.q = cal.q || []; d.head.appendChild(d.createElement("script")).src = A; cal.loaded = true; } if (ar[0] === L) { const api = function () { p(api, arguments); }; const namespace = ar[1]; api.q = api.q || []; if(typeof namespace === "string"){cal.ns[namespace] = cal.ns[namespace] || api;p(cal.ns[namespace], ar);p(cal, ["initNamespace", namespace]);} else p(cal, ar); return;} p(cal, ar); }; })(window, "https://app.cal.com/embed/embed.js", "init");
804Cal("init", "lets-talk", {origin:"https://cal.com"});
805
806  
807  // Important: Please add the following attributes to the element that should trigger the calendar to open upon clicking.
808  // `data-cal-link="nomira/lets-talk"`
809  // data-cal-namespace="lets-talk"
810  // `data-cal-config='{"layout":"month_view","theme":"dark"}'`
811
812  Cal.ns.lets-talk("ui", {"theme":"dark","cssVarsPerTheme":{"light":{"cal-brand":"#000000"},"dark":{"cal-brand":"#F5F5F5"}},"hideEventTypeDetails":false,"layout":"month_view"});
813  </script>
813
814  <!-- Cal element-click embed code ends -->
815
816
817<!-- JSON Presets (als globales Objekt oder als inline JSON) -->
818<script type="application/json" id="gsap-presets">
819{
820  "init": {
821    "fade": {
822      "startOpacity": 0,
823      "endOpacity": 1,
824      "duration": 1.2,
825      "delay": 0.5,
826      "ease": "power2.out"
827    },
828    "up": {
829      "startY": 30,
830      "endY": 0,
831      "startOpacity": 0,
832      "endOpacity": 1,
833      "duration": 1,
834      "delay": 0,
835      "ease": "power2.out"
836    },
837    "left": {
838      "startX": -30,
839      "endX": 0,
840      "startOpacity": 0,
841      "endOpacity": 1,
842      "duration": 1,
843      "delay": 0,
844      "ease": "power2.out"
845    },
846    "right": {
847      "startX": 30,
848      "endX": 0,
849      "startOpacity": 0,
850      "endOpacity": 1,
851      "duration": 1,
852      "delay": 0,
853      "ease": "power2.out"
854    }
855  },
856  
857  "view": {
858    "fade": {
859      "startOpacity": 0,
860      "endOpacity": 1,
861      "duration": 1,
862      "delay": 0,
863      "ease": "power1.out"
864    },
865    "up": {
866      "startY": 30,
867      "endY": 0,
868      "startOpacity": 0,
869      "endOpacity": 1,
870      "duration": 1,
871      "delay": 0,
872      "ease": "power1.out"
873    },
874    "left": {
875      "startX": -30,
876      "endX": 0,
877      "startOpacity": 0,
878      "endOpacity": 1,
879      "duration": 1,
880      "delay": 0,
881      "ease": "power1.out"
882    },
883    "right": {
884      "startX": 30,
885      "endX": 0,
886      "startOpacity": 0,
887      "endOpacity": 1,
888      "duration": 1,
889      "delay": 0,
890      "ease": "power1.out"
891    }
892  },
893  
894  "words": {
895    "up": {
896      "startY": 30,
897      "endY": 0,
898      "startOpacity": 0,
899      "endOpacity": 1,
900      "duration": 1,
901      "delay": 0,
902      "ease": "power1.out",
903      "stagger": 0.12,
904      "split": true,
905      "markers": false
906    },
907    "left": {
908      "startX": -30,
909      "endX": 0,
910      "startOpacity": 0,
911      "endOpacity": 1,
912      "duration": 1,
913      "delay": 0,
914      "ease": "power1.out",
915      "stagger": 0.12,
916      "split": true,
917      "markers": true
918    },
919    "right": {
920      "startX": 30,
921      "endX": 0,
922      "startOpacity": 0,
923      "endOpacity": 1,
924      "duration": 1,
925      "delay": 0,
926      "ease": "power1.out",
927      "stagger": 0.12,
928      "split": true,
929      "markers": false
930    }
931  },
932
933  "scrollWords": {
934    "up": {
935      "startY": 30,
936      "endY": 0,
937      "startOpacity": 0,
938      "endOpacity": 1,
939      "ease": "none",
940      "scrub": 2,
941      "split": true,
942      "trigger": "",
943      "start": "top 90%",
944      "end": "top 50%",
945      "wordSpread": 0.5,
946      "markers": false,
947      "tablet": {
948      	"start": "top 90%",
949      	"end": "top 45%",
950        "scrub": 1
951    	},
952    	"mobile-l": {
953      	"start": "top 90%",
954      	"end": "top 45%",
955        "scrub": 1
956    	},
957    	"mobile-p": {
958      	"start": "top 90%",
959      	"end": "top 45%",
960        "scrub": 1
961    	}
962    },
963    "left": {
964      "startX": -30,
965      "endX": 0,
966      "startOpacity": 0,
967      "endOpacity": 1,
968      "ease": "none",
969      "scrub": 2,
970      "split": true,
971      "trigger": "",
972      "start": "top bottom",
973      "end": "top 80%",
974      "wordSpread": 0.5,
975      "markers": false,
976      "tablet": {
977      	"start": "top bottom",
978      	"end": "top 65%",
979        "scrub": 1
980    	},
981    	"mobile-l": {
982      	"start": "top bottom",
983      	"end": "top 65%",
984        "scrub": 1
985    	},
986    	"mobile-p": {
987      	"start": "top bottom",
988      	"end": "top 65%",
989        "scrub": 1
990    	}
991    },
992    "right": {
993      "startX": 30,
994      "endX": 0,
995      "startOpacity": 0,
996      "endOpacity": 1,
997      "ease": "none",
998      "scrub": 2,
999      "split": true,
1000      "trigger": "",
1001      "start": "top bottom",
1002      "end": "top 70%",
1003      "wordSpread": 0.5,
1004      "markers": false,
1005      "tablet": {
1006      	"start": "top 90%",
1007      	"end": "top 65%",
1008        "scrub": 0.5
1009    	},
1010    	"mobile-l": {
1011      	"start": "top 90%",
1012      	"end": "top 65%",
1013        "scrub": 0.5
1014    	},
1015    	"mobile-p": {
1016      	"start": "top 90%",
1017      	"end": "top 65%",
1018        "scrub": 0.5
1019    	}
1020    }
1021  },
1022  
1023  "parallax": {
1024    "subtle": {
1025      "startY": 0,
1026      "endY": -50,
1027      "ease": "none",
1028      "scrub": 1,
1029      "trigger": "",
1030      "start": "top top",
1031      "end": "bottom top",
1032      "markers": false,
1033      "tablet": {
1034      	"endY": -30,
1035      	"scrub": 0.2 
1036    	},
1037    	"mobile-l": {
1038      	"endY": -10,
1039      	"scrub": 0.1
1040    	},
1041    	"exclude": "mobile-p"
1042    },
1043    "medium": {
1044      "startY": 0,
1045      "endY": -220,
1046      "startOpacity": 1,
1047      "endOpacity": 1,
1048      "ease": "none",
1049      "scrub": 1,
1050      "trigger": "",
1051      "start": "top top",
1052      "end": "bottom top",
1053      "markers": false,
1054      "tablet": {
1055      	"endY": -130,
1056      	"scrub": 0.5 
1057    	},
1058    	"mobile-l": {
1059      	"endY": -60,
1060      	"scrub": 0.3
1061    	},
1062    	"mobile-p": {
1063      	"endY": -60,
1064      	"scrub": 0.3
1065    	}
1066    },
1067    "strong": {
1068      "startY": 0,
1069      "endY": -280,
1070      "ease": "none",
1071      "scrub": 1,
1072      "trigger": "",
1073      "start": "top top",
1074      "end": "bottom top",
1075      "markers": false,
1076      "tablet": {
1077      	"endY": -170,
1078      	"scrub": 0.5 
1079    	},
1080    	"mobile-l": {
1081      	"endY": -80,
1082      	"scrub": 0.3
1083    	},
1084    	"mobile-p": {
1085      	"endY": -80,
1086      	"scrub": 0.3
1087    	}
1088    },
1089    "bg": {
1090      "startY": 0,
1091      "endY": -120,
1092      "ease": "none",
1093      "scrub": 1,
1094      "trigger": "",
1095      "start": "top top",
1096      "end": "bottom top",
1097      "markers": false,
1098      "tablet": {
1099      	"endY": -70,
1100      	"scrub": 0.5 
1101    	},
1102    	"mobile-l": {
1103      	"endY": -40,
1104      	"scrub": 0.3
1105    	},
1106    	"mobile-p": {
1107      	"endY": -40,
1108      	"scrub": 0.3
1109    	}
1110    }
1111  }
1112}
1113</script>
1113
1114
1115<!-- GSAP Core -->
1116<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.5/gsap.min.js"></script>
1116
1117
1118<!-- GSAP ScrollTrigger Plugin -->
1119<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.5/ScrollTrigger.min.js"></script>
1119
1120
1121<!-- Split Type Library -->
1122<script src="https://unpkg.com/split-type"></script>
1122
1123
1124<!-- Live Code (Presets in Project Settings beachten)-->
1125<script src="https://cdn.jsdelivr.net/gh/nomira-digital/[email protected]/script.js"></script>
1125
1126
1127<!-- Code Editor 
1128<script type=module src="http://127.0.0.1:5500/animations.js"></script>
1128 --><!-- GSAP Core -->
1129<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.5/gsap.min.js"></script>
1129
1130
1131<!-- GSAP ScrollTrigger Plugin -->
1132<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.5/ScrollTrigger.min.js"></script>
1132
1133
1134<!-- Split Type Library -->
1135<script src="https://unpkg.com/split-type"></script>
1135
1136
1137
1138<!-- Live Code (Presets in Project Settings beachten)
1139<script src="https://cdn.jsdelivr.net/gh/nomira-digital/[email protected]/script.js"></script>
1139 -->
1140
1141<!-- Code Editor
1142<script type="module" src="http://127.0.0.1:5500/animations.js"></script>
1142 -->
1143
1144<script>
1145// ================================================================
1146// =============== GSAP ANIMATION PRESET SYSTEM ==================
1147// ================================================================
1148// Dieses System ermöglicht die zentrale Verwaltung aller GSAP-Animationen 
1149// über ein JSON-Preset-System.
1150// 1. Presets werden in einem HTML-Element mit id="gsap-presets" als JSON definiert 
1151//    (Siehe Webflow (Projekt/Page)-Settings) oder als globales Objekt im Code Editor (gsapAnimations).
1152// 2. Jeder Top-Level-Schlüssel im JSON (z.B. "init", "view", "words") wird als Animation-Typ erkannt.
1153// 3. Elemente mit data-gsap-[typ]="[animation]" erhalten automatisch alle zugehörigen Parameter.
1154// 4. Neue Animationstypen können durch Erweiterung des JSON hinzugefügt werden, ohne den JS-Code zu ändern.
1155// 5. Falls im Preset bspw. "split": true gesetzt wird, fügt der Code automatisch data-gsap-split="true" hinzu.
1156// 6. Die eigentlichen GSAP-Animationen werden im nächsten Abschnitt initialisiert.
1157// 7. Responsive Breakpoints (desktop, tablet, mobile-l, mobile-p) werden automatisch als data-Attribute gesetzt.
1158// 8. Ausschluss von Animationen per Preset mit "exclude" (z.B. "exclude": "tablet,mobile-p").
1159
1160(function(){
1161  // Falls ein globales Objekt "gsapAnimations" definiert wurde, verwende dieses,
1162  // andernfalls suche im DOM nach einem Element mit id "gsap-presets" und parse dessen Inhalt.
1163  let presets;
1164  if (typeof gsapAnimations !== 'undefined') {
1165    presets = gsapAnimations;
1166  } else {
1167    const presetsElement = document.getElementById('gsap-presets');
1168    if (presetsElement) {
1169      try {
1170        presets = JSON.parse(presetsElement.textContent);
1171      } catch (err) {
1172        console.error('Error parsing GSAP presets:', err);
1173        return;
1174      }
1175    } else {
1176      console.error('No GSAP presets found (neither global variable nor #gsap-presets element).');
1177      return;
1178    }
1179  }
1180  
1181  // Hilfsfunktion, die camelCase in kebab-case umwandelt und den Präfix "data-gsap-" hinzufügt.
1182  function toDataAttr(key) {
1183    return 'data-gsap-' + key.replace(/([A-Z])/g, '-$1').toLowerCase();
1184  }
1185  
1186  // Liste der bekannten Breakpoints
1187  const breakpoints = ['desktop', 'tablet', 'mobile-l', 'mobile-p'];
1188  
1189  // Iteriere über alle Top-Level-Presets (z. B. "init", "view", "words")
1190  Object.keys(presets).forEach(function(animationType) {
1191    const presetGroup = presets[animationType];
1192    const typeAttr = `data-gsap-${animationType}`; // z.B. data-gsap-init
1193    
1194    document.querySelectorAll(`[${typeAttr}]`).forEach(function(element) {
1195      const animationName = element.getAttribute(typeAttr);
1196      const preset = presetGroup[animationName];
1197      
1198      if (!preset) {
1199        console.warn(`Animation "${animationName}" not found in ${animationType} category.`);
1200        return;
1201      }
1202      
1203      // Falls im Preset "split": true gesetzt ist, füge data-gsap-split="true" hinzu.
1204      if (preset.split === true) {
1205        element.setAttribute('data-gsap-split', 'true');
1206      }
1207      
1208      // Falls im Preset "exclude" gesetzt ist (z.B. "exclude": "tablet,mobile-p"),
1209      // setze data-gsap-exclude entsprechend.
1210      if (preset.exclude) {
1211        element.setAttribute('data-gsap-exclude', preset.exclude);
1212      }
1213      
1214      // Übertrage alle Parameter aus dem Preset als data-Attribute
1215      Object.entries(preset).forEach(function([key, value]) {
1216        // Überspringe Schlüssel, die speziell behandelt werden oder bereits gesetzt sind
1217        if (key === "split" || key === "exclude") return;
1218        // Trigger-Attribut nicht überschreiben, wenn es bereits gesetzt ist
1219        if (key === "trigger" && element.hasAttribute('data-gsap-trigger')) return;
1220        
1221        // Prüfen, ob es sich um einen Breakpoint handelt
1222        if (breakpoints.includes(key)) {
1223          // Wenn ja, setze die breakpoint-spezifischen Attribute
1224          if (typeof value === 'object') {
1225            Object.entries(value).forEach(function([bpKey, bpValue]) {
1226              element.setAttribute(toDataAttr(bpKey + '-' + key), bpValue);
1227            });
1228          }
1229        } else {
1230          // Sonst normales Attribut setzen
1231          element.setAttribute(toDataAttr(key), value);
1232        }
1233      });
1234    });
1235  });
1236})();
1237
1238// ================================================================
1239// ========= GSAP: TEXT-SPLITTING & ICON SETUP ==================
1240// ================================================================
1241// Zentrale Funktion zum Aufteilen von Text und Vorbereiten des Icons.
1242function setupAnimatedHeading(element) {
1243const hasHeadingIcon = element.hasAttribute('data-heading-icon');
1244let iconElement = null;
1245let splitWords = [];
1246let lastWordElement = null;
1247
1248// 1. Finde Icon (falls vorhanden) - im Elternelement suchen
1249if (hasHeadingIcon) {
1250  const container = element.parentElement;
1251  iconElement = container ? container.querySelector('.heading-icon') : null;
1252  if (iconElement) {
1253    gsap.set(iconElement, { opacity: 0, visibility: "hidden" }); // Initial verstecken
1254  } else {
1255    console.warn("Heading icon element not found for:", element);
1256  }
1257}
1258
1259// 2. Splitte Text mit SplitType, falls noch nicht geschehen
1260const existingSplitWords = element.querySelectorAll('.split-word');
1261if (existingSplitWords.length > 0) {
1262  splitWords = Array.from(existingSplitWords);
1263  // Stelle sicher, dass der Style korrekt ist
1264  splitWords.forEach(word => { word.style.display = 'inline-block'; });
1265} else {
1266  new SplitType(element, {
1267    types: 'words',
1268    tagName: 'span',
1269    wordClass: 'split-word'
1270  });
1271  splitWords = Array.from(element.querySelectorAll('.split-word'));
1272  splitWords.forEach(word => { word.style.display = 'inline-block'; });
1273}
1274
1275// 3. Identifiziere letztes Wort für Icon-Platzierung (falls Icon vorhanden)
1276if (iconElement && splitWords.length > 0) {
1277  lastWordElement = splitWords[splitWords.length - 1];
1278  lastWordElement.classList.add('last-word');
1279  // Das Anhängen des Icons geschieht später, je nach Animationstyp
1280}
1281
1282// Gib die vorbereiteten Elemente zurück
1283return { splitWords, iconElement, lastWordElement };
1284}
1285
1286
1287// ================================================================
1288// ============= HEADINGS ICON SETUP OHNE GSAP ====================
1289// ================================================================
1290// Dieser Handler kümmert sich um Icons bei Headings OHNE GSAP Wort-Animationen
1291document.addEventListener('DOMContentLoaded', function() {
1292const headings = document.querySelectorAll('[data-heading-icon]');
1293
1294headings.forEach(function(heading) {
1295  // Überspringen, wenn GSAP Wort-Animationen aktiv sind (diese kümmern sich selbst)
1296  if (heading.hasAttribute('data-gsap-words') || heading.hasAttribute('data-gsap-scrollwords')) {
1297    return; 
1298  }
1299  
1300  // Setup für Text und Icon durchführen
1301  const { iconElement, lastWordElement } = setupAnimatedHeading(heading);
1302  
1303  // Icon anhängen und einblenden, falls vorhanden
1304  if (iconElement && lastWordElement) {
1305    lastWordElement.appendChild(iconElement);
1306    // Icon sanft einblenden
1307    gsap.to(iconElement, {
1308      opacity: 1,
1309      visibility: "visible",
1310      duration: 0.3,
1311      delay: 0.1, // Kleine Verzögerung für smoothes Laden
1312      ease: "power1.out"
1313    });
1314  }
1315});
1316});
1317
1318
1319// ================================================================
1320// ========= AUTOMATISCHE TEXT-AUFTEILUNG FÜR STAGGER ============
1321// ================================================================
1322// Dies wird nun hauptsächlich durch setupAnimatedHeading abgedeckt.
1323// Wir behalten diesen Block, um data-gsap-split="true" bei Bedarf zu setzen,
1324// falls Elemente nur gesplittet, aber nicht animiert werden sollen (obwohl das selten sein sollte).
1325(function(){
1326document.querySelectorAll('[data-gsap-split="true"]').forEach(el => {
1327  // Prüfen ob bereits animiert (words/scrollwords)
1328  if (el.hasAttribute('data-gsap-words') || el.hasAttribute('data-gsap-scrollwords')) {
1329    return; // Wird schon von den Animationsfunktionen behandelt
1330  }
1331  // Nur splitten, wenn nicht schon geschehen und keine GSAP-Animation aktiv ist
1332  if (!el.querySelector('.split-word')) {
1333     new SplitType(el, {
1334       types: 'words',
1335       tagName: 'span',
1336       wordClass: 'split-word'
1337     });
1338     el.querySelectorAll('.split-word').forEach(word => {
1339       word.style.display = 'inline-block';
1340     });
1341  }
1342});
1343})();
1344
1345
1346// ================================================================
1347// =============== GSAP ANIMATION INITIALISIERUNG ================
1348// ================================================================
1349// Hier werden die GSAP-Animationen basierend auf den zuvor gesetzten data-Attributen initialisiert.
1350
1351(function(){
1352// ================================================================
1353// ================= HILFSFUNKTIONEN =============================
1354// ================================================================
1355
1356// Definition der Breakpoints für responsive Animationen
1357const BREAKPOINTS = {
1358  'desktop': { min: 992, max: Infinity, order: 4 },
1359  'tablet': { min: 768, max: 991, order: 3 },
1360  'mobile-l': { min: 480, max: 767, order: 2 },
1361  'mobile-p': { min: 0, max: 479, order: 1 }
1362};
1363
1364// Cache-Variablen für Breakpoints und responsive Werte
1365let currentBreakpoint = null;
1366const responsiveValueCache = new Map();
1367
1368// Ermittelt den aktuellen Breakpoint basierend auf der Fensterbreite
1369function getCurrentBreakpoint() {
1370  // Wenn der aktuelle Breakpoint bereits berechnet wurde, verwende ihn
1371  if (currentBreakpoint) return currentBreakpoint;
1372  
1373  const width = window.innerWidth;
1374  for (const [name, range] of Object.entries(BREAKPOINTS)) {
1375    if (width >= range.min && width <= range.max) {
1376      currentBreakpoint = name;
1377      return name;
1378    }
1379  }
1380  currentBreakpoint = 'desktop'; // Fallback
1381  return 'desktop';
1382}
1383
1384// Cache für Element-Werte aufbauen oder aktualisieren
1385function cacheResponsiveValuesForElement(element) {
1386  const cacheKey = element;
1387  if (!responsiveValueCache.has(cacheKey)) {
1388    responsiveValueCache.set(cacheKey, new Map());
1389  }
1390  return responsiveValueCache.get(cacheKey);
1391}
1392
1393// Prüft, ob die Animation für den aktuellen Breakpoint ausgeschlossen werden soll
1394function shouldExcludeAnimation(element) {
1395  const breakpoint = getCurrentBreakpoint();
1396  const breakpointOrder = BREAKPOINTS[breakpoint].order;
1397  
1398  // Cache für dieses Element abrufen oder erstellen
1399  const elementCache = cacheResponsiveValuesForElement(element);
1400  
1401  // Prüfen, ob wir das Ergebnis bereits gecacht haben
1402  const cacheKey = `exclude_${breakpoint}`;
1403  if (elementCache.has(cacheKey)) {
1404    return elementCache.get(cacheKey);
1405  }
1406  
1407  // Prüfe auf neue Exclude-Angabe (data-gsap-exclude="tablet,mobile-p")
1408  const excludeValue = element.getAttribute('data-gsap-exclude');
1409  if (excludeValue) {
1410    const excludedBreakpoints = excludeValue.split(',').map(b => b.trim());
1411    
1412    for (const excludedBreakpoint of excludedBreakpoints) {
1413      // Wenn der angegebene Breakpoint nicht existiert, ignorieren
1414      if (!BREAKPOINTS[excludedBreakpoint]) continue;
1415      
1416      // Wenn der aktuelle Breakpoint dem ausgeschlossenen entspricht oder 
1417      // einen niedrigeren Ordnungswert hat (kaskadierend nach unten)
1418      if (BREAKPOINTS[excludedBreakpoint].order >= breakpointOrder) {
1419        elementCache.set(cacheKey, true);
1420        return true;
1421      }
1422    }
1423  }
1424  
1425  // Prüfe auf altes Format für Abwärtskompatibilität (data-gsap-exclude-tablet)
1426  if (element.hasAttribute(`data-gsap-exclude-${breakpoint}`)) {
1427    elementCache.set(cacheKey, true);
1428    return true;
1429  }
1430  
1431  elementCache.set(cacheKey, false);
1432  return false;
1433}
1434
1435// Optimierte Funktion zum Abrufen responsiver Werte mit Caching
1436function getResponsiveValue(element, paramName, defaultValue) {
1437  const breakpoint = getCurrentBreakpoint();
1438  
1439  // Cache für dieses Element abrufen oder erstellen
1440  const elementCache = cacheResponsiveValuesForElement(element);
1441  
1442  // Prüfen, ob wir den Wert bereits gecacht haben
1443  const cacheKey = `${paramName}_${breakpoint}`;
1444  if (elementCache.has(cacheKey)) {
1445    return elementCache.get(cacheKey);
1446  }
1447  
1448  // 1. Versuche breakpoint-spezifisches Attribut zu finden (z.B. data-gsap-end-y-tablet)
1449  const breakpointValue = element.getAttribute(`data-gsap-${paramName}-${breakpoint}`);
1450  if (breakpointValue !== null) {
1451    const value = isNaN(parseFloat(breakpointValue)) ? breakpointValue : parseFloat(breakpointValue);
1452    elementCache.set(cacheKey, value);
1453    return value;
1454  }
1455  
1456  // 2. Fallback auf Standard-Attribut (z.B. data-gsap-end-y)
1457  const standardValue = element.getAttribute(`data-gsap-${paramName}`);
1458  if (standardValue !== null) {
1459    const value = isNaN(parseFloat(standardValue)) ? standardValue : parseFloat(standardValue);
1460    elementCache.set(cacheKey, value);
1461    return value;
1462  }
1463  
1464  // 3. Letzer Fallback auf übergebenen Standardwert
1465  elementCache.set(cacheKey, defaultValue);
1466  return defaultValue;
1467}
1468
1469// Prüft, ob das Element seine Opacity animieren soll (von 0 zu 1)
1470// Elemente mit data-initial-hidden brauchen Opacity-Animation
1471function shouldAnimateOpacity(element) {
1472  return element.hasAttribute('data-initial-hidden');
1473}
1474
1475// Hilfsfunktion zum Ermitteln des Trigger-Elements
1476function getTriggerElement(el) {
1477  const triggerSelector = el.getAttribute('data-gsap-trigger');
1478  if (!triggerSelector) return el; // Wenn kein Trigger angegeben, nutze das Element selbst
1479  const triggerElement = document.querySelector(triggerSelector);
1480  return triggerElement || el; // Fallback auf das Element selbst, wenn Selector nicht gefunden
1481}
1482
1483// Hilfsfunktion zum Ermitteln der Start- und Endpositionen
1484function getScrollPositions(el) {
1485  return {
1486    start: getResponsiveValue(el, 'start', "top bottom"),
1487    end: getResponsiveValue(el, 'end', "bottom top")
1488  };
1489}
1490
1491// Hilfsfunktion zur Überprüfung von data-gsap-markers
1492function hasMarkers(element) {
1493  return element.getAttribute('data-gsap-markers') === 'true';
1494}
1495
1496// Erkennt iOS-Geräte
1497function isIOS() {
1498  return /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
1499}
1500
1501// Optimierungen für ScrollTrigger, besonders für iOS
1502function optimizeScrollTrigger() {
1503  // Grundlegende Optimierungen für alle Geräte
1504  ScrollTrigger.config({
1505    // Ignoriert mobile resize events, die durch das Ein-/Ausblenden 
1506    // der Adressleiste verursacht werden (wichtig für iOS)
1507    ignoreMobileResize: true
1508  });
1509  
1510  // Zusätzliche iOS-spezifische Optimierungen
1511  if (isIOS()) {
1512    // Gibt iOS mehr Zeit, Momentum-Scroll zu initialisieren
1513    ScrollTrigger.config({
1514      // Reduziert die Anzahl der Auto-Refreshes (für bessere Performance)
1515      autoRefreshEvents: "visibilitychange,DOMContentLoaded,load",
1516      // Vermeidet Probleme mit der iOS-Tastatur
1517      syncInterval: 150
1518    });
1519  }
1520}
1521
1522// Optimierter Event-Listener für responsives Verhalten
1523function setupResponsiveListeners() {
1524  // Cache für den aktuellen Breakpoint
1525  currentBreakpoint = getCurrentBreakpoint();
1526  
1527  // Variable für Timeout-ID
1528  let resizeTimeout;
1529  
1530  // Resize-Handler mit Debounce
1531  window.addEventListener('resize', function() {
1532    // Debounce für bessere Performance
1533    clearTimeout(resizeTimeout);
1534    resizeTimeout = setTimeout(function() {
1535      // Prüfen, ob sich der Breakpoint tatsächlich geändert hat
1536      const newBreakpoint = getCurrentBreakpoint();
1537      if (newBreakpoint !== currentBreakpoint) {
1538        // Breakpoint hat sich geändert, Cache leeren
1539        currentBreakpoint = newBreakpoint;
1540        responsiveValueCache.clear();
1541        
1542        // Forciere Aktualisierung aller ScrollTrigger-Instanzen
1543        ScrollTrigger.refresh();
1544      }
1545    }, 250);
1546  });
1547  
1548  // Spezielle Behandlung für Orientierungswechsel (wichtig für Mobile)
1549  window.addEventListener('orientationchange', function() {
1550    // Nach Orientierungswechsel mehr Zeit geben, damit sich das Gerät anpassen kann
1551    setTimeout(function() {
1552      // Breakpoint neu ermitteln und Cache leeren
1553      currentBreakpoint = getCurrentBreakpoint();
1554      responsiveValueCache.clear();
1555      
1556      // ScrollTrigger aktualisieren
1557      ScrollTrigger.refresh();
1558    }, 350); // Längere Verzögerung für zuverlässigere Aktualisierung
1559  });
1560}
1561
1562// Initialisiert alle Optimierungen
1563function initOptimizations() {
1564  // ScrollTrigger optimieren
1565  optimizeScrollTrigger();
1566  
1567  // Responsive Listener einrichten
1568  setupResponsiveListeners();
1569}
1570
1571// ================================================================
1572// ================= ANIMATIONS-IMPLEMENTIERUNGEN =================
1573// ================================================================
1574
1575// ==============================================================
1576// ==================== INIT ANIMATIONEN =======================
1577// ==============================================================
1578document.querySelectorAll('[data-gsap-init]').forEach(function(el){
1579  // Prüfen, ob die Animation für den aktuellen Breakpoint ausgeschlossen werden soll
1580  if (shouldExcludeAnimation(el)) return;
1581  
1582  // Parameter mit responsiver Unterstützung auslesen
1583  const startOpacity = getResponsiveValue(el, 'start-opacity', 0);
1584  const endOpacity = getResponsiveValue(el, 'end-opacity', 1);
1585  const startY = getResponsiveValue(el, 'start-y', 0);
1586  const startX = getResponsiveValue(el, 'start-x', 0);
1587  const duration = getResponsiveValue(el, 'duration', 1);
1588  const delay = getResponsiveValue(el, 'delay', 0);
1589  const ease = getResponsiveValue(el, 'ease', "power2.out");
1590  const initType = el.getAttribute('data-gsap-init');
1591  
1592  // Prüfen, ob das Element initial hidden ist und Opacity animiert werden soll
1593  const shouldAnimate = shouldAnimateOpacity(el);
1594  
1595  // From-Konfiguration
1596  const fromConfig = { 
1597    visibility: "hidden" // Immer von hidden starten
1598  };
1599  
1600  // Opacity nur setzen, wenn das Element initial hidden ist
1601  if (shouldAnimate) {
1602    fromConfig.opacity = startOpacity;
1603  }
1604  
1605  // To-Konfiguration
1606  const toConfig = {
1607    visibility: "visible", // Immer zu visible animieren
1608    duration: duration,
1609    delay: delay,
1610    ease: ease
1611  };
1612  
1613  // Opacity nur setzen, wenn das Element initial hidden ist
1614  if (shouldAnimate) {
1615    toConfig.opacity = endOpacity;
1616  }
1617  
1618  // Y-Position hinzufügen
1619  if (initType === 'up') {
1620    fromConfig.y = startY;
1621    toConfig.y = 0;
1622  }
1623  
1624  // X-Position hinzufügen
1625  if (initType === 'left' || initType === 'right') {
1626    fromConfig.x = startX;
1627    toConfig.x = 0;
1628  }
1629
1630  // Animation mit fromTo durchführen
1631  gsap.fromTo(el, fromConfig, toConfig);
1632});
1633
1634// ==============================================================
1635// ==================== VIEW ANIMATIONEN =======================
1636// ==============================================================
1637document.querySelectorAll('[data-gsap-view]').forEach(function(el){
1638  // Wenn das Element auch init hat, überspringen wir es hier
1639  if (el.hasAttribute('data-gsap-init')) return;
1640  
1641  // Prüfen, ob die Animation für den aktuellen Breakpoint ausgeschlossen werden soll
1642  if (shouldExcludeAnimation(el)) return;
1643  
1644  // Parameter mit responsiver Unterstützung auslesen
1645  const startOpacity = getResponsiveValue(el, 'start-opacity', 0);
1646  const endOpacity = getResponsiveValue(el, 'end-opacity', 1);
1647  const startY = getResponsiveValue(el, 'start-y', 0);
1648  const endY = getResponsiveValue(el, 'end-y', 0);
1649  const startX = getResponsiveValue(el, 'start-x', 0);
1650  const endX = getResponsiveValue(el, 'end-x', 0);
1651  const duration = getResponsiveValue(el, 'duration', 1);
1652  const delay = getResponsiveValue(el, 'delay', 0);
1653  const ease = getResponsiveValue(el, 'ease', "power2.out");
1654  const viewType = el.getAttribute('data-gsap-view');
1655  
1656  // Prüfen, ob das Element initial hidden ist und Opacity animiert werden soll
1657  const shouldAnimate = shouldAnimateOpacity(el);
1658  
1659  // From-Konfiguration
1660  const fromConfig = { 
1661    visibility: "hidden" // Immer von hidden starten
1662  };
1663  
1664  // Opacity nur setzen, wenn das Element initial hidden ist
1665  if (shouldAnimate) {
1666    fromConfig.opacity = startOpacity;
1667  }
1668  
1669  // To-Konfiguration
1670  const toConfig = {
1671    visibility: "visible", // Immer zu visible animieren
1672    duration: duration,
1673    delay: delay,
1674    ease: ease
1675  };
1676  
1677  // Opacity nur setzen, wenn das Element initial hidden ist
1678  if (shouldAnimate) {
1679    toConfig.opacity = endOpacity;
1680  }
1681  
1682  // Y-Position hinzufügen
1683  if (viewType === 'up') {
1684    fromConfig.y = startY;
1685    toConfig.y = endY;
1686  }
1687  
1688  // X-Position hinzufügen
1689  if (viewType === 'left' || viewType === 'right') {
1690    fromConfig.x = startX;
1691    toConfig.x = endX;
1692  }
1693  
1694  // ScrollTrigger-Konfiguration
1695  const triggerElement = getTriggerElement(el);
1696  const { start: startPos } = getScrollPositions(el);
1697  toConfig.scrollTrigger = {
1698    trigger: triggerElement,
1699    start: startPos,
1700    markers: hasMarkers(el)
1701  };
1702  
1703  // Animation durchführen
1704  gsap.fromTo(el, fromConfig, toConfig);
1705});
1706
1707// ==============================================================
1708// ==================== PARALLAX ANIMATIONEN ==================
1709// ==============================================================
1710document.querySelectorAll('[data-gsap-parallax]').forEach(function(el){
1711    // Prüfen, ob die Animation für den aktuellen Breakpoint ausgeschlossen werden soll
1712    if (shouldExcludeAnimation(el)) return;
1713    
1714    // Parameter mit responsiver Unterstützung auslesen
1715    const startY = getResponsiveValue(el, 'start-y', 0);
1716    const endY = getResponsiveValue(el, 'end-y', 0);
1717    const scrub = getResponsiveValue(el, 'scrub', 1);
1718    const ease = getResponsiveValue(el, 'ease', "none");
1719    
1720    // Trigger und Positionen ermitteln
1721    const triggerElement = getTriggerElement(el);
1722    const { start: startPos, end: endPos } = getScrollPositions(el);
1723    
1724    // Einfache TO-Animation - vom Standard-DOM-Zustand zum Zielwert
1725    gsap.to(el, {
1726      y: endY,
1727      scrollTrigger: {
1728        trigger: triggerElement || el,
1729        start: startPos,
1730        end: endPos,
1731        scrub: scrub,
1732        markers: hasMarkers(el),
1733        ease: ease,
1734        // Für iOS optimierte Einstellungen
1735        ...(isIOS() && {
1736          invalidateOnRefresh: true,  // Besser für Orientierungswechsel
1737          fastScrollEnd: true,        // Verbessert das Ende von schnellem Scrollen
1738          preventOverlaps: true       // Verhindert Überlappungen bei schnellen Scrolls
1739        })
1740      }
1741    });
1742});
1743
1744// ==============================================================
1745// ==================== WORDS ANIMATIONEN =====================
1746// ==============================================================
1747document.querySelectorAll('[data-gsap-words]').forEach(function(el){
1748  // Prüfen, ob die Animation für den aktuellen Breakpoint ausgeschlossen werden soll
1749  if (shouldExcludeAnimation(el)) return;
1750  
1751  // Parameter mit responsiver Unterstützung auslesen
1752  const startOpacity = getResponsiveValue(el, 'start-opacity', 0);
1753  const endOpacity = getResponsiveValue(el, 'end-opacity', 1);
1754  const startY = getResponsiveValue(el, 'start-y', 50);
1755  const endY = getResponsiveValue(el, 'end-y', 0);
1756  const startX = getResponsiveValue(el, 'start-x', 0);
1757  const endX = getResponsiveValue(el, 'end-x', 0);
1758  const duration = getResponsiveValue(el, 'duration', 1);
1759  const delay = getResponsiveValue(el, 'delay', 0);
1760  const staggerTime = getResponsiveValue(el, 'stagger', 0.1);
1761  const ease = getResponsiveValue(el, 'ease', "power2.out");
1762  const wordsType = el.getAttribute('data-gsap-words');
1763  
1764  // Text splitten und Icon vorbereiten
1765  const { splitWords, iconElement, lastWordElement } = setupAnimatedHeading(el);
1766  
1767  // Wenn keine Wörter gefunden wurden, abbrechen
1768  if (splitWords.length === 0) {
1769    console.warn("No words found to animate for:", el);
1770    return;
1771  }
1772  
1773  // Prüfen, ob der Container opacity: 0 hat und animiert werden soll
1774  const shouldAnimate = shouldAnimateOpacity(el);
1775  
1776  // 1. Wörter immer auf ihren Startzustand setzen
1777  const wordInitialState = { 
1778    opacity: startOpacity, 
1779    visibility: "hidden"
1780  };
1781  
1782  if (wordsType === 'up') {
1783    wordInitialState.y = startY;
1784  } else if (wordsType === 'left' || wordsType === 'right') {
1785    wordInitialState.x = startX;
1786  }
1787  
1788  // Wörter auf initialen Zustand setzen
1789  gsap.set(splitWords, wordInitialState);
1790  
1791  // 2. Container vorbereiten
1792  if (shouldAnimate) {
1793    // Container mit data-initial-hidden: Container wird transparent starten
1794    gsap.set(el, { visibility: "hidden" });
1795  } else {
1796    // Container ohne data-initial-hidden: Sofort sichtbar machen
1797    gsap.set(el, { visibility: "visible" });
1798  }
1799  
1800  // 3. Wort-Animation konfigurieren
1801  const wordAnimConfig = {
1802    opacity: endOpacity,
1803    visibility: "visible",
1804    duration: duration,
1805    delay: delay,
1806    ease: ease,
1807    stagger: staggerTime,
1808    onComplete: function() {
1809      // Icon-Handling nach Abschluss der Wort-Animation
1810      if (iconElement && lastWordElement) {
1811        if (!lastWordElement.contains(iconElement)) {
1812          lastWordElement.appendChild(iconElement);
1813        }
1814        // Icon einblenden
1815        gsap.to(iconElement, { 
1816          opacity: 1, 
1817          visibility: "visible",
1818          duration: 0.3, 
1819          ease: "power1.out" 
1820        });
1821      }
1822    }
1823  };
1824  
1825  // Y/X-Position hinzufügen
1826  if (wordsType === 'up') {
1827    wordAnimConfig.y = endY;
1828  } else if (wordsType === 'left' || wordsType === 'right') {
1829    wordAnimConfig.x = endX;
1830  }
1831  
1832  // 4. ScrollTrigger vorbereiten, falls benötigt
1833  let scrollTriggerInstance = null;
1834  if (el.hasAttribute('data-gsap-trigger') || el.hasAttribute('data-gsap-start')) {
1835    const triggerElement = getTriggerElement(el);
1836    const { start: startPos } = getScrollPositions(el);
1837    
1838    const scrollTriggerConfig = {
1839      trigger: triggerElement,
1840      start: startPos,
1841      markers: hasMarkers(el)
1842    };
1843    
1844    scrollTriggerInstance = ScrollTrigger.create(scrollTriggerConfig);
1845    wordAnimConfig.scrollTrigger = scrollTriggerInstance;
1846  }
1847  
1848  // 5. Container-Animation, falls benötigt
1849  if (shouldAnimate) {
1850    // Container von transparent zu sichtbar animieren
1851    const containerConfig = {
1852      opacity: 1,
1853      visibility: "visible",
1854      duration: duration,
1855      delay: delay,
1856      ease: ease
1857    };
1858    
1859    // Falls ScrollTrigger existiert, auch für Container verwenden
1860    if (scrollTriggerInstance) {
1861      containerConfig.scrollTrigger = scrollTriggerInstance;
1862    }
1863    
1864    // Container-Animation starten
1865    gsap.to(el, containerConfig);
1866  }
1867  
1868  // 6. Wort-Animation starten
1869  gsap.to(splitWords, wordAnimConfig);
1870});
1871
1872// ==============================================================
1873// ==================== SCROLL WORDS ANIMATIONEN ===============
1874// ==============================================================
1875document.querySelectorAll('[data-gsap-scrollwords]').forEach(function(el) {
1876  // Prüfen, ob die Animation für den aktuellen Breakpoint ausgeschlossen werden soll
1877  if (shouldExcludeAnimation(el)) return;
1878  
1879  // Parameter mit responsiver Unterstützung auslesen
1880  const startY = getResponsiveValue(el, 'start-y', 30);
1881  const endY = getResponsiveValue(el, 'end-y', 0);
1882  const startX = getResponsiveValue(el, 'start-x', 0);
1883  const endX = getResponsiveValue(el, 'end-x', 0);
1884  const startOpacity = getResponsiveValue(el, 'start-opacity', 0);
1885  const endOpacity = getResponsiveValue(el, 'end-opacity', 1);
1886  const scrub = getResponsiveValue(el, 'scrub', 2);
1887  const wordSpread = getResponsiveValue(el, 'word-spread', 0.5);
1888  const ease = getResponsiveValue(el, 'ease', "none");
1889  const scrollWordsType = el.getAttribute('data-gsap-scrollwords');
1890  
1891  // Trigger und Positionen ermitteln
1892  const triggerElement = getTriggerElement(el);
1893  const { start: startPos, end: endPos } = getScrollPositions(el);
1894  
1895  // Text splitten und Icon vorbereiten
1896  const { splitWords, iconElement, lastWordElement } = setupAnimatedHeading(el);
1897  
1898  // Wenn keine Wörter gefunden wurden, abbrechen
1899  if (splitWords.length === 0) {
1900    console.warn("No words found to animate for scroll:", el);
1901    return;
1902  }
1903  
1904  // Prüfen, ob der Container opacity: 0 hat und animiert werden soll
1905  const shouldAnimate = shouldAnimateOpacity(el);
1906  
1907  // 1. Wörter auf Startzustand setzen
1908  const wordInitialState = { 
1909    opacity: startOpacity,
1910    visibility: "hidden"
1911  };
1912  
1913  if (scrollWordsType === 'up') {
1914    wordInitialState.y = startY;
1915  } else if (scrollWordsType === 'left') {
1916    wordInitialState.x = startX;
1917  } else if (scrollWordsType === 'right') {
1918    wordInitialState.x = startX;
1919  }
1920  
1921  // Wörter auf initialen Zustand setzen
1922  gsap.set(splitWords, wordInitialState);
1923  
1924  // 2. Container vorbereiten
1925  if (shouldAnimate) {
1926    // Container mit data-initial-hidden: Container wird transparent starten
1927    gsap.set(el, { visibility: "hidden" });
1928  } else {
1929    // Container ohne data-initial-hidden: Sofort sichtbar machen
1930    gsap.set(el, { visibility: "visible" });
1931  }
1932  
1933  // 3. Timeline erstellen
1934  const tl = gsap.timeline({
1935    scrollTrigger: {
1936      trigger: triggerElement,
1937      start: startPos,
1938      end: endPos,
1939      scrub: scrub,
1940      markers: hasMarkers(el),
1941      // Für iOS optimierte Einstellungen
1942      ...(isIOS() && {
1943        invalidateOnRefresh: true,
1944        fastScrollEnd: true,
1945        preventOverlaps: true
1946      })
1947    }
1948  });
1949  
1950  // 4. Container-Animation hinzufügen, falls nötig
1951  if (shouldAnimate) {
1952    // Container mit data-initial-hidden: von 0 auf 1 animieren
1953    tl.to(el, {
1954      opacity: 1,
1955      visibility: "visible",
1956      ease: ease
1957    }, 0); // Am Anfang der Timeline (bei Zeit 0)
1958  } else {
1959    // Container ohne data-initial-hidden: nur visibility sicherstellen
1960    tl.set(el, { visibility: "visible" }, 0);
1961  }
1962  
1963  // 5. Wort-Animationen hinzufügen
1964  splitWords.forEach((word, index) => {
1965    // Animation für dieses Wort
1966    const wordAnimation = {
1967      opacity: endOpacity,
1968      visibility: "visible",
1969      ease: ease
1970    };
1971    
1972    // Y/X-Position hinzufügen
1973    if (scrollWordsType === 'up') {
1974      wordAnimation.y = endY;
1975    } else if (scrollWordsType === 'left') {
1976      wordAnimation.x = endX;
1977    } else if (scrollWordsType === 'right') {
1978      wordAnimation.x = endX;
1979    }
1980    
1981    // Zeitpunkt in der Timeline berechnen
1982    const startTime = (splitWords.length > 1) ? 
1983      index * wordSpread / (splitWords.length - 1) : 0;
1984    
1985    // Wort zur Timeline hinzufügen
1986    tl.fromTo(
1987      word,
1988      { 
1989        opacity: startOpacity,
1990        visibility: "hidden",
1991        y: wordInitialState.y,
1992        x: wordInitialState.x
1993      },
1994      wordAnimation,
1995      startTime
1996    );
1997    
1998    // Icon-Logik für das letzte Wort
1999    if (index === splitWords.length - 1 && iconElement && lastWordElement) {
2000      const iconAttachTime = startTime;
2001      const iconFadeInDelay = 0.05; // Kleine Verzögerung
2002      const iconFadeInStartTime = iconAttachTime + iconFadeInDelay;
2003      
2004      // Icon anhängen
2005      tl.call(() => {
2006        if (!lastWordElement.contains(iconElement)) {
2007          lastWordElement.appendChild(iconElement);
2008        }
2009      }, null, iconAttachTime);
2010      
2011      // Icon einblenden
2012      tl.fromTo(
2013        iconElement,
2014        { opacity: 0, visibility: "hidden" },
2015        { opacity: 1, visibility: "visible", ease: ease },
2016        iconFadeInStartTime
2017      );
2018    }
2019  });
2020});
2021
2022// Alte Resize-Listener durch optimierte Version ersetzen
2023// und die initialen Optimierungen anwenden
2024initOptimizations();
2025
2026})(); // Ende der IIFE für GSAP Animation Initialisierung
2027
2028
2029// ================================================================
2030// =================== CUSTOM CURSOR SETUP ========================
2031// ================================================================
2032document.addEventListener('DOMContentLoaded', () => {
2033  // Nur auf Desktop aktivieren
2034  const isMobile = window.matchMedia('(max-width: 991px)').matches;
2035  if (isMobile) return;
2036  
2037  // Elemente finden
2038  const cursorDropdowns = document.querySelector('.custom-cursor-dropdowns');
2039  const cursorLinks = document.querySelector('.custom-cursor-links');
2040  if (!cursorDropdowns && !cursorLinks) return;
2041  
2042  const dropdowns = document.querySelectorAll('.services_dropdown, .approach_dropdown');
2043  const workItems = document.querySelectorAll('.work_item');
2044  const workImgWrappers = document.querySelectorAll('.work_img-wrapper');
2045  
2046  // =================== CURSOR VARIABLES & SETUP =====================
2047  // Aktuelle Hover-Information
2048  let currentDropdown = null;
2049  let currentWorkItem = null;
2050  let dropdownRect = null;
2051  let workItemRect = null;
2052  
2053  // Tracker für Mausbewegung
2054  let lastMouseX = 0;
2055  let lastMouseY = 0;
2056  let hasMouseMoved = false;
2057  let cursorIsReady = false;
2058  
2059  // Verzögerungsvariablen und Status-Tracker
2060  let dropdownLeaveTimeout = null;
2061  let isHoveringDropdown = false;
2062  
2063  // =================== PHYSIKBASIERTE ANIMATION ===================
2064  // Für Beschleunigungseffekt
2065  let targetX = 0;
2066  let currentX = 0;
2067  let currentSkew = 0;
2068  let skewVelocity = 0;
2069  
2070  // =================== CURSOR INITIALIZATION ======================
2071  // Initial GSAP setup für den Cursor (mit Opacity 0)
2072  if (cursorDropdowns) {
2073      gsap.set(cursorDropdowns, { 
2074          xPercent: -50, 
2075          yPercent: -50, 
2076          transformOrigin: 'center center',
2077          opacity: 0,
2078          visibility: 'hidden'
2079      });
2080  }
2081  
2082  if (cursorLinks) {
2083      gsap.set(cursorLinks, { 
2084          xPercent: -50, 
2085          yPercent: -50, 
2086          transformOrigin: 'center center',
2087          opacity: 0,
2088          visibility: 'hidden'
2089      });
2090  }
2091  
2092  // Setup für Text-Elemente
2093  let cursorTextWrapper = null;
2094  let cursorTextElements = [];
2095  let cursorVerticalLine = null;
2096  
2097  if (cursorDropdowns) {
2098      cursorTextWrapper = cursorDropdowns.querySelector('.cursor-text-wrapper-dropdowns');
2099      cursorTextElements = cursorDropdowns.querySelectorAll('.cursor-text-dropdowns');
2100      cursorVerticalLine = cursorDropdowns.querySelector('.cursor-icon-vertical-line');
2101  }
2102  
2103  if (cursorDropdowns && (!cursorTextWrapper || cursorTextElements.length === 0)) {
2104      console.warn('Cursor text elements not found');
2105      // Nicht komplett returnen, damit links-cursor noch funktioniert
2106  }
2107  
2108  // Hilfsfunktion: Cursor nur anzeigen, wenn er an der richtigen Position ist
2109  function showCursorWhenReady(cursorElement, x, y) {
2110      if (!cursorElement || !hasMouseMoved) return;
2111      
2112      // Cursor an die aktuelle Mausposition setzen
2113      gsap.set(cursorElement, {
2114          x: x,
2115          y: y
2116      });
2117      
2118      // Cursor einblenden, erst wenn die Maus bewegt wurde
2119      if (!cursorElement.classList.contains('active')) return;
2120      
2121      if (!cursorIsReady) {
2122          // Verzögertes Einblenden, um sicherzustellen, dass der Cursor an der richtigen Position ist
2123          setTimeout(() => {
2124              gsap.to(cursorElement, {
2125                  opacity: 1,
2126                  visibility: 'visible',
2127                  duration: 0.2,
2128                  ease: 'power2.out'
2129              });
2130              cursorIsReady = true;
2131          }, 20);
2132      }
2133  }
2134  
2135  // =================== MOUSEMOVE EVENT HANDLING ===================
2136  // Mousemove Event für Cursor-Positionierung
2137  document.addEventListener('mousemove', function(e) {
2138      // Setze hasMouseMoved auf true, sobald die Maus bewegt wurde
2139      hasMouseMoved = true;
2140      
2141      // Speichern der aktuellen Mausposition
2142      lastMouseX = e.clientX;
2143      lastMouseY = e.clientY;
2144      
2145      // Parallax für Work Item Images
2146      if (workImgWrappers.length > 0) {
2147          // Berechne relative Position (0 bis 1) basierend auf Viewport-Breite
2148          const relativeX = e.clientX / window.innerWidth;
2149          
2150          // Berechne Verschiebung (von -8rem bis +8rem)
2151          targetX = (relativeX - 0.5) * 128; // 0.5 ist die Mitte, 128 ist die maximale Verschiebung in PX
2152          
2153          // Wenn über einem Dropdown, füge Rotation hinzu
2154          if (currentDropdown && dropdownRect) {
2155              // Relative Positionen berechnen (0 bis 1)
2156              const relativeX = (e.clientX - dropdownRect.left) / dropdownRect.width;
2157              
2158              // Rotation
2159              const rotationDeg = 15 + (relativeX * -30);
2160              
2161              // Animation mit GSAP
2162              gsap.to(cursorDropdowns, {
2163                  duration: 0.2,
2164                  x: e.clientX,
2165                  y: e.clientY,
2166                  rotation: rotationDeg,
2167                  ease: "power3.out"
2168              });
2169              
2170              // Cursor anzeigen, wenn er bereit ist
2171              showCursorWhenReady(cursorDropdowns, e.clientX, e.clientY);
2172              
2173          } else if (currentWorkItem && workItemRect && cursorLinks) {
2174              // Relative Positionen berechnen für Work Step
2175              const relativeX = (e.clientX - workItemRect.left) / workItemRect.width;
2176              
2177              // Rotation
2178              const rotationDeg = 15 + (relativeX * -30);
2179              
2180              // Animation mit GSAP für Links-Cursor
2181              gsap.to(cursorLinks, {
2182                  duration: 0.2,
2183                  x: e.clientX,
2184                  y: e.clientY,
2185                  rotation: rotationDeg,
2186                  ease: "power3.out"
2187              });
2188              
2189              // Cursor anzeigen, wenn er bereit ist
2190              showCursorWhenReady(cursorLinks, e.clientX, e.clientY);
2191              
2192          } else {
2193              // Normale Bewegung ohne Rotation - Cursor verstecken
2194              if (cursorDropdowns) {
2195                  gsap.to(cursorDropdowns, {
2196                      duration: 0.2,
2197                      x: e.clientX,
2198                      y: e.clientY,
2199                      rotation: 0,
2200                      ease: "power3.out",
2201                      opacity: 0,
2202                      visibility: 'hidden'
2203                  });
2204                  cursorIsReady = false;
2205              }
2206              
2207              if (cursorLinks) {
2208                  gsap.to(cursorLinks, {
2209                      duration: 0.2,
2210                      x: e.clientX,
2211                      y: e.clientY,
2212                      rotation: 0,
2213                      ease: "power3.out",
2214                      opacity: 0,
2215                      visibility: 'hidden'
2216                  });
2217                  cursorIsReady = false;
2218              }
2219          }
2220      }
2221  });
2222
2223  // =================== DROPDOWN INTERACTION ======================
2224  // Hover Events für Dropdowns
2225  dropdowns.forEach(dropdown => {
2226      const checkbox = dropdown.querySelector('.services_dropdown-checkbox, .approach_dropdown-checkbox');
2227      if (!checkbox) return; 
2228      
2229      // Hover Events
2230      dropdown.addEventListener('mouseenter', () => {
2231          // Wenn ein Timeout zum Ausblenden gesetzt war, abbrechen
2232          if (dropdownLeaveTimeout) {
2233              clearTimeout(dropdownLeaveTimeout);
2234              dropdownLeaveTimeout = null;
2235          }
2236          
2237          isHoveringDropdown = true;
2238          cursorDropdowns.classList.add('active');
2239          currentDropdown = dropdown;
2240          dropdownRect = dropdown.getBoundingClientRect();
2241          
2242          // Text basierend auf dem aktuellen Zustand dieses spezifischen Dropdowns aktualisieren
2243          updateCursorTextState(checkbox.checked);
2244          
2245          // Vertikale Linie basierend auf Checkbox-Status ein-/ausblenden
2246          if (cursorVerticalLine) {
2247              // Gleiche Animation wie beim Click verwenden
2248              if (checkbox.checked) {
2249                  // Nach oben ausblenden (wenn geöffnet)
2250                  gsap.to(cursorVerticalLine, {
2251                      opacity: 0,
2252                      y: "-30%", // Hochanimieren
2253                      duration: 0.15,
2254                      ease: "power2.out" // Etwas smoothere Easing-Funktion
2255                  });
2256              } else {
2257                  // Direkt an der aktuellen Position wieder einblenden
2258                  gsap.to(cursorVerticalLine, {
2259                      opacity: 1,
2260                      y: 0, // Zurück zur Ausgangsposition
2261                      duration: 0.15,
2262                      ease: "power2.out" // Etwas smoothere Easing-Funktion
2263                  });
2264              }
2265          }
2266          
2267          // Cursor nur anzeigen, wenn die Maus bereits bewegt wurde
2268          if (hasMouseMoved) {
2269              // Cursor an die aktuelle Mausposition setzen und dann erst einblenden
2270              showCursorWhenReady(cursorDropdowns, lastMouseX, lastMouseY);
2271          }
2272      });
2273      
2274      dropdown.addEventListener('mouseleave', () => {
2275          // Verzögern des Ausblendens, um Flackern zu vermeiden
2276          dropdownLeaveTimeout = setTimeout(() => {
2277              // Nur ausblenden, wenn wir nicht über einem anderen Dropdown sind
2278              if (!isHoveringDropdown) {
2279                  cursorDropdowns.classList.remove('active');
2280                  currentDropdown = null;
2281                  dropdownRect = null;
2282                  
2283                  // Cursor ausblenden mit etwas Verzögerung
2284                  gsap.to(cursorDropdowns, {
2285                      opacity: 0,
2286                      visibility: 'hidden',
2287                      duration: 0.2,
2288                      ease: "power3.out"
2289                  });
2290                  cursorIsReady = false;
2291              }
2292              
2293              dropdownLeaveTimeout = null;
2294          }, 50); // Kurze Verzögerung, um Flackern zu vermeiden
2295          
2296          isHoveringDropdown = false;
2297      });
2298      
2299      // Checkbox Change Event
2300      checkbox.addEventListener('change', () => {
2301          // Text und vertikale Linie gleichzeitig animieren
2302          updateCursorTextState(checkbox.checked);
2303          
2304          // Vertikale Linie basierend auf Checkbox-Status ein-/ausblenden
2305          if (cursorVerticalLine) {
2306              if (checkbox.checked) {
2307                  // Nach oben ausblenden (wenn geöffnet)
2308                  gsap.to(cursorVerticalLine, {
2309                      opacity: 0,
2310                      y: "-30%", // Hochanimieren
2311                      duration: 0.15,
2312                      ease: "power2.out" // Etwas smoothere Easing-Funktion
2313                  });
2314              } else {
2315                  // Direkt an der aktuellen Position wieder einblenden
2316                  gsap.to(cursorVerticalLine, {
2317                      opacity: 1,
2318                      y: 0, // Zurück zur Ausgangsposition
2319                      duration: 0.15,
2320                      ease: "power2.out" // Etwas smoothere Easing-Funktion
2321                  });
2322              }
2323          }
2324      });
2325      
2326      // Initialen Zustand setzen
2327      if (checkbox.checked) {
2328          updateCursorTextState(true);
2329          
2330          // Auch beim initialen Zustand die vertikale Linie richtig setzen
2331          if (cursorVerticalLine) {
2332              gsap.set(cursorVerticalLine, { opacity: 0, y: "-30%" });
2333          }
2334      }
2335  });
2336  
2337  // =================== WORK ITEM INTERACTION =====================
2338  // Hover Events für Work Step Headings
2339  workItems.forEach(workItem => {
2340      if (!cursorLinks) return;
2341      
2342      // Finde den zugehörigen Image Wrapper
2343      const imgWrapper = workItem.querySelector('.work_img-wrapper');
2344      
2345      // Hover Events
2346      workItem.addEventListener('mouseenter', () => {
2347          cursorLinks.classList.add('active');
2348          currentWorkItem = workItem;
2349          workItemRect = workItem.getBoundingClientRect();
2350          
2351          // Zeige Image Wrapper
2352          if (imgWrapper) {
2353              gsap.set(imgWrapper, { opacity: 1 });
2354          }
2355          
2356          // Cursor nur anzeigen, wenn die Maus bereits bewegt wurde
2357          if (hasMouseMoved) {
2358              // Cursor an die aktuelle Mausposition setzen und dann erst einblenden
2359              showCursorWhenReady(cursorLinks, lastMouseX, lastMouseY);
2360          }
2361      });
2362      
2363      workItem.addEventListener('mouseleave', () => {
2364          cursorLinks.classList.remove('active');
2365          currentWorkItem = null;
2366          workItemRect = null;
2367          
2368          // Verstecke Image Wrapper
2369          if (imgWrapper) {
2370              gsap.set(imgWrapper, { opacity: 0 });
2371          }
2372          
2373          // Cursor ausblenden
2374          gsap.to(cursorLinks, {
2375              opacity: 0,
2376              visibility: 'hidden',
2377              duration: 0.2,
2378              ease: "power3.out"
2379          });
2380          cursorIsReady = false;
2381      });
2382  });
2383  
2384  // =================== HELPER FUNCTIONS ==========================
2385  // Funktion zum Aktualisieren der Text-Zustände
2386  function updateCursorTextState(isChecked) {
2387      if (cursorTextElements.length === 0) return;
2388      
2389      // Animation ohne unnötige Parameter
2390      const offset = isChecked ? "-1.1em" : "0";
2391      cursorTextElements.forEach(element => {
2392          gsap.to(element, {
2393              y: offset,
2394              duration: 0.1, // 100ms für schnellere, gleichmäßigere Animation
2395              ease: "ease" // Linear und gleichmäßig
2396          });
2397      });
2398  }
2399
2400  // =================== PHYSIKBASIERTE ANIMATION LOOP =============
2401  // Animation Loop für physikbasierte Bewegung
2402  function animateWorkImages() {
2403      if (workImgWrappers.length > 0) {
2404          // Physikbasierte Animation für X-Position
2405          const xDiff = targetX - currentX;
2406          currentX += xDiff * 0.2; // Verzögerung für natürliches Gefühl - höhere Werte (0.2-0.3) = schnellere Reaktion
2407          
2408          // Berechne Skew basierend auf der Geschwindigkeit der Bewegung
2409          const skewFactor = 0.5; // Stärke des Effekts - höhere Werte = stärkere Verzerrung (0.1-0.5 empfohlen)
2410          const targetSkew = xDiff * skewFactor; // Positiver Wert damit der untere Teil zuerst beschleunigt
2411          
2412          // Physikbasierte Animation für Skew
2413          skewVelocity += (targetSkew - currentSkew) * 0.5; // Beschleunigung - höhere Werte = schnellere Reaktion
2414          skewVelocity *= 0.75; // Dämpfung - niedrigere Werte = längeres Nachschwingen
2415          currentSkew += skewVelocity;
2416          
2417          // Animiere alle Work Item Images
2418          workImgWrappers.forEach(wrapper => {
2419              gsap.set(wrapper, {
2420                  x: currentX,
2421                  skewX: currentSkew
2422              });
2423          });
2424      }
2425      
2426      // Animation fortsetzen
2427      requestAnimationFrame(animateWorkImages);
2428  }
2429  
2430  // Animation starten
2431  animateWorkImages();
2432});
2433</script>
2433</body></html>

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.