lumen-harbor / src /styles.css
Mike0021's picture
Tune cinematic lighting and polish live interactions
01d1697 verified
Raw History Blame Contribute Delete
16.8 kB
:root {
color-scheme: dark;
font-family: Inter, ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
font-synthesis: none;
text-rendering: optimizeLegibility;
--ink: #f2f5f7;
--muted: rgba(227, 235, 240, 0.58);
--line: rgba(232, 240, 245, 0.16);
--glass: rgba(12, 18, 26, 0.54);
--accent: #a9d4ff;
}
* {
box-sizing: border-box;
}
html,
body,
#app,
#scene {
width: 100%;
height: 100%;
margin: 0;
overflow: hidden;
}
body {
background: #0b1018;
color: var(--ink);
overscroll-behavior: none;
}
button,
a {
color: inherit;
font: inherit;
}
button {
border: 0;
}
button:focus-visible,
a:focus-visible {
outline: 2px solid #c4e5ff;
outline-offset: 4px;
}
#scene,
#scene canvas {
display: block;
touch-action: none;
}
#scene canvas {
width: 100%;
height: 100%;
cursor: grab;
}
#scene canvas:active {
cursor: grabbing;
}
.interface {
position: fixed;
inset: 0;
z-index: 3;
pointer-events: none;
opacity: 0;
transition: opacity 1.1s ease;
}
.interface.is-ready {
opacity: 1;
}
.topbar {
position: absolute;
top: max(24px, env(safe-area-inset-top));
left: max(30px, env(safe-area-inset-left));
right: max(30px, env(safe-area-inset-right));
display: flex;
align-items: center;
justify-content: space-between;
}
.brand {
display: flex;
gap: 13px;
align-items: center;
color: var(--ink);
text-decoration: none;
pointer-events: auto;
}
.brand__glyph {
display: grid;
width: 38px;
height: 38px;
place-items: center;
border: 1px solid rgba(255, 255, 255, 0.38);
border-radius: 50%;
font-size: 9px;
font-weight: 700;
letter-spacing: 0.12em;
}
.brand b,
.brand small {
display: block;
}
.brand b {
font-size: 12px;
font-weight: 650;
letter-spacing: 0.11em;
text-transform: uppercase;
}
.brand small {
margin-top: 3px;
color: var(--muted);
font-size: 9px;
font-weight: 500;
letter-spacing: 0.14em;
text-transform: uppercase;
}
.conditions {
display: flex;
align-items: center;
gap: 10px;
padding: 10px 13px;
border: 1px solid var(--line);
border-radius: 999px;
background: rgba(9, 14, 21, 0.3);
box-shadow: inset 0 1px rgba(255, 255, 255, 0.05);
backdrop-filter: blur(16px);
color: rgba(239, 244, 247, 0.78);
font-size: 9px;
font-weight: 600;
letter-spacing: 0.12em;
}
.conditions i {
width: 1px;
height: 10px;
background: var(--line);
}
.conditions__pulse {
width: 5px;
height: 5px;
border-radius: 50%;
background: #a5dcff;
box-shadow: 0 0 12px #88ceff;
}
.intro {
position: absolute;
bottom: max(115px, calc(env(safe-area-inset-bottom) + 105px));
left: max(42px, env(safe-area-inset-left));
width: min(390px, calc(100vw - 84px));
isolation: isolate;
transition: opacity 0.6s ease, transform 0.8s cubic-bezier(0.2, 0.75, 0.2, 1);
}
.intro::before {
position: absolute;
inset: -38px -70px -34px -46px;
z-index: -1;
background: radial-gradient(ellipse at 28% 55%, rgba(5, 10, 16, 0.64) 0%, rgba(5, 10, 16, 0.33) 45%, transparent 74%);
content: "";
filter: blur(10px);
pointer-events: none;
}
.intro.is-hidden {
opacity: 0;
transform: translateY(12px);
}
.eyebrow {
display: block;
color: rgba(221, 233, 240, 0.56);
font-size: 9px;
font-weight: 650;
letter-spacing: 0.2em;
text-transform: uppercase;
}
.intro h2 {
margin: 13px 0 14px;
font-size: clamp(42px, 5.5vw, 78px);
font-weight: 420;
letter-spacing: -0.065em;
line-height: 0.88;
text-shadow: 0 2px 26px rgba(0, 0, 0, 0.22);
}
.intro h2 em {
color: #b9dfff;
font-family: Georgia, "Times New Roman", serif;
font-weight: 400;
letter-spacing: -0.035em;
}
.intro p {
width: min(360px, 100%);
margin: 0 0 22px;
color: rgba(235, 240, 244, 0.68);
font-size: 12px;
line-height: 1.65;
}
.text-button {
display: inline-flex;
align-items: center;
gap: 16px;
padding: 0 0 8px;
border-bottom: 1px solid rgba(255, 255, 255, 0.4);
background: transparent;
cursor: pointer;
pointer-events: auto;
font-size: 10px;
font-weight: 650;
letter-spacing: 0.13em;
text-transform: uppercase;
}
.text-button i {
font-size: 13px;
font-style: normal;
transition: transform 0.25s ease;
}
.text-button:hover i {
transform: translate(3px, -3px);
}
.metrics {
position: absolute;
right: max(32px, env(safe-area-inset-right));
bottom: max(114px, calc(env(safe-area-inset-bottom) + 104px));
display: flex;
gap: 30px;
padding-left: 22px;
border-left: 1px solid var(--line);
}
.metrics div {
display: flex;
flex-direction: column;
gap: 4px;
}
.metrics b {
font-size: 15px;
font-weight: 450;
letter-spacing: -0.02em;
}
.metrics span {
color: var(--muted);
font-size: 8px;
font-weight: 600;
letter-spacing: 0.14em;
text-transform: uppercase;
}
.dock {
position: absolute;
bottom: max(24px, env(safe-area-inset-bottom));
left: 50%;
display: flex;
height: 64px;
align-items: center;
gap: 18px;
padding: 0 12px 0 19px;
transform: translateX(-50%);
border: 1px solid rgba(235, 243, 248, 0.17);
border-radius: 17px;
background: rgba(10, 16, 23, 0.62);
box-shadow: 0 14px 44px rgba(0, 0, 0, 0.28), inset 0 1px rgba(255, 255, 255, 0.06);
backdrop-filter: blur(20px) saturate(120%);
pointer-events: auto;
}
.dock__group {
display: flex;
align-items: center;
}
.dock__group > span {
margin-right: 12px;
color: rgba(229, 237, 242, 0.38);
font-size: 8px;
font-weight: 650;
letter-spacing: 0.15em;
text-transform: uppercase;
}
.dock__views {
gap: 3px;
}
.dock__views button {
padding: 8px 10px;
border-radius: 8px;
background: transparent;
color: rgba(235, 241, 244, 0.52);
cursor: pointer;
font-size: 9px;
font-weight: 600;
letter-spacing: 0.035em;
transition: color 0.2s, background 0.2s;
}
.dock__views button:hover,
.dock__views button.is-active {
background: rgba(255, 255, 255, 0.08);
color: #fff;
}
.dock__divider {
width: 1px;
height: 25px;
background: var(--line);
}
.dock__time {
min-width: 153px;
}
.dock__time > b {
width: 34px;
margin-left: 9px;
color: rgba(238, 244, 247, 0.72);
font-size: 9px;
font-weight: 550;
}
.time-dots {
position: relative;
display: flex;
align-items: center;
gap: 0;
}
.time-dots::before {
position: absolute;
top: 50%;
right: 15px;
left: 15px;
z-index: -1;
height: 1px;
background: rgba(255, 255, 255, 0.14);
content: "";
}
.time-dots button {
position: relative;
width: 30px;
height: 44px;
padding: 0;
background: transparent;
cursor: pointer;
}
.time-dots button::after {
position: absolute;
top: 50%;
left: 50%;
width: 8px;
height: 8px;
transform: translate(-50%, -50%);
border: 2px solid rgba(7, 12, 18, 0.8);
border-radius: 50%;
background: #778797;
box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.22);
content: "";
transition: transform 0.2s, box-shadow 0.2s;
}
.time-dots button:nth-child(1)::after { background: #f6b184; }
.time-dots button:nth-child(2)::after { background: #cfe8f2; }
.time-dots button:nth-child(3)::after { background: #829fc2; }
.time-dots button:nth-child(4)::after { background: #33425f; }
.time-dots button:hover::after,
.time-dots button.is-active::after {
transform: translate(-50%, -50%) scale(1.45);
box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.55), 0 0 10px rgba(178, 216, 255, 0.6);
}
.icon-button {
display: grid;
width: 38px;
height: 38px;
flex: 0 0 38px;
place-items: center;
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 10px;
background: rgba(255, 255, 255, 0.045);
cursor: pointer;
transition: background 0.2s, border-color 0.2s;
}
.icon-button:hover,
.icon-button.is-active {
border-color: rgba(255, 255, 255, 0.25);
background: rgba(255, 255, 255, 0.11);
}
.icon-button svg {
width: 16px;
fill: none;
stroke: currentColor;
stroke-linecap: round;
stroke-linejoin: round;
stroke-width: 1.4;
}
.icon-button span {
font-family: Georgia, serif;
font-size: 15px;
}
.hint {
position: absolute;
bottom: max(38px, calc(env(safe-area-inset-bottom) + 14px));
left: max(30px, env(safe-area-inset-left));
display: flex;
align-items: center;
gap: 10px;
color: rgba(230, 237, 241, 0.48);
font-size: 8px;
font-weight: 600;
letter-spacing: 0.1em;
text-transform: uppercase;
transition: opacity 0.5s ease;
}
.hint.is-hidden {
opacity: 0;
}
.mouse {
position: relative;
width: 13px;
height: 19px;
border: 1px solid rgba(255, 255, 255, 0.38);
border-radius: 7px;
}
.mouse i {
position: absolute;
top: 4px;
left: 5px;
width: 1px;
height: 4px;
background: rgba(255, 255, 255, 0.58);
animation: scroll-hint 1.8s ease-in-out infinite;
}
.quality {
position: absolute;
right: max(30px, env(safe-area-inset-right));
bottom: max(39px, calc(env(safe-area-inset-bottom) + 15px));
display: flex;
align-items: center;
gap: 7px;
color: rgba(231, 238, 242, 0.42);
font-size: 8px;
font-weight: 600;
letter-spacing: 0.11em;
text-transform: uppercase;
}
.quality span {
width: 5px;
height: 5px;
border-radius: 50%;
background: #83cfad;
box-shadow: 0 0 8px rgba(107, 227, 166, 0.55);
}
.quality b {
font-weight: inherit;
}
.building-card {
position: absolute;
top: 50%;
right: max(32px, env(safe-area-inset-right));
width: 260px;
padding: 22px;
transform: translate(18px, -50%);
border: 1px solid rgba(255, 255, 255, 0.16);
border-radius: 14px;
background: rgba(10, 16, 24, 0.65);
box-shadow: 0 24px 60px rgba(0, 0, 0, 0.24), inset 0 1px rgba(255, 255, 255, 0.06);
backdrop-filter: blur(20px);
opacity: 0;
pointer-events: none;
transition: opacity 0.3s ease, transform 0.45s cubic-bezier(0.2, 0.8, 0.2, 1);
}
.building-card.is-visible {
transform: translate(0, -50%);
opacity: 1;
pointer-events: auto;
}
.building-card > button,
.help-panel__head button {
position: absolute;
top: 12px;
right: 12px;
width: 26px;
height: 26px;
border-radius: 50%;
background: transparent;
color: rgba(255, 255, 255, 0.55);
cursor: pointer;
font-size: 17px;
}
.building-card h3 {
margin: 9px 0 19px;
font-family: Georgia, "Times New Roman", serif;
font-size: 25px;
font-weight: 400;
letter-spacing: -0.025em;
}
.building-card__grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 8px;
padding-top: 15px;
border-top: 1px solid var(--line);
}
.building-card__grid b,
.building-card__grid span {
display: block;
}
.building-card__grid b {
font-size: 11px;
font-weight: 550;
}
.building-card__grid span {
margin-top: 3px;
color: var(--muted);
font-size: 7px;
letter-spacing: 0.1em;
text-transform: uppercase;
}
.help-panel {
position: absolute;
top: max(80px, calc(env(safe-area-inset-top) + 64px));
right: max(30px, env(safe-area-inset-right));
width: 290px;
padding: 24px;
transform: translateY(-10px);
border: 1px solid rgba(255, 255, 255, 0.16);
border-radius: 15px;
background: rgba(10, 16, 24, 0.72);
box-shadow: 0 24px 60px rgba(0, 0, 0, 0.3), inset 0 1px rgba(255, 255, 255, 0.06);
backdrop-filter: blur(22px);
opacity: 0;
pointer-events: none;
transition: opacity 0.25s, transform 0.35s ease;
}
.help-panel.is-visible {
transform: translateY(0);
opacity: 1;
pointer-events: auto;
}
.help-panel__head {
position: relative;
}
.help-panel__head button {
top: -12px;
right: -12px;
}
.help-panel h3 {
margin: 9px 0 17px;
font-family: Georgia, serif;
font-size: 23px;
font-weight: 400;
}
.help-panel dl {
margin: 0;
border-top: 1px solid var(--line);
}
.help-panel dl div {
display: flex;
justify-content: space-between;
padding: 9px 0;
border-bottom: 1px solid var(--line);
font-size: 10px;
}
.help-panel dt {
color: rgba(255, 255, 255, 0.84);
font-weight: 600;
}
.help-panel dd {
margin: 0;
color: var(--muted);
}
.help-panel > p {
margin: 16px 0 0;
color: var(--muted);
font-size: 10px;
line-height: 1.6;
}
.loading {
position: fixed;
inset: 0;
z-index: 10;
display: flex;
align-items: center;
justify-content: center;
gap: 34px;
background:
radial-gradient(circle at 65% 35%, rgba(47, 72, 97, 0.28), transparent 40%),
#0b1119;
transition: opacity 0.9s ease, visibility 0.9s;
}
.loading.is-complete {
visibility: hidden;
opacity: 0;
}
.loading__mark {
display: grid;
width: 50px;
height: 50px;
grid-template-columns: 1fr 1fr;
gap: 3px;
transform: rotate(45deg);
}
.loading__mark span {
border: 1px solid rgba(190, 222, 245, 0.55);
animation: city-mark 1.6s ease-in-out infinite alternate;
}
.loading__mark span:nth-child(2) { animation-delay: -0.35s; }
.loading__mark span:nth-child(3) { animation-delay: -0.7s; }
.loading__mark span:nth-child(4) { animation-delay: -1.05s; }
.loading__copy {
width: min(280px, 52vw);
}
.loading__copy h1 {
margin: 8px 0 14px;
font-family: Georgia, serif;
font-size: 30px;
font-weight: 400;
letter-spacing: -0.03em;
}
.loading__track {
width: 100%;
height: 1px;
background: rgba(255, 255, 255, 0.12);
}
.loading__track i {
display: block;
width: 6%;
height: 100%;
background: #c7e8ff;
box-shadow: 0 0 10px rgba(164, 217, 255, 0.65);
transition: width 0.45s ease;
}
.loading__copy p {
margin: 10px 0 0;
color: var(--muted);
font-size: 8px;
font-weight: 600;
letter-spacing: 0.13em;
text-transform: uppercase;
}
.grain,
.vignette {
position: fixed;
inset: 0;
z-index: 2;
pointer-events: none;
}
.grain {
opacity: 0.15;
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 160 160' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.8' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='.26'/%3E%3C/svg%3E");
mix-blend-mode: soft-light;
}
.vignette {
background: radial-gradient(circle at 50% 46%, transparent 42%, rgba(2, 5, 9, 0.33) 120%);
}
.webgl-error {
position: fixed;
inset: 0;
z-index: 20;
display: grid;
align-content: center;
justify-items: center;
padding: 30px;
background: #0c121b;
text-align: center;
}
.webgl-error[hidden] {
display: none;
}
.webgl-error h1 {
margin: 12px 0;
font-family: Georgia, serif;
font-size: clamp(36px, 7vw, 72px);
font-weight: 400;
}
.webgl-error p {
color: var(--muted);
}
@keyframes scroll-hint {
0%, 100% { transform: translateY(0); opacity: 0.4; }
50% { transform: translateY(4px); opacity: 1; }
}
@keyframes city-mark {
from { background: rgba(177, 220, 252, 0.04); transform: scale(0.88); }
to { background: rgba(177, 220, 252, 0.42); transform: scale(1); }
}
@media (max-width: 900px) {
.metrics,
.hint,
.quality {
display: none;
}
.intro {
bottom: max(112px, calc(env(safe-area-inset-bottom) + 100px));
}
.dock {
max-width: calc(100vw - 24px);
gap: 9px;
padding-right: 9px;
padding-left: 12px;
}
.dock__group > span,
.dock__divider:first-of-type,
#help-toggle {
display: none;
}
.dock__views button {
min-height: 44px;
padding-right: 8px;
padding-left: 8px;
}
.dock__time {
min-width: 106px;
}
.building-card {
top: auto;
right: 12px;
bottom: max(101px, calc(env(safe-area-inset-bottom) + 89px));
left: 12px;
width: auto;
transform: translateY(12px);
}
.building-card.is-visible {
transform: translateY(0);
}
}
@media (max-width: 560px) {
.topbar {
top: max(16px, env(safe-area-inset-top));
right: max(16px, env(safe-area-inset-right));
left: max(16px, env(safe-area-inset-left));
}
.brand small,
.conditions i,
#condition-weather {
display: none;
}
.intro {
left: max(22px, env(safe-area-inset-left));
width: calc(100vw - 44px);
}
.intro h2 {
font-size: clamp(45px, 15vw, 64px);
}
.intro p {
max-width: 310px;
font-size: 11px;
}
.dock {
width: calc(100vw - 20px);
height: 60px;
justify-content: center;
border-radius: 15px;
}
.dock__views button {
font-size: 8px;
}
.dock__time > b,
.dock__divider:last-of-type {
display: none;
}
.dock__time {
min-width: auto;
}
.icon-button {
width: 44px;
height: 44px;
flex-basis: 44px;
}
.help-panel {
right: 12px;
left: 12px;
width: auto;
}
.loading {
flex-direction: column;
gap: 26px;
}
.loading__copy {
width: min(280px, calc(100vw - 54px));
text-align: center;
}
}
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
scroll-behavior: auto !important;
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}