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&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 -></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&hl=de&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&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&hl=de&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 -></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.