/* =========================================================
   NOVAFAB — responsive layer (loaded last on every page)
   Phones 360–430 · tablets 768–1024 (portrait + landscape) · desktop 1280–1920.
   Kept separate from style.css / pages.css so it can be reviewed and tuned in one place.
   ========================================================= */

/* ---------- 1. no horizontal scroll, safe areas ---------- */
html,body{overflow-x:clip}
/* film-grain layer: was a fixed box at inset:-50% animated with transform → widened the mobile layout viewport
   and repainted a 4× screen-size SVG filter every frame. Now viewport-sized, animated via background-position. */
.bg-noise{inset:0;animation:grain-bg 1.2s steps(6) infinite;will-change:auto}
@keyframes grain-bg{0%{background-position:0 0}20%{background-position:-24px 16px}40%{background-position:16px -24px}60%{background-position:-16px -8px}80%{background-position:24px 24px}100%{background-position:0 0}}
@media (max-width:1024px),(prefers-reduced-motion:reduce){.bg-noise{animation:none}}
.nav-inner,.container{padding-left:max(var(--pad-x,32px),env(safe-area-inset-left));padding-right:max(var(--pad-x,32px),env(safe-area-inset-right))}
@media (max-width:720px){:root{--pad-x:20px}}
.footer{padding-bottom:calc(32px + env(safe-area-inset-bottom))}

/* ---------- 2. floating action buttons (see js/responsive.js) ---------- */
.fab{right:max(22px,calc(env(safe-area-inset-right) + 12px));bottom:max(22px,calc(env(safe-area-inset-bottom) + 12px));transition:transform .35s var(--ease),opacity .25s}
.fab.fab-away{transform:translateY(calc(100% + 40px));opacity:0;pointer-events:none}
@media (max-width:720px){.fab{right:max(14px,calc(env(safe-area-inset-right) + 8px));bottom:max(14px,calc(env(safe-area-inset-bottom) + 8px));gap:8px}}

/* ---------- 3. readable labels: nothing below 12px ---------- */
.logo-tag,.placeholder-note,.live,.tag,.panel-foot,.scroll-hint,.chips li,.prod-code,.stage-hud,.stage-foot,.ctrl legend > span.mono,
.seg-2 button small,.range-scale,.summary-head,.summary dt,.tl-time,.fv-head,.cert-wrap .kicker,.certs span,.tst figcaption .mono,
.contact-list li span.mono,.form-legal,.footer-grid h4,.footer-bottom,.story-rec,.story-steps li span,.g-over,.g-info p,.gallery-foot,
.view-toggle button,.drag-hint,.mega-h,.mega-feature .mono,.tags span,.crumbs,.media-frame figcaption,.table-spec thead th,.vb-meta,.team-ph em,
.team figcaption>span,.spec-mini dt,.rail-item>span:first-child,.sd-head .tl-time,.sd-box h4,.cert-card em,.p-badge,.p-code,.p-cat,.p-meta,
.pd-zoom-hint,.pd-tags>span,.pd-moq>div>span,.pd-moq small,.pd-block h4,.opt-card small,.opt-card em,.pd-price-h,.case-client,.case-go,.case-meta dt,
.soon,.post-meta,.callout b,.local-time>span:first-child,.method span.mono,.office>span,.map-pin span,.map-note,.da-sum textarea,.da-note,
.pd-samplepay .sp-l span.mono,.st-sub,.st-tpl span,.st-upload small,.st-range output,.st-pat span,.st-gfx span,.st-status{font-size:12px}
.st-tpl span,.st-pat span,.st-gfx span{line-height:1.2}
.story-stats dt small{font-size:max(12px,.5em)}

/* ---------- 4. text wrapping (EN + CJK) ---------- */
h1,h2,h3,.page-title,.hero-title{text-wrap:balance}
p,li,dd{text-wrap:pretty}
html.lang-zh body{line-break:strict}
html.lang-zh h1,html.lang-zh h2,html.lang-zh h3{word-break:normal;overflow-wrap:anywhere}
.footer a,.contact-list a,.method b,.prose a{overflow-wrap:anywhere}

/* ---------- 5. grids / tables that could blow out their column ---------- */
.article-grid>*,.pd-grid>*,.case-body-grid>*,.faq-layout>*,.proc-layout>*,.split-block>*,.split-2>*,.contact>*,.cfg>*{min-width:0}
.table-wrap{max-width:100%;-webkit-overflow-scrolling:touch;overscroll-behavior-x:contain}
.prose img,.prose video,.prose iframe{max-width:100%;height:auto}
@media (max-width:1024px){
  .article-grid,.pd-grid,.faq-layout,.proc-layout,.case-body-grid,.split-2,.split-block{grid-template-columns:minmax(0,1fr)}
}
@media (max-width:720px){
  .table-spec{font-size:13.5px}
  .table-wrap .table-spec{min-width:100%}
}

/* ---------- 6. tablets ---------- */
@media (min-width:721px) and (max-width:1180px){
  .p-grid,.p-grid.c-4{grid-template-columns:repeat(3,minmax(0,1fr))}
}
@media (min-width:768px) and (max-width:1024px){
  /* product detail: keep gallery + buy box side by side instead of a 1000px-tall photo */
  .pd-grid{grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:28px}
  .pd-gallery{position:sticky;top:calc(var(--nav-h) + 16px)}
  .pd-main{aspect-ratio:4/5}
  .pd-ctas .btn{flex:1 1 100%}
}
@media (min-width:900px) and (max-width:1024px) and (orientation:landscape){
  /* configurator side by side on landscape tablets */
  .cfg{grid-template-columns:minmax(0,1.05fr) minmax(0,1fr)}
  .cfg-stage,.cfg-full .cfg-stage{min-height:0}
}

/* ---------- 7. phones ---------- */
@media (max-width:720px){
  .filter-bar{flex-wrap:nowrap}
  .filter-bar>*{min-width:0;max-width:100%}
  .page-hero.has-media{min-height:min(70vh,640px)}
  .hero-panel{max-width:none}
}
@media (max-width:380px){
  .hero-title{font-size:clamp(36px,11vw,52px)}
}
/* touch devices: "hover to zoom" hints make no sense */
@media (hover:none),(pointer:coarse){.pd-zoom-hint{display:none}}

/* ---------- 8. touch targets ≥ 44px (coarse pointers) ---------- */
@media (pointer:coarse){
  .logo{min-height:44px;display:inline-flex;align-items:center}
  .burger{width:44px;height:44px}
  .btn,.btn-sm{min-height:44px}
  .chip,.pill,.st-btns .chip,.da-actions .chip{min-height:44px;height:auto}
  .swatch{width:44px;height:44px}
  .seg button,.view-toggle button,.vb-toggle,.rail-item,.st-seg button{min-height:44px}
  .view-toggle button{min-width:44px}
  .search input,.select-sm select,.filter-tools input,.filter-tools select{min-height:44px}
  input[type=range]{min-height:44px}
  .footer-grid .footer-social a{width:44px;height:44px;flex:none}
  .footer-grid a{min-height:44px;display:flex;align-items:center;padding:0}
  .footer-legal a{min-height:44px;min-width:44px;display:inline-flex;align-items:center;justify-content:center}
  .crumbs{row-gap:0}
  .crumbs a{min-height:44px;min-width:44px;display:inline-flex;align-items:center;justify-content:center}
  .scroll-hint{min-width:44px}
  .st-tool{min-width:44px;min-height:44px;justify-content:center}
  .st-layer{grid-template-columns:36px 1fr repeat(3,36px)}
  .st-layer button{height:40px}
  .st-range input[type=range]{height:44px}
  .mega-cat,.nav-links a.mega-link{min-height:44px}
}
.link-more{display:inline-flex;align-items:center;min-height:44px;margin-bottom:6px}

/* ---------- 9. language toggle (EN / 中文) ----------
   Two equal grid segments; the lime thumb is pure CSS: inset --lt-i on every side of the active segment,
   moved by html.lang-zh. Height = --lt-h (36px fine pointers, 44px touch = same as the burger).
   The border is an inset shadow so it never changes the box size; no transition until .lt-ready (no animate-in on ?lang=zh / stored lang). */
.lang-toggle{--lt-h:36px;--lt-w:46px;--lt-i:3px;display:grid;grid-template-columns:repeat(2,var(--lt-w));align-items:stretch;height:var(--lt-h);padding:0;border:0;box-shadow:inset 0 0 0 1px var(--line-2);flex:none}
.lang-toggle button{height:auto;min-width:0;width:100%;padding:0;display:flex;align-items:center;justify-content:center;font-size:12px;line-height:1;border-radius:999px}
.lang-toggle button:focus-visible{outline:2px solid var(--accent);outline-offset:-2px}
.lang-toggle .lang-thumb{top:var(--lt-i) !important;left:var(--lt-i) !important;height:auto !important;bottom:var(--lt-i);width:calc(var(--lt-w) - 2*var(--lt-i)) !important;transform:none !important;transition:none}
html.lang-zh .lang-toggle .lang-thumb{transform:translateX(var(--lt-w)) !important}
html.lt-ready .lang-toggle .lang-thumb{transition:transform .4s var(--ease)}
@media (pointer:coarse){.lang-toggle{--lt-h:44px;--lt-w:48px;--lt-i:4px}.lang-toggle button{font-size:13px}}
@media (pointer:coarse) and (max-width:380px){.lang-toggle{--lt-w:44px}}
@media (prefers-reduced-motion:reduce){html.lt-ready .lang-toggle .lang-thumb{transition:none}}
/* header CTA keeps one width in EN ("Get a Quote") and ZH ("获取报价") so the language toggle doesn't jump sideways when switching */
.nav-cta{min-width:118px;justify-content:center}

/* ---------- 10. app-like phone UX (≤720px; menu ≤1024px) ---------- */
/* 10a. full-screen menu sheet: fills the screen under the nav, big rows, CTA pinned at the bottom, page scroll locked (html.menu-open, set by responsive.js) */
@media (max-width:1024px){
  .nav-links{top:var(--nav-h);bottom:0;height:calc(100dvh - var(--nav-h));max-height:none !important;padding:8px var(--pad-x,20px) 0;overscroll-behavior:contain;background:var(--bg);-webkit-backdrop-filter:none;backdrop-filter:none}
  .nav-links>a.nav-a,.nav-links .nav-item>.nav-trigger{min-height:60px;display:flex;align-items:center;font-family:var(--f-display);font-size:22px;font-weight:500;letter-spacing:-.01em;padding:0 4px}
  .nav-links .nav-item>.nav-trigger .chev{width:18px;height:18px;transition:transform .3s var(--ease)}
  .nav-links .nav-item.open>.nav-trigger .chev{transform:rotate(180deg)}
  .nav-links a.mega-link,.nav-links .dropdown a{min-height:48px;display:flex;align-items:center;font-size:16px;padding:0 4px 0 14px;color:var(--muted)}
  .nav-links a.mega-cat{min-height:0}
  .nav-mobile-cta{position:sticky;bottom:0;margin-top:auto;padding:18px 0 calc(18px + env(safe-area-inset-bottom));background:linear-gradient(to bottom,rgba(10,11,13,0),var(--bg) 28%)}
  .nav-links .nav-mobile-cta a.btn{min-height:54px;justify-content:center}
  html.menu-open,html.menu-open body{overflow:hidden}
  .nav-links.open>*{animation:menuIn .45s var(--ease) both}
  .nav-links.open>*:nth-child(2){animation-delay:.03s}.nav-links.open>*:nth-child(3){animation-delay:.06s}.nav-links.open>*:nth-child(4){animation-delay:.09s}
  .nav-links.open>*:nth-child(5){animation-delay:.12s}.nav-links.open>*:nth-child(6){animation-delay:.15s}.nav-links.open>*:nth-child(n+7){animation-delay:.18s}
}
@keyframes menuIn{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:none}}
@media (prefers-reduced-motion:reduce){.nav-links.open>*{animation:none}}

@media (max-width:720px){
  /* 10b. vertical rhythm + type scale: tighter sections, readable body copy */
  .section{padding:72px 0}
  .svc-block{padding:64px 0}
  .section-head{margin-bottom:28px}
  .section-head p,.page-lead{font-size:16px;line-height:1.6}
  .cap-card p,.p-body p,.case-body p,.post-body p,.card p,.tl-body p,.faq-a,.prose p,.prose li{font-size:max(15px,1em)}
  .video-block{min-height:72svh;padding:88px 0 56px}

  /* 10c. swipe carousels (scroll-snap) instead of long stacks — non-listing grids only; listing pages (products, cases, blog) keep their filterable grids */
  .cap-grid,.tst-grid,.p-grid.c-4,.card-grid.c-3,.card-grid.c-4,.team-grid,main:has(.article-grid) .post-grid{
    display:grid !important;grid-template-columns:none !important;grid-auto-flow:column;grid-auto-columns:min(82%,340px);gap:12px;
    overflow-x:auto;overscroll-behavior-x:contain;scroll-snap-type:x mandatory;scroll-padding-inline:var(--pad-x,20px);
    margin-inline:calc(-1 * var(--pad-x,20px));padding:4px var(--pad-x,20px) 14px;scrollbar-width:none;-webkit-overflow-scrolling:touch}
  :is(.cap-grid,.tst-grid,.p-grid.c-4,.card-grid.c-3,.card-grid.c-4,.team-grid,.post-grid)::-webkit-scrollbar{display:none}
  :is(.cap-grid,.tst-grid,.p-grid.c-4,.card-grid.c-3,.card-grid.c-4,.team-grid,main:has(.article-grid) .post-grid)>*{scroll-snap-align:start;min-width:0}
  .swipe-dots{display:flex;justify-content:center;gap:6px;margin-top:2px}
  .swipe-dots i{width:6px;height:6px;border-radius:3px;background:var(--line-2);transition:width .3s var(--ease),background .3s}
  .swipe-dots i.on{width:18px;background:var(--accent)}

  /* 10d. configurator: controls read as a bottom sheet under the sticky 3D stage (configurator.css keeps the stage sticky) */
  .cfg-controls{border-radius:22px 22px var(--radius) var(--radius);position:relative;padding-top:26px}
  .cfg-controls::before{content:"";position:absolute;top:9px;left:50%;width:40px;height:4px;margin-left:-20px;border-radius:2px;background:var(--line-2)}

  /* 10e. forms: 16px fields (no iOS zoom-on-focus), 52px tall, sticky submit */
  .form input:not([type=hidden]):not([type=checkbox]):not([type=radio]):not([type=range]),.form select,.form textarea{font-size:16px;min-height:52px}
  .form button[type=submit]{position:sticky;bottom:calc(10px + env(safe-area-inset-bottom));z-index:3;box-shadow:0 12px 30px -8px rgba(0,0,0,.8)}
}

/* 10f. phones: WhatsApp + Inquiry FAB becomes one slim bottom action bar (Quote / WhatsApp).
   Layout comes from this media query alone and the bar starts off-screen (transform only), so it never causes layout shift;
   responsive.js shows it (.fab-ready) when scrolling up past the hero and hides it (.fab-away) while scrolling down,
   over forms / configurator / studio / footer and while the keyboard is open. body reserves its height at the page end. */
@media (max-width:720px){
  body:has(>.fab){padding-bottom:calc(64px + env(safe-area-inset-bottom))}
  .fab{left:0;right:0;bottom:0;flex-direction:row;align-items:center;gap:10px;padding:8px 12px calc(8px + env(safe-area-inset-bottom));
    background:rgba(10,11,13,.92);-webkit-backdrop-filter:blur(14px);backdrop-filter:blur(14px);border-top:1px solid var(--line);
    transition:transform .35s var(--ease),opacity .25s}
  .fab:not(.fab-ready),.fab.fab-away{transform:translateY(110%);opacity:0;pointer-events:none}
  .fab .fab-btn{height:48px;box-shadow:none}
  .fab .fab-inq{order:1;flex:1;width:auto;padding:0 18px;font-size:15px}
  .fab .fab-inq span{display:inline}
  .fab .fab-wa{order:2;width:auto;padding:0 16px 0 12px;gap:6px;font-weight:600;font-size:14px}
  .fab .fab-wa::after{display:none}
  .fab .fab-wa svg{width:22px;height:22px}
  .fab .fab-wa .wa-label{display:inline}
}
.fab .wa-label{display:none}

@media (max-width:720px){
  /* phones: first screen of the home hero is visible at first paint (motion.js skips the char fly-in / fade-ins there) */
  .js-motion .hero-title{visibility:visible}
  .hero .reveal{opacity:1;transform:none;transition:none}
}
/* 10g. hero poster paints first as a CSS background (the <video> ships preload="none"; phones get a portrait crop) */
.hero-media::before{content:"";position:absolute;inset:0;background:url(../assets/video/hero-silk-poster.jpg) center/cover no-repeat;filter:saturate(.15) contrast(1.12) brightness(1.15)}
@media (max-width:720px){.hero-media::before{background-image:url(../assets/video/hero-silk-poster-m.jpg)}}
/* focused fields / anchors scroll clear of the sticky submit and the action bar */
@media (max-width:720px){html{scroll-padding-bottom:88px}}
