{"id":16052,"date":"2026-07-30T10:00:04","date_gmt":"2026-07-30T08:00:04","guid":{"rendered":"https:\/\/kontracamps.com\/demande-de-remboursement\/"},"modified":"2026-07-30T10:00:04","modified_gmt":"2026-07-30T08:00:04","slug":"demande-de-remboursement","status":"publish","type":"page","link":"https:\/\/kontracamps.com\/fr\/demande-de-remboursement\/","title":{"rendered":"Demande de remboursement"},"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\">R\u00e9f\u00e9rence de r\u00e9servation<\/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 utilis\u00e9 pour la r\u00e9servation<\/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\">Poursuivre<\/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\":\"Demander un remboursement\",\"withdrawBtn\":\"Retirer l'\\u00e9quipe\",\"reasonLabel\":\"Motif (facultatif)\",\"refundTypeLabel\":\"Type de remboursement\",\"modeWhole\":\"Rembourser toute la r\\u00e9servation\",\"modeSome\":\"Rembourser certains participants\",\"participantsLabel\":\"Participants \\u00e0 rembourser (d\\u00e9cochez ceux qui restent) :\",\"needParticipant\":\"Veuillez garder au moins un participant s\\u00e9lectionn\\u00e9.\",\"payoutTitle\":\"Rembourser sur\",\"payoutAccount\":\"Mon compte\",\"payoutVoucher\":\"Avoir (bon d'achat)\",\"payoutVoucherBlocked\":\"Votre protection annulation vous rembourse sur votre moyen de paiement d'origine.\",\"payoutVoucherHint\":\"Vous recevez un montant plus \\u00e9lev\\u00e9 \\u00e0 utiliser pour n'importe quel camp ou tournoi futur.\",\"payoutVoucherInstallment\":\"Les bons d'achat ne sont disponibles que pour les r\\u00e9servations int\\u00e9gralement pay\\u00e9es.\",\"note\":\"Apr\\u00e8s l'envoi, vous recevrez un e-mail contenant un lien de confirmation. Le remboursement n'est finalis\\u00e9 qu'apr\\u00e8s avoir cliqu\\u00e9 dessus.\",\"genericError\":\"Une erreur s'est produite. Veuillez r\\u00e9essayer.\",\"needRef\":\"Veuillez s\\u00e9lectionner ou saisir une r\\u00e9servation.\",\"loading\":\"Chargement\\u2026\",\"submitting\":\"Envoi\\u2026\",\"recalcFailed\":\"Nous n'avons pas pu recalculer le montant \\u2014 v\\u00e9rifiez votre connexion et cochez \\u00e0 nouveau un participant.\",\"payoutNone\":\"Aucun remboursement n'est possible pour cette r\\u00e9servation. Contactez-nous si vous avez des questions.\",\"groupTitle\":\"\\u00c9quipes de cette commande \\u2014 s\\u00e9lectionnez qui se retire\",\"groupHint\":\"Cochez les autres \\u00e9quipes qui se retirent en m\\u00eame temps \\u2014 un seul e-mail de confirmation couvrira toutes les \\u00e9quipes s\\u00e9lectionn\\u00e9es.\",\"groupPrimaryHint\":\"l'\\u00e9quipe que vous retirez\",\"activeInitiated\":\"Une demande de remboursement est d\\u00e9j\\u00e0 en cours pour cette r\\u00e9servation. Consultez votre bo\\u00eete mail et cliquez sur le lien de confirmation pour la finaliser \\u2014 ou annulez la demande ci-dessous et soumettez-en une nouvelle.\",\"activeConfirmed\":\"Votre demande de remboursement pour cette r\\u00e9servation est confirm\\u00e9e et en attente d'examen. Si vous souhaitez la modifier, contactez-nous.\",\"activeProcessing\":\"Votre remboursement pour cette r\\u00e9servation est approuv\\u00e9 \\u2014 le versement est en cours.\",\"activeGroupPrefix\":\"Cette r\\u00e9servation fait partie d'un retrait group\\u00e9.\",\"resendBtn\":\"Renvoyer l'e-mail de confirmation\",\"cancelReqBtn\":\"Annuler cette demande\"};\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-16052","page","type-page","status-publish","hentry"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/kontracamps.com\/fr\/wp-json\/wp\/v2\/pages\/16052","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/kontracamps.com\/fr\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/kontracamps.com\/fr\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/kontracamps.com\/fr\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/kontracamps.com\/fr\/wp-json\/wp\/v2\/comments?post=16052"}],"version-history":[{"count":0,"href":"https:\/\/kontracamps.com\/fr\/wp-json\/wp\/v2\/pages\/16052\/revisions"}],"wp:attachment":[{"href":"https:\/\/kontracamps.com\/fr\/wp-json\/wp\/v2\/media?parent=16052"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/kontracamps.com\/fr\/wp-json\/wp\/v2\/categories?post=16052"},{"taxonomy":"folder","embeddable":true,"href":"https:\/\/kontracamps.com\/fr\/wp-json\/wp\/v2\/folder?post=16052"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}