PageSourceSearch

https://studio.yogaeasy.de/calendar/agenda

html yogaeasy.de collected 2026-09-25 14:31:46 UTC 82,752 bytes, 2,228 lines download raw bytes

1<!DOCTYPE html>
2<html lang="de" class="h-full">
3  <head>
4    <meta name="csrf-param" content="authenticity_token" />
5<meta name="csrf-token" content="71RS4IMZpqrDwqtPXkCTt7SUXB-uFoQAXfT3TfoScDnLr6u0R_iedTbrCBNPVdyQqcsH3qVhi9HzGtADLh-o3A" />
6    <meta charset="utf-8">
7    <meta name="viewport" content="width=device-width, initial-scale=1.0">
8
9    <link rel="preconnect" href="https://alpha.uscreencdn.com">
10    <link rel="preconnect">
11    <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&amp;display=swap">
12
13    <meta name="view-transition" content="same-origin">
14
15    
15<script src="https://assets-gke.uscreencdn.com/vite/assets/web-components-BnSq9iDb.js" crossorigin="anonymous" type="module"></script>
15<link rel="modulepreload" href="https://assets-gke.uscreencdn.com/vite/assets/preload-helper-s3Hva0Xc.js" as="script" crossorigin="anonymous">
16    
16<script src="https://assets-gke.uscreencdn.com/vite/assets/storefront_hotwire-DtHj5W-7.js" crossorigin="anonymous" type="module"></script>
16<link rel="modulepreload" href="https://assets-gke.uscreencdn.com/vite/assets/preload-helper-s3Hva0Xc.js" as="script" crossorigin="anonymous">
17<link rel="modulepreload" href="https://assets-gke.uscreencdn.com/vite/assets/excludeTurboTrainBroadcastReactEvents-BZh0xnrk.js" as="script" crossorigin="anonymous">
18<link rel="modulepreload" href="https://assets-gke.uscreencdn.com/vite/assets/VideoTracker-BZWAH44E.js" as="script" crossorigin="anonymous">
19<link rel="modulepreload" href="https://assets-gke.uscreencdn.com/vite/assets/_commonjsHelpers-BosuxZz1.js" as="script" crossorigin="anonymous"><link rel="stylesheet" href="https://assets-gke.uscreencdn.com/vite/assets/storefront_hotwire-DtHu4oK3.css" media="screen" />
20    <link rel="stylesheet" href="https://assets-gke.uscreencdn.com/vite/assets/tailwind-DY7eudTN.css" media="all" />
21    <link rel="stylesheet" href="https://assets-gke.uscreencdn.com/vite/assets/storefront_common-D_5IJA0x.css" media="all" />
22
23      
23<script>
24        window.hotwireCatalog = true
25        window.addEventListener('turbo:before-fetch-request', function (event) {
26          event.detail.fetchOptions.headers['X-Fastly-Origin'] = "yogaeasygermansite"
27        })
28      </script>
28
29    
29<script>
30      window.apiUrl = "https://api.uscreencdn.com"
31      window.apiOrigin = "yogaeasygermansite"
32    </script>
32
33
34    
34<script>
35//<![CDATA[
36window.gon={};gon.global={"uppy_companion_url":"/uppy","assets_cdn_url":"https://alpha.uscreencdn.com","mixpanel_token":"44e8d04b49529b306bd4a1c79afcc56e"};gon.feature_flags=["themeless","themeless_catalog_visual_fixes","ai_video_recommendations","ai_storefront_related_videos","ai_storefront_related_video_collections","show_captcha","show_captcha_v3","network_spam_detection","calendar_collection_scheduling","live_events_feed","checkout_donations","allow_invite_people","hotwire_catalog","passwordless_sign_up","rudolph_subscription_plans","content_moderation","audiences","email_topics","order_bumps","external_checkout","custom_google_cast_receiver","hubspot_hand_raise","refer_to_uscreen","billing_sales_tax_on_fees","community_notifications_v1","new_video_get_access_page","real_time_apple_notifications","real_time_roku_notifications","real_time_amazon_notifications","real_time_android_notifications","developer_apps_ui","users_mcp_permissions","apps_update_requests","account_creation_required","banner_with_live_stream_overage","paypal_beta","client_emails_footer","force_shortened_checkout","stripe_subscriptions","new_subscription_flow","pause_subscriptions","dm_attachments_in_app","stripe_tax_collection","ai_video_recommendations_waitlist","mobile_featured_category_thumbnail_style","prompt_app_updates","videos_bulk_all_matching","webhook_auto_disable"];gon.settings={"primary_color":"#009090","commenting":true,"my_library":true,"stats_id":"c43v645rpolt89529v2pesifn","analytics_env_id":"production","chapter_style":"sidebar","store_title":"yogaeasy.de","continue_watching":false,"mark_as_watched":true,"live_event_feed_link":"webcal://studio.yogaeasy.de/live_event_feed.ics","locale":"de","autoplay":true,"uplayer":false,"show_notifications_center":false,"time_format":null,"local_timezone":null};gon.currency="EUR";gon.locale="de";gon.country="US";gon.stripe="pk_live_DImPqz7QOOyx70XCA9DSifxb";gon.recaptcha_v3_pub_key="6LenX-EZAAAAAAITxgGIXKB3S2OVKsM5r5tg0wKL";gon.store_id=114449;gon.writing_direction="ltr";
37//]]>
38</script>
38
39
40    
40<script>
41      var sentryDsn = 'https://[email protected]/4509910289350656'
42      var sentryStorefrontActive = true
43      var sentryStorefrontSampleRate = 1.0
44      var railsEnv = 'production'
45      var analyticsHost = 'https://stats.uscreen.io'
46      var uscreenStoreId = 114449
47      var isUscreenUserImpersonated = false
48      var analyticsConfig = null
49      var storeId = 114449
50    </script>
50
51
52      <link
53  rel="icon"
54  href="https://alpha.uscreencdn.com/images/favicontypes/114649/favicon.1764767796.png"
55>
56<link
57  rel="apple-touch-icon"
58  sizes="180x180"
59  href="https://alpha.uscreencdn.com/images/favicontypes/114649/favicon.1764767796.png"
60>
61
62
63    
63<script
64  type="module"
65  crossorigin
66  src="https://cdn.jsdelivr.net/npm/@uscreentv/[email protected]/+esm"
67></script>
67
68
69      <title>yogaeasy.de</title>
70<meta name="description" content="">
71<!-- Twitter Card data -->
72<meta name="twitter:card" content="summary" />
73<meta name="twitter:title" content="yogaeasy.de" />
74<meta name="twitter:description" content="" />
75<meta name="twitter:image" content="https://alpha.uscreencdn.com/450xnull/images/logotypes/114649/logo_rgb.1775111741.png?auto=webp" />
76<!-- Open Graph data -->
77<meta property="og:title" content="yogaeasy.de" >
78<meta property="og:type" content="website" />
79<meta property="og:url" content="https://studio.yogaeasy.de/calendar/agenda" >
80<meta property="og:image" content="https://alpha.uscreencdn.com/1110xnull/images/logotypes/114649/logo_rgb.1775111741.png?auto=webp" >
81<meta property="og:image:width" content="740" >
82<meta property="og:image:height" content="420" >
83<meta property="og:description" content="" >
84<meta property="og:site_name" content="yogaeasy.de" />
85<link rel="canonical" href="https://studio.yogaeasy.de/calendar/agenda" />
86<script type = 'application/ld+json' >
87  {
88    "@context": "https://schema.org",
89    "@type": "Organization",
90    "url": "https://studio.yogaeasy.de",
91    "@id": "https://studio.yogaeasy.de/#organization",
92    "name": "yogaeasy.de",
93    "logo": "https://alpha.uscreencdn.com/450xnull/images/logotypes/114649/logo_rgb.1775111741.png?auto=webp"
94  }
95</script>
95
96
97
98    <!-- Google Analytics -->
99
100<!-- End Google Analytics -->
101
102    <!-- Google Tag Manager -->
103  
103<script>
vendor: 348 bytes, lines 103-108
103
104    (function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
105    new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
106    j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
107    'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
108    })(window,document,'script','dataLayer','
108GTM-5VXV6X
vendor: 6 bytes, lines 108-109
108');
109  
109</script>
109
110<!-- End Google Tag Manager -->
111
112
113    <style>
114    :root {
115        --primary: #009090;
116        --primary-rgb: 0, 144, 144;
117        --contrast-text-color: #FFFFFF;
118        --contrast-to-primary-color: #fff;
119    }
120</style>
121<style id="custom-theme-styles" media="all">
122    body.light {
123        --main-color-h: 0;
124        --main-color-s: 100;
125        --main-color-l: 100;
126        --ds-bg-main: hsl(0, 100%, 100%);
127
128        --ds-bg-default: hsl(var(--main-color-h), calc(var(--main-color-s) * 1%), 96%);
129        --ds-bg-inset: hsl(var(--main-color-h), calc(var(--main-color-s) * 1%), 91%);
130        --ds-bg-overlay: hsl(var(--main-color-h), calc(var(--main-color-s) * 1%), 98%);
131        --ds-bg-subtle: hsl(var(--main-color-h), calc(var(--main-color-s) * 1%), 91%);
132
133        --ds-border-default: hsl(var(--main-color-h), calc(var(--main-color-s) * 1%), 85%);
134        --ds-fg-default: hsl(var(--main-color-h), calc(var(--main-color-s) * 1%), 8%);
135        --ds-fg-muted: hsl(var(--main-color-h), calc(var(--main-color-s) * 1%), 25%);
136        --ds-fg-subtle: hsl(var(--main-color-h), calc(var(--main-color-s) * 1%), 50%);
137    }
138
139    body.dark {
140        --main-color-h: 0;
141        --main-color-s: 100;
142        --main-color-l: 0;
143        --ds-bg-main: hsl(0, 100%, 0%);
144
145        --ds-bg-default: hsl(var(--main-color-h), calc(var(--main-color-s) * 1%), 10%);
146        --ds-bg-overlay: hsl(var(--main-color-h), calc(var(--main-color-s) * 1%), 2%);
147        --ds-bg-inset: hsl(var(--main-color-h), calc(var(--main-color-s) * 1%), 6%);
148        --ds-bg-subtle: hsl(var(--main-color-h), calc(var(--main-color-s) * 1%), 15%);
149
150        --ds-border-default: hsl(var(--main-color-h), calc(var(--main-color-s) * 1%), 20%);
151        --ds-fg-default: hsl(var(--main-color-h), calc(var(--main-color-s) * 1%), 98%);
152        --ds-fg-muted: hsl(var(--main-color-h), calc(var(--main-color-s) * 1%), 70%);
153        --ds-fg-subtle: hsl(var(--main-color-h), clamp(7%, calc(calc(var(--main-color-s) - 10) * 1%), 100%), 60%);
154    }
155
156    body.dark,
157    body.light {
158        --main-color-h: 60;
159        --main-color-s: 12;
160        --main-color-l: 97;
161        --ds-bg-main: hsl(60, 12%, 97%);
162    }
163</style>
164
165    
166<link rel="preconnect" href="https://s3.us-east-1.amazonaws.com">
167<style>
168  .agenda-item-card:hover .agenda-item-button {
169    background-color: #009090;
170  }
171  .light-forced, :root {
172    --gray-700: #555547;
173  }
174  body.light,
175  html,
176  body {
177    --ds-fg-default: #555547 !important;
178  }
179  #website-links a {
180    font-weight: 500;
181  }
182  #upsell_form ds-button {
183    --primary-color: #009090 !important;
184  }
185  a.category.bg-black {
186    background: #009090;
187  }
188    @font-face {
189      font-family: 'SourceSansPro';
190      src: url('https://unode1.s3.amazonaws.com/assets%2F%2Fassets%2F15576%2F%2Fsourcesansproregular.1772012777.eot');
191      src: url('https://unode1.s3.amazonaws.com/assets%2F%2Fassets%2F15576%2F%2Fsourcesansproregular.1772012777.eot') format('embedded-opentype'),
192            url('https://unode1.s3.amazonaws.com/assets%2F%2Fassets%2F15576%2F%2Fsourcesansproregular.1772012770.woff2') format('woff2'),
193            url('https://unode1.s3.amazonaws.com/assets%2F%2Fassets%2F15576%2F%2Fsourcesansproregular.1772012783.woff') format('woff'),
194            url('https://unode1.s3.amazonaws.com/assets%2F%2Fassets%2F15576%2F%2Fsourcesansproregular.1772012893.ttf') format('truetype'),
195            url('https://unode1.s3.amazonaws.com/assets%2F%2Fassets%2F15576%2F%2Fsourcesansproregular.1772012790.svg#SourceSansPro') format('svg');
196      font-weight: normal;
197      font-style: normal;
198      font-display: swap;
199    }
200    @font-face {
201      font-family: 'SourceSansPro';
202      src: url('https://unode1.s3.amazonaws.com/assets%2F%2Fassets%2F15576%2F%2Fsourcesansprosemibold.1772012932.eot');
203      src: url('https://unode1.s3.amazonaws.com/assets%2F%2Fassets%2F15576%2F%2Fsourcesansprosemibold.1772012932.eot') format('embedded-opentype'),
204            url('https://unode1.s3.amazonaws.com/assets%2F%2Fassets%2F15576%2F%2Fsourcesansprosemibold.1772012925.woff2') format('woff2'),
205            url('https://unode1.s3.amazonaws.com/assets%2F%2Fassets%2F15576%2F%2Fsourcesansprosemibold.1772012945.woff') format('woff'),
206            url('https://unode1.s3.amazonaws.com/assets%2F%2Fassets%2F15576%2F%2Fsourcesansprosemibold.1772012950.ttf') format('truetype'),
207            url('https://unode1.s3.amazonaws.com/assets%2F%2Fassets%2F15576%2F%2Fsourcesansprosemibold.1772012939.svg#SourceSansPro') format('svg');
208      font-weight: 500;
209      font-style: normal;
210      font-display: swap;
211    }
212    @font-face {
213      font-family: 'SourceSansPro';
214      src: url('https://unode1.s3.amazonaws.com/assets%2F%2Fassets%2F15576%2F%2Fsourcesansprobold.1772113704.eot');
215      src: url('https://unode1.s3.amazonaws.com/assets%2F%2Fassets%2F15576%2F%2Fsourcesansprobold.1772113704.eot') format('embedded-opentype'),
216            url('https://unode1.s3.amazonaws.com/assets%2F%2Fassets%2F15576%2F%2Fsourcesansprobold.1772113691.woff2') format('woff2'),
217            url('https://unode1.s3.amazonaws.com/assets%2F%2Fassets%2F15576%2F%2Fsourcesansprobold.1772113714.woff') format('woff'),
218            url('https://unode1.s3.amazonaws.com/assets%2F%2Fassets%2F15576%2F%2Fsourcesansprobold.1772113736.ttf') format('truetype'),
219            url('https://unode1.s3.amazonaws.com/assets%2F%2Fassets%2F15576%2F%2Fsourcesansprobold.1772113723.svg#SourceSansPro') format('svg');
220      font-weight: 600;
221      font-style: normal;
222      font-display: swap;
223    }
224    @font-face {
225      font-family: 'SourceSansPro';
226      src: url('https://unode1.s3.amazonaws.com/assets%2F%2Fassets%2F15576%2F%2Fsourcesansproitalic.1772012981.eot');
227      src: url('https://unode1.s3.amazonaws.com/assets%2F%2Fassets%2F15576%2F%2Fsourcesansproitalic.1772012981.eot') format('embedded-opentype'),
228            url('https://unode1.s3.amazonaws.com/assets%2F%2Fassets%2F15576%2F%2Fsourcesansproitalic.1772012975.woff2') format('woff2'),
229            url('https://unode1.s3.amazonaws.com/assets%2F%2Fassets%2F15576%2F%2Fsourcesansproitalic.1772012986.woff') format('woff'),
230            url('https://unode1.s3.amazonaws.com/assets%2F%2Fassets%2F15576%2F%2Fsourcesansproitalic.1772012999.ttf') format('truetype'),
231            url('https://unode1.s3.amazonaws.com/assets%2F%2Fassets%2F15576%2F%2Fsourcesansproitalic.1772012991.svg#SourceSansPro') format('svg');
232      font-weight: normal;
233      font-style: italic;
234      font-display: swap;
235    }
236
237
238h1, h2, h3, h4, h5,
239.cbt-tabs--subtitle,
240.cbt-related-title,
241.category-title,
242.heading_font_family,
243.theme\:title {
244  font-family: 'SourceSansPro', sans-serif !important;
245  color: #0e5c63 !important
246}
247.category-title {
248  font-weight: 600;
249}
250.comments-title,
251.cbt-related-title {
252  color: #555547 !important
253}
254
255body, html,
256.card-title .card-duration,
257.cbt-tabs--content,
258.body_font_family {
259  font-family: 'SourceSansPro', sans-serif;
260}
261
262
263.theme\:navigation a,
264.button-content,
265.s-button {
266  font-family: 'SourceSansPro', sans-serif;
267}
268
269.light .category-see-all a {
270  color: #555547 !important;
271  font-weight: 400;
272}
273</style>
274
275<!-- Feature: YogaEasy checkout full-page coupon gate (Tag: checkout, coupon, multi-offer) -->
276<style>
277  html.ye-coupon-gate-open,
278  body.ye-coupon-gate-open {
279    overflow: hidden !important;
280  }
281
282  #ye-coupon-gate {
283    position: fixed;
284    inset: 0;
285    display: block;
286    overflow: auto;
287    background: #ffffff;
288    z-index: 2147483000;
289  }
290
291  #ye-coupon-gate[hidden] {
292    display: none;
293  }
294
295  .ye-coupon-gate__dialog {
296    width: 100%;
297    min-height: 100%;
298    background: #ffffff;
299  }
300
301  .ye-coupon-gate__inner {
302    width: min(1220px, 100%);
303    margin: 0 auto;
304    padding: clamp(14px, 2.8vh, 28px) clamp(14px, 3vw, 34px) clamp(20px, 4vh, 40px);
305    text-align: center;
306  }
307
308  .ye-coupon-gate__logo {
309    display: block;
310    width: min(290px, 72vw);
311    margin: 0 auto 12px;
312  }
313
314  .ye-coupon-gate__title {
315    margin: 0;
316    color: #005666;
317    font-size: clamp(1.9rem, 3.3vw, 3.7rem);
318    line-height: 1.08;
319    font-family: Georgia, "Times New Roman", serif;
320    font-weight: 700;
321    letter-spacing: -0.02em;
322  }
323
324  .ye-coupon-gate__copy {
325    margin: 8px auto 14px;
326    color: #3c3f42;
327    font-size: clamp(0.95rem, 1.22vw, 1.42rem);
328    line-height: 1.34;
329    max-width: 900px;
330    font-family: "Avenir Next", Avenir, "Segoe UI", Arial, sans-serif;
331  }
332
333  .ye-coupon-gate__hero {
334    display: block;
335    width: 100%;
336    max-width: 100%;
337    max-height: min(29vh, 340px);
338    aspect-ratio: 2.4 / 1;
339    object-fit: cover;
340    margin: 0 auto;
341    border-radius: 52% 52% 0 0 / 15% 15% 0 0;
342  }
343
344  .ye-coupon-gate__form-wrap {
345    padding: clamp(12px, 2.4vh, 24px) 0 clamp(10px, 1.8vh, 20px);
346  }
347
348  .ye-coupon-gate__form-title {
349    margin: 0 0 10px;
350    color: #005666;
351    font-size: clamp(1.3rem, 2.45vw, 2.1rem);
352    line-height: 1.2;
353    font-family: Georgia, "Times New Roman", serif;
354    font-weight: 700;
355  }
356
357  .ye-coupon-gate__field {
358    width: min(560px, 100%);
359    margin: 0 auto;
360  }
361
362  .ye-coupon-gate__input {
363    width: 100%;
364    border: 1px solid #cfd3d5;
365    background: #ffffff;
366    color: #2f3a3d;
367    border-radius: 0;
368    font-size: 1.05rem;
369    line-height: 1.3;
370    padding: 14px 16px;
371    outline: none;
372    font-family: "Avenir Next", Avenir, "Segoe UI", Arial, sans-serif;
373  }
374
375  .ye-coupon-gate__input:focus {
376    border-color: #1b7685;
377    box-shadow: 0 0 0 3px rgba(27, 118, 133, 0.2);
378  }
379
380  .ye-coupon-gate__submit {
381    width: min(560px, 100%);
382    margin: 10px auto 0;
383    border: none;
384    border-radius: 999px;
385    background: #f7d9d2;
386    color: #ffffff;
387    font-size: 1.08rem;
388    font-weight: 700;
389    letter-spacing: 0.01em;
390    padding: 13px 18px;
391    cursor: pointer;
392    font-family: "Avenir Next", Avenir, "Segoe UI", Arial, sans-serif;
393    transition: transform 0.16s ease, box-shadow 0.2s ease, filter 0.2s ease;
394  }
395
396  .ye-coupon-gate__submit:hover:not([disabled]) {
397    transform: translateY(-1px);
398    box-shadow: 0 10px 22px rgba(0, 86, 102, 0.18);
399    filter: brightness(1.02);
400  }
401
402  .ye-coupon-gate__submit[disabled] {
403    cursor: not-allowed;
404    opacity: 0.7;
405    box-shadow: none;
406    transform: none;
407  }
408
409  .ye-coupon-gate__error {
410    min-height: 22px;
411    margin: 8px auto 0;
412    color: #c13f4b;
413    font-size: 0.95rem;
414    line-height: 1.3;
415    font-family: "Avenir Next", Avenir, "Segoe UI", Arial, sans-serif;
416  }
417
418  @media (max-width: 900px) {
419    .ye-coupon-gate__inner {
420      padding-top: 16px;
421    }
422
423    .ye-coupon-gate__logo {
424      width: min(250px, 74vw);
425      margin-bottom: 10px;
426    }
427
428    .ye-coupon-gate__copy {
429      margin-bottom: 12px;
430    }
431
432    .ye-coupon-gate__hero {
433      max-height: min(24vh, 220px);
434      border-radius: 34% 34% 0 0 / 11% 11% 0 0;
435    }
436  }
437
438  @media (max-width: 640px) {
439    .ye-coupon-gate__title {
440      line-height: 1.08;
441    }
442
443    .ye-coupon-gate__copy {
444      max-width: 96vw;
445      font-size: 0.98rem;
446    }
447
448    .ye-coupon-gate__form-wrap {
449      padding-top: 12px;
450    }
451
452    .ye-coupon-gate__form-title {
453      margin-bottom: 8px;
454    }
455
456    .ye-coupon-gate__hero {
457      max-height: 170px;
458    }
459  }
460</style>
461
462<script>
463  (() => {
464    const FLAG = '__YE_COUPON_GATE__';
465    if (window[FLAG]) return;
466    window[FLAG] = true;
467
468    const OFFER_IDS = new Set(['224153', '224840', '224842', '224843']);
469    const COUPON_PARAM = 'd';
470    const COUPON_SUCCESS_SELECTOR = '#coupon-code';
471    const OVERLAY_ID = 'ye-coupon-gate';
472    const LOCK_CLASS = 'ye-coupon-gate-open';
473    const HERO_IMAGE_URL = 'https://unode1.s3.amazonaws.com/assets%2F%2Fassets%2F15576%2F%2Fcampaign_de.1770400233.jpg';
474    const LOGO_IMAGE_URL = 'https://alpha.uscreencdn.com/images/logotypes/114649/logo_rgb.1775111741.png';
475
476    let overlayEl = null;
477    let formEl = null;
478    let inputEl = null;
479    let submitEl = null;
480    let errorEl = null;
481    let focusables = [];
482    let observer = null;
483    let watchInterval = null;
484    let pendingStatusTimer = null;
485    let isLocked = false;
486
487    const isTargetCheckout = (url) => (
488      url.pathname === '/checkout/new' &&
489      OFFER_IDS.has(url.searchParams.get('o') || '')
490    );
491
492    const normalizeCoupon = (value) => String(value || '')
493      .trim()
494      .replace(/\s+/g, '')
495      .toUpperCase();
496
497    const getCouponFromUrl = () => {
498      const url = new URL(window.location.href);
499      return normalizeCoupon(url.searchParams.get(COUPON_PARAM));
500    };
501
502    const clearPendingStatusTimer = () => {
503      if (pendingStatusTimer) {
504        window.clearTimeout(pendingStatusTimer);
505        pendingStatusTimer = null;
506      }
507    };
508
509    const couponAppliedSuccessfully = () => {
510      const couponEl = document.querySelector(COUPON_SUCCESS_SELECTOR);
511      if (!couponEl) return false;
512      const pageCoupon = normalizeCoupon(couponEl.textContent || '');
513      if (!pageCoupon) return false;
514
515      const urlCoupon = getCouponFromUrl();
516      if (!urlCoupon) return true;
517      return pageCoupon.includes(urlCoupon) || urlCoupon.includes(pageCoupon);
518    };
519
520    const stopWatchingCouponApply = () => {
521      if (observer) {
522        observer.disconnect();
523        observer = null;
524      }
525      if (watchInterval) {
526        window.clearInterval(watchInterval);
527        watchInterval = null;
528      }
529      clearPendingStatusTimer();
530    };
531
532    const startWatchingCouponApply = () => {
533      if (observer || watchInterval) return;
534      if (!document.body) return;
535
536      observer = new MutationObserver(() => {
537        evaluateRoute();
538      });
539      observer.observe(document.body, {
540        childList: true,
541        subtree: true,
542        characterData: true
543      });
544
545      watchInterval = window.setInterval(() => {
546        evaluateRoute();
547      }, 500);
548    };
549
550    const schedulePendingCouponStatus = () => {
551      clearPendingStatusTimer();
552      const couponFromUrl = getCouponFromUrl();
553      if (!couponFromUrl) {
554        if (errorEl) errorEl.textContent = '';
555        return;
556      }
557
558      pendingStatusTimer = window.setTimeout(() => {
559        if (!isLocked) return;
560        if (couponAppliedSuccessfully()) return;
561        const liveInputCoupon = normalizeCoupon(inputEl?.value || '');
562        if (liveInputCoupon && liveInputCoupon !== couponFromUrl) return;
563        if (errorEl) {
564          errorEl.textContent = 'Coupon code not found. Bitte prüfe den Code und versuche es erneut.';
565        }
566        if (submitEl) {
567          submitEl.disabled = false;
568          submitEl.textContent = 'Gutschein einlösen';
569        }
570        if (inputEl) {
571          inputEl.disabled = false;
572          inputEl.focus();
573          inputEl.select();
574        }
575      }, 2800);
576    };
577
578    const setLocked = (locked) => {
579      const wasLocked = isLocked;
580      isLocked = locked;
581      document.documentElement.classList.toggle(LOCK_CLASS, locked);
582      document.body?.classList.toggle(LOCK_CLASS, locked);
583      const existingOverlay = overlayEl && overlayEl.isConnected
584        ? overlayEl
585        : document.getElementById(OVERLAY_ID);
586      const overlay = locked ? ensureOverlay() : existingOverlay;
587      if (!overlay) return;
588      overlay.hidden = !locked;
589      if (locked && !wasLocked) {
590        const couponFromUrl = getCouponFromUrl();
591        if (couponFromUrl && inputEl && !normalizeCoupon(inputEl.value)) {
592          inputEl.value = couponFromUrl;
593        }
594        schedulePendingCouponStatus();
595        setTimeout(() => inputEl?.focus(), 70);
596      } else if (!locked && wasLocked) {
597        clearPendingStatusTimer();
598        if (errorEl) errorEl.textContent = '';
599        if (submitEl) {
600          submitEl.disabled = false;
601          submitEl.textContent = 'Gutschein einlösen';
602        }
603        if (inputEl) inputEl.disabled = false;
604      }
605    };
606
607    const ensureOverlay = () => {
608      if (overlayEl && overlayEl.isConnected) return overlayEl;
609      if (!document.body) return null;
610
611      overlayEl = document.getElementById(OVERLAY_ID);
612      if (!overlayEl) {
613        overlayEl = document.createElement('div');
614        overlayEl.id = OVERLAY_ID;
615        overlayEl.hidden = true;
616        overlayEl.innerHTML = `
617          <div class="ye-coupon-gate__dialog" role="dialog" aria-modal="true" aria-labelledby="ye-coupon-gate-title">
618            <div class="ye-coupon-gate__inner">
619              <img class="ye-coupon-gate__logo" src="${LOGO_IMAGE_URL}" alt="yogaeasy logo" loading="eager" decoding="async" />
620              <h2 id="ye-coupon-gate-title" class="ye-coupon-gate__title">Dein Online-Yogastudio</h2>
621              <p class="ye-coupon-gate__copy">
622                Übe Yoga mit den besten Lehrer:innen für mehr Balance, Stärke und innere Ruhe.
623                Yoga für jeden Körper. Jederzeit.
624              </p>
625              <div class="ye-coupon-gate__form-wrap">
626                <h3 class="ye-coupon-gate__form-title">Gib hier deinen Gutscheincode ein</h3>
627                <form novalidate>
628                  <div class="ye-coupon-gate__field">
629                    <input
630                      class="ye-coupon-gate__input"
631                      type="text"
632                      name="coupon"
633                      autocomplete="off"
634                      autocapitalize="characters"
635                      spellcheck="false"
636                      placeholder="Dein persönlicher Gutscheincode"
637                      required
638                    />
639                  </div>
640                  <button class="ye-coupon-gate__submit" type="submit">Gutschein einlösen</button>
641                  <p class="ye-coupon-gate__error" role="alert" aria-live="assertive"></p>
642                </form>
643              </div>
644              <img class="ye-coupon-gate__hero" src="${HERO_IMAGE_URL}" alt="" loading="eager" decoding="async" />
645            </div>
646          </div>
647        `;
648        document.body.appendChild(overlayEl);
649      }
650
651      if (!overlayEl.dataset.bound) {
652        overlayEl.dataset.bound = 'true';
653        formEl = overlayEl.querySelector('form');
654        inputEl = overlayEl.querySelector('.ye-coupon-gate__input');
655        submitEl = overlayEl.querySelector('.ye-coupon-gate__submit');
656        errorEl = overlayEl.querySelector('.ye-coupon-gate__error');
657        focusables = [inputEl, submitEl].filter(Boolean);
658
659        formEl?.addEventListener('submit', (event) => {
660          event.preventDefault();
661
662          const rawCoupon = inputEl?.value || '';
663          const coupon = normalizeCoupon(rawCoupon);
664
665          if (!coupon) {
666            if (errorEl) errorEl.textContent = 'Bitte gib einen gültigen Gutscheincode ein.';
667            inputEl?.focus();
668            return;
669          }
670
671          if (errorEl) errorEl.textContent = '';
672          clearPendingStatusTimer();
673          if (submitEl) {
674            submitEl.disabled = true;
675            submitEl.textContent = 'Wird angewendet...';
676          }
677          if (inputEl) inputEl.disabled = true;
678
679          const url = new URL(window.location.href);
680          url.searchParams.set(COUPON_PARAM, coupon);
681          window.location.replace(url.toString());
682        });
683
684        inputEl?.addEventListener('input', () => {
685          if (errorEl) errorEl.textContent = '';
686          if (submitEl) {
687            submitEl.disabled = false;
688            submitEl.textContent = 'Gutschein einlösen';
689          }
690          clearPendingStatusTimer();
691        });
692
693        overlayEl.addEventListener('keydown', (event) => {
694          if (event.key !== 'Tab' || focusables.length < 2) return;
695          const first = focusables[0];
696          const last = focusables[focusables.length - 1];
697          if (event.shiftKey && document.activeElement === first) {
698            event.preventDefault();
699            last.focus();
700          } else if (!event.shiftKey && document.activeElement === last) {
701            event.preventDefault();
702            first.focus();
703          }
704        });
705      }
706
707      formEl = overlayEl.querySelector('form');
708      inputEl = overlayEl.querySelector('.ye-coupon-gate__input');
709      submitEl = overlayEl.querySelector('.ye-coupon-gate__submit');
710      errorEl = overlayEl.querySelector('.ye-coupon-gate__error');
711      return overlayEl;
712    };
713
714    const evaluateRoute = () => {
715      const url = new URL(window.location.href);
716      if (!isTargetCheckout(url)) {
717        setLocked(false);
718        stopWatchingCouponApply();
719        return;
720      }
721
722      if (couponAppliedSuccessfully()) {
723        setLocked(false);
724        stopWatchingCouponApply();
725      } else {
726        setLocked(true);
727        startWatchingCouponApply();
728      }
729    };
730
731    const init = () => {
732      evaluateRoute();
733    };
734
735    if (document.readyState === 'loading') {
736      document.addEventListener('DOMContentLoaded', init, { once: true });
737    } else {
738      init();
739    }
740
741    document.addEventListener('turbo:load', evaluateRoute);
742    document.addEventListener('turbo:frame-load', evaluateRoute);
743    window.addEventListener('popstate', evaluateRoute);
744  })();
745</script>
745
746<!--
747  Uscreen Support Snippet
748  Description: Content card metadata enhancement - adds author and tag information to Swiper content cards and playlist page cards with dynamic API fetching and Turbo navigation support
749  Added by: matt w
750  Date: 2026-04-29
751-->
752<script>
753(function () {
754var processed = new WeakSet();
755var timer = null;
756var tagCache = {};
757var permalinkCache = {};
758function fetchPermalink(contentId) {
759if (permalinkCache[contentId] !== undefined) return Promise.resolve(permalinkCache[contentId]);
760return fetch('/api/contents?id=' + contentId, {
761        credentials: 'same-origin',
762        headers: { 'Accept': 'application/json' }
763})
764.then(function (res) { return res.ok ? res.json() : null; })
765.then(function (json) {
766var item = Array.isArray(json) && json.length > 0 ? json[0] : null;
767var permalink = item && item.url ? item.url.replace('/programs/', '').split(/[?#]/)[0] : null;
768          permalinkCache[contentId] = permalink;
769return permalink;
770})
771.catch(function () {
772          permalinkCache[contentId] = null;
773return null;
774});
775}
776function fetchTags(permalink) {
777if (tagCache[permalink] !== undefined) return Promise.resolve(tagCache[permalink]);
778return fetch('/api/contents/' + encodeURIComponent(permalink), {
779        credentials: 'same-origin',
780        headers: { 'Accept': 'application/json' }
781})
782.then(function (res) { return res.ok ? res.json() : null; })
783.then(function (json) {
784var result = {
785            tags: json && Array.isArray(json.tags) ? json.tags : [],
786            author: json && json.author ? json.author.title : null
787};
788          tagCache[permalink] = result;
789return result;
790})
791.catch(function () {
792          tagCache[permalink] = { tags: [], author: null };
793return tagCache[permalink];
794});
795}
796function processCards() {
797var slides = document.querySelectorAll('swiper-slide[data-custom="content-card"]');
798      slides.forEach(function (slide) {
799if (processed.has(slide)) return;
800if (slide.querySelector('.us-card-info')) return;
801        processed.add(slide);
802var titleLink = slide.querySelector('.card-title');
803if (!titleLink) return;
804var wrapper = document.createElement('div');
805        wrapper.className = 'us-card-info';
806var author = slide.getAttribute('data-author-title-0');
807if (author) {
808var authorEl = document.createElement('p');
809          authorEl.className = 'us-custom-author';
810          authorEl.textContent = author;
811          wrapper.appendChild(authorEl);
812}
813        slide.insertBefore(wrapper, titleLink);
814        wrapper.appendChild(titleLink);
815var link = slide.querySelector('a[href^="/programs/"]');
816if (link) {
817var permalink = link.getAttribute('href').replace('/programs/', '').split(/[?#]/)[0];
818          fetchTags(permalink).then(function (result) {
819if (result.tags.length > 0 && !wrapper.querySelector('.us-custom-meta')) {
820var metaEl = document.createElement('p');
821              metaEl.className = 'us-custom-meta';
822              metaEl.textContent = result.tags.join('  |  ');
823              wrapper.appendChild(metaEl);
824}
825});
826}
827});
828}
829function processPlaylistCards() {
830var cards = document.querySelectorAll('div[data-test="playlist-card"]');
831      cards.forEach(function (card) {
832if (processed.has(card)) return;
833if (card.querySelector('.us-playlist-author')) return;
834        processed.add(card);
835var infoRow = card.querySelector('.flex.justify-between');
836if (!infoRow) return;
837// Pull the dropdown out of the flex row and pin it to the card corner
838var dropdown = infoRow.querySelector('ds-dropdown');
839if (dropdown) {
840          card.style.position = 'relative';
841          dropdown.style.position = 'absolute';
842          dropdown.style.top = '8px';
843          dropdown.style.right = '8px';
844          card.appendChild(dropdown);
845}
846var contentId = card.getAttribute('data-content-id');
847if (!contentId) return;
848        fetchPermalink(contentId).then(function (permalink) {
849if (!permalink) return;
850          fetchTags(permalink).then(function (result) {
851if (result.author && !card.querySelector('.us-playlist-author')) {
852var authorEl = document.createElement('p');
853              authorEl.className = 'us-playlist-author';
854              authorEl.textContent = result.author;
855              card.insertBefore(authorEl, infoRow);
856}
857if (result.tags.length > 0 && !card.querySelector('.us-playlist-meta')) {
858var metaEl = document.createElement('p');
859              metaEl.className = 'us-playlist-meta';
860              metaEl.textContent = result.tags.join('  |  ');
861              card.appendChild(metaEl);
862}
863});
864});
865});
866}
867function run() {
868      clearTimeout(timer);
869      timer = setTimeout(function () {
870        processCards();
871        processPlaylistCards();
872}, 150);
873}
874var observer = new MutationObserver(run);
875function init() {
876      observer.disconnect();
877      observer.observe(document.body, { childList: true, subtree: true });
878      processCards();
879      processPlaylistCards();
880}
881if (document.body) init();
882else document.addEventListener('DOMContentLoaded', init);
883    document.addEventListener('turbo:load', init);
884    document.addEventListener('turbo:frame-load', run);
885})();
886</script>
886
887<style>
888swiper-slide[data-custom="content-card"] {
889border-radius: 12px !important;
890overflow: hidden;
891background: #ffffff;
892box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
893}
894div[data-test="playlist-card"] {
895border-radius: 12px !important;
896background: #ffffff;
897box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
898padding: 0 0 10px 0;
899}
900.us-card-info {
901padding: 10px 12px 14px;
902background: #ffffff;
903}
904.us-custom-author {
905font-size: 0.85rem;
906color: #6b7280;
907margin: 0 0 2px 0;
908line-height: 1.4;
909white-space: nowrap;
910overflow: hidden;
911text-overflow: ellipsis;
912}
913.us-card-info .card-title {
914font-weight: 600 !important;
915display: block;
916padding: 0 !important;
917margin: 0 !important;
918}
919.us-custom-meta {
920font-size: 0.8rem;
921color: #9ca3af;
922margin: 6px 0 0 0;
923line-height: 1.4;
924white-space: nowrap;
925overflow: hidden;
926text-overflow: ellipsis;
927}
928.us-playlist-author {
929font-size: 0.85rem;
930color: #6b7280;
931margin: 4px 12px 2px;
932line-height: 1.4;
933white-space: nowrap;
934overflow: hidden;
935text-overflow: ellipsis;
936}
937div[data-test="playlist-card"] .card-title {
938font-weight: 600 !important;
939display: block;
940padding: 0 !important;
941margin: 0 !important;
942width: 100%;
943}
944div[data-test="playlist-card"] .flex.justify-between {
945display: block !important;
946padding: 0 12px;
947}
948.us-playlist-meta {
949font-size: 0.8rem;
950color: #9ca3af;
951margin: 4px 12px 0;
952line-height: 1.4;
953white-space: nowrap;
954overflow: hidden;
955text-overflow: ellipsis;
956}
957</style>
958<!-- end uscreen support snippet -->
959<style>
960  .uscr-program-tags {
961  margin-top: 6px;
962  margin-bottom: 0;
963  font-size: 1rem;
964  font-weight: 600;
965  color: #0e5c63;
966  opacity: 0.9;
967  line-height: 1.4;
968  }
969</style>
970<script>
971(function () {
972  'use strict';
973
974  var TAG_CACHE = {};
975  var TAG_EL_ID = 'uscr-program-tag-line';
976  var WRAPPER_ID = 'uscr-program-title-wrapper';
977  var TITLE_SELECTOR = '[data-area="program-title"], [data-area="collection-title"]';
978  var processedTitles = new WeakSet();
979  var timer = null;
980
981  function getPermalink() {
982    var match = window.location.pathname.match(/^\/programs\/([^/?#]+)/);
983    return match ? match[1] : null;
984  }
985
986  function fetchTags(permalink) {
987    if (TAG_CACHE[permalink] !== undefined) {
988      return Promise.resolve(TAG_CACHE[permalink]);
989    }
990    return fetch('/api/contents/' + encodeURIComponent(permalink), {
991      credentials: 'same-origin',
992      headers: { 'Accept': 'application/json' }
993    })
994      .then(function (res) { return res.ok ? res.json() : null; })
995      .then(function (json) {
996        var tags = json && Array.isArray(json.tags) ? json.tags : [];
997        TAG_CACHE[permalink] = tags;
998        return tags;
999      })
1000      .catch(function () {
1001        TAG_CACHE[permalink] = [];
1002        return [];
1003      });
1004  }
1005
1006  function processTitle() {
1007    var titleEl = document.querySelector(TITLE_SELECTOR);
1008    if (!titleEl) return;
1009    if (processedTitles.has(titleEl)) return;
1010    if (titleEl.parentNode && titleEl.parentNode.id === WRAPPER_ID) {
1011      processedTitles.add(titleEl);
1012      return;
1013    }
1014
1015    processedTitles.add(titleEl);
1016
1017    var permalink = getPermalink();
1018    if (!permalink) return;
1019
1020    // Only the program/collection-detail layout has the title as a flex child
1021    // next to the action bar. The collection landing page does NOT, so we skip
1022    // the wrapper there.
1023    var needsWrapping = titleEl.getAttribute('data-area') === 'program-title';
1024    var wrapper = null;
1025
1026    if (needsWrapping) {
1027      wrapper = document.createElement('div');
1028      wrapper.id = WRAPPER_ID;
1029      wrapper.className = 'flex-1 max-w-full lg:max-w-lg xl:max-w-2xl';
1030      titleEl.parentNode.insertBefore(wrapper, titleEl);
1031      wrapper.appendChild(titleEl);
1032    }
1033
1034    fetchTags(permalink).then(function (tags) {
1035      if (!tags || tags.length === 0) return;
1036      if (document.getElementById(TAG_EL_ID)) return;
1037      if (getPermalink() !== permalink) return;
1038      if (!document.body.contains(titleEl)) return;
1039
1040      var p = document.createElement('p');
1041      p.id = TAG_EL_ID;
1042      p.className = 'uscr-program-tags';
1043      p.textContent = tags.join('   |   ');
1044
1045      if (wrapper) {
1046        wrapper.appendChild(p);
1047      } else {
1048        titleEl.insertAdjacentElement('afterend', p);
1049      }
1050    });
1051  }
1052
1053  function run() {
1054    clearTimeout(timer);
1055    timer = setTimeout(processTitle, 100);
1056  }
1057
1058  var observer = new MutationObserver(run);
1059
1060  function init() {
1061    observer.disconnect();
1062    observer.observe(document.body, { childList: true, subtree: true });
1063    processTitle();
1064  }
1065
1066  if (document.body) init();
1067  else document.addEventListener('DOMContentLoaded', init);
1068  document.addEventListener('turbo:load', init);
1069  document.addEventListener('turbo:frame-load', run);
1070})();
1071</script>
1071
1072<!-- end uscreen support snippet -->
1073
1074<script src="https://5b8b666b9e33410b917df182e00403a0.js.ubembed.com" async></script>
1074
1075
1076<!-- Disable autoplay -->
1077<script>
1078   window.localStorage.setItem('AUTOPLAY', false)
1079</script>
1079
1080
1081
1082<script>
1083/*
1084########################################
1085# Replace the Filter placeholder terms below
1086########################################
1087*/
1088const newPlaceholderAuthor = "Teacher: All";
1089
1090/*
1091########################################
1092# Not recommended to change the code below
1093########################################
1094*/
1095
1096const updatePlaceholdersInterval = setInterval(() => {
1097    const authorSelect = document.getElementById('author_id');
1098    const categorySelect = document.getElementById('category_id');
1099
1100    let authorUpdated = false;
1101    let categoryUpdated = false;
1102
1103    if (authorSelect && authorSelect.placeholder !== newPlaceholderAuthor) {
1104        authorSelect.placeholder = newPlaceholderAuthor;
1105    }
1106    if (authorSelect && authorSelect.placeholder === newPlaceholderAuthor) {
1107        authorUpdated = true;
1108    }
1109
1110    if (categorySelect && categorySelect.placeholder !== newPlaceholderCategory) {
1111        categorySelect.placeholder = newPlaceholderCategory;
1112    }
1113    if (categorySelect && categorySelect.placeholder === newPlaceholderCategory) {
1114        categoryUpdated = true;
1115    }
1116
1117    if (authorUpdated && categoryUpdated) {
1118        clearInterval(updatePlaceholdersInterval);
1119    }
1120}, 500);
1121</script>
1121
1122  <!--
1123    Uscreen Support Snippet
1124    Description: Collection cards (.content-item) — boxed card + per-video author + tags
1125    Added by: matt w
1126    Date: 2026-06-01
1127  -->
1128  <style>
1129    .content-item {
1130      background: #ffffff;
1131      border-radius: 12px;
1132      overflow: hidden;
1133      box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
1134    }
1135    .content-item .content-item-video img {
1136      border-radius: 0 !important;
1137    }
1138    .content-item .content-item-title,
1139    .content-item .us-ci-author,
1140    .content-item .content-item-description,
1141    .content-item .us-ci-tags {
1142      padding-left: 12px;
1143      padding-right: 12px;
1144    }
1145    .content-item .content-item-title {
1146      margin-top: 10px !important;
1147      font-weight: 600 !important;
1148    }
1149    .content-item .us-ci-author {
1150      margin: 2px 0 0;
1151      font-size: 0.85rem;
1152      line-height: 1.4;
1153      color: #6b7280;
1154      white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
1155    }
1156    .content-item .content-item-description {
1157      margin-top: 4px;
1158    }
1159    .content-item .us-ci-tags {
1160      margin: 6px 0 0;
1161      padding-bottom: 14px;
1162      font-size: 0.8rem;
1163      line-height: 1.4;
1164      color: #9ca3af;
1165      white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
1166    }
1167  </style>
1168  
1168<script>
1169  (function () {
1170    'use strict';
1171
1172    var META_CACHE = {};
1173    var processed = new WeakSet();
1174    var timer = null;
1175
1176    function fetchMeta(permalink) {
1177      if (META_CACHE[permalink]) return META_CACHE[permalink];
1178      META_CACHE[permalink] = fetch('/api/contents/' + encodeURIComponent(permalink), {
1179        credentials: 'same-origin',
1180        headers: { 'Accept': 'application/json' }
1181      })
1182        .then(function (res) { return res.ok ? res.json() : null; })
1183        .then(function (json) {
1184          return {
1185            author: json && json.author && json.author.title ? json.author.title : null,
1186            tags: json && Array.isArray(json.tags) ? json.tags : []
1187          };
1188        })
1189        .catch(function () { return { author: null, tags: [] }; });
1190      return META_CACHE[permalink];
1191    }
1192
1193    function permalinkFor(card) {
1194      // Variant A — no whole-collection access: card opens a modal, permalink in a data attr
1195      var modal = card.getAttribute('data-playlist-modal-subject-permalink-param');
1196      if (modal) return modal;
1197      // Variant B — has access: permalink is the ?permalink= query param on the href
1198      try {
1199        var pl = new URL(card.href).searchParams.get('permalink');
1200        if (pl) return pl;
1201      } catch (e) {}
1202      // Last resort: the program slug in the path
1203      var m = (card.getAttribute('href') || '').match(/\/programs\/([^/?#]+)/);
1204      return m ? m[1] : null;
1205    }
1206
1207    function processCards() {
1208      document.querySelectorAll('.content-item').forEach(function (card) {
1209        if (processed.has(card)) return;
1210        processed.add(card);
1211
1212        var permalink = permalinkFor(card);
1213        if (!permalink) return;
1214
1215        fetchMeta(permalink).then(function (meta) {
1216          if (!card.isConnected) return;
1217          var title = card.querySelector('.content-item-title');
1218          var desc = card.querySelector('.content-item-description');
1219
1220          if (meta.author && title && !card.querySelector('.us-ci-author')) {
1221            var a = document.createElement('p');
1222            a.className = 'us-ci-author';
1223            a.textContent = meta.author;
1224            title.insertAdjacentElement('afterend', a);
1225          }
1226
1227          if (meta.tags.length && !card.querySelector('.us-ci-tags')) {
1228            var t = document.createElement('p');
1229            t.className = 'us-ci-tags';
1230            t.textContent = meta.tags.join('   |   ');
1231            (desc || title).insertAdjacentElement('afterend', t);
1232          }
1233        });
1234      });
1235    }
1236
1237    function run() { clearTimeout(timer); timer = setTimeout(processCards, 150); }
1238    var observer = new MutationObserver(run);
1239    function init() {
1240      observer.disconnect();
1241      observer.observe(document.body, { childList: true, subtree: true });
1242      processCards();
1243    }
1244    if (document.body) init();
1245    else document.addEventListener('DOMContentLoaded', init);
1246    document.addEventListener('turbo:load', init);
1247    document.addEventListener('turbo:frame-load', run);
1248  })();
1249  </script>
1249
1250  <!-- end uscreen support snippet -->
1251
1252
1253
1254<!-- Feature: YogaEasy calendar dynamic banner sync (Tag: calendar, page-builder, Turbo) -->
1255<style>
1256  /* Page Builder's global :root defaults must not turn the calendar blue. */
1257  .calendar-page {
1258    --primary: #009090;
1259    --primary-rgb: 0, 144, 144;
1260    --uscreen-primary: #009090;
1261  }
1262
1263  #ye-calendar-banner {
1264    width: 100%;
1265    position: relative;
1266    z-index: 1;
1267  }
1268
1269  #ye-calendar-banner [data-editor="section"] {
1270    width: 100%;
1271  }
1272
1273
1274</style>
1275<script>
1276  (() => {
1277    const FLAG = "__YE_CALENDAR_BANNER_SYNC__";
1278    if (window[FLAG]) return;
1279    window[FLAG] = true;
1280
1281    const SOURCE_PATH = "/pages/calendar-banner";
1282    const TARGET_PATH_RE = /^\/calendar\/agenda\/?$/;
1283    const TARGET_SELECTOR = ".calendar-page";
1284    const WRAPPER_ID = "ye-calendar-banner";
1285    const STYLE_MARKER = "data-ye-calendar-banner-source-style";
1286
1287    let observer = null;
1288    let debounceTimer = null;
1289    let pendingBannerFetch = null;
1290    let routeRunId = 0;
1291    let resolvedTarget = null;
1292    const stylesheetCache = new Map();
1293
1294    const isTargetRoute = () => TARGET_PATH_RE.test(window.location.pathname);
1295
1296    const removeBanner = () => {
1297      const existing = document.getElementById(WRAPPER_ID);
1298      if (existing) existing.remove();
1299      resolvedTarget = null;
1300    };
1301
1302    const disconnectObserver = () => {
1303      if (observer) {
1304        observer.disconnect();
1305        observer = null;
1306      }
1307      if (debounceTimer) {
1308        window.clearTimeout(debounceTimer);
1309        debounceTimer = null;
1310      }
1311    };
1312
1313    const scopeStyles = (css) => {
1314      const sheet = new CSSStyleSheet();
1315      sheet.replaceSync(css);
1316      const serialize = (rules) => Array.from(rules).map((rule) => {
1317        if (rule.type === CSSRule.STYLE_RULE) {
1318          // The storefront has an !important heading-font override. Within
1319          // this banner, the Page Builder's selected font takes precedence.
1320          if (/\.(heading|body)_font_family/.test(rule.selectorText)) {
1321            const family = rule.style.getPropertyValue("font-family");
1322            if (family) rule.style.setProperty("font-family", `${family}, sans-serif`, "important");
1323          }
1324          return `#${WRAPPER_ID} :is(${rule.selectorText}) { ${rule.style.cssText} }`;
1325        }
1326        if (rule.type === CSSRule.MEDIA_RULE || rule.type === CSSRule.SUPPORTS_RULE) {
1327          const group = rule.type === CSSRule.MEDIA_RULE ? "media" : "supports";
1328          return `@${group} ${rule.conditionText} { ${serialize(rule.cssRules)} }`;
1329        }
1330        return "";
1331      }).join("\n");
1332      return serialize(sheet.cssRules);
1333    };
1334
1335    const sourceStyles = async (sourceDoc) => {
1336      const links = Array.from(sourceDoc.querySelectorAll('link[rel="stylesheet"]'));
1337      const builder = links.find((link) => /\/page_builder-[^/]+\.css/.test(link.href));
1338      let css = "";
1339      if (builder) {
1340        if (!stylesheetCache.has(builder.href)) {
1341          stylesheetCache.set(builder.href, fetch(builder.href).then((response) => {
1342            if (!response.ok) throw new Error(`Banner stylesheet returned ${response.status}`);
1343            return response.text();
1344          }).catch((error) => {
1345            stylesheetCache.delete(builder.href);
1346            throw error;
1347          }));
1348        }
1349        css = await stylesheetCache.get(builder.href);
1350      }
1351      sourceDoc.querySelectorAll(
1352        "style#card_border_radius, style#button_border_radius, style#heading_font_family, style#body_font_family",
1353      ).forEach((style) => { css += `\n${style.textContent}`; });
1354      // Page Builder normally asks WebFont to load these configured families.
1355      // Read the data without executing the source page's scripts.
1356      const families = new Set();
1357      sourceDoc.querySelectorAll("script:not([src])").forEach((script) => {
1358        for (const match of script.textContent.matchAll(/window\.(?:body|heading)_font_family\s*=\s*['"]([^'"]+)['"]/g)) {
1359          families.add(match[1]);
1360        }
1361      });
1362      const fonts = links.filter((link) => new URL(link.href).hostname === "fonts.googleapis.com")
1363        .map((link) => link.href);
1364      if (families.size) {
1365        fonts.push(`https://fonts.googleapis.com/css?family=${encodeURIComponent(Array.from(families).join("|"))}&display=swap`);
1366      }
1367      return {
1368        css: scopeStyles(css),
1369        fonts,
1370      };
1371    };
1372
1373    const promoteLazyImages = (root) => {
1374      root.querySelectorAll("a[href]").forEach((link) => {
1375        // Preserve the editor's URL (including query/hash) and new-tab choice.
1376        if (!link.target || link.target === "_self") link.target = "_top";
1377        link.setAttribute("data-turbo-frame", "_top");
1378      });
1379      root.querySelectorAll("[data-srcset], img[data-src]").forEach((image) => {
1380        for (const name of ["srcset", "src"]) {
1381          const value = image.getAttribute(`data-${name}`);
1382          if (value) {
1383            image.setAttribute(name, value);
1384            image.removeAttribute(`data-${name}`);
1385          }
1386        }
1387      });
1388      root.querySelectorAll(".lazy-loaded_preview, [data-controller~='lazy-loaded']").forEach((image) => {
1389        image.classList.remove("lazy-loaded_preview", "lazy-loaded_loaded");
1390        const controllers = (image.getAttribute("data-controller") || "")
1391          .split(/\s+/).filter((name) => name && name !== "lazy-loaded");
1392        if (controllers.length) image.setAttribute("data-controller", controllers.join(" "));
1393        else image.removeAttribute("data-controller");
1394      });
1395    };
1396
1397    const extractBannerHtml = async (html) => {
1398      const sourceDoc = new DOMParser().parseFromString(html, "text/html");
1399      // Native per-page Settings > General > Head Code Snippet > Active is
1400      // the calendar-copy switch. It does not unpublish the source page.
1401      const enabled = Array.from(sourceDoc.scripts).some((script) => script.textContent.includes(FLAG));
1402      if (!enabled) return null;
1403
1404      const section =
1405        sourceDoc.querySelector("body > [data-editor='section']") ||
1406        sourceDoc.querySelector("main [data-editor='section']") ||
1407        sourceDoc.querySelector("[data-editor='section']");
1408
1409      if (!section) return null;
1410
1411      const clone = section.cloneNode(true);
1412      clone.querySelectorAll("script").forEach((script) => script.remove());
1413      return { html: clone.outerHTML, ...await sourceStyles(sourceDoc) };
1414    };
1415
1416    const fetchBannerHtml = () => {
1417      if (pendingBannerFetch) return pendingBannerFetch;
1418
1419      pendingBannerFetch = fetch(SOURCE_PATH, {
1420        credentials: "same-origin",
1421        cache: "no-store",
1422        headers: { Accept: "text/html" },
1423      })
1424        .then((response) => {
1425          if (!response.ok) {
1426            throw new Error(`Banner page returned ${response.status}`);
1427          }
1428          return response.text();
1429        })
1430        .then(extractBannerHtml)
1431        .finally(() => {
1432          pendingBannerFetch = null;
1433        });
1434
1435      return pendingBannerFetch;
1436    };
1437
1438    const injectBanner = async () => {
1439      const runId = ++routeRunId;
1440
1441      if (!isTargetRoute()) {
1442        removeBanner();
1443        disconnectObserver();
1444        return;
1445      }
1446
1447      const target = document.querySelector(TARGET_SELECTOR);
1448      if (!target) return;
1449
1450      const existing = document.getElementById(WRAPPER_ID);
1451      if (existing && existing.nextElementSibling === target) {
1452        return;
1453      }
1454      if (!existing && resolvedTarget === target) return;
1455      if (existing) existing.remove();
1456
1457      try {
1458        const bannerHtml = await fetchBannerHtml();
1459        if (runId !== routeRunId || !isTargetRoute()) return;
1460        resolvedTarget = target;
1461        if (!bannerHtml) return;
1462
1463        const currentTarget = document.querySelector(TARGET_SELECTOR);
1464        if (!currentTarget) return;
1465
1466        const wrapper = document.createElement("div");
1467        wrapper.id = WRAPPER_ID;
1468        wrapper.setAttribute("data-ye-calendar-banner", "");
1469        const styles = document.createElement("style");
1470        styles.setAttribute(STYLE_MARKER, "");
1471        styles.textContent = bannerHtml.css;
1472        wrapper.appendChild(styles);
1473        bannerHtml.fonts.forEach((href) => {
1474          const font = document.createElement("link");
1475          font.rel = "stylesheet";
1476          font.href = href;
1477          wrapper.appendChild(font);
1478        });
1479        wrapper.insertAdjacentHTML("beforeend", bannerHtml.html);
1480        promoteLazyImages(wrapper);
1481        currentTarget.insertAdjacentElement("beforebegin", wrapper);
1482      } catch (error) {
1483        console.warn("[YogaEasy] Calendar banner injection failed", error);
1484      }
1485    };
1486
1487    const scheduleInject = () => {
1488      if (debounceTimer) window.clearTimeout(debounceTimer);
1489      debounceTimer = window.setTimeout(injectBanner, 80);
1490    };
1491
1492    const ensureObserver = () => {
1493      if (observer || !document.body) return;
1494      observer = new MutationObserver(scheduleInject);
1495      observer.observe(document.body, { childList: true, subtree: true });
1496    };
1497
1498    const boot = () => {
1499      if (isTargetRoute()) {
1500        ensureObserver();
1501        scheduleInject();
1502      } else {
1503        removeBanner();
1504        disconnectObserver();
1505      }
1506    };
1507
1508    if (document.readyState === "loading") {
1509      document.addEventListener("DOMContentLoaded", boot, { once: true });
1510    } else {
1511      boot();
1512    }
1513
1514    document.addEventListener("turbo:load", boot);
1515    document.addEventListener("turbo:render", boot);
1516    document.addEventListener("turbo:frame-load", boot);
1517    document.addEventListener("turbo:before-cache", () => {
1518      ++routeRunId;
1519      disconnectObserver();
1520      removeBanner();
1521    });
1522    window.addEventListener("popstate", boot);
1523  })();
1524</script>
1524
1525
1526<!--
1527    Feature: YogaEasy content card metadata enhancement (Tag: catalog, card-style)
1528    Purpose: Show level/style (from API `tags`) as a meta line under each catalog card.
1529  -->
1530<script>
1531  (function () {
1532    var processed = new WeakSet();
1533    var timer = null;
1534    var tagCache = {};
1535
1536    function fetchTags(permalink) {
1537      if (tagCache[permalink] !== undefined) {
1538        return Promise.resolve(tagCache[permalink]);
1539      }
1540      return fetch("/api/contents/" + encodeURIComponent(permalink), {
1541        credentials: "same-origin",
1542        headers: { Accept: "application/json" },
1543      })
1544        .then(function (res) {
1545          return res.ok ? res.json() : null;
1546        })
1547        .then(function (json) {
1548          var tags = json && Array.isArray(json.tags) ? json.tags : [];
1549          tagCache[permalink] = tags;
1550          return tags;
1551        })
1552        .catch(function () {
1553          tagCache[permalink] = [];
1554          return [];
1555        });
1556    }
1557
1558    function processCards() {
1559      var slides = document.querySelectorAll(
1560        'swiper-slide[data-custom="content-card"]',
1561      );
1562
1563      slides.forEach(function (slide) {
1564        if (processed.has(slide)) return;
1565        if (slide.querySelector(".us-card-info")) return;
1566        processed.add(slide);
1567
1568        var titleLink = slide.querySelector(".card-title");
1569        if (!titleLink) return;
1570
1571        var wrapper = document.createElement("div");
1572        wrapper.className = "us-card-info";
1573        slide.insertBefore(wrapper, titleLink);
1574        wrapper.appendChild(titleLink);
1575
1576        var link = slide.querySelector('a[href^="/programs/"]');
1577        if (!link) return;
1578
1579        var permalink = link
1580          .getAttribute("href")
1581          .replace("/programs/", "")
1582          .split(/[?#]/)[0];
1583
1584        fetchTags(permalink).then(function (tags) {
1585          if (!tags.length || wrapper.querySelector(".us-custom-meta")) return;
1586          var metaEl = document.createElement("p");
1587          metaEl.className = "us-custom-meta";
1588          metaEl.textContent = tags.join("  |  ");
1589          wrapper.appendChild(metaEl);
1590        });
1591      });
1592    }
1593
1594    function run() {
1595      clearTimeout(timer);
1596      timer = setTimeout(processCards, 150);
1597    }
1598    var observer = new MutationObserver(run);
1599    function init() {
1600      observer.disconnect();
1601      observer.observe(document.body, { childList: true, subtree: true });
1602      processCards();
1603    }
1604    if (document.body) init();
1605    else document.addEventListener("DOMContentLoaded", init);
1606    document.addEventListener("turbo:load", init);
1607    document.addEventListener("turbo:frame-load", run);
1608  })();
1609</script>
1609
1610
1611<style>
1612  swiper-slide[data-custom="content-card"] {
1613    border-radius: 12px !important;
1614    overflow: hidden;
1615    background: #ffffff;
1616    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
1617  }
1618
1619  .us-card-info {
1620    padding: 10px 12px 14px;
1621    background: #ffffff;
1622  }
1623
1624  .us-card-info .card-title {
1625    display: block;
1626    padding: 0 !important;
1627    margin: 0 !important;
1628    font-weight: 600 !important;
1629  }
1630
1631  .us-custom-meta {
1632    margin: 6px 0 0;
1633    font-size: 0.8rem;
1634    line-height: 1.4;
1635    color: #9ca3af;
1636    white-space: nowrap;
1637    overflow: hidden;
1638    text-overflow: ellipsis;
1639  }
1640</style>
1641
1642<script>
1643  /*
1644  ########################################
1645  # Replace the Filter placeholder terms below
1646  ########################################
1647  */
1648  const newPlaceholderAuthor = "Lehrer:innen: Alle";
1649  /*
1650  ########################################
1651  # Not recommended to change the code below
1652  ########################################
1653  */
1654
1655  (function () {
1656    let attempts = 0;
1657    const maxAttempts = 60; // 60 * 500ms = 30s total
1658
1659    const interval = setInterval(() => {
1660      attempts += 1;
1661
1662      const authorSelect = document.getElementById("author_id");
1663      if (authorSelect && authorSelect.placeholder !== newPlaceholderAuthor) {
1664        authorSelect.placeholder = newPlaceholderAuthor;
1665      }
1666
1667      if (
1668        (authorSelect && authorSelect.placeholder === newPlaceholderAuthor) ||
1669        attempts >= maxAttempts
1670      ) {
1671        clearInterval(interval);
1672      }
1673    }, 500);
1674  })();
1675</script>
1675
1676
1677<!-- Disable autoplay -->
1678<script>
1679  window.localStorage.setItem("AUTOPLAY", false);
1680</script>
1680
1681
1682<script
1683  src="https://5b8b666b9e33410b917df182e00403a0.js.ubembed.com"
1684  async
1685></script>
1685
1686<!--
1687  Feature: YogaEasy content card metadata enhancement
1688  Ported from: studio.yogaeasy.com
1689  Purpose: Add author/tag metadata and boxed card treatment on Swiper content cards.
1690-->
1691<script>
1692  (function () {
1693    var processed = new WeakSet();
1694    var timer = null;
1695    var tagCache = {};
1696
1697    function fetchTags(permalink) {
1698      if (tagCache[permalink] !== undefined) {
1699        return Promise.resolve(tagCache[permalink]);
1700      }
1701      return fetch("/api/contents/" + encodeURIComponent(permalink), {
1702        credentials: "same-origin",
1703        headers: { Accept: "application/json" },
1704      })
1705        .then(function (res) {
1706          return res.ok ? res.json() : null;
1707        })
1708        .then(function (json) {
1709          var tags = json && Array.isArray(json.tags) ? json.tags : [];
1710          tagCache[permalink] = tags;
1711          return tags;
1712        })
1713        .catch(function () {
1714          tagCache[permalink] = [];
1715          return [];
1716        });
1717    }
1718
1719    function processCards() {
1720      var slides = document.querySelectorAll(
1721        'swiper-slide[data-custom="content-card"]',
1722      );
1723      slides.forEach(function (slide) {
1724        if (processed.has(slide)) return;
1725        processed.add(sli
1725de);
1726
1727        var titleLink = slide.querySelector(".card-title");
1728        if (!titleLink) return;
1729
1730        // Get or create the wrapper
1731        var wrapper = slide.querySelector(".us-card-info");
1732        if (!wrapper) {
1733          wrapper = document.createElement("div");
1734          wrapper.className = "us-card-info";
1735          slide.insertBefore(wrapper, titleLink);
1736          wrapper.appendChild(titleLink);
1737        }
1738
1739        // Add author if present and not already rendered
1740        if (!wrapper.querySelector(".us-custom-author")) {
1741          var author = slide.getAttribute("data-author-title-0");
1742          if (author) {
1743            var authorEl = document.createElement("p");
1744            authorEl.className = "us-custom-author";
1745            authorEl.textContent = author;
1746            wrapper.insertBefore(authorEl, wrapper.firstChild);
1747          }
1748        }
1749
1750        // Fetch and add tags if not already rendered
1751        if (!wrapper.querySelector(".us-custom-meta")) {
1752          var link = slide.querySelector('a[href^="/programs/"]');
1753          if (!link) return;
1754          var permalink = link
1755            .getAttribute("href")
1756            .replace("/programs/", "")
1757            .split(/[?#]/)[0];
1758          fetchTags(permalink).then(function (tags) {
1759            if (!tags.length || wrapper.querySelector(".us-custom-meta"))
1760              return;
1761            var metaEl = document.createElement("p");
1762            metaEl.className = "us-custom-meta";
1763            metaEl.textContent = tags.join("  |  ");
1764            wrapper.appendChild(metaEl);
1765          });
1766        }
1767      });
1768    }
1769
1770    function run() {
1771      clearTimeout(timer);
1772      timer = setTimeout(processCards, 150);
1773    }
1774
1775    var observer = new MutationObserver(run);
1776
1777    function init() {
1778      observer.disconnect();
1779      observer.observe(document.body, { childList: true, subtree: true });
1780      processCards();
1781    }
1782
1783    if (document.body) {
1784      init();
1785    } else {
1786      document.addEventListener("DOMContentLoaded", init);
1787    }
1788    document.addEventListener("turbo:load", init);
1789    document.addEventListener("turbo:frame-load", run);
1790  })();
1791</script>
1791
1792
1793<style>
1794  swiper-slide[data-custom="content-card"] {
1795    border-radius: 12px !important;
1796    overflow: hidden;
1797    background: #ffffff;
1798    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
1799  }
1800  .us-card-info {
1801    padding: 10px 12px 14px;
1802    background: #ffffff;
1803  }
1804  .us-custom-author {
1805    margin: 0 0 2px;
1806    font-size: 0.85rem;
1807    line-height: 1.4;
1808    color: #6b7280;
1809    white-space: nowrap;
1810    overflow: hidden;
1811    text-overflow: ellipsis;
1812  }
1813  .us-card-info .card-title {
1814    display: block;
1815    padding: 0 !important;
1816    margin: 0 !important;
1817    font-weight: 600 !important;
1818  }
1819  .us-custom-meta {
1820    margin: 6px 0 0;
1821    font-size: 0.8rem;
1822    line-height: 1.4;
1823    color: #9ca3af;
1824    white-space: nowrap;
1825    overflow: hidden;
1826    text-overflow: ellipsis;
1827  }
1828</style>
1829<!--
1830    Uscreen Support Snippet
1831    Description: Collection cards (.content-item) — boxed card + per-video author + tags
1832    Added by: matt w
1833    Date: 2026-06-01
1834  -->
1835<style>
1836  .content-item {
1837    background: #ffffff;
1838    border-radius: 12px;
1839    overflow: hidden;
1840    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
1841  }
1842  /* thumbnail flush to the top; the card's rounding clips its corners */
1843  .content-item .content-item-video img {
1844    border-radius: 0 !important;
1845  }
1846  /* pad the text inset from the card edges (image stays full-bleed) */
1847  .content-item .content-item-title,
1848  .content-item .us-ci-author,
1849  .content-item .content-item-description,
1850  .content-item .us-ci-tags {
1851    padding-left: 12px;
1852    padding-right: 12px;
1853  }
1854  .content-item .content-item-title {
1855    margin-top: 10px !important;
1856    font-weight: 600 !important;
1857  }
1858  .content-item .us-ci-author {
1859    margin: 2px 0 0;
1860    font-size: 0.85rem;
1861    line-height: 1.4;
1862    color: #6b7280;
1863    white-space: nowrap;
1864    overflow: hidden;
1865    text-overflow: ellipsis;
1866  }
1867  .content-item .content-item-description {
1868    margin-top: 4px;
1869  }
1870  .content-item .us-ci-tags {
1871    margin: 6px 0 0;
1872    padding-bottom: 14px;
1873    font-size: 0.8rem;
1874    line-height: 1.4;
1875    color: #9ca3af;
1876    white-space: nowrap;
1877    overflow: hidden;
1878    text-overflow: ellipsis;
1879  }
1880</style>
1881<script>
1882  (function () {
1883    "use strict";
1884
1885    var META_CACHE = {};
1886    var processed = new WeakSet();
1887    var timer = null;
1888
1889    function fetchMeta(permalink) {
1890      if (META_CACHE[permalink]) return META_CACHE[permalink];
1891      META_CACHE[permalink] = fetch(
1892        "/api/contents/" + encodeURIComponent(permalink),
1893        {
1894          credentials: "same-origin",
1895          headers: { Accept: "application/json" },
1896        },
1897      )
1898        .then(function (res) {
1899          return res.ok ? res.json() : null;
1900        })
1901        .then(function (json) {
1902          return {
1903            author:
1904              json && json.author && json.author.title
1905                ? json.author.title
1906                : null,
1907            tags: json && Array.isArray(json.tags) ? json.tags : [],
1908          };
1909        })
1910        .catch(function () {
1911          return { author: null, tags: [] };
1912        });
1913      return META_CACHE[permalink];
1914    }
1915
1916    function permalinkFor(card) {
1917      try {
1918        var pl = new URL(card.href).searchParams.get("permalink");
1919        if (pl) return pl;
1920      } catch (e) {}
1921      var m = (card.getAttribute("href") || "").match(/\/programs\/([^/?#]+)/);
1922      return m ? m[1] : null;
1923    }
1924
1925    function processCards() {
1926      document
1927        .querySelectorAll('a.content-item[href^="/programs/"]')
1928        .forEach(function (card) {
1929          if (processed.has(card)) return;
1930          processed.add(card);
1931
1932          var permalink = permalinkFor(card);
1933          if (!permalink) return;
1934
1935          fetchMeta(permalink).then(function (meta) {
1936            if (!card.isConnected) return;
1937            var title = card.querySelector(".content-item-title");
1938            var desc = card.querySelector(".content-item-description");
1939
1940            // Author — directly below the title
1941            if (meta.author && title && !card.querySelector(".us-ci-author")) {
1942              var a = document.createElement("p");
1943              a.className = "us-ci-author";
1944              a.textContent = meta.author;
1945              title.insertAdjacentElement("afterend", a);
1946            }
1947
1948            // Tags — at the bottom of the card
1949            if (meta.tags.length && !card.querySelector(".us-ci-tags")) {
1950              var t = document.createElement("p");
1951              t.className = "us-ci-tags";
1952              t.textContent = meta.tags.join("   |   ");
1953              (desc || title).insertAdjacentElement("afterend", t);
1954            }
1955          });
1956        });
1957    }
1958
1959    function run() {
1960      clearTimeout(timer);
1961      timer = setTimeout(processCards, 150);
1962    }
1963    var observer = new MutationObserver(run);
1964    function init() {
1965      observer.disconnect();
1966      observer.observe(document.body, { childList: true, subtree: true });
1967      processCards();
1968    }
1969    if (document.body) init();
1970    else document.addEventListener("DOMContentLoaded", init);
1971    document.addEventListener("turbo:load", init);
1972    document.addEventListener("turbo:frame-load", run);
1973  })();
1974</script>
1974
1975<!-- end uscreen support snippet -->
1976
1977  </head>
1978  <body
1979    dir="ltr"
1980    class="light themeless group/body min-h-screen flex flex-col catalog-constrained"
1981  >
1982    <turbo-frame id="website_modal"></turbo-frame>    <div id="flash_messages">
1983</div>
1984
1985      <div class="sticky top-0 z-[100]">
1986
1987
1988
1989        
1990 
1991        
1992        <header id="website-header"
1993  class="sticky top-0 z-[100] flex bg-ds-main h-20 border-b border-ds-default"
1994  data-controller="themeless--header"
1995>
1996  <div class="container flex justify-between items-center my-auto">
1997    <div class="flex justify-start w-[8.75rem] flex-none">
1998      <a class="max-w-36 me-auto text-sm md:text-base text-ds-default" id="store-logo" data-type="main_logo" href="/">
1999          <img alt="yogaeasy.de" src="https://alpha.uscreencdn.com/images/logotypes/114649/logo_rgb.1775111741.png" />
2000</a>    </div>
2001
2002    <nav id="website-links" class="h-full min-w-0 mx-auto hidden md:flex justify-center -mb-px" data-themeless--header-target="navigation">
2003      <ul class="h-full flex justify-start space-x-4 invisible" data-themeless--header-target="navigationLinks">
2004
2005          <li class="relative group/item">
2006            <a class="flex items-center min-w-max overflow-y-hidden text-center px-4 pt-8 pb-7 h-full border-b border-b-4 hover:text-primary font-medium border-transparent text-ds-default" target="_self" data-type="home" href="/"><span class="flex items-center"><span>Videos</span></span></a>
2007          </li>
2008
2009          <li class="relative group/item">
2010            <a class="flex items-center min-w-max overflow-y-hidden text-center px-4 pt-8 pb-7 h-full border-b border-b-4 hover:text-primary font-medium border-transparent text-ds-default" target="_self" href="https://studio.yogaeasy.de/categories/programme"><span class="flex items-center"><span>Programme</span></span></a>
2011          </li>
2012
2013          <li class="relative group/item">
2014            <a class="flex items-center min-w-max overflow-y-hidden text-center px-4 pt-8 pb-7 h-full border-b border-b-4 hover:text-primary font-medium border-primary text-primary" target="_self" data-type="calendar" href="/calendar"><span class="flex items-center"><span>Kalender</span></span></a>
2015          </li>
2016
2017          <li class="relative group/item">
2018            <a class="flex items-center min-w-max overflow-y-hidden text-center px-4 pt-8 pb-7 h-full border-b border-b-4 hover:text-primary font-medium border-transparent text-ds-default" target="_self" href="/pages/yogalehrer"><span class="flex items-center"><span>Lehrer:innen</span></span></a>
2019          </li>
2020
2021          <li class="relative group/item">
2022            <a class="flex items-center min-w-max overflow-y-hidden text-center px-4 pt-8 pb-7 h-full border-b border-b-4 hover:text-primary font-medium border-transparent text-ds-default" target="_blank" href="https://www.yogaeasy.de/magazin"><span class="flex items-center"><span>Magazin</span></span></a>
2023          </li>
2024
2025          <li class="relative group/item">
2026            <a class="flex items-center min-w-max overflow-y-hidden text-center px-4 pt-8 pb-7 h-full border-b border-b-4 hover:text-primary font-medium border-transparent text-ds-default" target="_self" href="https://studio.yogaeasy.de/categories/academy"><span class="flex items-center"><span>Academy</span></span></a>
2027          </li>
2028
2029          <li class="relative group/item">
2030            <a class="flex items-center min-w-max overflow-y-hidden text-center px-4 pt-8 pb-7 h-full border-b border-b-4 hover:text-primary font-medium border-transparent text-ds-default" target="_blank" href="https://shop.yogaeasy.com/?_gl=1*gi6jl5*_gcl_aw*R0NMLjE3NzQ0MzcyMzguQ2owS0NRandqNDdPQmhDbUFSSXNBRjV3VUVHbFBROENjQkJwWFJKTTgwMkkxOEFMNWU5T2hpbTBDdmZKMzJjNWNFRmJPQ193MHNyb3JmWWFBb3dkRUFMd193Y0I.*_gcl_au*MTQ5NjU1OTgyMi4xNzczMjE3NTc3"><span class="flex items-center"><span>Shop</span></span></a>
2031          </li>
2032      </ul>
2033    </nav>
2034
2035    <div class="flex gap-x-2 items-center justify-end relative flex-none">
2036
2037
2038      <ds-button style="--font-size: var(--font-size-4-5)" class="hidden lg:block" size="big" variant="regular" href="/sign_in">Anmelden</ds-button>
2039          <ds-button style="--font-size: var(--font-size-4-5)" size="big" variant="primary" href="/join">Beitreten</ds-button>
2040
2041    <div class="relative flex items-center">
2042      <input type="checkbox" id="menu-toggle" class="peer hidden" data-themeless--header-target="toggle" data-action="change->themeless--header#onMenuToggle">
2043      <label for="menu-toggle" class="overlay hidden peer-checked:block fixed inset-0 "></label>
2044      <label for="menu-toggle" class="cursor-pointer flex items-center justify-center p-2 rounded bg-ds-subtle hover:opacity-80 lg:hidden w-12"
2045        data-themeless--header-target="toggleBurger"
2046      >
2047        <ds-icon class="text-ds-default block p-1" name="burger" size="24"></ds-icon>
2048        <ds-icon class="text-ds-default hidden p-1" name="cross" size="24"></ds-icon>
2049      </label>
2050
2051      <div id="main-menu" class="invisible" data-themeless--header-target="menu">
2052        <div class="overflow-hidden relative box-border h-full flex w-full">
2053          <nav class="h-auto max-h-full w-full min-h-0 overflow-y-auto px-4 py-2 border-ds-default" data-themeless--header-target="menuNavigation">
2054            <ul class="flex flex-col space-y-1">
2055                <li class="text-base md:text-sm font-normal leading-tight md:leading-none">
2056                  <a class="block py-2 h-10 md:h-8 hover:underline" href="/sign_in">Anmelden</a>
2057                </li>
2058                <li class="text-base md:text-sm font-normal leading-tight md:leading-none">
2059                  <a class="block py-2 min-h-10 md:min-h-8 hover:underline underline-offset-2" target="_self" data-type="home" href="/"><span class="flex items-center justify-items-stretch"><span>Videos</span></span></a>
2060                </li>
2061                <li class="text-base md:text-sm font-normal leading-tight md:leading-none">
2062                  <a class="block py-2 min-h-10 md:min-h-8 hover:underline underline-offset-2" target="_self" href="https://studio.yogaeasy.de/categories/programme"><span class="flex items-center justify-items-stretch"><span>Programme</span></span></a>
2063                </li>
2064                <li class="text-base md:text-sm font-normal leading-tight md:leading-none">
2065                  <a class="block py-2 min-h-10 md:min-h-8 hover:underline underline-offset-2 underline" target="_self" data-type="calendar" href="/calendar"><span class="flex items-center justify-items-stretch"><span>Kalender</span></span></a>
2066                </li>
2067                <li class="text-base md:text-sm font-normal leading-tight md:leading-none">
2068                  <a class="block py-2 min-h-10 md:min-h-8 hover:underline underline-offset-2" target="_self" href="/pages/yogalehrer"><span class="flex items-center justify-items-stretch"><span>Lehrer:innen</span></span></a>
2069                </li>
2070                <li class="text-base md:text-sm font-normal leading-tight md:leading-none">
2071                  <a class="block py-2 min-h-10 md:min-h-8 hover:underline underline-offset-2" target="_blank" href="https://www.yogaeasy.de/magazin"><span class="flex items-center justify-items-stretch"><span>Magazin</span></span></a>
2072                </li>
2073                <li class="text-base md:text-sm font-normal leading-tight md:leading-none">
2074                  <a class="block py-2 min-h-10 md:min-h-8 hover:underline underline-offset-2" target="_self" href="https://studio.yogaeasy.de/categories/academy"><span class="flex items-center justify-items-stretch"><span>Academy</span></span></a>
2075                </li>
2076                <li class="text-base md:text-sm font-normal leading-tight md:leading-none">
2077                  <a class="block py-2 min-h-10 md:min-h-8 hover:underline underline-offset-2" target="_blank" href="https://shop.yogaeasy.com/?_gl=1*gi6jl5*_gcl_aw*R0NMLjE3NzQ0MzcyMzguQ2owS0NRandqNDdPQmhDbUFSSXNBRjV3VUVHbFBROENjQkJwWFJKTTgwMkkxOEFMNWU5T2hpbTBDdmZKMzJjNWNFRmJPQ193MHNyb3JmWWFBb3dkRUFMd193Y0I.*_gcl_au*MTQ5NjU1OTgyMi4xNzczMjE3NTc3"><span class="flex items-center justify-items-stretch"><span>Shop</span></span></a>
2078                </li>
2079              <ds-viewport data-action="change->themeless--header#onScrollAnchorChange">
2080                <div class="w-full h-[1px]"></div>
2081              </ds-viewport>
2082            </ul>
2083          </nav>
2084          <div aria-hidden="true" class="absolute top-0 left-0 right-0 bottom-0 pointer-events-none opacity-1 translate-y-0 aria-hidden:translate-y-10 aria-hidden:opacity-0 transition-all" style="box-shadow: 0px -60px 30px -32px var(--ds-bg-overlay) inset;" data-themeless--header-target="menuNavigationScrollShadow"></div>
2085        </div>
2086        <div class="p-4 border-ds-default border-t bg-ds-overlay text-xs font-normal">
2087          <div class="flex flex-wrap gap-y-2">
2088              <a class="block w-full mb-2 text-primary hover:underline underline-offset-2" data-turbo="true" data-turbo-frame="website_modal" href="/about/apps">App holen -&gt;</a>
2089              <a class="text-ds-muted text-sm md:text-[11px]" href="/terms">
2090                <span class="hover:underline underline-offset-2">AGB</span>
2091</a>              <span class="flex items-center font-medium mx-1 last:hidden">∙</span>
2092              <a class="text-ds-muted text-sm md:text-[11px]" href="/privacy">
2093                <span class="hover:underline underline-offset-2">Datenschutz</span>
2094</a>              <span class="flex items-center font-medium mx-1 last:hidden">∙</span>
2095              <a class="text-ds-muted text-sm md:text-[11px]" href="/pages/impressum">
2096                <span class="hover:underline underline-offset-2">Impressum</span>
2097</a>
2097              <span class="flex items-center font-medium mx-1 last:hidden">∙</span>
2098              <a class="text-ds-muted text-sm md:text-[11px]" href="https://yogaeasy.jobs.personio.de/?language=de">
2099                <span class="hover:underline underline-offset-2">Jobs</span>
2100</a>              <span class="flex items-center font-medium mx-1 last:hidden">∙</span>
2101              <a class="text-ds-muted text-sm md:text-[11px]" href="https://portal.yogaeasy.de/cancel">
2102                <span class="hover:underline underline-offset-2">Verträge hier kündigen</span>
2103</a>              <span class="flex items-center font-medium mx-1 last:hidden">∙</span>
2104              <a class="text-ds-muted text-sm md:text-[11px]" href="/pages/faq">
2105                <span class="hover:underline underline-offset-2">Fragen und Antworten</span>
2106</a>              <span class="flex items-center font-medium mx-1 last:hidden">∙</span>
2107              <a class="text-ds-muted text-sm md:text-[11px]" href="https://studio.yogaeasy.de/pages/ye-newsletter-anmeldung">
2108                <span class="hover:underline underline-offset-2">Newsletter-Anmeldung</span>
2109</a>              <span class="flex items-center font-medium mx-1 last:hidden">∙</span>
2110              <a class="text-ds-muted text-sm md:text-[11px]" href="https://apps.apple.com/de/app/yogaeasy-online-yoga-studio/id692200180">
2111                <span class="hover:underline underline-offset-2">YogaEasy iOS App</span>
2112</a>              <span class="flex items-center font-medium mx-1 last:hidden">∙</span>
2113              <a class="text-ds-muted text-sm md:text-[11px]" href="https://play.google.com/store/apps/details?id=de.yogaeasy.videoapp&amp;hl=de&amp;pli=1">
2114                <span class="hover:underline underline-offset-2">YogaEasy Android App</span>
2115</a>              <span class="flex items-center font-medium mx-1 last:hidden">∙</span>
2116          </div>
2117        </div>
2118      </div>
2119    </div>
2120  </div>
2121  </div>
2122</header>
2123
2124
2125      </div>
2126
2127      
2128
2129      <main class="flex-1 bg-ds-default relative" data-controller="catalog-scroll-position">
2130          
2130<script>
2131    window.hotwireCatalog = true
2132    window.addEventListener('turbo:before-fetch-request', function (event) {
2133      event.detail.fetchOptions.headers['X-Fastly-Origin'] = "yogaeasygermansite"
2134    })
2135  </script>
2135
2136
2137<script>
2138  window.apiUrl = "https://api.uscreencdn.com"
2139  window.apiOrigin = "yogaeasygermansite"
2140
2141  if (!window.CatalogAnalytics) {
2142    // Allows to call CatalogAnalytics from any other script or page without having to wait for the DOM to be loaded
2143    window.CatalogAnalytics = (...args) => {
2144      (window.CatalogAnalytics.q = window.CatalogAnalytics.q || []).push(args);
2145    };
2146  }
2147</script>
2147
2148
2149  <div id="flash_messages">
2150</div>
2151
2152
2153    
2154
2155
2156
2157      
2158<div class="storefront-widgets-container flex flex-col gap-4 sm:gap-3 fixed z-10 bottom-4 right-4 sm:bottom-auto sm:mt-10 sm:right-0 sm:mr-5">
2159
2160
2161</div>
2162
2163
2164      <turbo-frame data-turbo-action="replace" id="calendar" src="/calendar/agenda?action=show&amp;controller=storefront%2Fcalendar%2Fagenda"></turbo-frame>
2165
2166  
2167
2168
2169      </main>
2170
2171      <footer class="px-[3%] py-8 lg:py-6 w-full bg-ds-main border-t border-ds-default bg-ds-default text-ds-muted text-ds-base-regular">
2172  <div class="container flex flex-col space-y-4 justify-center">
2173    <div class="flex flex-wrap justify-center items-center space-y-2 space-x-2 text-center md:text-left rtl:md:text-right">
2174        <p class="mt-2 flex justify-center space-x-2 w-full md:w-fit text-center text-sm font-normal leading-5 text-ds-muted">
2175          <span id="store-title">© 2026 yogaeasy.de</span>
2176          <span class="ms-2 text-sm font-normal leading-5 text-ds-muted hidden md:inline-block">∙</span>
2177        </p>
2178          <p class="text-sm font-normal leading-5 text-ds-muted">
2179            <a class="hover:underline underline-offset-2" target="_self" href="/terms">AGB</a>
2180          </p>
2181          <p class="text-sm font-normal leading-5 text-ds-muted last-of-type:hidden">∙</p>
2182          <p class="text-sm font-normal leading-5 text-ds-muted">
2183            <a class="hover:underline underline-offset-2" target="_self" href="/privacy">Datenschutz</a>
2184          </p>
2185          <p class="text-sm font-normal leading-5 text-ds-muted last-of-type:hidden">∙</p>
2186          <p class="text-sm font-normal leading-5 text-ds-muted">
2187            <a class="hover:underline underline-offset-2" target="_self" href="/pages/impressum">Impressum</a>
2188          </p>
2189          <p class="text-sm font-normal leading-5 text-ds-muted last-of-type:hidden">∙</p>
2190          <p class="text-sm font-normal leading-5 text-ds-muted">
2191            <a class="hover:underline underline-offset-2" target="_blank" href="https://yogaeasy.jobs.personio.de/?language=de">Jobs</a>
2192          </p>
2193          <p class="text-sm font-normal leading-5 text-ds-muted last-of-type:hidden">∙</p>
2194          <p class="text-sm font-normal leading-5 text-ds-muted">
2195            <a class="hover:underline underline-offset-2" target="_blank" href="https://portal.yogaeasy.de/cancel">Verträge hier kündigen</a>
2196          </p>
2197          <p class="text-sm font-normal leading-5 text-ds-muted last-of-type:hidden">∙</p>
2198          <p class="text-sm font-normal leading-5 text-ds-muted">
2199            <a class="hover:underline underline-offset-2" target="_self" href="/pages/faq">Fragen und Antworten</a>
2200          </p>
2201          <p class="text-sm font-normal leading-5 text-ds-muted last-of-type:hidden">∙</p>
2202          <p class="text-sm font-normal leading-5 text-ds-muted">
2203            <a class="hover:underline underline-offset-2" target="_self" href="https://studio.yogaeasy.de/pages/ye-newsletter-anmeldung">Newsletter-Anmeldung</a>
2204          </p>
2205          <p class="text-sm font-normal leading-5 text-ds-muted last-of-type:hidden">∙</p>
2206          <p class="text-sm font-normal leading-5 text-ds-muted">
2207            <a class="hover:underline underline-offset-2" target="_blank" href="https://apps.apple.com/de/app/yogaeasy-online-yoga-studio/id692200180">YogaEasy iOS App</a>
2208          </p>
2209          <p class="text-sm font-normal leading-5 text-ds-muted last-of-type:hidden">∙</p>
2210          <p class="text-sm font-normal leading-5 text-ds-muted">
2211            <a class="hover:underline underline-offset-2" target="_blank" href="https://play.google.com/store/apps/details?id=de.yogaeasy.videoapp&amp;hl=de&amp;pli=1">YogaEasy Android App</a>
2212          </p>
2213          <p class="text-sm font-normal leading-5 text-ds-muted last-of-type:hidden">∙</p>
2214          <div class="mt-4 md:!ms-4 w-full md:w-fit text-center text-primary hover:underline underline-offset-2 leading-5">
2215            <a class="text-sm text-primary font-medium" data-turbo="true" data-turbo-frame="website_modal" href="/about/apps">App holen -&gt;</a>
2216          </div>
2217      </div>
2218
2219  </div>
2220  <div class="flex mt-0 md:mt-4 items-center justify-center">
2221    
2222  </div>
2223</footer>
2224
2225
2226
2227  </body>
2228</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.