/* A short title sequence with a broadcast-glitch flavour (v34): a CRT line powers the screen on, letters
   stutter in frame by frame, RGB-split and sliced-footage bursts hit on fixed beats, then the scene holds
   (nothing loops) until the page is ready and is cut away on one diagonal while the wordmark becomes the
   header mark. Full-frame flashes stay at most two per second. */
.site-intro { --intro-styles-ready: 1; --intro-cut: cubic-bezier(.76,0,.24,1); --intro-snap: cubic-bezier(.16,1,.3,1); --intro-progress: 0; position: fixed; inset: 0; z-index: 10000; isolation: isolate; overflow: clip; color: #f1f7fc; }
.site-intro[hidden] { display: none; }
.site-intro__plane { position: absolute; inset: 0; background: #034ed7; }
.site-intro__plane--edge { background: #67edff; }
.site-intro__plane--white { background: #eef8ff; }
.site-intro__mark { position: absolute; width: clamp(280px,43vw,720px); aspect-ratio: 160/72; left: 50%; top: 47%; transform: translate(-50%,-50%) rotate(-3deg) scale(1.03); overflow: visible; z-index: 2; }
.site-intro__mark svg { display: block; width: 100%; height: 100%; overflow: visible; fill: currentColor; }
.site-intro__accent { fill: #67edff; }
.site-intro__word { position: absolute; inset: 0; filter: drop-shadow(0 0 0 #0a3a9c00); transition: filter 140ms; }
/* The flight crosses the cyan and white bands; a hard navy edge keeps the mark legible, then shrinks away with it. */
.site-intro.is-revealing .site-intro__word { filter: drop-shadow(4px 4px 0 #0a3a9c); }
/* Charge rule: the track draws in, the fill follows time but never runs ahead of real readiness. */
.site-intro__meter { position: absolute; left: 8.5%; right: 12.5%; top: 83%; height: 2px; background: #9fd8ff38; overflow: hidden; transform-origin: left; transition: opacity 260ms; }
.site-intro__meter b { position: absolute; inset: 0; clip-path: inset(0 calc((1 - var(--intro-progress)) * 100%) 0 0); transition: clip-path 420ms cubic-bezier(.22,1,.36,1); }
.site-intro__meter i { position: absolute; inset: 0; background: #67edff; transform: scaleX(1); transform-origin: left; }
.site-intro__composition { position: absolute; inset: 0; overflow: hidden; pointer-events: none; }
/* Real footage passes once behind the title in a slanted slice: it starts and ends fully off-screen,
   the picture drifts slower than the slice, and a thin cyan light marks its leading edge. */
.intro-picture {
    --slice-w: 24vw; --slice-skew: -24deg; --slice-from: 124vw; --slice-to: -48vw; --image-from: -40vw; --image-to: 40vw;
    position: absolute; z-index: 1; top: -12%; bottom: -12%; left: 0; width: var(--slice-w); overflow: hidden; opacity: 0;
    transform: translateX(var(--slice-from)) skewX(var(--slice-skew));
}
.intro-picture::before { content: ''; position: absolute; z-index: 1; top: 0; bottom: 0; left: 0; width: 3px; background: #67edff; box-shadow: 0 0 18px 2px #67edff80; }
.intro-picture::after { content: ''; position: absolute; z-index: 1; top: 0; bottom: 0; right: 0; width: 1px; background: #ffffffa6; }
.intro-picture i { position: absolute; top: 0; bottom: 0; left: -60vw; width: 160vw; background: linear-gradient(#062f9a8c,#062f9a8c),url('https://zhanglt-2026-1324253163.cos.ap-shanghai.myqcloud.com/site/portfolio/optimized/hero-personal-poster.jpg') center/cover; transform: translateX(var(--image-from)) skewX(calc(var(--slice-skew) * -1)); }
.intro-blade { position: absolute; top: -30%; height: 160%; width: 44%; opacity: 0; transform: skewX(-24deg); }
.intro-blade--deep { left: -10%; background: #052b85; }
.intro-echo { position: absolute; width: max(950px,115vw); height: auto; top: 47%; left: 50%; transform: translate(-50%,-50%) rotate(-9deg); fill: #1470e5; stroke: none; opacity: 0; }
.intro-caption { position: absolute; z-index: 1; top: calc(47% + clamp(74px,8.2vw,118px)); left: 50%; width: max-content; text-align: center; transform: translateX(-50%); }
.intro-caption span { display: block; font: 700 clamp(22px,2.2vw,34px)/1.4 var(--sans); letter-spacing: .42em; padding-left: .42em; opacity: 0; }
.site-intro__skip { position: absolute; z-index: 5; right: max(28px,env(safe-area-inset-right)); bottom: max(24px,env(safe-area-inset-bottom)); min-height: 44px; padding: 10px 14px; border: 0; background: transparent; color: #dcefff; font: 500 12px/1.5 system-ui,sans-serif; letter-spacing: .08em; cursor: pointer; }
.site-intro__skip:hover { color: #67edff; }
.site-intro__skip:focus-visible { outline: 2px solid #67edff; outline-offset: 2px; }
/* Glitch layers. Ghost copies of the wordmark give a cyan / navy channel split; JS drives them in bursts. */
.site-intro__mark .intro-ghost { position: absolute; inset: 0; opacity: 0; pointer-events: none; }
.site-intro__mark .intro-ghost--cyan { fill: #67edff; }
.site-intro__mark .intro-ghost--deep { fill: #052b85; }
.intro-noise { position: absolute; inset: 0; z-index: 2; pointer-events: none; }
.intro-noise span { position: absolute; display: block; overflow: hidden; opacity: 0; }
.intro-noise span i { position: absolute; background-position: center; background-size: cover; }
.intro-scan { position: absolute; inset: 0; z-index: 3; pointer-events: none; opacity: 0; background: repeating-linear-gradient(to bottom,#0000 0 2px,#00175226 2px 3px); }
.intro-scan::after { content: ''; position: absolute; left: 0; right: 0; top: 0; height: 24vh; background: linear-gradient(#67edff00,#67edff12 58%,#eef8ff30 60%,#67edff00); transform: translateY(-30vh); }
.intro-tape { position: absolute; z-index: 2; left: 0; right: 0; height: clamp(8px,1vw,14px); overflow: hidden; clip-path: inset(0 100% 0 0); }
.intro-tape::before { content: ''; position: absolute; top: 0; bottom: 0; left: 0; width: calc(100% + 120px); background: repeating-linear-gradient(-45deg,#67edff 0 10px,#052b85 10px 20px); }
.intro-tape--top { top: 0; }
.intro-tape--bottom { bottom: 0; clip-path: inset(0 0 0 100%); }
.intro-halftone { position: absolute; z-index: 0; right: 0; bottom: 0; width: 46vw; height: 58vh; opacity: 0; background: radial-gradient(circle,#1470e5 1.6px,#0000 2px) 0 0/12px 12px; -webkit-mask-image: linear-gradient(135deg,#0000 30%,#000); mask-image: linear-gradient(135deg,#0000 30%,#000); }
.intro-flash { position: absolute; inset: 0; z-index: 3; pointer-events: none; opacity: 0; background: #eef8ff; }
/* CRT power-on: a bright line, then the dark screen splits open on the blue scene. */
.intro-crt { position: absolute; inset: 0; z-index: 4; pointer-events: none; }
.intro-crt::before, .intro-crt::after { content: ''; position: absolute; left: 0; right: 0; height: 50.5%; background: #021c5c; }
.intro-crt::before { top: 0; }
.intro-crt::after { bottom: 0; }
.intro-crt i { position: absolute; left: 0; right: 0; top: 50%; height: 2px; margin-top: -1px; background: #eef8ff; box-shadow: 0 0 22px 3px #67edff; opacity: 0; transform: scaleX(0); }
.site-intro__status { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
.site-intro__waiting { position: absolute; z-index: 2; left: 50%; top: calc(47% + clamp(128px,13vw,184px)); transform: translateX(-50%); margin: 0; font: 400 12px/1.5 var(--sans); letter-spacing: .12em; color: #c0defa; opacity: 0; transition: opacity 300ms; }
.site-intro.is-waiting .site-intro__waiting { opacity: 1; }
.site-intro.is-revealing :is(.site-intro__waiting,.site-intro__meter) { opacity: 0; transition-duration: 120ms; }

.intro-active { overflow: hidden; background: #034ed7; }
.intro-active body { overflow: hidden; }
.intro-managed .hero-enter { animation: none; opacity: 1; transform: none; }
.intro-active:not(.intro-revealing) :is(.art-title,.art-hero__name,.art-hero__actions,.site-header) { opacity: 0; }
.intro-revealing .site-mark { opacity: 0; }
.intro-active .hero-grid { animation-play-state: paused; }
.intro-managed .art-title .art-line { display: block; }
.art-reel__video.is-poster-fallback { visibility: hidden; }
.has-poster-fallback .art-reel__frame { background-image: url('https://zhanglt-2026-1324253163.cos.ap-shanghai.myqcloud.com/site/portfolio/optimized/hero-personal-poster.jpg'); background-position: center; background-size: cover; }
/* COS mirror unreachable: use the same poster from the site itself. */
.web-mirror-down .intro-picture i { background-image: linear-gradient(#062f9a8c,#062f9a8c),url('../portfolio/optimized/hero-personal-poster.jpg'); }
.web-mirror-down .has-poster-fallback .art-reel__frame { background-image: url('../portfolio/optimized/hero-personal-poster.jpg'); }

/* 0–0.3 s CRT on; 0.2–0.66 s letters stutter in and the Z blade lands (flash + glitch, JS);
   1.25 s sliced-footage burst; the footage slice passes 0.4–2.1 s while the rule charges. */
.site-intro.is-playing .intro-crt::before { animation: intro-crt-top 260ms 80ms cubic-bezier(.7,0,.2,1) both; }
.site-intro.is-playing .intro-crt::after { animation: intro-crt-bottom 260ms 80ms cubic-bezier(.7,0,.2,1) both; }
.site-intro.is-playing .intro-crt i { animation: intro-crt-line 300ms linear both; }
.site-intro.is-playing .site-intro__mark { animation: intro-camera 2000ms cubic-bezier(.22,1,.36,1) both; }
.site-intro.is-playing .intro-z-top { animation: intro-from-left 300ms 200ms steps(1,end) both; }
.site-intro.is-playing .intro-z-bottom { animation: intro-from-right 300ms 240ms steps(1,end) both; }
.site-intro.is-playing .intro-l-draw { animation: intro-drop 300ms 280ms steps(1,end) both; }
.site-intro.is-playing .intro-t-draw { animation: intro-drop 300ms 320ms steps(1,end) both; }
.site-intro.is-playing .intro-blade-draw { animation: intro-blade-in 260ms 400ms steps(1,end) both; }
.site-intro.is-playing .intro-blade--deep { animation: intro-deep-in 560ms 200ms var(--intro-snap) both; }
.site-intro.is-playing .intro-echo--back { animation: intro-echo-in 760ms 300ms var(--intro-snap) both, intro-echo-drift 7000ms 1060ms linear forwards; }
.site-intro.is-playing .intro-picture { animation: intro-slice 1750ms 380ms linear both; }
.site-intro.is-playing .intro-picture i { animation: intro-slice-image 1750ms 380ms linear both; }
.site-intro.is-playing .site-intro__meter { animation: intro-meter-in 300ms 620ms steps(4,end) both; }
.site-intro.is-playing .site-intro__meter i { animation: intro-meter-time 1300ms 680ms cubic-bezier(.35,.1,.25,1) both; }
.site-intro.is-playing .intro-caption span { animation: intro-caption-in 340ms 720ms steps(1,end) both; }
.site-intro.is-playing .intro-scan { animation: intro-show 120ms 160ms steps(2,end) both; }
.site-intro.is-playing .intro-scan::after { animation: intro-roll 1600ms 300ms linear both; }
.site-intro.is-playing .intro-tape--top { animation: intro-tape-left 240ms 640ms steps(4,end) both; }
.site-intro.is-playing .intro-tape--bottom { animation: intro-tape-right 240ms 680ms steps(4,end) both; }
.site-intro.is-playing .intro-tape::before { animation: intro-tape-run 2400ms 640ms linear both; }
.site-intro.is-playing .intro-halftone { animation: intro-halftone-in 420ms 660ms steps(3,end) both; }

@keyframes intro-crt-top { to { transform: translateY(-101%); } }
@keyframes intro-crt-bottom { to { transform: translateY(101%); } }
@keyframes intro-crt-line {
    0% { opacity: 1; transform: scaleX(0); }
    30% { opacity: 1; transform: scaleX(1); }
    55% { opacity: 1; transform: scaleX(1) scaleY(5); }
    100% { opacity: 0; transform: scaleX(1) scaleY(60); }
}
@keyframes intro-show { from { opacity: 0; } to { opacity: 1; } }
@keyframes intro-roll { from { transform: translateY(-30vh); } to { transform: translateY(110vh); } }
@keyframes intro-tape-left { from { clip-path: inset(0 100% 0 0); } to { clip-path: inset(0); } }
@keyframes intro-tape-right { from { clip-path: inset(0 0 0 100%); } to { clip-path: inset(0); } }
@keyframes intro-tape-run { from { transform: translateX(-113.14px); } to { transform: none; } }
@keyframes intro-halftone-in { from { opacity: 0; translate: 6vw 0; } to { opacity: .5; translate: 0 0; } }
@keyframes intro-camera {
    0% { transform: translate(-50%,-50%) rotate(-4deg) scale(.97); }
    31% { transform: translate(-50%,-50%) rotate(-4deg) scale(.99); }
    34% { transform: translate(-50%,-50%) rotate(-4deg) scale(1.06); }
    44% { transform: translate(-50%,-50%) rotate(-4deg) scale(1); }
    100% { transform: translate(-50%,-50%) rotate(-3deg) scale(1.03); }
}
/* Letters arrive in held frames (steps), jumping between partial slices instead of easing in. */
@keyframes intro-from-left {
    0% { opacity: 0; transform: translateX(-30px); clip-path: inset(0 100% 0 0); }
    20% { opacity: 1; transform: translateX(-30px); clip-path: inset(0 55% 0 0); }
    40% { opacity: 1; transform: translateX(10px); clip-path: inset(0 0 45% 0); }
    60% { opacity: .35; transform: translateX(-5px); clip-path: inset(40% 0 0 0); }
    80% { opacity: 1; transform: translateX(2px); clip-path: inset(0); }
    100% { opacity: 1; transform: none; clip-path: inset(0); }
}
@keyframes intro-from-right {
    0% { opacity: 0; transform: translateX(30px); clip-path: inset(0 0 0 100%); }
    20% { opacity: 1; transform: translateX(30px); clip-path: inset(0 0 0 55%); }
    40% { opacity: 1; transform: translateX(-10px); clip-path: inset(45% 0 0 0); }
    60% { opacity: .35; transform: translateX(5px); clip-path: inset(0 0 40% 0); }
    80% { opacity: 1; transform: translateX(-2px); clip-path: inset(0); }
    100% { opacity: 1; transform: none; clip-path: inset(0); }
}
@keyframes intro-drop {
    0% { opacity: 0; transform: translateY(-18px); clip-path: inset(0 0 100% 0); }
    20% { opacity: 1; transform: translate(6px,-12px); clip-path: inset(0 0 50% 0); }
    40% { opacity: .4; transform: translate(-6px,4px); clip-path: inset(30% 0 10% 0); }
    60% { opacity: 1; transform: translate(3px,0); clip-path: inset(0 0 0 30%); }
    80% { opacity: 1; transform: translate(-1px,0); clip-path: inset(0); }
    100% { opacity: 1; transform: none; clip-path: inset(0); }
}
@keyframes intro-blade-in {
    0% { opacity: 0; fill: #fff; transform: translate(26px,-24px); }
    25% { opacity: 1; fill: #fff; transform: translate(10px,-9px); }
    50% { opacity: 1; fill: #fff; transform: translate(-3px,2px); }
    75% { opacity: 1; fill: #fff; transform: none; }
    100% { opacity: 1; fill: #67edff; transform: none; }
}
@keyframes intro-deep-in {
    from { opacity: 0; transform: translateX(-110%) skewX(-24deg); }
    to { opacity: .55; transform: skewX(-24deg); }
}
@keyframes intro-echo-in {
    from { opacity: 0; translate: 14% 0; }
    to { opacity: .26; translate: 0 0; }
}
@keyframes intro-echo-drift {
    from { transform: translate(-50%,-50%) rotate(-9deg); }
    to { transform: translate(-56%,-50%) rotate(-9deg); }
}
@keyframes intro-slice {
    0% { opacity: 1; transform: translateX(calc(var(--slice-from) + (var(--slice-to) - var(--slice-from)) * 0.0000)) skewX(var(--slice-skew)); }
    10% { opacity: 1; transform: translateX(calc(var(--slice-from) + (var(--slice-to) - var(--slice-from)) * 0.1421)) skewX(var(--slice-skew)); }
    20% { opacity: 1; transform: translateX(calc(var(--slice-from) + (var(--slice-to) - var(--slice-from)) * 0.2681)) skewX(var(--slice-skew)); }
    30% { opacity: 1; transform: translateX(calc(var(--slice-from) + (var(--slice-to) - var(--slice-from)) * 0.3681)) skewX(var(--slice-skew)); }
    40% { opacity: 1; transform: translateX(calc(var(--slice-from) + (var(--slice-to) - var(--slice-from)) * 0.4421)) skewX(var(--slice-skew)); }
    50% { opacity: 1; transform: translateX(calc(var(--slice-from) + (var(--slice-to) - var(--slice-from)) * 0.5000)) skewX(var(--slice-skew)); }
    60% { opacity: 1; transform: translateX(calc(var(--slice-from) + (var(--slice-to) - var(--slice-from)) * 0.5579)) skewX(var(--slice-skew)); }
    70% { opacity: 1; transform: translateX(calc(var(--slice-from) + (var(--slice-to) - var(--slice-from)) * 0.6319)) skewX(var(--slice-skew)); }
    80% { opacity: 1; transform: translateX(calc(var(--slice-from) + (var(--slice-to) - var(--slice-from)) * 0.7319)) skewX(var(--slice-skew)); }
    90% { opacity: 1; transform: translateX(calc(var(--slice-from) + (var(--slice-to) - var(--slice-from)) * 0.8579)) skewX(var(--slice-skew)); }
    100% { opacity: 1; transform: translateX(calc(var(--slice-from) + (var(--slice-to) - var(--slice-from)) * 1.0000)) skewX(var(--slice-skew)); }
}
@keyframes intro-slice-image {
    0% { transform: translateX(calc(var(--image-from) + (var(--image-to) - var(--image-from)) * 0.0000)) skewX(calc(var(--slice-skew) * -1)); }
    10% { transform: translateX(calc(var(--image-from) + (var(--image-to) - var(--image-from)) * 0.1421)) skewX(calc(var(--slice-skew) * -1)); }
    20% { transform: translateX(calc(var(--image-from) + (var(--image-to) - var(--image-from)) * 0.2681)) skewX(calc(var(--slice-skew) * -1)); }
    30% { transform: translateX(calc(var(--image-from) + (var(--image-to) - var(--image-from)) * 0.3681)) skewX(calc(var(--slice-skew) * -1)); }
    40% { transform: translateX(calc(var(--image-from) + (var(--image-to) - var(--image-from)) * 0.4421)) skewX(calc(var(--slice-skew) * -1)); }
    50% { transform: translateX(calc(var(--image-from) + (var(--image-to) - var(--image-from)) * 0.5000)) skewX(calc(var(--slice-skew) * -1)); }
    60% { transform: translateX(calc(var(--image-from) + (var(--image-to) - var(--image-from)) * 0.5579)) skewX(calc(var(--slice-skew) * -1)); }
    70% { transform: translateX(calc(var(--image-from) + (var(--image-to) - var(--image-from)) * 0.6319)) skewX(calc(var(--slice-skew) * -1)); }
    80% { transform: translateX(calc(var(--image-from) + (var(--image-to) - var(--image-from)) * 0.7319)) skewX(calc(var(--slice-skew) * -1)); }
    90% { transform: translateX(calc(var(--image-from) + (var(--image-to) - var(--image-from)) * 0.8579)) skewX(calc(var(--slice-skew) * -1)); }
    100% { transform: translateX(calc(var(--image-from) + (var(--image-to) - var(--image-from)) * 1.0000)) skewX(calc(var(--slice-skew) * -1)); }
}
@keyframes intro-meter-in { from { transform: scaleX(0); } }
@keyframes intro-meter-time { from { transform: scaleX(0); } to { transform: scaleX(1); } }
@keyframes intro-caption-in {
    0% { opacity: 0; clip-path: inset(0 100% 0 0); transform: translateX(-12px); }
    25% { opacity: 1; clip-path: inset(0 60% 0 0); transform: translateX(-12px); }
    50% { opacity: .4; clip-path: inset(50% 0 0 0); transform: translateX(8px); }
    75% { opacity: 1; clip-path: inset(0 0 40% 0); transform: translateX(-3px); }
    100% { opacity: 1; clip-path: inset(-10% 0); transform: none; }
}
@media (max-width: 540px) {
    .site-intro__mark { width: 78vw; }
    .intro-echo { width: 240vw; }
    .intro-caption { top: calc(47% + 22vw); }
    .site-intro__waiting { top: calc(47% + 36vw); }
    .intro-halftone { width: 80vw; height: 40vh; }
    .site-intro__skip { right: max(14px,env(safe-area-inset-right)); bottom: max(14px,env(safe-area-inset-bottom)); }
}
/* Tall screens: a gentler slant and longer travel keep the slice fully off-screen at both ends. */
@media (max-aspect-ratio: 1/1) {
    .intro-picture { --slice-w: 42vw; --slice-skew: -14deg; --slice-from: 140vw; --slice-to: -84vw; --image-from: -55vw; --image-to: 45vw; }
    .intro-picture i { left: -80vw; width: 220vw; }
}
@media (max-height: 500px) {
    .site-intro__mark { width: min(42vw,360px); }
    .intro-caption { top: calc(47% + 64px); }
    .intro-caption span { font-size: 20px; }
    .site-intro__waiting { top: calc(47% + 104px); }
}
@media (prefers-reduced-motion: reduce) {
    .site-intro * { animation: none !important; }
    .intro-managed :is(.art-title,.art-hero__name,.art-hero__actions,.site-header,.site-mark) { opacity: 1 !important; transition: none !important; }
}
