openvibers/openvibe.live Commits

Ban page: animated sequence — stamp slam, message-by-message 'I asked you to stop' story, heartbeat verdict

OP OpenVibers committed 12 Sept 2026 · 13972c9cc8 · 1 file, +89 −25

Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01CMxJm1dB8rdsaMSgNjVa82

Changes

ddiff --git a/public/banned.html b/public/banned.html
iindex 1b194fe9..9738c5ab 100644
---- a/public/banned.html
++++ b/public/banned.html
@@@ -7,42 +7,106 @@
<title>Banned — OpenVibe.Live</title>
<link rel="icon" type="image/svg+xml" href="/assets/logo.svg">
<style>
-- :root { color-scheme: dark; }
++ :root { color-scheme: dark; --red: #e74c3c; --red-soft: #ff8a7a; }
* { box-sizing: border-box; }
-- body { margin: 0; min-height: 100vh; display: grid; place-items: center; padding: 24px 16px; font-family: 'Segoe UI', system-ui, -apple-system, sans-serif; color: #e8e6e3;
-- background: radial-gradient(120% 90% at 50% 110%, #3b0a0a 0%, #0d0d0f 60%); }
-- .card { max-width: 820px; width: 100%; text-align: center; padding: 36px 28px; border-radius: 20px; background: rgba(20,12,14,0.85); border: 1px solid rgba(231,76,60,0.45);
-- box-shadow: 0 30px 80px rgba(0,0,0,0.6), 0 0 0 1px rgba(231,76,60,0.2), 0 0 60px rgba(231,76,60,0.15); }
-- .stamp { display: inline-block; padding: 8px 22px; border: 4px solid #e74c3c; color: #e74c3c; border-radius: 10px; font-weight: 900; font-size: clamp(2rem, 8vw, 3.4rem); letter-spacing: 0.18em;
-- transform: rotate(-4deg); text-shadow: 0 0 20px rgba(231,76,60,0.5); }
-- h1 { margin: 22px 0 8px; font-size: clamp(1.3rem, 3.6vw, 1.9rem); }
-- .plea { margin: 26px 0 10px; font-size: clamp(2.2rem, 8.5vw, 4.6rem); line-height: 1.02; font-weight: 900; letter-spacing: -0.02em; color: #fff; text-shadow: 0 6px 30px rgba(0,0,0,0.6); }
-- .plea-body { font-size: clamp(1.25rem, 3.6vw, 1.9rem); line-height: 1.35; color: #fff; font-weight: 600; margin: 0 0 18px; }
-- .hurt { margin: 22px 0 8px; padding: 18px 16px 20px; border-radius: 16px; background: rgba(231,76,60,0.14); border: 2px solid rgba(231,76,60,0.7); box-shadow: 0 0 40px rgba(231,76,60,0.25) inset, 0 0 30px rgba(231,76,60,0.2); }
-- .hurt-head { font-size: clamp(1.9rem, 7vw, 3.6rem); line-height: 1.05; font-weight: 900; letter-spacing: -0.02em; color: #ff8a7a; text-shadow: 0 0 30px rgba(231,76,60,0.55); margin: 0 0 10px; }
-- .hurt-body { font-size: clamp(1.1rem, 3vw, 1.5rem); line-height: 1.4; color: #fff; font-weight: 700; margin: 0; }
-- .who { font-size: 1.05rem; color: #cfc9c4; margin: 0 0 6px; }
++ html, body { margin: 0; min-height: 100%; }
++ body { min-height: 100vh; display: grid; place-items: center; padding: 28px 16px 40px; font-family: 'Segoe UI', system-ui, -apple-system, sans-serif; color: #e8e6e3;
++ background: #0b0a0d; overflow-x: hidden; position: relative; }
++ /* Breathing red ground + slow drifting grain */
++ .bg { position: fixed; inset: 0; z-index: 0; pointer-events: none;
++ background: radial-gradient(120% 90% at 50% 115%, #4a0b0b 0%, #1a0708 45%, #0b0a0d 75%); animation: breathe 6s ease-in-out infinite; }
++ .bg::after { content: ''; position: absolute; inset: -50%; opacity: 0.07;
++ background-image: radial-gradient(rgba(255,255,255,0.9) 0.6px, transparent 0.7px); background-size: 3px 3px; animation: grain 1.4s steps(6) infinite; }
++ .vignette { position: fixed; inset: 0; z-index: 0; pointer-events: none; box-shadow: inset 0 0 160px 40px rgba(0,0,0,0.85); }
++ @keyframes breathe { 0%, 100% { filter: brightness(0.85); } 50% { filter: brightness(1.25); } }
++ @keyframes grain { 0% { transform: translate(0,0); } 20% { transform: translate(-4%,3%); } 40% { transform: translate(3%,-5%); } 60% { transform: translate(-2%,-2%); } 80% { transform: translate(4%,4%); } 100% { transform: translate(0,0); } }
++
++ .card { position: relative; z-index: 1; max-width: 860px; width: 100%; text-align: center; padding: 38px 26px 30px; border-radius: 22px; background: rgba(18,10,12,0.86); border: 1px solid rgba(231,76,60,0.45);
++ box-shadow: 0 30px 80px rgba(0,0,0,0.7), 0 0 0 1px rgba(231,76,60,0.2), 0 0 70px rgba(231,76,60,0.18); backdrop-filter: blur(6px); }
++
++ /* BANNED stamp slams in, the card shakes from the hit */
++ .stamp { display: inline-block; padding: 8px 24px; border: 4px solid var(--red); color: var(--red); border-radius: 10px; font-weight: 900; font-size: clamp(2rem, 8vw, 3.4rem); letter-spacing: 0.18em;
++ transform: rotate(-4deg); text-shadow: 0 0 20px rgba(231,76,60,0.5); animation: slam 0.55s cubic-bezier(.2,1.6,.4,1) both; }
++ @keyframes slam { 0% { transform: rotate(-14deg) scale(4); opacity: 0; } 60% { transform: rotate(-3deg) scale(0.96); opacity: 1; } 80% { transform: rotate(-5deg) scale(1.03); } 100% { transform: rotate(-4deg) scale(1); } }
++ .card.shake { animation: shake 0.4s 0.35s both; }
++ @keyframes shake { 0%,100% { transform: translate(0,0); } 20% { transform: translate(-7px,2px); } 40% { transform: translate(6px,-3px); } 60% { transform: translate(-4px,2px); } 80% { transform: translate(3px,-1px); } }
++
++ /* Reveal sequence */
++ .rv { opacity: 0; transform: translateY(18px); animation: rise 0.7s ease-out forwards; animation-delay: var(--d, 0s); }
++ @keyframes rise { to { opacity: 1; transform: none; } }
++
++ .plea { margin: 26px 0 8px; font-size: clamp(2.2rem, 8.5vw, 4.6rem); line-height: 1.02; font-weight: 900; letter-spacing: -0.02em; color: #fff; text-shadow: 0 6px 30px rgba(0,0,0,0.6); }
++ .plea-body { font-size: clamp(1.2rem, 3.5vw, 1.8rem); line-height: 1.35; color: #fff; font-weight: 600; margin: 0 0 22px; }
++
++ /* What happened — lines land one after another like messages */
++ .story { display: grid; gap: 10px; max-width: 640px; margin: 0 auto 24px; text-align: left; }
++ .msg { position: relative; padding: 12px 16px; border-radius: 16px 16px 16px 4px; background: rgba(255,255,255,0.06); border: 1px solid rgba(255,255,255,0.1); color: #f3efec; font-size: clamp(1rem, 2.8vw, 1.15rem); line-height: 1.45; font-weight: 600;
++ opacity: 0; transform: translateX(-24px) scale(0.98); animation: land 0.55s cubic-bezier(.2,.9,.3,1.2) forwards; animation-delay: var(--d); }
++ .msg.hot { background: rgba(231,76,60,0.16); border-color: rgba(231,76,60,0.55); color: #fff; }
++ .msg.hot::before { content: ''; position: absolute; inset: -1px; border-radius: inherit; animation: ring 1.6s ease-out 1; animation-delay: calc(var(--d) + 0.3s); pointer-events: none; }
++ @keyframes land { to { opacity: 1; transform: none; } }
++ @keyframes ring { 0% { box-shadow: 0 0 0 0 rgba(231,76,60,0.7); } 100% { box-shadow: 0 0 0 18px rgba(231,76,60,0); } }
++ .msg small { display: block; font-size: 0.7rem; letter-spacing: 0.12em; text-transform: uppercase; color: #c9a19b; margin-bottom: 3px; font-weight: 800; }
++
++ /* The verdict — heartbeat */
++ .hurt { margin: 8px 0 14px; padding: 22px 18px 24px; border-radius: 18px; background: rgba(231,76,60,0.14); border: 2px solid rgba(231,76,60,0.75);
++ box-shadow: 0 0 40px rgba(231,76,60,0.25) inset, 0 0 30px rgba(231,76,60,0.2); }
++ .hurt.beat { animation: rise 0.7s ease-out forwards, heartbeat 1.7s ease-in-out infinite; animation-delay: var(--d), calc(var(--d) + 0.7s); }
++ @keyframes heartbeat { 0%, 100% { transform: scale(1); box-shadow: 0 0 40px rgba(231,76,60,0.25) inset, 0 0 30px rgba(231,76,60,0.2); } 14% { transform: scale(1.025); box-shadow: 0 0 50px rgba(231,76,60,0.35) inset, 0 0 60px rgba(231,76,60,0.45); } 28% { transform: scale(1); } 42% { transform: scale(1.018); box-shadow: 0 0 50px rgba(231,76,60,0.3) inset, 0 0 50px rgba(231,76,60,0.35); } 56% { transform: scale(1); } }
++ .hurt-head { font-size: clamp(2rem, 8vw, 4rem); line-height: 1.02; font-weight: 900; letter-spacing: -0.02em; color: var(--red-soft); text-shadow: 0 0 30px rgba(231,76,60,0.6); margin: 0 0 12px; }
++ .hurt-body { font-size: clamp(1.1rem, 3.1vw, 1.55rem); line-height: 1.4; color: #fff; font-weight: 700; margin: 0; }
++ .hurt-body b { color: var(--red-soft); }
++
++ .who { font-size: 1.05rem; color: #cfc9c4; margin: 18px 0 6px; }
p { margin: 0 0 12px; font-size: 1.02rem; line-height: 1.55; color: #cfc9c4; }
p b { color: #fff; }
-- .reason { margin: 18px 0; padding: 12px 14px; border-radius: 12px; background: rgba(231,76,60,0.1); border-left: 3px solid #e74c3c; text-align: left; color: #f5d5d0; }
-- .reason small { display: block; font-size: 0.72rem; letter-spacing: 0.12em; text-transform: uppercase; color: #e74c3c; margin-bottom: 4px; }
++ .reason { margin: 14px 0; padding: 12px 14px; border-radius: 12px; background: rgba(231,76,60,0.1); border-left: 3px solid var(--red); text-align: left; color: #f5d5d0; }
++ .reason small { display: block; font-size: 0.72rem; letter-spacing: 0.12em; text-transform: uppercase; color: var(--red); margin-bottom: 4px; }
.fine { font-size: 0.82rem; color: #8a8480; margin-top: 18px; }
.logo { color: #a78bfa; font-weight: 800; text-decoration: none; }
++
++ @media (prefers-reduced-motion: reduce) {
++ .bg, .bg::after, .stamp, .card.shake, .rv, .msg, .msg.hot::before, .hurt.beat { animation: none !important; }
++ .rv, .msg { opacity: 1; transform: none; }
++ }
</style>
</head>
<body>
-- <div class="card">
++ <div class="bg"></div><div class="vignette"></div>
++ <div class="card shake">
<div class="stamp">BANNED</div>
-- <h1 class="plea">Please leave me alone.</h1>
-- <p class="plea-body">I'm trying to move forward with my life, and you have been nothing but disrespectful to me.</p>
-- <div class="hurt" role="alert">
++ <h1 class="plea rv" style="--d:0.5s">Please leave me alone.</h1>
++ <p class="plea-body rv" style="--d:0.9s">I'm trying to move forward with my life, and you have been nothing but disrespectful to me.</p>
++
++ <div class="story" aria-label="What happened">
++ <div class="msg" style="--d:1.6s"><small>I asked you</small>Please stop messaging me unless it's something respectful.</div>
++ <div class="msg" style="--d:2.5s"><small>I asked again</small>I'm being very serious. Please stop, because it is just hurting me.</div>
++ <div class="msg" style="--d:3.4s"><small>And again</small>Do not message me unless you have something respectful to say.</div>
++ <div class="msg hot" style="--d:4.4s"><small>What you did</small>You kept going anyway. Every message after that was you being rude to me.</div>
++ <div class="msg hot" style="--d:5.4s"><small>What it did</small>It only ever hurt me. Nothing else. And it sucks.</div>
++ </div>
++
++ <div class="hurt beat" style="--d:6.4s; opacity:0" role="alert">
<h2 class="hurt-head">You have ruined me.</h2>
-- <p class="hurt-body">What you did is hurtful. You did it, and you kept doing it. Please don't come here again.</p>
++ <p class="hurt-body">What you did is hurtful, and it is <b>unacceptable behavior</b>. I asked you to stop, over and over, and you kept doing it. Please don't come here again.</p>
</div>
-- <p class="who">{{HEADLINE}}</p>
-- <div class="reason"><small>Reason on record</small>{{REASON}}</div>
-- <p><b>This ban is permanent.</b> Don't put any effort into coming back — there is nothing here for you, and this decision won't change.</p>
-- <p class="fine"><span class="logo">OpenVibe.Live</span> · you will see this page every time you open the site, on every device and every network you use.</p>
++
++ <p class="who rv" style="--d:7.2s">{{HEADLINE}}</p>
++ <div class="reason rv" style="--d:7.4s"><small>Reason on record</small>{{REASON}}</div>
++ <p class="rv" style="--d:7.6s"><b>This ban is permanent.</b> Don't put any effort into coming back — there is nothing here for you, and this decision won't change.</p>
++ <p class="fine rv" style="--d:7.8s"><span class="logo">OpenVibe.Live</span> · you will see this page every time you open the site, on every device and every network you use.</p>
</div>
++ <script>
++ // If the tab was in the background while the sequence played, replay it when it is looked at.
++ (function () {
++ if (matchMedia('(prefers-reduced-motion: reduce)').matches) return;
++ document.addEventListener('visibilitychange', function () {
++ if (document.visibilityState !== 'visible') return;
++ document.querySelectorAll('.rv, .msg, .stamp, .hurt, .card').forEach(function (el) {
++ el.style.animation = 'none'; void el.offsetWidth; el.style.animation = '';
++ });
++ });
++ })();
++ </script>
</body>
</html>