Files
qtalker---/frontend/src/pages/CodexEntityPage.css
Indiana 6edbbbbc2a 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
2026-07-20 21:11:49 +00:00

483 lines
9.9 KiB
CSS

/* Codex dossier — single-spirit occult record. Same token palette as the registry:
bg #07070d, panel rgba(16,16,26,0.85), phosphor #7cffb2, violet #b26bff,
blood #ff3b5c (sparingly), borders rgba(124,255,178,0.18). */
.codex-detail-page {
min-height: 100vh;
width: 100%;
background:
radial-gradient(ellipse 70% 45% at 50% 0%, rgba(178, 107, 255, 0.09), transparent 70%),
#07070d;
color: #d8e6dc;
font-family: 'IBM Plex Mono', ui-monospace, monospace;
padding: 2rem clamp(1rem, 4vw, 3rem) 5rem;
box-sizing: border-box;
position: relative;
}
/* scanlines + vignette */
.codex-detail-overlay {
position: fixed;
inset: 0;
pointer-events: none;
z-index: 10;
background:
repeating-linear-gradient(
0deg,
rgba(255, 255, 255, 0.022) 0px,
rgba(255, 255, 255, 0.022) 1px,
transparent 1px,
transparent 3px
),
radial-gradient(ellipse at center, transparent 55%, rgba(0, 0, 0, 0.6) 100%);
}
/* ---- nav / states ---- */
.codex-detail-nav {
max-width: 780px;
margin: 0 auto 2.2rem;
}
.codex-detail-back {
font-size: 0.72rem;
letter-spacing: 0.18em;
text-transform: uppercase;
color: rgba(124, 255, 178, 0.55);
text-decoration: none;
transition: color 160ms ease, text-shadow 160ms ease;
}
.codex-detail-back:hover,
.codex-detail-back:focus-visible {
color: #7cffb2;
text-shadow: 0 0 12px rgba(124, 255, 178, 0.7);
}
.codex-detail-state {
text-align: center;
font-size: 0.85rem;
letter-spacing: 0.1em;
color: rgba(124, 255, 178, 0.65);
padding: 5rem 0;
animation: codex-detail-breathe 2.4s ease-in-out infinite;
}
.codex-detail-state-error {
color: #ff3b5c;
text-shadow: 0 0 14px rgba(255, 59, 92, 0.45);
animation: none;
}
/* ---- 404 / not reached ---- */
.codex-detail-missing {
max-width: 560px;
margin: 4rem auto 0;
text-align: center;
display: flex;
flex-direction: column;
align-items: center;
gap: 1.6rem;
}
.codex-detail-missing-sigil {
width: 110px;
height: 110px;
border-radius: 50%;
border: 1px dashed rgba(124, 255, 178, 0.35);
box-shadow:
inset 0 0 30px rgba(124, 255, 178, 0.06),
0 0 24px rgba(124, 255, 178, 0.08);
animation: codex-detail-sigil-spin 26s linear infinite;
}
.codex-detail-missing-title {
font-family: 'Cinzel', Georgia, serif;
font-size: clamp(1.4rem, 4vw, 2rem);
font-weight: 700;
letter-spacing: 0.14em;
margin: 0;
color: rgba(238, 247, 240, 0.85);
text-shadow: 0 0 18px rgba(124, 255, 178, 0.25);
animation: codex-detail-flicker 9s linear infinite;
}
/* ---- dossier sheet ---- */
.codex-dossier {
max-width: 780px;
margin: 0 auto;
background: rgba(16, 16, 26, 0.85);
border: 1px solid rgba(124, 255, 178, 0.18);
border-radius: 12px;
padding: clamp(1.8rem, 5vw, 3.2rem);
position: relative;
box-shadow:
0 24px 60px rgba(0, 0, 0, 0.5),
0 0 40px rgba(124, 255, 178, 0.05);
}
.codex-dossier::before {
content: '';
position: absolute;
inset: 10px;
border: 1px solid rgba(124, 255, 178, 0.08);
border-radius: 8px;
pointer-events: none;
}
.codex-dossier[data-rarity='rare'] {
border-color: rgba(178, 107, 255, 0.35);
}
.codex-dossier[data-rarity='mythic'] {
border-color: rgba(255, 157, 74, 0.4);
box-shadow:
0 24px 60px rgba(0, 0, 0, 0.5),
0 0 44px rgba(255, 157, 74, 0.1);
}
/* ---- dossier header ---- */
.codex-dossier-header {
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
gap: 0.55rem;
padding-bottom: 1.8rem;
border-bottom: 1px solid rgba(124, 255, 178, 0.14);
margin-bottom: 1.8rem;
}
.codex-dossier-glyph {
width: 150px;
height: 150px;
border-radius: 50%;
background: radial-gradient(
circle at 50% 42%,
hsl(var(--glyph-hue), 82%, 74%) 0%,
hsl(var(--glyph-hue), 80%, 65%) 24%,
hsla(var(--glyph-hue), 80%, 55%, 0.3) 52%,
transparent 72%
);
filter: blur(2px);
opacity: 0.92;
animation: codex-detail-glyph-drift 8s ease-in-out infinite;
margin-bottom: 0.4rem;
}
.codex-dossier-form {
font-size: 0.64rem;
letter-spacing: 0.34em;
text-transform: uppercase;
color: rgba(216, 230, 220, 0.4);
}
.codex-dossier-name {
font-family: 'Cinzel', Georgia, serif;
font-size: clamp(1.9rem, 5vw, 2.8rem);
font-weight: 700;
letter-spacing: 0.16em;
margin: 0.2rem 0 0;
color: #eef7f0;
text-shadow:
0 0 18px rgba(124, 255, 178, 0.3),
0 0 46px rgba(178, 107, 255, 0.2);
animation: codex-detail-flicker 11s linear infinite;
}
.codex-dossier-epithet {
margin: 0;
font-size: 0.82rem;
letter-spacing: 0.1em;
font-style: italic;
color: rgba(178, 107, 255, 0.8);
}
.codex-dossier-rarity {
display: inline-block;
font-size: 0.62rem;
letter-spacing: 0.3em;
text-transform: uppercase;
padding: 0.26rem 0.85rem;
border: 1px solid;
border-radius: 999px;
margin-top: 0.5rem;
}
.codex-dossier-rarity[data-rarity='common'] {
color: #8a8f98;
border-color: rgba(138, 143, 152, 0.45);
}
.codex-dossier-rarity[data-rarity='uncommon'] {
color: #7cffb2;
border-color: rgba(124, 255, 178, 0.45);
}
.codex-dossier-rarity[data-rarity='rare'] {
color: #b26bff;
border-color: rgba(178, 107, 255, 0.5);
}
.codex-dossier-rarity[data-rarity='mythic'] {
color: #ff9d4a;
border-color: rgba(255, 157, 74, 0.55);
text-shadow: 0 0 10px rgba(255, 157, 74, 0.8);
box-shadow: 0 0 16px rgba(255, 157, 74, 0.32), inset 0 0 8px rgba(255, 157, 74, 0.12);
}
/* ---- sections ---- */
.codex-dossier-section {
margin-bottom: 2rem;
}
.codex-dossier-heading {
font-family: 'IBM Plex Mono', ui-monospace, monospace;
font-size: 0.68rem;
font-weight: 600;
letter-spacing: 0.3em;
text-transform: uppercase;
color: rgba(124, 255, 178, 0.6);
margin: 0 0 0.9rem;
}
.codex-dossier-heading::after {
content: '';
display: block;
width: 42px;
height: 1px;
margin-top: 0.45rem;
background: linear-gradient(90deg, rgba(124, 255, 178, 0.5), transparent);
}
.codex-dossier-persona {
margin: 0;
font-family: 'Cinzel', Georgia, serif;
font-style: italic;
font-size: 1.02rem;
line-height: 1.75;
color: rgba(238, 247, 240, 0.85);
}
.codex-dossier-quotes {
list-style: none;
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
gap: 0.7rem;
}
.codex-dossier-quote {
font-family: 'Cinzel', Georgia, serif;
font-style: italic;
font-size: 0.94rem;
line-height: 1.6;
color: rgba(216, 230, 220, 0.8);
padding-left: 1rem;
border-left: 2px solid rgba(178, 107, 255, 0.35);
}
.codex-dossier-none {
margin: 0;
font-size: 0.75rem;
letter-spacing: 0.08em;
font-style: italic;
color: rgba(216, 230, 220, 0.4);
}
/* ---- stats row ---- */
.codex-dossier-stats {
margin: 0;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
gap: 1px;
background: rgba(124, 255, 178, 0.12);
border: 1px solid rgba(124, 255, 178, 0.12);
border-radius: 8px;
overflow: hidden;
}
.codex-dossier-stat {
background: rgba(10, 10, 18, 0.85);
padding: 0.9rem 1rem;
display: flex;
flex-direction: column;
gap: 0.35rem;
}
.codex-dossier-stat dt {
font-size: 0.58rem;
letter-spacing: 0.22em;
text-transform: uppercase;
color: rgba(216, 230, 220, 0.42);
}
.codex-dossier-stat dd {
margin: 0;
font-size: 0.95rem;
color: #7cffb2;
text-shadow: 0 0 10px rgba(124, 255, 178, 0.3);
overflow-wrap: anywhere;
}
/* ---- voice signature table ---- */
.codex-dossier-voice {
width: 100%;
border-collapse: collapse;
border: 1px solid rgba(124, 255, 178, 0.14);
border-radius: 8px;
overflow: hidden;
font-size: 0.78rem;
}
.codex-dossier-voice th,
.codex-dossier-voice td {
padding: 0.6rem 1rem;
text-align: left;
border-bottom: 1px solid rgba(124, 255, 178, 0.08);
}
.codex-dossier-voice tr:last-child th,
.codex-dossier-voice tr:last-child td {
border-bottom: none;
}
.codex-dossier-voice tr:nth-child(even) th,
.codex-dossier-voice tr:nth-child(even) td {
background: rgba(124, 255, 178, 0.03);
}
.codex-dossier-voice th {
font-weight: 400;
letter-spacing: 0.16em;
text-transform: uppercase;
font-size: 0.64rem;
color: rgba(216, 230, 220, 0.5);
width: 40%;
}
.codex-dossier-voice td {
color: #b26bff;
text-shadow: 0 0 10px rgba(178, 107, 255, 0.3);
overflow-wrap: anywhere;
}
/* ---- CTA ---- */
.codex-dossier-footer {
display: flex;
justify-content: center;
padding-top: 0.6rem;
}
.codex-detail-cta {
display: inline-block;
font-size: 0.78rem;
letter-spacing: 0.26em;
text-transform: uppercase;
text-decoration: none;
color: #07070d;
background: #7cffb2;
border: 1px solid #7cffb2;
border-radius: 6px;
padding: 0.85rem 2.2rem;
box-shadow: 0 0 22px rgba(124, 255, 178, 0.35);
transition: box-shadow 180ms ease, transform 180ms ease, background 180ms ease;
}
.codex-detail-cta:hover,
.codex-detail-cta:focus-visible {
background: #a5ffcb;
box-shadow: 0 0 34px rgba(124, 255, 178, 0.6);
transform: translateY(-2px);
outline: none;
}
.codex-detail-cta-ghost {
color: #7cffb2;
background: transparent;
}
.codex-detail-cta-ghost:hover,
.codex-detail-cta-ghost:focus-visible {
color: #07070d;
background: #7cffb2;
}
/* ---- motion ---- */
@keyframes codex-detail-flicker {
0%,
100% {
opacity: 1;
}
91% {
opacity: 1;
}
92% {
opacity: 0.55;
}
93% {
opacity: 1;
}
95% {
opacity: 0.72;
}
96% {
opacity: 1;
}
}
@keyframes codex-detail-glyph-drift {
0%,
100% {
transform: translateY(0) scale(1);
opacity: 0.85;
}
50% {
transform: translateY(-8px) scale(1.05);
opacity: 1;
}
}
@keyframes codex-detail-breathe {
0%,
100% {
opacity: 0.55;
}
50% {
opacity: 1;
}
}
@keyframes codex-detail-sigil-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
@media (prefers-reduced-motion: reduce) {
.codex-dossier-name,
.codex-dossier-glyph,
.codex-detail-state,
.codex-detail-missing-sigil,
.codex-detail-missing-title {
animation: none;
}
.codex-detail-cta,
.codex-detail-back {
transition: none;
}
}