Imperial Date Converter / styles.css
styles.css10.0 KB
:root {
--phos: #35e06a; /* phosphor green */
--phos-bright: #8effae;
--phos-dim: #1b7a3c;
--ink: #020604;
--panel: #04120a;
--panel-edge: #0e3a20;
--text: #a8d8b4;
--serif: "Trajan Pro", "Cinzel", "Optima", "Palatino Linotype", Palatino, Georgia, serif;
--slate-font: "Courier New", "DejaVu Sans Mono", ui-monospace, monospace;
}
* { box-sizing: border-box; }
body {
margin: 0;
min-height: 100vh;
color: var(--text);
font-family: var(--serif);
background: #101210; /* CRT housing; the glass lives in .screen */
overflow: hidden;
}
/* The CRT look is pure CSS — no SVG/pixel-displacement filter. Real warping
of live HTML proved unfixable across platforms (GPU resampling artifacts on
Windows, CPU-bound repaints, text clipping). Instead the curvature is sold
by the glass itself: a bowed silhouette (elliptical border-radius on every
glass layer), a curved specular glare, vignette and scanlines. Everything
is GPU-composited, text stays crisp, clicks land where they look. */
.screen {
position: fixed;
inset: 0;
overflow: hidden;
}
.scroll {
position: absolute;
inset: 0;
overflow-y: auto;
overflow-x: hidden;
padding: 2.5rem 1.4rem 3rem;
background:
radial-gradient(120% 80% at 50% -10%, #062512 0%, #031007 55%, #010502 100%),
#010502;
}
/* Curved-tube content: the header, panels and footer are rigid facets of a
barrel. Blocks above the centre lean their top edge away, blocks below
lean their bottom edge away, so the middle bulges toward the viewer.
Each element carries its own perspective() inside its transform — no
ancestor 3D context to break, nothing per-pixel, GPU-composited, and
hit-testing follows the transform natively on every platform. */
.masthead { transform: perspective(1100px) rotateX(9deg); transform-origin: 50% 100%; }
#g2i { transform: perspective(1100px) rotateX(4.5deg); transform-origin: 50% 100%; }
#i2g { transform: perspective(1100px) rotateX(-4.5deg); transform-origin: 50% 0%; }
footer { transform: perspective(1100px) rotateX(-9deg); transform-origin: 50% 0%; }
/* ---------------- CRT cogitator screen ---------------- */
/* rounded glass bezel: paints everything outside the rounded rect */
.bezel {
position: fixed;
inset: 0;
pointer-events: none;
border-radius: 50% / 5%;
box-shadow:
0 0 0 9999px #101210, /* housing outside the glass */
inset 0 0 6px 2px rgba(0,0,0,0.9), /* glass edge */
inset 0 0 60px rgba(53,224,106,0.06); /* phosphor bloom */
z-index: 8;
}
/* phosphor scanlines + aperture grille. The scanlines are a static SVG
(assets/scanlines.svg) whose horizontal lines actually bow toward the
vertical centre near the top/bottom edges — that curvature, more than
anything else, is what reads as "tube" rather than "flat panel". It's a
single pre-rendered background image: no per-frame cost, nothing to
resample or displace, identical on every browser/OS/device. */
.scanlines {
position: fixed;
inset: 0;
pointer-events: none;
border-radius: 50% / 5%;
background:
url("assets/scanlines.svg"),
repeating-linear-gradient(
to right, rgba(0,20,8,0.12) 0 1px, rgba(0,0,0,0) 1px 3px);
background-size: 100% 100%, auto;
z-index: 5;
mix-blend-mode: multiply;
animation: flicker 4s steps(60) infinite;
}
/* slow travelling refresh band */
.sweep {
position: fixed;
inset: 0;
pointer-events: none;
border-radius: 50% / 5%;
overflow: hidden;
z-index: 6;
}
.sweep::before {
content: "";
position: absolute;
left: 0; right: 0;
height: 14vh;
background: linear-gradient(180deg,
rgba(53,224,106,0) 0%, rgba(53,224,106,0.05) 50%, rgba(53,224,106,0) 100%);
animation: sweep 7s linear infinite;
}
/* curved-glass vignette + specular glare (the glare arc is what makes the
glass read as bulged) */
.vignette {
position: fixed;
inset: 0;
pointer-events: none;
border-radius: 50% / 5%;
background: radial-gradient(115% 105% at 50% 48%,
rgba(0,0,0,0) 62%, rgba(0,0,0,0.32) 86%, rgba(0,0,0,0.62) 100%);
z-index: 7;
}
.vignette::before {
content: "";
position: absolute;
inset: 0;
border-radius: inherit;
background:
radial-gradient(120% 55% at 50% -14%,
rgba(190,255,205,0.09), rgba(190,255,205,0.03) 46%, transparent 64%),
radial-gradient(130% 45% at 50% 116%,
rgba(190,255,205,0.045), transparent 55%);
}
@keyframes sweep {
from { top: -16vh; }
to { top: 102vh; }
}
@keyframes flicker {
0%, 100% { opacity: 1; }
92% { opacity: 1; }
93% { opacity: 0.86; }
94% { opacity: 1; }
97% { opacity: 0.93; }
}
@media (prefers-reduced-motion: reduce) {
.scanlines { animation: none; }
.sweep::before { animation: none; display: none; }
}
/* Administratum sigil, phosphor-tinted via CSS mask */
.sigil {
display: inline-block;
width: 0.85em;
aspect-ratio: 145 / 339;
background: linear-gradient(180deg, var(--phos-bright), var(--phos-dim));
-webkit-mask: url("assets/administratum.png") no-repeat center / contain;
mask: url("assets/administratum.png") no-repeat center / contain;
filter: drop-shadow(0 0 6px rgba(53,224,106,0.4));
}
/* ---------------- Masthead ---------------- */
.masthead { text-align: center; margin-bottom: 2.2rem; }
/* Imperial Aquila rendered from aquila.svg via CSS mask so it takes the phosphor color */
.aquila {
width: min(360px, 78vw);
aspect-ratio: 286.001 / 107.443;
margin: 0 auto 0.4rem;
background: linear-gradient(180deg, var(--phos-bright) 0%, var(--phos) 55%, var(--phos-dim) 100%);
-webkit-mask: url("assets/aquila.svg") no-repeat center / contain;
mask: url("assets/aquila.svg") no-repeat center / contain;
filter: drop-shadow(0 0 14px rgba(53,224,106,0.35));
}
h1 {
font-size: clamp(1.7rem, 5vw, 2.9rem);
letter-spacing: 0.32em;
text-transform: uppercase;
margin: 0.2rem 0 0;
color: var(--phos-bright);
text-shadow: 0 1px 0 #000, 0 0 18px rgba(53,224,106,0.35);
}
.subtitle {
margin: 0.5rem 0 0;
letter-spacing: 0.42em;
text-transform: uppercase;
font-size: clamp(0.62rem, 1.8vw, 0.82rem);
color: var(--text);
opacity: 0.7;
}
.rule {
margin: 1.1rem auto 0;
width: min(560px, 90%);
display: flex;
align-items: center;
gap: 1rem;
}
.rule::before, .rule::after {
content: "";
flex: 1;
height: 1px;
background: linear-gradient(90deg, transparent, var(--phos-dim));
}
.rule::after { background: linear-gradient(90deg, var(--phos-dim), transparent); }
.rule .badge { line-height: 0; }
.rule .sigil { width: 0.95rem; }
/* ---------------- Panels ---------------- */
main {
max-width: 760px;
margin: 0 auto;
display: flex;
flex-direction: column;
gap: 1.4rem;
}
.panel {
background:
linear-gradient(180deg, rgba(53,224,106,0.03), rgba(0,0,0,0.3)),
var(--panel);
border: 1px solid var(--panel-edge);
border-radius: 16px;
padding: 1.5rem 1.5rem 1.7rem;
position: relative;
box-shadow: inset 0 0 0 1px rgba(53,224,106,0.07),
0 10px 30px rgba(0,0,0,0.6);
}
.panel-title {
margin: 0;
font-size: clamp(1.1rem, 3vw, 1.5rem);
letter-spacing: 0.18em;
text-transform: uppercase;
color: var(--phos);
}
.panel-sub {
margin: 0.25rem 0 1.2rem;
font-size: 0.8rem;
font-style: italic;
color: var(--text);
opacity: 0.55;
}
.fields {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
gap: 0.85rem;
}
label {
display: flex;
flex-direction: column;
gap: 0.35rem;
font-size: 0.68rem;
letter-spacing: 0.16em;
text-transform: uppercase;
color: var(--text);
}
.tag { white-space: nowrap; line-height: 1.4; }
.hint { text-transform: none; letter-spacing: normal; opacity: 0.5; font-style: italic; }
input, select {
font-family: var(--slate-font);
font-size: 1rem;
color: var(--phos-bright);
background: #020b06;
border: 1px solid var(--panel-edge);
border-radius: 10px;
padding: 0.5rem 0.55rem;
outline: none;
transition: border-color 0.15s, box-shadow 0.15s;
}
input:focus, select:focus {
border-color: var(--phos);
box-shadow: 0 0 0 1px rgba(53,224,106,0.4), inset 0 0 8px rgba(53,224,106,0.08);
}
select { appearance: none; cursor: pointer; }
/* native spin buttons are white and off-theme — the fields are type-in */
input[type="number"]::-webkit-outer-spin-button,
input[type="number"]::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
input[type="number"] { -moz-appearance: textfield; appearance: textfield; }
/* ---------------- Readout / data-slate ---------------- */
.readout {
margin-top: 1.3rem;
text-align: center;
padding: 1rem 0.75rem;
border: 1px solid var(--phos-dim);
border-radius: 10px;
background:
linear-gradient(180deg, rgba(53,224,106,0.06), rgba(0,0,0,0.4));
box-shadow: inset 0 0 20px rgba(0,0,0,0.65);
}
.slate {
font-family: var(--slate-font);
font-size: clamp(1.15rem, 4.5vw, 1.7rem);
letter-spacing: 0.12em;
color: var(--phos-bright);
text-shadow: 0 0 10px rgba(53,224,106,0.55);
word-break: break-word;
}
.copy {
margin: 0.9rem auto 0;
display: block;
font-family: var(--serif);
font-size: 0.66rem;
letter-spacing: 0.22em;
text-transform: uppercase;
color: var(--text);
background: transparent;
border: 1px solid var(--panel-edge);
border-radius: 10px;
padding: 0.5rem 1.1rem;
cursor: pointer;
transition: color 0.15s, border-color 0.15s, background 0.15s;
}
.copy:hover { color: var(--phos-bright); border-color: var(--phos); }
.copy.done { color: var(--phos-bright); border-color: var(--phos); background: rgba(53,224,106,0.08); }
/* ---------------- Divider ---------------- */
.divider {
display: flex;
align-items: center;
justify-content: center;
gap: 1.1rem;
color: var(--phos-dim);
font-size: 0.85rem;
}
.divider .sigil { width: 0.8rem; }
/* ---------------- Footer ---------------- */
footer {
max-width: 760px;
margin: 2.6rem auto 0;
text-align: center;
}
.creed {
margin: 0;
font-size: 0.78rem;
letter-spacing: 0.5em;
text-transform: uppercase;
color: var(--phos);
opacity: 0.65;
text-shadow: 0 0 12px rgba(53,224,106,0.35);
}
@media (max-width: 520px) {
h1 { letter-spacing: 0.22em; }
.subtitle { letter-spacing: 0.28em; }
}
