rp_core (sessions, scrypt auth, self-written MySQL-wire driver rp_db), county-records NUI: residency-file auth, identity-record character intake, survey-grid spawn, procedural night-city loading screen. Secrets replaced with .example files. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
303 lines
7.6 KiB
CSS
303 lines
7.6 KiB
CSS
/* ---------------------------------------------------------------------------
|
|
Loading screen.
|
|
Layout: the city runs full bleed; the record sits in a rail on the left,
|
|
held there by a gradient scrim rather than a panel, so the two never feel
|
|
like separate windows.
|
|
--------------------------------------------------------------------------- */
|
|
|
|
#sky, .grain, .scrim, .vignette {
|
|
position: fixed;
|
|
inset: 0;
|
|
pointer-events: none;
|
|
}
|
|
|
|
#sky { width: 100%; height: 100%; display: block; }
|
|
|
|
.scrim {
|
|
background: linear-gradient(
|
|
90deg,
|
|
rgba(8, 9, 11, 0.97) 0%,
|
|
rgba(8, 9, 11, 0.93) 34%,
|
|
rgba(8, 9, 11, 0.72) 58%,
|
|
rgba(8, 9, 11, 0.15) 82%,
|
|
rgba(8, 9, 11, 0) 100%
|
|
);
|
|
}
|
|
|
|
.vignette {
|
|
background: radial-gradient(120% 90% at 62% 45%, transparent 40%, rgba(0, 0, 0, 0.55) 100%);
|
|
}
|
|
|
|
/* film grain, drawn once as an SVG turbulence tile */
|
|
.grain {
|
|
opacity: 0.16;
|
|
mix-blend-mode: overlay;
|
|
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
|
|
animation: grainshift 640ms steps(2) infinite;
|
|
}
|
|
@keyframes grainshift {
|
|
0% { transform: translate(0, 0); }
|
|
50% { transform: translate(-3px, 2px); }
|
|
100% { transform: translate(2px, -2px); }
|
|
}
|
|
|
|
/* --- rail ---------------------------------------------------------------- */
|
|
|
|
.rail {
|
|
position: relative;
|
|
z-index: 2;
|
|
width: var(--rail);
|
|
height: 100%;
|
|
padding: var(--gut-y) var(--gut-x);
|
|
display: grid;
|
|
grid-template-rows: auto 1fr auto auto;
|
|
gap: clamp(20px, 2.4vh, 34px);
|
|
}
|
|
|
|
/* staged entrance; each element declares its own delay */
|
|
.reveal {
|
|
opacity: 0;
|
|
transform: translateY(10px);
|
|
animation: rise 900ms var(--ease-out) forwards;
|
|
animation-delay: var(--d, 0ms);
|
|
}
|
|
@keyframes rise {
|
|
to { opacity: 1; transform: none; }
|
|
}
|
|
|
|
/* --- file header --------------------------------------------------------- */
|
|
|
|
.file {
|
|
border-top: 1px solid var(--sodium-line);
|
|
padding-top: 14px;
|
|
}
|
|
.file .serial {
|
|
margin-top: 7px;
|
|
color: var(--paper-dim);
|
|
}
|
|
.file .serial span { color: var(--sodium); }
|
|
|
|
/* --- wordmark ------------------------------------------------------------ */
|
|
|
|
.brand { align-self: end; }
|
|
|
|
.wordmark {
|
|
font-size: clamp(46px, 5.2vw, 82px);
|
|
font-weight: 800;
|
|
line-height: 0.86;
|
|
letter-spacing: 0.3em;
|
|
text-indent: 0.3em; /* keeps the wide tracking optically centred */
|
|
opacity: 0;
|
|
animation: settle 1500ms var(--ease-out) 180ms forwards;
|
|
}
|
|
/* the name tightens into place, like a stamp being pressed */
|
|
@keyframes settle {
|
|
0% { opacity: 0; letter-spacing: 0.3em; text-indent: 0.3em; filter: blur(6px); }
|
|
60% { opacity: 1; }
|
|
100% { opacity: 1; letter-spacing: -0.028em; text-indent: 0; filter: blur(0); }
|
|
}
|
|
|
|
.tagrow {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 14px;
|
|
margin-top: 16px;
|
|
}
|
|
.tagline {
|
|
font-family: 'Plex Mono', monospace;
|
|
font-size: 12px;
|
|
font-weight: 500;
|
|
letter-spacing: 0.42em;
|
|
color: var(--sodium);
|
|
text-transform: uppercase;
|
|
}
|
|
.dash {
|
|
flex: 1;
|
|
height: 1px;
|
|
background: linear-gradient(90deg, var(--sodium-line), transparent);
|
|
}
|
|
|
|
/* --- notices ------------------------------------------------------------- */
|
|
|
|
.notices { align-self: center; }
|
|
|
|
.notice-head {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: baseline;
|
|
padding-bottom: 10px;
|
|
border-bottom: 1px solid var(--line);
|
|
}
|
|
.notice-index { color: var(--muted); }
|
|
|
|
.notice { padding-top: 18px; min-height: 132px; }
|
|
|
|
.notice-title {
|
|
font-size: 21px;
|
|
font-weight: 600;
|
|
letter-spacing: -0.015em;
|
|
margin-bottom: 8px;
|
|
}
|
|
.notice-body {
|
|
font-size: 14.5px;
|
|
color: var(--paper-dim);
|
|
max-width: 40ch;
|
|
}
|
|
|
|
.notice.swap .notice-title,
|
|
.notice.swap .notice-body { animation: none; }
|
|
|
|
.notice-title, .notice-body {
|
|
animation: noticein 620ms var(--ease-out) both;
|
|
}
|
|
.notice-body { animation-delay: 70ms; }
|
|
@keyframes noticein {
|
|
from { opacity: 0; transform: translateY(7px); }
|
|
to { opacity: 1; transform: none; }
|
|
}
|
|
|
|
/* --- progress ------------------------------------------------------------ */
|
|
|
|
.load { align-self: end; }
|
|
|
|
.loadhead {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: flex-end;
|
|
margin-bottom: 11px;
|
|
gap: 16px;
|
|
}
|
|
.step {
|
|
color: var(--paper-dim);
|
|
white-space: nowrap;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
}
|
|
.pct {
|
|
font-family: 'Plex Mono', monospace;
|
|
font-weight: 500;
|
|
font-size: 28px;
|
|
line-height: 1;
|
|
color: var(--paper);
|
|
font-variant-numeric: tabular-nums;
|
|
}
|
|
.pct i {
|
|
font-style: normal;
|
|
font-size: 13px;
|
|
color: var(--muted);
|
|
margin-left: 2px;
|
|
}
|
|
|
|
.track {
|
|
position: relative;
|
|
height: 2px;
|
|
background: var(--line);
|
|
overflow: hidden;
|
|
}
|
|
.bar {
|
|
display: block;
|
|
height: 100%;
|
|
width: 0%;
|
|
background: var(--sodium);
|
|
transition: width 420ms var(--ease);
|
|
}
|
|
/* a light runs ahead of the fill so the bar reads as active even when the
|
|
game stalls on a long step */
|
|
.bar::after {
|
|
content: '';
|
|
position: absolute;
|
|
top: 0;
|
|
right: 0;
|
|
width: 64px;
|
|
height: 100%;
|
|
background: linear-gradient(90deg, transparent, rgba(255, 159, 69, 0.85));
|
|
animation: crawl 1900ms linear infinite;
|
|
}
|
|
@keyframes crawl {
|
|
0% { transform: translateX(-64px); opacity: 0; }
|
|
35% { opacity: 1; }
|
|
100% { transform: translateX(0); opacity: 0; }
|
|
}
|
|
|
|
/* --- volume fader -------------------------------------------------------- */
|
|
|
|
.fader {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 14px;
|
|
margin-top: 26px;
|
|
padding-top: 18px;
|
|
border-top: 1px solid var(--line-soft);
|
|
}
|
|
|
|
.mute {
|
|
width: 30px;
|
|
height: 30px;
|
|
display: grid;
|
|
place-items: center;
|
|
background: transparent;
|
|
border: 1px solid var(--line);
|
|
color: var(--paper-dim);
|
|
cursor: pointer;
|
|
transition: color 180ms var(--ease), border-color 180ms var(--ease), transform 120ms var(--ease);
|
|
}
|
|
.mute:hover { color: var(--sodium); border-color: var(--sodium-line); }
|
|
.mute:active { transform: translateY(1px); }
|
|
.mute.off #wave { opacity: 0.18; }
|
|
.mute.off { color: var(--muted); }
|
|
|
|
input[type='range'] {
|
|
flex: 1;
|
|
-webkit-appearance: none;
|
|
appearance: none;
|
|
height: 22px;
|
|
background: transparent;
|
|
cursor: pointer;
|
|
}
|
|
input[type='range']::-webkit-slider-runnable-track {
|
|
height: 2px;
|
|
background: var(--line);
|
|
}
|
|
input[type='range']::-webkit-slider-thumb {
|
|
-webkit-appearance: none;
|
|
width: 3px;
|
|
height: 15px;
|
|
margin-top: -6.5px;
|
|
background: var(--sodium);
|
|
border: 0;
|
|
border-radius: 0;
|
|
transition: height 160ms var(--ease), margin-top 160ms var(--ease);
|
|
}
|
|
input[type='range']:hover::-webkit-slider-thumb,
|
|
input[type='range']:focus-visible::-webkit-slider-thumb {
|
|
height: 21px;
|
|
margin-top: -9.5px;
|
|
}
|
|
|
|
.volval { width: 3ch; text-align: right; color: var(--muted); }
|
|
|
|
.audiohint {
|
|
margin-top: 10px;
|
|
color: var(--sodium);
|
|
animation: pulse 2.4s ease-in-out infinite;
|
|
}
|
|
@keyframes pulse { 50% { opacity: 0.45; } }
|
|
|
|
.sr-only {
|
|
position: absolute;
|
|
width: 1px; height: 1px;
|
|
padding: 0; margin: -1px;
|
|
overflow: hidden;
|
|
clip: rect(0 0 0 0);
|
|
white-space: nowrap;
|
|
}
|
|
|
|
/* Once the world is ready the rail steps aside and reveals the live camera.
|
|
The page background has to go transparent too, otherwise the fade reveals
|
|
nothing but our own backdrop colour. */
|
|
body.handover, body.handover .rail { background: transparent !important; }
|
|
body.handover .scrim { transition: opacity 1400ms var(--ease); opacity: 0; }
|
|
body.handover #sky { transition: opacity 1400ms var(--ease); opacity: 0; }
|
|
body.handover .grain { transition: opacity 1400ms var(--ease); opacity: 0; }
|
|
body.handover .rail { transition: opacity 900ms var(--ease), transform 1200ms var(--ease); opacity: 0; transform: translateY(-12px); }
|