@joaobarrosfranca · 7/2/2026, 6:46:30 PM
Initial version — all lines are new.
+<!doctype html>+<html>+<head>+<meta charset="utf-8" />+<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />+<style>+ * { margin: 0; padding: 0; box-sizing: border-box; }+ html, body { width: 100%; height: 100%; overflow: hidden; }+ body {+ display: flex; align-items: center; justify-content: center;+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;+ background: radial-gradient(120% 120% at 50% 15%, #b18cff 0%, #8a5cf6 38%, #ff9a6b 100%);+ color: #fff;+ }+ /* Title sits TOP-LEFT — the top-right ~140x56 corner is reserved for platform chrome. */+ .tag {+ position: absolute; top: 20px; left: 20px;+ font-size: 13px; font-weight: 600; letter-spacing: .08em; text-transform: uppercase;+ opacity: .82;+ }+ .wrap { text-align: center; padding: 0 28px; }+ .orb {+ width: 128px; height: 128px; margin: 0 auto 26px;+ border-radius: 50%;+ background: radial-gradient(circle at 34% 30%, #fff 0%, #ffd9c2 30%, #ff9a6b 70%);+ box-shadow: 0 20px 60px rgba(80,20,120,.45);+ animation: float 3.4s ease-in-out infinite;+ }+ @keyframes float { 0%,100% { transform: translateY(0) } 50% { transform: translateY(-16px) } }+ h1 { font-size: 34px; line-height: 1.12; font-weight: 800; margin-bottom: 14px; }+ p { font-size: 16px; line-height: 1.5; opacity: .92; max-width: 20em; margin: 0 auto; }+ /* Action button at the BOTTOM-CENTRE per the platform HUD convention. */+ .btn {+ position: absolute; bottom: 34px; left: 50%; transform: translateX(-50%);+ border: 0; cursor: pointer;+ background: rgba(255,255,255,.92); color: #6d28d9;+ font-weight: 700; font-size: 16px; padding: 14px 26px; border-radius: 999px;+ box-shadow: 0 10px 30px rgba(0,0,0,.2);+ }+ .btn:active { transform: translateX(-50%) scale(.96); }+ .count { display:block; margin-top: 10px; font-size: 13px; opacity:.8; min-height: 16px; }+</style>+</head>+<body>+ <div class="tag">Liveloop × ActivityPub</div>+ <div class="wrap">+ <div class="orb"></div>+ <h1>Hello, Fediverse 👋</h1>+ <p>This little loop just travelled from Liveloop into Mastodon — over open protocols, no lock-in.</p>+ </div>+ <button class="btn" id="wave">Wave back 👋<span class="count" id="c"></span></button>+ <script>+ let n = 0;+ const c = document.getElementById('c');+ document.getElementById('wave').addEventListener('click', () => {+ n++;+ c.textContent = n === 1 ? '1 wave' : n + ' waves';+ document.querySelector('.orb').animate(+ [{ transform: 'scale(1)' }, { transform: 'scale(1.15)' }, { transform: 'scale(1)' }],+ { duration: 300, easing: 'ease-out' }+ );+ });+ </script>+</body>+</html>