1<!DOCTYPE html> 2<html lang="en"> 3<head> 4 5 <meta charset="utf-8" /> 6 <meta name="color-scheme" content="dark light"> 7 <meta name="viewport" content="width=device-width, initial-scale=1.0" /> 8 <title>Cart | Alphadi</title> 9 <meta name="description" content="Lean Six Sigma, Operational Excellence und Qualitätsmanagement: Alphadi bietet Weiterbildung, Zertifizierung, Coaching, Beratung und AlphadiTab Software für Verbesserungsprojekte." /> 10 <meta name="og:title" content="Cart | Alphadi" /> 11 <meta name="og:description" content="Lean Six Sigma, Operational Excellence und Qualitätsmanagement: Alphadi bietet Weiterbildung, Zertifizierung, Coaching, Beratung und AlphadiTab Software für Verbesserungsprojekte." /> 12 <meta name="og:type" content="website" /> 13 <meta name="og:locale" content="en" /> 14 15 <link rel="icon" href="/img/favicon.ico" sizes="any"> 16 <link rel="apple-touch-icon" sizes="180x180" href="/img/apple-touch-icon.png"> 17 18 <link rel="preconnect" href="https://fonts.googleapis.com"> 19 <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> 20 <link rel="stylesheet" href="/bundles/hp-styles.css?v=_0Jinmn5XM4Jg2spIz_GA6SmJGHyq_C09ckEcirX2Nk" /> 21 <link rel="stylesheet" href="/lib/katex/katex.min.css?v=7NQzvryVCIQkViOS3GPdLDyHtm1nHMrm7xzxO09F158" /> 22 <style> 23 /* Mobile nav sheet: ALL top-level items look identical, whether or not they have sub-levels. 24 The plain links (Home, Events, â¦) are adjusted to match the dropdown group-triggers 25 (Akademie, Consulting, â¦) â uppercase section-header style. Inline so it always wins 26 over the prebuilt hp-styles bundle (which the browser may cache). */ 27 .nav__sheet-link, 28 .nav__sheet-group-trigger { 29 font-family: var(--f-ui); 30 font-size: 0.72rem; 31 font-weight: 700; 32 letter-spacing: 0.5px; /* matches desktop, reduced from the old 0.12em */ 33 text-transform: uppercase; 34 color: var(--c-subtle); 35 } 36 .nav__sheet-link { border-left: none; } 37 .nav__sheet-link:hover, 38 .nav__sheet-link.is-active { color: var(--c-dark); background: none; } 39 /* "Request a date" inquiry link (training/event booking box). It's a bare <button>, so with 40 color-scheme:dark light the browser paints its text white in OS dark mode and it vanishes. 41 Force it orange in every mode/device. Inline so it wins over the cached hp-styles bundle. */ 42 .btn-link-inline { 43 background: none; 44 border: none; 45 padding: 0; 46 font: inherit; 47 color: var(--c-orange) !important; 48 font-weight: 600; 49 text-decoration: underline; 50 cursor: pointer; 51 } 52 .btn-link-inline:hover { color: var(--c-orange) !important; opacity: 0.8; } 53 /* Per-date "By invoice" inquiry toggle in the training/event booking box. Clicking 54 "By invoice" expands an inline note whose "Inquire here" link opens the request 55 modal. Inline so it wins over the cached hp-styles bundle (which dotnet build 56 does not regenerate). */ 57 .date-item--two-row { flex-direction: column; align-items: stretch; gap: 0; } 58 .date-item--two-row .date-item__top { 59 display: flex; align-items: center; justify-content: space-between; 60 gap: 1rem; flex-wrap: wrap; width: 100%; 61 } 62 .date-item__actions { display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap; } 63 .date-invoice-body { 64 flex-basis: 100%; 65 display: grid; grid-template-rows: 0fr; 66 transition: grid-template-rows 0.25s ease; 67 } 68 .date-item.is-open .date-invoice-body { grid-template-rows: 1fr; } 69 .date-invoice-content { overflow: hidden; } 70 .date-invoice-content p { 71 font-family: var(--f-ui); font-size: 0.8rem; color: var(--c-dark); line-height: 1.6; 72 margin: 0.75rem 0 0; padding-top: 0.75rem; border-top: 1px solid var(--c-border); 73 } 74 .link-btn { 75 background: none; border: none; padding: 0; margin: 0; font: inherit; 76 color: var(--c-orange) !important; text-decoration: underline; cursor: pointer; 77 } 78 .link-btn:hover { opacity: 0.8; } 79 /* Two-row date item: date + action buttons on top, location on its own row below, so the 80 buttons always have room even with a long location. Inline so it wins over the cached 81 hp-styles bundle (which dotnet build does not regenerate). */ 82 .date-item--two-row { flex-direction: column; align-items: stretch; gap: 0; } 83 .date-item--two-row .date-item__top { display: flex; align-items: center; justify-content: space-between; gap: 1rem; flex-wrap: wrap; width: 100%; } 84 .date-item--two-row .date-item__loc { margin-top: 0.25rem; } 85 :root { 86 color-scheme: dark light; 87} 88 /* Logo strip is dark so the WHITE logo stays visible in light AND force-dark mode. 89 The white logo has a declared filter (filter:none) so browser force-dark won't re-invert it. */ 90 .account-menu { position: relative; display: flex; align-items: center; } 91 .account-menu__chevron { flex-shrink: 0; transition: transform var(--t-base); } 92 .account-menu.is-open .account-menu__chevron { transform: rotate(180deg); } 93 .account-menu__dropdown { 94 position: absolute; top: calc(100% + 0.75rem); right: 0; 95 background: var(--c-white); border: 1px solid var(--c-border); 96 border-radius: 6px; padding: 0.5rem; width: 300px; 97 box-shadow: 0 8px 24px rgba(0,0,0,.12); 98 opacity: 0; pointer-events: none; transform: translateY(-4px); 99 transition: opacity 0.18s ease, transform 0.18s ease; z-index: 1100; 100 } 101 .account-menu__dropdown::before { 102 content: ''; position: absolute; top: -5px; right: 13px; 103 width: 9px; height: 9px; background: #fff; 104 border-top: 1px solid var(--c-border); border-left: 1px solid var(--c-border); 105 border-radius: 2px 0 0 0; transform: rotate(45deg); 106 } 107 .account-menu.is-open .account-menu__dropdown { opacity: 1; pointer-events: all; transform: translateY(0); } 108 .account-menu__body { display: flex; flex-direction: column; gap: 1rem; padding: 0.5rem 0.5rem 0.75rem; } 109 .account-menu__lead { display: flex; align-items: center; gap: 0.75rem; font-family: var(--f-ui), sans-serif; font-size: 1rem; line-height: 1.5; color: var(--c-dark); margin: 0; } 110 .account-menu__lead-icon { color: var(--c-orange); flex: 1 1 25%; min-width: 0; display: flex; justify-content: center; } 111 .account-menu__lead-text { flex: 3 3 75%; min-width: 0; } 112 .account-menu__actions { display: flex; flex-direction: column; gap: 0.5rem; } 113 .account-menu__actions .btn { width: 100%; justify-content: center; } 114 .nav__sheet-account { display: flex; flex-direction: column; gap: 0.5rem; padding: 0.5rem 0 0.375rem; } 115 .nav__sheet-account-lead { font-family: var(--f-ui), sans-serif; font-size: 0.9rem; line-height: 1.5; color: var(--c-subtle); margin: 0 0 0.25rem; } 116 .nav__sheet-account .btn { width: 100%; justify-content: center; } 117 </style> 118
118<script src="/bundles/hp-plugins.min.js"></script>
118 119 120 121 122 <style>#training-modules { 123background-color: #efefef; 124} 125 126section[class*="hero-padded"] { 127 padding-top: 114px; 128} 129.hero { 130 position: relative; background: var(--c-bg-warm); overflow: hidden; 131 padding-bottom: 4rem; 132} 133 134section[class*="sa-hero"] { 135 padding-top: 190px; 136} 137 138 139:root { 140 color-scheme: light only; 141} 142 143@media (prefers-color-scheme: dark) { 144 :root { 145 color-scheme: light only; 146 } 147} 148 149.sa-freetext-wrap textarea { 150 151 color: #555555 !important; 152 153} 154#cartPageContent::after { 155 content: ""; 156 display: block; 157 width: 100%; 158 max-width: 420px; 159 aspect-ratio: 3 / 4; 160 margin: 3rem auto 0; 161 background: url("https://www.alphadi.org/image/1705") center / contain no-repeat; 162} 163 164html[lang="en"] #cartPageContent::after { background-image: url("https://www.alphadi.org/image/1706"); } 165html[lang="es"] #cartPageContent::after { background-image: url("https://www.alphadi.org/image/1707"); } 166html[lang="fr"] #cartPageContent::after { background-image: url("https://www.alphadi.org/image/1708"); } 167html[lang="it"] #cartPageContent::after { background-image: url("https://www.alphadi.org/image/1709"); } 168html[lang="pl"] #cartPageContent::after { background-image: url("https://www.alphadi.org/image/1710"); } 169html[lang="pt"] #cartPageContent::after { background-image: url("https://www.alphadi.org/image/1711"); }</style> 170</head> 171 172<body class=""> 173 <!-- Floating alerts --> 174 175 <!-- âââââââ NAVIGATION âââââââ --> 176 <nav class="nav nav--white nav--two-row" id="mainNav"> 177 <!-- Row 1: topbar (desktop only) --> 178 <div class="nav__row--top-wrap"> 179 <div class="nav__row--top"> 180 <div class="nav__row--top-right"> 181 <div class="lang-switch" id="topbarLangSwitch"> 182 <button class="lang-switch__btn" type="button" aria-haspopup="true"> 183 EN 184 <svg viewBox="0 0 10 6" fill="none" stroke="currentColor"> 185 <path d="M1 1L5 5L9 1" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/> 186 </svg> 187 </button> 188 <div class="lang-switch__dropdown"> 189 <form method="post" style="margin:0;padding:0;" action="/Home/SetLanguage?returnUrl=~%2Fen%2Fcart"> 190 <button type="submit" name="culture" value="de-DE" 191 class="lang-switch__opt "> 192 DE â German 193 </button> 194 <input name="__RequestVerificationToken" type="hidden" value="CfDJ8BIMwQTuEtBBtnnpT6fmYEKb6v25N11wuRzX0I64UnyPw-C7gZWLT11sxHWNTmQhtTiInNS7UPupdXQdYVRE6gQ_4u1wV71CUdofocXJdktLpstz1i59LCQiVkSbBohFHDcEK07xWddynYgIWADfKi8" /></form> 195 <form method="post" style="margin:0;padding:0;" action="/Home/SetLanguage?returnUrl=~%2Fen%2Fcart"> 196 <button type="submit" name="culture" value="en-US" 197 class="lang-switch__opt is-active"> 198 EN â English 199 </button> 200 <input name="__RequestVerificationToken" type="hidden" value="CfDJ8BIMwQTuEtBBtnnpT6fmYEKb6v25N11wuRzX0I64UnyPw-C7gZWLT11sxHWNTmQhtTiInNS7UPupdXQdYVRE6gQ_4u1wV71CUdofocXJdktLpstz1i59LCQiVkSbBohFHDcEK07xWddynYgIWADfKi8" /></form> 201 <form method="post" style="margin:0;padding:0;" action="/Home/SetLanguage?returnUrl=~%2Fen%2Fcart"> 202 <button type="submit" name="culture" value="es-ES" 203 class="lang-switch__opt "> 204 ES â Spanish 205 </button> 206 <input name="__RequestVerificationToken" type="hidden" value="CfDJ8BIMwQTuEtBBtnnpT6fmYEKb6v25N11wuRzX0I64UnyPw-C7gZWLT11sxHWNTmQhtTiInNS7UPupdXQdYVRE6gQ_4u1wV71CUdofocXJdktLpstz1i59LCQiVkSbBohFHDcEK07xWddynYgIWADfKi8" /></form> 207 <form method="post" style="margin:0;padding:0;" action="/Home/SetLanguage?returnUrl=~%2Fen%2Fcart"> 208 <button type="submit" name="culture" value="it-IT" 209 class="lang-switch__opt "> 210 IT â Italian 211 </button> 212 <input name="__RequestVerificationToken" type="hidden" value="CfDJ8BIMwQTuEtBBtnnpT6fmYEKb6v25N11wuRzX0I64UnyPw-C7gZWLT11sxHWNTmQhtTiInNS7UPupdXQdYVRE6gQ_4u1wV71CUdofocXJdktLpstz1i59LCQiVkSbBohFHDcEK07xWddynYgIWADfKi8" /></form> 213 <form method="post" style="margin:0;padding:0;" action="/Home/SetLanguage?returnUrl=~%2Fen%2Fcart"> 214 <button type="submit" name="culture" value="fr-FR" 215 class="lang-switch__opt "> 216 FR â French 217 </button> 218 <input name="__RequestVerificationToken" type="hidden" value="CfDJ8BIMwQTuEtBBtnnpT6fmYEKb6v25N11wuRzX0I64UnyPw-C7gZWLT11sxHWNTmQhtTiInNS7UPupdXQdYVRE6gQ_4u1wV71CUdofocXJdktLpstz1i59LCQiVkSbBohFHDcEK07xWddynYgIWADfKi8" /></form> 219 <form method="post" style="margin:0;padding:0;" action="/Home/SetLanguage?returnUrl=~%2Fen%2Fcart"> 220 <button type="submit" name="culture" value="pl-PL" 221 class="lang-switch__opt "> 222 PL â Polish 223 </button> 224 <input name="__RequestVerificationToken" type="hidden" value="CfDJ8BIMwQTuEtBBtnnpT6fmYEKb6v25N11wuRzX0I64UnyPw-C7gZWLT11sxHWNTmQhtTiInNS7UPupdXQdYVRE6gQ_4u1wV71CUdofocXJdktLpstz1i59LCQiVkSbBohFHDcEK07xWddynYgIWADfKi8" /></form> 225 <form method="post" style="margin:0;padding:0;" action="/Home/SetLanguage?returnUrl=~%2Fen%2Fcart"> 226 <button type="submit" name="culture" value="pt-PT"
227 class="lang-switch__opt "> 228 PT â Portuguese 229 </button> 230 <input name="__RequestVerificationToken" type="hidden" value="CfDJ8BIMwQTuEtBBtnnpT6fmYEKb6v25N11wuRzX0I64UnyPw-C7gZWLT11sxHWNTmQhtTiInNS7UPupdXQdYVRE6gQ_4u1wV71CUdofocXJdktLpstz1i59LCQiVkSbBohFHDcEK07xWddynYgIWADfKi8" /></form> 231 </div> 232 </div> 233 234 <div class="account-menu" id="accountMenu"> 235 <button class="nav__login-btn" id="accountMenuBtn" type="button" aria-haspopup="true" aria-expanded="false" aria-label="Account"> 236 <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="8" r="4"/><path d="M4 20c0-4 3.6-7 8-7s8 3 8 7"/></svg> 237 Account 238 <svg class="account-menu__chevron" width="10" height="10" viewBox="0 0 10 6" fill="none"><path d="M1 1l4 4 4-4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg> 239 </button> 240 <div class="account-menu__dropdown"> 241 <div class="account-menu__body"> 242 <div class="account-menu__lead"> 243 <div class="account-menu__lead-icon"> 244 <svg width="42" height="42" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="8" r="4"/><path d="M4 20c0-4 3.6-7 8-7s8 3 8 7"/></svg> 245 </div> 246 <div class="account-menu__lead-text">Log in into your shop account or create a new one.</div> 247 </div> 248 <div class="account-menu__actions"> 249 <a class="btn btn--primary" href="/Internal/Account/Login?returnUrl=~%2Fen%2Fcart"> 250 Login 251 </a> 252 <a class="btn btn--outline" href="/Internal/Account/Register?returnUrl=~%2Fen%2Fcart"> 253 Create account 254 </a> 255 </div> 256 </div> 257 </div> 258 </div> 259 260 <button class="cart-btn" id="cartNavBtn" aria-label="Cart"> 261 <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M6 2L3 6v14a2 2 0 002 2h14a2 2 0 002-2V6l-3-4z" /><line x1="3" y1="6" x2="21" y2="6" /><path d="M16 10a4 4 0 01-8 0" /></svg> 262 <span class="cart-badge">0</span> 263 </button> 264 </div> 265 </div> 266 </div> 267 268 <!-- Row 2: main nav bar --> 269 <div class="nav__inner"> 270 <a class="nav__logo" style="flex-shrink:0;" href="/en"> 271 <img src="/img/logo_f.svg" alt="Alphadi" /> 272 </a> 273 274 <button class="nav__toggle" id="sheetToggle" aria-label="Menu"> 275 <svg class="menu-icon" viewBox="0 0 32 32" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" width="22" height="22"> 276 <path class="menu-icon__morph" d="M27 10 13 10C10.8 10 9 8.2 9 6 9 3.5 10.8 2 13 2 15.2 2 17 3.8 17 6L17 26C17 28.2 18.8 30 21 30 23.2 30 25 28.2 25 26 25 23.8 23.2 22 21 22L7 22"/> 277 <path d="M7 16 27 16"/> 278 </svg> 279 </button> 280 281 <div class="nav__menu"> 282 <div class="nav__item nav__link "> 283 <button class="nav__dropdown-trigger"> 284 Academy 285 <svg viewBox="0 0 10 6" fill="none"><path d="M1 1l4 4 4-4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg> 286 </button> 287 288 <div class="nav__dropdown"> 289 <a href="/en/workshops" class="nav__dropdown-item "> 290 <div class="nav__dropdown-icon"> 291 <img src="/image/1164" alt="" width="25" height="25" style="object-fit:contain;"> 292 </div> 293 <div> 294 <div class="nav__dropdown-text-title">Further training & seminars</div> 295 <div class="nav__dropdown-text-desc"><p>Internationally certified – with access to the Excellence Program.</p> 296</div> 297 </div> 298 </a> 299 <a href="/en/excellence-program" class="nav__dropdown-item "> 300 <div class="nav__dropdown-icon"> 301 <img src="/image/1180" alt="" width="25" height="25" style="object-fit:contain;"> 302 </div> 303 <div> 304 <div class="nav__dropdown-text-title">Excellence Program</div> 305 <div class="nav__dropdown-text-desc"><p>Internationally recognized certifications for professionals and executives</p> 306</div> 307 </div> 308 </a> 309 <a href="/en/coaching" class="nav__dropdown-item "> 310 <div class="nav__dropdown-icon"> 311 <img src="/image/1167" alt="" width="25" height="25" style="object-fit:contain;"> 312 </div> 313 <div> 314 <div class="nav__dropdown-text-title">Coaching & Consulting</div> 315 <div class="nav__dropdown-text-desc"><p>Individual support for companies and executives – on demand</p> 316</div> 317 </div> 318 </a> 319 <a href="/en/shingo-model" class="nav__dropdown-item "> 320 <div class="nav__dropdown-icon"> 321 <img src="/image/1178" alt="" width="25" height="25" style="object-fit:contain;"> 322 </div> 323 <div> 324 <div class="nav__dropdown-text-title">Shingo Model™</div> 325 <div class="nav__dropdown-text-desc"><p>Systemically develop operational excellence — with culture, behavior, and leadership as the foundation.</p> 326</div> 327 </div> 328 </a> 329 </div> 330 </div> 331 <a href="/en/events" class="nav__link ">Events</a> 332 <div class="nav__item nav__link "> 333 <button class="nav__dropdown-trigger"> 334 Consulting 335 <svg viewBox="0 0 10 6" fill="none"><path d="M1 1l4 4 4-4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg> 336 </button> 337 338 <div class="nav__dropdown"> 339 <a href="/en/benchmarking" class="nav__dropdown-item "> 340 <div class="nav__dropdown-icon"> 341 <img src="/image/1165" alt="" width="25" height="25" style="object-fit:contain;"> 342 </div> 343 <div> 344 <div class="nav__dropdown-text-title">Benchmarking</div> 345 <div class="nav__dropdown-text-desc"><p>Identify potential improvements in processes, structures, and collaboration.</p> 346</div> 347 </div> 348 </a> 349 <a href="/en/culture-development-system-explained" class="nav__dropdown-item "> 350 <div class="nav__dropdown-icon"> 351 <img src="/image/1713" alt="" width="25" height="25" style="object-fit:contain;"> 352 </div> 353 <div> 354 <div class="nav__dropdown-text-title">What is the Culture Development System?</div> 355 <div class="nav__dropdown-text-desc"><p>Develop culture purposefully</p> 356</div> 357 </div> 358 </a> 359 <a href="/en/excellence-community" class="nav__dropdown-item "> 360 <div class="nav__dropdown-icon"> 361 <img src="/image/1181" alt="" width="25" height="25" style="object-fit:contain;"> 362 </div> 363 <div> 364 <div class="nav__dropdown-text-title">Excellence Community</div> 365 <div class="nav__dropdown-text-desc"><p>Network, refresh knowledge, and exchange best practices.</p> 366</div> 367 </div> 368 </a> 369 <a href="/en/talent-development" class="nav__dropdown-item "> 370 <div class="nav__dropdown-icon"> 371 <img src="/image/1173" alt="" width="25" height="25" style="object-fit:contain;"> 372 </div> 373 <div> 374 <div class="nav__dropdown-text-title">Talent development</div> 375 <div class="nav__dropdown-text-desc"><p>Strengthen employees in a targeted manner – for performance, change, and competitiveness.</p> 376</div> 377 </div> 378 </a> 379 <a href="/en/opex-roll-out" class="nav__dropdown-item "> 380 <div class="nav__dropdown-icon"> 381 <img src="/image/1170" alt="" width="25" height="25" style="object-fit:contain;"> 382 </div> 383 <div> 384 <div class="nav__dropdown-text-title">OPEX Roll-out</div> 385 <div class="nav__dropdown-text-desc"><p>Effectively roll out OPEX – for less waste and more sustainable impact.</p> 386</div> 387 </div> 388 </a> 389 </div> 390 </div> 391 <div class="nav__item nav__link "> 392 <button class="nav__dropdown-trigger"> 393 Products 394 <svg viewBox="0 0 10 6" fill="none"><path d="M1 1l4 4 4-4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg> 395 </button> 396 397 <div class="nav__dropdown"> 398 <a href="/en/products/books" class="nav__dropdown-item "> 399 <div class="nav__dropdown-icon"> 400 <img src="/image/1166" alt="" width="25" height="25" style="object-fit:contain;"> 401 </div> 402 <div> 403 <div class="nav__dropdown-text-title">Publications</div> 404 <div class="nav__dropdown-text-desc"><p>Books, case studies, and booklets for process managers and organizations.</p> 405</div> 406 </div> 407 </a> 408 <a href="/en/products/tools-templates" class="nav__dropdown-item "> 409 <div class="nav__dropdown-icon"> 410 <img src="/image/1184" alt="" width="25" height="25" style="object-fit:contain;"> 411 </div> 412 <div> 413 <div class="nav__dropdown-text-title">Tools</div> 414 <div class="nav__dropdown-text-desc"><p>Handouts, plots, and presentations for Lean & LSS — ready to use.</p> 415</div> 416 </div> 417 </a> 418 <a href="/en/products/workshops" class="nav__dropdown-item "> 419 <div class="nav__dropdown-icon"> 420 <img src="/image/1293" alt="" width="25" height="25" style="object-fit:contain;"> 421 </div> 422 <div> 423 <div class="nav__dropdown-text-title">Workshops</div> 424 <div class="nav__dropdown-text-desc"><p>Interactive formats for targeted awareness and knowledge transfer – compact and practical.</p> 425</div> 426 </div> 427 </a> 428 </div> 429 </div> 430 <div class="nav__item nav__link "> 431 <button class="nav__dropdown-trigger">
432 Software 433 <svg viewBox="0 0 10 6" fill="none"><path d="M1 1l4 4 4-4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg> 434 </button> 435 436 <div class="nav__dropdown"> 437 <a href="/en/support" class="nav__dropdown-item "> 438 <div class="nav__dropdown-icon"> 439 <img src="/image/1172" alt="" width="25" height="25" style="object-fit:contain;"> 440 </div> 441 <div> 442 <div class="nav__dropdown-text-title">Support</div> 443 <div class="nav__dropdown-text-desc"><p>Everything about documentation, help, and support for our software solutions</p> 444</div> 445 </div> 446 </a> 447 <a href="/en/alphadi-tab" class="nav__dropdown-item "> 448 <div class="nav__dropdown-icon"> 449 <img src="/image/1169" alt="" width="25" height="25" style="object-fit:contain;"> 450 </div> 451 <div> 452 <div class="nav__dropdown-text-title">AlphadiTab</div> 453 <div class="nav__dropdown-text-desc"><p>Project management software for problem solving</p> 454</div> 455 </div> 456 </a> 457 </div> 458 </div> 459 <div class="nav__item nav__link "> 460 <button class="nav__dropdown-trigger"> 461 About us 462 <svg viewBox="0 0 10 6" fill="none"><path d="M1 1l4 4 4-4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg> 463 </button> 464 465 <div class="nav__dropdown"> 466 <a href="/en/career" class="nav__dropdown-item "> 467 <div class="nav__dropdown-icon"> 468 <img src="/image/1416" alt="" width="25" height="25" style="object-fit:contain;"> 469 </div> 470 <div> 471 <div class="nav__dropdown-text-title">Career </div> 472 <div class="nav__dropdown-text-desc"><p>Open positions at Alphadi – flat hierarchies, real responsibility, and room for professional development.</p> 473</div> 474 </div> 475 </a> 476 <a href="/en/ueber-uns" class="nav__dropdown-item "> 477 <div class="nav__dropdown-icon"> 478 <img src="/image/1182" alt="" width="25" height="25" style="object-fit:contain;"> 479 </div> 480 <div> 481 <div class="nav__dropdown-text-title">Meet the Team</div> 482 <div class="nav__dropdown-text-desc"><p>Get to know the people who shape Alphadi with heart and experience.</p> 483</div> 484 </div> 485 </a> 486 <a href="/en/glossary" class="nav__dropdown-item "> 487 <div class="nav__dropdown-icon"> 488 <img src="/image/216" alt="" width="25" height="25" style="object-fit:contain;"> 489 </div> 490 <div> 491 <div class="nav__dropdown-text-title">Glossary</div> 492 <div class="nav__dropdown-text-desc"><p>Terms, definitions and important technical terms explained at a glance.</p> 493</div> 494 </div> 495 </a> 496 </div> 497 </div> 498 499 500 </div> 501 502 <a href="/en/contact" class="nav__cta nav__cta--desktop">Contact</a> 503 </div> 504 </nav> 505 506 <!-- Backdrop --> 507 <div class="nav__sheet-overlay" id="sheetOverlay"></div> 508 509 <!-- Right-side nav sheet --> 510 <div class="nav__sheet" id="navSheet"> 511 <div class="nav__sheet-header"> 512 <div class="nav__sheet-logo"> 513 <a href="/en"> 514 <img src="/img/logo_f.svg" alt="Alphadi" style="height:35px;width:auto;" /> 515 </a> 516 </div> 517 <button class="nav__sheet-close" id="sheetClose" aria-label="Close menu"> 518 <svg viewBox="0 0 14 14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"> 519 <path d="M1 1l12 12M13 1L1 13"/> 520 </svg> 521 </button> 522 </div> 523 524 <div class="nav__sheet-body"> 525 526 <a class="nav__sheet-link " href="/en">Home</a> 527 528 <button class="nav__sheet-group-trigger" type="button">
529 <span>Academy</span> 530 <svg viewBox="0 0 10 6" fill="none"><path d="M1 1l4 4 4-4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg> 531 </button> 532 <div class="nav__sheet-sub"> 533 <a href="/en/workshops" class="nav__sheet-sub-item"> 534 <div class="nav__sheet-sub-icon"> 535 <img src="/image/1164" alt="" width="20" height="20" style="object-fit:contain;"> 536 </div> 537 Further training & seminars 538 </a> 539 <a href="/en/excellence-program" class="nav__sheet-sub-item"> 540 <div class="nav__sheet-sub-icon"> 541 <img src="/image/1180" alt="" width="20" height="20" style="object-fit:contain;"> 542 </div> 543 Excellence Program 544 </a> 545 <a href="/en/coaching" class="nav__sheet-sub-item"> 546 <div class="nav__sheet-sub-icon"> 547 <img src="/image/1167" alt="" width="20" height="20" style="object-fit:contain;"> 548 </div> 549 Coaching & Consulting 550 </a> 551 <a href="/en/shingo-model" class="nav__sheet-sub-item"> 552 <div class="nav__sheet-sub-icon"> 553 <img src="/image/1178" alt="" width="20" height="20" style="object-fit:contain;"> 554 </div> 555 Shingo Model™ 556 </a> 557 </div> 558 <a href="/en/events" class="nav__sheet-link ">Events</a> 559 <button class="nav__sheet-group-trigger" type="button"> 560 <span>Consulting</span> 561 <svg viewBox="0 0 10 6" fill="none"><path d="M1 1l4 4 4-4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg> 562 </button> 563 <div class="nav__sheet-sub"> 564 <a href="/en/benchmarking" class="nav__sheet-sub-item"> 565 <div class="nav__sheet-sub-icon"> 566 <img src="/image/1165" alt="" width="20" height="20" style="object-fit:contain;"> 567 </div> 568 Benchmarking 569 </a> 570 <a href="/en/culture-development-system-explained" class="nav__sheet-sub-item"> 571 <div class="nav__sheet-sub-icon"> 572 <img src="/image/1713" alt="" width="20" height="20" style="object-fit:contain;"> 573 </div> 574 What is the Culture Development System? 575 </a> 576 <a href="/en/excellence-community" class="nav__sheet-sub-item"> 577 <div class="nav__sheet-sub-icon"> 578 <img src="/image/1181" alt="" width="20" height="20" style="object-fit:contain;"> 579 </div> 580 Excellence Community 581 </a> 582 <a href="/en/talent-development" class="nav__sheet-sub-item"> 583 <div class="nav__sheet-sub-icon"> 584 <img src="/image/1173" alt="" width="20" height="20" style="object-fit:contain;"> 585 </div> 586 Talent development 587 </a> 588 <a href="/en/opex-roll-out" class="nav__sheet-sub-item"> 589 <div class="nav__sheet-sub-icon"> 590 <img src="/image/1170" alt="" width="20" height="20" style="object-fit:contain;"> 591 </div> 592 OPEX Roll-out 593 </a> 594 </div> 595 <button class="nav__sheet-group-trigger" type="button">
596 <span>Products</span> 597 <svg viewBox="0 0 10 6" fill="none"><path d="M1 1l4 4 4-4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg> 598 </button> 599 <div class="nav__sheet-sub"> 600 <a href="/en/products/books" class="nav__sheet-sub-item"> 601 <div class="nav__sheet-sub-icon"> 602 <img src="/image/1166" alt="" width="20" height="20" style="object-fit:contain;"> 603 </div> 604 Publications 605 </a> 606 <a href="/en/products/tools-templates" class="nav__sheet-sub-item"> 607 <div class="nav__sheet-sub-icon"> 608 <img src="/image/1184" alt="" width="20" height="20" style="object-fit:contain;"> 609 </div> 610 Tools 611 </a> 612 <a href="/en/products/workshops" class="nav__sheet-sub-item"> 613 <div class="nav__sheet-sub-icon"> 614 <img src="/image/1293" alt="" width="20" height="20" style="object-fit:contain;"> 615 </div> 616 Workshops 617 </a> 618 </div> 619 <button class="nav__sheet-group-trigger" type="button"> 620 <span>Software</span> 621 <svg viewBox="0 0 10 6" fill="none"><path d="M1 1l4 4 4-4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg> 622 </button> 623 <div class="nav__sheet-sub"> 624 <a href="/en/support" class="nav__sheet-sub-item"> 625 <div class="nav__sheet-sub-icon"> 626 <img src="/image/1172" alt="" width="20" height="20" style="object-fit:contain;"> 627 </div> 628 Support 629 </a> 630 <a href="/en/alphadi-tab" class="nav__sheet-sub-item"> 631 <div class="nav__sheet-sub-icon"> 632 <img src="/image/1169" alt="" width="20" height="20" style="object-fit:contain;"> 633 </div> 634 AlphadiTab 635 </a> 636 </div> 637 <button class="nav__sheet-group-trigger" type="button"> 638 <span>About us</span> 639 <svg viewBox="0 0 10 6" fill="none"><path d="M1 1l4 4 4-4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg> 640 </button> 641 <div class="nav__sheet-sub"> 642 <a href="/en/career" class="nav__sheet-sub-item"> 643 <div class="nav__sheet-sub-icon"> 644 <img src="/image/1416" alt="" width="20" height="20" style="object-fit:contain;"> 645 </div> 646 Career 647 </a> 648 <a href="/en/ueber-uns" class="nav__sheet-sub-item"> 649 <div class="nav__sheet-sub-icon"> 650 <img src="/image/1182" alt="" width="20" height="20" style="object-fit:contain;"> 651 </div> 652 Meet the Team 653 </a> 654 <a href="/en/glossary" class="nav__sheet-sub-item"> 655 <div class="nav__sheet-sub-icon"> 656 <img src="/image/216" alt="" width="20" height="20" style="object-fit:contain;"> 657 </div> 658 Glossary 659 </a> 660 </div> 661 662 663 664 <div class="nav__sheet-divider"></div> 665 <button class="nav__sheet-group-trigger" type="button" aria-haspopup="true" aria-expanded="false">
666 <span> 667 <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:middle;margin-right:.35rem;"><circle cx="12" cy="8" r="4"/><path d="M4 20c0-4 3.6-7 8-7s8 3 8 7"/></svg> 668 Account 669 </span> 670 <svg viewBox="0 0 10 6" fill="none"><path d="M1 1l4 4 4-4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg> 671 </button> 672 <div class="nav__sheet-sub"> 673 <div class="nav__sheet-account"> 674 <p class="nav__sheet-account-lead">Log in into your shop account or create a new one.</p> 675 <a class="btn btn--primary" href="/Internal/Account/Login?returnUrl=~%2Fen%2Fcart">Login</a> 676 <a class="btn btn--outline" href="/Internal/Account/Register?returnUrl=~%2Fen%2Fcart">Create account</a> 677 </div> 678 </div> 679 680 <div class="nav__sheet-divider"></div> 681 <button class="nav__sheet-group-trigger" id="sheetLangTrigger" type="button"> 682 <span> 683 <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="vertical-align:middle;margin-right:.35rem;"><circle cx="12" cy="12" r="10"/><path d="M2 12h20"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg> 684 Language 685 </span> 686 <svg viewBox="0 0 10 6" fill="none"><path d="M1 1l4 4 4-4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg> 687 </button> 688 <div class="nav__sheet-sub" id="sheetLangSub"> 689 <form method="post" style="margin:0;padding:0;display:contents;" action="/Home/SetLanguage?returnUrl=~%2Fen%2Fcart"> 690 <button type="submit" name="culture" value="de-DE" 691 class="nav__sheet-sub-item "> 692 DE â German 693 </button> 694 <input name="__RequestVerificationToken" type="hidden" value="CfDJ8BIMwQTuEtBBtnnpT6fmYEKb6v25N11wuRzX0I64UnyPw-C7gZWLT11sxHWNTmQhtTiInNS7UPupdXQdYVRE6gQ_4u1wV71CUdofocXJdktLpstz1i59LCQiVkSbBohFHDcEK07xWddynYgIWADfKi8" /></form> 695 <form method="post" style="margin:0;padding:0;display:contents;" action="/Home/SetLanguage?returnUrl=~%2Fen%2Fcart"> 696 <button type="submit" name="culture" value="en-US" 697 class="nav__sheet-sub-item is-active"> 698 EN â English 699 </button> 700 <input name="__RequestVerificationToken" type="hidden" value="CfDJ8BIMwQTuEtBBtnnpT6fmYEKb6v25N11wuRzX0I64UnyPw-C7gZWLT11sxHWNTmQhtTiInNS7UPupdXQdYVRE6gQ_4u1wV71CUdofocXJdktLpstz1i59LCQiVkSbBohFHDcEK07xWddynYgIWADfKi8" /></form> 701 <form method="post" style="margin:0;padding:0;display:contents;" action="/Home/SetLanguage?returnUrl=~%2Fen%2Fcart"> 702 <button type="submit" name="culture" value="es-ES" 703 class="nav__sheet-sub-item "> 704 ES â Spanish 705 </button> 706 <input name="__RequestVerificationToken" type="hidden" value="CfDJ8BIMwQTuEtBBtnnpT6fmYEKb6v25N11wuRzX0I64UnyPw-C7gZWLT11sxHWNTmQhtTiInNS7UPupdXQdYVRE6gQ_4u1wV71CUdofocXJdktLpstz1i59LCQiVkSbBohFHDcEK07xWddynYgIWADfKi8" /></form> 707 <form method="post" style="margin:0;padding:0;display:contents;" action="/Home/SetLanguage?returnUrl=~%2Fen%2Fcart"> 708 <button type="submit" name="culture" value="it-IT" 709 class="nav__sheet-sub-item "> 710 IT â Italian 711 </button> 712 <input name="__RequestVerificationToken" type="hidden" value="CfDJ8BIMwQTuEtBBtnnpT6fmYEKb6v25N11wuRzX0I64UnyPw-C7gZWLT11sxHWNTmQhtTiInNS7UPupdXQdYVRE6gQ_4u1wV71CUdofocXJdktLpstz1i59LCQiVkSbBohFHDcEK07xWddynYgIWADfKi8" /></form> 713 <form method="post" style="margin:0;padding:0;display:contents;" action="/Home/SetLanguage?returnUrl=~%2Fen%2Fcart"> 714 <button type="submit" name="culture" value="fr-FR" 715 class="nav__sheet-sub-item "> 716 FR â French 717 </button> 718 <input name="__RequestVerificationToken" type="hidden" value="CfDJ8BIMwQTuEtBBtnnpT6fmYEKb6v25N11wuRzX0I64UnyPw-C7gZWLT11sxHWNTmQhtTiInNS7UPupdXQdYVRE6gQ_4u1wV71CUdofocXJdktLpstz1i59LCQiVkSbBohFHDcEK07xWddynYgIWADfKi8" /></form> 719 <form method="post" style="margin:0;padding:0;display:contents;" action="/Home/SetLanguage?returnUrl=~%2Fen%2Fcart"> 720 <button type="submit" name="culture" value="pl-PL" 721 class="nav__sheet-sub-item "> 722 PL â Polish 723 </button> 724 <input name="__RequestVerificationToken" type="hidden" value="CfDJ8BIMwQTuEtBBtnnpT6fmYEKb6v25N11wuRzX0I64UnyPw-C7gZWLT11sxHWNTmQhtTiInNS7UPupdXQdYVRE6gQ_4u1wV71CUdofocXJdktLpstz1i59LCQiVkSbBohFHDcEK07xWddynYgIWADfKi8" /></form> 725 <form method="post" style="margin:0;padding:0;display:contents;" action="/Home/SetLanguage?returnUrl=~%2Fen%2Fcart"> 726 <button type="submit" name="culture" value="pt-PT"
727 class="nav__sheet-sub-item "> 728 PT â Portuguese 729 </button> 730 <input name="__RequestVerificationToken" type="hidden" value="CfDJ8BIMwQTuEtBBtnnpT6fmYEKb6v25N11wuRzX0I64UnyPw-C7gZWLT11sxHWNTmQhtTiInNS7UPupdXQdYVRE6gQ_4u1wV71CUdofocXJdktLpstz1i59LCQiVkSbBohFHDcEK07xWddynYgIWADfKi8" /></form> 731 </div> 732 </div> 733 734 <div class="nav__sheet-footer"> 735 <a href="/en/contact">Contact</a> 736 </div> 737 </div> 738 739 <!-- âââââââ MAIN âââââââ --> 740 741<div class="page-hero"> 742 <div class="container"> 743 <nav class="breadcrumb"> 744 <a href="/en">Home</a> 745 <span>/</span> 746 <span style="color:rgba(0,0,0,.45);">Cart</span> 747 </nav> 748 <h1 class="page-hero__title">Cart</h1> 749 </div> 750</div> 751 752<section class="section bg-white"> 753 <div class="container"> 754 755 <div id="cartPageNotice" style="display:none;max-width:640px;margin:0 auto 1.5rem;" 756 data-msg-title="Your cart was updated" 757 data-msg-removed="{name} is no longer available and was removed." 758 data-msg-repriced="Price of {name} changed to {price}."></div> 759 760 <div id="cartPageEmpty" style="display:none;text-align:center;padding:4rem 1rem;"> 761 <svg width="64" height="64" viewBox="0 0 24 24" fill="none" stroke="var(--c-border)" stroke-width="1.5" style="margin-bottom:1.5rem;"><path d="M6 2L3 6v14a2 2 0 002 2h14a2 2 0 002-2V6l-3-4z"/><line x1="3" y1="6" x2="21" y2="6"/><path d="M16 10a4 4 0 01-8 0"/></svg> 762 <p style="font-family:var(--f-ui);font-size:1.1rem;color:var(--c-mid);margin-bottom:2rem;">Your cart is empty.</p> 763 <a href="/en" class="btn btn--primary">Continue shopping</a> 764 </div> 765 766 <div id="cartPageContent" style="display:none;"> 767 <div class="cart-page-layout"> 768 769 <!-- Items table --> 770 <div class="cart-page-items"> 771 <div class="cart-page-table-head"> 772 <span>Product</span> 773 <span style="text-align:center;">Quantity</span> 774 <span style="text-align:right;">Price</span> 775 </div> 776 <div id="cartPageRows"></div> 777 </div> 778 779 <!-- Order summary --> 780 <div class="cart-page-summary"> 781 <h2 class="cart-page-summary__title">Order summary</h2> 782 <div class="cart-page-summary__rows" id="cartPageSummaryRows"></div> 783 <div class="cart-page-summary__total"> 784 <span>Total</span> 785 <span id="cartPageTotal">0,00 â¬</span> 786 </div> 787 <a href="/en/checkout" class="btn btn--primary btn--lg" style="width:100%;justify-content:center;margin-top:1.5rem;"> 788 Proceed to checkout â 789 </a> 790 <a href="/en" class="btn btn--ghost" style="width:100%;justify-content:center;margin-top:0.75rem;"> 791 â Continue shopping 792 </a> 793 </div> 794 795 </div> 796 </div> 797 798 </div> 799</section> 800 801 802 803 804 <!-- âââââââ FOOTER âââââââ --> 805<meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"> 806<title></title> 807<link href="https://api.fontshare.com" rel="preconnect" /> 808<link href="https://fonts.googleapis.com" rel="preconnect" /> 809<link href="https://api.fontshare.com/v2/css?f[]=satoshi@300,400,500,600,700,900&display=swap" rel="stylesheet" /> 810<link href="https://fonts.googleapis.com/css2?family=Lexend:wght@300;400;500;600;700&display=swap" rel="stylesheet" /> 811<style type="text/css">*, *::before, *::after { 812 box-sizing: border-box; 813 margin: 0; 814 padding: 0; 815 } 816 html { 817 font-size: 16px; 818 } 819 body { 820 font-family: 'Satoshi', system-ui, sans-serif; 821 -webkit-font-smoothing: antialiased; 822 } 823 a { 824 color: inherit; 825 text-decoration: none; 826 } 827 img { 828 max-width: 100%; 829 display: block; 830 } 831 .footer-v2 { 832 background: #111111; 833 position: relative; 834 overflow: hidden; 835 } 836 .footer-v2::before { 837 content: ''; 838 position: absolute; 839 top: 0; 840 left: 0; 841 right: 0; 842 height: 3px; 843 background: linear-gradient(90deg, #111111, #EC841F, #1a0a00); 844 } 845 .footer-v2::after { 846 content: ''; 847 position: absolute; 848 top: -120px; 849 left: -80px; 850 width: 500px; 851 height: 500px; 852 border-radius: 50%; 853 background: radial-gradient(circle, rgba(236,132,31,.07) 0%, transparent 65%); 854 pointer-events: none; 855 } 856 .footer-v2__inner { 857 max-width: 1280px; 858 margin: 0 auto; 859 padding: 4rem 3rem 0; 860 } 861 @media (max-width: 767px) { 862 .footer-v2__inner { 863 padding: 3rem 1.5rem 0; 864 } 865 } 866 .footer-v2__top { 867 display: grid; 868 grid-template-columns: 1.6fr 2.4fr; 869 gap: 4rem; 870 padding-bottom: 3rem; 871 border-bottom: 1px solid rgba(255,255,255,.08); 872 } 873 @media (max-width: 767px) { 874 .footer-v2__top { 875 grid-template-columns: 1fr; 876 gap: 2.5rem; 877 } 878 } 879 .footer-v2__brand img { 880 height: 56px; 881 width: auto; 882 margin-bottom: 2rem; 883 filter: none !important; 884 /* Prevents browser dark mode from inverting the white logo to black */ 885 forced-color-adjust: none;
886 /* Exclude logo from automatic color adjustment (Dark Mode/High Contrast) */ 887 } 888 .footer-v2__claim { 889 font-family: 'Satoshi', system-ui, sans-serif; 890 font-size: clamp(1.15rem, 1.8vw, 1.45rem); 891 font-weight: 700; 892 color: #ffffff; 893 line-height: 1.35; 894 letter-spacing: -0.02em; 895 margin-bottom: 1.5rem; 896 max-width: 280px; 897 } 898 .footer-v2__claim em { 899 font-style: normal; 900 color: #EC841F; 901 } 902 .footer-v2__contact { 903 display: flex; 904 flex-direction: column; 905 gap: 0.4rem; 906 } 907 .footer-v2__contact a { 908 display: flex; 909 align-items: center; 910 gap: 0.5rem; 911 font-family: 'Satoshi', system-ui, sans-serif; 912 font-size: 0.78rem; 913 color: rgba(255,255,255,.88); 914 text-decoration: none; 915 transition: color 0.15s; 916 font-weight: 400; 917 letter-spacing: 0.8px; 918 } 919 .footer-v2__contact a:hover { 920 color: #EC841F; 921 } 922 .footer-v2__contact svg { 923 flex-shrink: 0; 924 opacity: .6; 925 } 926 .footer-v2__links { 927 display: grid; 928 grid-template-columns: repeat(3, 1fr); 929 gap: 2rem; 930 padding-top: 0.25rem; 931 } 932 @media (max-width: 479px) { 933 .footer-v2__links { 934 grid-template-columns: repeat(2, 1fr); 935 } 936 } 937 .footer-v2__col h4 { 938 font-family: 'Satoshi', system-ui, sans-serif; 939 font-size: 0.65rem; 940 font-weight: 700; 941 letter-spacing: 0.14em; 942 text-transform: uppercase; 943 color: #ffffff; 944 margin-bottom: 1rem; 945 } 946 .footer-v2__col a { 947 display: block; 948 font-family: 'Satoshi', system-ui, sans-serif; 949 font-size: 0.78rem; 950 color: rgba(255,255,255,.88); 951 margin-bottom: 0.5rem; 952 text-decoration: none; 953 transition: color 0.15s, padding-left 0.15s; 954 font-weight: 300; 955 letter-spacing: 0.8px; 956 } 957 .footer-v2__col a:hover { 958 color: #fff; 959 padding-left: 3px; 960 } 961 .footer-v2__bottom { 962 max-width: 1280px; 963 margin: 0 auto; 964 padding: 1.25rem 3rem; 965 border-top: 1px solid rgba(255,255,255,.14); 966 display: flex; 967 flex-wrap: wrap; 968 justify-content: space-between; 969 align-items: center; 970 gap: 0.75rem; 971 } 972 @media (max-width: 767px) { 973 .footer-v2__bottom { 974 padding: 1.25rem 1.5rem; 975 flex-direction: column; 976 align-items: flex-start; 977 } 978 } 979 .footer-v2__copy { 980 font-family: 'Satoshi', system-ui, sans-serif; 981 font-size: 0.75rem; 982 color: rgba(255,255,255,.88); 983 } 984 .footer-v2__socials { 985 display: flex;
986 align-items: center; 987 gap: 0.5rem; 988 } 989 .footer-v2__social { 990 width: 36px; 991 height: 36px; 992 display: flex; 993 align-items: center; 994 justify-content: center; 995 border: 1px solid rgba(255,255,255,.5); 996 border-radius: 8px; 997 color: rgba(255,255,255,.9); 998 text-decoration: none; 999 transition: border-color 0.15s, color 0.15s, background 0.15s; 1000 } 1001 .footer-v2__social:hover { 1002 border-color: #EC841F; 1003 color: #EC841F; 1004 background: rgba(236,132,31,.08); 1005 } 1006 .footer-v2__social svg { 1007 width: 14px; 1008 height: 14px; 1009 } 1010</style> 1011<footer class="footer-v2"> 1012<div class="footer-v2__inner"> 1013<div class="footer-v2__top"> 1014<div class="footer-v2__brand"> 1015<a href="/"><img alt="Alphadi" src="/image/222" /></a> 1016 1017<p class="footer-v2__claim">We focus on<br /> 1018<em>people</em>.</p> 1019 1020<div class="footer-v2__contact"> 1021<a href="tel:+4956194918900"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> 1022 <path d="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07A19.5 19.5 0 0 1 4.68 12a19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 3.59 1.23h3a2 2 0 0 1 2 1.72c.128.96.361 1.903.7 2.81a2 2 0 0 1-.45 2.11L7.91 8.87a16 16 0 0 0 6 6l.87-.87a2 2 0 0 1 2.11-.45c.907.339 1.85.572 2.81.7A2 2 0 0 1 22 16.92z"/> 1023 </svg>+49 561 949 189 0</a> 1024 1025<a href="mailto:[email protected]"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> 1026 <path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"/> 1027 <polyline points="22,6 12,13 2,6"/> 1028 </svg>[email protected]</a> 1029</div> 1030</div> 1031 1032<div class="footer-v2__links"> 1033<div class="footer-v2__col"> 1034<h4>Programs</h4> 1035 1036<a href="/en/workshops">Workshops & Seminars</a> 1037 1038<a href="/en/events">Events</a> 1039 1040<a href="/en/assessments">Assessments</a> 1041 1042<a href="/en/support">Software Support & Help</a> 1043</div> 1044 1045<div class="footer-v2__col"> 1046<h4>Company</h4> 1047 1048<a href="/en/ueber-uns">About us</a> 1049 1050<a href="/en/contact">Contact</a> 1051 1052<a href="/en/career">Career</a> 1053</div> 1054 1055<div class="footer-v2__col"> 1056<h4>Legal</h4> 1057 1058<a href="/en/privacy-policy">Privacy Policy</a> 1059 1060<a href="/en/t&c">Terms and Conditions</a> 1061 1062<a href="/en/imprint">Imprint</a> 1063 1064<a href="/en/cancellation-policy">Revoke Contract Here</a> 1065 1066<a href="/en/shipping-payment-terms">Shipping & Payment</a> 1067</div> 1068</div> 1069</div> 1070 1071<div class="footer-v2__bottom"><span class="footer-v2__copy">© 2026 Alphadi Deutschland GmbH. All rights reserved.</span> 1072 1073<div class="footer-v2__socials"> 1074<a aria-label="YouTube" class="footer-v2__social" href="#"><svg viewBox="0 0 24 24" fill="currentColor" width="16" height="16"> 1075 <path d="M23.498 6.186a3.016 3.016 0 0 0-2.122-2.136C19.505 3.545 12 3.545 12 3.545s-7.505 0-9.377.505A3.017 3.017 0 0 0 .502 6.186C0 8.07 0 12 0 12s0 3.93.502 5.814a3.016 3.016 0 0 0 2.122 2.136c1.871.505 9.376.505 9.376.505s7.505 0 9.377-.505a3.015 3.015 0 0 0 2.122-2.136C24 15.93 24 12 24 12s0-3.93-.502-5.814zM9.545 15.568V8.432L15.818 12l-6.273 3.568z"/> 1076 </svg></a> 1077 1078<a aria-label="LinkedIn" class="footer-v2__social" href="#"><svg viewBox="0 0 24 24" fill="currentColor" width="16" height="16"> 1079 <path d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433a2.062 2.062 0 0 1-2.063-2.065 2.064 2.064 0 1 1 2.063 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z"/> 1080 </svg></a> 1081</div> 1082</div> 1083</div> 1084</footer> 1085 1086
1086<script> 1087 // Shared price formatter â mirrors DecimalUtils.PriceDisplay (German format, e.g. "6.600,00 â¬"). 1088 // Used by every client-side price render (cart drawer, cart page, checkout, product options). 1089 window.formatPrice = function (value, symbol) { 1090 var n = Number(value); 1091 if (!isFinite(n)) { n = 0; } 1092 var number = n.toLocaleString('de-DE', { minimumFractionDigits: 2, maximumFractionDigits: 2 }); 1093 return number + ' ' + (symbol || 'â¬'); 1094 }; 1095 </script>
1095 1096
1096<script src="/bundles/hp-scripts.min.js?v=ZHApbpWBMcSvjokQcwPZYptpuVDzcPqCftH9nsYyTTE"></script>
1096 1097
1097<script src="/js/cart-sync.js?v=9IsathfVPUw6nubjgrQKNjXkyoTVZ-DBaj0qJNKNn8w"></script>
1097 1098 1099 <!-- KaTeX: render LaTeX math anywhere in the page content (delimiters \( \), \[ \], $$ $$) --> 1100
1100<script src="/lib/katex/katex.min.js?v=3ISyluw-iE3gkxWPdg_Z1Ftser5YtTgVV_ThOPRqWK4"></script>
1100 1101
1101<script src="/lib/katex/contrib/auto-render.min.js?v=nLjaz8CGwpZsnsS6VPSi3EO3y-KzPOwaJ0PYhsf7R6c"></script>
1101 1102
1102<script> 1103 1104 1105 (function () { 1106 function renderMath() { 1107 if (typeof renderMathInElement !== 'function') { return; } 1108 renderMathInElement(document.body, { 1109 delimiters: [ 1110 { left: '$$', right: '$$', display: true }, 1111 { left: '\\[', right: '\\]', display: true }, 1112 { left: '\\(', right: '\\)', display: false } 1113 ], 1114 throwOnError: false, 1115 ignoredTags: ['script', 'noscript', 'style', 'textarea', 'pre', 'code'] 1116 }); 1117 } 1118 1119 if (document.readyState === 'loading') { 1120 document.addEventListener('DOMContentLoaded', renderMath); 1121 } else { 1122 renderMath(); 1123 } 1124 })(); 1125 </script>
1125 1126 1127 <!-- Topbar user menu toggle --> 1128
1128<script> 1129 (function () { 1130 var userMenu = document.getElementById('userMenu'); 1131 var userMenuBtn = document.getElementById('userMenuBtn'); 1132 if (userMenu && userMenuBtn) { 1133 userMenuBtn.addEventListener('click', function (e) { 1134 e.stopPropagation(); 1135 userMenu.classList.toggle('is-open'); 1136 }); 1137 document.addEventListener('click', function () { 1138 userMenu.classList.remove('is-open'); 1139 }); 1140 userMenu.addEventListener('click', function (e) { e.stopPropagation(); }); 1141 } 1142 // Note: lang-switch toggles are already handled globally by hp-scripts.js 1143 })(); 1144 </script>
1144 1145 1146 <!-- Topbar account (signed out) dropdown toggle --> 1147
1147<script> 1148 (function () { 1149 var accountMenu = document.getElementById('accountMenu'); 1150 var accountMenuBtn = document.getElementById('accountMenuBtn'); 1151 if (accountMenu && accountMenuBtn) { 1152 accountMenuBtn.addEventListener('click', function (e) { 1153 e.stopPropagation(); 1154 var open = accountMenu.classList.toggle('is-open'); 1155 accountMenuBtn.setAttribute('aria-expanded', open ? 'true' : 'false'); 1156 }); 1157 document.addEventListener('click', function () { 1158 if (accountMenu.classList.contains('is-open')) { 1159 accountMenu.classList.remove('is-open'); 1160 accountMenuBtn.setAttribute('aria-expanded', 'false'); 1161 } 1162 }); 1163 accountMenu.addEventListener('click', function (e) { e.stopPropagation(); }); 1164 } 1165 })(); 1166 </script>
1166 1167 1168
1169<script> 1170(function () { 1171 let state = {}; 1172 try { state = JSON.parse(localStorage.getItem('alphadi-cart') || '{}'); } catch (e) { state = {}; } 1173 1174 const entries = Object.entries(state).filter(([, v]) => v.qty > 0); 1175 const emptyEl = document.getElementById('cartPageEmpty'); 1176 const contentEl = document.getElementById('cartPageContent'); 1177 const rowsEl = document.getElementById('cartPageRows'); 1178 const summaryEl = document.getElementById('cartPageSummaryRows'); 1179 const totalEl = document.getElementById('cartPageTotal'); 1180 1181 const save = () => localStorage.setItem('alphadi-cart', JSON.stringify(state)); 1182 1183 const updateBadges = () => { 1184 const n = Object.values(state).reduce((s, v) => s + v.qty, 0); 1185 document.querySelectorAll('.cart-badge').forEach(b => { 1186 b.textContent = n; 1187 b.classList.toggle('has-items', n > 0); 1188 }); 1189 }; 1190 1191 const render = () => { 1192 const live = Object.entries(state).filter(([, v]) => v.qty > 0); 1193 if (!live.length) { 1194 contentEl.style.display = 'none'; 1195 emptyEl.style.display = ''; 1196 return; 1197 } 1198 emptyEl.style.display = 'none'; 1199 contentEl.style.display = ''; 1200 1201 let grandTotal = 0; 1202 1203 rowsEl.innerHTML = live.map(([id, v]) => { 1204 const lineTotal = v.price * v.qty; 1205 grandTotal += lineTotal; 1206 const unitHtml = v.price < 0 1207 ? `<span style="color:#28a745;">${window.formatPrice(v.price)}</span>` 1208 : `${window.formatPrice(v.price)}`; 1209 const coverHtml = v.image 1210 ? `<img src="${v.image}" alt="${v.name}" style="width:100%;height:100%;object-fit:cover;display:block;">` 1211 : `<svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="rgba(255,255,255,.4)" stroke-width="1.5"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg>`; 1212 const isBooking = v.type === 'training' || v.type === 'event'; 1213 const qtyHtml = isBooking 1214 ? `<div style="text-align:center;font-size:.85rem;color:var(--c-mid);">1 seat</div>` 1215 : `<div class="cart-item__qty"> 1216 <button data-action="dec" data-id="${id}">−</button> 1217 <span class="cart-item__qty-num">${v.qty}</span> 1218 <button data-action="inc" data-id="${id}">+</button> 1219 </div>`; 1220 const participantHtml = isBooking && v.participant && v.participant.name 1221 ? `<div class="cart-page-row__format" style="margin-top:.25rem;"> 1222 <strong>Participant:</strong> ${v.participant.name}${v.participant.company ? ' · ' + v.participant.company : ''}${v.participant.email ? ' · ' + v.participant.email : ''} 1223 </div>` 1224 : ''; 1225 return ` 1226 <div class="cart-page-row" data-row-id="${id}"> 1227 <div class="cart-page-row__cover" style="overflow:hidden;"> 1228 ${coverHtml} 1229 </div> 1230 <div class="cart-page-row__info"> 1231 <div class="cart-page-row__name">${v.name}</div> 1232 ${v.format ? `<div class="cart-page-row__format">${v.format}</div>` : ''} 1233 ${participantHtml} 1234 <div class="cart-page-row__unit">${unitHtml} / unit</div> 1235 </div> 1236 <div class="cart-page-row__qty"> 1237 ${qtyHtml} 1238 <button class="cart-page-row__remove" data-action="remove" data-id="${id}">Remove</button> 1239 </div> 1240 <div class="cart-page-row__total">${window.formatPrice(lineTotal)}</div> 1241 </div>`; 1242 }).join(''); 1243 1244 summaryEl.innerHTML = live.map(([, v]) => 1245 `<div class="cart-page-summary__row"> 1246 <span>${v.name}${v.format ? ` <small>(${v.format})</small>` : ''} à ${v.qty}</span> 1247 <span>${window.formatPrice(v.price * v.qty)}</span> 1248 </div>` 1249 ).join(''); 1250 1251 if (totalEl) { totalEl.textContent = window.formatPrice(grandTotal); } 1252 updateBadges(); 1253 }; 1254 1255 // Qty / remove actions 1256 rowsEl?.addEventListener('click', e => { 1257 const btn = e.target.closest('[data-action]'); 1258 if (!btn) { return; } 1259 const { action, id } = btn.dataset;
1260 if (action === 'inc') { 1261 if (state[id]) { state[id].qty += 1; } 1262 } else if (action === 'dec') { 1263 if (state[id]) { 1264 state[id].qty = Math.max(0, state[id].qty - 1); 1265 if (state[id].qty === 0) { delete state[id]; } 1266 } 1267 } else if (action === 'remove') { 1268 delete state[id]; 1269 } 1270 save(); 1271 render(); 1272 }); 1273 1274 // Re-sync stale cart data (price / availability may have changed) before showing it, 1275 // then surface a notice about anything that changed / was removed. 1276 if (window.AlphadiCartSync) { 1277 window.AlphadiCartSync.applyTo(state).then(function (r) { 1278 render(); 1279 window.AlphadiCartSync.showNotice(r, document.getElementById('cartPageNotice')); 1280 }); 1281 } else { 1282 render(); 1283 } 1284})(); 1285</script>
1285 1286 1287 1288 1289 <!-- Cart FAB (mobile) --> 1290 <button class="cart-fab cart-btn" id="cartFab" aria-label="Cart"> 1291 <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M6 2L3 6v14a2 2 0 002 2h14a2 2 0 002-2V6l-3-4z"/><line x1="3" y1="6" x2="21" y2="6"/><path d="M16 10a4 4 0 01-8 0"/></svg> 1292 <span class="cart-fab__badge cart-badge">0</span> 1293 </button> 1294 1295 <!-- Cart Overlay + Drawer --> 1296 <div class="cart-overlay" id="cartOverlay"></div> 1297 <div class="cart-drawer" id="cartDrawer" 1298 data-label-empty="Your cart is empty." 1299 data-label-remove="Remove" 1300 data-label-order="Order now" 1301 data-label-continue="Continue shopping" 1302 data-label-unit="unit" 1303 data-label-required="This option is required."> 1304 <div class="cart-drawer__head"> 1305 <span class="cart-drawer__title">Cart</span> 1306 <button class="cart-drawer__close" id="cartClose">✕</button> 1307 </div> 1308 <div class="cart-drawer__notice" id="cartNotice" style="display:none;padding:0.9rem 1.1rem 0;" 1309 data-msg-title="Your cart was updated" 1310 data-msg-removed="{name} is no longer available and was removed." 1311 data-msg-repriced="Price of {name} changed to {price}."></div> 1312 <div class="cart-drawer__body" id="cartBody"></div> 1313 <div class="cart-drawer__foot" id="cartFoot" style="display:none;"> 1314 <div class="cart-subtotal"> 1315 <span class="cart-subtotal__label">Total</span> 1316 <span class="cart-subtotal__amount" id="cartTotal">0,00 €</span> 1317 </div> 1318 <a href="/en/cart" class="btn btn--primary btn--lg" style="width:100%;justify-content:center;">View cart</a> 1319 <button class="cart-continue" id="cartContinue">Continue shopping</button> 1320 </div> 1321 </div> 1322 1323 1324<div class="modal-overlay" id="bookingRequestModal"> 1325 <div class="modal" role="dialog" aria-modal="true" aria-labelledby="bookingRequestModalTitle"> 1326 <button type="button" class="modal__close" data-booking-request-close aria-label="Close">×</button> 1327 <div class="modal__title" id="bookingRequestModalTitle">Reserve a seat</div> 1328 <p style="font-family:var(--f-ui);font-size:0.875rem;color:var(--c-mid);margin-bottom:1.5rem;"> 1329 <strong id="bookingRequestProduct"></strong> 1330 <span id="bookingRequestFormat"></span> 1331 </p> 1332 <form id="bookingRequestForm" novalidate> 1333 <div class="form-group"> 1334 <label class="form-label">First name *</label> 1335 <input type="text" class="form-input" name="firstName" required /> 1336 <div class="field-error"></div> 1337 </div> 1338 <div class="form-group"> 1339 <label class="form-label">Last name *</label> 1340 <input type="text" class="form-input" name="lastName" required /> 1341 <div class="field-error"></div> 1342 </div> 1343 <div class="form-group"> 1344 <label class="form-label">Company *</label> 1345 <input type="text" class="form-input" name="company" required /> 1346 <div class="field-error"></div> 1347 </div> 1348 <div class="form-group"> 1349 <label class="form-label">Email *</label> 1350 <input type="email" class="form-input" name="email" required /> 1351 <div class="field-error"></div> 1352 </div> 1353 <div class="form-group"> 1354 <label class="form-label">Phone *</label> 1355 <input type="tel" class="form-input" name="phone" required /> 1356 <div class="field-error"></div> 1357 </div> 1358 <div class="form-group"> 1359 <label class="form-label">Notes / special requirements</label> 1360 <textarea class="form-textarea" name="notes" rows="3"></textarea> 1361 </div> 1362 <div class="checkout-check-field"> 1363 <label class="checkout-check-label"> 1364 <input type="checkbox" id="br-terms" name="terms" />
1365 <span> 1366 I have read the 1367 <a href="/en/t&c" target="_blank" rel="noopener">Terms & Conditions</a> 1368 and agree to them. <span class="req">*</span> 1369 </span> 1370 </label> 1371 <span class="field-error fw-bold text-danger" id="brTermsError"></span> 1372 </div> 1373 <div class="checkout-check-field"> 1374 <label class="checkout-check-label"> 1375 <input type="checkbox" id="br-privacy" name="privacy" /> 1376 <span> 1377 I have read the 1378 <a href="/en/privacy-policy" target="_blank" rel="noopener">Privacy Policy</a> 1379 and agree that my data will be processed. <span class="req">*</span> 1380 </span> 1381 </label> 1382 <span class="field-error fw-bold text-danger" id="brPrivacyError"></span> 1383 </div> 1384 1385 <div class="field-error" id="bookingRequestFormError" style="margin-bottom:.75rem;"></div> 1386 <button type="submit" class="btn btn--primary" style="width:100%;justify-content:center;"> 1387 Send booking request 1388 </button> 1389 </form> 1390 </div> 1391</div> 1392
1393<script> 1394(function () { 1395 'use strict'; 1396 1397 var overlay = document.getElementById('bookingRequestModal'); 1398 var form = document.getElementById('bookingRequestForm'); 1399 if (!overlay || !form) { return; } 1400 1401 var productEl = document.getElementById('bookingRequestProduct'); 1402 var formatEl = document.getElementById('bookingRequestFormat'); 1403 var formError = document.getElementById('bookingRequestFormError'); 1404 var pending = null; 1405 var submitting = false; 1406 1407 var POST_URL = '/en/cart/submit-booking-request'; 1408 var MSG_REQUIRED = "This field is required."; 1409 var MSG_EMAIL = "Please enter a valid e-mail address."; 1410 var MSG_ERROR = "An error occurred. Please try again."; 1411 var MSG_TERMS = "You must agree to the Terms & Conditions to continue."; 1412 var MSG_PRIVACY = "You must agree to the Privacy Policy to continue."; 1413 1414 function isEmail(v) { return /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/.test((v || '').trim()); } 1415 1416 function openModal(data) { 1417 pending = data; 1418 productEl.textContent = data.name || ''; 1419 formatEl.innerHTML = data.format ? (' · ' + data.format) : ''; 1420 form.reset(); 1421 formError.textContent = ''; 1422 form.querySelectorAll('.is-invalid').forEach(function (el) { el.classList.remove('is-invalid'); }); 1423 form.querySelectorAll('.field-error').forEach(function (el) { el.textContent = ''; }); 1424 overlay.classList.add('is-open'); 1425 document.body.style.overflow = 'hidden'; 1426 setTimeout(function () { form.querySelector('[name=firstName]')?.focus(); }, 50); 1427 } 1428 1429 function closeModal() { 1430 overlay.classList.remove('is-open'); 1431 document.body.style.overflow = ''; 1432 pending = null; 1433 } 1434 1435 overlay.addEventListener('click', function (e) { 1436 if (e.target === overlay) { closeModal(); } 1437 }); 1438 overlay.querySelectorAll('[data-booking-request-close]').forEach(function (b) { 1439 b.addEventListener('click', closeModal); 1440 }); 1441 document.addEventListener('keydown', function (e) { 1442 if (e.key === 'Escape' && overlay.classList.contains('is-open')) { closeModal(); } 1443 }); 1444 1445 // Capture-phase interception so we beat both the cart booking modal and the global add-to-cart handler. 1446 document.addEventListener('click', function (e) { 1447 var btn = e.target.closest('[data-add-to-cart][data-cart-type]'); 1448 if (!btn) { return; } 1449 if (btn.dataset.onlyBooking !== 'true') { return; } // not an OnlyBooking appointment â let the cart flow run 1450 var type = btn.dataset.cartType; 1451 if (type !== 'training' && type !== 'event') { return; } 1452 if (btn.disabled) { return; } 1453 e.preventDefault(); 1454 e.stopImmediatePropagation(); 1455 openModal({ 1456 id: btn.dataset.addToCart, 1457 type: type, 1458 name: btn.dataset.cartName || btn.dataset.addToCart, 1459 format: btn.dataset.cartFormat || '', 1460 }); 1461 }, true); 1462 1463 function showErr(field, msg) { 1464 field.classList.add('is-invalid'); 1465 var s = field.parentElement.querySelector('.field-error'); 1466 if (s) { s.textContent = msg; } 1467 } 1468 function clearErr(field) { 1469 field.classList.remove('is-invalid'); 1470 var s = field.parentElement.querySelector('.field-error'); 1471 if (s) { s.textContent = ''; } 1472 } 1473 function validate(field) { 1474 var val = (field.value || '').trim(); 1475 if (field.hasAttribute('required') && !val) { showErr(field, MSG_REQUIRED); return false; } 1476 if (field.type === 'email' && val && !isEmail(val)) { showErr(field, MSG_EMAIL); return false; } 1477 clearErr(field); return true; 1478 } 1479 1480 form.querySelectorAll('input, textarea').forEach(function (f) { 1481 f.addEventListener('blur', function () { validate(f); }); 1482 f.addEventListener('input', function () { if (f.classList.contains('is-invalid')) { clearErr(f); } }); 1483 }); 1484 1485 form.addEventListener('submit', function (e) { 1486 e.preventDefault(); 1487 if (!pending || submitting) { return; } 1488 formError.textContent = ''; 1489 var ok = true; 1490 form.querySelectorAll('input[required], input[type=email]').forEach(function (f) { 1491 if (!validate(f)) { ok = false; } 1492 }); 1493 1494 var termsCb = document.getElementById('br-terms'); 1495 var termsErr = document.getElementById('brTermsError'); 1496 if (termsCb) { 1497 if (!termsCb.checked) { 1498 termsCb.classList.add('is-invalid'); 1499 if (termsErr) { termsErr.textContent = MSG_TERMS; } 1500 ok = false; 1501 } else { 1502 termsCb.classList.remove('is-invalid'); 1503 if (termsErr) { termsErr.textContent = ''; } 1504 } 1505 } 1506 1507 var privacyCb = document.getElementById('br-privacy'); 1508 var privacyErr = document.getElementById('brPrivacyError'); 1509 if (!privacyCb.checked) { 1510 privacyCb.classList.add('is-invalid'); 1511 if (privacyErr) { privacyErr.textContent = MSG_PRIVACY; } 1512 ok = false; 1513 } else { 1514 privacyCb.classList.remove('is-invalid'); 1515 if (privacyErr) { privacyErr.textContent = ''; } 1516 } 1517 1518 if (!ok) { return; } 1519 1520 var fd = new FormData(form); 1521 var payload = {
1522 id: pending.id, 1523 type: pending.type, 1524 firstName: (fd.get('firstName') || '').trim(), 1525 lastName: (fd.get('lastName') || '').trim(), 1526 company: (fd.get('company') || '').trim(), 1527 email: (fd.get('email') || '').trim(), 1528 phone: (fd.get('phone') || '').trim(), 1529 notes: (fd.get('notes') || '').trim(), 1530 }; 1531 1532 submitting = true; 1533 var submitBtn = form.querySelector('button[type=submit]'); 1534 if (submitBtn) { submitBtn.disabled = true; } 1535 1536 fetch(POST_URL, { 1537 method: 'POST', 1538 headers: { 'Content-Type': 'application/json' }, 1539 body: JSON.stringify(payload), 1540 }).then(function (res) { 1541 return res.ok ? res.json() : Promise.reject(res); 1542 }).then(function (data) { 1543 if (data && data.redirectUrl) { 1544 window.location = data.redirectUrl; 1545 } else { 1546 window.location.reload(); 1547 } 1548 }).catch(function () { 1549 submitting = false; 1550 if (submitBtn) { submitBtn.disabled = false; } 1551 formError.textContent = MSG_ERROR; 1552 }); 1553 }); 1554})(); 1555</script>
1555 1556 1557 1558<div class="modal-overlay" id="bookingModal"> 1559 <div class="modal" role="dialog" aria-modal="true" aria-labelledby="bookingModalTitle"> 1560 <button type="button" class="modal__close" data-booking-close aria-label="Close">×</button> 1561 <div class="modal__title" id="bookingModalTitle">Reserve a seat</div> 1562 <p style="font-family:var(--f-ui);font-size:0.875rem;color:var(--c-mid);margin-bottom:1.5rem;"> 1563 <strong id="bookingModalProduct"></strong> 1564 <span id="bookingModalFormat"></span> 1565 </p> 1566 <form id="bookingForm" novalidate> 1567 <div class="form-group"> 1568 <label class="form-label">First name *</label> 1569 <input type="text" class="form-input" name="participantFirstName" required /> 1570 <div class="field-error"></div> 1571 </div> 1572 <div class="form-group"> 1573 <label class="form-label">Last name *</label> 1574 <input type="text" class="form-input" name="participantLastName" required /> 1575 <div class="field-error"></div> 1576 </div> 1577 <div class="form-group"> 1578 <label class="form-label">Company *</label> 1579 <input type="text" class="form-input" name="participantCompany" required /> 1580 <div class="field-error"></div> 1581 </div> 1582 <div class="form-group"> 1583 <label class="form-label">Email *</label> 1584 <input type="email" class="form-input" name="participantEmail" required /> 1585 <div class="field-error"></div> 1586 </div> 1587 <div class="form-group"> 1588 <label class="form-label">Phone *</label> 1589 <input type="tel" class="form-input" name="participantPhone" required /> 1590 <div class="field-error"></div> 1591 </div> 1592 <div class="form-group"> 1593 <label class="form-label">Notes / special requirements</label> 1594 <textarea class="form-textarea" name="participantNotes" rows="3"></textarea> 1595 </div> 1596 <button type="submit" class="btn btn--primary" style="width:100%;justify-content:center;"> 1597 Add to cart 1598 </button> 1599 </form> 1600 </div> 1601</div> 1602
1603<script> 1604(function () { 1605 'use strict'; 1606 1607 var overlay = document.getElementById('bookingModal'); 1608 var form = document.getElementById('bookingForm'); 1609 if (!overlay || !form) { return; } 1610 1611 var productEl = document.getElementById('bookingModalProduct'); 1612 var formatEl = document.getElementById('bookingModalFormat'); 1613 var pending = null; 1614 1615 var MSG_REQUIRED = 'This field is required.'; 1616 var MSG_EMAIL = 'Please enter a valid e-mail address.'; 1617 1618 function isEmail(v) { return /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/.test((v || '').trim()); } 1619 1620 function openModal(data) { 1621 pending = data; 1622 productEl.textContent = data.name || ''; 1623 formatEl.innerHTML = data.format ? (' · ' + data.format) : ''; 1624 form.reset(); 1625 form.querySelectorAll('.is-invalid').forEach(function (el) { el.classList.remove('is-invalid'); }); 1626 form.querySelectorAll('.field-error').forEach(function (el) { el.textContent = ''; }); 1627 overlay.classList.add('is-open'); 1628 document.body.style.overflow = 'hidden'; 1629 setTimeout(function () { form.querySelector('[name=participantFirstName]')?.focus(); }, 50); 1630 } 1631 1632 function closeModal() { 1633 overlay.classList.remove('is-open'); 1634 document.body.style.overflow = ''; 1635 pending = null; 1636 } 1637 1638 overlay.addEventListener('click', function (e) { 1639 if (e.target === overlay) { closeModal(); } 1640 }); 1641 overlay.querySelectorAll('[data-booking-close]').forEach(function (b) { 1642 b.addEventListener('click', closeModal); 1643 }); 1644 document.addEventListener('keydown', function (e) { 1645 if (e.key === 'Escape' && overlay.classList.contains('is-open')) { closeModal(); } 1646 }); 1647 1648 // Intercept add-to-cart clicks for trainings/events so we collect participant info first. 1649 document.addEventListener('click', function (e) { 1650 var btn = e.target.closest('[data-add-to-cart][data-cart-type]'); 1651 if (!btn) { return; } 1652 var type = btn.dataset.cartType; 1653 if (type !== 'training' && type !== 'event') { return; } 1654 // OnlyBooking appointments are handled by the separate "Send booking request" modal. 1655 if (btn.dataset.onlyBooking === 'true') { return; } 1656 if (btn.disabled) { return; } 1657 e.preventDefault(); 1658 e.stopImmediatePropagation(); 1659 openModal({ 1660 id: btn.dataset.addToCart, 1661 name: btn.dataset.cartName || btn.dataset.addToCart, 1662 price: btn.dataset.cartPrice || '0', 1663 format: btn.dataset.cartFormat || '', 1664 image: btn.dataset.cartImage || '', 1665 type: type, 1666 }); 1667 }, true); // capture phase so we beat the global add-to-cart handler 1668 1669 function showErr(field, msg) { 1670 field.classList.add('is-invalid'); 1671 var s = field.parentElement.querySelector('.field-error'); 1672 if (s) { s.textContent = msg; } 1673 } 1674 function clearErr(field) { 1675 field.classList.remove('is-invalid'); 1676 var s = field.parentElement.querySelector('.field-error'); 1677 if (s) { s.textContent = ''; } 1678 } 1679 function validate(field) { 1680 var val = (field.value || '').trim(); 1681 if (field.hasAttribute('required') && !val) { showErr(field, MSG_REQUIRED); return false; } 1682 if (field.type === 'email' && val && !isEmail(val)) { showErr(field, MSG_EMAIL); return false; } 1683 clearErr(field); return true; 1684 } 1685 1686 form.querySelectorAll('input, textarea').forEach(function (f) { 1687 f.addEventListener('blur', function () { validate(f); }); 1688 f.addEventListener('input', function () { if (f.classList.contains('is-invalid')) { clearErr(f); } }); 1689 }); 1690 1691 form.addEventListener('submit', function (e) { 1692 e.preventDefault(); 1693 if (!pending) { return; } 1694 var ok = true; 1695 form.querySelectorAll('input[required], input[type=email]').forEach(function (f) { 1696 if (!validate(f)) { ok = false; } 1697 }); 1698 if (!ok) { return; } 1699 1700 var fd = new FormData(form); 1701 var firstName = (fd.get('participantFirstName') || '').trim(); 1702 var lastName = (fd.get('participantLastName') || '').trim(); 1703 var participant = { 1704 firstName: firstName, 1705 lastName: lastName, 1706 // Combined name kept for the mini-cart display (and legacy back-compat). 1707 name: (firstName + ' ' + lastName).trim(), 1708 company: (fd.get('participantCompany') || '').trim(), 1709 email: (fd.get('participantEmail') || '').trim(), 1710 phone: (fd.get('participantPhone') || '').trim(), 1711 notes: (fd.get('participantNotes') || '').trim(), 1712 }; 1713 1714 if (typeof window.alphadiAddBookingToCart === 'function') { 1715 window.alphadiAddBookingToCart(pending, participant); 1716 } 1717 closeModal(); 1718 });
1719})(); 1720</script>
1720 1721 1722 1723<div class="modal-overlay" id="requestModal"> 1724 <div class="modal" role="dialog" aria-modal="true" aria-labelledby="requestModalTitle"> 1725 <button type="button" class="modal__close" data-request-close aria-label="Close">×</button> 1726 <div class="modal__title" id="requestModalTitle">Request</div> 1727 <p style="font-family:var(--f-ui);font-size:0.875rem;color:var(--c-mid);margin-bottom:1.5rem;"> 1728 <strong id="requestModalProduct"></strong> 1729 </p> 1730 <form id="requestForm" novalidate> 1731 <input type="hidden" name="itemName" id="requestItemName" /> 1732 <div class="form-group"> 1733 <label class="form-label">First name *</label> 1734 <input type="text" class="form-input" name="firstName" required /> 1735 <div class="field-error"></div> 1736 </div> 1737 <div class="form-group"> 1738 <label class="form-label">Last name *</label> 1739 <input type="text" class="form-input" name="lastName" required /> 1740 <div class="field-error"></div> 1741 </div> 1742 <div class="form-group"> 1743 <label class="form-label">Company</label> 1744 <input type="text" class="form-input" name="company" /> 1745 <div class="field-error"></div> 1746 </div> 1747 <div class="form-group"> 1748 <label class="form-label">Email *</label> 1749 <input type="email" class="form-input" name="email" required /> 1750 <div class="field-error"></div> 1751 </div> 1752 <div class="form-group"> 1753 <label class="form-label">Phone *</label> 1754 <input type="tel" class="form-input" name="phone" required /> 1755 <div class="field-error"></div> 1756 </div> 1757 <div class="form-group"> 1758 <label class="form-label">Message</label> 1759 <textarea class="form-textarea" name="message" rows="3"></textarea> 1760 </div> 1761 <div id="requestFormStatus" style="display:none;margin-bottom:1rem;font-family:var(--f-ui);font-size:0.875rem;"></div> 1762 1763 <div class="checkout-check-field"> 1764 <label class="checkout-check-label"> 1765 <input type="checkbox" id="req-terms" name="terms" /> 1766 <span> 1767 I have read the 1768 <a href="/en/t&c" target="_blank" rel="noopener">Terms & Conditions</a> 1769 and agree to them. <span class="req">*</span> 1770 </span> 1771 </label> 1772 <span class="field-error fw-bold text-danger" id="reqTermsError"></span> 1773 </div> 1774 <div class="checkout-check-field"> 1775 <label class="checkout-check-label"> 1776 <input type="checkbox" id="req-privacy" name="privacy" /> 1777 <span> 1778 I have read the 1779 <a href="/en/privacy-policy" target="_blank" rel="noopener">Privacy Policy</a> 1780 and agree that my data will be processed. <span class="req">*</span> 1781 </span> 1782 </label> 1783 <span class="field-error fw-bold text-danger" id="reqPrivacyError"></span> 1784 </div> 1785 1786 <button type="submit" class="btn btn--primary" style="width:100%;justify-content:center;"> 1787 Send request 1788 </button> 1789 </form> 1790 </div> 1791</div> 1792
1793<script> 1794(function () { 1795 'use strict'; 1796 1797 var overlay = document.getElementById('requestModal'); 1798 var form = document.getElementById('requestForm'); 1799 var productEl = document.getElementById('requestModalProduct'); 1800 var itemNameEl = document.getElementById('requestItemName'); 1801 var statusEl = document.getElementById('requestFormStatus'); 1802 if (!overlay || !form) { return; } 1803 1804 var MSG_REQUIRED = "This field is required."; 1805 var MSG_EMAIL = "Please enter a valid e-mail address."; 1806 var MSG_SUCCESS = "Your request has been sent. We will get back to you shortly."; 1807 var MSG_ERROR = "Something went wrong. Please try again."; 1808 var MSG_TERMS = "You must agree to the Terms & Conditions to continue."; 1809 var MSG_PRIVACY = "You must agree to the Privacy Policy to continue."; 1810 1811 function isEmail(v) { return /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/.test((v || '').trim()); } 1812 1813 function openModal(name) { 1814 if (productEl) { productEl.textContent = name || ''; } 1815 if (itemNameEl) { itemNameEl.value = name || ''; } 1816 form.reset(); 1817 if (itemNameEl) { itemNameEl.value = name || ''; } 1818 form.querySelectorAll('.is-invalid').forEach(function (el) { el.classList.remove('is-invalid'); }); 1819 form.querySelectorAll('.field-error').forEach(function (el) { el.textContent = ''; }); 1820 statusEl.style.display = 'none'; 1821 statusEl.textContent = ''; 1822 overlay.classList.add('is-open'); 1823 document.body.style.overflow = 'hidden'; 1824 setTimeout(function () { form.querySelector('[name=firstName]')?.focus(); }, 50); 1825 } 1826 1827 function closeModal() { 1828 overlay.classList.remove('is-open'); 1829 document.body.style.overflow = ''; 1830 } 1831 1832 overlay.addEventListener('click', function (e) { 1833 if (e.target === overlay) { closeModal(); } 1834 }); 1835 overlay.querySelectorAll('[data-request-close]').forEach(function (b) { 1836 b.addEventListener('click', closeModal); 1837 }); 1838 document.addEventListener('keydown', function (e) { 1839 if (e.key === 'Escape' && overlay.classList.contains('is-open')) { closeModal(); } 1840 }); 1841 1842 document.addEventListener('click', function (e) { 1843 var btn = e.target.closest('[data-open-request-modal]'); 1844 if (!btn) { return; } 1845 e.preventDefault(); 1846 openModal(btn.dataset.openRequestModal || ''); 1847 }); 1848 1849 // Per-date "By invoice" toggle â expands the inline note ("Inquire here â¦") within the 1850 // booking box; the link inside it opens this modal. 1851 document.addEventListener('click', function (e) { 1852 var toggle = e.target.closest('[data-invoice-toggle]'); 1853 if (!toggle) { return; } 1854 var item = toggle.closest('[data-date-item]'); 1855 if (item) { item.classList.toggle('is-open'); } 1856 }); 1857 1858 function showErr(field, msg) { 1859 field.classList.add('is-invalid'); 1860 var s = field.parentElement.querySelector('.field-error'); 1861 if (s) { s.textContent = msg; } 1862 } 1863 function clearErr(field) { 1864 field.classList.remove('is-invalid'); 1865 var s = field.parentElement.querySelector('.field-error'); 1866 if (s) { s.textContent = ''; } 1867 } 1868 function validate(field) { 1869 var val = (field.value || '').trim(); 1870 if (field.hasAttribute('required') && !val) { showErr(field, MSG_REQUIRED); return false; } 1871 if (field.type === 'email' && val && !isEmail(val)) { showErr(field, MSG_EMAIL); return false; } 1872 clearErr(field); return true; 1873 } 1874 1875 form.querySelectorAll('input, textarea').forEach(function (f) { 1876 f.addEventListener('blur', function () { validate(f); }); 1877 f.addEventListener('input', function () { if (f.classList.contains('is-invalid')) { clearErr(f); } }); 1878 }); 1879 1880 form.addEventListener('submit', function (e) { 1881 e.preventDefault(); 1882 var ok = true; 1883 form.querySelectorAll('input[required], input[type=email]').forEach(function (f) { 1884 if (!validate(f)) { ok = false; } 1885 }); 1886 1887 var termsCb = document.getElementById('req-terms'); 1888 var termsErr = document.getElementById('reqTermsError'); 1889 if (termsCb) { 1890 if (!termsCb.checked) { 1891 termsCb.classList.add('is-invalid'); 1892 if (termsErr) { termsErr.textContent = MSG_TERMS; } 1893 ok = false; 1894 } else { 1895 termsCb.classList.remove('is-invalid'); 1896 if (termsErr) { termsErr.textContent = ''; } 1897 } 1898 } 1899 1900 var privacyCb = document.getElementById('req-privacy'); 1901 var privacyErr = document.getElementById('reqPrivacyError'); 1902 if (!privacyCb.checked) { 1903 privacyCb.classList.add('is-invalid'); 1904 if (privacyErr) { privacyErr.textContent = MSG_PRIVACY; } 1905 ok = false; 1906 } else { 1907 privacyCb.classList.remove('is-invalid'); 1908 if (privacyErr) { privacyErr.textContent = ''; } 1909 } 1910 1911 if (!ok) { return; } 1912 1913 var submitBtn = form.querySelector('[type=submit]'); 1914 submitBtn.disabled = true; 1915 1916 var fd = new FormData(form); 1917 var payload = { 1918 itemName: (fd.get('itemName') || '').trim(), 1919 firstName: (fd.get('firstName') || '').trim(), 1920 lastName: (fd.get('lastName') || '').trim(), 1921 company: (fd.get('company') || '').trim(), 1922 email: (fd.get('email') || '').trim(), 1923 phone: (fd.get('phone') || '').trim(), 1924 message: (fd.get('message') || '').trim(), 1925 }; 1926 1927 fetch('/Home/SendRequest', { 1928 method: 'POST', 1929 headers: { 'Content-Type': 'application/json' }, 1930 body: JSON.stringify(payload), 1931 }) 1932 .then(function (r) { return r.json(); }) 1933 .then(function (data) { 1934 if (data.success) { 1935 if (data.redirectUrl) { 1936 window.location.href = data.redirectUrl; 1937 } else { 1938 statusEl.style.display = 'block'; 1939 statusEl.style.color = 'var(--c-green, green)'; 1940 statusEl.textContent = MSG_SUCCESS; 1941 form.querySelectorAll('input, textarea, button[type=submit]').forEach(function (el) { el.disabled = true; }); 1942 } 1943 } else { 1944 statusEl.style.display = 'block'; 1945 statusEl.style.color = 'var(--c-error, red)'; 1946 statusEl.textContent = data.message || MSG_ERROR; 1947 submitBtn.disabled = false; 1948 } 1949 }) 1950 .catch(function () { 1951 statusEl.style.display = 'block'; 1952 statusEl.style.color = 'var(--c-error, red)'; 1953 statusEl.textContent = MSG_ERROR; 1954 submitBtn.disabled = false; 1955 }); 1956 });
1957})(); 1958</script>
1958 1959 1960 1961<div class="modal-overlay" id="productFeatureModal"> 1962 <div class="modal" role="dialog" aria-modal="true" aria-labelledby="productFeatureModalTitle" style="max-width:560px;"> 1963 <button type="button" class="modal__close" data-pf-close aria-label="Close">×</button> 1964 <div class="modal__title" id="productFeatureModalTitle">Choose options</div> 1965 <p style="font-family:var(--f-ui);font-size:0.875rem;color:var(--c-mid);margin-bottom:1.25rem;"> 1966 <strong id="pfModalProduct"></strong> 1967 </p> 1968 1969 <div id="pfModalBody"></div> 1970 1971 <div style="display:flex;align-items:baseline;justify-content:space-between;gap:1rem;margin:1.25rem 0 1rem;padding-top:1rem;border-top:1px solid var(--c-border);"> 1972 <span style="font-family:var(--f-ui);font-size:0.8rem;font-weight:600;letter-spacing:0.08em;text-transform:uppercase;color:var(--c-subtle);">Total</span> 1973 <span id="pfModalTotal" style="font-family:var(--f-display);font-size:1.75rem;font-weight:700;color:var(--c-orange);line-height:1;">0,00 €</span> 1974 </div> 1975 1976 <button type="button" id="pfModalSubmit" class="btn btn--primary" style="width:100%;justify-content:center;"> 1977 Add to cart 1978 </button> 1979 </div> 1980</div> 1981
1982<script> 1983(function () { 1984 'use strict'; 1985 1986 var overlay = document.getElementById('productFeatureModal'); 1987 if (!overlay) { return; } 1988 1989 var productEl = document.getElementById('pfModalProduct'); 1990 var bodyEl = document.getElementById('pfModalBody'); 1991 var totalEl = document.getElementById('pfModalTotal'); 1992 var submitBtn = document.getElementById('pfModalSubmit'); 1993 1994 var MSG_REQUIRED = 'Please select an option.'; 1995 1996 var pending = null; // { id, name, basePrice, image, shippableMap } 1997 var features = []; // [{ name, isRequired, options: [...] }] 1998 var selected = {}; // { [featureIndex]: { name, price, isShippable } } 1999 2000 function fmtPrice(v) { 2001 return window.formatPrice 2002 ? window.formatPrice(v) 2003 : '\u20AC' + (v < 0 ? '-' + Math.abs(v).toFixed(2) : v.toFixed(2)); 2004 } 2005 2006 // Build shippability lookup from raw DB JSON (PascalCase, all feature types). 2007 // Returns map[listFeatureIndex][optionIndex] = bool 2008 function buildShippableMap(rawJson) { 2009 var map = {}; 2010 try { 2011 var all = JSON.parse(rawJson || '[]'); 2012 var listIdx = 0; 2013 all.forEach(function (f) { 2014 if ((f.Type !== undefined ? f.Type : f.type) !== 0) { return; } 2015 var fi = listIdx++; 2016 map[fi] = {}; 2017 (f.Options || f.options || []).forEach(function (o, oi) { 2018 map[fi][oi] = !!(o.IsShippable || o.isShippable); 2019 }); 2020 }); 2021 } catch (e) {} 2022 return map; 2023 } 2024 2025 function recalcTotal() { 2026 var delta = 0; 2027 Object.keys(selected).forEach(function (k) { delta += selected[k].price; }); 2028 var total = Math.max(0, pending.basePrice + delta); 2029 totalEl.textContent = fmtPrice(total); 2030 return total; 2031 } 2032 2033 function renderBody() { 2034 selected = {}; 2035 if (!features.length) { bodyEl.innerHTML = ''; return; } 2036 var sm = (pending && pending.shippableMap) || {}; 2037 2038 bodyEl.innerHTML = features.map(function (f, fi) { 2039 var opts = (f.options || []).map(function (o, oi) { 2040 var deltaHtml = ''; 2041 if (o.price > 0) { deltaHtml = '<span class="product-fmt-card__delta">+' + fmtPrice(o.price) + '</span>'; } 2042 else if (o.price < 0) { deltaHtml = '<span class="product-fmt-card__delta product-fmt-card__delta--down">' + fmtPrice(o.price) + '</span>'; } 2043 2044 var badgeHtml = o.badgeText 2045 ? '<span class="product-fmt-card__badge">' + o.badgeText + '</span>' 2046 : ''; 2047 2048 var isShippable = !!(sm[fi] && sm[fi][oi]); 2049 var isDefault = !!o.isDefault; 2050 if (isDefault) { 2051 selected[fi] = { name: o.name, price: parseFloat(o.price) || 0, isShippable: isShippable }; 2052 } 2053 2054 return '<label class="product-fmt-card' + (isDefault ? ' is-selected' : '') + '"' + 2055 ' data-feature-index="' + fi + '"' + 2056 ' data-option-index="' + oi + '"' + 2057 ' data-option-name="' + (o.name || '').replace(/"/g, '"') + '"' + 2058 ' data-option-price="' + (parseFloat(o.price) || 0) + '"' + 2059 ' data-option-shippable="' + (isShippable ? 'true' : 'false') + '">' + 2060 '<input type="radio" name="pf-' + fi + '" ' + (isDefault ? 'checked' : '') + ' style="display:none">' + 2061 '<div class="product-fmt-card__name">' + (o.name || '') + ' ' + badgeHtml + '</div>' +
2062 (deltaHtml ? '<div class="product-fmt-card__meta">' + deltaHtml + '</div>' : '') + 2063 '</label>'; 2064 }).join(''); 2065 2066 return '<div class="product-fmt-group" data-feature-index="' + fi + '" data-feature-required="' + (f.isRequired ? 'true' : 'false') + '">' + 2067 '<div class="product-fmt-group__label">' + 2068 (f.name || '') + 2069 (f.isRequired ? '<span class="product-fmt-group__req" title="Required">*</span>' : '') + 2070 '</div>' + 2071 '<div class="product-fmt-grid">' + opts + '</div>' + 2072 '<div class="product-fmt-error"></div>' + 2073 '</div>'; 2074 }).join(''); 2075 } 2076 2077 function openModal(data, parsedFeatures, shippableMap) { 2078 pending = data; 2079 pending.shippableMap = shippableMap || {}; 2080 features = parsedFeatures || []; 2081 productEl.textContent = data.name || ''; 2082 renderBody(); 2083 recalcTotal(); 2084 overlay.classList.add('is-open'); 2085 document.body.style.overflow = 'hidden'; 2086 } 2087 2088 function closeModal() { 2089 overlay.classList.remove('is-open'); 2090 document.body.style.overflow = ''; 2091 pending = null; 2092 features = []; 2093 selected = {}; 2094 } 2095 2096 overlay.addEventListener('click', function (e) { 2097 if (e.target === overlay) { closeModal(); } 2098 }); 2099 overlay.querySelectorAll('[data-pf-close]').forEach(function (b) { 2100 b.addEventListener('click', closeModal); 2101 }); 2102 document.addEventListener('keydown', function (e) { 2103 if (e.key === 'Escape' && overlay.classList.contains('is-open')) { closeModal(); } 2104 }); 2105 2106 bodyEl.addEventListener('click', function (e) { 2107 var card = e.target.closest('.product-fmt-card'); 2108 if (!card) { return; } 2109 var fi = card.dataset.featureIndex; 2110 var group = card.closest('.product-fmt-group'); 2111 if (group) { 2112 group.querySelectorAll('.product-fmt-card').forEach(function (c) { c.classList.remove('is-selected', 'is-error'); }); 2113 var errEl = group.querySelector('.product-fmt-error'); 2114 if (errEl) { errEl.textContent = ''; } 2115 } 2116 card.classList.add('is-selected'); 2117 var input = card.querySelector('input[type=radio]'); 2118 if (input) { input.checked = true; } 2119 selected[fi] = { 2120 name: card.dataset.optionName, 2121 price: parseFloat(card.dataset.optionPrice) || 0, 2122 isShippable: card.dataset.optionShippable === 'true', 2123 }; 2124 recalcTotal(); 2125 }); 2126 2127 submitBtn.addEventListener('click', function () { 2128 if (!pending) { return; } 2129 2130 var ok = true; 2131 bodyEl.querySelectorAll('.product-fmt-group[data-feature-required="true"]').forEach(function (group) { 2132 var fi = group.dataset.featureIndex; 2133 var errEl = group.querySelector('.product-fmt-error'); 2134 if (!selected[fi]) { 2135 if (errEl) { errEl.textContent = MSG_REQUIRED; } 2136 group.querySelectorAll('.product-fmt-card').forEach(function (c) { c.classList.add('is-error'); }); 2137 ok = false; 2138 } 2139 }); 2140 if (!ok) { return; } 2141 2142 var finalPrice = recalcTotal(); 2143 var parts = []; 2144 features.forEach(function (f, fi) { if (selected[fi]) { parts.push(selected[fi].name); } }); 2145 var finalFormat = parts.join(', ') || (pending.format || ''); 2146 var isShippable = Object.values(selected).some(function (s) { return s.isShippable; }); 2147 2148 if (typeof window.alphadiAddProductToCart === 'function') { 2149 window.alphadiAddProductToCart({ 2150 id: pending.id, 2151 name: pending.name, 2152 price: finalPrice, 2153 format: finalFormat, 2154 image: pending.image, 2155 isShippable: isShippable, 2156 }); 2157 } 2158 closeModal(); 2159 });
2160 2161 // Intercept add-to-cart clicks for products that ship feature data. 2162 document.addEventListener('click', function (e) { 2163 var btn = e.target.closest('[data-add-to-cart][data-cart-type="product"]'); 2164 if (!btn) { return; } 2165 if (btn.disabled) { return; } 2166 2167 var raw = btn.dataset.cartFeatures; 2168 if (!raw) { return; } // no features â fall through to global handler 2169 2170 var parsed = null; 2171 try { parsed = JSON.parse(raw); } catch (_) { parsed = null; } 2172 if (!parsed || !parsed.length) { return; } 2173 2174 e.preventDefault(); 2175 e.stopImmediatePropagation(); 2176 2177 var shippableMap = buildShippableMap(btn.dataset.featuresRaw || ''); 2178 2179 openModal({ 2180 id: btn.dataset.addToCart, 2181 name: btn.dataset.cartName || btn.dataset.addToCart, 2182 basePrice: parseFloat(btn.dataset.cartPrice) || 0, 2183 format: btn.dataset.cartFormat || '', 2184 image: btn.dataset.cartImage || '', 2185 }, parsed, shippableMap); 2186 }, true); // capture phase â beat the global add-to-cart handler 2187})(); 2188</script>
2188 2189 2190 2191 <div style="display: none !important"> 2192 <a href="https://www.alphadi.org/de">Cart German</a> 2193 <a href="https://www.alphadi.org/en">Cart English</a> 2194 <a href="https://www.alphadi.org/es">Cart Spanish</a> 2195 <a href="https://www.alphadi.org/it">Cart Italian</a> 2196 <a href="https://www.alphadi.org/fr">Cart French</a> 2197 <a href="https://www.alphadi.org/pl">Cart Polish</a> 2198 <a href="https://www.alphadi.org/pt">Cart Portuguese</a> 2199 </div> 2200</body> 2201</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.