.clhh-brand,.clhh-copy{position:fixed;z-index:20;color:#dcf8f0;font-family:Arial,'PingFang SC',sans-serif}.clhh-brand{top:42px;left:42px;text-decoration:none;font-size:25px;letter-spacing:5px;font-weight:700}.clhh-brand span{display:block;font-size:8px;letter-spacing:2px;font-weight:400;margin-top:8px;opacity:.7}.clhh-copy{bottom:54px;left:42px;transition:opacity .4s}.clhh-copy>span{font-size:9px;letter-spacing:2px;opacity:.65}.clhh-copy h1{font-size:28px;font-weight:400;letter-spacing:2px;margin:12px 0 20px}.clhh-copy a{color:inherit;font-size:11px;letter-spacing:2px;text-decoration:none;border-bottom:1px solid #ffffff50;padding-bottom:7px}.clhh-scrolled .clhh-copy{opacity:0;pointer-events:none}
/* Inbound links to the SEO landing pages plus the ICP filing. Unlike .clhh-copy
   these stay visible while scrolling: the ICP number is a compliance
   requirement and must not be hidden. */
.clhh-links,.clhh-legal{position:fixed;z-index:20;right:42px;text-align:right;font-family:Arial,'PingFang SC',sans-serif}.clhh-links{bottom:54px;display:flex;gap:22px;justify-content:flex-end}.clhh-links a{color:#dcf8f0;opacity:.7;font-size:11px;letter-spacing:2px;text-decoration:none;transition:opacity .2s}.clhh-links a:hover,.clhh-links a:focus-visible{opacity:1}.clhh-legal{bottom:30px}.clhh-legal a{color:#dcf8f0;opacity:.45;font-size:10px;letter-spacing:1px;text-decoration:none}.clhh-legal a:hover,.clhh-legal a:focus-visible{opacity:.9}
/* Language switch. On desktop it sits to the left of the engine's WORK/CONTACT
   nav pill and is centred on it vertically. That pill is drawn into the WebGL
   canvas rather than the DOM, so it cannot be laid out against -- there is no
   element to anchor to. But it is right-anchored, and measured identically at
   viewport widths 1280/1440/1680/1920: its text box is always [W-217, W-69] and
   its rounded outline always [W-246, W-34], i.e. a constant right margin rather
   than a proportional one. So the fixed offsets below hold at any width, and
   this doesn't need to chase the pill as the window resizes. */
.clhh-lang{position:fixed;z-index:20;right:274px;top:65px;transform:translateY(-50%);display:flex;align-items:baseline;gap:14px;font-family:Arial,'PingFang SC',sans-serif}
.clhh-lang a,.clhh-lang span{font-size:11px;line-height:1;letter-spacing:2px;text-decoration:none}
.clhh-lang a{color:#dcf8f0;opacity:.55;transition:opacity .2s}
.clhh-lang a:hover,.clhh-lang a:focus-visible{opacity:1}
/* The current language is underlined with text-decoration rather than a bottom
   border. A border plus padding is taken out of the flex item's own content box,
   which pushed "EN" 4px above "中文" once the two sat on one line. The explicit
   line-height matters too: the Latin label sets in Arial and the Chinese one
   falls back to PingFang, whose taller default line box would otherwise leave
   the two baselines at different heights. */
.clhh-lang span{color:#dcf8f0;text-decoration:underline;text-decoration-color:#ffffff50;text-underline-offset:4px;text-decoration-thickness:1px}
/* Mobile keeps the switch below the pill instead of beside it: at 390 the pill
   already reaches x=144 for that same constant right margin, and the CLHH
   brand occupies the band to its left. */
/* The slogan beside the wordmark: one span per line, scrambled into place on
   load by clhh.js. It clears out with .clhh-copy once you scroll into the
   sections, leaving only the brand and the pieces that must stay reachable. */
.clhh-magic{position:fixed;z-index:20;left:240px;top:42px;font-family:Arial,'PingFang SC',sans-serif;color:#dcf8f0;font-size:22px;letter-spacing:3px;line-height:1.3;pointer-events:none;transition:opacity .4s}
.clhh-magic span{display:block}
.clhh-scrolled .clhh-magic{opacity:0}
@media(max-width:700px){.clhh-links,.clhh-legal,.clhh-lang{right:22px}.clhh-links{bottom:35px;gap:14px}.clhh-links a{font-size:10px;letter-spacing:1px}.clhh-legal{bottom:16px}.clhh-legal a{font-size:9px}.clhh-lang{top:118px;transform:none;gap:12px}.clhh-lang a,.clhh-lang span{font-size:10px;letter-spacing:1px}
/* Mobile has no room beside the wordmark: the nav pill already reaches x=144
   there, over the brand itself. The slogan drops below the brand instead. */
.clhh-magic{left:22px;top:104px;font-size:14px;letter-spacing:2px}}
/* The contact cards, carried over from the Vue homepage that used to hold /.
   They appear in two places, both of which were otherwise dead ends: the
   Contact screen (the nav pill's modal, which offers "Start a Project" and
   nothing else), and the end of the scroll (the footer screen with the CLHH
   ring, which carries no way to reach anyone at all).
   On the Contact screen they sit in the band it leaves free: below the
   LED -> VOD -> AI wordmark, above the right-hand link row, and clear of the
   scene's own links in the lower left. Hidden the rest of the time, so they
   never compete with the first screen.
   Styled to this overlay rather than to the old site -- same #dcf8f0,
   hairlines and blur as the rest of clhh.css -- so they read as part of the
   page they now live on. */
/* Centred with left/right + justify-content rather than left:50% and a
   translate. A fixed box anchored at left:50% is only 50vw wide, so the row
   shrink-to-fit inside half the screen and squeezed the QR card's caption into
   three lines. */
.clhh-contact{position:fixed;z-index:25;left:0;right:0;bottom:96px;display:flex;justify-content:center;align-items:stretch;gap:10px;padding:0 42px;box-sizing:border-box;font-family:Arial,'PingFang SC',sans-serif;color:#dcf8f0}
.clhh-contact[hidden]{display:none}
/* The QR card is sized 100% of the panel on a phone; without this its padding
   and border are added on top of that and it hangs past the right edge. */
.clhh-contact,.clhh-contact *{box-sizing:border-box}
.clhh-contact-list{display:flex;gap:10px;margin:0;padding:0;list-style:none}
.clhh-contact-list li{display:flex;flex-direction:column;justify-content:space-between;gap:11px;padding:12px 15px;border:1px solid #ffffff26;border-radius:3px;background:#0b0f14a6;-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px)}
.clhh-contact-list span{font-size:9px;letter-spacing:2px;opacity:.5;white-space:nowrap}
.clhh-contact-list a{color:#dcf8f0;font-size:12px;letter-spacing:.4px;white-space:nowrap;text-decoration:none;border-bottom:1px solid #ffffff33;padding-bottom:2px;transition:border-bottom-color .2s}
.clhh-contact-list a:hover,.clhh-contact-list a:focus-visible{border-bottom-color:#dcf8f0}
/* The Douyin card is the one with a picture in it, so it is laid out as the
   QR beside its label and hint rather than stacked like the others. */
.clhh-contact-qr{display:flex;align-items:center;gap:13px;padding:11px 15px;border:1px solid #ffffff26;border-radius:3px;background:#0b0f14a6;-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);color:#dcf8f0;text-decoration:none;transition:border-color .2s}
.clhh-contact-qr:hover,.clhh-contact-qr:focus-visible{border-color:#ffffff73}
.clhh-contact-code{position:relative;flex:none;display:block;width:58px;height:58px;padding:4px;border-radius:2px;background:#fff}
.clhh-contact-code svg{display:block;width:100%;height:100%}
/* The 抖 badge, as on the old site -- it is what keeps a bare QR from reading
   as an anonymous square. */
.clhh-contact-code i{position:absolute;left:50%;top:50%;display:grid;place-items:center;width:22px;height:22px;border-radius:5px;color:#fff;background:#050606;font:400 12px/1 Arial,'PingFang SC',sans-serif;transform:translate(-50%,-50%)}
.clhh-contact-qr-text{display:flex;flex-direction:column;gap:7px;max-width:190px}
.clhh-contact-qr-text b{font-size:9px;font-weight:400;letter-spacing:2px;opacity:.5}
.clhh-contact-qr-text em{font-size:11px;line-height:1.5;letter-spacing:.4px;font-style:normal;opacity:.8}
/* Below 1100 the five cards no longer fit on one line, so the row wraps. */
@media(max-width:1100px){.clhh-contact-list{flex-wrap:wrap;justify-content:center}}
/* On a phone the row becomes a two-column grid with the QR card across the
   bottom. A grid rather than a wrapping flex row on purpose: the cards hold
   nowrap values like "lumina-os.clhh.tech", whose min-content width is wider
   than half of 390, so flex would drop to one column per row. The old site
   stacked them one per row too, but it was a page you scrolled -- here it is
   an overlay on a fixed screen, and one column per row covers 40% of it. */
@media(max-width:700px){.clhh-contact{bottom:78px;padding:0 22px;gap:8px;flex-direction:column}
.clhh-contact-list{display:grid;grid-template-columns:1fr 1fr;gap:8px;flex:1}
.clhh-contact-list li{padding:10px 12px;gap:7px}
.clhh-contact-list span{font-size:8px;letter-spacing:1px}
.clhh-contact-list a{font-size:11px}
.clhh-contact-qr{width:100%;padding:9px 12px;gap:11px}
.clhh-contact-code{width:46px;height:46px;padding:3px}
.clhh-contact-code i{width:18px;height:18px;font-size:10px}
.clhh-contact-qr-text{max-width:none;gap:5px}
.clhh-contact-qr-text em{font-size:10px}}

/* The project film reel. The 3D scene can only ever play one video at a time --
   every project card shares a single VideoTexture fed by the global
   WorkItems/videoURL state, and the GL text channel has no Chinese glyphs -- so
   the multi-clip view with captions is a DOM overlay of its own, opened from
   the project view. Bottom-centre is the one band the project view leaves free:
   the engine's own panel owns the left column and the nav pill owns the right. */
.clhh-reel-open{position:fixed;z-index:30;left:50%;bottom:54px;transform:translateX(-50%);display:inline-flex;align-items:center;gap:10px;padding:11px 20px;border:1px solid #ffffff3d;border-radius:999px;background:#0b0f14a6;color:#dcf8f0;font-family:Arial,'PingFang SC',sans-serif;font-size:11px;letter-spacing:2px;cursor:pointer;backdrop-filter:blur(8px);transition:border-color .2s,background .2s}
.clhh-reel-open[hidden]{display:none}
.clhh-reel-open:hover,.clhh-reel-open:focus-visible{border-color:#ffffff8a;background:#0b0f14d9}
.clhh-reel-open b{font-weight:400;opacity:.5}
/* A scrim, not a curtain: the scene keeps moving behind the reel, which is the
   point of opening the films over it. The blur is what keeps the caption and
   the counter legible -- at this alpha, unblurred text sitting directly on
   moving footage reads badly. */
.clhh-reel{position:fixed;inset:0;z-index:60;background:#04070a9e;color:#dcf8f0;font-family:Arial,'PingFang SC',sans-serif;opacity:0;visibility:hidden;transition:opacity .25s,visibility .25s;-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px)}
/* Without backdrop-filter (older Safari, some Android WebViews) the blur above
   is simply dropped, and 62% over moving footage is not readable. Go opaque. */
@supports not ((backdrop-filter:blur(10px)) or (-webkit-backdrop-filter:blur(10px))){.clhh-reel{background:#04070af2}}
.clhh-reel.is-open{opacity:1;visibility:visible}
.clhh-reel-stage{position:absolute;inset:0;overflow:hidden;cursor:grab;touch-action:pan-y}
.clhh-reel-stage.is-dragging{cursor:grabbing}
.clhh-reel-track{display:flex;height:100%;will-change:transform}
.clhh-reel-track.is-animating{transition:transform .42s cubic-bezier(.33,1,.68,1)}
/* One clip per screen, its caption directly underneath -- mixed portrait and
   landscape sources, so the video is sized by max-height and letterboxed rather
   than cropped to a common ratio. */
.clhh-reel-slide{flex:0 0 100%;min-width:0;box-sizing:border-box;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:22px;padding:60px 5vw 116px;margin:0}
.clhh-reel-slide video{display:block;max-width:100%;max-height:62vh;background:#000;border-radius:2px;box-shadow:0 24px 90px #000000b3}
.clhh-reel-slide figcaption{max-width:min(720px,84vw);text-align:center;font-size:13px;line-height:1.7;letter-spacing:1px;color:#dcf8f0c4}
.clhh-reel-nav{position:absolute;top:50%;transform:translateY(-50%);z-index:2;display:flex;align-items:center;justify-content:center;width:52px;height:52px;border:1px solid #ffffff2e;border-radius:50%;background:#0b0f1499;color:#dcf8f0;font:400 18px/1 Arial,sans-serif;cursor:pointer;transition:border-color .2s,background .2s}
.clhh-reel-nav:hover,.clhh-reel-nav:focus-visible{border-color:#ffffff80;background:#0b0f14e6}
.clhh-reel-prev{left:26px}
.clhh-reel-next{right:26px}
.clhh-reel-close{position:absolute;top:30px;right:34px;z-index:2;padding:9px 16px;border:1px solid #ffffff2e;border-radius:999px;background:#0b0f1499;color:#dcf8f0;font-family:inherit;font-size:10px;letter-spacing:2px;cursor:pointer;transition:border-color .2s}
.clhh-reel-close:hover,.clhh-reel-close:focus-visible{border-color:#ffffff80}
.clhh-reel-count{position:absolute;left:50%;bottom:66px;transform:translateX(-50%);font-size:10px;letter-spacing:3px;opacity:.5}
.clhh-reel-dots{position:absolute;left:50%;bottom:36px;transform:translateX(-50%);display:flex;gap:9px}
.clhh-reel-dots button{width:7px;height:7px;padding:0;border:0;border-radius:50%;background:#dcf8f02e;cursor:pointer;transition:background .2s,transform .2s}
.clhh-reel-dots button[aria-current="true"]{background:#dcf8f0;transform:scale(1.3)}
@media(max-width:700px){.clhh-reel-open{bottom:82px;font-size:10px;padding:9px 15px}
.clhh-reel-slide{gap:16px;padding:54px 16px 112px}
.clhh-reel-slide video{max-height:52vh}
.clhh-reel-slide figcaption{font-size:12px}
.clhh-reel-nav{width:42px;height:42px;font-size:15px}
.clhh-reel-prev{left:10px}.clhh-reel-next{right:10px}
.clhh-reel-close{top:18px;right:18px}
.clhh-reel-count{bottom:58px}.clhh-reel-dots{bottom:30px}}
