{"id":16051,"date":"2026-07-30T10:00:04","date_gmt":"2026-07-30T08:00:04","guid":{"rendered":"https:\/\/kontracamps.com\/erstattungsantrag\/"},"modified":"2026-07-30T10:00:04","modified_gmt":"2026-07-30T08:00:04","slug":"erstattungsantrag","status":"publish","type":"page","link":"https:\/\/kontracamps.com\/de\/erstattungsantrag\/","title":{"rendered":"Erstattungsantrag"},"content":{"rendered":"        <div class=\"sc-refund-request\" data-ajax=\"https:\/\/kontracamps.com\/wp-admin\/admin-ajax.php\" data-nonce=\"bf1fdd1119\" data-logged-in=\"0\">\r\n                            <div class=\"sc-refund-field\">\r\n                    <p>\r\n                        <label for=\"sc-refund-ref\">Buchungsnummer<\/label><br>\r\n                        <input type=\"text\" id=\"sc-refund-ref\" class=\"sc-refund-ref-input\" value=\"\" placeholder=\"SC-2026-...\">\r\n                    <\/p>\r\n                    <p>\r\n                        <label for=\"sc-refund-email\">Bei der Buchung verwendete E-Mail<\/label><br>\r\n                        <input type=\"email\" id=\"sc-refund-email\" class=\"sc-refund-email-input\">\r\n                    <\/p>\r\n                                        <input type=\"text\" class=\"sc-refund-hp\" name=\"website_url\" value=\"\" tabindex=\"-1\" autocomplete=\"off\" aria-hidden=\"true\" readonly style=\"position:absolute;left:-9999px;\">\r\n                    <button type=\"button\" class=\"button sc-refund-lookup-btn\">Weiter<\/button>\r\n                <\/div>\r\n            \r\n            <div class=\"sc-refund-panel-area\" style=\"display:none;\"><\/div>\r\n            <div class=\"sc-refund-msg\" role=\"status\" aria-live=\"polite\"><\/div>\r\n        <\/div>\r\n                <style>\r\n        .sc-refund-request{max-width:880px;margin:24px auto;padding:24px 26px;border:1px solid #e5e7eb;border-radius:12px;background:#fff;color:#1f2937;font-size:15px;line-height:1.5}\r\n        .sc-refund-request label,.sc-refund-request .scr-lbl{display:block;font-weight:600;color:#01224d;margin:0 0 6px;font-size:14px}\r\n        .sc-refund-request select,.sc-refund-request input[type=text],.sc-refund-request input[type=email],.sc-refund-request textarea.sc-refund-reason{width:100%;height:auto;min-height:46px;line-height:1.4;padding:11px 14px;border:1px solid #d1d5db;border-radius:8px;font-size:15px;box-sizing:border-box;background:#fff;color:#1f2937}\r\n        .sc-refund-request textarea.sc-refund-reason{min-height:0}\r\n        .sc-refund-request .scr-mode-select{min-height:42px}\r\n        .sc-refund-request .sc-refund-participant-row.is-locked{opacity:.85}\r\n        .sc-refund-request .scr-group-primary{color:#6b7280;font-style:italic;font-size:12px}\r\n        .sc-refund-request .button{background:#01224d;color:#fff;border:0;border-radius:8px;padding:9px 18px;min-height:0;line-height:1.25;text-transform:none;letter-spacing:normal;font-weight:600;cursor:pointer;margin-top:14px;transition:background .15s,color .15s}\r\n        .sc-refund-request .button:hover{background:#fbbf24;color:#01224d}\r\n                .sc-refund-request input[type=text][readonly],.sc-refund-request input[type=email][readonly]{background:#f3f4f6;color:#6b7280;cursor:default}\r\n        .sc-refund-request .scr-select-row{display:flex;gap:10px;align-items:stretch}\r\n        .sc-refund-request .scr-select-row select{flex:1 1 auto;min-width:0}\r\n        .sc-refund-request .scr-select-row .button{flex:0 0 auto;margin-top:0;white-space:nowrap}\r\n        .sc-refund-request .scr-grid{display:grid;gap:16px 28px;grid-template-columns:1fr 1fr;grid-template-areas:\"choices summary\" \"reason submit\";margin-top:20px}\r\n        .sc-refund-request .scr-choices{grid-area:choices}\r\n        .sc-refund-request .scr-summary{grid-area:summary;display:flex}\r\n        .sc-refund-request .scr-summary .sc-refund-breakdown{flex:1 1 auto;display:flex;flex-direction:column}\r\n        .sc-refund-request .scr-summary .scr-bd{flex:1 1 auto}\r\n        .sc-refund-request .scr-reason{grid-area:reason}\r\n        .sc-refund-request .scr-submit{grid-area:submit}\r\n        .sc-refund-request .scr-field{margin-bottom:8px}\r\n        .sc-refund-request .scr-payout{margin-top:12px}\r\n        .sc-refund-request .scr-payout .scr-lbl{margin-bottom:5px}\r\n        .sc-refund-request .scr-payout-opt{display:inline-block;margin-right:16px;font-size:13px;font-weight:500;color:#1f2937;cursor:pointer}\r\n        .sc-refund-request .scr-payout-opt.is-disabled{color:#9ca3af;cursor:default}\r\n        .sc-refund-request .scr-payout-blocked,.sc-refund-request .scr-payout-hint{margin:6px 0 0;font-size:12px;font-style:italic;color:#6b7280}\r\n        .sc-refund-request .scr-payout-opt input{width:auto;min-height:0;margin:0 4px 0 0}\r\n        .sc-refund-request .scr-bd{margin:0;border:1px solid #eef0f2;border-radius:10px;padding:14px 16px;background:#fafbfc}\r\n        .sc-refund-request .scr-bd-row{display:flex;justify-content:space-between;gap:16px;padding:5px 0;font-size:14px}\r\n        .sc-refund-request .scr-bd-row>span:last-child{white-space:nowrap;font-variant-numeric:tabular-nums}\r\n        .sc-refund-request .scr-bd-muted,.sc-refund-request .scr-bd-context{color:#6b7280}\r\n        .sc-refund-request .scr-bd-sub{padding:2px 0 2px 14px;font-size:13px}\r\n        .sc-refund-request .scr-bd-channel[hidden]{display:none}\r\n        .sc-refund-request .scr-bd-fee>span:last-child{color:#b91c1c}\r\n        .sc-refund-request .scr-bd-sep{border-top:1px solid #e5e7eb;margin:8px 0}\r\n        .sc-refund-request .scr-bd-refund{font-size:19px;font-weight:700;color:#01224d;padding-top:4px}\r\n        .sc-refund-request .scr-bd-note{font-size:12px;color:#9ca3af;margin-top:3px}\r\n        .sc-refund-request .scr-bd-policy{font-size:12px;color:#6b7280;margin-top:10px;font-style:italic}\r\n        .sc-refund-request .scr-bd-empty{margin:0;padding:10px 2px;color:#b91c1c;font-size:14px}\r\n        .sc-refund-request .scr-roster{margin:0 0 12px;border:1px solid #eef0f2;border-radius:10px;overflow:hidden}\r\n        .sc-refund-request .scr-rrow{display:flex;align-items:center;gap:10px;padding:8px 12px;border-top:1px solid #f2f3f5;font-size:14px}\r\n        .sc-refund-request .scr-rrow:first-child{border-top:0}\r\n        .sc-refund-request .scr-rname{font-weight:600}\r\n        .sc-refund-request .scr-chip{margin-left:auto;font-size:11px;font-weight:600;padding:2px 9px;border-radius:100px;white-space:nowrap}\r\n        .sc-refund-request .scr-rt-refunded{color:#157347;background:#e8f4ec}\r\n        .sc-refund-request .scr-rt-now{color:#1d4ed8;background:#e9effc}\r\n        .sc-refund-request .scr-rt-booked{color:#475569;background:#eef1f5}\r\n        .sc-refund-request .scr-policy-open{margin-top:10px;background:none;border:0;padding:0;cursor:pointer;font-size:12px;font-weight:400;font-style:italic;color:#6b7280;text-decoration:underline}\r\n        .sc-refund-request .scr-policy-modal{position:fixed;top:0;left:0;right:0;bottom:0;z-index:100000;display:flex;align-items:center;justify-content:center;padding:16px;background-color:rgba(0,0,0,.5);backdrop-filter:blur(4px);-webkit-backdrop-filter:blur(4px);animation:scrPolicyFade .3s ease}\r\n        .sc-refund-request .scr-policy-modal[hidden]{display:none}\r\n        .admin-bar .sc-refund-request .scr-policy-modal{top:32px}\r\n        @keyframes scrPolicyFade{from{opacity:0}to{opacity:1}}\r\n        .sc-refund-request .scr-policy-dialog{position:relative;background:#fff;border-radius:12px;padding:22px 24px;max-width:420px;width:100%;box-shadow:0 20px 50px rgba(0,0,0,.3)}\r\n        .sc-refund-request .scr-policy-title{margin:0 0 12px;font-size:16px;font-weight:700;color:#01224d}\r\n        .sc-refund-request .scr-policy-body{margin:0}\r\n        .sc-refund-request .scr-policy-intro{margin:0 0 12px;padding-bottom:12px;border-bottom:1px solid #e5e7eb}\r\n        .sc-refund-request .scr-policy-intro p{margin:0 0 6px;font-size:12px;line-height:1.45;color:#6b7280}\r\n        .sc-refund-request .scr-policy-intro p:last-child{margin-bottom:0}\r\n        .sc-refund-request .scr-policy-row{display:flex;justify-content:space-between;gap:12px;font-size:13px;color:#6b7280;padding:4px 0}\r\n        .sc-refund-request .scr-policy-row.is-current{color:#01224d;font-weight:600}\r\n        .sc-refund-request .scr-policy-terms{display:inline-block;margin-top:12px;font-size:13px;color:#01224d;text-decoration:underline}\r\n        .sc-refund-request .sc-refund-participants{border:0;padding:0;margin:4px 0 8px;max-height:140px;overflow-y:auto}\r\n        .sc-refund-request .sc-refund-participants legend{font-size:13px;color:#6b7280;padding:0 4px}\r\n        .sc-refund-request .sc-refund-participant-row{display:flex;align-items:center;gap:9px;padding:7px 6px;font-size:14px;font-weight:500;color:#1f2937;border-radius:6px;cursor:pointer}\r\n        .sc-refund-request .sc-refund-participant-row:hover{background:#f3f4f6}\r\n        .sc-refund-request .sc-refund-participant-row input{width:auto;min-height:0;margin:0}\r\n        .sc-refund-request .sc-refund-participant-row.is-disabled{color:#9ca3af;cursor:default}\r\n        .sc-refund-request .sc-refund-participant-row.is-disabled:hover{background:none}\r\n        .sc-refund-request .sc-refund-reason-wrap{margin:2px 0 0}\r\n        .sc-refund-request .sc-refund-note{font-size:13px;color:#6b7280;margin:12px 0 0}\r\n        .sc-refund-request .sc-refund-msg{margin-top:12px;font-size:14px}\r\n        .sc-refund-request .sc-refund-msg.is-ok{color:#166534}\r\n        .sc-refund-request .sc-refund-msg.is-err{color:#b91c1c}\r\n        @media(max-width:640px){\r\n        .sc-refund-request .scr-select-row{flex-direction:column;align-items:stretch}\r\n        .sc-refund-request .scr-grid{grid-template-columns:1fr;grid-template-areas:\"choices\" \"summary\" \"reason\" \"submit\"}\r\n        .sc-refund-request .scr-choices,.sc-refund-request .scr-summary{min-height:0}\r\n        }\r\n        <\/style>\r\n        <script>\r\n        (function () {\r\n            var L = {\"requestBtn\":\"Erstattung beantragen\",\"withdrawBtn\":\"Team zur\\u00fcckziehen\",\"reasonLabel\":\"Grund (optional)\",\"refundTypeLabel\":\"Art der Erstattung\",\"modeWhole\":\"Gesamte Buchung erstatten\",\"modeSome\":\"Bestimmte Teilnehmer erstatten\",\"participantsLabel\":\"Teilnehmer f\\u00fcr die Erstattung (H\\u00e4kchen bei allen entfernen, die bleiben):\",\"needParticipant\":\"Bitte lassen Sie mindestens einen Teilnehmer ausgew\\u00e4hlt.\",\"payoutTitle\":\"Erstattung an\",\"payoutAccount\":\"Mein Konto\",\"payoutVoucher\":\"Guthaben (Gutschein)\",\"payoutVoucherBlocked\":\"Ihr Stornoschutz erstattet auf Ihre urspr\\u00fcngliche Zahlungsmethode.\",\"payoutVoucherHint\":\"Sie erhalten einen h\\u00f6heren Betrag, den Sie f\\u00fcr jedes k\\u00fcnftige Camp oder Turnier einsetzen k\\u00f6nnen.\",\"payoutVoucherInstallment\":\"Gutscheine sind nur f\\u00fcr vollst\\u00e4ndig bezahlte Buchungen verf\\u00fcgbar.\",\"note\":\"Nach dem Absenden erhalten Sie eine E-Mail mit einem Best\\u00e4tigungslink. Die Erstattung wird erst nach dem Klick darauf abgeschlossen.\",\"genericError\":\"Etwas ist schiefgelaufen. Bitte versuchen Sie es erneut.\",\"needRef\":\"Bitte w\\u00e4hlen oder geben Sie eine Buchung ein.\",\"loading\":\"Wird geladen\\u2026\",\"submitting\":\"Wird gesendet\\u2026\",\"recalcFailed\":\"Der Betrag konnte nicht neu berechnet werden \\u2014 bitte pr\\u00fcfen Sie Ihre Verbindung und w\\u00e4hlen Sie einen Teilnehmer erneut aus.\",\"payoutNone\":\"F\\u00fcr diese Buchung ist keine Erstattung m\\u00f6glich. Bei Fragen kontaktieren Sie uns bitte.\",\"groupTitle\":\"Teams in dieser Bestellung \\u2014 w\\u00e4hlen Sie aus, wer zur\\u00fcckzieht\",\"groupHint\":\"Markieren Sie weitere Teams, die zusammen mit diesem zur\\u00fcckziehen \\u2014 eine Best\\u00e4tigungs-E-Mail deckt alle ausgew\\u00e4hlten Teams ab.\",\"groupPrimaryHint\":\"das Team, das Sie zur\\u00fcckziehen\",\"activeInitiated\":\"F\\u00fcr diese Buchung l\\u00e4uft bereits ein Erstattungsantrag. Pr\\u00fcfen Sie Ihren Posteingang und klicken Sie auf den Best\\u00e4tigungslink, um ihn abzuschlie\\u00dfen \\u2014 oder brechen Sie den Antrag unten ab und stellen Sie einen neuen.\",\"activeConfirmed\":\"Ihr Erstattungsantrag f\\u00fcr diese Buchung ist best\\u00e4tigt und wartet auf unsere Pr\\u00fcfung. Wenn Sie ihn \\u00e4ndern m\\u00f6chten, kontaktieren Sie uns bitte.\",\"activeProcessing\":\"Ihre Erstattung f\\u00fcr diese Buchung ist genehmigt \\u2014 die Auszahlung ist unterwegs.\",\"activeGroupPrefix\":\"Diese Buchung ist Teil eines Gruppenr\\u00fcckzugs.\",\"resendBtn\":\"Best\\u00e4tigungs-E-Mail erneut senden\",\"cancelReqBtn\":\"Diesen Antrag abbrechen\"};\r\n            var preselect = \"\";\r\n            var loggedIn = false;\r\n\r\n            function root() { return document.querySelector('.sc-refund-request'); }\r\n            function esc(s) { var d = document.createElement('div'); d.textContent = (s == null ? '' : String(s)); return d.innerHTML; }\r\n            function msg(text, ok) {\r\n                var m = root() && root().querySelector('.sc-refund-msg');\r\n                if (m) { m.textContent = text || ''; m.className = 'sc-refund-msg ' + (ok ? 'is-ok' : 'is-err'); }\r\n            }\r\n            function post(action, data, cb) {\r\n                var el = root(); if (!el) return;\r\n                var body = new URLSearchParams();\r\n                body.append('action', action);\r\n                body.append('nonce', el.getAttribute('data-nonce'));\r\n                Object.keys(data || {}).forEach(function (k) {\r\n                    body.append(k, Array.isArray(data[k]) ? JSON.stringify(data[k]) : data[k]);\r\n                });\r\n                fetch(el.getAttribute('data-ajax'), {\r\n                    method: 'POST', credentials: 'same-origin',\r\n                    headers: { 'Content-Type': 'application\/x-www-form-urlencoded' },\r\n                    body: body.toString()\r\n                }).then(function (r) { return r.json(); })\r\n                  .then(function (j) { cb(j); })\r\n                  .catch(function () { cb({ success: false, data: { message: L.genericError } }); });\r\n            }\r\n            function currentRef() {\r\n                var el = root();\r\n                var sel = el.querySelector('.sc-refund-booking-select');\r\n                if (sel) { return sel.value; }\r\n                var inp = el.querySelector('.sc-refund-ref-input');\r\n                return inp ? inp.value.trim() : '';\r\n            }\r\n            function currentEmail() {\r\n                var inp = root().querySelector('.sc-refund-email-input');\r\n                return inp ? inp.value.trim() : '';\r\n            }\r\n            function honeypot() {\r\n                var h = root().querySelector('.sc-refund-hp');\r\n                return h ? h.value : '';\r\n            }\r\n            \/\/ Once the panel is up it belongs to ONE reference, so the lookup locks: Continue hides\r\n            \/\/ and the reference\/e-mail go readonly. They stay VISIBLE \u2014 the customer keeps seeing\r\n            \/\/ which booking is being refunded \u2014 but can no longer be edited into disagreeing with\r\n            \/\/ the panel below (doSubmit pins the reference from data-ref while the e-mail is read\r\n            \/\/ live, so an edit could only produce a request that contradicts what is on screen).\r\n            \/\/ Filing the request unlocks both. Logged-in users are unaffected: their selector is\r\n            \/\/ the navigation between bookings and its `change` re-runs the lookup. Values are never\r\n            \/\/ cleared \u2014 currentRef\/currentEmail\/honeypot keep reading these nodes.\r\n            function lockLookup(locked) {\r\n                var el = root(); if (!el) { return; }\r\n                var btn = el.querySelector('.sc-refund-lookup-btn');\r\n                if (btn) { btn.style.display = locked ? 'none' : ''; }\r\n                ['.sc-refund-ref-input', '.sc-refund-email-input'].forEach(function (sel) {\r\n                    var f = el.querySelector(sel);\r\n                    if (f) { f.readOnly = locked; }\r\n                });\r\n            }\r\n            function doLookup() {\r\n                var ref = currentRef();\r\n                if (!ref) { msg(L.needRef, false); return; }\r\n                msg(L.loading, true);\r\n                post('sportscamp_refund_lookup', { booking_reference: ref, email: currentEmail(), website_url: honeypot() }, function (j) {\r\n                    \/\/ Wrong reference \/ e-mail: nothing gets locked, the typo has to stay fixable\r\n                    \/\/ (also covers a failed re-lookup after cancelling an active request).\r\n                    if (!j || !j.success) { lockLookup(false); msg((j && j.data && j.data.message) || L.genericError, false); return; }\r\n                    msg('', true);\r\n                    renderPanel(j.data);\r\n                });\r\n            }\r\n            function renderPanel(d) {\r\n                var area = root().querySelector('.sc-refund-panel-area');\r\n                lockLookup(true);\r\n                \/\/ A request is already in flight for this booking \u2014 block the form and say what to\r\n                \/\/ do instead (the server refuses a duplicate submit anyway; re-rendering a fillable\r\n                \/\/ form would only invite redoing work that must fail).\r\n                if (d.active_request) {\r\n                    var st = d.active_request.status;\r\n                    var noteText = st === 'initiated' ? L.activeInitiated : (st === 'customer_confirmed' ? L.activeConfirmed : L.activeProcessing);\r\n                    if (d.active_request.is_group) { noteText = L.activeGroupPrefix + ' ' + noteText; }\r\n                    var html = '<div class=\"scr-active-request\"><p>' + esc(noteText) + '<\/p>';\r\n                    if (st === 'initiated') {\r\n                        html += '<p><button type=\"button\" class=\"button sc-refund-resend-btn\">' + esc(L.resendBtn) + '<\/button> '\r\n                              + '<button type=\"button\" class=\"button sc-refund-cancelreq-btn\">' + esc(L.cancelReqBtn) + '<\/button><\/p>';\r\n                    }\r\n                    html += '<\/div>';\r\n                    area.innerHTML = html;\r\n                    area.style.display = '';\r\n                    area.setAttribute('data-ref', currentRef());\r\n                    return;\r\n                }\r\n                \/\/ Tournament team withdraws whole \u2014 no per-player checkboxes (no checkboxes\r\n                \/\/ = empty selection = whole booking, which is exactly the withdrawal semantics;\r\n                \/\/ the server refuses tournament subsets regardless).\r\n                var multi = !d.is_tournament && d.participants && d.participants.length > 1;\r\n\r\n                \/\/ LEFT-top: the choices. Refund type is a dropdown (whole vs specific); selecting a\r\n                \/\/ subset reveals styled participant checkboxes. Selecting every participant is a\r\n                \/\/ whole-booking refund server-side (ratio 1.0), so no special-casing is needed here.\r\n                var choices = '';\r\n                if (multi) {\r\n                    \/\/ All refundable participants are checked by default; uncheck anyone staying booked.\r\n                    \/\/ Everyone checked = whole-booking refund (ratio 1.0 server-side). No separate\r\n                    \/\/ whole-vs-specific control needed \u2014 fewer elements, still explicit.\r\n                    choices += '<fieldset class=\"sc-refund-participants\"><legend>' + esc(L.participantsLabel) + '<\/legend>';\r\n                    d.participants.forEach(function (p) {\r\n                        var disabled = (p.status === 'refunded' || p.status === 'cancelled');\r\n                        choices += '<label class=\"sc-refund-participant-row' + (disabled ? ' is-disabled' : '') + '\">'\r\n                                 +   '<input type=\"checkbox\" class=\"sc-refund-participant\" value=\"' + esc(p.id) + '\"' + (disabled ? ' disabled' : ' checked') + '>'\r\n                                 +   '<span>' + esc(p.name) + (disabled ? ' (' + esc(p.status) + ')' : '') + '<\/span><\/label>';\r\n                    });\r\n                    choices += '<\/fieldset>';\r\n                }\r\n\r\n                \/\/ GROUP WITHDRAWAL (tournaments): sibling teams of the same order join as opt-in\r\n                \/\/ checkboxes. Amounts are display-only quotes; the confirmation page shows the\r\n                \/\/ authoritative totals. data-cash\/data-voucher swap with the payout radio.\r\n                if (d.is_tournament && d.group_siblings && d.group_siblings.length) {\r\n                    choices += '<fieldset class=\"sc-refund-group\"><legend>' + esc(L.groupTitle) + '<\/legend>'\r\n                             + '<p class=\"scr-group-hint\">' + esc(L.groupHint) + '<\/p>';\r\n                    \/\/ The entered team leads the list: checked and LOCKED \u2014 it is the authorization\r\n                    \/\/ anchor of this entry (withdraw only the sibling? enter from the sibling).\r\n                    if (d.primary_team) {\r\n                        var pname = d.primary_team.team_name ? '\u201e' + d.primary_team.team_name + '\u201d' : d.primary_team.reference;\r\n                        choices += '<label class=\"sc-refund-participant-row is-locked\">'\r\n                                 +   '<input type=\"checkbox\" checked disabled>'\r\n                                 +   '<span>' + esc(pname) + (d.primary_team.category_name ? ' \u2014 ' + esc(d.primary_team.category_name) : '')\r\n                                 +     ' <em class=\"scr-group-primary\">(' + esc(L.groupPrimaryHint) + ')<\/em><\/span>'\r\n                                 + '<\/label>';\r\n                    }\r\n                    d.group_siblings.forEach(function (s) {\r\n                        var name = s.team_name ? '\u201e' + s.team_name + '\u201d' : s.reference;\r\n                        choices += '<label class=\"sc-refund-participant-row\">'\r\n                                 +   '<input type=\"checkbox\" class=\"sc-refund-group-sib\" value=\"' + esc(s.reference) + '\"'\r\n                                 +     ' data-cash=\"' + esc(s.cash_amount) + '\" data-voucher=\"' + esc(s.voucher_amount) + '\">'\r\n                                 +   '<span>' + esc(name) + (s.category_name ? ' \u2014 ' + esc(s.category_name) : '')\r\n                                 +     ' <span class=\"scr-group-amt\" data-cash=\"' + esc(s.cash_amount) + '\" data-voucher=\"' + esc(s.voucher_amount) + '\"><\/span><\/span>'\r\n                                 + '<\/label>';\r\n                    });\r\n                    choices += '<\/fieldset>';\r\n                }\r\n\r\n                \/\/ RIGHT: the styled breakdown (server-rendered). LEFT-bottom: reason + submit.\r\n                \/\/ Payout method \u2014 the customer may take a store-credit voucher instead of a cash refund\r\n                \/\/ to the original method. The handler whitelists these two (never 'manual'\/IBAN from the\r\n                \/\/ customer surface) and the executor mints the coupon on approval.\r\n                choices += '<div class=\"scr-payout\"><span class=\"scr-lbl\">' + esc(L.payoutTitle) + '<\/span>'\r\n                         +   '<label class=\"scr-payout-opt\"><input type=\"radio\" name=\"scr-payout\" value=\"original_payment\" checked> ' + esc(L.payoutAccount) + '<\/label>'\r\n                         +   '<label class=\"scr-payout-opt\"><input type=\"radio\" name=\"scr-payout\" value=\"store_credit\"> ' + esc(L.payoutVoucher) + '<\/label>'\r\n                         +   '<p class=\"scr-payout-hint\">' + esc(L.payoutVoucherHint) + '<\/p>'\r\n                         + '<\/div>';\r\n\r\n                var summary = '<div class=\"sc-refund-breakdown\">' + (d.breakdown_html || '') + '<\/div>';\r\n                var reason  = '<p class=\"sc-refund-reason-wrap\"><label class=\"scr-lbl\">' + esc(L.reasonLabel) + '<\/label><textarea class=\"sc-refund-reason\" rows=\"3\"><\/textarea><\/p>';\r\n                var submitLabel = d.is_tournament ? L.withdrawBtn : L.requestBtn;\r\n                var submit  = '<p class=\"sc-refund-note\">' + esc(L.note) + '<\/p>'\r\n                            + '<button type=\"button\" class=\"button sc-refund-submit-btn\" data-label=\"' + esc(submitLabel) + '\">' + esc(submitLabel) + '<\/button>';\r\n\r\n                \/\/ Desktop 2\u00d72 grid: row1 = choices | breakdown (equal, fixed height so toggling\r\n                \/\/ whole\u2194specific never reflows), row2 = reason | submit. Mobile stacks in source order:\r\n                \/\/ choices \u2192 breakdown \u2192 reason \u2192 submit.\r\n                area.innerHTML = '<div class=\"scr-grid\">'\r\n                               +   '<div class=\"scr-choices\">' + choices + '<\/div>'\r\n                               +   '<div class=\"scr-summary\">' + summary + '<\/div>'\r\n                               +   '<div class=\"scr-reason\">' + reason + '<\/div>'\r\n                               +   '<div class=\"scr-submit\">' + submit + '<\/div>'\r\n                               + '<\/div>';\r\n                area.style.display = '';\r\n                area.setAttribute('data-ref', currentRef());\r\n                if (d.primary_quote) {\r\n                    area.setAttribute('data-pq-cash', d.primary_quote.cash_amount);\r\n                    area.setAttribute('data-pq-voucher', d.primary_quote.voucher_amount);\r\n                    area.setAttribute('data-pq-cur', d.primary_quote.currency || '');\r\n                }\r\n                applyPayoutPolicies(d);\r\n            }\r\n            \/\/ Group section: per-sibling amount hint next to each checkbox, following the selected\r\n            \/\/ payout channel. Totals live in the server-rendered breakdown panel \u2014 never summed here.\r\n            function updateGroupAmounts() {\r\n                var el = root(); if (!el) { return; }\r\n                var area = el.querySelector('.sc-refund-panel-area');\r\n                var payoutEl = el.querySelector('input[name=\"scr-payout\"]:checked');\r\n                var isVoucher = !!(payoutEl && payoutEl.value === 'store_credit');\r\n                var cur = area ? (area.getAttribute('data-pq-cur') || '') : '';\r\n                el.querySelectorAll('.scr-group-amt').forEach(function (span) {\r\n                    var amt = parseFloat(isVoucher ? span.getAttribute('data-voucher') : span.getAttribute('data-cash')) || 0;\r\n                    span.textContent = '(' + amt.toFixed(2) + ' ' + cur + ')';\r\n                });\r\n            }\r\n            function groupRefs() {\r\n                var refs = [];\r\n                root().querySelectorAll('.sc-refund-group-sib:checked').forEach(function (c) { refs.push(c.value); });\r\n                return refs;\r\n            }\r\n            \/\/ Sibling toggled \u2192 re-fetch the SERVER-rendered breakdown for the selected group so the\r\n            \/\/ right panel always shows the full authoritative figures (never client-side sums).\r\n            function refreshGroupBreakdown() {\r\n                var area = root().querySelector('.sc-refund-panel-area');\r\n                if (!area) { return; }\r\n                var bd = area.querySelector('.sc-refund-breakdown');\r\n                var submitBtn = root().querySelector('.sc-refund-submit-btn');\r\n                if (bd) { bd.style.opacity = '0.5'; }\r\n                post('sportscamp_refund_lookup', {\r\n                    booking_reference: area.getAttribute('data-ref') || currentRef(),\r\n                    email: currentEmail(),\r\n                    group_refs: JSON.stringify(groupRefs()),\r\n                    website_url: honeypot()\r\n                }, function (j) {\r\n                    if (bd) { bd.style.opacity = ''; }\r\n                    if (j && j.success) {\r\n                        if (bd) { bd.innerHTML = j.data.breakdown_html || ''; }\r\n                        if (submitBtn) { submitBtn.disabled = false; }\r\n                        applyPayoutPolicies(j.data);\r\n                    } else {\r\n                        if (bd) { bd.innerHTML = '<p class=\"scr-bd-empty\">' + esc(L.recalcFailed) + '<\/p>'; }\r\n                        if (submitBtn) { submitBtn.disabled = true; }\r\n                    }\r\n                });\r\n            }\r\n            \/\/ Orchestrates both channel policies + the \"no channel left\" edge. Voucher blocks show a\r\n            \/\/ disabled radio with an explanation; a blocked CASH channel is HIDDEN entirely (owner\r\n            \/\/ decision 2026-07-23 \u2014 a visible 0.00 option only misleads) and the voucher becomes the\r\n            \/\/ selected default. With no channel available the submit is blocked with a notice.\r\n            function applyPayoutPolicies(d) {\r\n                applyVoucherPolicy(d.voucher_available, d.voucher_reason);\r\n                applyCashPolicy(d.cash_available);\r\n                var anyOpen = false;\r\n                root().querySelectorAll('input[name=\"scr-payout\"]').forEach(function (r) {\r\n                    var row = r.closest('.scr-payout-opt');\r\n                    var hidden = row && row.style.display === 'none';\r\n                    if (!r.disabled && !hidden) { anyOpen = true; }\r\n                });\r\n                var submitBtn = root().querySelector('.sc-refund-submit-btn');\r\n                if (!anyOpen) {\r\n                    if (submitBtn) { submitBtn.disabled = true; }\r\n                    msg(L.payoutNone, false);\r\n                }\r\n            }\r\n            function applyCashPolicy(available) {\r\n                var cash = root().querySelector('input[name=\"scr-payout\"][value=\"original_payment\"]');\r\n                if (!cash) { return; }\r\n                var blocked = (available === false);\r\n                var row = cash.closest('.scr-payout-opt');\r\n                cash.disabled = blocked;\r\n                if (row) { row.style.display = blocked ? 'none' : ''; }\r\n                if (blocked && cash.checked) {\r\n                    cash.checked = false;\r\n                    var voucher = root().querySelector('input[name=\"scr-payout\"][value=\"store_credit\"]');\r\n                    if (voucher && !voucher.disabled) { voucher.checked = true; }\r\n                }\r\n                applyChannelToBreakdown();\r\n            }\r\n            \/\/ Store-credit availability is one server-side rule (RefundChannelPolicy): blocked by active\r\n            \/\/ protection, an unpaid installment, or no voucher value. Disable the radio + explain when\r\n            \/\/ blocked; keep the promo hint only while it's selectable. Recomputed on every lookup\/refresh\r\n            \/\/ because it depends on WHICH participants are selected. The server refuses it regardless \u2014\r\n            \/\/ this only stops the customer from choosing something that will fail.\r\n            function applyVoucherPolicy(available, reason) {\r\n                var voucher = root().querySelector('input[name=\"scr-payout\"][value=\"store_credit\"]');\r\n                if (!voucher) { return; }\r\n                var blocked = (available === false);\r\n                var label = voucher.closest('.scr-payout-opt');\r\n                var hint  = root().querySelector('.scr-payout-blocked');\r\n                voucher.disabled = blocked;\r\n                if (label) { label.classList.toggle('is-disabled', blocked); }\r\n                var promo = root().querySelector('.scr-payout-hint');\r\n                if (promo) { promo.style.display = blocked ? 'none' : ''; }\r\n                if (blocked) {\r\n                    if (voucher.checked) {\r\n                        voucher.checked = false;\r\n                        var original = root().querySelector('input[name=\"scr-payout\"][value=\"original_payment\"]');\r\n                        if (original) { original.checked = true; }\r\n                    }\r\n                    var text = (reason === 'unpaid_installment') ? L.payoutVoucherInstallment : L.payoutVoucherBlocked;\r\n                    if (!hint) {\r\n                        hint = document.createElement('p');\r\n                        hint.className = 'scr-payout-blocked';\r\n                        var wrap = root().querySelector('.scr-payout');\r\n                        if (wrap) { wrap.appendChild(hint); }\r\n                    }\r\n                    hint.textContent = text;\r\n                } else if (hint) {\r\n                    hint.remove();\r\n                }\r\n                \/\/ Freshly rendered\/refetched breakdown HTML always defaults to the cash block; the\r\n                \/\/ radio may say otherwise (kept selection, or the force-flip above) \u2014 resync.\r\n                applyChannelToBreakdown();\r\n            }\r\n            function participantIds() {\r\n                var ids = [];\r\n                root().querySelectorAll('.sc-refund-participant:checked').forEach(function (c) { ids.push(c.value); });\r\n                return ids;\r\n            }\r\n            \/\/ Re-fetch ONLY the breakdown table for the current participant selection so the shown\r\n            \/\/ amount always matches what will actually be requested (checkboxes are preserved \u2014 we\r\n            \/\/ don't rebuild the whole panel). Empty selection = whole booking.\r\n            function refreshBreakdown() {\r\n                var area = root().querySelector('.sc-refund-panel-area');\r\n                if (!area) { return; }\r\n                var ref = area.getAttribute('data-ref') || currentRef();\r\n                var bd = area.querySelector('.sc-refund-breakdown');\r\n                var ids = participantIds();\r\n                var boxes = root().querySelectorAll('.sc-refund-participant');\r\n                var submitBtn = root().querySelector('.sc-refund-submit-btn');\r\n                \/\/ With participant checkboxes present, refunding nobody is invalid \u2014 and an empty list\r\n                \/\/ would otherwise be read as a whole-booking refund server-side. Block + explain.\r\n                if (boxes.length && ids.length === 0) {\r\n                    if (bd) { bd.innerHTML = '<p class=\"scr-bd-empty\">' + esc(L.needParticipant) + '<\/p>'; }\r\n                    if (submitBtn) { submitBtn.disabled = true; }\r\n                    return;\r\n                }\r\n                if (submitBtn) { submitBtn.disabled = false; }\r\n                if (bd) { bd.style.opacity = '0.5'; }\r\n                post('sportscamp_refund_lookup', { booking_reference: ref, email: currentEmail(), participant_ids: ids, website_url: honeypot() }, function (j) {\r\n                    if (bd) { bd.style.opacity = ''; }\r\n                    if (j && j.success) {\r\n                        if (bd) { bd.innerHTML = j.data.breakdown_html || ''; }\r\n                        \/\/ Deselecting the protected participant (or changing the paid amount) re-evaluates\r\n                        \/\/ both channel policies. Re-enable submit first \u2014 applyPayoutPolicies re-blocks\r\n                        \/\/ it when no channel is left.\r\n                        if (submitBtn) { submitBtn.disabled = false; }\r\n                        msg('', true);\r\n                        applyPayoutPolicies(j.data);\r\n                    } else {\r\n                        \/\/ Recompute failed (dropped request \/ expired session). The breakdown on screen no\r\n                        \/\/ longer matches the checkbox selection \u2014 never let a stale amount stand on a money\r\n                        \/\/ flow. Replace it with a notice and block submit until a clean recompute succeeds.\r\n                        if (bd) { bd.innerHTML = '<p class=\"scr-bd-empty\">' + esc(L.recalcFailed) + '<\/p>'; }\r\n                        if (submitBtn) { submitBtn.disabled = true; }\r\n                        msg((j && j.data && j.data.message) || L.recalcFailed, false);\r\n                    }\r\n                });\r\n            }\r\n            function doSubmit(btn) {\r\n                var area = root().querySelector('.sc-refund-panel-area');\r\n                var ref = area.getAttribute('data-ref') || currentRef();\r\n                var reasonEl = root().querySelector('.sc-refund-reason');\r\n                var ids = participantIds();\r\n                var boxes = root().querySelectorAll('.sc-refund-participant');\r\n                if (boxes.length && ids.length === 0) { msg(L.needParticipant, false); return; }\r\n                var payoutEl = root().querySelector('input[name=\"scr-payout\"]:checked');\r\n                var payout = (payoutEl && payoutEl.value === 'store_credit') ? 'store_credit' : 'original_payment';\r\n                btn.disabled = true; btn.textContent = L.submitting;\r\n                post('sportscamp_refund_submit', {\r\n                    booking_reference: ref, email: currentEmail(),\r\n                    participant_ids: ids, reason: reasonEl ? reasonEl.value : '',\r\n                    payout_channel: payout, website_url: honeypot(),\r\n                    group_refs: JSON.stringify(groupRefs())\r\n                }, function (j) {\r\n                    if (!j || !j.success) { btn.disabled = false; btn.textContent = btn.getAttribute('data-label') || L.requestBtn; msg((j && j.data && j.data.message) || L.genericError, false); return; }\r\n                    \/\/ Request filed: drop the panel and unlock the lookup, otherwise a guest is left\r\n                    \/\/ with nothing but the confirmation text and no way to check another booking\r\n                    \/\/ short of a page reload (which clears the fields).\r\n                    area.style.display = 'none';\r\n                    area.innerHTML = '';\r\n                    area.removeAttribute('data-ref');\r\n                    lockLookup(false);\r\n                    msg(j.data.message || '', true);\r\n                });\r\n            }\r\n            function togglePolicy(show) {\r\n                var m = root() && root().querySelector('.scr-policy-modal');\r\n                if (m) { m.hidden = !show; }\r\n            }\r\n            \/\/ Active-request panel: resend the confirmation email \/ cancel the still-initiated\r\n            \/\/ request (then re-run the lookup so a fresh form appears immediately).\r\n            function doResend(btn) {\r\n                btn.disabled = true;\r\n                post('sportscamp_refund_resend', { booking_reference: currentRef(), email: currentEmail(), website_url: honeypot() }, function (j) {\r\n                    btn.disabled = false;\r\n                    msg((j && j.data && j.data.message) || L.genericError, !!(j && j.success));\r\n                });\r\n            }\r\n            function doCancelRequest(btn) {\r\n                btn.disabled = true;\r\n                post('sportscamp_refund_cancel', { booking_reference: currentRef(), email: currentEmail(), website_url: honeypot() }, function (j) {\r\n                    btn.disabled = false;\r\n                    msg((j && j.data && j.data.message) || L.genericError, !!(j && j.success));\r\n                    if (j && j.success) { doLookup(); }\r\n                });\r\n            }\r\n            document.addEventListener('click', function (e) {\r\n                if (!e.target) { return; }\r\n                if (e.target.classList.contains('sc-refund-lookup-btn')) { e.preventDefault(); doLookup(); return; }\r\n                if (e.target.classList.contains('sc-refund-submit-btn')) { e.preventDefault(); doSubmit(e.target); return; }\r\n                if (e.target.classList.contains('sc-refund-resend-btn')) { e.preventDefault(); doResend(e.target); return; }\r\n                if (e.target.classList.contains('sc-refund-cancelreq-btn')) { e.preventDefault(); doCancelRequest(e.target); return; }\r\n                if (e.target.classList.contains('scr-policy-open')) { e.preventDefault(); togglePolicy(true); return; }\r\n                if (e.target.classList.contains('scr-policy-modal')) { togglePolicy(false); return; }\r\n            });\r\n            document.addEventListener('keydown', function (e) {\r\n                if (e.key === 'Escape') { togglePolicy(false); }\r\n            });\r\n            \/\/ The breakdown carries one delivery block per payout channel (cash: installment\r\n            \/\/ reduction + cash; voucher: coupon + installment-still-due). Show the block matching\r\n            \/\/ the selected radio. Called after every render\/refresh \u2014 the server default is cash.\r\n            function applyChannelToBreakdown() {\r\n                var el = root(); if (!el) { return; }\r\n                var payoutEl = el.querySelector('input[name=\"scr-payout\"]:checked');\r\n                var channel = (payoutEl && payoutEl.value === 'store_credit') ? 'store_credit' : 'original_payment';\r\n                el.querySelectorAll('.scr-bd-channel').forEach(function (div) {\r\n                    div.hidden = div.getAttribute('data-channel') !== channel;\r\n                });\r\n                updateGroupAmounts();\r\n            }\r\n            document.addEventListener('change', function (e) {\r\n                if (!e.target) { return; }\r\n                \/\/ Logged-in: changing the selected booking auto-loads its refund panel (the Continue\r\n                \/\/ button beside the selector stays as an explicit trigger \/ guest fallback).\r\n                if (e.target.classList.contains('sc-refund-booking-select')) { doLookup(); return; }\r\n                \/\/ Checking\/unchecking a participant recomputes the amount.\r\n                if (e.target.classList.contains('sc-refund-participant')) { refreshBreakdown(); }\r\n                \/\/ Switching payout channel swaps the delivery block in the breakdown.\r\n                if (e.target.name === 'scr-payout') { applyChannelToBreakdown(); }\r\n                \/\/ Toggling a sibling team: refresh the per-row hint AND re-fetch the full\r\n                \/\/ server-rendered group breakdown for the right panel.\r\n                if (e.target.classList.contains('sc-refund-group-sib')) { updateGroupAmounts(); refreshGroupBreakdown(); }\r\n            });\r\n            \/\/ Logged-in user arriving from a profile link with a preselected booking \u2192 auto-load it.\r\n            if (loggedIn && preselect) {\r\n                document.addEventListener('DOMContentLoaded', function () {\r\n                    var sel = root() && root().querySelector('.sc-refund-booking-select');\r\n                    if (sel && sel.value === preselect) { doLookup(); }\r\n                });\r\n            }\r\n        })();\r\n        <\/script>\r\n        \n","protected":false},"excerpt":{"rendered":"","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"categories":[],"folder":[],"class_list":["post-16051","page","type-page","status-publish","hentry"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/kontracamps.com\/de\/wp-json\/wp\/v2\/pages\/16051","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/kontracamps.com\/de\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/kontracamps.com\/de\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/kontracamps.com\/de\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/kontracamps.com\/de\/wp-json\/wp\/v2\/comments?post=16051"}],"version-history":[{"count":0,"href":"https:\/\/kontracamps.com\/de\/wp-json\/wp\/v2\/pages\/16051\/revisions"}],"wp:attachment":[{"href":"https:\/\/kontracamps.com\/de\/wp-json\/wp\/v2\/media?parent=16051"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/kontracamps.com\/de\/wp-json\/wp\/v2\/categories?post=16051"},{"taxonomy":"folder","embeddable":true,"href":"https:\/\/kontracamps.com\/de\/wp-json\/wp\/v2\/folder?post=16051"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}