{"id":185,"date":"2026-09-16T22:42:10","date_gmt":"2026-09-16T22:42:10","guid":{"rendered":"https:\/\/breadman.men\/?page_id=185"},"modified":"2026-09-17T05:30:31","modified_gmt":"2026-09-17T05:30:31","slug":"polls","status":"publish","type":"page","link":"https:\/\/breadman.men\/index.php\/polls\/","title":{"rendered":"Polls"},"content":{"rendered":"\n<div class=\"wp-block-buttons is-layout-flex wp-block-buttons-is-layout-flex\"><\/div>\n\n\n\n<!-- Floating Disband Button Linking to \/disband\/ -->\n<div id=\"floating-disband-container\" style=\"position: fixed; top: 95px; right: 24px; z-index: 99999; pointer-events: auto;\">\n  <a href=\"https:\/\/breadman.men\/index.php\/disband\/\" id=\"floating-disband-btn\" style=\"display: inline-flex; align-items: center; justify-content: center; background: #dc3545; color: #ffffff; font-family: inherit; font-size: 0.95rem; font-weight: 700; text-decoration: none; padding: 10px 18px; border-radius: 8px; border: 1px solid #b02a37; box-shadow: 0 4px 16px rgba(220, 53, 69, 0.4); cursor: pointer; transition: all 0.2s ease; user-select: none;\">\n    Disband the Friend Group\n  <\/a>\n<\/div>\n\n<style>\n  #floating-disband-btn:hover {\n    background: #bb2d3b !important;\n    transform: translateY(-2px);\n    box-shadow: 0 6px 22px rgba(220, 53, 69, 0.6) !important;\n    color: #ffffff !important;\n    text-decoration: none !important;\n  }\n  #floating-disband-btn:active {\n    transform: translateY(0);\n  }\n  @media (max-width: 600px) {\n    #floating-disband-container {\n      top: auto !important;\n      bottom: 20px !important;\n      right: 16px !important;\n    }\n    #floating-disband-btn {\n      font-size: 0.85rem !important;\n      padding: 10px 14px !important;\n    }\n  }\n<\/style>\n\n\n    <script src=\"https:\/\/cdn.jsdelivr.net\/npm\/canvas-confetti@1.9.3\/dist\/confetti.browser.min.js\"><\/script>\n\n    <style>\n        .shared-poll-box {\n            max-width: 580px;\n            margin: 40px auto;\n            background: #181818;\n            border: 1px solid #282828;\n            border-radius: 12px;\n            padding: 30px;\n            color: #eee;\n            box-shadow: 0 10px 30px rgba(0,0,0,0.5);\n            font-family: inherit;\n            position: relative;\n        }\n        .shared-poll-box h2 {\n            margin-top: 0;\n            color: #fff;\n            text-align: center;\n        }\n        .poll-field {\n            margin-bottom: 20px;\n            display: flex;\n            flex-direction: column;\n            gap: 8px;\n        }\n        .poll-field label {\n            font-weight: 600;\n            font-size: 0.95rem;\n            color: #bbb;\n        }\n        .poll-field input, .poll-field textarea {\n            width: 100%;\n            background: #242424;\n            border: 1px solid #3a3a3a;\n            border-radius: 6px;\n            padding: 10px 14px;\n            color: #fff;\n            box-sizing: border-box;\n            font-size: 1rem;\n        }\n        .poll-field input:focus, .poll-field textarea:focus {\n            outline: none;\n            border-color: #ffb400;\n        }\n        .poll-action-btn {\n            background: #ffb400;\n            color: #111;\n            font-weight: bold;\n            border: none;\n            border-radius: 6px;\n            padding: 12px 20px;\n            font-size: 1rem;\n            cursor: pointer;\n            width: 100%;\n            transition: opacity 0.2s ease;\n        }\n        .poll-action-btn:hover { opacity: 0.9; }\n        .poll-card {\n            background: #222;\n            border: 1px solid #333;\n            border-radius: 8px;\n            padding: 14px 18px;\n            margin-bottom: 12px;\n            cursor: pointer;\n            transition: all 0.2s ease;\n            position: relative;\n            overflow: hidden;\n        }\n        .poll-card:hover:not(.locked) {\n            border-color: #ffb400;\n            background: #2a2a2a;\n        }\n        .poll-card.selected-choice {\n            border: 2px solid #ffb400 !important;\n            background: #252218 !important;\n        }\n        .poll-card.locked { cursor: default; }\n        .poll-bar {\n            position: absolute;\n            top: 0; left: 0; bottom: 0;\n            background: rgba(255, 180, 0, 0.18);\n            width: 0%;\n            transition: width 0.3s ease;\n            z-index: 1;\n        }\n        .poll-content {\n            position: relative;\n            z-index: 2;\n            display: flex;\n            justify-content: space-between;\n            align-items: center;\n        }\n        .hijack-active {\n            border: 2px solid #dc3545 !important;\n            background: #200d0f !important;\n            animation: pulse-red 1.2s infinite alternate;\n        }\n        @keyframes pulse-red {\n            from { box-shadow: 0 0 10px rgba(220, 53, 69, 0.4); }\n            to { box-shadow: 0 0 25px rgba(220, 53, 69, 0.9); }\n        }\n        .admin-btn-row {\n            display: flex;\n            gap: 10px;\n            margin-top: 22px;\n        }\n        .hijack-btn {\n            background: #dc3545;\n            color: #fff;\n            border: none;\n            border-radius: 6px;\n            padding: 10px 14px;\n            cursor: pointer;\n            font-weight: bold;\n            font-size: 0.85rem;\n            flex: 1;\n        }\n        .hijack-btn:hover { background: #bb2d3b; }\n        .release-btn {\n            background: #28a745;\n            color: #fff;\n            border: none;\n            border-radius: 6px;\n            padding: 10px 14px;\n            cursor: pointer;\n            font-weight: bold;\n            font-size: 0.85rem;\n            flex: 1;\n        }\n        .release-btn:hover { background: #218838; }\n        .end-poll-btn {\n            background: #444;\n            color: #ffb400;\n            border: 1px solid #555;\n            border-radius: 6px;\n            padding: 10px 14px;\n            cursor: pointer;\n            font-weight: bold;\n            font-size: 0.85rem;\n            flex: 1;\n        }\n        .end-poll-btn:hover { background: #555; }\n        .apology-box {\n            background: rgba(40, 167, 69, 0.2);\n            border: 2px solid #28a745;\n            color: #a3f7b5;\n            padding: 16px 20px;\n            border-radius: 8px;\n            margin-bottom: 22px;\n            text-align: center;\n            font-size: 1.15rem;\n            font-weight: bold;\n            box-shadow: 0 4px 15px rgba(40, 167, 69, 0.3);\n            animation: fadeIn 0.4s ease;\n        }\n        @keyframes fadeIn {\n            from { opacity: 0; transform: translateY(-8px); }\n            to { opacity: 1; transform: translateY(0); }\n        }\n    <\/style>\n\n    <div class=\"shared-poll-box\" id=\"shared-poll\">\n        <!-- Apology Alert Banner -->\n        <div id=\"sp-apology\" class=\"apology-box\" style=\"display: none;\"><\/div>\n\n        <!-- Setup View -->\n        <div id=\"sp-setup\" style=\"display: none;\">\n            <h2>Start a New Poll<\/h2>\n            <div class=\"poll-field\">\n                <label>Question \/ Topic:<\/label>\n                <input type=\"text\" id=\"sp-question\" placeholder=\"e.g., Which album or movie should we review next?\" \/>\n            <\/div>\n            <div class=\"poll-field\">\n                <label>Options (one per line):<\/label>\n                <textarea id=\"sp-options\" rows=\"4\" placeholder=\"Option 1&#10;Option 2&#10;Option 3\"><\/textarea>\n            <\/div>\n            <div class=\"poll-field\">\n                <label>Total Votes Allowed Across Site:<\/label>\n                <input type=\"number\" id=\"sp-max-votes\" value=\"5\" min=\"1\" \/>\n            <\/div>\n            <button class=\"poll-action-btn\" onclick=\"submitNewPoll()\">Publish Poll<\/button>\n        <\/div>\n\n        <!-- Live Voting View -->\n        <div id=\"sp-voting\" style=\"display: none;\">\n            <h2 id=\"sp-display-title\" style=\"margin-bottom: 6px;\"><\/h2>\n            <p style=\"text-align: center; color: #888; margin-top: 0; margin-bottom: 8px;\">\n                Total Votes: <span id=\"sp-vote-count\" style=\"color: #ffb400; font-weight: bold;\">0<\/span> \/ <span id=\"sp-vote-max\">0<\/span>\n            <\/p>\n            <p id=\"sp-switch-hint\" style=\"text-align: center; color: #777; font-size: 0.82rem; margin-top: 0; margin-bottom: 20px; display: none;\">\n                \ud83d\udca1 You voted. Click any other option to switch your vote before the poll closes.\n            <\/p>\n\n            <div id=\"sp-options-container\"><\/div>\n\n            <div id=\"sp-winner-box\" style=\"display: none; text-align: center; background: rgba(255,180,0,0.1); border: 1px solid #ffb400; border-radius: 8px; padding: 16px; margin-top: 25px;\">\n                <h3 id=\"sp-winner-heading\" style=\"margin: 0 0 6px 0; color: #ffb400;\">\ud83c\udf89 Winner!<\/h3>\n                <div id=\"sp-winner-text\" style=\"font-size: 1.15rem; font-weight: 600; color: #fff;\"><\/div>\n                <button class=\"poll-action-btn\" style=\"margin-top: 15px; background: #333; color: #eee;\" onclick=\"resetSharedPoll()\">Create Another Poll<\/button>\n            <\/div>\n\n                    <\/div>\n    <\/div>\n\n    <script>\n        const restBase = 'https:\/\/breadman.men\/index.php\/wp-json\/custom-poll\/v1';\n        const restNonce = '779c2a0bc1';\n\n        let mySelectedChoice = sessionStorage.getItem('poll_my_choice') !== null \n            ? parseInt(sessionStorage.getItem('poll_my_choice'), 10) \n            : null;\n\n        let isFetching = false;\n\n        async function fetchPollState() {\n            if (isFetching) return;\n            isFetching = true;\n            try {\n                const res = await fetch(restBase + '\/state?_t=' + Date.now(), { cache: 'no-store' });\n                const poll = await res.json();\n                renderPollState(poll);\n            } catch (err) {\n                console.error('Poll fetch error:', err);\n            } finally {\n                isFetching = false;\n            }\n        }\n\n        function renderPollState(poll) {\n            const container = document.getElementById('shared-poll');\n            const setupView = document.getElementById('sp-setup');\n            const votingView = document.getElementById('sp-voting');\n            const apologyEl = document.getElementById('sp-apology');\n            const switchHint = document.getElementById('sp-switch-hint');\n\n            if (!poll || !poll.active) {\n                container.classList.remove('hijack-active');\n                setupView.style.display = 'block';\n                votingView.style.display = 'none';\n                apologyEl.style.display = 'none';\n                mySelectedChoice = null;\n                sessionStorage.removeItem('poll_my_choice');\n                return;\n            }\n\n            setupView.style.display = 'none';\n            votingView.style.display = 'block';\n\n            if (poll.apology && poll.apology.length > 0) {\n                apologyEl.innerHTML = '\ud83d\udcac <em>\"' + poll.apology + '\"<\/em>';\n                apologyEl.style.display = 'block';\n            } else {\n                apologyEl.style.display = 'none';\n            }\n\n            \/\/ Accurately sum all votes across options to prevent 100%+ glitches\n            const totalCastVotes = poll.options.reduce((sum, opt) => sum + (parseInt(opt.votes, 10) || 0), 0);\n            const isFinished = totalCastVotes >= poll.maxVotes;\n\n            \/\/ Admin buttons toggle\n            const hijackBtn = document.getElementById('admin-hijack-btn');\n            const releaseBtn = document.getElementById('admin-release-btn');\n            const endBtn = document.getElementById('admin-end-btn');\n\n            if (poll.hijacked) {\n                container.classList.add('hijack-active');\n                if (hijackBtn) hijackBtn.style.display = 'none';\n                if (releaseBtn) releaseBtn.style.display = 'block';\n                if (endBtn) endBtn.style.display = 'none';\n            } else {\n                container.classList.remove('hijack-active');\n                if (hijackBtn) hijackBtn.style.display = 'block';\n                if (releaseBtn) releaseBtn.style.display = 'none';\n                if (endBtn) endBtn.style.display = isFinished ? 'none' : 'block';\n            }\n\n            document.getElementById('sp-display-title').innerText = poll.question;\n            document.getElementById('sp-vote-count').innerText = totalCastVotes;\n            document.getElementById('sp-vote-max').innerText = poll.maxVotes;\n\n            if (mySelectedChoice !== null && !isFinished) {\n                switchHint.style.display = 'block';\n            } else {\n                switchHint.style.display = 'none';\n            }\n\n            const optsDiv = document.getElementById('sp-options-container');\n            optsDiv.innerHTML = '';\n\n            poll.options.forEach((opt, idx) => {\n                \/\/ Calculated strictly against totalCastVotes\n                const percent = totalCastVotes > 0 ? Math.round((opt.votes \/ totalCastVotes) * 100) : 0;\n                const isSelected = (mySelectedChoice === idx);\n\n                const card = document.createElement('div');\n                card.className = 'poll-card' + (isFinished ? ' locked' : '') + (isSelected ? ' selected-choice' : '');\n\n                if (!isFinished && !isSelected) {\n                    card.onclick = () => castOrChangeVote(idx);\n                }\n\n                const checkIcon = isSelected ? '<span style=\"color: #ffb400; margin-right: 6px;\">\u2713<\/span>' : '';\n\n                card.innerHTML = `\n                    <div class=\"poll-bar\" style=\"width: ${percent}%;\"><\/div>\n                    <div class=\"poll-content\">\n                        <span style=\"font-weight: 500;\">${checkIcon}${opt.text}<\/span>\n                        <span style=\"color: #ffb400; font-weight: bold;\">${opt.votes} (${percent}%)<\/span>\n                    <\/div>\n                `;\n                optsDiv.appendChild(card);\n            });\n\n            \/\/ Finish banner & Confetti\n            const winBox = document.getElementById('sp-winner-box');\n            if (isFinished) {\n                let max = -1;\n                let winners = [];\n                poll.options.forEach(o => {\n                    if (o.votes > max) { max = o.votes; winners = [o.text]; }\n                    else if (o.votes === max) { winners.push(o.text); }\n                });\n\n                if (poll.hijacked) {\n                    document.getElementById('sp-winner-heading').innerText = '\ud83d\udea8 POLL COMPROMISED';\n                    document.getElementById('sp-winner-text').innerText = 'ALL YOUR POLL ARE BELONG TO ME';\n                } else {\n                    document.getElementById('sp-winner-heading').innerText = '\ud83c\udf89 Winner!';\n                    if (max === 0) {\n                        document.getElementById('sp-winner-text').innerText = 'Poll ended with no votes cast!';\n                    } else {\n                        document.getElementById('sp-winner-text').innerText = winners.join(' & ') + ` (${max} vote${max === 1 ? '' : 's'})`;\n                    }\n                    triggerConfetti();\n                }\n                winBox.style.display = 'block';\n            } else {\n                winBox.style.display = 'none';\n            }\n        }\n\n        async function submitNewPoll() {\n            const question = document.getElementById('sp-question').value.trim();\n            const rawOpts = document.getElementById('sp-options').value.trim().split('\\n');\n            const maxVotes = parseInt(document.getElementById('sp-max-votes').value, 10);\n\n            if (!question || rawOpts.length < 2) {\n                alert('Please enter a question and at least 2 options.');\n                return;\n            }\n\n            mySelectedChoice = null;\n            sessionStorage.removeItem('poll_my_choice');\n            confettiFired = false;\n\n            const res = await fetch(restBase + '\/update', {\n                method: 'POST',\n                headers: { 'Content-Type': 'application\/json', 'X-WP-Nonce': restNonce },\n                body: JSON.stringify({ action: 'create', question, options: rawOpts, maxVotes })\n            });\n            const poll = await res.json();\n            renderPollState(poll);\n        }\n\n        async function castOrChangeVote(newIndex) {\n            const prevIndex = mySelectedChoice;\n            mySelectedChoice = newIndex;\n            sessionStorage.setItem('poll_my_choice', newIndex);\n\n            const res = await fetch(restBase + '\/update', {\n                method: 'POST',\n                headers: { 'Content-Type': 'application\/json', 'X-WP-Nonce': restNonce },\n                body: JSON.stringify({ \n                    action: 'vote', \n                    optionIndex: newIndex, \n                    previousIndex: prevIndex \n                })\n            });\n            const poll = await res.json();\n            renderPollState(poll);\n        }\n\n        async function adminEndPoll() {\n            if (!confirm('Are you sure you want to end this poll early and lock the results?')) return;\n            const res = await fetch(restBase + '\/update', {\n                method: 'POST',\n                headers: { 'Content-Type': 'application\/json', 'X-WP-Nonce': restNonce },\n                body: JSON.stringify({ action: 'end_poll' })\n            });\n            const poll = await res.json();\n            renderPollState(poll);\n        }\n\n        async function hijackPoll() {\n            const res = await fetch(restBase + '\/update', {\n                method: 'POST',\n                headers: { 'Content-Type': 'application\/json', 'X-WP-Nonce': restNonce },\n                body: JSON.stringify({ action: 'hijack' })\n            });\n            const poll = await res.json();\n            renderPollState(poll);\n        }\n\n        async function releasePoll() {\n            const res = await fetch(restBase + '\/update', {\n                method: 'POST',\n                headers: { 'Content-Type': 'application\/json', 'X-WP-Nonce': restNonce },\n                body: JSON.stringify({ action: 'release' })\n            });\n            const poll = await res.json();\n            renderPollState(poll);\n        }\n\n        async function resetSharedPoll() {\n            mySelectedChoice = null;\n            sessionStorage.removeItem('poll_my_choice');\n            confettiFired = false;\n            const res = await fetch(restBase + '\/update', {\n                method: 'POST',\n                headers: { 'Content-Type': 'application\/json', 'X-WP-Nonce': restNonce },\n                body: JSON.stringify({ action: 'reset' })\n            });\n            renderPollState({ active: false });\n        }\n\n        let confettiFired = false;\n        function triggerConfetti() {\n            if (confettiFired || typeof confetti !== 'function') return;\n            confettiFired = true;\n            confetti({ particleCount: 120, spread: 80, origin: { y: 0.6 } });\n            setTimeout(() => {\n                confetti({ particleCount: 50, angle: 60, spread: 55, origin: { x: 0 } });\n                confetti({ particleCount: 50, angle: 120, spread: 55, origin: { x: 1 } });\n            }, 200);\n        }\n\n        fetchPollState();\n        setInterval(fetchPollState, 500);\n    <\/script>\n    \n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Disband the Friend Group<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"pages-with-header-footer","meta":{"_acf_changed":false,"footnotes":""},"class_list":["post-185","page","type-page","status-publish","hentry"],"acf":[],"_links":{"self":[{"href":"https:\/\/breadman.men\/index.php\/wp-json\/wp\/v2\/pages\/185","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/breadman.men\/index.php\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/breadman.men\/index.php\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/breadman.men\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/breadman.men\/index.php\/wp-json\/wp\/v2\/comments?post=185"}],"version-history":[{"count":19,"href":"https:\/\/breadman.men\/index.php\/wp-json\/wp\/v2\/pages\/185\/revisions"}],"predecessor-version":[{"id":278,"href":"https:\/\/breadman.men\/index.php\/wp-json\/wp\/v2\/pages\/185\/revisions\/278"}],"wp:attachment":[{"href":"https:\/\/breadman.men\/index.php\/wp-json\/wp\/v2\/media?parent=185"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}