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