JSFiddle - React, Tailwind, and code Playground

HTML

<main class="anniversary-window" id="anniversaryWindow">

  <div class="shade" aria-hidden="true"></div>

  <div
    class="floating-ribbons"
    id="floatingRibbons"
    aria-hidden="true"
  ></div>

  <canvas
    class="fireworks"
    id="fireworks"
    aria-hidden="true"
  ></canvas>

  <section class="content" aria-labelledby="anniversaryTitle">
    <p class="eyebrow">CELEBRATE WITH US</p>

    <h1 id="anniversaryTitle">
      Rolife 9th Anniversary
    </h1>

    <p class="subtitle">
      Nine years of tiny worlds, wonderful stories and shared joy.
    </p>

    <button class="join-button" id="joinButton" type="button">
      <span class="button-sparkle" aria-hidden="true">✦</span>
      <span id="buttonText">
        Join Rolife 9th Anniversary
      </span>
    </button>

    <p class="counter" aria-live="polite">
      <span class="online-dot" aria-hidden="true"></span>
      <span id="counterText">
        Loading celebration count…
      </span>
    </p>

    <p
      class="status-message"
      id="statusMessage"
      aria-live="polite"
    ></p>
  </section>

  <div
    class="success-card"
    id="successCard"
    role="status"
    aria-live="polite"
  >
    <span class="success-icon">♥</span>

    <strong>
      You’re part of the celebration!
    </strong>

    <span>
      Thank you for celebrating nine wonderful years with Rolife.
    </span>
  </div>
</main>

CSS

:root {
  --cream: #fff8e9;
  --gold: #ffd676;
  --coral: #ff6f78;
  --rose: #db4267;
  --ink: #593244;
  --glass: rgba(82, 33, 48, 0.28);
}

* {
  box-sizing: border-box;
}

body {
  min-height: 100vh;
  margin: 0;
  display: grid;
  place-items: center;
  overflow-x: hidden;
  background: #271b25;
  color: var(--cream);
  font-family: "Trebuchet MS", "Avenir Next", Arial, sans-serif;
}

button,
input {
  font: inherit;
}

.anniversary-window {
  position: relative;
  isolation: isolate;
  width: min(100vw, 1440px);
  min-height: min(100vh, 900px);
  overflow: hidden;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  padding: 48px 24px 54px;
  background-color: #6b3e48;
  background-image: url("https://community.robotime.com/uploads/default/original/3X/7/f/7fcf175aa66bdbd70f5ad20bd80c8f01cdae9582.jpeg");
  background-position: center;
  background-size: cover;
  box-shadow: 0 24px 80px rgba(0, 0, 0, 0.4);
}

.shade {
  position: absolute;
  inset: 0;
  z-index: -1;
  background:
    linear-gradient(180deg, rgba(33, 16, 25, 0.03) 25%, rgba(33, 16, 25, 0.25) 58%, rgba(33, 16, 25, 0.82) 100%),
    radial-gradient(circle at 50% 68%, transparent 0 24%, rgba(28, 14, 20, 0.18) 72%);
}

.brand-logo {
  position: absolute;
  z-index: 4;
  top: clamp(20px, 4vw, 46px);
  left: clamp(20px, 5vw, 68px);
  width: clamp(92px, 12vw, 168px);
  max-height: 74px;
  object-fit: contain;
  object-position: left center;
  filter: drop-shadow(0 4px 12px rgba(0, 0, 0, 0.18));
}

.content {
  z-index: 3;
  width: min(720px, 100%);
  text-align: center;
  text-shadow: 0 2px 14px rgba(58, 26, 37, 0.55);
}

.eyebrow {
  margin: 0 0 7px;
  color: var(--gold);
  font-size: clamp(0.68rem, 1vw, 0.82rem);
  font-weight: 800;
  letter-spacing: 0.3em;
}

h1 {
  margin: 0;
  font-family: Georgia, "Times New Roman", serif;
  font-size: clamp(2rem, 5vw, 4.35rem);
  line-height: 1.02;
 ...

JavaScript

/* --------------------------------------------------------------------------
   1) Replace these values with your Supabase project details.
   Project URL: Supabase > Project Settings > Data API
   Browser key: Supabase > Project Settings > API Keys > Publishable key
   -------------------------------------------------------------------------- */
const CONFIG = {
  supabaseUrl: "https://snisuupgavqwiqxjyrkd.supabase.co",
  supabasePublishableKey: "sb_publishable_T1QQU1RKue_n9dWda8E1pQ_cuzvgkcA",
  counterId: "rolife-9th",
  demoStartingCount: 0
};

const joinButton = document.querySelector("#joinButton");
const buttonText = document.querySelector("#buttonText");
const counterText = document.querySelector("#counterText");
const statusMessage = document.querySelector("#statusMessage");
const successCard = document.querySelector("#successCard");
const canvas = document.querySelector("#fireworks");
const ctx = canvas.getContext("2d");

const joinedKey = `rolife-anniversary-joined:${CONFIG.counterId}`;
const visitorKey = "rolife-anniversary-visitor-id";
const demoCountKey = `rolife-anniversary-demo-count:${CONFIG.counterId}`;
const formatter = new Intl.NumberFormat("en-US");

let currentCount = CONFIG.demoStartingCount;
let particles = [];
let animationFrame = null;

function databaseIsConfigured() {
  return (
    CONFIG.supabaseUrl.startsWith("https://") &&
    !CONFIG.supabaseUrl.includes("YOUR_") &&
    CONFIG.supabasePublishableKey &&
    !CONFIG.supabasePublishableKey.includes("YOUR_")
  );
}

function getVisitorId() {
  let id = localStorage.getItem(visitorKey);
  if (!id) {
    id = crypto.randomUUID();
    localStorage.setItem(visitorKey, id);
  }
  return id;
}

function hasJoined() {
  return localStorage.getItem(joinedKey) === "true";
}

function setJoinedUI() {
  joinButton.disabled = true;
  buttonText.textContent = "You’re Celebrating With Us!";
}

function renderCount(count) {
  currentCount =...