feat: engine off at the destination

On arrival the drive winds down to a stop, the tail and running lamps
drop to parking level, the sky darkens about 10% with more stars and
the grid fades. The engine and road noise take a 1.2 s low-pass sweep
to idle. The letterbox stays within 8vh and the closing credit types
into the lower bar; reduced motion keeps only the bars and dimming.
This commit is contained in:
2026-10-10 23:37:51 +03:00
parent 07e3ea014d
commit f08dfc3fba
7 changed files with 124 additions and 34 deletions

View File

@@ -507,15 +507,15 @@
/* 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. */
The upper bar hangs below the gantry; the lower bar carries a closing
credit built from real identity facts, typed in once the bars close. */
.journey-world::before,
.journey-world::after {
position: absolute;
z-index: 1;
inset-inline: 0;
block-size: max(54px, 10vh);
/* Engine off: the bars stay within 8vh of the frame each. */
block-size: min(8vh, 72px);
background: #020108;
content: '';
transform: scaleY(0);
@@ -526,20 +526,45 @@
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%);
block-size: calc(var(--gantry-h, 72px) + min(5vh, 44px));
transform-origin: top;
}
/* The closing credit types in, in mono, once the bars have closed. */
.journey-world__credit {
position: absolute;
z-index: 2;
/* In the lower bar: the upper one is shared with the contact avatar. */
inset: auto 0 0;
display: flex;
align-items: center;
justify-content: center;
block-size: min(8vh, 72px);
padding-inline: 16px;
pointer-events: none;
}
.journey-world__credit::before {
content: attr(data-credit) / '';
color: rgb(255 226 196 / 78%);
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;
clip-path: inset(0 100% 0 0);
opacity: 0;
}
.journey-world[data-arrived='true'] .journey-world__credit::before {
clip-path: inset(0 -1em 0 0);
opacity: 1;
transition:
opacity 1ms linear 1.9s,
clip-path 1.5s steps(36, end) 1.9s;
}
/* Reduced motion: the bars and the dimming only; the credit simply shows. */
@media (prefers-reduced-motion: reduce) {
.journey-world[data-arrived='true'] .journey-world__credit::before { transition: none; }
}
.journey-poster { transition: filter 1.6s ease; }
.journey-world[data-arrived='true'] .journey-poster { filter: brightness(0.9); }
.journey-world::after {
inset-block-end: 0;
transform-origin: bottom;
@@ -549,17 +574,22 @@
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 {
.journey-world::after { block-size: min(7vh, 56px); }
/* Phones: the credit may wrap, so it fades in rather than types. */
.journey-world__credit { block-size: min(7vh, 56px); }
.journey-world__credit::before {
clip-path: none;
font-size: 0.5rem;
letter-spacing: 0.14em;
text-align: center;
white-space: normal;
}
.journey-world[data-arrived='true'] .journey-world__credit::before {
clip-path: none;
transition: opacity 0.8s ease 1.9s;
}
}
@media (prefers-reduced-motion: reduce) {
.journey-world::before,
@@ -571,7 +601,11 @@
}
@media (forced-colors: active) {
.journey-world::before,
.journey-world::after { display: none; }
.journey-world::after,
.journey-world__credit { display: none; }
}
@media (prefers-reduced-motion: reduce) {
.journey-world[data-arrived='true'] .journey-poster { filter: saturate(0.86) brightness(0.83); }
}
@media (prefers-reduced-motion: reduce) {