overscroll-behavior: none on the script-scrolled, overflow-hidden reading viewport swallowed wheel events, so the page only moved by keyboard, touch or the navigation.
627 lines
15 KiB
CSS
627 lines
15 KiB
CSS
.visually-hidden {
|
|
position: absolute !important;
|
|
inline-size: 1px !important;
|
|
block-size: 1px !important;
|
|
margin: -1px !important;
|
|
overflow: hidden !important;
|
|
clip-path: inset(50%) !important;
|
|
white-space: nowrap !important;
|
|
}
|
|
|
|
.journey-world {
|
|
position: fixed;
|
|
z-index: 0;
|
|
inset: 0;
|
|
overflow: hidden;
|
|
pointer-events: none;
|
|
background: #040713;
|
|
}
|
|
|
|
.journey-poster,
|
|
.journey-canvas {
|
|
position: absolute;
|
|
inset: 0;
|
|
inline-size: 100%;
|
|
block-size: 100%;
|
|
}
|
|
|
|
/* A still destination grade when motion is disabled; no animation or WebGL. */
|
|
.journey-world[data-static-fallback='true'][data-arrived='true'] .journey-poster {
|
|
filter: sepia(0.35) saturate(0.85);
|
|
}
|
|
|
|
.journey-poster {
|
|
object-fit: cover;
|
|
background:
|
|
radial-gradient(ellipse at 50% 47%, rgb(242 31 139 / 34%) 0 7%, rgb(110 21 113 / 25%) 20%, transparent 48%),
|
|
linear-gradient(180deg, #01030a 0 25%, #070817 43%, #1b0b27 59%, #02060b 100%);
|
|
background-size: cover;
|
|
}
|
|
|
|
.journey-poster-composition,
|
|
.journey-poster-composition > span {
|
|
position: absolute;
|
|
}
|
|
|
|
.journey-poster-composition {
|
|
inset: 0;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.journey-poster__stars {
|
|
inset: 0;
|
|
opacity: 0.72;
|
|
background-image:
|
|
radial-gradient(circle, rgb(225 252 255 / 90%) 0 1px, transparent 1.3px),
|
|
radial-gradient(circle, rgb(120 216 229 / 72%) 0 0.8px, transparent 1.1px);
|
|
background-position: 17px 29px, 83px 97px;
|
|
background-size: 173px 149px, 227px 181px;
|
|
mask-image: linear-gradient(180deg, #000 0 54%, transparent 72%);
|
|
}
|
|
|
|
.journey-poster__sun {
|
|
inset: 34% auto auto 50%;
|
|
inline-size: clamp(8rem, 13.5vw, 14.5rem);
|
|
aspect-ratio: 1;
|
|
translate: -50% 0;
|
|
border-radius: 50%;
|
|
background:
|
|
repeating-linear-gradient(
|
|
180deg,
|
|
transparent 0 8%,
|
|
rgb(51 5 31 / 72%) 8.5% 11%,
|
|
transparent 11.5% 15%
|
|
),
|
|
linear-gradient(180deg, #ff4d9b, #d52378 58%, #8e155c);
|
|
box-shadow:
|
|
0 0 2.4rem rgb(255 44 151 / 42%),
|
|
0 1.2rem 8rem 2.4rem rgb(126 29 143 / 28%);
|
|
}
|
|
|
|
.journey-poster__terrain {
|
|
inset: 45% -12% -8%;
|
|
background:
|
|
repeating-linear-gradient(0deg, transparent 0 7.6%, rgb(84 221 233 / 19%) 7.8% 8.15%, transparent 8.35% 12%),
|
|
repeating-linear-gradient(76deg, transparent 0 6.8%, rgb(220 50 168 / 17%) 7% 7.25%, transparent 7.5% 11%),
|
|
repeating-linear-gradient(104deg, transparent 0 8.4%, rgb(73 207 228 / 14%) 8.6% 8.85%, transparent 9.1% 13%),
|
|
linear-gradient(180deg, rgb(104 21 101 / 34%), rgb(3 10 17 / 86%));
|
|
clip-path: polygon(0 17%, 6% 8%, 12% 20%, 18% 13%, 24% 25%, 30% 17%, 36% 29%, 42% 23%, 47% 34%, 50% 41%, 53% 34%, 58% 23%, 64% 29%, 70% 17%, 76% 25%, 82% 13%, 88% 20%, 94% 8%, 100% 17%, 100% 100%, 0 100%);
|
|
filter: drop-shadow(0 -0.35rem 1.5rem rgb(223 40 169 / 22%));
|
|
}
|
|
|
|
.journey-poster__road {
|
|
inset: 46% -8% -10%;
|
|
background:
|
|
repeating-linear-gradient(180deg, transparent 0 7%, rgb(244 177 80 / 84%) 7.35% 8.35%, transparent 8.7% 15%) 50% 0 / clamp(0.15rem, 0.32vw, 0.34rem) 100% no-repeat,
|
|
linear-gradient(90deg, rgb(46 188 212 / 15%), transparent 5% 95%, rgb(46 188 212 / 15%)),
|
|
linear-gradient(180deg, #050813, #000207);
|
|
clip-path: polygon(49.55% 0, 50.45% 0, 76% 100%, 24% 100%);
|
|
}
|
|
|
|
.journey-poster__rail {
|
|
inset: 0;
|
|
background: #67d4e4;
|
|
filter: drop-shadow(0 0 0.55rem rgb(76 207 225 / 72%));
|
|
}
|
|
|
|
.journey-poster__rail--left {
|
|
clip-path: polygon(49.38% 46%, 49.5% 46%, 24.3% 100%, 23.55% 100%);
|
|
}
|
|
|
|
.journey-poster__rail--right {
|
|
clip-path: polygon(50.5% 46%, 50.62% 46%, 76.45% 100%, 75.7% 100%);
|
|
}
|
|
|
|
.journey-poster__car {
|
|
inset: auto auto 1.6% 50%;
|
|
inline-size: clamp(9.5rem, 20vw, 21rem);
|
|
block-size: clamp(3.6rem, 7.4vw, 7.8rem);
|
|
translate: -50% 0;
|
|
border-radius: 40% 40% 8% 8% / 34% 34% 12% 12%;
|
|
background:
|
|
linear-gradient(106deg, transparent 0 24%, rgb(13 41 56 / 98%) 24.5% 42%, rgb(3 13 22 / 98%) 42.5% 57.5%, rgb(13 41 56 / 98%) 58% 75.5%, transparent 76%) 50% 6% / 78% 48% no-repeat,
|
|
linear-gradient(180deg, #173444 0 26%, #0a2231 46%, #06131f 68%, #020711 100%);
|
|
clip-path: polygon(29% 0, 71% 0, 82% 25%, 95% 43%, 100% 76%, 94% 100%, 6% 100%, 0 76%, 5% 43%, 18% 25%);
|
|
filter:
|
|
drop-shadow(0 0.8rem 1.2rem rgb(0 0 0 / 82%))
|
|
drop-shadow(0 0.2rem 1.1rem rgb(46 181 207 / 12%));
|
|
}
|
|
|
|
.journey-poster__car::before {
|
|
position: absolute;
|
|
inset: 61% 8% auto;
|
|
block-size: clamp(0.24rem, 0.38vw, 0.42rem);
|
|
border-radius: 50%;
|
|
background: linear-gradient(90deg, #ff244f, #ff7592 48% 52%, #ff244f);
|
|
box-shadow: 0 0 1rem rgb(255 49 95 / 64%);
|
|
content: '';
|
|
}
|
|
|
|
.journey-poster__car::after {
|
|
position: absolute;
|
|
inset: 88% 20% auto;
|
|
block-size: 0.16rem;
|
|
border-radius: 50%;
|
|
background: #67d4e4;
|
|
box-shadow: 0 0 1.1rem 0.36rem rgb(61 208 229 / 48%);
|
|
content: '';
|
|
}
|
|
|
|
.journey-canvas {
|
|
max-inline-size: none;
|
|
}
|
|
|
|
.portfolio-shell {
|
|
position: relative;
|
|
z-index: 1;
|
|
}
|
|
|
|
.site-header {
|
|
position: relative;
|
|
z-index: 2;
|
|
}
|
|
|
|
.portfolio-main {
|
|
isolation: isolate;
|
|
}
|
|
|
|
.journey-hud {
|
|
position: fixed;
|
|
z-index: var(--z-hud);
|
|
inset: auto max(0.75rem, env(safe-area-inset-right)) max(0.75rem, env(safe-area-inset-bottom)) auto;
|
|
display: flex;
|
|
min-block-size: 44px;
|
|
align-items: center;
|
|
gap: 0.72rem;
|
|
padding: 0.48rem 0.72rem;
|
|
border: 1px solid rgb(126 220 232 / 25%);
|
|
border-radius: 2px;
|
|
background: var(--surface-strong);
|
|
box-shadow: 0 0.8rem 2.4rem rgb(0 5 14 / 28%);
|
|
color: var(--text-muted);
|
|
font: 560 0.72rem/1 var(--mono);
|
|
letter-spacing: 0.08em;
|
|
pointer-events: none;
|
|
}
|
|
|
|
.journey-hud__route {
|
|
display: inline-flex;
|
|
align-items: baseline;
|
|
gap: 0.4rem;
|
|
}
|
|
|
|
.journey-hud__route span {
|
|
color: rgb(170 185 194 / 70%);
|
|
font-size: 0.61rem;
|
|
}
|
|
|
|
.journey-hud__route strong {
|
|
color: var(--text);
|
|
font-size: 0.76rem;
|
|
}
|
|
|
|
.journey-hud__section,
|
|
.journey-hud__arrival {
|
|
color: var(--cyan);
|
|
}
|
|
|
|
.journey-hud__section::before {
|
|
margin-inline-end: 0.72rem;
|
|
color: rgb(126 220 232 / 35%);
|
|
content: '/';
|
|
}
|
|
|
|
.journey-hud__arrival {
|
|
padding-inline-start: 0.12rem;
|
|
color: var(--amber);
|
|
}
|
|
|
|
.drive-controls {
|
|
position: fixed;
|
|
z-index: var(--z-popover);
|
|
inset: auto auto max(0.75rem, env(safe-area-inset-bottom)) max(0.75rem, env(safe-area-inset-left));
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.38rem;
|
|
max-inline-size: calc(100vw - 1.5rem);
|
|
font-family: var(--mono);
|
|
font-size: 0.72rem;
|
|
}
|
|
|
|
.drive-controls__dock {
|
|
display: flex;
|
|
gap: 1px;
|
|
padding: 3px;
|
|
border: 1px solid rgb(126 220 232 / 24%);
|
|
border-radius: 3px;
|
|
background: var(--surface-strong);
|
|
box-shadow: 0 0.8rem 2.4rem rgb(0 5 14 / 28%);
|
|
}
|
|
|
|
.drive-start,
|
|
.drive-control-button {
|
|
min-block-size: 44px;
|
|
border: 1px solid transparent;
|
|
border-radius: 2px;
|
|
font-weight: 620;
|
|
cursor: pointer;
|
|
transition: opacity var(--transition), transform var(--transition);
|
|
}
|
|
|
|
.drive-start {
|
|
display: inline-flex;
|
|
min-inline-size: 12.5rem;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
gap: 1rem;
|
|
padding-inline: 1rem;
|
|
border-color: rgb(120 216 229 / 72%);
|
|
background: rgb(120 216 229 / 94%);
|
|
box-shadow: 0 0 1.5rem rgb(77 201 220 / 17%);
|
|
color: #041017;
|
|
letter-spacing: 0.1em;
|
|
}
|
|
|
|
.drive-start:hover:not(:disabled) {
|
|
transform: translateY(-2px);
|
|
}
|
|
|
|
.drive-start:disabled {
|
|
cursor: wait;
|
|
opacity: 0.64;
|
|
}
|
|
|
|
.drive-control-button {
|
|
position: relative;
|
|
display: inline-grid;
|
|
inline-size: 44px;
|
|
place-items: center;
|
|
padding: 0;
|
|
background: rgb(8 17 29 / 92%);
|
|
color: var(--text-muted);
|
|
}
|
|
|
|
.drive-control-button:hover {
|
|
color: var(--cyan);
|
|
transform: translateY(-1px);
|
|
}
|
|
|
|
.drive-controls__settings-trigger {
|
|
border-color: rgb(126 220 232 / 24%);
|
|
background: var(--surface-strong);
|
|
box-shadow: 0 0.8rem 2.4rem rgb(0 5 14 / 28%);
|
|
}
|
|
|
|
.drive-start:focus-visible,
|
|
.drive-start:focus,
|
|
.drive-control-button:focus-visible,
|
|
.drive-control-button:focus,
|
|
.drive-popover input:focus-visible,
|
|
.drive-popover select:focus-visible {
|
|
outline: none;
|
|
box-shadow: inset 0 0 0 2px var(--focus), 0 0 0 1px rgb(3 8 17 / 90%);
|
|
}
|
|
|
|
.drive-control-button::after {
|
|
position: absolute;
|
|
inset: auto auto calc(100% + 0.5rem) 50%;
|
|
padding: 0.32rem 0.46rem;
|
|
transform: translate(-50%, 4px);
|
|
border: 1px solid rgb(126 220 232 / 18%);
|
|
background: rgb(3 8 17 / 96%);
|
|
color: var(--text);
|
|
content: attr(data-tooltip);
|
|
font: 520 0.65rem/1 var(--mono);
|
|
letter-spacing: 0.02em;
|
|
opacity: 0;
|
|
pointer-events: none;
|
|
transition: opacity var(--transition), transform var(--transition);
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.drive-control-button:hover::after,
|
|
.drive-control-button:focus-visible::after {
|
|
transform: translate(-50%, 0);
|
|
opacity: 1;
|
|
}
|
|
|
|
.drive-popover {
|
|
position: absolute;
|
|
inset: auto auto calc(100% + 0.7rem) 0;
|
|
display: grid;
|
|
transform-origin: left bottom;
|
|
border: 1px solid rgb(126 220 232 / 27%);
|
|
border-radius: 3px;
|
|
background: var(--surface-strong);
|
|
box-shadow: 0 1.4rem 3rem rgb(0 4 12 / 42%);
|
|
color: var(--text);
|
|
animation: drive-popover-in var(--transition) both;
|
|
}
|
|
|
|
@keyframes drive-popover-in {
|
|
from {
|
|
transform: translateY(6px);
|
|
opacity: 0;
|
|
}
|
|
|
|
to {
|
|
transform: translateY(0);
|
|
opacity: 1;
|
|
}
|
|
}
|
|
|
|
.drive-popover--volume {
|
|
grid-template-columns: auto minmax(8rem, 1fr) auto;
|
|
min-inline-size: 16.5rem;
|
|
align-items: center;
|
|
gap: 0.7rem;
|
|
padding: 0.7rem;
|
|
}
|
|
|
|
.drive-popover--settings {
|
|
grid-template-columns: auto minmax(7rem, 1fr);
|
|
min-inline-size: 15rem;
|
|
gap: 0.55rem 1rem;
|
|
padding: 0.85rem;
|
|
}
|
|
|
|
.drive-popover strong,
|
|
.drive-popover label {
|
|
color: var(--text-muted);
|
|
font-size: 0.64rem;
|
|
font-weight: 560;
|
|
letter-spacing: 0.1em;
|
|
}
|
|
|
|
.drive-popover strong {
|
|
grid-column: 1 / -1;
|
|
padding-block-end: 0.45rem;
|
|
border-block-end: 1px solid rgb(126 220 232 / 14%);
|
|
color: var(--cyan);
|
|
}
|
|
|
|
.drive-popover input,
|
|
.drive-popover select {
|
|
min-block-size: 44px;
|
|
}
|
|
|
|
.drive-popover input[type="range"] {
|
|
inline-size: 100%;
|
|
accent-color: var(--cyan);
|
|
}
|
|
|
|
.drive-popover select {
|
|
border: 1px solid rgb(126 220 232 / 24%);
|
|
border-radius: 2px;
|
|
background: #08111d;
|
|
color: var(--text);
|
|
padding-inline: 0.65rem;
|
|
}
|
|
|
|
.drive-popover output {
|
|
color: var(--cyan);
|
|
font-size: 0.68rem;
|
|
}
|
|
|
|
.drive-controls__audio-status {
|
|
display: inline-flex;
|
|
min-block-size: 44px;
|
|
align-items: center;
|
|
margin: 0;
|
|
padding-inline: 0.85rem;
|
|
border: 1px solid rgb(244 173 103 / 26%);
|
|
border-radius: 2px;
|
|
background: var(--surface-strong);
|
|
color: var(--text-muted);
|
|
}
|
|
|
|
.drive-controls__status {
|
|
grid-column: 1 / -1;
|
|
margin: 0;
|
|
padding-block-start: 0.4rem;
|
|
border-block-start: 1px solid rgb(126 220 232 / 14%);
|
|
color: var(--text-muted);
|
|
font-size: 0.66rem;
|
|
}
|
|
|
|
@media (max-width: 767px) {
|
|
html {
|
|
scroll-padding-block-end: 7rem;
|
|
}
|
|
|
|
#contact {
|
|
padding-block-end: 7rem;
|
|
}
|
|
|
|
#contact a {
|
|
scroll-margin-block-end: 7rem;
|
|
}
|
|
|
|
.drive-controls {
|
|
inset-inline-start: max(0.5rem, env(safe-area-inset-left));
|
|
inset-block-end: max(0.5rem, env(safe-area-inset-bottom));
|
|
}
|
|
|
|
.journey-hud {
|
|
inset-inline-end: max(0.5rem, env(safe-area-inset-right));
|
|
inset-block-end: max(0.5rem, env(safe-area-inset-bottom));
|
|
max-inline-size: 6.5rem;
|
|
gap: 0.3rem;
|
|
padding-inline: 0.55rem;
|
|
letter-spacing: 0.04em;
|
|
}
|
|
|
|
.journey-hud__route span,
|
|
.journey-hud__section::before {
|
|
display: none;
|
|
}
|
|
|
|
.journey-hud__section {
|
|
max-inline-size: 4.25rem;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.journey-hud__arrival {
|
|
display: none;
|
|
}
|
|
|
|
.drive-start {
|
|
min-inline-size: 9rem;
|
|
gap: 0.6rem;
|
|
padding-inline: 0.62rem;
|
|
font-size: 0.6rem;
|
|
}
|
|
|
|
.drive-popover {
|
|
position: fixed;
|
|
inset: auto 0.5rem calc(max(0.5rem, env(safe-area-inset-bottom)) + 3.25rem);
|
|
max-inline-size: calc(100vw - 1rem);
|
|
}
|
|
}
|
|
|
|
@media (max-height: 420px) {
|
|
.journey-hud {
|
|
display: none;
|
|
}
|
|
|
|
.drive-controls {
|
|
position: relative;
|
|
inset: auto;
|
|
inline-size: fit-content;
|
|
max-inline-size: calc(100% - 1.5rem);
|
|
margin: 0.75rem;
|
|
}
|
|
|
|
#contact {
|
|
padding-block-end: var(--space-3);
|
|
}
|
|
|
|
.drive-popover {
|
|
position: absolute;
|
|
inset: auto auto calc(100% + 0.5rem) 0;
|
|
}
|
|
}
|
|
|
|
/* Round 5 outro: letterbox bars close in on arrival, on every tier (they are
|
|
CSS, so the static poster gets them too). They sit in the world layer,
|
|
under the reading column, so they frame the sky and never cover content.
|
|
The upper bar hangs below the gantry and carries a closing credit built
|
|
from real identity facts; the lower bar is left clear for the trip
|
|
summary that ends the contact chapter. */
|
|
.journey-world::before,
|
|
.journey-world::after {
|
|
position: absolute;
|
|
z-index: 1;
|
|
inset-inline: 0;
|
|
block-size: max(54px, 10vh);
|
|
background: #020108;
|
|
content: '';
|
|
transform: scaleY(0);
|
|
transition: transform 1.6s cubic-bezier(0.65, 0, 0.35, 1);
|
|
}
|
|
.journey-world::before {
|
|
inset-block-start: 0;
|
|
display: grid;
|
|
align-items: end;
|
|
justify-items: center;
|
|
block-size: calc(var(--gantry-h, 72px) + max(30px, 4.5vh));
|
|
padding: 0 16px max(8px, 1.2vh);
|
|
color: rgb(255 226 196 / 0%);
|
|
font: 600 0.6rem/1.3 var(--mono, ui-monospace, monospace);
|
|
letter-spacing: 0.32em;
|
|
text-align: center;
|
|
text-transform: uppercase;
|
|
white-space: nowrap;
|
|
content: attr(data-credit) / '';
|
|
transform-origin: top;
|
|
transition:
|
|
transform 1.6s cubic-bezier(0.65, 0, 0.35, 1),
|
|
color 1.2s ease;
|
|
}
|
|
.journey-world::after {
|
|
inset-block-end: 0;
|
|
transform-origin: bottom;
|
|
}
|
|
.journey-world[data-arrived='true']::before,
|
|
.journey-world[data-arrived='true']::after {
|
|
transform: scaleY(1);
|
|
transition-delay: 0.5s;
|
|
}
|
|
.journey-world[data-arrived='true']::before {
|
|
color: rgb(255 226 196 / 74%);
|
|
transition-delay: 0.5s, 1.9s;
|
|
}
|
|
@media (max-width: 767px) {
|
|
.journey-world::after { block-size: max(40px, 7vh); }
|
|
.journey-world::before {
|
|
font-size: 0.5rem;
|
|
letter-spacing: 0.14em;
|
|
white-space: normal;
|
|
}
|
|
}
|
|
@media (prefers-reduced-motion: reduce) {
|
|
.journey-world::before,
|
|
.journey-world::after,
|
|
.journey-world[data-arrived='true']::before,
|
|
.journey-world[data-arrived='true']::after {
|
|
transition: none;
|
|
}
|
|
}
|
|
@media (forced-colors: active) {
|
|
.journey-world::before,
|
|
.journey-world::after { display: none; }
|
|
}
|
|
|
|
@media (prefers-reduced-motion: reduce) {
|
|
.journey-poster {
|
|
filter: saturate(0.86) brightness(0.92);
|
|
}
|
|
}
|
|
|
|
@media print {
|
|
.journey-world,
|
|
.journey-hud,
|
|
.drive-controls,
|
|
#journey-scene-description {
|
|
display: none !important;
|
|
}
|
|
}
|
|
|
|
/* The outer stage retains the native document height. The viewport owns one
|
|
reusable alpha mask; only its content translates when the document scrolls. */
|
|
.reading-stage[data-reading-stage='live'] > .reading-viewport {
|
|
position: sticky;
|
|
top: 0;
|
|
/* A real scroll container (scrolled from script, never by the user), so
|
|
sticky children and view timelines resolve against the reading window. */
|
|
overflow: hidden;
|
|
/* Wheel and touch scrolling must chain through to the document, which
|
|
drives this container: no overscroll-behavior here. */
|
|
isolation: isolate;
|
|
}
|
|
|
|
/* The stationary reading edge supplies the live reveal. View timelines use
|
|
layout positions, which no longer follow the translated content here. */
|
|
.reading-stage[data-reading-stage='live'] :is(.portfolio-section, .project-stage__lead) > h2,
|
|
.reading-stage[data-reading-stage='live'] .project-case-study__header {
|
|
animation: none;
|
|
}
|
|
|
|
@media print {
|
|
.reading-stage,
|
|
.reading-viewport {
|
|
height: auto !important;
|
|
}
|
|
.reading-stage[data-reading-stage='live'] > .reading-viewport {
|
|
position: static;
|
|
overflow: visible;
|
|
mask-image: none !important;
|
|
}
|
|
.reading-stage .portfolio-main {
|
|
transform: none !important;
|
|
will-change: auto;
|
|
}
|
|
}
|