| /* ============================================================ | |
| RAIN WALKER — GLOBAL STYLES | |
| ============================================================ */ | |
| :root { | |
| --background: #000000; | |
| --foreground: #ffffff; | |
| } | |
| /* ------------------------------------------------------------ | |
| RESET | |
| ------------------------------------------------------------ */ | |
| * { | |
| box-sizing: border-box; | |
| margin: 0; | |
| padding: 0; | |
| } | |
| html, | |
| body { | |
| width: 100%; | |
| height: 100%; | |
| overflow: hidden; | |
| background: var(--background); | |
| color: var(--foreground); | |
| } | |
| body { | |
| position: fixed; | |
| inset: 0; | |
| font-family: | |
| "Courier New", | |
| Courier, | |
| monospace; | |
| overscroll-behavior: none; | |
| /* Prevent accidental selection while interacting */ | |
| user-select: none; | |
| -webkit-user-select: none; | |
| /* Prevent mobile touch scrolling */ | |
| touch-action: none; | |
| } | |
| /* ============================================================ | |
| GAME | |
| ============================================================ */ | |
| #game { | |
| position: fixed; | |
| inset: 0; | |
| width: 100vw; | |
| height: 100vh; | |
| overflow: hidden; | |
| background: #000000; | |
| } | |
| /* | |
| Three.js creates this canvas automatically. | |
| */ | |
| #game canvas { | |
| position: absolute; | |
| top: 0; | |
| left: 0; | |
| display: block; | |
| width: 100%; | |
| height: 100%; | |
| outline: none; | |
| /* | |
| Important for the eventual hybrid low-poly / | |
| pixel-art presentation. | |
| */ | |
| image-rendering: pixelated; | |
| image-rendering: crisp-edges; | |
| } | |
| /* ============================================================ | |
| LOADING SCREEN | |
| ============================================================ */ | |
| #loading-screen { | |
| position: fixed; | |
| inset: 0; | |
| z-index: 100; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| background: #000000; | |
| opacity: 1; | |
| visibility: visible; | |
| transition: | |
| opacity 1.2s ease, | |
| visibility 1.2s ease; | |
| } | |
| /* | |
| JavaScript adds this class once the GLB, | |
| environment and renderer are ready. | |
| */ | |
| #loading-screen.hidden { | |
| opacity: 0; | |
| visibility: hidden; | |
| pointer-events: none; | |
| } | |
| .loader-content { | |
| display: flex; | |
| flex-direction: column; | |
| align-items: center; | |
| gap: 20px; | |
| } | |
| #loading-text { | |
| font-size: 11px; | |
| font-weight: 700; | |
| letter-spacing: 4px; | |
| color: rgba(255, 255, 255, 0.62); | |
| text-transform: uppercase; | |
| } | |
| /* ------------------------------------------------------------ | |
| PIXEL LOADER | |
| ------------------------------------------------------------ */ | |
| .loader-pixel { | |
| width: 7px; | |
| height: 7px; | |
| background: #ffffff; | |
| animation: | |
| pixelPulse 1s steps(2, end) infinite; | |
| } | |
| @keyframes pixelPulse { | |
| 0% { | |
| opacity: 0.15; | |
| transform: scale(1); | |
| } | |
| 50% { | |
| opacity: 1; | |
| transform: scale(1.5); | |
| } | |
| 100% { | |
| opacity: 0.15; | |
| transform: scale(1); | |
| } | |
| } | |
| /* ============================================================ | |
| CINEMATIC SCREEN OVERLAY | |
| ============================================================ */ | |
| #screen-overlay { | |
| position: fixed; | |
| inset: 0; | |
| z-index: 50; | |
| pointer-events: none; | |
| background: #000000; | |
| opacity: 1; | |
| /* | |
| main.js will fade this away when the scene starts. | |
| */ | |
| transition: opacity 2s ease; | |
| } | |
| #screen-overlay.visible { | |
| opacity: 1; | |
| } | |
| #screen-overlay.hidden { | |
| opacity: 0; | |
| } | |
| /* ============================================================ | |
| OPTIONAL PIXEL / CRT ATMOSPHERE | |
| ============================================================ */ | |
| /* | |
| Very faint horizontal scan lines. | |
| They're deliberately subtle because the character itself | |
| will remain low-poly rather than becoming full pixel art. | |
| */ | |
| #game::after { | |
| content: ""; | |
| position: absolute; | |
| inset: 0; | |
| z-index: 10; | |
| pointer-events: none; | |
| background: | |
| repeating-linear-gradient( | |
| to bottom, | |
| rgba(255, 255, 255, 0.012) 0px, | |
| rgba(255, 255, 255, 0.012) 1px, | |
| transparent 1px, | |
| transparent 4px | |
| ); | |
| opacity: 0.45; | |
| } | |
| /* ============================================================ | |
| VIGNETTE | |
| ============================================================ */ | |
| #game::before { | |
| content: ""; | |
| position: absolute; | |
| inset: 0; | |
| z-index: 11; | |
| pointer-events: none; | |
| background: | |
| radial-gradient( | |
| ellipse at center, | |
| transparent 35%, | |
| rgba(0, 0, 0, 0.18) 60%, | |
| rgba(0, 0, 0, 0.72) 100% | |
| ); | |
| } | |
| /* ============================================================ | |
| MOBILE | |
| ============================================================ */ | |
| @media (max-width: 700px) { | |
| #loading-text { | |
| font-size: 9px; | |
| letter-spacing: 3px; | |
| } | |
| } | |
| /* ============================================================ | |
| ACCESSIBILITY | |
| ============================================================ */ | |
| @media (prefers-reduced-motion: reduce) { | |
| .loader-pixel { | |
| animation: none; | |
| } | |
| #loading-screen, | |
| #screen-overlay { | |
| transition-duration: 0.01ms; | |
| } | |
| } |