{"id":16050,"date":"2026-07-30T10:00:04","date_gmt":"2026-07-30T08:00:04","guid":{"rendered":"https:\/\/kontracamps.com\/zgloszenie-zwrotu\/"},"modified":"2026-07-30T10:00:04","modified_gmt":"2026-07-30T08:00:04","slug":"zgloszenie-zwrotu","status":"publish","type":"page","link":"https:\/\/kontracamps.com\/pl\/zgloszenie-zwrotu\/","title":{"rendered":"Zg\u0142oszenie zwrotu"},"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\">Numer rezerwacji<\/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\">E-mail podany przy rezerwacji<\/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\">Kontynuuj<\/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\":\"Zg\\u0142o\\u015b zwrot\",\"withdrawBtn\":\"Wycofaj dru\\u017cyn\\u0119\",\"reasonLabel\":\"Pow\\u00f3d (opcjonalnie)\",\"refundTypeLabel\":\"Rodzaj zwrotu\",\"modeWhole\":\"Zwrot za ca\\u0142\\u0105 rezerwacj\\u0119\",\"modeSome\":\"Zwrot za wybranych uczestnik\\u00f3w\",\"participantsLabel\":\"Uczestnicy do zwrotu (odznacz tych, kt\\u00f3rzy zostaj\\u0105):\",\"needParticipant\":\"Zaznacz przynajmniej jednego uczestnika.\",\"payoutTitle\":\"Zwrot na\",\"payoutAccount\":\"Moje konto\",\"payoutVoucher\":\"Kredyt w sklepie (voucher)\",\"payoutVoucherBlocked\":\"Twoja ochrona przed anulowaniem zwraca \\u015brodki na pierwotn\\u0105 metod\\u0119 p\\u0142atno\\u015bci.\",\"payoutVoucherHint\":\"Otrzymasz wi\\u0119ksz\\u0105 kwot\\u0119 do wykorzystania na dowolny przysz\\u0142y ob\\u00f3z lub turniej.\",\"payoutVoucherInstallment\":\"Vouchery s\\u0105 dost\\u0119pne tylko dla rezerwacji op\\u0142aconych w ca\\u0142o\\u015bci.\",\"note\":\"Po wys\\u0142aniu zg\\u0142oszenia otrzymasz e-mail z linkiem potwierdzaj\\u0105cym. Zwrot jest finalizowany dopiero po jego klikni\\u0119ciu.\",\"genericError\":\"Co\\u015b posz\\u0142o nie tak. Spr\\u00f3buj ponownie.\",\"needRef\":\"Wybierz lub wpisz rezerwacj\\u0119.\",\"loading\":\"\\u0141adowanie\\u2026\",\"submitting\":\"Wysy\\u0142anie\\u2026\",\"recalcFailed\":\"Nie uda\\u0142o si\\u0119 przeliczy\\u0107 kwoty \\u2014 sprawd\\u017a po\\u0142\\u0105czenie i zaznacz uczestnika ponownie.\",\"payoutNone\":\"Dla tej rezerwacji nie przys\\u0142uguje wyp\\u0142ata zwrotu. W razie pyta\\u0144 skontaktuj si\\u0119 z nami.\",\"groupTitle\":\"Dru\\u017cyny w tym zam\\u00f3wieniu \\u2014 zaznacz, kto si\\u0119 wycofuje\",\"groupHint\":\"Zaznacz pozosta\\u0142e dru\\u017cyny, kt\\u00f3re wycofuj\\u0105 si\\u0119 razem z t\\u0105 \\u2014 jeden e-mail potwierdzaj\\u0105cy obejmie wszystkie zaznaczone.\",\"groupPrimaryHint\":\"dru\\u017cyna, kt\\u00f3r\\u0105 wycofujesz\",\"activeInitiated\":\"Zg\\u0142oszenie zwrotu dla tej rezerwacji jest ju\\u017c w toku. Sprawd\\u017a skrzynk\\u0119 i kliknij link potwierdzaj\\u0105cy, aby je sfinalizowa\\u0107 \\u2014 albo anuluj je poni\\u017cej i wy\\u015blij nowe.\",\"activeConfirmed\":\"Twoje zg\\u0142oszenie zwrotu dla tej rezerwacji jest potwierdzone i czeka na rozpatrzenie. Je\\u015bli chcesz je zmieni\\u0107, skontaktuj si\\u0119 z nami.\",\"activeProcessing\":\"Zwrot dla tej rezerwacji zosta\\u0142 zatwierdzony \\u2014 wyp\\u0142ata jest w drodze.\",\"activeGroupPrefix\":\"Ta rezerwacja jest cz\\u0119\\u015bci\\u0105 grupowego wycofania.\",\"resendBtn\":\"Wy\\u015blij ponownie e-mail potwierdzaj\\u0105cy\",\"cancelReqBtn\":\"Anuluj to zg\\u0142oszenie\"};\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-16050","page","type-page","status-publish","hentry"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/kontracamps.com\/pl\/wp-json\/wp\/v2\/pages\/16050","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/kontracamps.com\/pl\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/kontracamps.com\/pl\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/kontracamps.com\/pl\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/kontracamps.com\/pl\/wp-json\/wp\/v2\/comments?post=16050"}],"version-history":[{"count":0,"href":"https:\/\/kontracamps.com\/pl\/wp-json\/wp\/v2\/pages\/16050\/revisions"}],"wp:attachment":[{"href":"https:\/\/kontracamps.com\/pl\/wp-json\/wp\/v2\/media?parent=16050"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/kontracamps.com\/pl\/wp-json\/wp\/v2\/categories?post=16050"},{"taxonomy":"folder","embeddable":true,"href":"https:\/\/kontracamps.com\/pl\/wp-json\/wp\/v2\/folder?post=16050"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}