/* Worldbound Tools — stage v4 "scene life" (isolated preview; loaded after styles.css)
   ---------------------------------------------------------------------------------------------------------
   What this file adds: per-chapter physical micro-events, authored as short CSS timelines.
   Rules of the house
   • Every event is an environmental effect of something that belongs to the place (light, shade, water, steam,
     a beacon, a passing mast). No people are animated, no labels/signage/text are drawn, no particles for decor.
   • Positions are in IMAGE coordinates: .life is sized by src/scene-life.js to the far picture's cover rectangle,
     so left/top/width/height in % are fractions of the 1672×941 artwork; --u = 1 % of the artwork's width (px).
   • Depth: .life sits directly above the far plane and below haze, vignette, mid cut-outs and near occluders, so
     a maple, a counter edge or a window frame correctly covers an event behind it. Screen-anchored passage layers
     (.fx-*) sit at the depth named in index.html (LAX glass in front of everything in that scene; rail masts
     between the verge grass and the window frame; cabin reflection on top of the cabin window).
   • Only opacity and transform are animated; gradients are static paint. No filter/blur/backdrop animation.
   • Timeline gate: animations exist only under .scene[data-life="arriving"|"live"]. data-life="off" removes them,
     so re-entering a chapter restarts its timeline from t=0 (delays below are the cue sheet).
   • .minor = secondary event: dropped on small screens (≤650px) to keep two events per chapter on phones.
   • #experience[data-life="paused"] (finder open / page hidden) pauses these AND the v3 ambient loops;
     [data-life="off"] (reduced motion or Save-Data) removes them and stops the v3 ambient loops.
   Layer budget at rest (visible chapter only; hidden chapters are display:none): ≤ 6 animated layers per chapter
   on desktop, ≤ 4 on phones; largest animated surface ≈ 0.6 × viewport (flight shade, rail overpass). */

/* ---------- base ---------- */
.lens>.life,.lens>.fx-glass,.lens>.fx-bloom,.lens>.fx-cabin,.lens>.fx-rail{transform-origin:0 0}
.life{pointer-events:none;--u:16.72px}
/* events belong to the decoded picture: never over the blurred poster or the no-image fallback */
.scene:not([data-far-ready="true"]) .life{visibility:hidden}
.scene[data-media-state="failed"] :is(.life,.fx-rail){display:none}
.life>*,.wing-clip>*,.water-clip>*,.fx-glass>*,.fx-cabin>*,.fx-rail>*{position:absolute;display:block;pointer-events:none}
.ev{opacity:0;animation-fill-mode:both}
.scene:is([data-life="arriving"],[data-life="live"]) .ev,
.scene:is([data-life="arriving"],[data-life="live"]) .fx-rail>*{will-change:transform,opacity}
.scene:not([data-life="arriving"]):not([data-life="live"]) :is(.ev,.fx-rail>*,.glass-sheen,.cabin-reflect){animation:none!important}

/* pause everything that moves at rest while the finder is open or the tab is hidden */
.stage[data-life="paused"] .scene,.stage[data-life="paused"] .scene *{animation-play-state:paused!important}
/* reduced motion / Save-Data: no micro-events; the v3 resting loops stop too */
.stage[data-life="off"] .life,.stage[data-life="off"] .fx-rail{display:none}
.stage[data-life="off"] :is(.ambient,.light-plane,.rail-rush,.glass-sheen,.cabin-reflect),
.stage[data-life="off"] .scene-night .space-plane{animation:none!important}

/* v4.8 AI-generated loops (02 clouds, 05 steam): a muted video over the far picture, in the same image-anchored
   plane, so it rides with the picture when its scene is passed through. Played by scene-life.js only after the
   scene has landed; it fades in over the still (1.2 s) once playing and is never shown under reduced motion / Save-Data.
   The CSS events it replaces (steam, sea glitter) step aside for good, not at the moment it appears, so nothing
   is doubled and nothing pops out; they come back only if the video fails. */
.life>.life-video{inset:0;width:100%;height:100%;object-fit:fill;opacity:0;transition:opacity 1.2s ease}
.scene[data-life="live"] .life-video[data-media="ready"]{opacity:1} /* not under an incoming passage: fades in after landing */
.life-video:not([data-media="failed"])~:is(.food-steam,.sea-glitter){display:none}

/* =========================================================================================================
   01 LOS ANGELES · LAX — "the gate before boarding": the sun lowers, a distant departure rolls, the beacon
   on the aircraft at the gate comes on. Cue sheet after landing: 0.4 s sun begins to settle (18 s, once) ·
   2.8 s gate aircraft beacon starts (1.1 s period) · 4 s distant take-off roll behind the mullions (26 s cycle)
   ========================================================================================================= */
/* sun glare lowering toward the ridge line, then staying low (settles, does not loop) */
.lax-sun{left:63%;top:23%;width:22%;height:36%;background:radial-gradient(closest-side,#ffe4ae 0%,#ffc070a6 22%,#ffac5a3a 52%,#ffac5a00 100%)}
.scene-home:is([data-life="arriving"],[data-life="live"]) .lax-sun{animation:lax-sun 18s cubic-bezier(.4,0,.3,1) .4s 1 both}
@keyframes lax-sun{from{opacity:.62;transform:translate3d(0,0,0) scale(1)}to{opacity:.26;transform:translate3d(0,4%,0) scale(.9)}}
/* the warm floor patch cools with it (same light source, same timing) */
.lax-floor{left:46%;top:61%;width:54%;height:22%;background:radial-gradient(ellipse 60% 50% at 62% 40%,#ffb7623d,#ffb76200 70%)}
.scene-home:is([data-life="arriving"],[data-life="live"]) .lax-floor{animation:lax-floor 18s cubic-bezier(.4,0,.3,1) .4s 1 both}
@keyframes lax-floor{from{opacity:1}to{opacity:.25}}
/* red anti-collision beacon on top of the parked aircraft: it switches on, then keeps a steady rhythm */
.lax-beacon{left:calc(83.8% - 1.3 * var(--u));top:calc(50.7% - 1.3 * var(--u));width:calc(2.6 * var(--u));height:calc(2.6 * var(--u));background:radial-gradient(closest-side,#fff0e8 0%,#ff4a3a 16%,#ff2a2a66 38%,#ff2a2a00 100%)}
.scene-home[data-life="live"] .lax-beacon{animation:lax-beacon 1.1s linear 2.8s infinite both}
@keyframes lax-beacon{0%{opacity:0}6%{opacity:1}20%{opacity:.15}30%,100%{opacity:0}}
/* a distant aircraft's lights rolling along the far runway, accelerating, lifting slightly, then hidden by a mullion */
.lax-takeoff{left:calc(44% - .5 * var(--u));top:calc(53% - .5 * var(--u));width:var(--u);height:var(--u);background:radial-gradient(closest-side,#fffdf4 0%,#fff3d0b0 30%,#fff3d000 100%)}
.scene-home[data-life="live"] .lax-takeoff{animation:lax-takeoff 26s cubic-bezier(.55,0,.9,.6) 4s infinite both}
@keyframes lax-takeoff{
 0%{opacity:0;transform:translate3d(0,0,0)}
 4%{opacity:.95;transform:translate3d(calc(.4 * var(--u)),0,0)}
 30%{opacity:.95;transform:translate3d(calc(9.4 * var(--u)),calc(-.2 * var(--u)),0)}
 35%{opacity:.9;transform:translate3d(calc(11.6 * var(--u)),calc(-.9 * var(--u)),0)}
 36%,100%{opacity:0;transform:translate3d(calc(11.9 * var(--u)),calc(-1 * var(--u)),0)}}

/* LAX glazing (screen-anchored, front-most in the LAX scene). At rest: a faint warm reflection on the glass that
   drifts as the low sun moves (16 s, alternate = seamless). During LAX→flight the controller scales this pane
   past the camera (3.4×), brightens the sheen and reveals reflected mullions — the glass is felt as passed. */
.fx-glass{inset:0}
.glass-sheen{inset:-10%;opacity:.3;background:linear-gradient(104deg,#fff3dc00 36%,#fff3dc1f 44%,#ffe7c03d 48.5%,#fff3dc12 52%,#fff3dc00 58%),linear-gradient(104deg,#fff3dc00 63%,#fff3dc17 66.5%,#fff3dc00 70%)}
.scene-home:is([data-life="arriving"],[data-life="live"]) .glass-sheen{animation:glass-drift 16s ease-in-out infinite alternate}
@keyframes glass-drift{from{transform:translate3d(-2.5vw,0,0)}to{transform:translate3d(2.5vw,0,0)}}
.glass-mullions{inset:0;opacity:0;background:repeating-linear-gradient(90deg,#fff6e400 0,#fff6e400 10.6vw,#fff6e470 10.9vw,#fffaf0a8 11.05vw,#fff6e470 11.2vw,#fff6e400 11.6vw,#fff6e400 14.2vw),linear-gradient(0deg,#fff6e400 0%,#fff6e42e 50%,#fff6e400 100%)}

/* =========================================================================================================
   02 ACROSS THE PACIFIC — exposure after the glass, then a quiet cruise: a thin cloud's shade crosses the
   wing, the sun's highlight on the wing breathes with the slight bank. Cue sheet: during the passage, bloom
   (controller) · 2.2 s first shade pass (1.2 s, every 15 s) · sun highlight 9 s alternate (synced to amb-bank)
   ========================================================================================================= */
/* exposure bloom around the opening the camera exits through (opacity driven by the controller only) */
.fx-bloom{inset:0;opacity:0;background:radial-gradient(circle at var(--vx,55%) var(--vy,48%),#fffbf2f5 0,#fff6e2d0 16%,#fff2d870 38%,#fff0d000 72%)}
/* the wing: shade and highlight never spill onto the ocean far below */
.wing-clip{inset:0;clip-path:polygon(35% 23.5%,43% 35.5%,51% 42%,100% 53%,100% 100%,86% 100%,78% 73%,60% 56%,48% 46%,40% 36%)}
.wing-shadow{left:0;top:30%;width:70%;height:70%;background:radial-gradient(ellipse 46% 40% at 50% 50%,#0b1b3a70 0%,#0b1b3a40 45%,#0b1b3a00 72%)}
.scene-flight[data-life="live"] .wing-shadow{animation:wing-shade 15s linear 2.2s infinite both}
/* the shade travels from the leading edge toward the trailing edge (the aircraft moves into the picture) */
@keyframes wing-shade{
 0%{opacity:0;transform:translate3d(-55%,-34%,0)}
 1.5%{opacity:1}
 7%{opacity:1}
 8.5%,100%{opacity:0;transform:translate3d(110%,26%,0)}}
.wing-glint{left:calc(89% - 6 * var(--u));top:calc(58.5% - 3 * var(--u));width:calc(12 * var(--u));height:calc(6 * var(--u));background:radial-gradient(closest-side,#fffdf4c0 0%,#fff6dc55 40%,#fff6dc00 100%)}
.scene-flight:is([data-life="arriving"],[data-life="live"]) .wing-glint{animation:wing-glint 9s ease-in-out infinite alternate}
@keyframes wing-glint{from{opacity:.2;transform:translate3d(calc(1.6 * var(--u)),calc(-.8 * var(--u)),0)}to{opacity:.75;transform:translate3d(calc(-1.6 * var(--u)),calc(.8 * var(--u)),0)}}
/* sun path on the ocean: glitter shifts between two states (alternate = seamless) */
.sea-glitter{left:80%;top:29%;width:20%;height:16%;background:repeating-linear-gradient(0deg,#fff8e000 0,#fff8e000 .55vh,#fff8e055 .7vh,#fff8e000 .9vh);-webkit-mask-image:radial-gradient(ellipse 50% 50% at 60% 50%,#000 30%,#0000 100%);mask-image:radial-gradient(ellipse 50% 50% at 60% 50%,#000 30%,#0000 100%)}
.scene-flight:is([data-life="arriving"],[data-life="live"]) .sea-glitter{animation:sea-glitter 2.6s ease-in-out infinite alternate}
@keyframes sea-glitter{from{opacity:.15;transform:translate3d(0,0,0)}to{opacity:.5;transform:translate3d(0,.35vh,0)}}
/* cabin window glass: a faint interior reflection that moves with the bank; rides with the frame in a passage */
.fx-cabin{inset:0}
.cabin-reflect{inset:-12%;opacity:.55;background:linear-gradient(118deg,#ffffff00 30%,#ffffff12 39%,#ffffff1c 41%,#ffffff00 49%),linear-gradient(118deg,#ffffff00 58%,#dfefff0d 61%,#ffffff00 64%)}
.scene-flight:is([data-life="arriving"],[data-life="live"]) .cabin-reflect{animation:cabin-reflect 9s ease-in-out infinite alternate}
@keyframes cabin-reflect{from{transform:translate3d(-1.8vw,.6vh,0)}to{transform:translate3d(1.8vw,-.6vh,0)}}

/* =========================================================================================================
   03 TOKYO · HANEDA T3 ARRIVALS (public side) — rhythm told by light, never by moving people or signs:
   daylight at the end of the hall swells and eases, shadows of people walking by the windows cross the sunlit
   floor, an escalator handrail gleam travels, the counter's floor reflection is briefly occluded.
   Cue sheet: 1.5 s daylight swell (20 s cycle) · 3 s first floor shadow (14 s) · 8.5 s second (15.5 s) ·
   escalator gleam 3.2 s loop · 6 s counter-reflection occlusion (17 s). The hanging boards stay blank.
   ========================================================================================================= */
.hnd-daylight{left:39%;top:29%;width:24%;height:28%;background:radial-gradient(closest-side,#fff6e0 0%,#fff1d470 35%,#fff1d400 100%)}
.scene-airport[data-life="live"] .hnd-daylight{animation:hnd-daylight 20s ease-in-out 1.5s infinite both}
@keyframes hnd-daylight{0%{opacity:0}18%{opacity:.42}45%{opacity:.42}70%,100%{opacity:0}}
/* long low-sun shadows: soft, elongated toward the camera, no figure outline */
.hnd-passer{left:88%;top:62%;width:16%;height:5%;background:radial-gradient(closest-side,#0d0904 0%,#0d090480 45%,#0d090400 100%);transform-origin:50% 50%}
.scene-airport[data-life="live"] .hnd-passer{animation:hnd-passer 14s cubic-bezier(.3,0,.7,1) 3s infinite both}
.scene-airport[data-life="live"] .hnd-passer-2{top:66%;animation-duration:15.5s;animation-delay:8.5s}
@keyframes hnd-passer{
 0%{opacity:0;transform:translate3d(0,0,0) rotate(-9deg)}
 6%{opacity:.34}
 38%{opacity:.34}
 46%,100%{opacity:0;transform:translate3d(-170%,130%,0) rotate(-9deg)}}
/* escalator handrail: a highlight travelling down the moving rail */
.hnd-rail{left:calc(73.6% - .7 * var(--u));top:calc(53.6% - .4 * var(--u));width:calc(1.4 * var(--u));height:calc(.8 * var(--u));background:radial-gradient(closest-side,#fff8e8 0%,#fff8e800 100%)}
.scene-airport[data-life="live"] .hnd-rail{animation:hnd-rail 3.2s linear .8s infinite both}
@keyframes hnd-rail{0%{opacity:0;transform:translate3d(0,0,0)}20%{opacity:.8}80%{opacity:.8}100%{opacity:0;transform:translate3d(calc(4 * var(--u)),calc(2.5 * var(--u)),0)}}
/* the counter's warm reflection on the polished floor, briefly occluded by someone passing in front of it */
.hnd-counter{left:2%;top:67%;width:30%;height:9%;background:radial-gradient(ellipse 18% 70% at 50% 50%,#0c0804b0 0%,#0c080400 100%)}
.scene-airport[data-life="live"] .hnd-counter{animation:hnd-counter 17s ease-in-out 6s infinite both}
@keyframes hnd-counter{0%{opacity:0;transform:translate3d(-30%,0,0)}5%{opacity:.5}17%{opacity:.5}22%,100%{opacity:0;transform:translate3d(32%,0,0)}}

/* =========================================================================================================
   04 TOKYO · MINATO SKYLINE FROM SHIBUYA STREAM (v4.2: one credited real photograph, David Kernan, CC BY 4.0)
   Authored ARRIVAL, then rest = the unaltered photograph. Nothing is added to the picture: no new lights, no
   people, no signage, no tint. Every layer is a DARKENING veil that starts present and only lifts away, so what
   appears is the photograph's own light.
   v4.3 polish (seen in headless captures): the v4.2 tower ellipse and the lighter dusk grade above it read as a
   dark smudge hanging round a still-dim tower on the flat night sky. Both are gone. All veils now span the full
   width of the picture with horizontal edges only, so no localized shape or halo can form in the sky.
   Cue sheet (from the start of the passage, "arriving" — so it is already under way as the camera lands):
   0 s the whole frame is a little under-exposed and comes up to the photograph (1.6 s, once; .minor) ·
   0.35 s the skyline veil sweeps down while it lifts: the tallest lights (the Azabudai tower crown, the tower's
   spire) come up first, then the tower's deck and legs, then the streets (3.4 s, once) · 1.9 s the UI seam on
   the comparison action draws itself (1.4 s, once). After ≈3.8 s nothing in the picture moves except the v3
   resting drift (amb-pan 28 s). Re-entry restarts the sequence (scene-life.js).
   ========================================================================================================= */
.tky-night{inset:0;background:#02060c}
.scene-tokyo:is([data-life="arriving"],[data-life="live"]) .tky-night{animation:tky-night 1.6s cubic-bezier(.3,0,.3,1) 0s 1 both}
@keyframes tky-night{from{opacity:.42}to{opacity:0}}
/* skyline veil: transparent above the skyline, a soft horizontal ramp from the tallest roofs (≈26 %) down past
   the tower's deck, opaque below. It moves down while it fades, so the ramp passes over the city top-down. */
.tky-city{left:0;top:24%;width:100%;height:100%;background:linear-gradient(180deg,#03080f00 0%,#03080f9e 14%,#03080fe0 30%,#03080fe8 100%)}
.scene-tokyo:is([data-life="arriving"],[data-life="live"]) .tky-city{animation:tky-city 3.4s cubic-bezier(.35,0,.25,1) .35s 1 both}
@keyframes tky-city{0%{opacity:.9;transform:translate3d(0,0,0)}50%{opacity:.62;transform:translate3d(0,14%,0)}100%{opacity:0;transform:translate3d(0,30%,0)}}
/* UI, not picture: the gold-coloured seam in the comparison action draws once (static = fully drawn) */
.scene-tokyo:is([data-life="arriving"],[data-life="live"]) .tky-seam path{animation:tky-seam 1.4s cubic-bezier(.5,0,.2,1) 1.9s 1 both}
@keyframes tky-seam{from{stroke-dashoffset:1}to{stroke-dashoffset:0}}

/* =========================================================================================================
   05 A TABLE — the dish is set down: the server's shade withdraws back over the counter while the camera
   settles, the broth's surface shivers and goes still, warm table light gathers, steam begins to rise; outside
   the window a car's headlight sweeps the wet glass. Cue sheet (from the start of the passage, "arriving"):
   0.35 s shade withdraws (1.5 s, once) · 1.0 s broth settles (2.4 s, once) · 0.6 s table light (2.2 s, stays)
   · live: 1.2 s steam A (5.6 s loop) · 4.0 s steam B · 7 s window headlight (11 s). No menu, price or venue.
   ========================================================================================================= */
.food-serve{left:50%;top:26%;width:44%;height:56%;background:radial-gradient(ellipse 50% 50% at 52% 56%,#060302d0 0%,#06030270 46%,#06030200 78%)}
/* v4.5: slower and weaker (was .62 over 1.5 s with a front-loaded curve, which lifted the whole bowl area in the
   first ~0.3 s after arrival and read as a flash) */
.scene-food:is([data-life="arriving"],[data-life="live"]) .food-serve{animation:food-serve 2.8s cubic-bezier(.45,0,.35,1) .35s 1 both}
@keyframes food-serve{from{opacity:.34;transform:translate3d(0,0,0) scale(1)}to{opacity:0;transform:translate3d(6%,-34%,0) scale(.86)}}
/* v4.1 settling beat: the broth inside the rim (clip = inner rim ellipse of the pictured bowl) sloshes side to
   side with decaying swing, two rings spread from where it was jolted, then the surface goes still */
.food-surface{left:51.5%;top:41%;width:34.5%;height:16.5%;border-radius:50%;overflow:hidden}
.food-surface>*{position:absolute;display:block}
.food-slosh{left:-30%;top:0;width:160%;height:100%;background:radial-gradient(ellipse 20% 34% at 30% 40%,#fff3d0d0 0%,#ffe9b860 40%,#ffe9b800 100%),radial-gradient(ellipse 14% 22% at 72% 66%,#fff3d0a0 0%,#fff3d000 100%)}
.scene-food:is([data-life="arriving"],[data-life="live"]) .food-slosh{animation:food-slosh 3.4s cubic-bezier(.3,.2,.4,1) .7s 1 both}
/* v4.5: one slow swell and settle (was a five-swing slosh peaking at .95 within 0.17 s, i.e. a bright blob jumping
   left and right: it read as flicker) */
@keyframes food-slosh{0%{opacity:0;transform:translate3d(0,0,0)}30%{opacity:.36;transform:translate3d(5%,0,0)}100%{opacity:0;transform:translate3d(-2%,0,0)}}
.food-ring{left:calc(13% - 5 * var(--u));top:calc(42% - 1.6 * var(--u));width:calc(10 * var(--u));height:calc(3.2 * var(--u));background:radial-gradient(closest-side,#fff0c800 55%,#fff4d8c0 68%,#fff0c840 78%,#fff0c800 90%)}
.food-ring-2{left:calc(82% - 5 * var(--u));top:calc(66% - 1.6 * var(--u))}
.scene-food:is([data-life="arriving"],[data-life="live"]) .food-ring{animation:food-ring 2.2s cubic-bezier(.1,.6,.3,1) .75s 1 both}
.scene-food:is([data-life="arriving"],[data-life="live"]) .food-ring-2{animation-delay:1.15s}
@keyframes food-ring{0%{opacity:0;transform:scale(.1)}30%{opacity:.4}100%{opacity:0;transform:scale(1.7)}}
/* lacquered chopsticks (original SVG, same red as the pictured spoon) set down beside the bowl from the
   viewer's side once the broth is still; they stay. A contact shadow is part of the drawing. */
.food-hashi{left:calc(38% - 11 * var(--u));top:calc(66% - 1.4 * var(--u));width:calc(22 * var(--u));height:calc(2.8 * var(--u));background:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 300 40'%3E%3Cdefs%3E%3ClinearGradient id='a' x2='0' y2='1'%3E%3Cstop offset='0' stop-color='%23e0664c'/%3E%3Cstop offset='.4' stop-color='%23861a12'/%3E%3Cstop offset='1' stop-color='%232c0503'/%3E%3C/linearGradient%3E%3Cfilter id='b'%3E%3CfeGaussianBlur stdDeviation='2.6'/%3E%3C/filter%3E%3C/defs%3E%3Cpath d='M6 30L296 26V36L6 34Z' opacity='.6' filter='url(%23b)'/%3E%3Cpath d='M4 17L294 9V13L4 22Z' fill='url(%23a)'/%3E%3Cpath d='M8 25L298 17V21L8 30Z' fill='url(%23a)'/%3E%3Cpath d='M240 11L294 9V10L240 12Z' fill='%23f3d9b0' opacity='.5'/%3E%3C/svg%3E") 0 0/100% 100% no-repeat;transform-origin:70% 50%}
.scene-food:is([data-life="arriving"],[data-life="live"]) .food-hashi{animation:food-hashi 1.1s cubic-bezier(.2,.7,.2,1) 1.9s 1 both}
@keyframes food-hashi{0%{opacity:0;transform:translate3d(calc(-1.5 * var(--u)),calc(5 * var(--u)),0) rotate(-17deg) scale(1.08)}35%{opacity:1}80%{transform:translate3d(0,calc(-.25 * var(--u)),0) rotate(-7.5deg) scale(1)}100%{opacity:1;transform:translate3d(0,0,0) rotate(-8deg) scale(1)}}
.food-table{left:42%;top:56%;width:56%;height:32%;background:radial-gradient(ellipse 50% 50% at 50% 46%,#ffb4603a 0%,#ffb46000 74%)}
.scene-food:is([data-life="arriving"],[data-life="live"]) .food-table{animation:food-table 2.2s ease-out .6s 1 both}
@keyframes food-table{from{opacity:0}to{opacity:1}}
/* v4.1 steam: drawn curling wisps (original SVG, static blur) rising off the broth and leaning toward the
   window draught; warm-white so it reads against the dark kitchen at full-screen size */
.food-steam{left:calc(66% - 6 * var(--u));top:3%;width:calc(12 * var(--u));height:40%;transform-origin:50% 100%;background:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 200'%3E%3Cfilter id='b' x='-50%25' y='-10%25' width='200%25' height='120%25'%3E%3CfeGaussianBlur stdDeviation='3.2'/%3E%3C/filter%3E%3Cg fill='none' stroke='%23fff4e6' stroke-linecap='round' filter='url(%23b)'%3E%3Cpath d='M48 198C34 170 64 152 50 126S28 86 47 62 68 28 55 6' stroke-width='9' opacity='.7'/%3E%3Cpath d='M60 196C72 170 46 150 60 122S80 88 63 64' stroke-width='5' opacity='.55'/%3E%3Cpath d='M38 194C30 176 44 160 36 142' stroke-width='6' opacity='.5'/%3E%3C/g%3E%3C/svg%3E") 0 0/100% 100% no-repeat}
.scene-food[data-life="live"] .food-steam{animation:food-steam 6.4s cubic-bezier(.25,.4,.45,1) .9s infinite both}
.scene-food[data-life="live"] .food-steam-2{left:calc(71% - 6 * var(--u));animation-delay:4.1s;animation-duration:7.2s}
@keyframes food-steam{0%{opacity:0;transform:translate3d(0,20%,0) scale(.6,.55) rotate(0)}18%{opacity:.95}55%{opacity:.7;transform:translate3d(calc(.8 * var(--u)),-4%,0) scale(1,1) rotate(3deg)}100%{opacity:0;transform:translate3d(calc(2.6 * var(--u)),-26%,0) scale(1.45,1.2) rotate(7deg)}}
.food-car{left:83.5%;top:3%;width:16.5%;height:34%;overflow:hidden;opacity:1}
.food-car::before{content:"";position:absolute;top:0;bottom:0;left:-60%;width:60%;opacity:0;background:linear-gradient(90deg,#fff2d000 0%,#fff2d040 45%,#fffbe866 50%,#fff2d040 55%,#fff2d000 100%)}
.scene-food[data-life="live"] .food-car::before{animation:food-car 11s cubic-bezier(.5,0,.5,1) 7s infinite both}
@keyframes food-car{0%{opacity:0;transform:translate3d(0,0,0)}8%{opacity:.55}24%{opacity:.55}32%,100%{opacity:0;transform:translate3d(270%,0,0)}}

/* =========================================================================================================
   06 TOKYO → KYOTO BY RAIL — three speeds that belong to three distances, plus the glass itself:
   far: a cloud's shade drifts over the hills very slowly (no scrolling of the mountains) · mid: sun glitter on
   the river · near (v3): verge grass rush · once per 19 s a soft overpass shade (max .2, ~3 s) sweeps the window
   and, because it is darker outside for a moment, the carriage's reflection in the glass rises with it (same
   cue). Carriage rhythm = v3 amb-sway. The v4.0 lineside mast / post were removed in v4.4: they strobed.
   ========================================================================================================= */
.fx-rail{inset:0;overflow:hidden}
.rail-mast{top:-4%;bottom:-4%;left:0;width:5.5vw;opacity:0;background:linear-gradient(90deg,#08100c00 0%,#08100cb0 30%,#030605e6 50%,#08100cb0 70%,#08100c00 100%)}
/* v4.4: the lineside mast (2.9 s) and the thinner post (6.1 s) were near-black bars crossing the whole window in
   0.2-0.5 s. Measured in headless Chrome they strobed the scene (and were reported as flicker), so they stay
   un-animated and invisible here. The elements remain only so the markup is unchanged. */
.rail-mast-2{width:2.2vw;top:18%;background:linear-gradient(90deg,#0a140f00 0%,#0a140f80 50%,#0a140f00 100%)}
.rail-overpass{top:-4%;bottom:-4%;left:0;width:64vw;opacity:0;background:linear-gradient(90deg,#02050800 0%,#020508c0 18%,#020508cc 82%,#02050800 100%)}
.scene-rail[data-life="live"] .rail-overpass{animation:rail-overpass 19s linear 7s infinite both}
/* v4.4: a soft shade, not a dark wipe: max .2 (was .55) over ~3 s (was ~1 s) */
@keyframes rail-overpass{0%{opacity:.2;transform:translate3d(104vw,0,0)}16%{opacity:.2;transform:translate3d(-70vw,0,0)}16.1%,100%{opacity:0;transform:translate3d(-70vw,0,0)}}
.rail-reflect{inset:0;opacity:.35;background:linear-gradient(0deg,#cfe3ff1c 0%,#cfe3ff00 34%),radial-gradient(ellipse 30% 46% at 16% 78%,#e7f0ff1a,#e7f0ff00 70%),linear-gradient(112deg,#ffffff00 52%,#ffffff14 57%,#ffffff00 62%)}
.scene-rail[data-life="live"] .rail-reflect{animation:rail-reflect 19s linear 7s infinite both}
@keyframes rail-reflect{0%,2%{opacity:.35}6%,11%{opacity:.55}16%,100%{opacity:.35}}
.rail-river{left:84%;top:56%;width:16%;height:12%;background:repeating-linear-gradient(0deg,#fffbe800 0,#fffbe800 .5vh,#fffbe866 .65vh,#fffbe800 .85vh);-webkit-mask-image:radial-gradient(ellipse 50% 50% at 60% 50%,#000 25%,#0000 100%);mask-image:radial-gradient(ellipse 50% 50% at 60% 50%,#000 25%,#0000 100%)}
.scene-rail[data-life="live"] .rail-river{animation:sea-glitter 1.9s ease-in-out .6s infinite alternate both}
.rail-cloud{left:46%;top:18%;width:46%;height:24%;background:radial-gradient(ellipse 50% 50% at 50% 50%,#0a1a2a40 0%,#0a1a2a00 72%)}
.scene-rail[data-life="live"] .rail-cloud{animation:rail-cloud 30s ease-in-out 1s infinite alternate both}
@keyframes rail-cloud{from{opacity:.25;transform:translate3d(0,0,0)}to{opacity:.6;transform:translate3d(-40%,4%,0)}}

/* =========================================================================================================
   07 KYOTO — after the noren passage (v3, controller): leaf-filtered sun moves on the work table, a light runs
   along the gold seam of the mended bowl already in the picture, and the garden beyond the door brightens and
   dims as the canopy moves. Mood only: no class, booking, price or Tokyo workshop fact is implied.
   Cue sheet: 0.6 s dapple A/B/C (7 / 9.5 / 11 s alternate) · 2.2 s gold-seam glint (12 s cycle) · garden 6 s.
   ========================================================================================================= */
.kyo-dapple{background:radial-gradient(closest-side,#ffe2a07a 0%,#ffd88a33 50%,#ffd88a00 100%);opacity:0}
.kyo-d1{left:calc(51% - 5 * var(--u));top:calc(53% - 1.5 * var(--u));width:calc(10 * var(--u));height:calc(3 * var(--u))}
.kyo-d2{left:calc(63% - 6.5 * var(--u));top:calc(63% - 2 * var(--u));width:calc(13 * var(--u));height:calc(4 * var(--u))}
.kyo-d3{left:calc(80% - 6 * var(--u));top:calc(71% - 2 * var(--u));width:calc(12 * var(--u));height:calc(3.6 * var(--u))}
.scene-kyoto[data-life="live"] .kyo-d1{animation:kyo-dapple 7s ease-in-out .6s infinite alternate both}
.scene-kyoto[data-life="live"] .kyo-d2{animation:kyo-dapple 9.5s ease-in-out 1.4s infinite alternate-reverse both}
.scene-kyoto[data-life="live"] .kyo-d3{animation:kyo-dapple 11s ease-in-out 2.1s infinite alternate both}
@keyframes kyo-dapple{from{opacity:.15;transform:translate3d(calc(-1 * var(--u)),0,0) scale(.92)}45%{opacity:.7}to{opacity:.3;transform:translate3d(calc(1.2 * var(--u)),calc(.3 * var(--u)),0) scale(1.06)}}
.kyo-gold{left:calc(66.8% - .9 * var(--u));top:calc(45.6% - .9 * var(--u));width:calc(1.8 * var(--u));height:calc(1.8 * var(--u));background:radial-gradient(closest-side,#fffbe6 0%,#ffe08a90 30%,#ffd07000 100%)}
.scene-kyoto[data-life="live"] .kyo-gold{animation:kyo-gold 12s cubic-bezier(.4,0,.6,1) 2.2s infinite both}
/* v4.5: a slow sheen along the seam (was a point that lit 0 -> .9 in 0.36 s and vanished in ~1.5 s every 12 s: a twinkle) */
@keyframes kyo-gold{0%{opacity:0;transform:translate3d(0,0,0)}16%{opacity:.5}34%{opacity:.5;transform:translate3d(calc(1.6 * var(--u)),calc(2.2 * var(--u)),0)}58%,100%{opacity:0;transform:translate3d(calc(1.8 * var(--u)),calc(2.4 * var(--u)),0)}}
.kyo-garden{left:19%;top:30%;width:28%;height:32%;background:radial-gradient(ellipse 50% 50% at 50% 55%,#f6ffcf40 0%,#f6ffcf00 72%)}
.scene-kyoto[data-life="live"] .kyo-garden{animation:kyo-garden 6s ease-in-out .9s infinite alternate both}
@keyframes kyo-garden{from{opacity:.1}to{opacity:.6}}

/* =========================================================================================================
   08 NIGHTFALL — the day settles before the choice: ripples keep breaking the reflections, a few lit windows
   across the river go dark one by one (their reflections dim with them), the railing lantern breathes.
   Cue sheet: water continuous (seamless, period-length loops) · 5 s first windows out (stays) · 5.25 s its
   reflection dims · 11 s second windows out · lantern 3.6 s alternate. Copy and CTA stay above (z-index 3).
   ========================================================================================================= */
.water-clip{left:0;top:44%;width:100%;height:44%;overflow:hidden;-webkit-mask-image:linear-gradient(180deg,#0000 0%,#000 14%);mask-image:linear-gradient(180deg,#0000 0%,#000 14%)}
.ngt-shimmer{left:0;right:0;top:-6%;bottom:-6%;opacity:1;background:repeating-linear-gradient(0deg,#02061000 0,#02061000 .9vh,#0206103d 1.1vh,#02061000 1.4vh)}
.scene-night[data-life="live"] .ngt-shimmer{animation:ngt-shimmer 2.4s linear infinite both}
.ngt-shimmer-2{background:repeating-linear-gradient(0deg,#ffe6c000 0,#ffe6c000 1.6vh,#ffe6c014 1.75vh,#ffe6c000 2.1vh)}
.scene-night[data-life="live"] .ngt-shimmer-2{animation:ngt-shimmer-2 3.9s linear infinite both}
@keyframes ngt-shimmer{from{transform:translate3d(0,0,0)}to{transform:translate3d(0,1.4vh,0)}}
@keyframes ngt-shimmer-2{from{transform:translate3d(0,0,0)}to{transform:translate3d(0,2.1vh,0)}}
.ngt-out{background:radial-gradient(closest-side,#120a14e0 0%,#120a14a0 60%,#120a1400 100%)}
.ngt-out-1{left:21.2%;top:22.8%;width:7.4%;height:6%}
.ngt-out-2{left:75%;top:29%;width:5.6%;height:4.2%}
.scene-night[data-life="live"] .ngt-out-1{animation:ngt-out 1.4s ease-out 5s 1 both}
.scene-night[data-life="live"] .ngt-out-2{animation:ngt-out 1.4s ease-out 11s 1 both}
@keyframes ngt-out{0%{opacity:0}30%{opacity:.4}38%{opacity:.25}100%{opacity:.68}}
.ngt-out-wet{left:20.5%;top:49%;width:9%;height:22%;background:linear-gradient(180deg,#05101e00 0%,#05101e8c 30%,#05101e60 70%,#05101e00 100%)}
.scene-night[data-life="live"] .ngt-out-1w{animation:ngt-out 1.6s ease-out 5.25s 1 both}
.ngt-lantern{left:91%;top:61%;width:9%;height:21%;background:radial-gradient(closest-side,#ffc4708a 0%,#ffb05a30 50%,#ffb05a00 100%)}
.scene-night[data-life="live"] .ngt-lantern{animation:ngt-lantern 3.6s ease-in-out .4s infinite alternate both}
@keyframes ngt-lantern{0%{opacity:.35}30%{opacity:.6}48%{opacity:.45}74%{opacity:.7}100%{opacity:.5}}

/* ---------- phones: two events per chapter, no secondary layers ---------- */
@media(max-width:650px){
 .life .minor,.fx-rail .minor{display:none}
}
/* ---------- reduced motion: still compositions (JS also sets data-life="off") ---------- */
@media(prefers-reduced-motion:reduce){
 .life,.fx-rail,.fx-bloom,.glass-mullions{display:none!important}
 .glass-sheen,.cabin-reflect{animation:none!important}
}
