- 18 low + 2 low-medium discrete elements (comm badge, door swishes, bosun whistle, sickbay ECG, TARDIS lever/door, Sevastopol sparks, commlock tone, station ECG, solar roar, cryo sigh, Orion thump, tea dispenser, kettle whistle, plaid alarm, cassette transport, grappler servo, radio static, mag-boot latch) with soundboard buttons, preset tuning, and automated background loops - bio-wraith misty life-support tuning; sound_reference.md and audio_gaps.md implementation tracking - gitignore audition scratch and local artifacts
2374 lines
58 KiB
CSS
2374 lines
58 KiB
CSS
/**
|
||
* Authentic LCARS & Multi-Era Star Trek Styling
|
||
* Includes TNG 24th Century, TOS Retro 23rd Century, and NX-01 Industrial themes.
|
||
*/
|
||
|
||
@import url('https://fonts.googleapis.com/css2?family=Antonio:wght@400;600;700&family=Share+Tech+Mono&display=swap');
|
||
|
||
:root {
|
||
/* TNG 24th Century LCARS Palette */
|
||
--lcars-orange: #ff9900;
|
||
--lcars-tangerine: #ff6600;
|
||
--lcars-amber: #cc6600;
|
||
--lcars-sand: #ffcc66;
|
||
--lcars-lavender: #cc99cc;
|
||
--lcars-violet: #9966cc;
|
||
--lcars-ice-blue: #99ccff;
|
||
--lcars-blue: #3366cc;
|
||
--lcars-red: #cc3333;
|
||
--lcars-crimson: #990000;
|
||
--lcars-bg: #000000;
|
||
--lcars-panel-bg: #0d0f14;
|
||
--lcars-font: 'Antonio', 'Arial Narrow', sans-serif;
|
||
--mono-font: 'Share Tech Mono', monospace;
|
||
|
||
/* Theme variables (Defaults to TNG) */
|
||
--primary-accent: var(--lcars-orange);
|
||
--secondary-accent: var(--lcars-lavender);
|
||
--tertiary-accent: var(--lcars-ice-blue);
|
||
--warning-accent: var(--lcars-red);
|
||
}
|
||
|
||
/* Voyager Era Palette */
|
||
body.theme-lcars-voyager {
|
||
--primary-accent: #3399cc;
|
||
--secondary-accent: #9999ff;
|
||
--tertiary-accent: #66cccc;
|
||
--warning-accent: #cc3333;
|
||
}
|
||
|
||
/* Defiant Combat Palette */
|
||
body.theme-lcars-defiant {
|
||
--primary-accent: #cc5500;
|
||
--secondary-accent: #aa3300;
|
||
--tertiary-accent: #dd8800;
|
||
--warning-accent: #ff0000;
|
||
}
|
||
|
||
/* Deep Space Nine Palette */
|
||
body.theme-lcars-ds9 {
|
||
--primary-accent: #997755;
|
||
--secondary-accent: #bb8844;
|
||
--tertiary-accent: #667788;
|
||
--warning-accent: #bb3322;
|
||
}
|
||
|
||
/* TOS Retro 23rd Century Palette */
|
||
body.theme-tos-retro {
|
||
--primary-accent: #ffcc00;
|
||
--secondary-accent: #0099ff;
|
||
--tertiary-accent: #cc0000;
|
||
--lcars-panel-bg: #15181c;
|
||
--lcars-font: 'Share Tech Mono', monospace;
|
||
}
|
||
|
||
/* NX Industrial Palette */
|
||
body.theme-nx-industrial {
|
||
--primary-accent: #33bbee;
|
||
--secondary-accent: #88aacc;
|
||
--tertiary-accent: #445566;
|
||
--lcars-panel-bg: #0e1217;
|
||
--lcars-font: 'Share Tech Mono', monospace;
|
||
}
|
||
|
||
* {
|
||
box-sizing: border-box;
|
||
margin: 0;
|
||
padding: 0;
|
||
user-select: none;
|
||
}
|
||
|
||
body {
|
||
background-color: var(--lcars-bg);
|
||
color: #ffffff;
|
||
font-family: var(--lcars-font);
|
||
letter-spacing: 0.05em;
|
||
overflow-x: hidden;
|
||
min-height: 100vh;
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
/* Header & Frame */
|
||
.lcars-header {
|
||
display: flex;
|
||
align-items: stretch;
|
||
height: 64px;
|
||
background: transparent;
|
||
padding: 8px 16px 0 16px;
|
||
gap: 12px;
|
||
}
|
||
|
||
.lcars-elbow-left {
|
||
width: 180px;
|
||
background-color: var(--primary-accent);
|
||
border-top-left-radius: 32px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: flex-end;
|
||
padding-right: 14px;
|
||
font-size: 1.25rem;
|
||
font-weight: 700;
|
||
color: #000000;
|
||
text-transform: uppercase;
|
||
}
|
||
|
||
.lcars-top-bar {
|
||
flex: 1;
|
||
background-color: var(--secondary-accent);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
padding: 0 16px;
|
||
font-size: 1.1rem;
|
||
font-weight: 700;
|
||
color: #000000;
|
||
text-transform: uppercase;
|
||
}
|
||
|
||
.lcars-pill-end {
|
||
width: 70px;
|
||
background-color: var(--tertiary-accent);
|
||
border-top-right-radius: 20px;
|
||
border-bottom-right-radius: 20px;
|
||
}
|
||
|
||
/* Header Volume Dock */
|
||
.header-volume-dock {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
background: rgba(0, 0, 0, 0.25);
|
||
padding: 2px 10px;
|
||
border-radius: 12px;
|
||
}
|
||
|
||
.btn-header-mute {
|
||
background: #000000;
|
||
color: var(--secondary-accent);
|
||
border: 1px solid var(--secondary-accent);
|
||
border-radius: 8px;
|
||
padding: 2px 8px;
|
||
font-family: var(--lcars-font);
|
||
font-size: 0.8rem;
|
||
font-weight: 700;
|
||
cursor: pointer;
|
||
transition: all 0.15s;
|
||
}
|
||
|
||
.btn-header-mute:hover {
|
||
background: var(--secondary-accent);
|
||
color: #000;
|
||
}
|
||
|
||
.btn-header-mute.muted {
|
||
background: #ff0000;
|
||
color: #ffffff;
|
||
border-color: #ff0000;
|
||
}
|
||
|
||
.header-vol-val {
|
||
font-family: var(--mono-font);
|
||
font-size: 0.85rem;
|
||
color: #000;
|
||
font-weight: 700;
|
||
min-width: 32px;
|
||
}
|
||
|
||
/* Main Layout Grid */
|
||
.lcars-container {
|
||
display: grid;
|
||
grid-template-columns: 240px 1fr 300px;
|
||
gap: 16px;
|
||
padding: 16px;
|
||
flex: 1;
|
||
}
|
||
|
||
@media (max-width: 1080px) {
|
||
.lcars-container {
|
||
grid-template-columns: 220px 1fr;
|
||
}
|
||
.right-column {
|
||
grid-column: span 2;
|
||
}
|
||
}
|
||
|
||
@media (max-width: 768px) {
|
||
.lcars-container {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
.lcars-elbow-left {
|
||
width: 100px;
|
||
font-size: 0.9rem;
|
||
}
|
||
}
|
||
|
||
/* Left Sidebar - Presets & Ship Selector */
|
||
.left-sidebar {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 10px;
|
||
}
|
||
|
||
.sidebar-heading {
|
||
background-color: var(--primary-accent);
|
||
color: #000;
|
||
padding: 6px 12px;
|
||
font-weight: 700;
|
||
font-size: 1rem;
|
||
text-transform: uppercase;
|
||
border-radius: 4px;
|
||
}
|
||
|
||
.preset-list {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 6px;
|
||
max-height: calc(100vh - 220px);
|
||
overflow-y: auto;
|
||
padding-right: 4px;
|
||
}
|
||
|
||
.preset-btn {
|
||
background-color: #1a1e27;
|
||
color: #e0e6ed;
|
||
border: 2px solid transparent;
|
||
padding: 10px 12px;
|
||
text-align: left;
|
||
font-family: var(--lcars-font);
|
||
font-size: 0.95rem;
|
||
font-weight: 600;
|
||
text-transform: uppercase;
|
||
border-radius: 0 16px 16px 0;
|
||
cursor: pointer;
|
||
transition: all 0.15s ease;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 2px;
|
||
}
|
||
|
||
.preset-btn:hover {
|
||
background-color: #272d3b;
|
||
border-left: 6px solid var(--primary-accent);
|
||
padding-left: 8px;
|
||
}
|
||
|
||
.preset-btn.active {
|
||
background-color: var(--primary-accent);
|
||
color: #000000;
|
||
font-weight: 700;
|
||
}
|
||
|
||
.preset-btn .ship-era-tag {
|
||
font-size: 0.7rem;
|
||
opacity: 0.75;
|
||
font-family: var(--mono-font);
|
||
}
|
||
|
||
/* Center Panel - Main Controls & Mixers */
|
||
.center-panel {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 16px;
|
||
}
|
||
|
||
.panel-card {
|
||
background-color: var(--lcars-panel-bg);
|
||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||
border-radius: 8px;
|
||
padding: 16px;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 14px;
|
||
}
|
||
|
||
.panel-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
border-bottom: 2px solid var(--primary-accent);
|
||
padding-bottom: 6px;
|
||
}
|
||
|
||
.panel-title {
|
||
font-size: 1.25rem;
|
||
font-weight: 700;
|
||
color: var(--primary-accent);
|
||
text-transform: uppercase;
|
||
}
|
||
|
||
.panel-sub {
|
||
font-family: var(--mono-font);
|
||
font-size: 0.85rem;
|
||
color: #8899aa;
|
||
}
|
||
|
||
/* Transport Controls Bar */
|
||
.transport-bar {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 12px;
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
.btn-lcars-large {
|
||
background-color: var(--primary-accent);
|
||
color: #000;
|
||
font-family: var(--lcars-font);
|
||
font-size: 1.3rem;
|
||
font-weight: 700;
|
||
padding: 12px 28px;
|
||
border: none;
|
||
border-radius: 24px;
|
||
cursor: pointer;
|
||
text-transform: uppercase;
|
||
transition: transform 0.1s, filter 0.15s;
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
}
|
||
|
||
.btn-lcars-large:hover {
|
||
filter: brightness(1.2);
|
||
}
|
||
|
||
.btn-lcars-large:active {
|
||
transform: scale(0.97);
|
||
}
|
||
|
||
.btn-lcars-large.playing {
|
||
background-color: #ff3333;
|
||
color: #fff;
|
||
}
|
||
|
||
/* Master Engage / Full Stop Play Button */
|
||
#btn-master-play {
|
||
background: #00cc66;
|
||
color: #000000;
|
||
box-shadow: 0 0 12px rgba(0, 204, 102, 0.45);
|
||
transition: transform 0.1s, filter 0.15s, background-color 0.2s, box-shadow 0.2s;
|
||
}
|
||
|
||
#btn-master-play:hover {
|
||
filter: brightness(1.2);
|
||
}
|
||
|
||
#btn-master-play.playing {
|
||
background: #ff3333;
|
||
color: #ffffff;
|
||
box-shadow: 0 0 14px rgba(255, 51, 51, 0.5);
|
||
}
|
||
|
||
#btn-master-play.engaging {
|
||
animation: lcars-engage-flash 0.35s infinite alternate ease-in-out;
|
||
}
|
||
|
||
#btn-master-play.stopping {
|
||
animation: lcars-stop-flash 0.35s infinite alternate ease-in-out;
|
||
}
|
||
|
||
@keyframes lcars-engage-flash {
|
||
0% {
|
||
background: #00cc66;
|
||
color: #000000;
|
||
box-shadow: 0 0 6px rgba(0, 204, 102, 0.4);
|
||
filter: brightness(0.95);
|
||
}
|
||
100% {
|
||
background: #33ff99;
|
||
color: #000000;
|
||
box-shadow: 0 0 24px rgba(0, 255, 136, 0.95);
|
||
filter: brightness(1.35);
|
||
}
|
||
}
|
||
|
||
@keyframes lcars-stop-flash {
|
||
0% {
|
||
background: #ff3333;
|
||
color: #ffffff;
|
||
box-shadow: 0 0 6px rgba(255, 51, 51, 0.4);
|
||
filter: brightness(0.95);
|
||
}
|
||
100% {
|
||
background: #ff6666;
|
||
color: #ffffff;
|
||
box-shadow: 0 0 24px rgba(255, 51, 51, 0.95);
|
||
filter: brightness(1.35);
|
||
}
|
||
}
|
||
|
||
/* Action Pill Buttons */
|
||
.pill-button-group {
|
||
display: flex;
|
||
gap: 8px;
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
.btn-lcars-pill {
|
||
background-color: var(--secondary-accent);
|
||
color: #000;
|
||
font-family: var(--lcars-font);
|
||
font-size: 0.95rem;
|
||
font-weight: 700;
|
||
padding: 8px 16px;
|
||
border: none;
|
||
border-radius: 14px;
|
||
cursor: pointer;
|
||
text-transform: uppercase;
|
||
transition: all 0.15s;
|
||
}
|
||
|
||
.btn-lcars-pill:hover {
|
||
filter: brightness(1.25);
|
||
}
|
||
|
||
.btn-lcars-pill.active-alert {
|
||
background-color: #ff0000 !important;
|
||
color: #ffffff !important;
|
||
animation: lcars-red-pulse 1s infinite alternate;
|
||
}
|
||
|
||
@keyframes lcars-red-pulse {
|
||
0% { box-shadow: 0 0 4px #ff0000; }
|
||
100% { box-shadow: 0 0 20px #ff0000; }
|
||
}
|
||
|
||
/* Dedicated Master Volume Console */
|
||
.master-volume-console {
|
||
background: rgba(255, 153, 0, 0.05);
|
||
border: 1px solid var(--primary-accent);
|
||
border-left: 6px solid var(--primary-accent);
|
||
border-radius: 6px;
|
||
padding: 12px 16px;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 10px;
|
||
}
|
||
|
||
.master-vol-top {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
flex-wrap: wrap;
|
||
gap: 8px;
|
||
}
|
||
|
||
.master-vol-title-group {
|
||
display: flex;
|
||
align-items: baseline;
|
||
gap: 10px;
|
||
}
|
||
|
||
.master-vol-tag {
|
||
font-family: var(--lcars-font);
|
||
font-size: 1.05rem;
|
||
font-weight: 700;
|
||
color: var(--primary-accent);
|
||
text-transform: uppercase;
|
||
}
|
||
|
||
.master-vol-readout {
|
||
font-family: var(--mono-font);
|
||
font-size: 1.4rem;
|
||
font-weight: 700;
|
||
color: #ffffff;
|
||
}
|
||
|
||
.master-vol-db {
|
||
font-family: var(--mono-font);
|
||
font-size: 0.85rem;
|
||
color: #00e6ff;
|
||
}
|
||
|
||
.master-vol-actions {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
.btn-mute {
|
||
background-color: var(--primary-accent);
|
||
color: #000;
|
||
font-weight: 700;
|
||
min-width: 68px;
|
||
text-align: center;
|
||
}
|
||
|
||
.btn-mute.muted {
|
||
background-color: #ff0000 !important;
|
||
color: #ffffff !important;
|
||
box-shadow: 0 0 10px #ff0000;
|
||
}
|
||
|
||
.master-vol-presets {
|
||
display: flex;
|
||
gap: 4px;
|
||
}
|
||
|
||
.btn-vol-step {
|
||
background: #1e2430;
|
||
color: #a0b4cc;
|
||
border: 1px solid #334455;
|
||
border-radius: 4px;
|
||
padding: 4px 8px;
|
||
font-family: var(--mono-font);
|
||
font-size: 0.75rem;
|
||
cursor: pointer;
|
||
transition: all 0.1s;
|
||
}
|
||
|
||
.btn-vol-step:hover {
|
||
background: var(--primary-accent);
|
||
color: #000;
|
||
border-color: var(--primary-accent);
|
||
}
|
||
|
||
.btn-vol-step.active {
|
||
background: var(--primary-accent);
|
||
color: #000;
|
||
font-weight: bold;
|
||
}
|
||
|
||
/* Master Slider Row & Level Meter */
|
||
.master-slider-row {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 12px;
|
||
}
|
||
|
||
.vol-adj-btn {
|
||
width: 32px;
|
||
height: 32px;
|
||
background: #1b212c;
|
||
color: var(--primary-accent);
|
||
border: 1px solid var(--primary-accent);
|
||
border-radius: 50%;
|
||
font-family: var(--mono-font);
|
||
font-size: 1.2rem;
|
||
font-weight: bold;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
cursor: pointer;
|
||
transition: all 0.1s;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.vol-adj-btn:hover {
|
||
background: var(--primary-accent);
|
||
color: #000;
|
||
}
|
||
|
||
.vol-adj-btn:active {
|
||
transform: scale(0.92);
|
||
}
|
||
|
||
.slider-track-container {
|
||
flex: 1;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 6px;
|
||
}
|
||
|
||
.slider-master-large {
|
||
height: 12px !important;
|
||
border-radius: 6px !important;
|
||
background: #161b24 !important;
|
||
}
|
||
|
||
.slider-master-large::-webkit-slider-thumb {
|
||
width: 24px !important;
|
||
height: 24px !important;
|
||
background: var(--primary-accent) !important;
|
||
box-shadow: 0 0 10px rgba(255, 153, 0, 0.8) !important;
|
||
}
|
||
|
||
/* Segmented LED Volume Meter */
|
||
.vol-meter-leds {
|
||
display: flex;
|
||
gap: 3px;
|
||
height: 6px;
|
||
width: 100%;
|
||
}
|
||
|
||
.led-pip {
|
||
flex: 1;
|
||
background: #18202c;
|
||
border-radius: 1px;
|
||
transition: background 0.08s;
|
||
}
|
||
|
||
.led-pip.active:nth-child(-n+6) {
|
||
background: #00e6ff;
|
||
box-shadow: 0 0 4px #00e6ff;
|
||
}
|
||
|
||
.led-pip.active:nth-child(n+7):nth-child(-n+8) {
|
||
background: #ffcc00;
|
||
box-shadow: 0 0 4px #ffcc00;
|
||
}
|
||
|
||
.led-pip.active:nth-child(n+9) {
|
||
background: #ff3333;
|
||
box-shadow: 0 0 4px #ff3333;
|
||
}
|
||
|
||
/* Multi-Channel Synthesizer Mixer */
|
||
.mixer-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
|
||
gap: 14px;
|
||
}
|
||
|
||
.channel-strip {
|
||
background: rgba(255, 255, 255, 0.03);
|
||
border-left: 4px solid var(--primary-accent);
|
||
padding: 12px;
|
||
border-radius: 0 8px 8px 0;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 10px;
|
||
}
|
||
|
||
.channel-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
font-size: 0.95rem;
|
||
font-weight: 700;
|
||
color: var(--primary-accent);
|
||
text-transform: uppercase;
|
||
}
|
||
|
||
.control-row {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 4px;
|
||
}
|
||
|
||
.control-label {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
font-family: var(--mono-font);
|
||
font-size: 0.75rem;
|
||
color: #a0b0c0;
|
||
}
|
||
|
||
/* Sliders */
|
||
input[type="range"] {
|
||
-webkit-appearance: none;
|
||
width: 100%;
|
||
height: 8px;
|
||
background: #202634;
|
||
border-radius: 4px;
|
||
outline: none;
|
||
}
|
||
|
||
input[type="range"]::-webkit-slider-thumb {
|
||
-webkit-appearance: none;
|
||
width: 18px;
|
||
height: 18px;
|
||
border-radius: 50%;
|
||
background: var(--primary-accent);
|
||
cursor: pointer;
|
||
border: 2px solid #000;
|
||
box-shadow: 0 0 6px rgba(255, 153, 0, 0.5);
|
||
}
|
||
|
||
/* Right Sidebar - Warp Core & Diagnostic Monitor */
|
||
.right-column {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 16px;
|
||
}
|
||
|
||
.telemetry-triggers {
|
||
display: grid;
|
||
grid-template-columns: 1fr 1fr;
|
||
gap: 8px;
|
||
}
|
||
|
||
.btn-chirp {
|
||
background-color: #232b3b;
|
||
color: var(--tertiary-accent);
|
||
border: 1px solid var(--tertiary-accent);
|
||
border-radius: 6px;
|
||
padding: 8px;
|
||
font-family: var(--lcars-font);
|
||
font-size: 0.85rem;
|
||
font-weight: 600;
|
||
cursor: pointer;
|
||
text-transform: uppercase;
|
||
transition: all 0.1s;
|
||
}
|
||
|
||
.btn-chirp:hover {
|
||
background-color: var(--tertiary-accent);
|
||
color: #000;
|
||
}
|
||
|
||
.btn-chirp:active {
|
||
transform: scale(0.95);
|
||
}
|
||
|
||
/* Sleep Timer Display */
|
||
.timer-readout {
|
||
font-family: var(--mono-font);
|
||
font-size: 1.1rem;
|
||
color: #00e6ff;
|
||
text-align: center;
|
||
background: #131a26;
|
||
padding: 6px;
|
||
border-radius: 4px;
|
||
border: 1px solid rgba(0, 230, 255, 0.3);
|
||
}
|
||
|
||
/* Footer status bar */
|
||
.lcars-footer {
|
||
margin-top: auto;
|
||
padding: 8px 16px;
|
||
background-color: var(--primary-accent);
|
||
color: #000;
|
||
display: flex;
|
||
justify-content: space-between;
|
||
font-weight: 700;
|
||
font-size: 0.9rem;
|
||
text-transform: uppercase;
|
||
}
|
||
|
||
|
||
/**
|
||
* Canvas Visualizers & Diagnostic Displays CSS
|
||
*/
|
||
|
||
.visualizer-container {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 8px;
|
||
}
|
||
|
||
.canvas-wrapper {
|
||
position: relative;
|
||
width: 100%;
|
||
background-color: #080b10;
|
||
border: 1px solid rgba(255, 153, 0, 0.25);
|
||
border-radius: 6px;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.canvas-wrapper canvas {
|
||
display: block;
|
||
width: 100%;
|
||
}
|
||
|
||
.spectrum-wrapper {
|
||
height: 140px;
|
||
}
|
||
|
||
.warp-core-wrapper {
|
||
height: 240px;
|
||
}
|
||
|
||
.canvas-label-overlay {
|
||
position: absolute;
|
||
top: 6px;
|
||
left: 8px;
|
||
font-family: var(--mono-font);
|
||
font-size: 0.7rem;
|
||
color: var(--primary-accent);
|
||
letter-spacing: 0.1em;
|
||
pointer-events: none;
|
||
background: rgba(0, 0, 0, 0.6);
|
||
padding: 2px 6px;
|
||
border-radius: 3px;
|
||
}
|
||
|
||
.diagnostic-stats {
|
||
display: grid;
|
||
grid-template-columns: 1fr 1fr;
|
||
gap: 6px;
|
||
font-family: var(--mono-font);
|
||
font-size: 0.75rem;
|
||
}
|
||
|
||
.stat-box {
|
||
background: rgba(255, 255, 255, 0.04);
|
||
padding: 6px 8px;
|
||
border-left: 2px solid var(--secondary-accent);
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
.stat-label {
|
||
color: #8899aa;
|
||
font-size: 0.65rem;
|
||
}
|
||
|
||
.stat-value {
|
||
color: #00e6ff;
|
||
font-weight: bold;
|
||
}
|
||
|
||
|
||
/**
|
||
* Whoniverse (Doctor Who TARDIS) Aesthetic Stylesheet & Universe Switcher Dropdown
|
||
*/
|
||
|
||
/* Universe Switcher Dropdown */
|
||
.universe-selector-container {
|
||
position: relative;
|
||
display: inline-block;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.universe-dropdown-menu {
|
||
display: none;
|
||
position: absolute;
|
||
top: 100%;
|
||
left: 0;
|
||
min-width: 220px;
|
||
background-color: #0b111a;
|
||
border: 2px solid var(--primary-accent);
|
||
border-radius: 0 0 12px 12px;
|
||
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.9);
|
||
z-index: 1000;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.universe-dropdown-menu.show {
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
.universe-item {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 10px;
|
||
padding: 12px 16px;
|
||
color: #ffffff;
|
||
font-family: var(--lcars-font);
|
||
font-size: 1rem;
|
||
font-weight: 700;
|
||
text-transform: uppercase;
|
||
background: transparent;
|
||
border: none;
|
||
border-bottom: 1px solid rgba(255, 255, 255, 0.08);
|
||
cursor: pointer;
|
||
text-align: left;
|
||
transition: all 0.15s ease;
|
||
}
|
||
|
||
.universe-item:hover {
|
||
background-color: var(--primary-accent);
|
||
color: #000000;
|
||
}
|
||
|
||
.universe-item.active {
|
||
background-color: rgba(255, 255, 255, 0.12);
|
||
border-left: 4px solid var(--primary-accent);
|
||
}
|
||
|
||
.universe-item .u-icon {
|
||
font-size: 1.2rem;
|
||
width: 24px;
|
||
text-align: center;
|
||
}
|
||
|
||
/* ==========================================================================
|
||
WHONIVERSE (TARDIS CONSOLE) THEME
|
||
========================================================================== */
|
||
|
||
body.theme-whoniverse-tardis {
|
||
--tardis-blue: #003b6f;
|
||
--tardis-deep: #001f3f;
|
||
--tardis-cyan: #00e5ff;
|
||
--tardis-teal: #008080;
|
||
--tardis-amber: #d4af37;
|
||
--tardis-brass: #b8860b;
|
||
--tardis-roundel: #e0f2fe;
|
||
|
||
--primary-accent: var(--tardis-cyan);
|
||
--secondary-accent: var(--tardis-blue);
|
||
--tertiary-accent: var(--tardis-amber);
|
||
--warning-accent: #cc0000;
|
||
|
||
--lcars-bg: #030712;
|
||
--lcars-panel-bg: #070e1b;
|
||
--lcars-font: 'Share Tech Mono', monospace;
|
||
background-color: #030712;
|
||
background-image:
|
||
radial-gradient(circle at 50% 10%, rgba(0, 59, 111, 0.3) 0%, transparent 60%),
|
||
radial-gradient(circle at 10% 90%, rgba(0, 229, 255, 0.05) 0%, transparent 40%);
|
||
}
|
||
|
||
/* Header Styling for TARDIS Police Box */
|
||
body.theme-whoniverse-tardis .lcars-elbow-left {
|
||
background: linear-gradient(135deg, #004a8b, #002244);
|
||
color: #ffffff;
|
||
border: 1px solid var(--tardis-cyan);
|
||
border-radius: 4px 4px 0 0;
|
||
box-shadow: 0 0 12px rgba(0, 229, 255, 0.3);
|
||
letter-spacing: 0.15em;
|
||
}
|
||
|
||
body.theme-whoniverse-tardis .lcars-top-bar {
|
||
background: #001f3f;
|
||
color: #ffffff;
|
||
border: 1px solid rgba(0, 229, 255, 0.4);
|
||
border-radius: 4px;
|
||
}
|
||
|
||
body.theme-whoniverse-tardis .header-vol-val {
|
||
color: var(--tardis-cyan);
|
||
}
|
||
|
||
body.theme-whoniverse-tardis .lcars-pill-end {
|
||
background-color: var(--tardis-amber);
|
||
border-radius: 4px;
|
||
}
|
||
|
||
/* TARDIS Roundel Buttons & Cards */
|
||
body.theme-whoniverse-tardis .sidebar-heading {
|
||
background: linear-gradient(90deg, #003b6f, #001f3f);
|
||
color: var(--tardis-cyan);
|
||
border-left: 4px solid var(--tardis-cyan);
|
||
letter-spacing: 0.1em;
|
||
}
|
||
|
||
body.theme-whoniverse-tardis .preset-btn {
|
||
background: rgba(0, 59, 111, 0.2);
|
||
border: 1px solid rgba(0, 229, 255, 0.2);
|
||
border-radius: 8px;
|
||
color: #e2e8f0;
|
||
}
|
||
|
||
body.theme-whoniverse-tardis .preset-btn:hover {
|
||
background: rgba(0, 229, 255, 0.15);
|
||
border-color: var(--tardis-cyan);
|
||
box-shadow: 0 0 8px rgba(0, 229, 255, 0.3);
|
||
}
|
||
|
||
body.theme-whoniverse-tardis .preset-btn.active {
|
||
background: linear-gradient(135deg, #003b6f, #002244);
|
||
border: 1px solid var(--tardis-cyan);
|
||
color: #ffffff;
|
||
box-shadow: 0 0 15px rgba(0, 229, 255, 0.5);
|
||
}
|
||
|
||
/* Master Play Button for TARDIS */
|
||
body.theme-whoniverse-tardis .btn-lcars-large {
|
||
background: linear-gradient(135deg, #00e5ff, #0088cc);
|
||
color: #000000;
|
||
border-radius: 8px;
|
||
box-shadow: 0 0 16px rgba(0, 229, 255, 0.4);
|
||
}
|
||
|
||
body.theme-whoniverse-tardis .btn-lcars-large.playing {
|
||
background: linear-gradient(135deg, #d4af37, #996515);
|
||
color: #ffffff;
|
||
box-shadow: 0 0 20px rgba(212, 175, 55, 0.6);
|
||
}
|
||
|
||
/* Roundel Keypad Buttons */
|
||
body.theme-whoniverse-tardis .btn-chirp {
|
||
background: radial-gradient(circle, rgba(0, 229, 255, 0.1) 0%, rgba(0, 31, 63, 0.4) 100%);
|
||
border: 1px solid rgba(0, 229, 255, 0.4);
|
||
border-radius: 20px;
|
||
color: #b0e0e6;
|
||
transition: all 0.2s;
|
||
}
|
||
|
||
body.theme-whoniverse-tardis .btn-chirp:hover {
|
||
background: var(--tardis-cyan);
|
||
color: #000000;
|
||
box-shadow: 0 0 12px var(--tardis-cyan);
|
||
}
|
||
|
||
/* Cloister Bell Active Siren */
|
||
body.theme-whoniverse-tardis .btn-lcars-pill.active-alert {
|
||
background-color: #ff3300 !important;
|
||
color: #ffffff !important;
|
||
animation: cloister-pulse 1.2s infinite alternate;
|
||
}
|
||
|
||
@keyframes cloister-pulse {
|
||
0% { box-shadow: 0 0 4px #ff3300; }
|
||
100% { box-shadow: 0 0 25px #ff3300; }
|
||
}
|
||
|
||
/* TARDIS Footer */
|
||
body.theme-whoniverse-tardis .lcars-footer {
|
||
background: linear-gradient(90deg, #001f3f, #003b6f);
|
||
color: var(--tardis-cyan);
|
||
border-top: 1px solid rgba(0, 229, 255, 0.3);
|
||
}
|
||
|
||
|
||
/**
|
||
* Expanded Sci-Fi Universes Themes Stylesheet
|
||
* Custom visual aesthetics for: Industrial, Bioships, Retro Future, Military,
|
||
* Deep Space, Outlaw / Frontier, Space Stations, and Comedy / Adventure.
|
||
*/
|
||
|
||
/* ==========================================================================
|
||
1. INDUSTRIAL SPACE (Weyland-Yutani, Firefly, Expanse, Mining Grit)
|
||
========================================================================== */
|
||
body.theme-industrial {
|
||
--primary-accent: #ffaa00;
|
||
--secondary-accent: #b45309;
|
||
--tertiary-accent: #d97706;
|
||
--warning-accent: #dc2626;
|
||
|
||
--lcars-bg: #0d0a07;
|
||
--lcars-panel-bg: #140f0a;
|
||
--lcars-font: 'Share Tech Mono', monospace;
|
||
|
||
background-color: #0d0a07;
|
||
background-image: repeating-linear-gradient(0deg, rgba(0, 0, 0, 0.25), rgba(0, 0, 0, 0.25) 2px, transparent 2px, transparent 4px);
|
||
}
|
||
|
||
body.theme-industrial .lcars-elbow-left {
|
||
background: linear-gradient(135deg, #b45309, #78350f);
|
||
color: #ffaa00;
|
||
border: 1px solid #ffaa00;
|
||
border-radius: 2px;
|
||
box-shadow: inset 0 0 10px rgba(0, 0, 0, 0.8);
|
||
}
|
||
|
||
body.theme-industrial .lcars-top-bar {
|
||
background: #1e150d;
|
||
color: #ffaa00;
|
||
border-bottom: 2px solid #b45309;
|
||
}
|
||
|
||
body.theme-industrial .panel-card {
|
||
border: 1px solid #451a03;
|
||
border-left: 4px solid #b45309;
|
||
}
|
||
|
||
body.theme-industrial .preset-btn {
|
||
background: #1a120b;
|
||
border-left: 3px solid #78350f;
|
||
color: #fdba74;
|
||
}
|
||
|
||
body.theme-industrial .preset-btn.active {
|
||
background: #b45309;
|
||
color: #000000;
|
||
font-weight: bold;
|
||
}
|
||
|
||
/* ==========================================================================
|
||
2. BIOSHIPS (Living Starships, Moya, Lexx, Species 8472)
|
||
========================================================================== */
|
||
body.theme-bioships {
|
||
--primary-accent: #10b981;
|
||
--secondary-accent: #8b5cf6;
|
||
--tertiary-accent: #065f46;
|
||
--warning-accent: #ef4444;
|
||
|
||
--lcars-bg: #021a12;
|
||
--lcars-panel-bg: #04271c;
|
||
--lcars-font: 'Antonio', sans-serif;
|
||
|
||
background-color: #021a12;
|
||
background-image: radial-gradient(circle at 50% 50%, rgba(139, 92, 246, 0.12) 0%, transparent 70%);
|
||
}
|
||
|
||
body.theme-bioships .lcars-elbow-left {
|
||
background: linear-gradient(135deg, #059669, #4c1d95);
|
||
color: #ffffff;
|
||
border-radius: 28px 0 28px 0;
|
||
box-shadow: 0 0 18px rgba(16, 185, 129, 0.4);
|
||
}
|
||
|
||
body.theme-bioships .lcars-top-bar {
|
||
background: #064e3b;
|
||
color: #a7f3d0;
|
||
border-radius: 0 16px 16px 0;
|
||
}
|
||
|
||
body.theme-bioships .panel-card {
|
||
border: 1px solid rgba(16, 185, 129, 0.25);
|
||
border-radius: 14px;
|
||
}
|
||
|
||
body.theme-bioships .preset-btn {
|
||
border-radius: 12px;
|
||
background: rgba(16, 185, 129, 0.08);
|
||
color: #d1fae5;
|
||
}
|
||
|
||
body.theme-bioships .preset-btn.active {
|
||
background: linear-gradient(90deg, #10b981, #7c3aed);
|
||
color: #000000;
|
||
font-weight: bold;
|
||
}
|
||
|
||
/* ==========================================================================
|
||
3. RETRO FUTURE (1950s–1970s Golden Age, 2001, Jupiter 2)
|
||
========================================================================== */
|
||
body.theme-retrofuture {
|
||
--primary-accent: #22c55e;
|
||
--secondary-accent: #15803d;
|
||
--tertiary-accent: #86efac;
|
||
--warning-accent: #dc2626;
|
||
|
||
--lcars-bg: #03140a;
|
||
--lcars-panel-bg: #052212;
|
||
--lcars-font: 'Share Tech Mono', monospace;
|
||
|
||
background-color: #03140a;
|
||
}
|
||
|
||
body.theme-retrofuture .lcars-elbow-left {
|
||
background: #15803d;
|
||
color: #bbf7d0;
|
||
border-radius: 8px;
|
||
border: 2px solid #22c55e;
|
||
}
|
||
|
||
body.theme-retrofuture .lcars-top-bar {
|
||
background: #052e16;
|
||
color: #22c55e;
|
||
border: 1px solid #15803d;
|
||
}
|
||
|
||
body.theme-retrofuture .preset-btn {
|
||
background: #052914;
|
||
border: 1px solid #14532d;
|
||
color: #86efac;
|
||
}
|
||
|
||
body.theme-retrofuture .preset-btn.active {
|
||
background: #22c55e;
|
||
color: #000000;
|
||
box-shadow: 0 0 12px #22c55e;
|
||
}
|
||
|
||
/* ==========================================================================
|
||
4. MILITARY SPACE (Battlestar Galactica, Sulaco, Fleet Combat)
|
||
========================================================================== */
|
||
body.theme-military {
|
||
--primary-accent: #eab308;
|
||
--secondary-accent: #71717a;
|
||
--tertiary-accent: #ca8a04;
|
||
--warning-accent: #ef4444;
|
||
|
||
--lcars-bg: #09090b;
|
||
--lcars-panel-bg: #18181b;
|
||
--lcars-font: 'Share Tech Mono', monospace;
|
||
}
|
||
|
||
body.theme-military .lcars-elbow-left {
|
||
background: #27272a;
|
||
color: #eab308;
|
||
border: 2px solid #eab308;
|
||
border-radius: 0;
|
||
font-weight: 900;
|
||
}
|
||
|
||
body.theme-military .lcars-top-bar {
|
||
background: #18181b;
|
||
color: #fef08a;
|
||
border-bottom: 2px solid #eab308;
|
||
}
|
||
|
||
body.theme-military .panel-card {
|
||
border: 1px solid #3f3f46;
|
||
border-left: 4px solid #eab308;
|
||
}
|
||
|
||
body.theme-military .preset-btn {
|
||
background: #27272a;
|
||
border: 1px solid #3f3f46;
|
||
color: #e4e4e7;
|
||
border-radius: 2px;
|
||
}
|
||
|
||
body.theme-military .preset-btn.active {
|
||
background: #eab308;
|
||
color: #000000;
|
||
font-weight: bold;
|
||
}
|
||
|
||
/* ==========================================================================
|
||
5. DEEP SPACE (Generation Ships, Icarus II, Event Horizon)
|
||
========================================================================== */
|
||
body.theme-deepspace {
|
||
--primary-accent: #6366f1;
|
||
--secondary-accent: #312e81;
|
||
--tertiary-accent: #38bdf8;
|
||
--warning-accent: #f43f5e;
|
||
|
||
--lcars-bg: #030712;
|
||
--lcars-panel-bg: #0b0f19;
|
||
--lcars-font: 'Antonio', sans-serif;
|
||
background-image: radial-gradient(circle at 80% 20%, rgba(99, 102, 241, 0.15) 0%, transparent 60%);
|
||
}
|
||
|
||
body.theme-deepspace .lcars-elbow-left {
|
||
background: linear-gradient(135deg, #4338ca, #1e1b4b);
|
||
color: #e0e7ff;
|
||
border: 1px solid #6366f1;
|
||
}
|
||
|
||
body.theme-deepspace .lcars-top-bar {
|
||
background: #111827;
|
||
color: #818cf8;
|
||
}
|
||
|
||
body.theme-deepspace .preset-btn {
|
||
background: rgba(49, 46, 129, 0.25);
|
||
border: 1px solid rgba(99, 102, 241, 0.25);
|
||
color: #c7d2fe;
|
||
}
|
||
|
||
body.theme-deepspace .preset-btn.active {
|
||
background: #6366f1;
|
||
color: #ffffff;
|
||
box-shadow: 0 0 15px rgba(99, 102, 241, 0.6);
|
||
}
|
||
|
||
/* ==========================================================================
|
||
6. OUTLAW / FRONTIER (Cowboy Bebop, Outlaw Star, Milano, Betty)
|
||
========================================================================== */
|
||
body.theme-outlaw {
|
||
--primary-accent: #ec4899;
|
||
--secondary-accent: #f59e0b;
|
||
--tertiary-accent: #8b5cf6;
|
||
--warning-accent: #ef4444;
|
||
|
||
--lcars-bg: #0f0714;
|
||
--lcars-panel-bg: #1a0c23;
|
||
--lcars-font: 'Share Tech Mono', monospace;
|
||
}
|
||
|
||
body.theme-outlaw .lcars-elbow-left {
|
||
background: linear-gradient(135deg, #db2777, #9d174d);
|
||
color: #fef08a;
|
||
box-shadow: 0 0 14px rgba(236, 72, 153, 0.4);
|
||
}
|
||
|
||
body.theme-outlaw .lcars-top-bar {
|
||
background: #200d2d;
|
||
color: #f472b6;
|
||
border-bottom: 2px solid #ec4899;
|
||
}
|
||
|
||
body.theme-outlaw .preset-btn {
|
||
background: #261135;
|
||
border: 1px solid rgba(236, 72, 153, 0.3);
|
||
color: #fbcfe8;
|
||
}
|
||
|
||
body.theme-outlaw .preset-btn.active {
|
||
background: linear-gradient(90deg, #ec4899, #f59e0b);
|
||
color: #000000;
|
||
font-weight: bold;
|
||
}
|
||
|
||
/* ==========================================================================
|
||
7. SPACE STATIONS (Babylon 5, Moonbase Alpha, Sevastopol, Tycho)
|
||
========================================================================== */
|
||
body.theme-spacestations {
|
||
--primary-accent: #f97316;
|
||
--secondary-accent: #0284c7;
|
||
--tertiary-accent: #38bdf8;
|
||
--warning-accent: #dc2626;
|
||
|
||
--lcars-bg: #050b14;
|
||
--lcars-panel-bg: #0a1322;
|
||
--lcars-font: 'Share Tech Mono', monospace;
|
||
}
|
||
|
||
body.theme-spacestations .lcars-elbow-left {
|
||
background: #ea580c;
|
||
color: #000000;
|
||
border-radius: 4px;
|
||
}
|
||
|
||
body.theme-spacestations .lcars-top-bar {
|
||
background: #0f1e33;
|
||
color: #fdba74;
|
||
border-bottom: 2px solid #0284c7;
|
||
}
|
||
|
||
body.theme-spacestations .preset-btn {
|
||
background: #0e1b2e;
|
||
border-left: 3px solid #0284c7;
|
||
color: #bae6fd;
|
||
}
|
||
|
||
body.theme-spacestations .preset-btn.active {
|
||
background: #f97316;
|
||
color: #000000;
|
||
font-weight: bold;
|
||
}
|
||
|
||
/* ==========================================================================
|
||
8. COMEDY / ADVENTURE (The Orville, Heart of Gold, Spaceballs)
|
||
========================================================================== */
|
||
body.theme-comedy {
|
||
--primary-accent: #06b6d4;
|
||
--secondary-accent: #f43f5e;
|
||
--tertiary-accent: #fbbf24;
|
||
--warning-accent: #ef4444;
|
||
|
||
--lcars-bg: #0c0a21;
|
||
--lcars-panel-bg: #151233;
|
||
--lcars-font: 'Antonio', sans-serif;
|
||
background-image: radial-gradient(circle at 50% 10%, rgba(6, 182, 212, 0.2) 0%, transparent 60%);
|
||
}
|
||
|
||
body.theme-comedy .lcars-elbow-left {
|
||
background: linear-gradient(135deg, #06b6d4, #f43f5e);
|
||
color: #ffffff;
|
||
border-radius: 20px;
|
||
box-shadow: 0 0 16px rgba(6, 182, 212, 0.5);
|
||
}
|
||
|
||
body.theme-comedy .lcars-top-bar {
|
||
background: #1e1b4b;
|
||
color: #67e8f9;
|
||
}
|
||
|
||
body.theme-comedy .preset-btn {
|
||
background: rgba(6, 182, 212, 0.1);
|
||
border: 1px solid rgba(6, 182, 212, 0.3);
|
||
border-radius: 12px;
|
||
color: #cffafe;
|
||
}
|
||
|
||
body.theme-comedy .preset-btn.active {
|
||
background: linear-gradient(90deg, #06b6d4, #fbbf24);
|
||
color: #000000;
|
||
font-weight: bold;
|
||
}
|
||
|
||
|
||
/* ==========================================================================
|
||
OBSERVATION MODE
|
||
Passive casting / display view. Click anywhere to return.
|
||
========================================================================== */
|
||
|
||
.btn-observation {
|
||
background: transparent !important;
|
||
color: var(--primary-accent) !important;
|
||
border: 2px solid var(--primary-accent) !important;
|
||
}
|
||
.btn-observation:hover {
|
||
background: var(--primary-accent) !important;
|
||
color: #000 !important;
|
||
}
|
||
|
||
.observation-overlay {
|
||
position: fixed;
|
||
inset: 0;
|
||
z-index: 10000;
|
||
display: none;
|
||
background: #010308;
|
||
overflow: hidden;
|
||
cursor: default;
|
||
}
|
||
|
||
.observation-overlay.active {
|
||
display: block;
|
||
}
|
||
|
||
/* Layer 0 & 1: 60fps Deep Celestial Canvas */
|
||
.observation-canvas {
|
||
position: absolute;
|
||
inset: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
z-index: 1;
|
||
pointer-events: none;
|
||
display: block;
|
||
}
|
||
|
||
.observation-stage {
|
||
position: absolute;
|
||
inset: 0;
|
||
z-index: 2;
|
||
overflow: hidden;
|
||
pointer-events: none;
|
||
}
|
||
|
||
.observation-stage svg {
|
||
width: 100%;
|
||
height: 100%;
|
||
display: block;
|
||
}
|
||
|
||
/* Allow 60fps dynamic celestial canvas to show through legacy SVG stage while preserving telemetry & HUDs.
|
||
NOTE (v2cs): this previously read `rect:first-child`, which never matched -- every renderer's
|
||
<defs> block is the true first child of the <svg>, so the background rect is actually the second
|
||
child (or, more robustly, simply the first element of its own tag type). That silently left an
|
||
opaque near-black rectangle sitting on z-index 2, directly over the canvas engine at z-index 1,
|
||
hiding almost everything the canvas draws for every theme. Fixed by matching on type instead of
|
||
position.
|
||
|
||
NOTE (v3co): the selector above is correct but was applied GLOBALLY, which uncovered the
|
||
shared canvas layer stack in nine themes simultaneously. It is now scoped behind
|
||
`.obs-canvas-on`, a class toggled in ObservationEngine.start() from the OBSERVATION_CANVAS
|
||
manifest. Themes declared canvas:false keep their opaque background rect -- their
|
||
OBSERVATION display is their own bespoke SVG art and nothing else. */
|
||
.observation-overlay.obs-canvas-on .observation-stage svg > rect:first-of-type {
|
||
display: none;
|
||
}
|
||
.observation-stage svg g[style*="obs-drift-left"],
|
||
.observation-stage svg g[style*="obs-drift-right"] {
|
||
display: none;
|
||
}
|
||
|
||
/* Space Stations Native Viewport respect & toggle */
|
||
.obs-station-bulkhead {
|
||
transition: opacity 0.4s ease;
|
||
}
|
||
.obs-station-frame {
|
||
transition: opacity 0.4s ease;
|
||
}
|
||
.obs-viewport-hidden .obs-station-bulkhead,
|
||
.obs-viewport-hidden .obs-station-frame {
|
||
opacity: 0;
|
||
}
|
||
|
||
/* Layer 2: Architectural Starship Viewport Framing */
|
||
.observation-viewport-frame {
|
||
position: absolute;
|
||
inset: 0;
|
||
z-index: 4;
|
||
pointer-events: none;
|
||
transition: opacity 0.4s ease;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.observation-viewport-frame svg {
|
||
width: 100%;
|
||
height: 100%;
|
||
display: block;
|
||
}
|
||
|
||
.observation-viewport-frame.frame-hidden {
|
||
opacity: 0;
|
||
}
|
||
|
||
.observation-glass-sheen {
|
||
position: absolute;
|
||
inset: 0;
|
||
z-index: 5;
|
||
pointer-events: none;
|
||
background: linear-gradient(135deg, rgba(255,255,255,0.055) 0%, transparent 42%, rgba(255,255,255,0.02) 68%, transparent 100%);
|
||
}
|
||
|
||
.observation-scanlines {
|
||
position: absolute;
|
||
inset: 0;
|
||
z-index: 6;
|
||
pointer-events: none;
|
||
opacity: .14;
|
||
background: repeating-linear-gradient(
|
||
0deg,
|
||
rgba(255,255,255,.04) 0px,
|
||
rgba(255,255,255,.04) 1px,
|
||
transparent 1px,
|
||
transparent 4px
|
||
);
|
||
}
|
||
|
||
.observation-vignette {
|
||
position: absolute;
|
||
inset: 0;
|
||
z-index: 7;
|
||
pointer-events: none;
|
||
box-shadow: inset 0 0 16vw rgba(0,0,0,.82);
|
||
}
|
||
|
||
/* Layer 3: Emergency Alert Lighting Wash */
|
||
.observation-alert-wash {
|
||
position: absolute;
|
||
inset: 0;
|
||
z-index: 8;
|
||
pointer-events: none;
|
||
opacity: 0;
|
||
transition: opacity 0.45s ease;
|
||
}
|
||
|
||
.observation-alert-wash.alert-red {
|
||
opacity: 1;
|
||
background: radial-gradient(circle at center, rgba(255, 0, 0, 0.08) 0%, rgba(220, 20, 20, 0.35) 75%, rgba(120, 0, 0, 0.72) 100%);
|
||
animation: obsAlertStrobeRed 1.1s ease-in-out infinite alternate;
|
||
}
|
||
|
||
.observation-alert-wash.alert-yellow {
|
||
opacity: 1;
|
||
background: radial-gradient(circle at center, rgba(255, 180, 0, 0.06) 0%, rgba(220, 150, 20, 0.28) 75%, rgba(140, 80, 0, 0.6) 100%);
|
||
animation: obsAlertStrobeYellow 1.5s ease-in-out infinite alternate;
|
||
}
|
||
|
||
@keyframes obsAlertStrobeRed {
|
||
0% { opacity: 0.2; }
|
||
100% { opacity: 0.95; }
|
||
}
|
||
|
||
@keyframes obsAlertStrobeYellow {
|
||
0% { opacity: 0.25; }
|
||
100% { opacity: 0.85; }
|
||
}
|
||
|
||
/* Layer 4: Holographic LCARS HUD */
|
||
.observation-chrome {
|
||
position: absolute;
|
||
inset: 0;
|
||
z-index: 9;
|
||
pointer-events: none;
|
||
font-family: var(--mono-font);
|
||
color: #e8f4ff;
|
||
text-shadow: 0 0 8px rgba(255,255,255,0.18);
|
||
opacity: 1;
|
||
transition: opacity 0.5s ease;
|
||
}
|
||
|
||
.observation-topline {
|
||
position: absolute;
|
||
top: 3.2vh;
|
||
left: 3vw;
|
||
right: 3vw;
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: flex-start;
|
||
gap: 2rem;
|
||
pointer-events: none;
|
||
}
|
||
|
||
.observation-mode-label {
|
||
font-family: var(--lcars-font);
|
||
font-size: clamp(1rem, 1.6vw, 1.7rem);
|
||
letter-spacing: 0.22em;
|
||
font-weight: 700;
|
||
color: var(--primary-accent);
|
||
}
|
||
|
||
.observation-profile {
|
||
margin-top: .45rem;
|
||
font-size: clamp(.8rem, 1.05vw, 1.1rem);
|
||
letter-spacing: .08em;
|
||
color: rgba(235,245,255,.78);
|
||
}
|
||
|
||
.observation-status {
|
||
text-align: right;
|
||
font-size: clamp(.7rem, .9vw, .95rem);
|
||
letter-spacing: .1em;
|
||
line-height: 1.65;
|
||
color: rgba(235,245,255,.62);
|
||
}
|
||
|
||
.observation-waveform-container {
|
||
position: absolute;
|
||
bottom: 2.2vh;
|
||
left: 50%;
|
||
transform: translateX(-50%);
|
||
z-index: 9;
|
||
pointer-events: none;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
gap: 4px;
|
||
opacity: 0.82;
|
||
}
|
||
|
||
.observation-waveform-label {
|
||
font-family: var(--mono-font);
|
||
font-size: 0.65rem;
|
||
letter-spacing: 0.2em;
|
||
color: var(--tertiary-accent);
|
||
text-shadow: 0 0 6px rgba(0,0,0,0.9);
|
||
}
|
||
|
||
#observation-waveform-canvas {
|
||
width: clamp(240px, 32vw, 440px);
|
||
height: 24px;
|
||
border-radius: 4px;
|
||
}
|
||
|
||
/* Scrolling Universe-Specific Status Ticker */
|
||
.observation-ticker {
|
||
position: absolute;
|
||
top: 1.05vh;
|
||
left: 3vw;
|
||
right: 3vw;
|
||
z-index: 9;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 10px;
|
||
pointer-events: none;
|
||
opacity: 0.85;
|
||
}
|
||
|
||
.observation-ticker-label {
|
||
font-family: var(--lcars-font);
|
||
font-size: 0.62rem;
|
||
font-weight: 700;
|
||
letter-spacing: 0.18em;
|
||
color: #000;
|
||
background: var(--tertiary-accent, #99ccff);
|
||
padding: 2px 9px;
|
||
border-radius: 8px;
|
||
flex-shrink: 0;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.observation-ticker-track {
|
||
flex: 1;
|
||
min-width: 0;
|
||
overflow: hidden;
|
||
white-space: nowrap;
|
||
-webkit-mask-image: linear-gradient(90deg, transparent 0%, #000 6%, #000 94%, transparent 100%);
|
||
mask-image: linear-gradient(90deg, transparent 0%, #000 6%, #000 94%, transparent 100%);
|
||
}
|
||
|
||
.observation-ticker-text {
|
||
display: inline-block;
|
||
font-family: var(--mono-font);
|
||
font-size: 0.7rem;
|
||
letter-spacing: 0.13em;
|
||
color: rgba(235,245,255,.7);
|
||
white-space: nowrap;
|
||
padding-left: 100%;
|
||
animation: obsTickerScroll 20s linear infinite;
|
||
}
|
||
|
||
@keyframes obsTickerScroll {
|
||
0% { transform: translateX(0); }
|
||
100% { transform: translateX(-100%); }
|
||
}
|
||
|
||
/* Auto-hiding in-observation dock */
|
||
.observation-control-dock {
|
||
position: absolute;
|
||
bottom: 2.5vh;
|
||
right: 2.5vw;
|
||
z-index: 12;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
background: rgba(8, 12, 22, 0.88);
|
||
backdrop-filter: blur(14px);
|
||
border: 1px solid color-mix(in srgb, var(--primary-accent) 65%, transparent);
|
||
box-shadow: 0 4px 28px rgba(0,0,0,0.8), inset 0 0 14px rgba(255,255,255,0.03);
|
||
border-radius: 20px;
|
||
padding: 6px 12px;
|
||
transition: opacity 0.35s ease, transform 0.35s ease;
|
||
opacity: 1;
|
||
}
|
||
|
||
.observation-control-dock.dock-autohide {
|
||
opacity: 0;
|
||
pointer-events: none;
|
||
transform: translateY(8px);
|
||
}
|
||
|
||
.obs-dock-btn {
|
||
background: rgba(0,0,0,0.55);
|
||
border: 1px solid color-mix(in srgb, var(--primary-accent) 55%, transparent);
|
||
color: #e2e8f0;
|
||
font-family: var(--lcars-font);
|
||
font-size: 0.82rem;
|
||
font-weight: 700;
|
||
letter-spacing: 0.08em;
|
||
padding: 5px 12px;
|
||
border-radius: 12px;
|
||
cursor: pointer;
|
||
transition: all 0.16s ease;
|
||
white-space: nowrap;
|
||
user-select: none;
|
||
}
|
||
|
||
.obs-dock-btn:hover {
|
||
background: var(--primary-accent);
|
||
color: #000;
|
||
box-shadow: 0 0 10px var(--primary-accent);
|
||
}
|
||
|
||
.obs-dock-btn.active {
|
||
background: var(--primary-accent);
|
||
color: #000;
|
||
border-color: var(--primary-accent);
|
||
box-shadow: 0 0 12px var(--primary-accent);
|
||
}
|
||
|
||
.obs-dock-btn.btn-alert-active {
|
||
background: #dc2626 !important;
|
||
color: #fff !important;
|
||
border-color: #f87171 !important;
|
||
box-shadow: 0 0 14px #dc2626 !important;
|
||
animation: obsBtnAlertPulse 0.9s ease-in-out infinite alternate;
|
||
}
|
||
|
||
.obs-dock-btn.obs-dock-close {
|
||
border-color: #f87171;
|
||
color: #fca5a5;
|
||
}
|
||
|
||
.obs-dock-btn.obs-dock-close:hover {
|
||
background: #dc2626;
|
||
color: #fff;
|
||
box-shadow: 0 0 12px #dc2626;
|
||
}
|
||
|
||
@keyframes obsBtnAlertPulse {
|
||
from { opacity: 0.75; }
|
||
to { opacity: 1; }
|
||
}
|
||
|
||
.obs-dock-select {
|
||
background: rgba(0,0,0,0.75);
|
||
border: 1px solid color-mix(in srgb, var(--tertiary-accent) 60%, transparent);
|
||
color: var(--tertiary-accent);
|
||
font-family: var(--mono-font);
|
||
font-size: 0.78rem;
|
||
padding: 5px 8px;
|
||
border-radius: 8px;
|
||
cursor: pointer;
|
||
max-width: 170px;
|
||
outline: none;
|
||
}
|
||
|
||
.obs-dock-select option {
|
||
background: #0d1117;
|
||
color: #e2e8f0;
|
||
}
|
||
|
||
.observation-return {
|
||
position: absolute;
|
||
bottom: 2.8vh;
|
||
left: 3vw;
|
||
padding: .45rem .9rem;
|
||
border: 1px solid color-mix(in srgb, var(--primary-accent) 55%, transparent);
|
||
border-radius: 999px;
|
||
background: rgba(0,0,0,.45);
|
||
backdrop-filter: blur(8px);
|
||
color: rgba(255,255,255,.78);
|
||
font-size: clamp(.65rem, .78vw, .82rem);
|
||
letter-spacing: .16em;
|
||
white-space: nowrap;
|
||
cursor: pointer;
|
||
z-index: 12;
|
||
transition: background 0.2s ease, color 0.2s ease, opacity 0.5s ease;
|
||
}
|
||
|
||
.observation-return:hover {
|
||
background: var(--primary-accent);
|
||
color: #000;
|
||
}
|
||
|
||
@keyframes obs-drift-left {
|
||
from { transform: translateX(0); }
|
||
to { transform: translateX(-160px); }
|
||
}
|
||
@keyframes obs-drift-right {
|
||
from { transform: translateX(-100px); }
|
||
to { transform: translateX(80px); }
|
||
}
|
||
@keyframes obs-pulse {
|
||
0%, 100% { opacity: .35; transform: scale(1); }
|
||
50% { opacity: 1; transform: scale(1.045); }
|
||
}
|
||
@keyframes obs-rotate {
|
||
to { transform: rotate(360deg); }
|
||
}
|
||
@keyframes obs-rotate-rev {
|
||
to { transform: rotate(-360deg); }
|
||
}
|
||
@keyframes obs-sweep {
|
||
0% { opacity: 0; transform: translateY(-8%); }
|
||
15% { opacity: .65; }
|
||
85% { opacity: .65; }
|
||
100% { opacity: 0; transform: translateY(108%); }
|
||
}
|
||
@keyframes obs-flicker {
|
||
0%, 95%, 100% { opacity: 1; }
|
||
96% { opacity: .35; }
|
||
97% { opacity: .9; }
|
||
98% { opacity: .2; }
|
||
}
|
||
@keyframes obs-blink {
|
||
0%, 44%, 100% { opacity: .2; }
|
||
45%, 70% { opacity: 1; }
|
||
}
|
||
@keyframes obs-breathe {
|
||
0%, 100% { transform: scale(.98); filter: brightness(.86); }
|
||
50% { transform: scale(1.04); filter: brightness(1.15); }
|
||
}
|
||
@keyframes obs-wave {
|
||
0% { stroke-dashoffset: 0; }
|
||
100% { stroke-dashoffset: -180; }
|
||
}
|
||
|
||
.obs-spin {
|
||
transform-box: fill-box;
|
||
transform-origin: center;
|
||
animation: obs-rotate 18s linear infinite;
|
||
}
|
||
.obs-spin-slow {
|
||
transform-box: fill-box;
|
||
transform-origin: center;
|
||
animation: obs-rotate 42s linear infinite;
|
||
}
|
||
.obs-spin-rev {
|
||
transform-box: fill-box;
|
||
transform-origin: center;
|
||
animation: obs-rotate-rev 28s linear infinite;
|
||
}
|
||
.obs-pulse {
|
||
transform-box: fill-box;
|
||
transform-origin: center;
|
||
animation: obs-pulse 3.8s ease-in-out infinite;
|
||
}
|
||
.obs-breathe {
|
||
transform-box: fill-box;
|
||
transform-origin: center;
|
||
animation: obs-breathe 5.5s ease-in-out infinite;
|
||
}
|
||
.obs-flicker {
|
||
animation: obs-flicker 8s steps(1,end) infinite;
|
||
}
|
||
.obs-blink {
|
||
animation: obs-blink 3.5s steps(1,end) infinite;
|
||
}
|
||
.obs-dashflow {
|
||
stroke-dasharray: 20 12;
|
||
animation: obs-wave 7s linear infinite;
|
||
}
|
||
|
||
/* OBSERVATION-specific theme tinting */
|
||
body.theme-whoniverse-tardis .observation-overlay { background: #020817; }
|
||
body.theme-industrial .observation-overlay { background: #070706; }
|
||
body.theme-bioships .observation-overlay { background: #010b07; }
|
||
body.theme-retrofuture .observation-overlay { background: #010903; }
|
||
body.theme-military .observation-overlay { background: #050506; }
|
||
body.theme-deepspace .observation-overlay { background: #010207; }
|
||
body.theme-outlaw .observation-overlay { background: #09040c; }
|
||
body.theme-spacestations .observation-overlay { background: #02070d; }
|
||
body.theme-comedy .observation-overlay { background: #07061a; }
|
||
|
||
@media (prefers-reduced-motion: reduce) {
|
||
.observation-overlay * {
|
||
animation-duration: 1ms !important;
|
||
animation-iteration-count: 1 !important;
|
||
}
|
||
}
|
||
|
||
|
||
/* ==========================================================================
|
||
OBSERVATION ACTIVITY ENGINE
|
||
Generative transient visuals + richer ambient motion.
|
||
========================================================================== */
|
||
|
||
.observation-activity-control {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
min-width: min(330px, 100%);
|
||
padding: 6px 10px;
|
||
border: 1px solid color-mix(in srgb, var(--primary-accent) 55%, transparent);
|
||
border-radius: 14px;
|
||
background: rgba(255,255,255,.025);
|
||
font-family: var(--mono-font);
|
||
}
|
||
|
||
.observation-activity-label {
|
||
color: var(--primary-accent);
|
||
font-size: .72rem;
|
||
font-weight: 700;
|
||
letter-spacing: .08em;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.observation-activity-control input[type="range"] {
|
||
flex: 1;
|
||
min-width: 90px;
|
||
height: 6px;
|
||
}
|
||
|
||
.observation-activity-value {
|
||
min-width: 38px;
|
||
text-align: right;
|
||
color: #dbeafe;
|
||
font-size: .75rem;
|
||
}
|
||
|
||
.observation-event-layer {
|
||
position: absolute;
|
||
inset: 0;
|
||
z-index: 3;
|
||
overflow: hidden;
|
||
pointer-events: none;
|
||
}
|
||
|
||
.obs-transient {
|
||
position: absolute;
|
||
inset: 0;
|
||
opacity: 0;
|
||
pointer-events: none;
|
||
animation: obs-transient-life var(--obs-life, 4.5s) ease-in-out forwards;
|
||
}
|
||
|
||
.obs-transient svg {
|
||
width: 100%;
|
||
height: 100%;
|
||
display: block;
|
||
}
|
||
|
||
@keyframes obs-transient-life {
|
||
0% { opacity: 0; }
|
||
8% { opacity: 1; }
|
||
78% { opacity: .92; }
|
||
100% { opacity: 0; }
|
||
}
|
||
|
||
@keyframes obs-transient-pop {
|
||
0% { transform: scale(.55); opacity: 0; }
|
||
22% { transform: scale(1.08); opacity: 1; }
|
||
100% { transform: scale(1); opacity: .2; }
|
||
}
|
||
|
||
@keyframes obs-transient-ring {
|
||
from { transform: scale(.15); opacity: .95; }
|
||
to { transform: scale(2.7); opacity: 0; }
|
||
}
|
||
|
||
@keyframes obs-slide-horizontal {
|
||
from { transform: translateX(-130px); }
|
||
to { transform: translateX(130px); }
|
||
}
|
||
|
||
@keyframes obs-slide-horizontal-wide {
|
||
from { transform: translateX(-520px); }
|
||
to { transform: translateX(520px); }
|
||
}
|
||
|
||
@keyframes obs-slide-vertical {
|
||
from { transform: translateY(-160px); }
|
||
to { transform: translateY(160px); }
|
||
}
|
||
|
||
@keyframes obs-soft-wobble {
|
||
0%,100% { transform: translate(0,0) rotate(0deg); }
|
||
25% { transform: translate(4px,-2px) rotate(.25deg); }
|
||
60% { transform: translate(-3px,3px) rotate(-.2deg); }
|
||
}
|
||
|
||
@keyframes obs-glow-cycle {
|
||
0%,100% { opacity: .18; }
|
||
50% { opacity: .88; }
|
||
}
|
||
|
||
@keyframes obs-drift-up {
|
||
from { transform: translateY(70px); opacity: 0; }
|
||
15% { opacity: .7; }
|
||
to { transform: translateY(-120px); opacity: 0; }
|
||
}
|
||
|
||
@keyframes obs-zoom-in {
|
||
from { transform: scale(.82); opacity: .15; }
|
||
to { transform: scale(1.16); opacity: .8; }
|
||
}
|
||
|
||
@keyframes obs-route-wander {
|
||
0%,100% { stroke-dashoffset: 0; opacity: .35; }
|
||
50% { stroke-dashoffset: -120; opacity: .9; }
|
||
}
|
||
|
||
@keyframes obs-planet-drift {
|
||
from { transform: translateX(-220px); }
|
||
to { transform: translateX(1900px); }
|
||
}
|
||
|
||
@keyframes obs-comet-drift {
|
||
from { transform: translate(-250px, 180px) rotate(-15deg); opacity: 0; }
|
||
10% { opacity: .8; }
|
||
85% { opacity: .65; }
|
||
to { transform: translate(1900px, -260px) rotate(-15deg); opacity: 0; }
|
||
}
|
||
|
||
@keyframes obs-camera-pan {
|
||
0%,100% { transform: translateX(-14px) scale(1.03); }
|
||
50% { transform: translateX(14px) scale(1.07); }
|
||
}
|
||
|
||
@keyframes obs-organic-undulate {
|
||
0%,100% { transform: scale(1, .97) skewX(-1deg); }
|
||
50% { transform: scale(1.035, 1.045) skewX(1deg); }
|
||
}
|
||
|
||
@keyframes obs-crt-jump {
|
||
0%,93%,100% { transform: translateY(0); opacity: 1; }
|
||
94% { transform: translateY(9px); opacity: .6; }
|
||
95% { transform: translateY(-5px); opacity: .85; }
|
||
96% { transform: translateY(2px); opacity: .35; }
|
||
}
|
||
|
||
/* ==========================================================================
|
||
INDUSTRIAL OBSERVATION — v13co
|
||
Video-feed artifacts and mechanical work cycles.
|
||
EVERY effect below is authored to live INSIDE a camera clip-path so it
|
||
can never bleed across the console the way the old full-screen sweep and
|
||
the free-floating steam blobs did.
|
||
========================================================================== */
|
||
|
||
/* Rolling horizontal sync bar — travels down ONE feed, not the screen. */
|
||
@keyframes obs-feed-roll {
|
||
0% { transform: translateY(-72px); }
|
||
100% { transform: translateY(292px); }
|
||
}
|
||
|
||
/* Occasional tracking tear: a couple of displaced scan blocks, then gone. */
|
||
@keyframes obs-feed-tear {
|
||
0%, 87%, 100% { opacity: 0; transform: translate(0, 120px); }
|
||
88% { opacity: .55; transform: translate(-11px, 74px); }
|
||
90% { opacity: .32; transform: translate(9px, 158px); }
|
||
92% { opacity: .48; transform: translate(-5px, 44px); }
|
||
94% { opacity: 0; transform: translate(0, 210px); }
|
||
}
|
||
|
||
/* Analogue grain: churn opacity only so the turbulence filter stays cached. */
|
||
@keyframes obs-feed-grain {
|
||
0%, 100% { opacity: .055; }
|
||
25% { opacity: .10; }
|
||
50% { opacity: .04; }
|
||
75% { opacity: .115; }
|
||
}
|
||
|
||
/* Automatic gain control hunting for exposure. */
|
||
@keyframes obs-feed-agc {
|
||
0%, 100% { opacity: 0; }
|
||
40% { opacity: .055; }
|
||
70% { opacity: .02; }
|
||
}
|
||
|
||
/* Active-feed selector; four cameras share this with negative delays. */
|
||
@keyframes obs-cam-focus {
|
||
0%, 21% { opacity: 1; }
|
||
23%, 100% { opacity: 0; }
|
||
}
|
||
|
||
/* --- CARGO BAY: gantry crane work cycle. Phases interlock on one clock. --- */
|
||
@keyframes obs-gantry-traverse {
|
||
0%, 18% { transform: translateX(0px); }
|
||
38%, 62% { transform: translateX(290px); }
|
||
82%, 100% { transform: translateX(0px); }
|
||
}
|
||
@keyframes obs-gantry-hoist {
|
||
0% { transform: translateY(0px); }
|
||
5% { transform: translateY(66px); }
|
||
11% { transform: translateY(66px); }
|
||
17% { transform: translateY(0px); }
|
||
40% { transform: translateY(0px); }
|
||
45% { transform: translateY(66px); }
|
||
53% { transform: translateY(66px); }
|
||
60% { transform: translateY(0px); }
|
||
100% { transform: translateY(0px); }
|
||
}
|
||
@keyframes obs-gantry-load {
|
||
0%, 11% { opacity: 0; }
|
||
13%, 45% { opacity: 1; }
|
||
53%, 100% { opacity: 0; }
|
||
}
|
||
@keyframes obs-gantry-taken {
|
||
0%, 10% { opacity: 1; }
|
||
13%, 96% { opacity: 0; }
|
||
100% { opacity: 1; }
|
||
}
|
||
@keyframes obs-gantry-placed {
|
||
0%, 52% { opacity: 0; }
|
||
56%, 96% { opacity: 1; }
|
||
100% { opacity: 0; }
|
||
}
|
||
@keyframes obs-gantry-lamp {
|
||
0%, 16%, 62%, 100% { fill: #16a34a; }
|
||
19%, 38% { fill: #f59e0b; }
|
||
45%, 59% { fill: #f59e0b; }
|
||
}
|
||
@keyframes obs-bay-shudder {
|
||
0%, 46%, 52%, 100% { transform: translate(0, 0); }
|
||
47% { transform: translate(.9px, -.7px); }
|
||
49% { transform: translate(-.8px, .6px); }
|
||
51% { transform: translate(.5px, .4px); }
|
||
}
|
||
|
||
/* Rotating hazard beacon. Pivot comes from a zero-fill bbox anchor circle. */
|
||
@keyframes obs-beacon-sweep { to { transform: rotate(360deg); } }
|
||
@keyframes obs-beacon-flash {
|
||
0%, 100% { opacity: .16; }
|
||
50% { opacity: .95; }
|
||
}
|
||
|
||
/* Steam / vapour: rises from a vent and dissipates. Always inside a clip. */
|
||
@keyframes obs-vapour {
|
||
0% { transform: translate(0, 0) scale(.3); opacity: 0; }
|
||
18% { opacity: .34; }
|
||
60% { opacity: .16; }
|
||
100% { transform: translate(var(--vx, 12px), -94px) scale(1.9); opacity: 0; }
|
||
}
|
||
|
||
/* --- REACTOR PLANT --- */
|
||
@keyframes obs-core-breathe {
|
||
0%, 100% { transform: scale(.93); opacity: .55; }
|
||
50% { transform: scale(1.08); opacity: 1; }
|
||
}
|
||
@keyframes obs-rod-travel {
|
||
0%, 100% { transform: translateY(0); }
|
||
50% { transform: translateY(11px); }
|
||
}
|
||
@keyframes obs-heat-shimmer {
|
||
0%, 100% { transform: translateY(0) scaleY(1); opacity: .14; }
|
||
50% { transform: translateY(-3px) scaleY(1.07); opacity: .3; }
|
||
}
|
||
@keyframes obs-needle-hunt {
|
||
0%, 100% { transform: rotate(-33deg); }
|
||
30% { transform: rotate(19deg); }
|
||
55% { transform: rotate(-9deg); }
|
||
78% { transform: rotate(30deg); }
|
||
}
|
||
@keyframes obs-pipe-flow { to { stroke-dashoffset: -240; } }
|
||
|
||
/* --- AIRLOCK --- */
|
||
@keyframes obs-dog-ring {
|
||
0%, 30% { transform: rotate(0deg); }
|
||
46%, 76% { transform: rotate(45deg); }
|
||
92%, 100% { transform: rotate(0deg); }
|
||
}
|
||
@keyframes obs-airlock-cycle {
|
||
0%, 24% { opacity: 1; }
|
||
26%, 100% { opacity: .1; }
|
||
}
|
||
|
||
/* --- MACHINE CORRIDOR --- */
|
||
@keyframes obs-lamp-fail {
|
||
0%, 61%, 100% { opacity: .85; }
|
||
62% { opacity: .1; }
|
||
63.5% { opacity: .72; }
|
||
65% { opacity: .08; }
|
||
67% { opacity: .8; }
|
||
70% { opacity: .22; }
|
||
72% { opacity: .82; }
|
||
}
|
||
@keyframes obs-drip {
|
||
0%, 72% { transform: translateY(0); opacity: 0; }
|
||
76% { opacity: .75; }
|
||
100% { transform: translateY(54px); opacity: 0; }
|
||
}
|
||
|
||
.obs-feed-roll { animation: obs-feed-roll 7.5s linear infinite; }
|
||
.obs-feed-grain { animation: obs-feed-grain .45s steps(2, end) infinite; }
|
||
.obs-feed-agc { animation: obs-feed-agc 9s ease-in-out infinite; }
|
||
.obs-feed-tear { animation: obs-feed-tear 13s linear infinite; }
|
||
.obs-cam-focus { animation: obs-cam-focus 32s linear infinite; }
|
||
.obs-beacon-sweep { transform-box: fill-box; transform-origin: center; animation: obs-beacon-sweep 3.4s linear infinite; }
|
||
.obs-beacon-flash { animation: obs-beacon-flash 1.7s ease-in-out infinite; }
|
||
.obs-pipe-flow { animation: obs-pipe-flow 4s linear infinite; }
|
||
.obs-heat-shimmer { transform-box: fill-box; transform-origin: bottom center; animation: obs-heat-shimmer 3.2s ease-in-out infinite; }
|
||
.obs-lamp-fail { animation: obs-lamp-fail 9s linear infinite; }
|
||
.obs-bay-shudder { animation: obs-bay-shudder 17s ease-in-out infinite; }
|
||
.obs-pivot { transform-box: fill-box; transform-origin: center; }
|
||
|
||
/* Functional link: the OBSERVATION activity slider drives plant output and
|
||
crane pace, so what you see tracks what the console says it is doing.
|
||
All six gantry animations share one clock so their phases stay locked. */
|
||
.observation-overlay {
|
||
--obs-activity: .6;
|
||
--obs-gantry-clock: calc(34s - var(--obs-activity, .6) * 14s);
|
||
}
|
||
.obs-core-load {
|
||
transform-box: fill-box;
|
||
transform-origin: center;
|
||
animation: obs-core-breathe calc(7.4s - var(--obs-activity, .6) * 4s) ease-in-out infinite;
|
||
}
|
||
.obs-core-halo { opacity: calc(.03 + var(--obs-activity, .6) * .16); }
|
||
|
||
@media (prefers-reduced-motion: reduce) {
|
||
.obs-feed-roll, .obs-feed-grain, .obs-feed-tear, .obs-feed-agc,
|
||
.obs-beacon-sweep, .obs-bay-shudder, .obs-lamp-fail { animation: none; }
|
||
}
|
||
|
||
.obs-ambient-wobble {
|
||
transform-box: fill-box;
|
||
transform-origin: center;
|
||
animation: obs-soft-wobble 8s ease-in-out infinite;
|
||
}
|
||
|
||
.obs-ambient-glow {
|
||
animation: obs-glow-cycle 5.5s ease-in-out infinite;
|
||
}
|
||
|
||
.obs-camera-pan {
|
||
transform-box: fill-box;
|
||
transform-origin: center;
|
||
animation: obs-camera-pan 14s ease-in-out infinite;
|
||
}
|
||
|
||
.obs-organic-undulate {
|
||
transform-box: fill-box;
|
||
transform-origin: center;
|
||
animation: obs-organic-undulate 7s ease-in-out infinite;
|
||
}
|
||
|
||
.obs-crt-jump {
|
||
animation: obs-crt-jump 11s steps(1,end) infinite;
|
||
}
|
||
|
||
.obs-route-wander {
|
||
animation: obs-route-wander 8s linear infinite;
|
||
}
|
||
|
||
/* OBSERVATION chrome remains above generative effects. */
|
||
.observation-chrome { z-index: 9; }
|
||
.observation-scanlines { z-index: 6; }
|
||
.observation-vignette { z-index: 7; }
|
||
|
||
@media (max-width: 820px) {
|
||
.observation-activity-control {
|
||
width: 100%;
|
||
}
|
||
}
|
||
|
||
|
||
/* ==========================================================================
|
||
LIVE OBSERVATION INSTRUMENTATION
|
||
Applies only to fantasy text inside the SVG observation visualization.
|
||
========================================================================== */
|
||
.observation-stage text.obs-live-instrument,
|
||
.observation-event-layer text.obs-live-instrument {
|
||
transition: opacity .12s linear;
|
||
}
|
||
.observation-stage text.obs-live-glitch,
|
||
.observation-event-layer text.obs-live-glitch {
|
||
opacity: .72;
|
||
}
|
||
|
||
|
||
/* ==========================================================================
|
||
OBSERVATION HUD PERSISTENCE
|
||
HUD HOLD on = profile/status/return chrome stays visible.
|
||
HUD HOLD off = chrome fades away over 30 seconds after OBSERVATION starts.
|
||
========================================================================== */
|
||
|
||
.observation-hud-control {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
padding: 6px 10px;
|
||
border: 1px solid color-mix(in srgb, var(--primary-accent) 55%, transparent);
|
||
border-radius: 14px;
|
||
background: rgba(255,255,255,.025);
|
||
font-family: var(--mono-font);
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.observation-hud-label {
|
||
color: var(--primary-accent);
|
||
font-size: .72rem;
|
||
font-weight: 700;
|
||
letter-spacing: .08em;
|
||
}
|
||
|
||
.observation-hud-control input[type="checkbox"] {
|
||
width: 18px;
|
||
height: 18px;
|
||
accent-color: var(--primary-accent);
|
||
cursor: pointer;
|
||
}
|
||
|
||
.observation-hud-state {
|
||
min-width: 34px;
|
||
color: #dbeafe;
|
||
font-size: .75rem;
|
||
text-align: right;
|
||
}
|
||
|
||
.observation-chrome {
|
||
opacity: 1;
|
||
transition: opacity 30s linear;
|
||
}
|
||
|
||
.observation-chrome.observation-hud-fade {
|
||
opacity: 0;
|
||
}
|
||
|
||
|
||
/* CLICK ANYWHERE TO RETURN always fades away over 30 seconds,
|
||
independently of the HUD HOLD setting. */
|
||
.observation-return {
|
||
opacity: 1;
|
||
transition: opacity 30s linear;
|
||
}
|
||
|
||
.observation-return.observation-return-fade {
|
||
opacity: 0;
|
||
}
|
||
|
||
|
||
/* ==========================================================================
|
||
OBSERVATION SCENE ENGINE
|
||
Persistent generative world layer. Unlike transient alerts, these entities
|
||
have lifecycles and move through the scene over time.
|
||
========================================================================== */
|
||
.observation-sim-layer {
|
||
position: absolute;
|
||
inset: 0;
|
||
z-index: 2;
|
||
overflow: hidden;
|
||
pointer-events: none;
|
||
}
|
||
|
||
.observation-sim-layer svg {
|
||
width: 100%;
|
||
height: 100%;
|
||
display: block;
|
||
}
|
||
|
||
.obs-scene-entity {
|
||
will-change: transform, opacity;
|
||
}
|
||
|
||
.obs-scene-soft {
|
||
filter: url(#obsSceneGlow);
|
||
}
|
||
|
||
@keyframes obs-scene-fan-spin {
|
||
to { transform: rotate(360deg); }
|
||
}
|
||
|
||
@keyframes obs-scene-breathe {
|
||
0%, 100% { opacity: .28; transform: scale(.96); }
|
||
50% { opacity: .72; transform: scale(1.06); }
|
||
}
|
||
|
||
@keyframes obs-scene-flicker {
|
||
0%, 92%, 100% { opacity: .72; }
|
||
93% { opacity: .28; }
|
||
94% { opacity: .86; }
|
||
96% { opacity: .42; }
|
||
}
|
||
|
||
.obs-scene-fan {
|
||
transform-box: fill-box;
|
||
transform-origin: center;
|
||
animation: obs-scene-fan-spin 5s linear infinite;
|
||
}
|
||
|
||
.obs-scene-breathe {
|
||
transform-box: fill-box;
|
||
transform-origin: center;
|
||
animation: obs-scene-breathe 6s ease-in-out infinite;
|
||
}
|
||
|
||
.obs-scene-flicker {
|
||
animation: obs-scene-flicker 10s steps(1,end) infinite;
|
||
}
|
||
|