/* ---- Base ---- */ * { box-sizing: border-box; margin: 0; padding: 0; -webkit-user-select: none; user-select: none; } :root { --font: "Comic Sans MS", "Chalkboard SE", "Baloo 2", "Segoe UI Rounded", system-ui, "Segoe UI", sans-serif; } html, body { height: 100%; overflow: hidden; font-family: var(--font); background: #1b2a4a; color: #fff; } #app { position: fixed; inset: 0; overflow: hidden; background: linear-gradient(160deg, #6ec6ff 0%, #a0e9ff 40%, #ffe29a 100%); cursor: none; /* the on-screen hand is the pointer */ } /* ---- Camera (mirrored) ---- */ #video { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; transform: scaleX(-1); /* mirror so it feels like a mirror; coords.js compensates */ z-index: 1; } /* ---- Game layer ---- */ #stage { position: absolute; inset: 0; z-index: 2; } #fruits-layer { position: absolute; inset: 0; } /* ---- Fruits ---- */ .fruit { position: absolute; display: flex; flex-direction: column; align-items: center; justify-content: center; transform-origin: center; animation: pop-in 0.5s cubic-bezier(0.34, 1.56, 0.64, 1) both; will-change: transform; } .fruit .emoji { font-size: 1em; /* .fruit font-size is set per-fruit in JS */ line-height: 1; filter: drop-shadow(0 6px 10px rgba(0, 0, 0, 0.35)); animation: float 3s ease-in-out infinite; z-index: 1; } .fruit .label { margin-top: 0.12em; font-size: 0.3em; font-weight: 700; padding: 0.15em 0.6em; border-radius: 999px; background: rgba(0, 0, 0, 0.45); color: #fff; white-space: nowrap; z-index: 1; } /* dwell progress ring — only visible while hovering */ .fruit .ring { position: absolute; top: -6%; left: -6%; width: 112%; height: 112%; opacity: 0; transition: opacity 0.15s ease; pointer-events: none; } .fruit.hover .ring { opacity: 1; } .fruit.hover { transform: scale(1.08); } .ring-bg { fill: none; stroke: rgba(255, 255, 255, 0.35); stroke-width: 7; } .ring-fg { fill: none; stroke: #fff44f; stroke-width: 8; stroke-linecap: round; transform: rotate(-90deg); transform-origin: 50% 50%; filter: drop-shadow(0 0 6px rgba(255, 244, 79, 0.9)); } /* feedback states */ .fruit.correct { animation: wow 1.2s cubic-bezier(0.34, 1.56, 0.64, 1) forwards; z-index: 4; } .fruit.correct .emoji { animation: none; filter: drop-shadow(0 0 22px rgba(255, 255, 120, 0.95)) drop-shadow(0 6px 10px rgba(0, 0, 0, 0.3)); } .fruit.wrong { animation: shake 0.7s ease both; } .fruit.wrong .emoji { animation: none; filter: grayscale(0.4) drop-shadow(0 6px 10px rgba(0, 0, 0, 0.35)); } .fruit.faded { opacity: 0.25; transform: scale(0.85); transition: opacity 0.5s ease, transform 0.5s ease; } /* ---- Hand cursor ---- */ #hand-icon { position: absolute; top: 0; left: 0; font-size: 66px; line-height: 1; opacity: 0; transition: opacity 0.2s ease; pointer-events: none; z-index: 5; filter: drop-shadow(0 4px 6px rgba(0, 0, 0, 0.55)); } #hand-icon.visible { opacity: 1; } /* ---- Confetti ---- */ #confetti { position: absolute; inset: 0; width: 100%; height: 100%; z-index: 3; pointer-events: none; } /* ---- HUD ---- */ #hud { position: absolute; top: 14px; left: 14px; right: 14px; display: flex; justify-content: space-between; align-items: flex-start; z-index: 6; pointer-events: none; } #score { display: flex; align-items: center; gap: 8px; background: rgba(0, 0, 0, 0.4); padding: 8px 18px; border-radius: 999px; font-size: clamp(24px, 4vw, 40px); font-weight: 800; } #score .star { filter: drop-shadow(0 0 6px rgba(255, 220, 80, 0.9)); } #score-value.pop { animation: score-pop 0.4s ease; display: inline-block; } #replay { pointer-events: auto; border: none; cursor: pointer; width: clamp(52px, 8vw, 66px); height: clamp(52px, 8vw, 66px); border-radius: 50%; background: #fff; color: #333; font-size: clamp(24px, 4vw, 32px); box-shadow: 0 4px 0 rgba(0, 0, 0, 0.25); transition: transform 0.1s ease; } #replay:active { transform: translateY(3px); box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); } /* ---- Prompt banner ---- */ #prompt-banner { position: absolute; top: 14px; left: 50%; transform: translateX(-50%); text-align: center; background: rgba(0, 0, 0, 0.45); padding: 10px 28px; border-radius: 22px; z-index: 6; max-width: 70vw; backdrop-filter: blur(2px); } #banner-main { font-size: clamp(26px, 5vw, 52px); font-weight: 800; text-shadow: 0 2px 6px rgba(0, 0, 0, 0.5); animation: banner-in 0.4s ease; } #banner-sub { font-size: clamp(16px, 2.6vw, 26px); opacity: 0.9; margin-top: 2px; } /* ---- No-hand hint ---- */ #hint { position: absolute; bottom: 6%; left: 50%; transform: translateX(-50%); background: rgba(0, 0, 0, 0.5); padding: 12px 26px; border-radius: 999px; font-size: clamp(20px, 3vw, 30px); font-weight: 700; z-index: 6; opacity: 0; transition: opacity 0.3s ease; pointer-events: none; } #hint.show { opacity: 1; animation: hint-bounce 1.2s ease-in-out infinite; } /* ---- Overlay (start / loading / error) ---- */ #overlay { position: absolute; inset: 0; z-index: 20; display: flex; align-items: center; justify-content: center; background: linear-gradient(160deg, rgba(30, 60, 120, 0.92), rgba(120, 60, 160, 0.92)); text-align: center; padding: 24px; } #overlay[hidden] { display: none; } #overlay .big-emoji { font-size: clamp(48px, 12vw, 96px); margin-bottom: 8px; animation: float 3s ease-in-out infinite; } #overlay h1 { font-size: clamp(34px, 8vw, 72px); margin-bottom: 10px; text-shadow: 0 4px 0 rgba(0, 0, 0, 0.2); } .subtitle { font-size: clamp(18px, 3.4vw, 28px); margin-bottom: 28px; opacity: 0.95; } .tiny { margin-top: 18px; font-size: clamp(13px, 2vw, 16px); opacity: 0.8; } #start-btn, #retry-btn { border: none; cursor: pointer; font-family: var(--font); font-weight: 800; font-size: clamp(24px, 5vw, 40px); color: #fff; padding: 16px 48px; border-radius: 999px; background: linear-gradient(180deg, #ff8a5b 0%, #ff5e7e 100%); box-shadow: 0 8px 0 rgba(0, 0, 0, 0.25), 0 12px 24px rgba(0, 0, 0, 0.3); transition: transform 0.12s ease, box-shadow 0.12s ease; } #start-btn:hover, #retry-btn:hover { transform: translateY(-2px); } #start-btn:active, #retry-btn:active { transform: translateY(6px); box-shadow: 0 2px 0 rgba(0, 0, 0, 0.25); } #error-text { font-size: clamp(18px, 3.4vw, 26px); max-width: 620px; line-height: 1.4; margin-bottom: 26px; } /* spinner */ .spinner { width: 64px; height: 64px; border: 8px solid rgba(255, 255, 255, 0.3); border-top-color: #fff; border-radius: 50%; animation: spin 1s linear infinite; margin: 0 auto 20px; } #loading p { font-size: clamp(18px, 3.4vw, 28px); } #loading[hidden], #error[hidden] { display: none; } /* ---- Keyframes ---- */ @keyframes pop-in { from { transform: scale(0); opacity: 0; } to { transform: scale(1); opacity: 1; } } @keyframes float { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-8px); } } @keyframes wow { 0% { transform: scale(1.08) rotate(0deg); } 30% { transform: scale(1.45) rotate(-8deg); } 50% { transform: scale(1.4) rotate(8deg); } 70% { transform: scale(1.5) rotate(-4deg); } 100% { transform: scale(1.5) rotate(0deg); } } @keyframes shake { 0%, 100% { transform: translateX(0) rotate(0); } 15% { transform: translateX(-12px) rotate(-6deg); } 30% { transform: translateX(12px) rotate(6deg); } 45% { transform: translateX(-10px) rotate(-5deg); } 60% { transform: translateX(10px) rotate(5deg); } 75% { transform: translateX(-6px) rotate(-3deg); } } @keyframes score-pop { 0% { transform: scale(1); } 50% { transform: scale(1.6); color: #fff44f; } 100% { transform: scale(1); } } @keyframes banner-in { from { transform: translateY(-12px); opacity: 0; } to { transform: translateY(0); opacity: 1; } } @keyframes hint-bounce { 0%, 100% { transform: translateX(-50%) translateY(0); } 50% { transform: translateX(-50%) translateY(-8px); } } @keyframes spin { to { transform: rotate(360deg); } }