/* Tàu vượt ga (tau.js): the tunnel on top, the question below. Everything that moves moves by transform or opacity.
   --ln/--lnd: the line of the station the train goes to, set inline. */
.tv { --l: var(--ln); --lf: var(--lnf, var(--ln)); --lt: var(--lnt, #fff); --lb: var(--lnd, var(--ln));
  --mt-card: var(--card, var(--paper, #fff)); --mt-ink: var(--ink, #1B201C); --tv-lip: #E0D8C7;
  position: fixed; inset: 0; z-index: 40; display: flex; flex-direction: column; max-width: 600px; margin: 0 auto;
  background: var(--bg, #F4F1E9); overflow: hidden; touch-action: manipulation; -webkit-user-select: none; user-select: none; -webkit-tap-highlight-color: transparent; }
html[data-theme="dark"] .tv { --tv-lip: rgba(0, 0, 0, .45); --l: var(--lnd); --lf: var(--lndf, var(--lnd)); --lt: var(--lndt, #fff); }
.tv-defs { position: absolute; width: 0; height: 0; }

/* ---------- the scene ---------- */
.tv-scene { --g: 18px; position: relative; flex: none; height: clamp(250px, 40dvh, 340px); overflow: hidden; isolation: isolate; background: #1C2534; }
.tv-cam { position: absolute; inset: 0; }
/* the last seconds: the edges glow red */
.tv-scene::after { content: ''; position: absolute; inset: 0; z-index: 11; pointer-events: none; opacity: 0; box-shadow: inset 0 0 70px rgba(255, 64, 40, .6); transition: opacity .3s; }
.tv.hot .tv-scene::after { animation: tv-hot .5s ease-in-out infinite alternate; }
@keyframes tv-hot { from { opacity: .35; } to { opacity: 1; } }
.tv-bg { position: absolute; inset: 0; background: radial-gradient(120% 85% at 50% 18%, #3B4D6B, #232E41 58%, #161D29); }
.tv-loop { position: absolute; left: 0; bottom: 0; height: 360px; background-repeat: repeat-x; background-position: left bottom; will-change: transform; pointer-events: none; }
.tv-far, .tv-mid { z-index: 1; }
.tv-rails { z-index: 3; height: calc(76px + var(--g)); }
.tv-wind { z-index: 9; opacity: 0; transition: opacity .5s; }
.tv.fast .tv-wind { opacity: .6; }

/* a station: the wall across the track, and the floor of the platform in front (both slide as one) */
.tv-pwall { position: absolute; left: 0; top: 0; bottom: 0; z-index: 2; width: calc(100% + 280px); will-change: transform;
  background: linear-gradient(#D8CFBE, #CBC1AE) 0 0 / 100% 44px no-repeat,
    linear-gradient(var(--l), var(--l)) 0 calc(100% - 164px) / 100% 8px no-repeat,
    repeating-linear-gradient(90deg, transparent 0 39px, rgba(120, 100, 70, .1) 39px 40px),
    repeating-linear-gradient(0deg, transparent 0 23px, rgba(120, 100, 70, .08) 23px 24px),
    linear-gradient(#F7F2E8, #E6DDCB);
  box-shadow: inset 36px 0 30px -22px rgba(10, 14, 22, .7), inset -36px 0 30px -22px rgba(10, 14, 22, .7); }
.tv-pwall::before { content: ''; position: absolute; left: 0; right: 0; top: 34px; height: 5px; background: repeating-linear-gradient(90deg, #FFFCEB 0 70px, transparent 70px 120px); box-shadow: 0 3px 10px rgba(255, 240, 200, .6); }
.tv-board { position: absolute; bottom: 190px; display: flex; flex-direction: column; align-items: center; gap: 3px; transform: translateX(-50%); white-space: nowrap; }
.tv-bd-pill { display: flex; align-items: center; gap: 7px; padding: 4px 14px 4px 4px; border: 4px solid var(--l); border-radius: 999px; background: #fff; box-shadow: 0 4px 10px -4px rgba(60, 40, 10, .35); }
.tv-bd-pill b { font: 800 21px/1.15 var(--kr-sans, system-ui), sans-serif; letter-spacing: -.03em; color: #1B201C; }
.tv-bd-pill .mt-code { height: 26px; min-width: 26px; border: 0; background: var(--lf); color: var(--lt); }
.tv-board small { font-size: 13px; font-weight: 800; color: #5F5646; }
.tv-poster { position: absolute; bottom: 194px; width: 32px; height: 44px; border-radius: 6px; background: linear-gradient(160deg, #FFD9A0, #F59BB8); box-shadow: 0 0 0 3px #fff, 0 5px 10px -3px rgba(60, 40, 10, .35); }
.tv-poster::after { content: ''; position: absolute; left: 7px; right: 7px; top: 9px; height: 13px; border-radius: 50%; background: rgba(255, 255, 255, .75); }
.tv-poster.b { background: linear-gradient(160deg, #A6E6D2, #79BDF2); }
.tv-pfloor { position: absolute; left: 0; bottom: 0; z-index: 7; width: calc(100% + 280px); height: calc(46px + var(--g)); will-change: transform;
  background: linear-gradient(#F3EDE1 0 4px, #CFC4B0 4px 5px, transparent 5px),
    radial-gradient(circle, rgba(110, 80, 0, .4) 1.3px, transparent 1.8px) 0 8px / 6px 5px repeat-x,
    linear-gradient(transparent 6px, #F2C21B 6px 18px, transparent 18px),
    linear-gradient(#E6DECE, #C9BDA6);
  box-shadow: inset 36px 0 26px -22px rgba(10, 14, 22, .6), inset -36px 0 26px -22px rgba(10, 14, 22, .6), 0 -1px 0 rgba(0, 0, 0, .12); }
.tv-pfloor::after { content: ''; position: absolute; left: 0; right: 0; top: 8px; height: 5px; background: radial-gradient(circle, rgba(110, 80, 0, .4) 1.3px, transparent 1.8px) 0 0 / 6px 5px repeat-x; }

/* ---------- the train ---------- */
.tv-train { position: absolute; left: 0; bottom: calc(var(--g) + 26px); z-index: 5; height: 102px; will-change: transform; pointer-events: none; }
.tv-car { position: absolute; bottom: 0; width: 84px; height: 90px; transition: transform .45s cubic-bezier(.3, 1.3, .5, 1); }
.tv-car.tv-cab { width: 122px; height: 102px; }
.tv-lift { height: 100%; transition: transform .36s cubic-bezier(.35, 1.45, .55, 1); }
.tv-bob { position: relative; height: 100%; animation: tv-rumble .44s linear infinite paused; }
.tv.run .tv-bob { animation-play-state: running; }
.tv-bob > svg { display: block; overflow: visible; }
@keyframes tv-rumble { 0%, 100% { transform: none; } 30% { transform: translateY(-1.2px); } 65% { transform: translateY(.4px); } }
.tv .tb { fill: url(#tvB); } .tv .tr { fill: #D2CABA; } .tv .tt { fill: #fff; opacity: .8; } .tv .tu { fill: #39414A; }
.tv .tw { fill: url(#tvW); } .tv .twh { fill: #AEB7BE; } .tv .ln { fill: var(--l); } .tv .lnd { fill: color-mix(in srgb, var(--l) 62%, #0B1220); }
.tv .tg { fill: url(#tvG); } .tv .tgl { fill: #fff; opacity: .26; } .tv .td { fill: #EEE9E0; stroke: #CBC2B1; stroke-width: 1; } .tv .tdi { fill: #FFE3A3; }
.tv .tfr { fill: #22324A; stroke: #C2B8A5; stroke-width: 2.4; stroke-linejoin: round; }
.tv .tp { fill: none; stroke: #4B535B; stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round; }
.tv-dl, .tv-dr { transition: transform .5s cubic-bezier(.5, 0, .3, 1); }
.tv-train.open .tv-dl { transform: translateX(-9px); }
.tv-train.open .tv-dr { transform: translateX(9px); }
/* the windscreen: Nếp in the driver's seat, the dashboard in front of him, the glass over */
.tv-win { position: absolute; left: 51px; top: 22px; width: 61px; height: 40px; overflow: hidden; border-radius: 2px 21px 2px 2px; background: linear-gradient(#34496A, #1C2A3F); }
.tv-seat { position: absolute; left: 50%; top: 7px; width: 42px; height: 40px; margin-left: -21px; border-radius: 13px 13px 4px 4px; background: color-mix(in srgb, var(--l) 72%, #0E1A2C); }
.tv-pilot { position: absolute; left: 50%; top: -7px; width: 54px; margin-left: -27px; }
.tv-pilot .nd { width: 54px; }
.tv-dash { position: absolute; left: 0; right: 0; bottom: 0; height: 9px; border-top: 1.5px solid #6A7686; background: linear-gradient(#3B4757, #212A35); }
.tv-dash::before { content: ''; position: absolute; left: 9px; top: 2.5px; width: 3px; height: 3px; border-radius: 50%; background: #5BF0A0; box-shadow: 7px 0 #FFD45C, 14px 0 #5BC8FF, 32px 0 #FF7A6B; }
.tv-glass { position: absolute; inset: 0; pointer-events: none; background: linear-gradient(115deg, rgba(255, 255, 255, .3) 0 16%, transparent 16% 58%, rgba(255, 255, 255, .12) 58% 64%, transparent 64%); }
.tv-beam { position: absolute; left: 117px; bottom: -14px; width: 180px; height: 80px; pointer-events: none; transition: opacity .6s;
  background: linear-gradient(90deg, rgba(255, 238, 170, .5), rgba(255, 238, 170, 0) 85%); clip-path: polygon(0 47%, 100% 0, 100% 100%, 0 57%); }
.tv:not(.on) .tv-beam, .tv.atst .tv-beam { opacity: .25; }

/* ---------- the monster ---------- */
.tv-mon { position: absolute; left: 0; bottom: calc(var(--g) + 27px); z-index: 6; width: 76px; height: 93px; will-change: transform; pointer-events: none; }
.tv-mon.t1 { z-index: 4; }
.tv-mon[hidden] { display: none; }
.tv-msh { position: absolute; left: 6px; right: 6px; bottom: -5px; height: 11px; border-radius: 50%; background: radial-gradient(closest-side, rgba(0, 0, 0, .45), transparent); }
.tv-min { position: absolute; inset: 0; transform-origin: 50% 100%; }

/* Its body moves on .tv-mbob (HTML, so on the compositor), its parts in the SVG (tau.js tauMon) a little on top.
   s0 the grumpy stomper, s1 the jittery one, s2 the smug swayer, s3 the bouncy one. tease: half the time gone;
   taunt: the last 3 s; ent: coming on, act: hit or dodged (tau.js moves it then, its own moves stop). */
.tv-m .tv-mbob { width: 100%; height: 100%; transform-origin: 50% 100%; }
.tv-m svg { display: block; width: 100%; height: 100%; overflow: visible; }
.tv-m .mb { fill: #FF7FA0; opacity: .55; }
.tv-m .mp { fill: #2B2230; }
.tv-m .mh { fill: url(#tvH); }
.tv-m .ml { fill: none; stroke: #3B2530; stroke-width: 3.2; stroke-linecap: round; stroke-linejoin: round; }
.tv-m .mbr { fill: none; stroke: #3B2530; stroke-width: 3; stroke-linecap: round; opacity: .8; }
.tv-m :is(.mfl, .mfr, .mal, .mar, .mh1, .mh2, .mant, .mey, .mpp, .mtg, .msw, .msp) { transform-box: fill-box; }
.tv-m :is(.mfl, .mfr, .mh1, .mh2) { transform-origin: 50% 100%; }
/* an arm hangs from its shoulder, just inside the body's edge: + swings the near one out and up, - the far one */
.tv-m :is(.mal, .mar) { transform-origin: 50% 0; }
.tv-m .mant { transform-origin: 8% 94%; }
.tv-m :is(.mey, .msp) { transform-origin: 50% 50%; }
.tv-m .mtg { transform-origin: 50% 0; }
/* the face turns to the train as it comes (--near, 0 to 1, set by the clock) */
.tv-m .mturn { transform: translateX(calc(var(--near, 0) * -3.5px)); transition: transform .4s; }
/* one face at a time */
.tv-m .fc, .tv-m .msw { display: none; }
.tv-m[data-f="idle"] .fc-idle, .tv-m[data-f="tease"] .fc-tease, .tv-m[data-f="mad"] .fc-mad, .tv-m[data-f="panic"] .fc-panic, .tv-m[data-f="uhoh"] .fc-uhoh,
.tv-m[data-f="oh"] .fc-oh, .tv-m[data-f="joy"] .fc-joy, .tv-m[data-f="oof"] .fc-oof, .tv-m[data-f="dizzy"] .fc-dizzy { display: inline; }
.tv-m.sweat .msw { display: inline; animation: tv-sweat .8s ease-in infinite; }
.tv-m .msp { animation: tv-spin .7s linear infinite; }
@keyframes tv-sweat { 0% { opacity: 0; transform: translate(-3px, -4px) scale(.5); } 25% { opacity: 1; transform: none; } 100% { opacity: 0; transform: translate(3px, 12px) scale(.9); } }
@keyframes tv-spin { to { transform: rotate(360deg); } }

/* blinking, at its own pace (--bl, --bd: tau.js); the jittery one blinks twice */
.tv-m .mey { animation: tv-blink var(--bl, 3.8s) var(--bd, 0s) infinite; }
.tv-m.s1 .mey { animation-name: tv-blink2; }
@keyframes tv-blink { 0%, 93%, 99%, 100% { transform: none; } 96% { transform: scaleY(.08); } }
@keyframes tv-blink2 { 0%, 82%, 87%, 90%, 95%, 100% { transform: none; } 84.5%, 92.5% { transform: scaleY(.08); } }
/* the eyes: a look at the learner now and then, the jittery one's dart over its shoulder */
.tv-m:is(.s0, .s2) .mpp { animation: tv-glance 5.2s ease-in-out infinite; }
.tv-m.s0 .mpp { animation-duration: 6.4s; animation-delay: -2s; }
.tv-m.s1 .mpp { animation: tv-dart 2.4s infinite; }
.tv-m:is(.taunt, .act) .mpp { animation: none; }
@keyframes tv-glance { 0%, 58%, 90%, 100% { transform: none; } 63%, 85% { transform: translateX(3.4px); } }
@keyframes tv-dart { 0%, 55%, 100% { transform: none; } 58%, 63% { transform: translate(5.4px, -1px); } 66% { transform: translate(5.4px, 1.5px); } 70% { transform: translateX(1px); } 73% { transform: none; } }

/* s0, grumpy: stamps one foot then the other (a puff of dust each), its horns twitch */
.tv-m.s0 .tv-mbob { animation: tv-stomp 1.6s ease-in-out infinite; }
.tv-m.s0 .mfr { animation: tv-footr 1.6s ease-in-out infinite; }
.tv-m.s0 .mfl { animation: tv-footl 1.6s ease-in-out infinite; }
.tv-m.s0 .mal { animation: tv-armsw 1.6s ease-in-out infinite; }
.tv-m.s0 .mar { animation: tv-armsw 1.6s ease-in-out -.8s infinite; }
.tv-m.s0 .mh1 { animation: tv-twitch 3.4s infinite; }
.tv-m.s0 .mh2 { animation: tv-twitch 3.4s -1.3s infinite; }
.tv-m.s0 .tv-msh::before, .tv-m.s0 .tv-msh::after { content: ''; position: absolute; bottom: 1px; width: 16px; height: 10px; border-radius: 50%; background: #EDE6DA; opacity: 0;
  animation: tv-puffr 1.6s ease-out infinite; }
.tv-m.s0 .tv-msh::after { right: 0; }
.tv-m.s0 .tv-msh::before { left: 0; animation-name: tv-puffl; }
@keyframes tv-stomp { 0%, 32%, 50%, 82%, 100% { transform: none; } 12% { transform: translateY(-5px) rotate(-5deg); } 22% { transform: scale(1.08, .92); } 62% { transform: translateY(-5px) rotate(5deg); } 72% { transform: scale(1.08, .92); } }
@keyframes tv-footr { 0%, 22%, 100% { transform: none; } 12% { transform: translateY(-5px); } }
@keyframes tv-footl { 0%, 50%, 72%, 100% { transform: none; } 62% { transform: translateY(-5px); } }
@keyframes tv-armsw { 0%, 100% { transform: rotate(-8deg); } 50% { transform: rotate(8deg); } }
@keyframes tv-twitch { 0%, 86%, 100% { transform: none; } 89% { transform: rotate(-14deg); } 92% { transform: rotate(9deg); } 95% { transform: rotate(-4deg); } }
@keyframes tv-puffr { 0%, 21% { opacity: 0; transform: scale(.4); } 24% { opacity: .9; } 44%, 100% { opacity: 0; transform: translate(12px, -3px) scale(1.5); } }
@keyframes tv-puffl { 0%, 71% { opacity: 0; transform: scale(.4); } 74% { opacity: .9; } 94%, 100% { opacity: 0; transform: translate(-12px, -3px) scale(1.5); } }

/* s1, jittery: never still, a start now and then, its antenna on a spring */
.tv-m.s1 .tv-mbob { animation: tv-jit 2.4s linear infinite; }
.tv-m.s1 .mant { animation: tv-boing .62s ease-in-out infinite alternate; }
.tv-m.s1 :is(.mal, .mar) { animation: tv-shiver .16s linear infinite alternate; }
@keyframes tv-jit {
  0%, 28%, 52%, 72%, 92%, 100% { transform: none; }
  4%, 12%, 20%, 76%, 84% { transform: translateX(-.9px); } 8%, 16%, 24%, 80%, 88% { transform: translateX(.9px); }
  58% { transform: translateY(-11px) scale(.92, 1.1); } 64% { transform: scale(1.08, .93); } 68% { transform: translateY(-2px); } }
@keyframes tv-boing { from { transform: rotate(-9deg); } to { transform: rotate(11deg); } }
@keyframes tv-shiver { from { transform: rotate(-5deg); } to { transform: rotate(5deg); } }

/* s2, smug: sways from its feet, beckons the train on with the near hand */
.tv-m.s2 .tv-mbob { animation: tv-sway 2.8s ease-in-out infinite; }
.tv-m.s2 .mal { animation: tv-beckon 2.8s ease-in-out infinite; }
.tv-m.s2 .mh1 { animation: tv-sway 2.8s ease-in-out -.3s infinite; }
@keyframes tv-sway { 0%, 100% { transform: rotate(-4deg); } 50% { transform: rotate(4deg) scale(1.02, .98); } }
@keyframes tv-beckon { 0%, 40%, 100% { transform: none; } 50%, 70% { transform: rotate(75deg); } 60%, 80% { transform: rotate(40deg); } 90% { transform: rotate(70deg); } }

/* s3, bouncy: hops on the spot, squashing as it lands, arms up at the top (the shadow shrinks under it) */
.tv-m.s3 .tv-mbob { animation: tv-hop .9s infinite; }
.tv-m.s3 .tv-msh { animation: tv-hopsh .9s infinite; }
.tv-m.s3 .mal { animation: tv-flapl .9s ease-in-out infinite; }
.tv-m.s3 .mar { animation: tv-flapr .9s ease-in-out infinite; }
@keyframes tv-hop {
  0%, 100% { transform: scale(1.12, .88); animation-timing-function: ease-out; }
  14% { transform: translateY(-5px) scale(.92, 1.1); animation-timing-function: ease-out; }
  44% { transform: translateY(-22px) scale(.98, 1.02); animation-timing-function: ease-in; }
  76% { transform: translateY(-3px) scale(.93, 1.09); animation-timing-function: ease-in; }
  86% { transform: scale(1.16, .85); } }
@keyframes tv-hopsh { 0%, 86%, 100% { transform: none; opacity: 1; } 44% { transform: scale(.62); opacity: .55; } }
@keyframes tv-flapl { 0%, 86%, 100% { transform: rotate(-6deg); } 44% { transform: rotate(64deg); } }
@keyframes tv-flapr { 0%, 86%, 100% { transform: rotate(6deg); } 44% { transform: rotate(-64deg); } }

/* half the time gone: tongue out, and each its own taunt */
.tv-m.tease .mtg { animation: tv-wag .32s ease-in-out infinite alternate; }
.tv-m.s0.tease :is(.tv-mbob, .mfl, .mfr), .tv-m.s0.tease .tv-msh::before, .tv-m.s0.tease .tv-msh::after { animation-duration: .9s; }
.tv-m.s0.tease .mal { animation: tv-pump .3s ease-in-out infinite alternate; }
.tv-m.s0.tease .mar { animation: tv-pump2 .3s ease-in-out -.15s infinite alternate; }
.tv-m.s1.tease .tv-mbob { animation: tv-dance .56s ease-in-out infinite; }
.tv-m.s1.tease :is(.mal, .mar) { animation-duration: .1s; }
.tv-m.s2.tease .tv-mbob { animation: tv-wiggle .5s ease-in-out infinite; }
.tv-m.s2.tease .mal { animation: tv-nyahl .22s ease-in-out infinite alternate; }
.tv-m.s2.tease .mar { animation: tv-nyahr .22s ease-in-out infinite alternate; }
.tv-m.s3.tease :is(.tv-mbob, .tv-msh, .mal, .mar) { animation-duration: .62s; }
@keyframes tv-wag { from { transform: rotate(-12deg); } to { transform: rotate(12deg) scaleY(1.1); } }
@keyframes tv-pump { from { transform: rotate(10deg); } to { transform: rotate(80deg); } }
@keyframes tv-pump2 { from { transform: rotate(-10deg); } to { transform: rotate(-80deg); } }
@keyframes tv-dance { 0%, 100% { transform: translateX(-3px) rotate(-7deg); } 25%, 75% { transform: translateY(-7px) scale(.95, 1.06); } 50% { transform: translateX(3px) rotate(7deg); } }
@keyframes tv-wiggle { 0%, 100% { transform: rotate(-7deg) scale(1.03, .97); } 50% { transform: rotate(7deg) scale(1.03, .97); } }
@keyframes tv-nyahl { from { transform: rotate(135deg); } to { transform: rotate(160deg); } }
@keyframes tv-nyahr { from { transform: rotate(-135deg); } to { transform: rotate(-160deg); } }

/* the last 3 s: the grumpy one crouches, fists up; the jittery one shakes, arms everywhere; the smug one leans away
   sweating; the bouncy one bounces higher and faster */
.tv-m.s0.taunt .tv-mbob { animation: tv-brace .14s linear infinite alternate; }
.tv-m.s0.taunt :is(.mfl, .mfr, .mh1, .mh2), .tv-m.s0.taunt .tv-msh::before, .tv-m.s0.taunt .tv-msh::after { animation: none; }
.tv-m.s0.taunt .mal { animation: tv-fistl .18s ease-in-out infinite alternate; }
.tv-m.s0.taunt .mar { animation: tv-fistr .18s ease-in-out -.09s infinite alternate; }
.tv-m.s1.taunt .tv-mbob { animation: tv-panic .12s linear infinite alternate; }
.tv-m.s1.taunt .mal { animation: tv-flaill .14s linear infinite alternate; }
.tv-m.s1.taunt .mar { animation: tv-flailr .14s linear -.07s infinite alternate; }
.tv-m.s1.taunt .mant { animation-duration: .16s; }
.tv-m.s2.taunt .tv-mbob { animation: tv-lean .5s ease-in-out infinite alternate; }
.tv-m.s2.taunt .mal { animation: tv-fistl .3s ease-in-out infinite alternate; }
.tv-m.s2.taunt .mh1 { animation: none; }
.tv-m.s3.taunt .tv-mbob { animation: tv-hop2 .5s infinite; }
.tv-m.s3.taunt .tv-msh { animation: tv-hopsh2 .5s infinite; }
.tv-m.s3.taunt .mal { animation: tv-flapl2 .5s ease-in-out infinite; }
.tv-m.s3.taunt .mar { animation: tv-flapr2 .5s ease-in-out infinite; }
@keyframes tv-brace { from { transform: translateX(-1.2px) scale(1.1, .87); } to { transform: translateX(1.2px) scale(1.12, .86); } }
@keyframes tv-fistl { from { transform: rotate(112deg); } to { transform: rotate(140deg); } }
@keyframes tv-fistr { from { transform: rotate(-112deg); } to { transform: rotate(-140deg); } }
@keyframes tv-panic { from { transform: translateX(-2.6px) rotate(-3deg) scale(.97, 1.04); } to { transform: translateX(2.6px) rotate(3deg) scale(1.02, .98); } }
@keyframes tv-flaill { from { transform: rotate(20deg); } to { transform: rotate(150deg); } }
@keyframes tv-flailr { from { transform: rotate(-20deg); } to { transform: rotate(-150deg); } }
@keyframes tv-lean { from { transform: rotate(7deg) translateX(1px); } to { transform: rotate(11deg) translateX(3px) scale(.98, 1.02); } }
@keyframes tv-hop2 {
  0%, 100% { transform: scale(1.16, .84); animation-timing-function: ease-out; }
  44% { transform: translateY(-34px) scale(.94, 1.08) rotate(-6deg); animation-timing-function: ease-in; }
  82% { transform: translateY(-2px) scale(.92, 1.1); } }
@keyframes tv-hopsh2 { 0%, 82%, 100% { transform: none; opacity: 1; } 44% { transform: scale(.5); opacity: .45; } }
@keyframes tv-flapl2 { 0%, 82%, 100% { transform: rotate(10deg); } 44% { transform: rotate(145deg); } }
@keyframes tv-flapr2 { 0%, 82%, 100% { transform: rotate(-10deg); } 44% { transform: rotate(-145deg); } }

/* coming on or reacting: tau.js moves it, its own moves stop */
.tv-m:is(.ent, .act) :is(.tv-mbob, .tv-msh, .mfl, .mfr, .mal, .mar, .mh1, .mh2), .tv-m.act .tv-msh::before, .tv-m.act .tv-msh::after { animation: none !important; }

/* what it shouts */
.tv-mtalk { position: absolute; left: 44%; bottom: calc(100% + 8px); z-index: 1; padding: 3px 10px 4px; border-radius: 12px; background: #fff; color: #1B201C; opacity: 0; pointer-events: none;
  font: 900 15px/1.25 var(--kr-sans, system-ui), sans-serif; letter-spacing: -.02em; white-space: nowrap; transform: translateX(-50%); box-shadow: 0 5px 12px -5px rgba(0, 0, 0, .55); }
.tv-mtalk::after { content: ''; position: absolute; left: 50%; top: calc(100% - 1px); margin-left: -5px; border: 5px solid transparent; border-top-color: #fff; }
.tv-m.s0.taunt .tv-mtalk, .tv-m.s1.taunt .tv-mtalk { color: #C23A2C; }

/* seeing stars: three going round its head */
.tv-mstars { position: absolute; left: 50%; top: 9px; width: 0; height: 0; display: none; }
.tv-m.stars .tv-mstars { display: block; }
.tv-mstars i { position: absolute; left: -6px; top: -6px; width: 12px; height: 12px; background: #FFE066; animation: tv-orbit .9s linear infinite;
  clip-path: polygon(50% 0, 63% 37%, 100% 50%, 63% 63%, 50% 100%, 37% 63%, 0 50%, 37% 37%); }
.tv-mstars i:nth-child(2) { animation-delay: -.3s; background: #fff; }
.tv-mstars i:nth-child(3) { animation-delay: -.6s; }
@keyframes tv-orbit {
  0%, 100% { transform: translate(-25px, 0) scale(.8); } 12.5% { transform: translate(-18px, 5px) scale(.98) rotate(45deg); } 25% { transform: translate(0, 7px) scale(1.12) rotate(90deg); }
  37.5% { transform: translate(18px, 5px) scale(.98) rotate(135deg); } 50% { transform: translate(25px, 0) scale(.8) rotate(180deg); } 62.5% { transform: translate(18px, -5px) scale(.62) rotate(225deg); }
  75% { transform: translate(0, -7px) scale(.5) rotate(270deg); } 87.5% { transform: translate(-18px, -5px) scale(.62) rotate(315deg); } }

/* dust at its feet, dirt from the track bed */
.tv-dust { position: absolute; width: 0; height: 0; margin-bottom: var(--g); }
.tv-dust i { position: absolute; left: -8px; top: -11px; width: 16px; height: 12px; border-radius: 50%; background: var(--c, #EDE6DA); animation: tv-dust .7s ease-out forwards; }
@keyframes tv-dust { 0% { opacity: .95; transform: scale(.3); } 100% { opacity: 0; transform: translate(var(--x), var(--y)) scale(var(--s, 1.2)); } }

/* ---------- Nếp on the platform ---------- */
.tv-walk { position: absolute; left: 0; bottom: calc(var(--g) + 4px); z-index: 8; width: 84px; will-change: transform; pointer-events: none; }
.tv-walk[hidden] { display: none; }
.tv-walk .nd { width: 84px; }
.tv-say { position: absolute; left: 50%; bottom: calc(100% - 2px); padding: 6px 12px; border-radius: 14px; background: #fff; color: #1B201C; font-size: 14px; font-weight: 800; white-space: nowrap;
  transform: translateX(-50%); box-shadow: 0 6px 14px -6px rgba(0, 0, 0, .45); transition: opacity .2s; }
.tv-say::after { content: ''; position: absolute; left: 50%; top: 100%; margin-left: -6px; border: 6px solid transparent; border-top-color: #fff; }
.tv-walk.go .tv-say { opacity: 0; }
.tv-walk.cheer .tv-say { opacity: 1; transition-delay: .7s; }

/* ---------- the moments: words, the hit, a car gone, confetti ---------- */
.tv-fx { position: absolute; inset: 0; z-index: 10; pointer-events: none; }
.tv-pop { position: absolute; bottom: calc(var(--g) + 150px); color: #fff; font-size: 22px; font-weight: 900; line-height: 1; white-space: nowrap; text-shadow: 0 2px 0 var(--lf), 0 5px 12px rgba(0, 0, 0, .4);
  animation: tv-pop 1s cubic-bezier(.2, 1.4, .4, 1) forwards; }
@keyframes tv-pop { 0% { opacity: 0; transform: translateY(14px) scale(.6); } 25% { opacity: 1; transform: scale(1.08); } 70% { opacity: 1; transform: translateY(-8px); } 100% { opacity: 0; transform: translateY(-22px); } }
.tv-boom { position: absolute; width: 0; height: 0; margin-bottom: var(--g); }
.tv-flash { position: absolute; left: -70px; top: -70px; width: 140px; height: 140px; border-radius: 50%; background: radial-gradient(closest-side, #fff, rgba(255, 238, 180, .75) 45%, transparent); animation: tv-flash .5s ease-out forwards; }
.tv-bit { position: absolute; left: -5px; top: -5px; width: 10px; height: 10px; border-radius: 3px; background: var(--c); animation: tv-bit .7s cubic-bezier(.2, .7, .4, 1) forwards; }
.tv-bit.st { left: -8px; top: -8px; width: 16px; height: 16px; border-radius: 0; animation-duration: .85s; clip-path: polygon(50% 0, 63% 37%, 100% 50%, 63% 63%, 50% 100%, 37% 63%, 0 50%, 37% 37%); }
.tv-boom b { position: absolute; left: -20px; top: -80px; color: #FFE066; font-size: 28px; font-weight: 900; line-height: 1; white-space: nowrap; text-shadow: 0 3px 0 #C2410C, 0 6px 14px rgba(0, 0, 0, .45);
  animation: tv-bonk .95s cubic-bezier(.2, 1.5, .4, 1) forwards; }
@keyframes tv-flash { 0% { opacity: 1; transform: scale(.3); } 100% { opacity: 0; transform: scale(1.4); } }
@keyframes tv-bit { 0% { opacity: 1; transform: none; } 100% { opacity: 0; transform: translate(var(--x), var(--y)) rotate(200deg) scale(.4); } }
@keyframes tv-bonk { 0% { opacity: 0; transform: rotate(-9deg) scale(.3); } 30% { opacity: 1; transform: rotate(-9deg) scale(1.15); } 75% { opacity: 1; transform: rotate(-9deg); } 100% { opacity: 0; transform: rotate(-9deg) translateY(-14px); } }
.tv-poof { position: absolute; width: 0; height: 0; margin-bottom: var(--g); }
.tv-poof i { position: absolute; left: -15px; top: -15px; width: 30px; height: 30px; border-radius: 50%; background: #F3EFE8; animation: tv-poof .8s ease-out forwards; }
.tv-poof i:nth-child(1) { --x: -26px; --y: -18px; } .tv-poof i:nth-child(2) { --x: 22px; --y: -24px; } .tv-poof i:nth-child(3) { --x: 0px; --y: -40px; }
.tv-poof i:nth-child(4) { --x: -34px; --y: 8px; } .tv-poof i:nth-child(5) { --x: 32px; --y: 6px; }
@keyframes tv-poof { 0% { opacity: .95; transform: scale(.3); } 100% { opacity: 0; transform: translate(var(--x), var(--y)) scale(1.4); } }
.tv-conf { position: absolute; inset: 0; z-index: 30; overflow: hidden; pointer-events: none; }
.tv-conf i { position: absolute; top: -16px; width: var(--w); height: calc(var(--w) * .55); border-radius: 2px; background: var(--c); opacity: 0; animation: tv-cf var(--t) cubic-bezier(.3, .5, .5, 1) var(--d) forwards; }
@keyframes tv-cf { 0% { opacity: 1; transform: none; } 85% { opacity: 1; } 100% { opacity: 0; transform: translate(var(--x), var(--y)) rotate(var(--r)); } }

/* ---------- on top of the scene: the way out, where the train is, the cars left, the streak ---------- */
.tv-hud { position: absolute; left: 0; right: 0; top: 0; z-index: 12; display: flex; align-items: center; gap: 10px; padding: calc(8px + env(safe-area-inset-top)) 12px 10px;
  background: linear-gradient(rgba(9, 13, 21, .42), rgba(9, 13, 21, 0)); }
.tv-x { flex: none; display: grid; place-items: center; width: 40px; height: 40px; padding: 0; border: 0; border-radius: 50%; background: rgba(255, 255, 255, .16); cursor: pointer; }
.tv-x svg { width: 20px; height: 20px; fill: none; stroke: #fff; stroke-width: 3; stroke-linecap: round; }
.tv-route { flex: 1; display: flex; align-items: center; gap: 6px; min-width: 0; }
.tv-route .mt-code { flex: none; height: 24px; min-width: 42px; padding: 0 5px; border-width: 2.5px; font-size: 13px; background: #fff; color: #1B201C; }
.tv-route .mt-code.to { background: var(--lf); color: var(--lt); border-color: #fff; }
.tv-rl { position: relative; flex: 1; height: 6px; border-radius: 3px; background: rgba(255, 255, 255, .22); }
.tv-rl-fill { position: absolute; inset: 0; border-radius: 3px; background: var(--lb); transform: scaleX(0); transform-origin: left; transition: transform .6s; }
.tv-rl-car { position: absolute; left: 0; top: -6px; width: 20px; height: 18px; border-radius: 6px 8px 5px 5px; transition: transform .6s;
  background: linear-gradient(var(--l), var(--l)) 5px 4px / 10px 5px no-repeat, #fff; box-shadow: 0 2px 6px rgba(0, 0, 0, .4); }
.tv-cars { flex: none; display: flex; gap: 4px; }
.tv-ci { width: 22px; height: 17px; border-radius: 6px 6px 4px 4px; transition: transform .3s, background-color .3s, opacity .3s;
  background: linear-gradient(rgba(255, 255, 255, .9), rgba(255, 255, 255, .9)) 4px 3px / 14px 5px no-repeat, var(--lb); box-shadow: 0 2px 0 rgba(0, 0, 0, .35); }
.tv-ci.lost { opacity: .35; background: rgba(255, 255, 255, .3); box-shadow: none; transform: scale(.82); animation: st-shake .45s; }
.tv-combo { position: absolute; right: 12px; top: 60px; z-index: 12; padding: 4px 12px; border-radius: 999px; background: #237A3E; color: #fff; font-size: 14px; font-weight: 800; opacity: 0; pointer-events: none; }
.tv-combo.on { animation: st-combo 1.6s; }
.tv-fastb { position: absolute; left: 50%; top: 60px; z-index: 12; display: flex; align-items: center; gap: 4px; padding: 5px 13px 5px 9px; border-radius: 999px; pointer-events: none;
  background: linear-gradient(#FFB547, #FF7A3D); color: #fff; font-size: 14px; font-weight: 900; letter-spacing: .02em; text-transform: uppercase;
  box-shadow: 0 4px 16px rgba(255, 120, 40, .55); opacity: 0; transform: translateX(-50%) scale(.5); transition: transform .35s cubic-bezier(.3, 1.6, .5, 1), opacity .2s; }
.tv-fastb svg { width: 16px; height: 16px; fill: #fff; }
.tv.fast .tv-fastb { opacity: 1; transform: translateX(-50%); }

/* ---------- the question ---------- */
.tv-panel { position: relative; z-index: 2; flex: 1; min-height: 0; margin-top: -18px; padding: 14px 16px calc(14px + env(safe-area-inset-bottom)); overflow-y: auto; overscroll-behavior: contain;
  border-radius: 22px 22px 0 0; background: var(--bg, #F4F1E9); box-shadow: 0 -8px 20px rgba(0, 0, 0, .2); -webkit-user-select: text; user-select: text; }
.tv-time { height: 10px; margin: 0 4px 12px; overflow: hidden; border-radius: 5px; background: var(--fill, #E9E4D8); box-shadow: inset 0 1px 2px rgba(0, 0, 0, .12); }
.tv-time i { position: relative; display: block; height: 100%; border-radius: 5px; background: linear-gradient(90deg, #22B868, #8BE07A); transform-origin: left; }
.tv-time b { position: absolute; inset: 0; border-radius: 5px; background: linear-gradient(90deg, #F2493A, #FF9A3D); opacity: 0; }
.tv.wait .tv-time i { animation: tv-wait 1s ease-in-out infinite; }
@keyframes tv-wait { 50% { opacity: .45; } }
.tv:not(.on) .tv-time, .tv.ended .tv-time { visibility: hidden; }
.tv .st-q { box-shadow: 0 4px 0 var(--tv-lip), 0 10px 18px -12px rgba(70, 58, 30, .45); }
.tv .st-opt:not(.right, .wrong) { box-shadow: 0 4px 0 var(--tv-lip), 0 8px 16px -12px rgba(70, 58, 30, .45); }
.tv .st-opt:active:not(:disabled) { transform: translateY(3px); box-shadow: 0 1px 0 var(--tv-lip); }
.tv .st-opt.right { box-shadow: 0 4px 0 #237A3E; }
.tv .st-opt.wrong { box-shadow: 0 4px 0 #C23A2C; }
.tv .st-opts { margin-top: 12px; }
.tv .st-fix { margin-top: 6px; }

/* before the first question: where the train goes */
.tv-ticket { margin-top: 2px; padding: 18px 14px 16px; border-radius: 22px; background: var(--card, #fff); box-shadow: 0 4px 0 var(--tv-lip), 0 12px 22px -14px rgba(70, 58, 30, .45); text-align: center; }
.tv-tk-row { display: grid; grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr); align-items: center; gap: 8px; }
.tv-tk-st { display: flex; flex-direction: column; align-items: center; gap: 5px; min-width: 0; }
.tv-tk-st b { font: 800 17px/1.2 var(--kr-sans, system-ui), sans-serif; letter-spacing: -.02em; color: var(--ink2, #4F5751); word-break: keep-all; overflow-wrap: anywhere; }
.tv-tk-st.to b { font-size: 22px; color: var(--ink, #1B201C); }
.tv-tk-st small { font-size: 13px; font-weight: 700; color: var(--ink2, #4F5751); }
.tv-tk-st .mt-code { height: 26px; }
.tv-tk-st.to .mt-code { border-color: var(--lf); background: var(--lf); color: var(--lt); }
.tv-tk-go { position: relative; width: 46px; height: 14px; overflow: hidden; }
.tv-tk-go::before { content: ''; position: absolute; left: -12px; right: 8px; top: 5px; height: 4px; background: repeating-linear-gradient(90deg, var(--l) 0 6px, transparent 6px 12px); animation: tv-go .6s linear infinite; }
.tv-tk-go::after { content: ''; position: absolute; right: 2px; top: 2px; width: 7px; height: 7px; border: solid var(--l); border-width: 3px 3px 0 0; transform: rotate(45deg); }
@keyframes tv-go { to { transform: translateX(12px); } }
.tv-tk-chips { display: flex; flex-wrap: wrap; justify-content: center; gap: 6px; margin: 16px 0 0; }
.tv-tk-chips span { padding: 5px 12px; border-radius: 999px; background: var(--fill, #EFECE4); color: var(--ink2, #4F5751); font-size: 14px; font-weight: 800; }

/* the end: stars, how it went, the way on */
.tv-end { text-align: center; }
.tv-stars { display: flex; align-items: flex-end; justify-content: center; gap: 6px; margin: 0 0 2px; }
.tv-star { width: 50px; height: 48px; opacity: 0; transform: scale(.3) rotate(-30deg); }
.tv-star:nth-child(2) { width: 64px; height: 61px; margin-bottom: 8px; }
.tv-star svg { display: block; width: 100%; height: 100%; }
.tv-star.pop { opacity: .3; filter: grayscale(1); transform: none; transition: transform .5s cubic-bezier(.3, 1.8, .5, 1), opacity .2s; }
.tv-star.on.pop { opacity: 1; filter: none; }
.tv-end .win-title { margin-top: 2px; font-size: 25px; }
.tv-res { display: flex; justify-content: center; gap: 8px; margin-top: 14px; }
.tv-r { flex: 1; max-width: 120px; padding: 8px 6px 9px; border-radius: 16px; background: var(--card, #fff); box-shadow: 0 3px 0 var(--tv-lip); }
.tv-r small { display: block; font-size: 13px; font-weight: 800; color: var(--ink2, #4F5751); }
.tv-r b { display: flex; align-items: center; justify-content: center; gap: 3px; font-size: 22px; font-weight: 900; font-variant-numeric: tabular-nums; }
.tv-r.gr { background: var(--honey-soft, #FCEFD2); box-shadow: 0 3px 0 #EBCB8A; }
.tv-r.gr b { color: var(--honey-ink, #8A5A00); }
.tv-r .win-gi { width: 22px; height: 22px; }
.tv .svm { margin-top: 12px; }
.tv .svm .svl-list { max-height: 150px; }
.tv-end.lose .win-title { color: var(--red-ink, #B8321F); }
.tv .actions { display: flex; gap: 10px; margin-top: 16px; }
.tv .actions .btn { flex: 1; min-height: 50px; }

/* the way out, asked */
.tv-quit-m { position: relative; padding-top: 18px; animation: pop .35s cubic-bezier(.3, 1.6, .5, 1); }
.tv-quit-mon { width: 68px; height: 83px; margin: -58px auto 6px; }
.tv-quit-mon .tv-mbob { transform-origin: 50% 100%; }
.tv-quit-m h3 { font-size: 21px; }

/* the map: the button on each station ahead, and the stations further down the line */
.mt-tau { display: inline-flex; align-items: center; gap: 6px; min-height: 36px; margin-top: 8px; padding: 5px 14px 5px 10px; border: 2px solid var(--l); border-radius: 999px; background: transparent;
  color: var(--mt-ink); font: inherit; font-size: 14px; font-weight: 800; line-height: 1.2; cursor: pointer; -webkit-tap-highlight-color: transparent; }
.mt-tau-ic { flex: none; width: 18px; height: 18px; color: var(--l); }
.mt-tau-ic .w { fill: var(--mt-card); }
.mt-st.next:not(.next ~ .next) .mt-tau:not(.wait) { border-color: var(--lf); background: var(--lf); color: var(--lt); box-shadow: 0 3px 0 color-mix(in srgb, var(--lf) 60%, #000); }
.mt-st.next:not(.next ~ .next) .mt-tau:not(.wait) .mt-tau-ic { color: var(--lt); }
.mt-st.next:not(.next ~ .next) .mt-tau:not(.wait) .mt-tau-ic .w { fill: var(--lf); }
.mt-tau:active { transform: translateY(2px); }
.mt-tau.wait { border-style: dashed; border-color: var(--mt-rail); color: var(--mt-ink3); }
.mt-more-row { padding: 6px 16px 16px 60px; }
.mt-more { min-height: 40px; padding: 8px 16px; border: 2px solid var(--mt-line); border-radius: 999px; background: var(--mt-card); color: var(--mt-ink2); font: inherit; font-size: 14px; font-weight: 800; cursor: pointer; }

@media (prefers-reduced-motion: reduce) {
  .tv-bob, .tv-tk-go::before, .tv-m *, .tv-m *::before, .tv-m *::after { animation: none !important; }
  .tv-conf { display: none; }
}
