*, *::before, *::after { box-sizing: border-box; } :root { --wood: #3a281a; --wood-light: #5e4129; --wood-dark: #241710; --brass: #c9a227; --brass-dark: #8b6914; --phosphor: #7cdf8f; --phosphor-dim: #2c4a30; --screen-bg: #06120a; --glow: #ff6b35; --glow-dim: #994020; --station-glow: #7cdf8f; } html, body { margin: 0; min-height: 100vh; background: radial-gradient(ellipse at 50% 30%, #100b18 0%, #04030a 75%); font-family: "Courier New", Courier, monospace; color: #d4c4a8; display: flex; align-items: center; justify-content: center; padding: 1rem; overflow-x: hidden; } /* =================================================================== Galaxy: drifting starfield canvas + breathing nebulas =================================================================== */ .galaxy { position: fixed; inset: 0; z-index: 0; width: 100vw; height: 100vh; pointer-events: none; } .nebula { position: fixed; z-index: 0; width: 70vmax; height: 70vmax; border-radius: 50%; pointer-events: none; filter: blur(60px); opacity: 0.5; mix-blend-mode: screen; } .nebula-a { top: -25vmax; left: -18vmax; background: radial-gradient(circle at 40% 45%, rgba(64, 134, 90, 0.32) 0%, rgba(30, 80, 110, 0.18) 45%, transparent 70%); animation: nebula-drift-a 46s ease-in-out infinite alternate; } .nebula-b { bottom: -30vmax; right: -20vmax; background: radial-gradient(circle at 60% 55%, rgba(110, 60, 130, 0.26) 0%, rgba(40, 90, 80, 0.16) 50%, transparent 72%); animation: nebula-drift-b 58s ease-in-out infinite alternate; } @keyframes nebula-drift-a { 0% { transform: translate(0, 0) scale(1); } 100% { transform: translate(9vmax, 6vmax) scale(1.18); } } @keyframes nebula-drift-b { 0% { transform: translate(0, 0) scale(1.1); } 100% { transform: translate(-8vmax, -7vmax) scale(0.95); } } /* =================================================================== Boot screen: power-on ritual =================================================================== */ .boot { position: fixed; inset: 0; z-index: 50; display: flex; align-items: center; justify-content: center; background: radial-gradient(ellipse at 50% 42%, rgba(10, 26, 16, 0.55) 0%, rgba(2, 3, 7, 0.92) 75%); backdrop-filter: blur(2px); transition: opacity 0.7s ease, visibility 0.7s; } .boot.hidden { opacity: 0; visibility: hidden; pointer-events: none; } .boot-inner { display: flex; flex-direction: column; align-items: center; gap: 18px; text-align: center; padding: 24px; max-width: 640px; } /* the host emerges from a signal portal: concentric rings + a radar sweep */ .boot-portal { position: relative; width: min(340px, 72vw); aspect-ratio: 1; display: grid; place-items: center; margin-bottom: 4px; } .portal-ring { position: absolute; inset: 0; margin: auto; border-radius: 50%; border: 1px solid rgba(124, 223, 143, 0.35); pointer-events: none; } .portal-ring-1 { width: 96%; height: 96%; box-shadow: 0 0 40px rgba(124, 223, 143, 0.12) inset; animation: portal-spin 26s linear infinite; border-style: dashed; } .portal-ring-2 { width: 72%; height: 72%; border-color: rgba(124, 223, 143, 0.22); animation: portal-pulse 3.6s ease-in-out infinite; } .portal-ring-3 { width: 48%; height: 48%; border-color: rgba(154, 216, 255, 0.3); animation: portal-pulse 3.6s ease-in-out infinite 0.6s; } .portal-sweep { position: absolute; inset: 2%; border-radius: 50%; pointer-events: none; background: conic-gradient( from 0deg, rgba(124, 223, 143, 0) 0deg, rgba(124, 223, 143, 0) 300deg, rgba(124, 223, 143, 0.28) 350deg, rgba(124, 223, 143, 0) 360deg ); mask-image: radial-gradient(circle, transparent 30%, black 31%, black 100%); animation: portal-spin 5.5s linear infinite; } @keyframes portal-spin { to { transform: rotate(360deg); } } @keyframes portal-pulse { 0%, 100% { transform: scale(1); opacity: 0.6; } 50% { transform: scale(1.05); opacity: 1; } } .boot-host { position: relative; z-index: 2; width: min(248px, 52vw); mix-blend-mode: screen; filter: drop-shadow(0 0 36px rgba(124, 223, 143, 0.4)); animation: boot-host-float 4.2s ease-in-out infinite; user-select: none; } /* decorative frequency strip under the title */ .boot-strip { display: flex; gap: 18px; align-items: baseline; font-size: 0.7rem; letter-spacing: 0.2em; color: rgba(124, 223, 143, 0.5); border-top: 1px solid rgba(124, 223, 143, 0.18); border-bottom: 1px solid rgba(124, 223, 143, 0.18); padding: 5px 0; } .boot-strip span:nth-child(4) { color: #ff5a48; animation: boot-strip-blip 1.6s steps(1) infinite; } @keyframes boot-strip-blip { 0%, 60% { opacity: 1; } 61%, 100% { opacity: 0.2; } } @keyframes boot-host-float { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-9px); } } .boot-title { position: relative; margin: 0; font-size: clamp(1.7rem, 6.6vw, 3.5rem); font-weight: bold; letter-spacing: 0.3em; line-height: 1.05; color: #d6ffe0; text-shadow: 0 0 18px rgba(124, 223, 143, 0.8), 0 0 44px rgba(124, 223, 143, 0.45), 0 0 90px rgba(124, 223, 143, 0.25); animation: title-glitch 5s steps(1) infinite; } /* RGB split glitch flashes */ @keyframes title-glitch { 0%, 91%, 100% { text-shadow: 0 0 16px rgba(124, 223, 143, 0.7), 0 0 50px rgba(124, 223, 143, 0.3); transform: none; } 92% { text-shadow: -3px 0 #ff3b6b, 3px 0 #3bd9ff, 0 0 18px rgba(124, 223, 143, 0.8); transform: translateX(2px) skewX(2deg); } 94% { text-shadow: 3px 0 #ff3b6b, -3px 0 #3bd9ff, 0 0 18px rgba(124, 223, 143, 0.8); transform: translateX(-2px); } 96% { text-shadow: -2px 0 #ff3b6b, 2px 0 #3bd9ff, 0 0 18px rgba(124, 223, 143, 0.8); transform: skewX(-1.5deg); } } .boot-sub { margin: 0; font-size: 0.78rem; letter-spacing: 0.3em; color: var(--phosphor); opacity: 0.6; text-transform: uppercase; } .boot-langs { display: flex; gap: 10px; } .boot-langs button { font-family: inherit; font-size: 0.78rem; letter-spacing: 0.16em; padding: 8px 18px; background: rgba(4, 16, 8, 0.6); border: 1px solid rgba(124, 223, 143, 0.35); border-radius: 4px; color: rgba(124, 223, 143, 0.6); cursor: pointer; transition: all 0.18s; } .boot-langs button:hover { border-color: rgba(124, 223, 143, 0.8); color: var(--phosphor); } .boot-langs button.active { background: rgba(124, 223, 143, 0.14); border-color: var(--phosphor); color: var(--phosphor); box-shadow: 0 0 16px rgba(124, 223, 143, 0.3); } .power-btn { display: flex; align-items: center; gap: 12px; margin-top: 6px; padding: 14px 34px; font-family: inherit; font-size: 0.95rem; letter-spacing: 0.32em; text-transform: uppercase; color: #061008; background: linear-gradient(180deg, #9df2ae, #58c878); border: none; border-radius: 40px; cursor: pointer; box-shadow: 0 0 28px rgba(124, 223, 143, 0.5), 0 6px 18px rgba(0, 0, 0, 0.6), inset 0 1px 0 rgba(255, 255, 255, 0.5); animation: power-pulse 2.2s ease-in-out infinite; transition: transform 0.12s; } .power-btn:hover { transform: scale(1.05); } .power-btn:active { transform: scale(0.97); } .power-icon { font-size: 1.25rem; } @keyframes power-pulse { 0%, 100% { box-shadow: 0 0 22px rgba(124, 223, 143, 0.45), 0 6px 18px rgba(0, 0, 0, 0.6), inset 0 1px 0 rgba(255, 255, 255, 0.5); } 50% { box-shadow: 0 0 48px rgba(124, 223, 143, 0.85), 0 6px 18px rgba(0, 0, 0, 0.6), inset 0 1px 0 rgba(255, 255, 255, 0.5); } } .boot-hint { margin: 4px 0 0; font-size: 0.62rem; letter-spacing: 0.24em; color: var(--phosphor); opacity: 0.4; text-transform: uppercase; } /* CRT power-on: collapses to a bright line, then opens */ @keyframes crt-on { 0% { transform: scaleY(0.005) scaleX(0.4); filter: brightness(7) saturate(0.4); } 45% { transform: scaleY(0.005) scaleX(1.02); filter: brightness(7) saturate(0.4); } 70% { transform: scaleY(1.04) scaleX(1); filter: brightness(2.2); } 100% { transform: none; filter: none; } } .tv-screen.powering-on { animation: crt-on 1.05s cubic-bezier(0.3, 0.8, 0.3, 1) 1; } /* =================================================================== Vintage TV cabinet =================================================================== */ .tv-cabinet { position: relative; z-index: 1; width: min(1040px, 92vw); background: repeating-linear-gradient( 93deg, rgba(0, 0, 0, 0.1) 0 3px, rgba(255, 255, 255, 0.02) 3px 7px ), linear-gradient(150deg, var(--wood-light) 0%, var(--wood) 45%, var(--wood-dark) 100%); border-radius: 22px; padding: 18px 20px 12px; /* no border, no glow halo — just one soft drop shadow so the cabinet sits cleanly on the galaxy instead of inside a framed box */ box-shadow: 0 26px 64px rgba(0, 0, 0, 0.55); } /* =================================================================== The CRT screen (everything lives inside) =================================================================== */ .tv-screen { position: relative; background: radial-gradient(ellipse at 50% 38%, #0b1d10 0%, var(--screen-bg) 62%, #03080a 100%); border-radius: 34px / 30px; border: 3px solid #0a0805; overflow: hidden; box-shadow: inset 0 0 60px rgba(0, 0, 0, 0.85), inset 0 0 8px rgba(0, 0, 0, 0.9), 0 0 0 3px #11130d, 0 0 26px rgba(124, 223, 143, 0.07); min-height: 520px; } .screen-content { position: relative; z-index: 1; padding: 26px 36px 18px; display: flex; flex-direction: column; gap: 14px; height: 100%; } /* CRT layers above all content */ .noise-canvas { position: absolute; inset: 0; z-index: 6; width: 100%; height: 100%; pointer-events: none; opacity: 0; image-rendering: pixelated; } .crt-scanlines { position: absolute; inset: 0; z-index: 7; pointer-events: none; background: repeating-linear-gradient( to bottom, rgba(0, 0, 0, 0) 0px, rgba(0, 0, 0, 0) 2px, rgba(0, 0, 0, 0.18) 3px, rgba(0, 0, 0, 0) 4px ); mix-blend-mode: multiply; } .crt-vignette { position: absolute; inset: 0; z-index: 8; pointer-events: none; background: radial-gradient( ellipse at center, rgba(0, 0, 0, 0) 55%, rgba(0, 0, 0, 0.42) 100% ); } /* curved-glass shine */ .crt-glass { position: absolute; inset: 0; z-index: 9; pointer-events: none; background: radial-gradient( ellipse 120% 60% at 50% -12%, rgba(255, 255, 255, 0.07) 0%, rgba(255, 255, 255, 0) 55% ); } /* =================================================================== Header inside the screen =================================================================== */ .screen-header { text-align: center; } .screen-header h1 { margin: 0; font-size: clamp(0.95rem, 2.2vw, 1.35rem); letter-spacing: 0.5em; text-transform: uppercase; color: var(--phosphor); font-weight: normal; text-shadow: 0 0 10px rgba(124, 223, 143, 0.6); } .screen-header p { margin: 5px 0 0; font-size: 0.82rem; letter-spacing: 0.22em; color: var(--phosphor); opacity: 0.6; } /* =================================================================== Main grid: text | dial | announcer =================================================================== */ .screen-main { display: grid; grid-template-columns: 1.05fr 0.95fr 0.9fr; gap: 26px; align-items: stretch; flex: 1; } .panel { min-width: 0; } /* --- Left panel: transmission --- */ .transmission { background: rgba(2, 10, 4, 0.55); border: 1px solid rgba(124, 223, 143, 0.18); border-radius: 6px; height: 320px; overflow-y: auto; padding: 14px 16px; font-size: 1.02rem; line-height: 1.6; color: var(--phosphor-dim); word-break: break-word; scrollbar-width: thin; scrollbar-color: rgba(124, 223, 143, 0.25) transparent; text-transform: uppercase; } .transmission.active { color: var(--station-glow); text-shadow: 0 0 6px color-mix(in srgb, var(--station-glow) 45%, transparent), 0 0 18px color-mix(in srgb, var(--station-glow) 18%, transparent); } .transmission .marker { color: var(--glow); font-weight: bold; } /* teletype cursor */ .transmission.active::after { content: "▮"; margin-left: 2px; color: var(--station-glow); animation: cursor-blink 0.9s steps(1) infinite; } @keyframes cursor-blink { 0%, 60% { opacity: 1; } 61%, 100% { opacity: 0; } } /* phosphor flicker */ @keyframes crt-flicker { 0% { opacity: 1; } 50% { opacity: calc(1 - var(--flicker-amp, 0.04)); } 100% { opacity: 1; } } .transmission.active { animation: crt-flicker 0.18s steps(2) infinite; } /* [FIN DE TRANSMISION] */ .transmission.signing-off { transition: opacity 2.2s ease, filter 2.2s ease; opacity: 0.35; filter: blur(0.4px); } /* [INTERFERENCIA] */ @keyframes glitch-shake { 0% { transform: translate(0, 0); } 20% { transform: translate(-3px, 1px) skewX(-2deg); } 40% { transform: translate(2px, -1px) skewX(1.5deg); } 60% { transform: translate(-2px, 0) skewX(-1deg); } 80% { transform: translate(1px, 1px); } 100% { transform: translate(0, 0); } } .tv-screen.glitching .screen-content { animation: glitch-shake 0.12s linear 4; filter: saturate(2) contrast(1.3); } /* =================================================================== Center panel: galvanometer-style gauge =================================================================== */ .panel-center { display: flex; flex-direction: column; align-items: center; gap: 8px; } .gauge-wrap { position: relative; width: min(100%, 340px); cursor: ew-resize; touch-action: none; user-select: none; outline: none; border-radius: 14px; } .gauge-wrap:focus-visible { box-shadow: 0 0 0 2px rgba(124, 223, 143, 0.5); } .gauge-wrap:active { cursor: grabbing; } .gauge-svg { width: 100%; display: block; filter: drop-shadow(0 0 14px rgba(124, 223, 143, 0.12)); } .gauge-arc { fill: none; stroke: rgba(124, 223, 143, 0.28); stroke-width: 2; } .gauge-hub { fill: #14100b; stroke: var(--brass-dark); stroke-width: 2; } /* mandala-like ornament behind the gauge (as in the reference) */ .gauge-ornament { position: absolute; inset: -16% -8%; z-index: -1; pointer-events: none; background: radial-gradient(circle at 50% 55%, rgba(124, 223, 143, 0.12) 0%, transparent 38%), repeating-conic-gradient( from 0deg at 50% 55%, rgba(124, 223, 143, 0.07) 0deg 6deg, transparent 6deg 30deg ); border-radius: 50%; mask-image: radial-gradient(circle at 50% 55%, black 0%, transparent 68%); } .dial-tick { stroke: rgba(124, 223, 143, 0.65); stroke-width: 1.2; } .dial-tick-major { stroke: var(--phosphor); stroke-width: 2.4; filter: drop-shadow(0 0 2px rgba(124, 223, 143, 0.5)); } .dial-label { fill: rgba(160, 240, 175, 0.95); font-size: 11.5px; font-weight: bold; text-anchor: middle; } /* hidden band 108-112 */ .dial-tick-hidden { stroke: #58ff8f; opacity: 0.75; filter: drop-shadow(0 0 2px #58ff8f); } .dial-label-hidden { fill: #58ff8f; opacity: 0.85; } .dial-needle { stroke: #ff4a3a; stroke-width: 2.4; stroke-linecap: round; filter: drop-shadow(0 0 5px rgba(255, 74, 58, 0.7)); transition: stroke 0.2s; } .dial-needle.locked { stroke: var(--station-glow); filter: drop-shadow(0 0 7px var(--station-glow)); } .freq-display { font-size: 2.6rem; color: #ff5a48; text-shadow: 0 0 14px rgba(255, 90, 72, 0.55); letter-spacing: 0.14em; font-variant-numeric: tabular-nums; } .freq-display.locked { color: var(--station-glow); text-shadow: 0 0 16px var(--station-glow); } @keyframes lock-settle { 0% { transform: scale(1.06); filter: brightness(1.7); } 100% { transform: scale(1); filter: brightness(1); } } .freq-display.just-locked { animation: lock-settle 0.45s cubic-bezier(0.22, 1.4, 0.36, 1); } .meters { display: flex; align-items: center; gap: 16px; } .vu-meter { width: 160px; height: 14px; background: rgba(0, 0, 0, 0.55); border: 1px solid rgba(124, 223, 143, 0.25); border-radius: 2px; overflow: hidden; } .vu-bar { height: 100%; width: 0%; background: linear-gradient(90deg, #1d4d22, var(--phosphor), #ffd24a); transition: width 0.1s; } .tuning-lamp { width: 18px; height: 18px; border-radius: 50%; background: #20140a; border: 2px solid #3a2410; box-shadow: inset 0 0 4px rgba(0, 0, 0, 0.8); } .tuning-lamp.on { background: var(--glow); border-color: #ff9944; box-shadow: 0 0 12px var(--glow), inset 0 0 4px #fff8; } .tuning-lamp.locked { background: var(--station-glow); border-color: #5a9a20; box-shadow: 0 0 12px var(--station-glow); } @keyframes lamp-pulse { 0%, 100% { box-shadow: 0 0 12px var(--station-glow); } 50% { box-shadow: 0 0 26px var(--station-glow), 0 0 40px var(--station-glow); } } .tuning-lamp.jingle { animation: lamp-pulse 0.3s ease-in-out 3; } .station-name { font-size: 1.05rem; letter-spacing: 0.14em; text-transform: uppercase; color: var(--station-glow); text-shadow: 0 0 10px color-mix(in srgb, var(--station-glow) 60%, transparent), 0 0 26px color-mix(in srgb, var(--station-glow) 25%, transparent); text-align: center; min-height: 1.3em; opacity: 1; } /* =================================================================== Right panel: the on-screen announcer =================================================================== */ .panel-right { display: flex; flex-direction: column; align-items: center; gap: 10px; } .announcer-frame { position: relative; width: 100%; max-width: 320px; aspect-ratio: 4 / 3; border-radius: 10px; overflow: hidden; background: radial-gradient(ellipse at center, rgba(124, 223, 143, 0.06), transparent 75%); } .announcer-img { width: 100%; height: 100%; object-fit: cover; display: block; opacity: 0; transform-origin: 50% 85%; transition: opacity 0.35s ease; mix-blend-mode: screen; /* the portrait's black background melts into the screen */ filter: drop-shadow(0 0 18px rgba(124, 223, 143, 0.25)); } .announcer-frame.visible .announcer-img { opacity: 1; } /* idle breathing */ @keyframes announcer-idle { 0%, 100% { transform: translateY(0) scale(1); } 50% { transform: translateY(-2px) scale(1.006); } } .announcer-frame.visible .announcer-img { animation: announcer-idle 3.4s ease-in-out infinite; } /* talking: quick bobbing synced with the voice blips */ @keyframes announcer-talk { 0% { transform: translateY(0) scale(1); } 30% { transform: translateY(-1.5px) scale(1.015, 0.99) rotate(-0.4deg); } 60% { transform: translateY(0.5px) scale(0.995, 1.01) rotate(0.3deg); } 100% { transform: translateY(0) scale(1); } } .announcer-frame.talking .announcer-img { animation: announcer-talk 0.24s ease-in-out infinite; } /* announcer swap: glitch sweep */ @keyframes announcer-swap { 0% { filter: brightness(3) saturate(0); transform: translateX(-3px) skewX(3deg); opacity: 0.2; } 40% { filter: brightness(1.6); transform: translateX(2px) skewX(-2deg); opacity: 0.7; } 100% { filter: brightness(1); transform: none; opacity: 1; } } .announcer-frame.swapping .announcer-img { animation: announcer-swap 0.5s steps(5) 1; } /* no signal: noise silhouette */ .announcer-nosignal { position: absolute; inset: 12%; border-radius: 50%; background: radial-gradient(ellipse at 50% 38%, rgba(124, 223, 143, 0.18) 0%, transparent 55%), radial-gradient(ellipse at 50% 95%, rgba(124, 223, 143, 0.12) 0%, transparent 50%); filter: blur(6px); opacity: 0.6; transition: opacity 0.4s; } .announcer-frame.visible .announcer-nosignal { opacity: 0; } /* speech bubble */ .speech-bubble { position: absolute; top: 8%; left: 4%; display: flex; gap: 5px; padding: 7px 11px; border: 1px solid rgba(124, 223, 143, 0.55); border-radius: 12px 12px 12px 2px; background: rgba(4, 16, 8, 0.7); opacity: 0; transition: opacity 0.25s; } .speech-bubble span { width: 5px; height: 5px; border-radius: 50%; background: var(--phosphor); box-shadow: 0 0 6px var(--phosphor); animation: bubble-dot 1s ease-in-out infinite; } .speech-bubble span:nth-child(2) { animation-delay: 0.18s; } .speech-bubble span:nth-child(3) { animation-delay: 0.36s; } @keyframes bubble-dot { 0%, 100% { opacity: 0.25; transform: translateY(0); } 40% { opacity: 1; transform: translateY(-2.5px); } } .announcer-frame.talking .speech-bubble { opacity: 1; } /* voice bars next to the announcer */ .talk-bars { display: flex; align-items: flex-end; gap: 4px; height: 30px; } .talk-bars i { width: 5px; height: 4px; border-radius: 2px; background: var(--station-glow); box-shadow: 0 0 6px color-mix(in srgb, var(--station-glow) 60%, transparent); transition: height 0.3s; } @keyframes talk-bar { 0%, 100% { height: 4px; } 50% { height: var(--bar-max, 26px); } } .talk-bars.talking i { animation: talk-bar 0.5s ease-in-out infinite; } .talk-bars.talking i:nth-child(1) { --bar-max: 12px; animation-delay: 0s; } .talk-bars.talking i:nth-child(2) { --bar-max: 20px; animation-delay: 0.07s; } .talk-bars.talking i:nth-child(3) { --bar-max: 28px; animation-delay: 0.14s; } .talk-bars.talking i:nth-child(4) { --bar-max: 16px; animation-delay: 0.21s; } .talk-bars.talking i:nth-child(5) { --bar-max: 30px; animation-delay: 0.05s; } .talk-bars.talking i:nth-child(6) { --bar-max: 18px; animation-delay: 0.18s; } .talk-bars.talking i:nth-child(7) { --bar-max: 26px; animation-delay: 0.11s; } .talk-bars.talking i:nth-child(8) { --bar-max: 14px; animation-delay: 0.25s; } .talk-bars.talking i:nth-child(9) { --bar-max: 22px; animation-delay: 0.02s; } /* =================================================================== Bottom oscilloscope (full width) =================================================================== */ .scope { width: 100%; height: 72px; background: rgba(2, 8, 4, 0.6); border: 1px solid rgba(124, 223, 143, 0.18); border-radius: 6px; background-image: repeating-linear-gradient(to right, rgba(124, 223, 143, 0.07) 0 1px, transparent 1px 28px), repeating-linear-gradient(to bottom, rgba(124, 223, 143, 0.07) 0 1px, transparent 1px 16px); } .hint { text-align: center; margin: 2px 0 0; font-size: 0.88rem; color: var(--phosphor); opacity: 0.7; letter-spacing: 0.16em; min-height: 1.1em; } /* =================================================================== Encrypted console =================================================================== */ .console-wrap { margin-top: 10px; background: rgba(2, 8, 4, 0.75); border: 1px solid #1f3a1f; border-radius: 6px; padding: 10px; font-size: 0.88rem; box-shadow: inset 0 0 16px rgba(0, 0, 0, 0.7), 0 0 10px rgba(60, 255, 120, 0.06); } .console-wrap.hidden { display: none; } .console-log { max-height: 130px; overflow-y: auto; color: #58c878; white-space: pre-wrap; word-break: break-word; margin-bottom: 6px; } .console-log .op { color: #8fff9f; text-shadow: 0 0 6px rgba(110, 255, 140, 0.4); } .console-log .you { color: #4a7a55; } .console-input-row { display: flex; align-items: center; gap: 6px; } .console-prompt { color: #8fff9f; } .console-input { flex: 1; background: transparent; border: none; outline: none; color: #b8ffc8; font-family: inherit; font-size: inherit; caret-color: #8fff9f; } /* =================================================================== Wooden bezel: physical switches =================================================================== */ .bezel { display: grid; grid-template-columns: auto 1fr auto; align-items: center; gap: 22px; padding: 18px 14px 8px; margin-top: 6px; border-top: 2px solid rgba(0, 0, 0, 0.35); box-shadow: inset 0 2px 0 rgba(255, 255, 255, 0.05); } .bezel-side { display: flex; align-items: center; gap: 20px; } .bezel-left { flex-direction: column; gap: 8px; } .bezel-right { justify-content: flex-end; } .bezel-mid { display: flex; align-items: center; gap: 16px; } .bezel-group { display: flex; flex-direction: column; align-items: center; gap: 6px; } .bezel-label { font-size: 0.72rem; letter-spacing: 0.28em; color: #d9b886; text-shadow: 0 1px 0 rgba(0, 0, 0, 0.6); } /* language selector: three positions */ .lang-switch { display: flex; gap: 4px; background: #1c120a; border-radius: 14px; padding: 3px; border: 1px solid #0e0905; box-shadow: inset 0 2px 6px rgba(0, 0, 0, 0.8); } .lang-switch button { font-family: inherit; font-size: 0.74rem; letter-spacing: 0.1em; padding: 6px 13px; border-radius: 10px; border: 1px solid transparent; background: transparent; color: #8a6f4a; cursor: pointer; transition: all 0.15s; } .lang-switch button:hover { color: #d9b886; } .lang-switch button.active { background: linear-gradient(180deg, #6d4f2e, #4a3119); border-color: #2a1b0d; color: #ffe9bd; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.6), inset 0 1px 0 rgba(255, 255, 255, 0.2); } /* decorative speaker grill */ .speaker-grill { flex: 1; height: 26px; border-radius: 6px; background: repeating-linear-gradient( 90deg, #1d130b 0 4px, #31210f 4px 8px ); box-shadow: inset 0 2px 5px rgba(0, 0, 0, 0.7); opacity: 0.85; } /* help / host-assistant button: replays the host's guidance */ .help-wrap { display: flex; flex-direction: column; align-items: center; gap: 6px; } .guide-btn { position: relative; width: 52px; height: 52px; border-radius: 50%; border: 2px solid #2a1b0d; background: radial-gradient(circle at 35% 28%, #8a6a3e, #5a3d18 55%, #38260f 100%); cursor: pointer; box-shadow: 0 4px 9px rgba(0, 0, 0, 0.65), inset 0 1px 0 rgba(255, 255, 255, 0.3), inset 0 -3px 6px rgba(0, 0, 0, 0.5); transition: transform 0.1s, filter 0.15s; } .guide-btn .guide-q { font-family: inherit; font-size: 1.5rem; font-weight: bold; color: #ffe9bd; text-shadow: 0 1px 2px rgba(0, 0, 0, 0.7); } .guide-btn::after { /* soft pulsing ring so newcomers notice the help affordance */ content: ""; position: absolute; inset: -5px; border-radius: 50%; border: 1.5px solid rgba(124, 223, 143, 0.5); animation: help-ring 2.6s ease-in-out infinite; pointer-events: none; } @keyframes help-ring { 0%, 100% { opacity: 0.15; transform: scale(0.96); } 50% { opacity: 0.7; transform: scale(1.06); } } .guide-btn:hover { filter: brightness(1.15); } .guide-btn:active { transform: translateY(1px); } .help-label { font-size: 0.6rem; } /* tuning knob: large brass control, ridged skirt, rotating face */ .knob-housing { display: grid; place-items: center; width: 156px; height: 156px; border-radius: 50%; background: radial-gradient(circle at 50% 40%, #2c1d10 0%, #190f08 70%), var(--wood-dark); border: 2px solid #0c0704; box-shadow: inset 0 4px 14px rgba(0, 0, 0, 0.85), inset 0 -2px 4px rgba(255, 255, 255, 0.04), 0 2px 4px rgba(255, 255, 255, 0.05); } .tune-knob { position: relative; width: 122px; height: 122px; border-radius: 50%; cursor: grab; touch-action: none; user-select: none; outline: none; background: radial-gradient(circle at 50% 50%, #14100b 58%, transparent 59%), repeating-conic-gradient(#0c0805 0deg 5deg, #4a371d 5deg 10deg); border: 2px solid #0e0905; box-shadow: 0 8px 18px rgba(0, 0, 0, 0.75), inset 0 1px 0 rgba(255, 255, 255, 0.14); } .tune-knob:active { cursor: grabbing; } .tune-knob:focus-visible { box-shadow: 0 0 0 3px rgba(124, 223, 143, 0.5), 0 8px 18px rgba(0, 0, 0, 0.75); } .knob-skirt { position: absolute; inset: 6px; border-radius: 50%; background: radial-gradient(circle at 38% 30%, #6e5230, #2e1f10 70%); box-shadow: inset 0 -3px 8px rgba(0, 0, 0, 0.6); } .knob-face { position: absolute; inset: 18px; border-radius: 50%; background: radial-gradient(circle at 36% 26%, #b08a52, #6a4920 52%, #2a1b0d 100%); box-shadow: 0 4px 10px rgba(0, 0, 0, 0.65), inset 0 1px 0 rgba(255, 255, 255, 0.4), inset 0 -4px 8px rgba(0, 0, 0, 0.55); will-change: transform; } /* a subtle finger-grip dimple opposite the marker */ .knob-grip { position: absolute; bottom: 14%; left: 50%; width: 14px; height: 14px; margin-left: -7px; border-radius: 50%; background: radial-gradient(circle at 40% 35%, rgba(0, 0, 0, 0.55), rgba(0, 0, 0, 0.1)); box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.7); } .knob-marker { position: absolute; top: 7px; left: 50%; width: 6px; height: 24px; margin-left: -3px; border-radius: 3px; background: linear-gradient(180deg, #ff7a5a, #ff3a28); box-shadow: 0 0 9px rgba(255, 90, 72, 0.9); } .knob-label { font-size: 0.8rem; letter-spacing: 0.32em; color: #ecc794; } /* static switch: ON/OFF lever */ .static-toggle { position: relative; width: 46px; height: 64px; border-radius: 10px; border: 2px solid #0e0905; background: linear-gradient(180deg, #241709, #18100a); cursor: pointer; box-shadow: inset 0 2px 8px rgba(0, 0, 0, 0.8); padding: 0; } .static-toggle .lever { position: absolute; left: 50%; transform: translateX(-50%); width: 12px; height: 26px; border-radius: 6px; background: linear-gradient(180deg, #d9b886, #8a6536); box-shadow: 0 2px 5px rgba(0, 0, 0, 0.7); transition: top 0.16s cubic-bezier(0.5, 1.6, 0.4, 1); top: 6px; } .static-toggle:not(.on) .lever { top: 32px; } .static-toggle .state-on, .static-toggle .state-off { position: absolute; right: -26px; font-size: 0.55rem; letter-spacing: 0.12em; color: #6a5232; } .static-toggle .state-on { top: 8px; } .static-toggle .state-off { bottom: 8px; } .static-toggle.on .state-on { color: #ffd98c; text-shadow: 0 0 6px rgba(255, 217, 140, 0.6); } .static-toggle:not(.on) .state-off { color: #ffd98c; text-shadow: 0 0 6px rgba(255, 217, 140, 0.6); } /* =================================================================== Band expansion =================================================================== */ @keyframes band-expand { 0% { filter: brightness(2.2) saturate(0); transform: scale(0.96); } 60% { filter: brightness(1.4); transform: scale(1.015); } 100% { filter: brightness(1); transform: scale(1); } } .gauge-svg.expanding { animation: band-expand 1.6s ease-out; } /* =================================================================== Boot mission briefing (what the listener has to do) =================================================================== */ .boot-mission { display: flex; flex-direction: column; gap: 9px; width: min(440px, 88vw); margin: 4px 0 2px; } .mission-step { display: flex; align-items: center; gap: 12px; text-align: left; font-size: 0.84rem; line-height: 1.35; letter-spacing: 0.03em; color: rgba(206, 240, 214, 0.85); } .mission-num { flex: 0 0 auto; width: 26px; height: 26px; display: grid; place-items: center; border-radius: 50%; border: 1px solid rgba(124, 223, 143, 0.55); color: var(--phosphor); font-size: 0.78rem; box-shadow: inset 0 0 10px rgba(124, 223, 143, 0.2), 0 0 10px rgba(124, 223, 143, 0.12); } .boot-tip { max-width: min(450px, 88vw); margin: 4px 0 0; padding: 9px 14px; font-size: 0.76rem; line-height: 1.5; letter-spacing: 0.02em; text-align: left; color: rgba(255, 222, 150, 0.9); border: 1px solid rgba(255, 210, 124, 0.35); border-radius: 8px; background: rgba(46, 33, 12, 0.35); } /* =================================================================== Operator intercept: the warden warns you off the number station =================================================================== */ .intercept { position: absolute; z-index: 12; left: 50%; bottom: 9%; transform: translate(-50%, 22px); display: flex; align-items: center; gap: 14px; max-width: min(78%, 540px); padding: 12px 18px; border: 1px solid rgba(120, 255, 150, 0.45); border-radius: 12px; background: rgba(2, 12, 6, 0.84); box-shadow: 0 0 34px rgba(60, 255, 120, 0.22), inset 0 0 22px rgba(0, 0, 0, 0.6); opacity: 0; pointer-events: none; transition: opacity 0.28s ease, transform 0.28s ease, border-color 0.28s; } .intercept.active { opacity: calc(0.45 + 0.55 * var(--prox, 0.5)); transform: translate(-50%, 0); } .intercept-frame { flex: 0 0 auto; width: 58px; height: 58px; border-radius: 8px; overflow: hidden; border: 1px solid rgba(120, 255, 150, 0.4); background: radial-gradient(circle, rgba(60, 255, 120, 0.12), transparent 75%); } .intercept-img { width: 100%; height: 100%; object-fit: cover; mix-blend-mode: screen; filter: contrast(1.1) brightness(1.05); } .intercept-text { color: #9effb0; font-size: 0.95rem; line-height: 1.35; letter-spacing: 0.03em; text-shadow: 0 0 8px rgba(60, 255, 120, 0.45); } @keyframes intercept-jitter { 0%, 100% { transform: translate(-50%, 0); } 25% { transform: translate(calc(-50% - 2px), 1px); } 50% { transform: translate(calc(-50% + 2px), -1px); } 75% { transform: translate(calc(-50% - 1px), 0); } } .intercept.urgent { border-color: #ff5a48; box-shadow: 0 0 40px rgba(255, 90, 72, 0.4), inset 0 0 22px rgba(0, 0, 0, 0.6); animation: intercept-jitter 0.22s linear infinite; } .intercept.urgent .intercept-text { color: #ff8c7a; text-shadow: 0 0 9px rgba(255, 90, 72, 0.6); } /* =================================================================== Field notebook (side drawer): log frequencies, the cipher, fragments =================================================================== */ .notes-tab { position: fixed; top: 50%; right: 0; transform: translateY(-50%); z-index: 40; display: flex; align-items: center; gap: 10px; padding: 22px 13px; border: 1.5px solid rgba(124, 223, 143, 0.65); border-right: none; border-radius: 14px 0 0 14px; background: linear-gradient(180deg, rgba(18, 38, 22, 0.96), rgba(8, 18, 10, 0.96)); color: var(--phosphor); font-family: inherit; font-size: 0.82rem; font-weight: bold; letter-spacing: 0.26em; cursor: pointer; writing-mode: vertical-rl; text-shadow: 0 0 9px rgba(124, 223, 143, 0.55); box-shadow: -6px 0 22px rgba(124, 223, 143, 0.22); animation: notes-tab-pulse 2.4s ease-in-out infinite; transition: padding-right 0.2s, background 0.2s, box-shadow 0.2s; } @keyframes notes-tab-pulse { 0%, 100% { box-shadow: -6px 0 16px rgba(124, 223, 143, 0.18); border-color: rgba(124, 223, 143, 0.5); } 50% { box-shadow: -8px 0 34px rgba(124, 223, 143, 0.5); border-color: rgba(124, 223, 143, 0.95); } } .notes-tab:hover { padding-right: 20px; background: linear-gradient(180deg, rgba(26, 52, 31, 1), rgba(12, 26, 15, 1)); box-shadow: -8px 0 34px rgba(124, 223, 143, 0.5); } .notes-tab-icon { writing-mode: horizontal-tb; font-size: 1.2rem; } .notes-tab.hidden { display: none; } .notes-panel { position: fixed; top: 0; right: 0; height: 100vh; width: min(330px, 88vw); z-index: 46; transform: translateX(100%); transition: transform 0.32s cubic-bezier(0.4, 0.9, 0.3, 1); background: linear-gradient(180deg, #15120b 0%, #0b0a06 100%); border-left: 1px solid rgba(124, 223, 143, 0.25); box-shadow: -14px 0 44px rgba(0, 0, 0, 0.6); display: flex; flex-direction: column; gap: 14px; padding: 16px 16px 22px; color: var(--phosphor); } .notes-panel.open { transform: translateX(0); } .notes-head { display: flex; align-items: center; justify-content: space-between; font-size: 0.9rem; letter-spacing: 0.28em; color: #ecc794; border-bottom: 1px solid rgba(124, 223, 143, 0.2); padding-bottom: 10px; } .notes-close { background: none; border: none; color: #d9b886; font-size: 1.4rem; line-height: 1; cursor: pointer; padding: 0 4px; } .notes-close:hover { color: #fff; } .notes-section { display: flex; flex-direction: column; gap: 7px; } .notes-grow { flex: 1; min-height: 0; } .notes-label { font-size: 0.66rem; letter-spacing: 0.24em; color: rgba(124, 223, 143, 0.65); } .notes-list { list-style: none; margin: 0; padding: 0; max-height: 30vh; overflow-y: auto; display: flex; flex-direction: column; gap: 4px; scrollbar-width: thin; scrollbar-color: rgba(124, 223, 143, 0.25) transparent; } .notes-list li { display: flex; gap: 8px; font-size: 0.8rem; color: rgba(206, 240, 214, 0.9); padding: 4px 8px; border-radius: 5px; background: rgba(124, 223, 143, 0.05); border-left: 2px solid rgba(124, 223, 143, 0.4); } .notes-list li .nf-freq { color: #ffd27c; font-variant-numeric: tabular-nums; flex: 0 0 auto; } .notes-list li.nf-fragment { border-left-color: #d8fffb; } .notes-list li.nf-cipher { border-left-color: #58ff8f; } .notes-list .nf-empty { border: none; background: none; opacity: 0.45; font-style: italic; } .notes-cipher { font-size: 0.92rem; letter-spacing: 0.08em; color: #b8ffc8; background: rgba(2, 12, 6, 0.7); border: 1px solid rgba(88, 255, 143, 0.25); border-radius: 6px; padding: 8px 10px; white-space: pre-line; min-height: 1.4em; } .notes-cipher .nc-code { color: #ffd27c; text-shadow: 0 0 8px rgba(255, 210, 124, 0.4); } .notes-scratch { flex: 1; min-height: 90px; resize: none; background: rgba(2, 12, 6, 0.6); border: 1px solid rgba(124, 223, 143, 0.2); border-radius: 6px; padding: 10px; color: #cdeede; font-family: inherit; font-size: 0.86rem; line-height: 1.5; outline: none; } .notes-scratch:focus { border-color: rgba(124, 223, 143, 0.5); } /* a freshly-logged row flashes */ @keyframes note-flash { 0% { background: rgba(124, 223, 143, 0.4); } 100% { background: rgba(124, 223, 143, 0.05); } } .notes-list li.just-added { animation: note-flash 1.1s ease-out; } /* =================================================================== Endgame mission HUD (fragment hunt in the secret band) =================================================================== */ .mission-hud { display: flex; flex-direction: column; gap: 7px; width: 100%; max-width: 620px; margin: 0 auto; padding: 9px 16px; border: 1px solid rgba(255, 246, 216, 0.4); border-radius: 9px; background: rgba(8, 14, 6, 0.72); box-shadow: 0 0 26px rgba(255, 246, 216, 0.12), inset 0 0 18px rgba(0, 0, 0, 0.5); animation: mission-glow 2.6s ease-in-out infinite; } .mission-hud.hidden { display: none; } @keyframes mission-glow { 0%, 100% { box-shadow: 0 0 18px rgba(255, 246, 216, 0.1), inset 0 0 18px rgba(0, 0, 0, 0.5); } 50% { box-shadow: 0 0 34px rgba(255, 246, 216, 0.22), inset 0 0 18px rgba(0, 0, 0, 0.5); } } .mission-hud-text { font-size: 0.82rem; letter-spacing: 0.08em; text-align: center; color: #fff6d8; text-shadow: 0 0 10px rgba(255, 246, 216, 0.4); } .mission-hud-track { height: 9px; border-radius: 5px; background: rgba(0, 0, 0, 0.55); border: 1px solid rgba(255, 246, 216, 0.2); overflow: hidden; } .mission-hud-fill { height: 100%; width: 0%; background: linear-gradient(90deg, #8a7a3a, #fff6d8); box-shadow: 0 0 10px rgba(255, 246, 216, 0.6); transition: width 0.12s linear; } .mission-hud-pips { display: flex; justify-content: center; gap: 9px; } .mission-hud-pips span { width: 11px; height: 11px; border-radius: 50%; border: 1px solid rgba(255, 246, 216, 0.45); background: rgba(255, 246, 216, 0.06); transition: background 0.25s, box-shadow 0.25s; } .mission-hud-pips span.on { background: #fff6d8; border-color: #fff6d8; box-shadow: 0 0 10px rgba(255, 246, 216, 0.8); } /* =================================================================== Endgame answer bar (the operator speaks on screen; you type here) =================================================================== */ .endgame-bar { display: flex; align-items: center; gap: 10px; width: 100%; max-width: 640px; margin: 6px auto 0; padding: 12px 18px; border: 1px solid rgba(88, 255, 143, 0.5); border-radius: 10px; background: rgba(2, 12, 6, 0.82); box-shadow: 0 0 26px rgba(88, 255, 143, 0.18), inset 0 0 16px rgba(0, 0, 0, 0.6); animation: endgame-pulse 2.2s ease-in-out infinite; } .endgame-bar.hidden { display: none; } @keyframes endgame-pulse { 0%, 100% { box-shadow: 0 0 16px rgba(88, 255, 143, 0.12), inset 0 0 16px rgba(0, 0, 0, 0.6); } 50% { box-shadow: 0 0 34px rgba(88, 255, 143, 0.32), inset 0 0 16px rgba(0, 0, 0, 0.6); } } .endgame-caret { color: #8fff9f; font-size: 1.25rem; text-shadow: 0 0 8px rgba(110, 255, 140, 0.5); } .endgame-input { flex: 1; min-width: 0; background: transparent; border: none; outline: none; color: #c8ffd6; font-family: inherit; font-size: 1.05rem; letter-spacing: 0.04em; caret-color: #8fff9f; } .endgame-input::placeholder { color: rgba(120, 200, 140, 0.4); } /* =================================================================== Responsive =================================================================== */ @media (max-width: 860px) { .screen-main { grid-template-columns: 1fr 1fr; } .panel-left { grid-column: 1 / -1; order: 2; } .panel-center { order: 1; } .panel-right { order: 1; } .transmission { height: 220px; } .tv-screen { min-height: 0; } .knob-housing { width: 124px; height: 124px; } .tune-knob { width: 96px; height: 96px; } .knob-face { inset: 14px; } } @media (max-width: 560px) { body { padding: 0.4rem; } .tv-cabinet { padding: 12px 10px 8px; border-radius: 18px; } .screen-content { padding: 14px 12px 12px; } .screen-main { grid-template-columns: 1fr; } .panel-right { order: 0; } .announcer-frame { max-width: 200px; } .screen-header h1 { letter-spacing: 0.3em; } .static-toggle .state-on, .static-toggle .state-off { display: none; } .bezel { grid-template-columns: 1fr; justify-items: center; gap: 14px; } .bezel-mid { order: 3; } .bezel-right { order: 2; justify-content: center; gap: 24px; } .speaker-grill { display: none; } .knob-housing { width: 112px; height: 112px; } .tune-knob { width: 86px; height: 86px; } .knob-face { inset: 12px; } .knob-marker { height: 18px; top: 5px; } } /* =================================================================== Accessibility / degradation =================================================================== */ @media (prefers-reduced-motion: reduce) { .transmission.active, .tuning-lamp.jingle, .tv-screen.glitching .screen-content, .freq-display.just-locked, .gauge-svg.expanding, .announcer-frame.visible .announcer-img, .announcer-frame.talking .announcer-img, .announcer-frame.swapping .announcer-img, .talk-bars.talking i, .speech-bubble span, .boot-host, .boot-title, .power-btn, .portal-ring-1, .portal-ring-2, .portal-ring-3, .portal-sweep, .boot-strip span, .nebula-a, .nebula-b, .tv-screen.powering-on { animation: none; } .guide-btn::after, .intercept.urgent, .notes-list li.just-added, .mission-hud, .notes-tab, .endgame-bar { animation: none; } .noise-canvas, .galaxy { display: none; } }