Spaces:
Running
Running
| /* ---- 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); | |
| } | |
| } | |