.orbit-wrapper { position: absolute; bottom: 30px; right: 30px; width: 120px; height: 120px; z-index: 2000; user-select: none; } /* Core orb */ .orbit { width: 100%; height: 100%; border-radius: 50%; background: radial-gradient(circle at 30% 30%, var(--orb-core, #fff), transparent 70%); box-shadow: 0 0 15px var(--orb-glow, #0ff), 0 0 30px var(--orb-glow, #0ff); transform: scale(var(--orb-scale, 1)); opacity: var(--orb-opacity, 1); transition: all 0.3s ease, opacity 0.5s ease; cursor: grab; overflow: visible; animation: orbPulse 4s infinite ease-in-out; position: relative; } .orbit:hover { transform: scale(1.08); /* gentle grow */ box-shadow: 0 0 25px var(--orb-glow, #0ff), 0 0 50px var(--orb-glow, #0ff); filter: brightness(1.1); } .orbit:active { cursor: grabbing; } /* Inner aura ripple */ .orbit::before { content: ""; position: absolute; inset: -15%; border-radius: 50%; background: radial-gradient(circle, var(--orb-glow, #0ff), transparent 70%); opacity: 0.5; animation: orbRipple 6s infinite linear; } /* Outer rotating energy */ .orbit::after { content: ""; position: absolute; inset: -35%; border-radius: 50%; background: conic-gradient(from 0deg, var(--orb-ray, cyan), transparent 50%, var(--orb-ray, cyan)); animation: orbSpin 10s linear infinite; opacity: 0.3; } /* Resize handle */ .orbit-resize-handle { width: 14px; height: 14px; background: linear-gradient(135deg, #fff, #ddd); border: 2px solid #444; border-radius: 50%; position: absolute; bottom: -10px; right: -10px; cursor: nwse-resize; box-shadow: 0 0 6px rgba(255, 255, 255, 0.6); transition: transform 0.2s ease; } .orbit-resize-handle:hover { transform: scale(1.2); } /* -------------------- */ /* State animations */ /* -------------------- */ .orbit.listening { --orb-core: #00c6ff; --orb-glow: #00c6ff; --orb-ray: #0088ff; animation: listeningPulse 2s infinite ease-in-out; } .orbit.speaking { --orb-core: #ffdd55; --orb-glow: #ffbb00; --orb-ray: #ffaa00; animation: speakingRays 1.5s infinite alternate; } .orbit.thinking { --orb-core: #c77dff; --orb-glow: #a855f7; --orb-ray: #9333ea; animation: thinkingBreathe 3s infinite ease-in-out; } .orbit.error { --orb-core: #ff4d4d; --orb-glow: #ff1a1a; --orb-ray: #cc0000; animation: errorFlicker 0.5s infinite; } .orbit.idle { --orb-core: #fff; --orb-glow: #00f; --orb-ray: #f0f; background: conic-gradient(from 0deg, red, orange, yellow, lime, cyan, blue, violet, red); animation: rainbowFlow 6s linear infinite; background-size: 200% 200%; } /* -------------------- */ /* Keyframes */ /* -------------------- */ @keyframes orbPulse { 0%, 100% { transform: scale(var(--orb-scale, 1)); opacity: 0.9; } 50% { transform: scale(calc(var(--orb-scale, 1) * 1.08)); opacity: 1; } } @keyframes orbRipple { 0% { transform: scale(0.9); opacity: 0.3; } 50% { transform: scale(1.1); opacity: 0.6; } 100% { transform: scale(0.9); opacity: 0.3; } } @keyframes orbSpin { from { transform: rotate(0deg) scale(1); } to { transform: rotate(360deg) scale(1); } } @keyframes listeningPulse { 0%, 100% { box-shadow: 0 0 12px #00c6ff, 0 0 25px #0088ff; } 50% { box-shadow: 0 0 25px #00c6ff, 0 0 50px #0088ff; } } @keyframes speakingRays { 0% { box-shadow: 0 0 15px #ffaa00, 0 0 30px #ffbb00; } 100% { box-shadow: 0 0 30px #ffaa00, 0 0 60px #ffdd55; } } @keyframes thinkingBreathe { 0%, 100% { transform: scale(1); opacity: 0.9; } 50% { transform: scale(1.1); opacity: 1; } } @keyframes errorFlicker { 0%, 100% { opacity: 1; } 50% { opacity: 0.3; } } @keyframes rainbowFlow { from { filter: hue-rotate(0deg); } to { filter: hue-rotate(360deg); } }