/* Yuheng Leo Wang — portfolio home. White / Apple-like, same tokens as the project pages. */
:root{
  --bg:#ffffff; --ink:#1d1d1f; --ink-2:#6e6e73; --line:#e5e5ea; --tile:#f5f5f7;
  --accent:#1d5fbf;                                   /* storyline numbers; each research group swaps it */
  --display:"Inter",-apple-system,"SF Pro Display","Helvetica Neue",system-ui,sans-serif;
  --text:"Inter",-apple-system,"SF Pro Text","Helvetica Neue",system-ui,sans-serif;
  --max:1080px; --gutter:clamp(20px,4vw,48px); --nav:56px;
  color-scheme:light;
}
[data-theme="dark"]{
  --bg:#000000; --ink:#f5f5f7; --ink-2:#86868b; --line:#2c2c2e; --tile:#1c1c1e;
  color-scheme:dark;
}
body[data-lens="personal-robots"]{--accent:#1d5fbf}
body[data-lens="tangible-media"]{--accent:#16806f}
body[data-lens="cyborg-psychology"]{--accent:#6a55d0}
[data-theme="dark"] body[data-lens="personal-robots"]{--accent:#6aa4ff}
[data-theme="dark"] body[data-lens="tangible-media"]{--accent:#4cc7b0}
[data-theme="dark"] body[data-lens="cyborg-psychology"]{--accent:#a596ff}

*{box-sizing:border-box}
html{scroll-behavior:smooth}
body{margin:0;background:var(--bg);color:var(--ink);font-family:var(--text);font-size:17px;line-height:1.5;-webkit-font-smoothing:antialiased;transition:background .3s,color .3s;font-feature-settings:"cv11","ss01";min-height:100vh;min-height:100svh;display:flex;flex-direction:column}
a{color:inherit;text-decoration:none}
img{display:block;max-width:100%}
h1,h2{font-family:var(--display);font-weight:600;letter-spacing:-.025em;margin:0}
.wrap{max-width:var(--max);margin:0 auto;padding:0 var(--gutter)}
.btn{display:inline-flex;align-items:center;padding:8px 16px;border-radius:980px;font:500 13px/1.2 var(--display);transition:opacity .2s}
.btn-dark{background:var(--ink);color:var(--bg)}
.btn-dark:hover{opacity:.82}

/* ---------- nav ---------- */
.nav{position:fixed;top:0;left:0;right:0;z-index:50;background:rgba(255,255,255,.78);background:color-mix(in srgb,var(--bg) 78%,transparent);-webkit-backdrop-filter:saturate(180%) blur(20px);backdrop-filter:saturate(180%) blur(20px);border-bottom:1px solid transparent;transition:border-color .3s,background .3s}
[data-theme="dark"] .nav{background:rgba(0,0,0,.78);background:color-mix(in srgb,var(--bg) 78%,transparent)}
.nav.scrolled{border-color:var(--line)}
.nav .wrap{display:flex;align-items:center;justify-content:space-between;height:var(--nav);gap:20px}
.brand{font:600 15px/1 var(--display);letter-spacing:-.01em}
.nav .links{display:flex;gap:30px;list-style:none;margin:0;padding:0;font:500 14px/1 var(--display)}
.nav .links a{opacity:.68;padding:6px 0;transition:opacity .2s}
.nav .links a:hover,.nav .links a.on{opacity:1}
.nav .right{display:flex;align-items:center;gap:10px}
.theme{width:36px;height:36px;border-radius:999px;border:0;background:var(--tile);color:var(--ink);display:grid;place-items:center;cursor:pointer;padding:0}
.theme:hover{opacity:.8}
.theme svg{width:17px;height:17px}
.theme .moon{display:none}
[data-theme="dark"] .theme .moon{display:block}
[data-theme="dark"] .theme .sun{display:none}

/* ---------- projects ---------- */
main{flex:1 0 auto}
.work{padding:calc(var(--nav) + 28px) 0 40px}
.wtitle{display:flex;justify-content:space-between;align-items:center;gap:12px 20px;flex-wrap:wrap}
.wtitle h1{font-size:clamp(30px,3.4vw,40px);line-height:1.2}
.thesis{margin:4px 0 16px;font-size:14px;line-height:1.45;color:var(--ink-2);min-height:1.45em}
.thesis b{color:var(--ink);font-weight:600}

/* research-group switch (v7, Liquid Glass): "All" is a quiet text pill; the three groups are separate pieces of
   Liquid Glass — translucent and thick-edged (bright top edge, inner rim light, soft inner shade), floating on their
   own shadow, with a specular highlight that follows the pointer, a faint dispersion rim and a springy press.
   Colour stays sparing, as Apple asks for controls: one dot per group and a light tint on the open group.
   Until a group is opened a soft light breathes under each pill (brightness only, nothing moves). */
.lenses{display:none;align-items:center;gap:10px;flex-wrap:wrap;
  --iris:linear-gradient(115deg,#ff9cbc 0%,#ffd27a 25%,#8fe6ae 50%,#7ccfff 75%,#b99bff 100%)}
.js .lenses{display:flex}
.lens-cell{position:relative;display:inline-flex}
.lens-cell[data-g="personal-robots"]{--c:#3b7be6}
.lens-cell[data-g="tangible-media"]{--c:#1f9e86}
.lens-cell[data-g="cyborg-psychology"]{--c:#7a63e6}
[data-theme="dark"] .lens-cell[data-g="personal-robots"]{--c:#5a95ff}
[data-theme="dark"] .lens-cell[data-g="tangible-media"]{--c:#3cc4aa}
[data-theme="dark"] .lens-cell[data-g="cyborg-psychology"]{--c:#9c8bff}

/* light under the glass (the hint) */
.lens-cell[data-g]::before{content:"";position:absolute;left:6%;right:6%;top:10%;bottom:10%;z-index:0;border-radius:999px;
  background:var(--iris);filter:blur(14px);opacity:0;transition:opacity .6s ease;pointer-events:none}
.lenses.hinting .lens-cell[data-g]::before{animation:lens-halo 2.6s ease-in-out infinite}
.lenses.hinting .lens-cell[data-g="tangible-media"]::before{animation-delay:.45s}
.lenses.hinting .lens-cell[data-g="cyborg-psychology"]::before{animation-delay:.9s}
@keyframes lens-halo{0%,100%{opacity:.12}50%{opacity:.55}}
.lens-cell.is-on::before{opacity:.32}

/* the glass */
.lens-cell button{position:relative;z-index:1;isolation:isolate;display:inline-flex;align-items:center;gap:8px;white-space:nowrap;cursor:pointer;
  font:500 13px/1 var(--display);letter-spacing:-.005em;color:var(--ink);padding:10px 16px 10px 13px;border:0;border-radius:999px;
  background:rgba(255,255,255,.5);background:linear-gradient(180deg,rgba(255,255,255,.7),rgba(255,255,255,.36));
  -webkit-backdrop-filter:blur(14px) saturate(190%) brightness(1.05);backdrop-filter:blur(14px) saturate(190%) brightness(1.05);
  box-shadow:inset 0 1px 1px rgba(255,255,255,.95),inset 0 -1px 1px rgba(255,255,255,.5),inset 0 -9px 14px -10px rgba(0,0,0,.12),
    0 0 0 .5px rgba(0,0,0,.08),0 3px 10px rgba(0,0,0,.07),0 14px 34px -10px rgba(0,0,0,.14);
  transition:transform .5s cubic-bezier(.34,1.56,.64,1),box-shadow .3s ease,background .3s ease}
.lens-cell .dot{width:7px;height:7px;border-radius:50%;flex:0 0 auto;background:var(--c);box-shadow:0 0 0 2px rgba(255,255,255,.55),0 0 8px var(--c)}
/* specular highlight: sits on the glass, under the label, and follows the pointer (--mx / --my from home.js) */
.lens-cell[data-g] button::after{content:"";position:absolute;top:0;left:0;right:0;bottom:0;z-index:-1;border-radius:inherit;pointer-events:none;
  background:radial-gradient(130% 160% at var(--mx,28%) var(--my,-30%),rgba(255,255,255,.9),rgba(255,255,255,0) 58%);opacity:.55;transition:opacity .3s ease}
/* dispersion rim: a 1 px iridescent edge, cut out with a mask (skipped where masks are not supported) */
@supports ((-webkit-mask-composite:xor) or (mask-composite:exclude)){
  .lens-cell[data-g] button::before{content:"";position:absolute;top:0;left:0;right:0;bottom:0;z-index:-1;border-radius:inherit;padding:1px;
    background:var(--iris);opacity:.3;pointer-events:none;transition:opacity .35s ease;
    -webkit-mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);-webkit-mask-composite:xor;
    mask:linear-gradient(#000 0 0) content-box exclude,linear-gradient(#000 0 0)}
}
.lens-cell[data-g] button:hover{transform:scale(1.03)}
.lens-cell[data-g] button:hover::after{opacity:1}
.lens-cell[data-g] button:hover::before{opacity:.65}
.lens-cell[data-g] button:active{transform:scale(1.07);transition-duration:.18s}
.lens-cell button:focus-visible{outline:2px solid var(--c,var(--ink));outline-offset:3px}
/* the open group: prominent glass, lightly tinted with its colour */
.lens-cell[data-g] button[aria-selected="true"]{background:rgba(255,255,255,.85);
  background:linear-gradient(180deg,color-mix(in srgb,var(--c) 14%,rgba(255,255,255,.9)),color-mix(in srgb,var(--c) 8%,rgba(255,255,255,.62)))}
.lens-cell[data-g] button[aria-selected="true"]::before{opacity:.85}
.lens-cell button.pop{animation:lens-pop .55s cubic-bezier(.34,1.56,.64,1)}
@keyframes lens-pop{0%{transform:scale(1)}40%{transform:scale(1.08)}100%{transform:scale(1)}}

/* "All": no glass, just text with a soft tile when it is the current view */
.lens-cell--all button{background:none;box-shadow:none;-webkit-backdrop-filter:none;backdrop-filter:none;color:var(--ink-2);padding:10px 12px}
.lens-cell--all button:hover{color:var(--ink)}
.lens-cell--all button[aria-selected="true"]{background:var(--tile);color:var(--ink)}

/* dark: smoked glass */
[data-theme="dark"] .lens-cell button{background:rgba(255,255,255,.1);background:linear-gradient(180deg,rgba(255,255,255,.16),rgba(255,255,255,.06));
  box-shadow:inset 0 1px 1px rgba(255,255,255,.28),inset 0 -1px 1px rgba(255,255,255,.08),0 0 0 .5px rgba(255,255,255,.1),0 8px 26px rgba(0,0,0,.55)}
[data-theme="dark"] .lens-cell[data-g] button::after{background:radial-gradient(130% 160% at var(--mx,28%) var(--my,-30%),rgba(255,255,255,.3),rgba(255,255,255,0) 58%)}
[data-theme="dark"] .lens-cell .dot{box-shadow:0 0 0 2px rgba(0,0,0,.35),0 0 10px var(--c)}
[data-theme="dark"] .lens-cell[data-g] button[aria-selected="true"]{background:rgba(255,255,255,.18);
  background:linear-gradient(180deg,color-mix(in srgb,var(--c) 30%,rgba(255,255,255,.12)),color-mix(in srgb,var(--c) 18%,rgba(255,255,255,.05)))}
[data-theme="dark"] .lens-cell--all button{background:none;box-shadow:none}
[data-theme="dark"] .lens-cell--all button[aria-selected="true"]{background:var(--tile)}

/* settings people choose: less transparency, more contrast, less motion */
@supports not ((-webkit-backdrop-filter:blur(1px)) or (backdrop-filter:blur(1px))){.lens-cell[data-g] button{background:rgba(255,255,255,.94)}[data-theme="dark"] .lens-cell[data-g] button{background:#2c2c2e}}
@media (prefers-reduced-transparency:reduce){.lens-cell[data-g] button{background:#f5f5f7;-webkit-backdrop-filter:none;backdrop-filter:none}[data-theme="dark"] .lens-cell[data-g] button{background:#2c2c2e}}
@media (prefers-contrast:more){.lens-cell[data-g] button{box-shadow:0 0 0 1.5px var(--ink),0 3px 10px rgba(0,0,0,.08)}}
@media (prefers-reduced-motion:reduce){
  .lenses.hinting .lens-cell[data-g]::before{animation:none;opacity:.35}
  .lens-cell button,.lens-cell button.pop{transition:none;animation:none}
  .lens-cell[data-g] button:hover,.lens-cell[data-g] button:active{transform:none}}

/* four tiles at 2:1 like the renders; on short screens the grid narrows instead of cropping a product */
.works{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:14px 20px;margin:0 auto;max-width:calc(2 * (100vh - 392px) + 20px);max-width:calc(2 * (100svh - 392px) + 20px);min-width:min(100%,560px)}
.wcard{position:relative;display:block;color:inherit;min-width:0;border-radius:16px;outline-offset:4px}
.wcard .img{position:relative;width:100%;aspect-ratio:2 / 1;border-radius:16px;border:1px solid var(--line);background:#fff;overflow:hidden}
@supports not (aspect-ratio:2 / 1){.wcard .img{height:0;padding-top:50%}.wcard .img img,.wcard .img .chap{position:absolute;top:0;left:0}}
.wcard .img img{width:100%;height:100%;object-fit:cover;transition:transform .8s cubic-bezier(.2,.8,.2,1)}
.wcard .img img.fit{object-fit:contain}
a.wcard:hover .img img,.wcard.has-link:hover .img img{transform:scale(1.03)}
.wcard .meta{display:flex;flex-wrap:wrap;gap:4px 0;margin:8px 0 1px;font-size:12px;line-height:1.5;color:var(--ink-2)}
.wcard .meta span+span::before{content:"|";margin:0 8px;opacity:.5}
.wcard .meta .n{color:var(--accent);font-weight:600}
.wcard h2{font-size:17px;line-height:1.2}
.wcard p{margin:2px 0 0;color:var(--ink-2);font-size:13px;line-height:1.4}
[data-theme="dark"] .wcard .img{border-color:transparent}
/* a chapter with two projects: the card opens the first, the second name is its own link */
.wcard .cover{position:absolute;top:0;left:0;right:0;bottom:0;z-index:1;border-radius:16px}
.wcard .also{position:relative;z-index:2;color:var(--ink);text-decoration:underline;text-decoration-color:var(--line);text-underline-offset:3px}
.wcard .also:hover{text-decoration-color:currentColor}

/* chapter without a page yet: a typographic tile in the storyline's colour */
.wcard .img.type{background:var(--tile);border-color:transparent}
.chap{width:100%;height:100%;display:flex;flex-direction:column;justify-content:space-between;padding:clamp(14px,2.2vw,24px)}
.chap .num{font:700 clamp(30px,3.6vw,44px)/1 var(--display);color:var(--accent);letter-spacing:-.02em}
.chap .verb{display:block;margin-top:6px;font:600 clamp(15px,1.5vw,19px)/1.1 var(--display);letter-spacing:.04em;text-transform:uppercase;color:var(--ink)}
.chap .q{font:500 clamp(15px,1.55vw,19px)/1.35 var(--display);letter-spacing:-.01em;color:var(--ink);max-width:30ch}
.wcard.soon{cursor:default}
.wcard .meta .soon-tag{color:var(--ink-2);opacity:.8}

/* entrance: on load, and again whenever the storyline changes */
@keyframes rise{from{opacity:0;transform:translateY(18px)}to{opacity:1;transform:none}}
.wtitle,.thesis,.wcard{animation:rise .8s cubic-bezier(.2,.8,.2,1) both}
.wcard:nth-child(1){animation-delay:.08s}.wcard:nth-child(2){animation-delay:.16s}.wcard:nth-child(3){animation-delay:.24s}.wcard:nth-child(4){animation-delay:.32s}
.works.swap .wcard{animation:rise .55s cubic-bezier(.2,.8,.2,1) both}
.works.swap .wcard:nth-child(1){animation-delay:0s}.works.swap .wcard:nth-child(2){animation-delay:.05s}.works.swap .wcard:nth-child(3){animation-delay:.1s}.works.swap .wcard:nth-child(4){animation-delay:.15s}
.thesis.swap{animation:rise .45s cubic-bezier(.2,.8,.2,1) both}
.wcard:nth-child(5){animation-delay:.4s}.works.swap .wcard:nth-child(5){animation-delay:.2s}
.wcard:nth-child(6){animation-delay:.48s}.works.swap .wcard:nth-child(6){animation-delay:.25s}

/* All: five projects — two large tiles, then three. Same image height as the old 2 x 2, so it still fits one screen.
   (Since 10/20 a group keeps this grid too: home.js only fades the projects outside it.) */
@media (min-width:641px){
  .works{grid-template-columns:repeat(6,minmax(0,1fr));max-width:calc(2.4 * (100vh - 392px) + 28px);max-width:calc(2.4 * (100svh - 392px) + 28px)}
  .works .wcard{grid-column:span 2}
  .works .wcard:first-child:nth-last-child(5),.works .wcard:first-child:nth-last-child(5)+.wcard{grid-column:span 3}
  .works:has(> .wcard:nth-child(6)){max-width:calc(3 * (100vh - 392px) + 40px);max-width:calc(3 * (100svh - 392px) + 40px)}   /* 3 × 2: same image height budget */
}
@media (prefers-reduced-motion:reduce){.wtitle,.thesis,.wcard,.works.swap .wcard,.thesis.swap{animation:none}.wcard .img img{transition:none}a.wcard:hover .img img,.wcard.has-link:hover .img img{transform:none}html{scroll-behavior:auto}}

/* ---------- more projects: no page yet, one image each (Leo 10/15) — under the tiles, in All and in each storyline ---------- */
.xworks{margin:clamp(40px,6vw,64px) auto 0;max-width:calc(2 * (100vh - 392px) + 20px);max-width:calc(2 * (100svh - 392px) + 20px);min-width:min(100%,560px)}
.xworks{max-width:calc(2.4 * (100vh - 392px) + 28px);max-width:calc(2.4 * (100svh - 392px) + 28px)}
.xworks:empty{display:none}
.xhead{font-size:20px;letter-spacing:-.02em;margin:0 0 14px}
.xgrid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:16px 20px}
.xcard{min-width:0;cursor:default}
.xcard .img{position:relative;width:100%;aspect-ratio:2 / 1;border-radius:14px;border:1px solid var(--line);background:#fff;overflow:hidden}
.xcard .img img{width:100%;height:100%;object-fit:cover}
[data-theme="dark"] .xcard .img{border-color:transparent}
.xcard .meta{display:flex;flex-wrap:wrap;margin:8px 0 1px;font-size:12px;line-height:1.5;color:var(--ink-2)}
.xcard .meta span+span::before{content:"|";margin:0 8px;opacity:.5}
.xcard .meta .soon-tag{opacity:.8}
.xcard h3{margin:0;font-size:15px;line-height:1.25}
.xcard p{margin:2px 0 0;color:var(--ink-2);font-size:13px;line-height:1.4}
.xworks.swap .xcard{animation:rise .55s cubic-bezier(.2,.8,.2,1) both}
@media (max-width:900px){.xgrid{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media (max-width:640px){.xworks{max-width:none;min-width:0}.xgrid{gap:18px 14px}}
@media (prefers-reduced-motion:reduce){.xworks.swap .xcard{animation:none}}

/* ---------- intro (assets/intro.js): the switch first, centred, with the light / dark choice; then it moves up and the projects rise in ---------- */
html.intro .wtitle,.wtitle.no-rise,html.intro .thesis{animation:none}
html.intro .wtitle h1,html.intro .thesis,html.intro .works,html.intro .xworks,html.intro footer{opacity:0}
html.intro .lenses{opacity:0;position:relative;z-index:30}
html.intro.intro-in .lenses{opacity:1;transition:opacity .25s ease}
html.intro-out .wtitle h1,html.intro-out footer{opacity:1;transition:opacity .5s ease .25s}
.wtitle h1.swap{animation:rise .55s cubic-bezier(.2,.8,.2,1) both}
.intro-theme{position:fixed;left:50%;z-index:40;display:flex;align-items:center;gap:8px;transform:translate(-50%,8px);opacity:0;
  transition:opacity .25s ease .08s,transform .25s ease .08s;font:500 13px/1 var(--display);color:var(--ink-2);white-space:nowrap}
html.intro-in .intro-theme{opacity:1;transform:translate(-50%,0)}
.intro-theme button{display:inline-flex;align-items:center;gap:6px;height:30px;padding:0 12px;border-radius:999px;border:1px solid var(--line);
  background:var(--bg);color:var(--ink);font:inherit;cursor:pointer;transition:background .2s,color .2s,border-color .2s}
.intro-theme button svg{width:14px;height:14px}
.intro-theme button[aria-pressed="true"]{background:var(--ink);color:var(--bg);border-color:var(--ink)}
.intro-theme__a{opacity:.85}
html.intro .fold-cue{opacity:0!important;pointer-events:none!important}   /* the scroll cue waits for the intro */
.intro-line{position:fixed;left:50%;z-index:40;margin:0;width:min(760px,calc(100% - 40px));transform:translate(-50%,10px);opacity:0;text-align:center;
  font:600 clamp(22px,2.6vw,32px)/1.25 var(--display);letter-spacing:-.022em;color:var(--ink);text-wrap:balance;transition:opacity .5s ease,transform .5s ease}
html.intro-in .intro-line{opacity:1;transform:translate(-50%,0)}
html.intro-out .intro-line{opacity:0;transform:translate(-50%,-12px);transition:opacity .35s ease,transform .35s ease}
html.intro.intro-in .lenses{transition:opacity .5s ease .15s}
.theme.is-told{animation:told 1.1s ease-out 2}
@keyframes told{0%{box-shadow:0 0 0 0 rgba(0,113,227,.55)}100%{box-shadow:0 0 0 12px rgba(0,113,227,0)}}
@media (max-width:640px){.intro-theme{flex-wrap:wrap;justify-content:center;width:calc(100% - 32px);white-space:normal}.intro-theme__a{flex-basis:100%;text-align:center}}

/* the films (intro.js, step 1; Leo 10/15 "同时开四个窗口 … 播放的同时白色一下切换黑色"): four windows open at once, each plays one
   interaction; at 2 s the page and all four films turn from light to dark together, then the screen snaps to the choice */
html.intro-demo body,html.intro-demo .nav{transition-duration:.12s}
.idemo{position:fixed;inset:0;z-index:45;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:clamp(14px,2.6vh,24px);
  padding:calc(var(--nav) + 10px) 16px 28px;-webkit-tap-highlight-color:transparent;-webkit-user-select:none;user-select:none}
.idemo__grid{--vh:100vh;--w:min(600px,calc((100vw - 56px) / 2),calc(((var(--vh) - var(--nav) - 130px) / 2 - 30px) * 1.6));
  display:grid;grid-template-columns:repeat(2,var(--w));gap:clamp(12px,1.6vw,22px)}
@supports (height:100svh){.idemo__grid{--vh:100svh}}
.idemo__win{margin:0;border-radius:14px;overflow:hidden;background:var(--bg);box-shadow:0 0 0 .5px rgba(0,0,0,.14),0 24px 56px -20px rgba(0,0,0,.32);
  opacity:0;transform:translateY(26px) scale(.9);transition:opacity .35s ease calc(var(--i) * 70ms),transform .7s cubic-bezier(.2,.9,.3,1.1) calc(var(--i) * 70ms)}
[data-theme="dark"] .idemo__win{box-shadow:0 0 0 .5px rgba(255,255,255,.18),0 24px 56px -20px rgba(0,0,0,.7)}
html.idemo-open .idemo__win{opacity:1;transform:none}
html.idemo-out .idemo__win{opacity:0;transform:scale(.95);transition:opacity .2s ease,transform .25s ease}
.idemo__bar{position:relative;height:30px;display:flex;align-items:center;gap:7px;padding:0 12px;background:var(--tile);box-shadow:inset 0 -.5px 0 var(--line)}
.idemo__bar i{flex:none;width:10px;height:10px;border-radius:50%;background:#ff5f57}
.idemo__bar i:nth-child(2){background:#febc2e}.idemo__bar i:nth-child(3){background:#28c840}
.idemo__bar span{position:absolute;inset:0 70px;display:flex;align-items:center;justify-content:center;white-space:nowrap;overflow:hidden;
  font:500 12px/1 var(--display);letter-spacing:-.005em;color:var(--ink-2)}
.idemo__bar b{font-weight:600;color:var(--ink)}
.idemo__bar em{font-style:normal}
.idemo__bar small{display:none;font-size:inherit}
.idemo__win video{display:block;width:var(--w);height:calc(var(--w) / 1.6);object-fit:cover;background:var(--bg)}
/* a small light / dark switch under the windows: it flips with the page, so the change reads as the site's dark mode */
.idemo__mode{position:relative;display:grid;grid-template-columns:1fr 1fr;padding:3px;border-radius:999px;background:var(--tile);box-shadow:inset 0 0 0 .5px var(--line);
  opacity:0;transform:translateY(8px);transition:opacity .4s ease .3s,transform .4s ease .3s}
html.idemo-open .idemo__mode{opacity:1;transform:none}
html.idemo-out .idemo__mode{opacity:0;transition:opacity .2s ease}
.idemo__mode span{position:relative;z-index:1;display:inline-flex;align-items:center;justify-content:center;gap:6px;padding:7px 16px;
  font:500 12.5px/1 var(--display);color:var(--ink-2);transition:color .15s}
.idemo__mode svg{width:13px;height:13px}
.idemo__mode i{position:absolute;left:3px;top:3px;bottom:3px;width:calc(50% - 3px);border-radius:999px;background:var(--bg);
  box-shadow:0 1px 3px rgba(0,0,0,.14),0 0 0 .5px rgba(0,0,0,.06);transition:transform .45s cubic-bezier(.3,1.35,.5,1),background .15s}
[data-theme="dark"] .idemo__mode i{transform:translateX(100%);background:#3a3a3c;box-shadow:none}
html:not([data-theme="dark"]) .idemo__mode span:first-child,[data-theme="dark"] .idemo__mode span:nth-child(2){color:var(--ink)}
.idemo__skip{position:fixed;right:max(18px,env(safe-area-inset-right));bottom:max(18px,env(safe-area-inset-bottom));display:inline-flex;align-items:center;gap:5px;
  height:32px;padding:0 14px 0 16px;border:0;border-radius:999px;cursor:pointer;font:500 12.5px/1 var(--display);color:var(--ink-2);
  background:rgba(255,255,255,.62);background:color-mix(in srgb,var(--bg) 62%,transparent);-webkit-backdrop-filter:blur(14px) saturate(180%);backdrop-filter:blur(14px) saturate(180%);
  box-shadow:0 0 0 .5px rgba(0,0,0,.1),0 4px 14px rgba(0,0,0,.08);opacity:0;transition:opacity .4s ease .5s,color .2s}
.idemo__skip span{font-size:15px;line-height:1;margin-top:-1px}
[data-theme="dark"] .idemo__skip{box-shadow:0 0 0 .5px rgba(255,255,255,.14),0 4px 14px rgba(0,0,0,.4)}
html.idemo-open .idemo__skip{opacity:1}
html.idemo-out .idemo__skip{opacity:0;transition:opacity .15s}
.idemo__skip:hover{color:var(--ink)}
.idemo__skip:focus-visible{outline:2px solid var(--accent);outline-offset:3px}
@media (max-width:640px){
  .idemo{padding:calc(var(--nav) + 8px) 10px 24px}
  .idemo__grid{--w:min(calc((100vw - 30px) / 2),calc(((var(--vh) - var(--nav) - 120px) / 2 - 22px) * 1.6));gap:10px}
  .idemo__win{border-radius:10px}
  .idemo__bar{height:22px;gap:4px;padding:0 8px}
  .idemo__bar i{width:6px;height:6px}
  .idemo__bar span{inset:0 8px 0 40px;justify-content:flex-start;font-size:10px}
  .idemo__bar em{display:none}
  .idemo__bar small{display:inline}
}
@media (prefers-reduced-transparency:reduce){.idemo__skip{background:var(--tile);-webkit-backdrop-filter:none;backdrop-filter:none}}

/* ---------- footer ---------- */
footer{padding:24px 0 36px;font-size:12px;color:var(--ink-2);border-top:1px solid var(--line)}
footer .wrap{display:flex;justify-content:space-between;gap:12px 20px;flex-wrap:wrap}
footer .links a{margin-left:18px}
footer .links a:first-child{margin-left:0}
footer a:hover{color:var(--ink)}

/* ---------- phones ---------- */
@media (max-width:640px){
  .nav .links{display:none}
  .work{padding-top:calc(var(--nav) + 20px)}
  .wtitle h1{font-size:32px}
  .thesis{margin-top:10px}
  /* four choices on a phone: a 2 x 2 switch, every name readable without sideways scrolling */
  /* phones: All + three pills on two rows, every pill as wide as its column */
  .js .lenses{display:grid;grid-template-columns:1fr 1fr;width:100%;gap:10px}
  .lens-cell{display:flex}
  .lens-cell button{width:100%;justify-content:center;padding:11px 10px}
  .works{grid-template-columns:minmax(0,1fr);gap:28px;max-width:none;min-width:0}
  footer .wrap{flex-direction:column}
  footer .links a{margin-left:0;margin-right:18px}
}

/* a project in "More projects" with its own page (RD95, 10/15): the card is a link */
a.xcard{display:block;color:inherit;cursor:pointer}
a.xcard .img img{transition:transform .8s cubic-bezier(.2,.8,.2,1)}
a.xcard:hover .img img{transform:scale(1.03)}
@media (prefers-reduced-motion:reduce){a.xcard .img img{transition:none}a.xcard:hover .img img{transform:none}}

/* ---------- groups dim, corners square (10/20, Leo: "如果选personal robot其他几个透明度就降低 灰掉其实就行 一页一共6个项目 … 不要圆角了")
   A group keeps the six projects and "More projects" where they are; the ones outside it fade to grey and stay links.
   (Opacity sits on the children: the cards' rise animation keeps opacity 1 on the card itself.) ---------- */
.wcard,.wcard .img,.wcard .cover,.xcard .img{border-radius:0}
.wcard>*,.xcard>*{transition:opacity .45s ease,filter .45s ease}
body[data-lens] .wcard.is-dim>*,body[data-lens] .xcard.is-dim>*{opacity:.28;filter:grayscale(1)}
body[data-lens] a.wcard.is-dim:hover>*,body[data-lens] a.xcard.is-dim:hover>*{opacity:.6}
@media (min-width:641px){.works:has(> .wcard:nth-child(6))+.xworks{max-width:calc(3 * (100vh - 392px) + 40px);max-width:calc(3 * (100svh - 392px) + 40px)}}   /* More projects as wide as the 3 x 2 above */
@media (prefers-reduced-motion:reduce){.wcard>*,.xcard>*{transition:none}}

/* 10/20 Leo "选了谁不够明显": the open group is filled with its colour and a white label; the other two step back */
.lens-cell[data-g] button[aria-selected="true"]{background:var(--c);color:#fff;
  box-shadow:inset 0 1px 1px rgba(255,255,255,.35),inset 0 -8px 14px -10px rgba(0,0,0,.28),0 0 0 .5px color-mix(in srgb,var(--c) 70%,#000),0 6px 18px color-mix(in srgb,var(--c) 40%,transparent)}
[data-theme="dark"] .lens-cell[data-g] button[aria-selected="true"]{background:color-mix(in srgb,var(--c) 80%,#000);color:#fff;
  box-shadow:inset 0 1px 1px rgba(255,255,255,.25),0 0 0 .5px rgba(255,255,255,.18),0 8px 24px color-mix(in srgb,var(--c) 35%,transparent)}
.lens-cell[data-g] button[aria-selected="true"]::before{opacity:0}
.lens-cell[data-g] button[aria-selected="true"]::after{opacity:.3}
.lens-cell[data-g] button[aria-selected="true"] .dot,[data-theme="dark"] .lens-cell[data-g] button[aria-selected="true"] .dot{background:#fff;box-shadow:0 0 0 2px rgba(255,255,255,.28)}
body[data-lens] .lens-cell[data-g] button[aria-selected="false"]{color:var(--ink-2)}
body[data-lens] .lens-cell[data-g] button[aria-selected="false"]:hover{color:var(--ink)}

/* ---------- global nav, after apple.com (Leo 10/21 "顶部菜单栏 学苹果这种干净的"): one quiet 44 px row, 12 px type, the
   name, five links, Contact and the theme switch spread evenly over 1024 px; no pills, no line. Phones: name, theme, menu. ---------- */
:root{--nav:44px}
.nav{background:rgba(250,250,252,.8);-webkit-backdrop-filter:saturate(180%) blur(20px);backdrop-filter:saturate(180%) blur(20px);border-bottom:0}
[data-theme="dark"] .nav{background:rgba(22,22,23,.8)}
.nav.scrolled{border-color:transparent}
.nav .wrap{max-width:1024px;height:var(--nav);padding:0 22px;gap:0;justify-content:space-between}
.nav ul,.nav .links,.nav .right{display:contents}
.nav ul li{list-style:none}
.nav .brand,.nav ul a,.nav .right>a{display:block;padding:0 8px;font:400 12px/var(--nav) var(--text);letter-spacing:-.01em;color:var(--ink);opacity:.8;
  white-space:nowrap;background:none;border-radius:0;transition:opacity .2s}
.nav .brand{font-weight:600;opacity:.92}
.nav .brand:hover,.nav ul a:hover,.nav ul a.on,.nav .right>a:hover{opacity:1}
.nav .theme{display:grid;place-items:center;width:auto;height:var(--nav);padding:0 8px;border:0;border-radius:0;background:none;color:var(--ink);opacity:.8;cursor:pointer}
.nav .theme:hover{opacity:1}
.nav .theme svg{width:15px;height:15px}
.nav .burger{display:none;position:relative;width:40px;height:var(--nav);margin-right:-8px;padding:0;border:0;border-radius:0;background:none;color:var(--ink);cursor:pointer}
.nav .burger i{position:absolute;left:12px;top:50%;width:16px;height:1.2px;border-radius:1px;background:currentColor;opacity:.8;transition:transform .25s;transform:translateY(-3px)}
.nav .burger i:last-child{transform:translateY(3px)}
body.menu .nav .burger i:first-child{transform:rotate(45deg)}
body.menu .nav .burger i:last-child{transform:rotate(-45deg)}
.mnav{position:fixed;inset:var(--nav) 0 0;z-index:49;display:none;padding-top:20px;background:#fafafc}
[data-theme="dark"] .mnav{background:#161617}
body.menu .mnav{display:block}
.mnav .wrap{max-width:1024px;padding:0 48px}
.mnav a{display:block;padding:6px 0;border:0;font:600 28px/1.25 var(--display);letter-spacing:-.015em;color:var(--ink)}
.mnav a.c{margin-top:22px;font:400 14px/1.4 var(--text);color:var(--ink-2)}
@media (max-width:833px){
  .nav .wrap{padding:0 16px}
  .nav ul,.nav .links,.nav .right>a{display:none}
  .nav .brand{margin-right:auto;padding-left:0}
  .nav .burger{display:block}
}
@media (max-width:480px){.mnav .wrap{padding:0 28px}}

/* ---------- home: the projects as apple.com's tiles (Leo 10/21 "项目页面也学他这种 充满屏幕 不要一个一个小方 一点张力也没有"):
   two to a row across the whole window, 12 px apart; the name large and centred at the top, one line, "Learn more", the
   product big underneath. Light tiles in both themes (the renders are on white; multiply drops the white into the tile). ---------- */
.works,body:not([data-lens]) .works,.works:has(> .wcard:nth-child(6)){display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;
  max-width:none;min-width:0;margin:0 12px}
.works .wcard,body:not([data-lens]) .works .wcard,body:not([data-lens]) .works .wcard:first-child:nth-last-child(5),body:not([data-lens]) .works .wcard:first-child:nth-last-child(5)+.wcard{grid-column:auto}
.works .wcard{--wt:#f5f5f7;position:relative;display:flex;flex-direction:column;align-items:center;min-height:clamp(560px,47vw,760px);
  padding:clamp(44px,4.2vw,60px) clamp(20px,3vw,44px) 0;overflow:hidden;border-radius:0;background:var(--wt);color:#1d1d1f;text-align:center;outline-offset:-3px}
.works .wcard .meta{order:0;justify-content:center;gap:0;margin:0 0 10px;font-size:12px;letter-spacing:.01em;color:#6e6e73}
.works .wcard .meta>span:nth-child(2){display:none}
.works .wcard .meta span+span::before{color:#6e6e73}
.works .wcard h2{order:1;font:600 clamp(34px,3.6vw,52px)/1.06 var(--display);letter-spacing:-.025em;color:#1d1d1f}
.works .wcard p{order:2;max-width:26em;margin:8px 0 0;font-size:clamp(17px,1.55vw,22px);line-height:1.3;color:#1d1d1f}
.works .wcard .cta{order:3;display:inline-block;margin-top:20px;padding:10px 21px;border-radius:980px;background:#005eae;color:#fff;font:400 15px/1.2 var(--text);letter-spacing:-.01em;transition:background .2s}
.works a.wcard:hover .cta{background:#0a6bc6}
.works .wcard .img{order:5;flex:1 1 auto;display:flex;align-items:center;justify-content:center;width:calc(100% + 2 * clamp(20px,3vw,44px));
  min-height:0;margin-top:clamp(16px,2vw,28px);aspect-ratio:auto;border:0;border-radius:0;background:none;overflow:visible}
.works .wcard .img img,.works .wcard .img img.fit{width:100%;height:100%;max-height:none;object-fit:contain;object-position:center 60%;mix-blend-mode:multiply}
.works a.wcard:hover .img img{transform:scale(1.025)}
/* ROUTE is a photograph: it fills the tile, the words sit on its light wall */
.works .wcard--photo{--wt:#dadada}
.works .wcard--photo .img{position:absolute;left:0;right:0;bottom:0;top:auto;width:auto;height:60%;margin:0;z-index:0;
  -webkit-mask-image:linear-gradient(to bottom,transparent 0,#000 24%);mask-image:linear-gradient(to bottom,transparent 0,#000 24%)}
.works .wcard--photo .img img{object-fit:cover;object-position:center 70%;mix-blend-mode:normal}
.works .wcard--photo>*:not(.img){position:relative;z-index:1}
[data-theme="dark"] .works .wcard{--wt:#f5f5f7}
[data-theme="dark"] .works .wcard--photo{--wt:#dadada}
[data-theme="dark"] .works .wcard .img{border-color:transparent}
.works .wcard .ca--row{order:4;justify-content:center;margin:18px 0 0}
.work .wtitle,.work .thesis{position:relative}
@media (max-width:734px){
  .works,body:not([data-lens]) .works,.works:has(> .wcard:nth-child(6)){grid-template-columns:minmax(0,1fr);margin:0}
  .works .wcard{min-height:clamp(480px,130vw,620px);padding:40px 20px 0}
  .works .wcard .img{width:calc(100% + 40px)}
}

/* ---------- home tiles shorter than the screen (Leo 10/21 "不要全铺满 看前两个的时候能看到下面的一点一小部分 这样用户知道要往下翻阅"):
   the first row ends above the fold and the top of the next row shows, as on apple.com. --wtop = where the tiles start
   (nav + "Projects"; the group pills that used to sit here went 10/21), --peek = how much of the next row shows. ---------- */
.works{--wtop:140px;--peek:clamp(72px,15vh,180px);--th:clamp(440px,min(calc(100vh - var(--wtop) - 12px - var(--peek)),calc((100vw - 36px) * .75)),740px)}
@supports (height:100svh){.works{--peek:clamp(72px,15svh,180px);--th:clamp(440px,min(calc(100svh - var(--wtop) - 12px - var(--peek)),calc((100vw - 36px) * .75)),740px)}}
.works .wcard{min-height:0;height:var(--th);padding-top:clamp(32px,5.4vh,60px)}
/* ROUTE's photo under the words: the whole picture (2 : 1) at the height that is left, never cropped at the top or the
   bottom (the traveler's head, the wheels); a wide tile shows its edges fading into the tile, a narrow one crops its sides */
.works .wcard--photo .img{height:auto;top:max(40%,240px);display:flex;justify-content:center;overflow:hidden;-webkit-mask-image:none;mask-image:none}
.works .wcard--photo .img img{flex:none;width:auto;height:100%;max-width:none;aspect-ratio:2 / 1;object-fit:cover;object-position:center;
  -webkit-mask-image:linear-gradient(to right,transparent,#000 14%,#000 86%,transparent),linear-gradient(to bottom,transparent,#000 22%);
  -webkit-mask-composite:source-in;mask-image:linear-gradient(to right,transparent,#000 14%,#000 86%,transparent),linear-gradient(to bottom,transparent,#000 22%);mask-composite:intersect}
/* ---------- the timeline is the first tile, across the whole row (Leo 10/21 "如果选了pr组的话 就第一页像苹果那个
   第一页一样横画幅 展示这个东西"); shown to everyone since the research groups went, the same day. timeline.js
   draws it. The spread needs 860 px of width to stay readable, so on short screens this tile is a little taller than
   the peek rule. Light in both themes, like the other tiles. ---------- */
.works .whero{--hp:clamp(16px,2vw,32px);grid-column:1 / -1;display:flex;align-items:center;justify-content:center;
  padding:var(--hp);background:#f5f5f7;color:#1d1d1f;--ink:#1d1d1f;--ink-2:#6e6e73}
/* the timeline takes the whole tile: full width, the height that fits the screen above the peek (at least 566 px, so the
   type stays readable), and is laid out to that box (timeline.js, --tl-fit) — Leo 10/21 "铺开 不要聚集在中间 根据空间去排版啊" */
.whero__tl{--tl-fit:1;display:flex;flex-direction:column;justify-content:center;width:100%;height:clamp(566px,calc(100vh - var(--wtop) - 20px - 12px - var(--peek) - 2 * var(--hp)),900px)}
@supports (height:100svh){.whero__tl{height:clamp(566px,calc(100svh - var(--wtop) - 20px - 12px - var(--peek) - 2 * var(--hp)),900px)}}
[data-theme="dark"] .whero .tl{--tl-blue:#005eae;--tl-tint:rgba(37,99,235,.09);--tl-tint-h:rgba(37,99,235,.15);--tl-q:#52514e;--tl-cap:#79797a;--tl-bar:0,94,174}
[data-theme="dark"] .whero .tlw .tl-f img{opacity:.24}[data-theme="dark"] .whero .tlw .tl-f:hover img{opacity:.55}[data-theme="dark"] .whero .tlw .tl-f--link:hover img{opacity:1}
@media (max-width:979px){
  .works .whero{padding:28px clamp(16px,4vw,32px) 32px}
  .whero__tl{--tl-fit:0;display:block;height:auto}
}
@media (max-width:734px){
  .works{--wtop:214px;--peek:clamp(48px,12vh,120px);--th:clamp(400px,calc(100vh - var(--wtop) - 12px - var(--peek)),600px)}
  @supports (height:100svh){.works{--peek:clamp(48px,12svh,120px);--th:clamp(400px,calc(100svh - var(--wtop) - 12px - var(--peek)),600px)}}
  .works .wcard{padding-top:clamp(28px,4.6vh,40px)}
  .works .wcard--photo .img{top:max(40%,220px)}
}

/* ---------- home tiles, 10/21 01:07 (Leo, screenshot of the ElectroGlide / CIHANG row: "文字压缩 产品放大一些，并且尽量左右两侧产品
   底部保持同一水平线（不强求如有特殊情况）"): smaller words, and each product drawn from its own outline instead of its picture's
   white margins, as large as the space under the words allows, standing on one baseline a little above the tile's bottom
   edge, so two tiles in a row line up. Per picture: --A its aspect (w / h) and the product's box inside it as fractions
   (--bx0 left, --bw width, --by1 bottom, --bh height; measured on the files 10/21); --fh trims a product that would get too
   big (CloudBuds). The photograph tile (ROUTE) is unchanged. (_tools/incoming/tiles-v1) ---------- */
.works .wcard{padding-top:clamp(24px,3.8vh,44px)}
.works .wcard .meta{margin:0 0 6px}
.works .wcard h2{font-size:clamp(26px,2.5vw,38px)}
.works .wcard p{max-width:30em;margin-top:4px;font-size:clamp(14px,1.1vw,16px);line-height:1.35;text-wrap:balance}
.works .wcard .cta{margin-top:12px;padding:7px 15px;font-size:13px}
@supports (height:1cqh){
  .works .wcard:not(.wcard--photo) .img{position:relative;container-type:size;margin-top:clamp(6px,1.2vh,14px)}
  .works .wcard:not(.wcard--photo) .img img,.works .wcard:not(.wcard--photo) .img img.fit{
    --g:clamp(16px,6cqh,44px);--av:calc(100cqh - var(--g) - 3cqh);
    --W:min(calc(92cqw / var(--bw,1)),calc(var(--av) * var(--fh,1) * var(--A,2) / var(--bh,1)));
    position:absolute;width:var(--W);height:auto;max-width:none;max-height:none;object-fit:fill;
    left:calc(50cqw - (var(--bx0,0) + var(--bw,1) / 2) * var(--W));
    top:calc(100cqh - var(--g) - var(--by1,1) * var(--W) / var(--A,2))}
  .works .wcard img[src*="img/electroglide.jpg"]{--A:2;--bx0:.08;--bw:.84;--by1:.91;--bh:.8188}
  .works .wcard img[src*="img/cihang.jpg"]{--A:2;--bx0:.07;--bw:.8544;--by1:.8525;--bh:.6537}
  .works .wcard img[src*="img/xiongda.jpg"]{--A:2;--bx0:.4106;--bw:.175;--by1:.9444;--bh:.8911}
  .works .wcard img[src*="img/cloudbuds.jpg"]{--A:1.7778;--bx0:.2569;--bw:.4869;--by1:.8;--bh:.5978;--fh:.78}
  .works .wcard img[src*="img/ar-helmet.jpg"]{--A:2;--bx0:.0187;--bw:.9625;--by1:.925;--bh:.8237}
}

/* ROUTE tile, 10/21 01:19 (Leo: "右侧的机器人小了 需要和左侧一样"): the robot render on its own grey instead of the airport
   photo, placed like the other products, so it stands as tall as XIONGDA on the same baseline. The photo stays in More projects. */
.works .wcard--grey,[data-theme="dark"] .works .wcard--grey{--wt:#e2e3e5}   /* = the render's background, rgb(226,227,229) */
.works .wcard--grey .img img{mix-blend-mode:normal}
@supports (height:1cqh){
  .works .wcard img[src*="img/route-robot.jpg"]{--A:1;--bx0:.1667;--bw:.6657;--by1:.9259;--bh:.8519}
}
.works .wcard--grey>*:not(.img){position:relative;z-index:1}   /* the words over the render's (invisible) top edge */

/* ---------- home, first screen: the film (Leo 10/21, option 1 of his five: "选1 视频我在剪辑制作，你先用ono官网用的哪个视频").
   Full width under the nav: his name and one line on top, the film filling the rest, as tall as the screen less a peek of
   what follows (apple.com). The words sit above the film, not on it — the reel has light and black frames. (hero_film.py) ---------- */
.hfilm{--hpeek:clamp(72px,15vh,180px);display:flex;flex-direction:column;margin-top:var(--nav);
  height:max(480px,calc(100vh - var(--nav) - var(--hpeek)));background:#fff;color:#1d1d1f;text-align:center;overflow:hidden}
@supports (height:100svh){.hfilm{--hpeek:clamp(72px,15svh,180px);height:max(480px,calc(100svh - var(--nav) - var(--hpeek)))}}
.hfilm__t{flex:none;padding:clamp(26px,5vh,56px) 24px clamp(18px,3.2vh,34px)}
.hfilm__name{margin:0;font:600 clamp(40px,5.4vw,80px)/1.02 var(--display);letter-spacing:-.035em}
.hfilm__line{max-width:32em;margin:12px auto 0;font-size:clamp(17px,1.6vw,24px);line-height:1.3;text-wrap:balance}
.hfilm__v{position:relative;flex:1 1 auto;min-height:0;background:#eef0f4}
.hfilm__v video{position:absolute;inset:0;display:block;width:100%;height:100%;object-fit:cover}
[data-theme="dark"] .hfilm{background:#000;color:#f5f5f7}
[data-theme="dark"] .hfilm__v{background:#111}
/* "Projects" under the film (h2 now; the name is the page's h1) */
.hfilm + .work{padding-top:clamp(28px,4vh,44px)}
.wtitle h2{margin:0;font-size:clamp(30px,3.4vw,40px);line-height:1.2}
/* the tiles below the film: a row sized as if it were at the top of the screen, so each one shows the next peeking in */
.hfilm + .work .works{--th:clamp(440px,min(calc(100vh - var(--nav) - 24px - var(--peek)),calc((100vw - 36px) * .75)),740px)}
@supports (height:100svh){.hfilm + .work .works{--th:clamp(440px,min(calc(100svh - var(--nav) - 24px - var(--peek)),calc((100vw - 36px) * .75)),740px)}}
@media (max-width:734px){
  .hfilm{height:max(460px,calc(100vh - var(--nav) - 96px))}
  @supports (height:100svh){.hfilm{height:max(460px,calc(100svh - var(--nav) - 96px))}}
  .hfilm__t{padding:28px 20px 18px}
  .hfilm + .work{padding-top:24px}
  .wtitle h2{font-size:32px}
  .hfilm + .work .works{--th:clamp(400px,calc(100vh - var(--nav) - 24px - var(--peek)),600px)}
  @supports (height:100svh){.hfilm + .work .works{--th:clamp(400px,calc(100svh - var(--nav) - 24px - var(--peek)),600px)}}
}

/* ---------- the home film whole (Leo 10/21 "全尺寸"): full width at 16:9 under the nav, never cropped (on a short wide
   screen its bottom edge runs just past the fold). The name and the line follow under it. "Projects" centred (Leo "放中间或者往左移动"). (film_full.py) ---------- */
.hfilm{height:auto}
.hfilm__v{order:-1;flex:none;width:100%;aspect-ratio:16 / 9}
.hfilm__v video{object-fit:contain}
.hfilm__t{padding:clamp(30px,5vh,60px) 24px 0}
.hfilm + .work .wtitle{justify-content:center;margin-bottom:clamp(16px,2.6vh,28px);text-align:center}
@media (max-width:734px){.hfilm{height:auto}.hfilm__t{padding:28px 20px 0}}

/* ---------- the film alone: no name, no "Projects" (Leo 10/21 03:21 "去掉 包括project也去掉"). The name is kept for screen
   readers as a hidden h1; the tiles start one tile gap under the film. (no_title.py) ---------- */
.vh{position:absolute!important;width:1px;height:1px;margin:-1px;padding:0;border:0;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
.hfilm + .work{padding-top:12px}
@media (max-width:734px){.hfilm + .work{padding-top:12px}}

/* ---------- the award marks flash in the film's bottom-right corner when the home opens, then go (Leo 10/21 03:29
   "上来视频右下角闪现一下需要的logo"). hfilm_awards.py ---------- */
.hfilm__aw{position:absolute;z-index:2;right:clamp(14px,2.4vw,40px);bottom:clamp(12px,2.2vw,36px);display:flex;align-items:center;
  gap:clamp(10px,1.4vw,22px);pointer-events:none}
.hfilm__aw img{display:block;width:auto;height:clamp(22px,3vw,46px);opacity:0;animation:hfaw 5.2s cubic-bezier(.2,.8,.2,1) .9s both}
.hfilm__aw img:nth-child(2){animation-delay:1.02s}
.hfilm__aw img:nth-child(3){animation-delay:1.14s}
@keyframes hfaw{0%{opacity:0;transform:translateY(10px)}10%{opacity:1;transform:none}82%{opacity:1;transform:none}100%{opacity:0;transform:none}}
@media (prefers-reduced-motion:reduce){@keyframes hfaw{0%{opacity:0}8%{opacity:1}84%{opacity:1}100%{opacity:0}}}

/* ---------- the award marks stay inside the first screen (Leo 10/21 03:35 "太往下了看不到"): on a short screen the film's bottom
   edge runs past the fold, so the marks sit on the screen's bottom instead of the film's, whichever is higher. (aw_fold.py) ---------- */
.hfilm__aw{bottom:auto;top:min(calc(100% - clamp(22px,3vw,46px) - clamp(12px,2.2vw,36px)),calc(100vh - var(--nav) - clamp(22px,3vw,46px) - clamp(18px,2.6vw,40px)))}
@supports (height:100svh){.hfilm__aw{top:min(calc(100% - clamp(22px,3vw,46px) - clamp(12px,2.2vw,36px)),calc(100svh - var(--nav) - clamp(22px,3vw,46px) - clamp(18px,2.6vw,40px)))}}

/* ---------- the tiles are big again (Leo 10/21 "这些尺寸都坏了 需要恢复大的", with a screenshot of four wide, short
   tiles whose products look tiny) ----------
   The two fold patches above ("home tiles shorter than the screen", "the tiles below the film") pinned every tile to
   --th, a height taken from the window's HEIGHT alone. On a wide, short window (his is about 2000 x 735 CSS px) that
   leaves a 975 px wide tile only 555 px tall, and the product - fitted with object-fit:contain - is then scaled by the
   height, so it sits small between two empty margins. A tile is now never shorter than apple.com's own tile height
   (47 % of the window width, 560-760 px) and still grows with a tall window; the next row keeps peeking in wherever
   the screen is tall enough for that to happen by itself. Phones (one column) keep their own heights below. */
.works{--thbig:clamp(560px,47vw,760px)}
.works,.hfilm + .work .works{--th:max(var(--thbig),min(calc(100vh - var(--nav) - 24px - var(--peek)),calc((100vw - 36px) * .75)))}
@supports (height:100svh){.works,.hfilm + .work .works{--th:max(var(--thbig),min(calc(100svh - var(--nav) - 24px - var(--peek)),calc((100vw - 36px) * .75)))}}
.works .wcard{padding-top:clamp(44px,4.2vw,60px)}
@media (max-width:734px){
  .works{--thbig:clamp(480px,130vw,620px)}
  .works .wcard{padding-top:40px}
}
