feat: complete Quantumancy web app — full frontend + docs

Frontend (React 18 + TS + Vite):
- Landing: glitching hero, live /api/stats veil ticker, mode cards, featured spirits
- Séance: three.js shader ghost (hue/form per entity, mood + audio-reactive),
  Ouija planchette board spelling utterances, transcript with TTS replay,
  entity dossier, direct contact streaming, passive/active listening
- Modes: Wire Ghost telemetry panel, EVP mic anomaly detection, WebUSB
  RTL-SDR sweep + waterfall (hardware pass pending), Ouija/Direct Contact
- Codex: public registry + entity dossiers, rarity tiers, i18n EN/ES complete
- State: VeilSocket (reconnect/backoff), seance reducer, auth context
- 72 vitest tests green; served by FastAPI at :7777

Docs: README + as-built plans 3-7
This commit is contained in:
Indiana
2026-07-20 21:11:49 +00:00
parent 1ec9ea5863
commit 6edbbbbc2a
48 changed files with 10494 additions and 168 deletions

View File

@@ -1,84 +1,134 @@
/* Quantumancy global theme — gothic × hacker. Page-specific styles live in
each page's own CSS file; this is only the shared foundation. */
:root {
color-scheme: dark;
--qm-bg: #07070d;
--qm-panel: rgba(16, 16, 26, 0.85);
--qm-green: #7cffb2;
--qm-violet: #b26bff;
--qm-blood: #ff3b5c;
--qm-text: #d6e4dc;
--qm-dim: #8a8f98;
--qm-border: rgba(124, 255, 178, 0.18);
--qm-font-ui: 'IBM Plex Mono', 'Courier New', monospace;
--qm-font-display: 'Cinzel', Georgia, 'Times New Roman', serif;
}
* {
box-sizing: border-box;
}
html,
body,
#root {
margin: 0;
padding: 0;
min-height: 100vh;
background: var(--qm-bg);
}
body {
margin: 0;
min-height: 100vh;
background: #0a0a0f;
color: #e6e6f0;
font-family: Georgia, serif;
display: flex;
align-items: center;
justify-content: center;
color: var(--qm-text);
font-family: var(--qm-font-ui);
font-size: 15px;
line-height: 1.55;
overflow-x: hidden;
}
.app {
width: min(90vw, 420px);
padding: 2rem;
text-align: center;
h1,
h2,
h3,
.display {
font-family: var(--qm-font-display);
letter-spacing: 0.08em;
}
h1 {
font-size: 2.5rem;
letter-spacing: 0.1em;
margin-bottom: 0.25rem;
a {
color: var(--qm-green);
text-decoration: none;
}
.tagline {
opacity: 0.6;
margin-bottom: 2rem;
font-style: italic;
}
form {
display: flex;
flex-direction: column;
gap: 1rem;
text-align: left;
}
label {
display: flex;
flex-direction: column;
gap: 0.25rem;
font-size: 0.9rem;
opacity: 0.8;
}
input {
background: #16161f;
border: 1px solid #333;
color: inherit;
padding: 0.6rem;
border-radius: 4px;
font-size: 1rem;
a:hover {
text-shadow: 0 0 8px rgba(124, 255, 178, 0.6);
}
button {
background: #2a1f3d;
border: 1px solid #5a3f8f;
color: inherit;
padding: 0.6rem 1rem;
border-radius: 4px;
font-family: var(--qm-font-ui);
cursor: pointer;
font-size: 1rem;
}
button:hover {
background: #3a2a55;
input,
textarea {
font-family: var(--qm-font-ui);
}
.mode-toggle {
display: flex;
gap: 0.5rem;
::selection {
background: rgba(178, 107, 255, 0.35);
color: #fff;
}
.mode-toggle button.active {
background: #5a3f8f;
/* Thin phosphor scrollbar */
::-webkit-scrollbar {
width: 8px;
height: 8px;
}
::-webkit-scrollbar-track {
background: #0a0a12;
}
::-webkit-scrollbar-thumb {
background: rgba(124, 255, 178, 0.25);
border-radius: 4px;
}
::-webkit-scrollbar-thumb:hover {
background: rgba(124, 255, 178, 0.45);
}
.error {
color: #ff6b6b;
font-size: 0.9rem;
/* Global CRT glass: scanlines + vignette above every page, never clickable. */
.crt-overlay {
position: fixed;
inset: 0;
pointer-events: none;
z-index: 9999;
}
.crt-scanlines {
position: absolute;
inset: 0;
background: repeating-linear-gradient(
to bottom,
transparent 0px,
transparent 2px,
rgba(0, 0, 0, 0.14) 3px,
rgba(0, 0, 0, 0.14) 4px
);
mix-blend-mode: multiply;
opacity: 0.55;
}
.crt-vignette {
position: absolute;
inset: 0;
background: radial-gradient(
ellipse at center,
transparent 55%,
rgba(0, 0, 0, 0.55) 100%
);
}
/* Shared focus glow */
:focus-visible {
outline: 1px solid var(--qm-green);
outline-offset: 2px;
box-shadow: 0 0 12px rgba(124, 255, 178, 0.35);
}
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}