/* ==========================================================================
   Lobumatic — shared motion & liquid-glass system
   Loaded after each page's inline <style>, so it wins at equal specificity.
   Single source of truth for all six pages (EN + 中文).
   ========================================================================== */

:root{
  --ease: cubic-bezier(.22,1,.36,1);
  --nav-h: 72px;

  /* Liquid glass — tuned for a light, warm ground */
  --glass-tint: rgba(250,247,244,.62);
  --glass-tint-strong: rgba(250,247,244,.78);
  --glass-blur: 18px;
  --glass-sat: 1.7;
  --glass-edge: rgba(255,255,255,.55);
  --glass-shadow: 0 8px 32px rgba(28,22,18,.10);
}

/* ==========================================================================
   1. Scroll-anchor offset — stop headings landing under the fixed nav
   ========================================================================== */
[id]{ scroll-margin-top: calc(var(--nav-h) + 16px); }
html{ scroll-padding-top: calc(var(--nav-h) + 16px); }

/* ==========================================================================
   2. Visible keyboard focus (the reset suppressed the browser default)
   ========================================================================== */
a:focus-visible,
button:focus-visible,
select:focus-visible,
input:focus-visible,
textarea:focus-visible,
[tabindex]:focus-visible{
  outline: 2px solid var(--orange, #E8580A);
  outline-offset: 3px;
  border-radius: 2px;
}
.skip-link{
  position:absolute; left:-9999px; top:0; z-index:200;
  background: var(--orange, #E8580A); color:#fff;
  padding:12px 20px; font-size:14px; font-weight:600; letter-spacing:.04em;
}
.skip-link:focus{ left:8px; top:8px; }

/* ==========================================================================
   3. Reveal animations — only hide content when JS is confirmed running
   ========================================================================== */
.anim,
.anim-grid > *{ opacity:1; transform:none; }

html.js .anim{
  opacity:0; transform:translateY(28px);
  transition:opacity .65s var(--ease), transform .65s var(--ease);
}
html.js .anim.anim-left { transform:translateX(-36px); }
html.js .anim.anim-right{ transform:translateX(36px); }
html.js .anim.in-view   { opacity:1; transform:none; }

/* Index-driven stagger — no longer capped at six children */
html.js .anim-grid > *{
  opacity:0; transform:translateY(24px);
  transition:opacity .55s var(--ease), transform .55s var(--ease);
  transition-delay: calc(var(--i, 0) * 90ms);
}
html.js .anim-grid.in-view > *{ opacity:1; transform:none; }

@media (max-width:768px){
  html.js .anim.anim-left,
  html.js .anim.anim-right{ transform:translateY(28px); }
}

/* ==========================================================================
   4. Hero — svh so the mobile toolbar stops causing a jump
   ========================================================================== */
.hero{ height:auto; min-height:100vh; }
@supports (height: 100svh){ .hero{ min-height:100svh; } }

/* ==========================================================================
   5. Nav — constant height (no layout animation), glass on scroll
   ========================================================================== */
nav#main-nav{
  height: var(--nav-h);
  transition: background .45s ease, box-shadow .45s ease, backdrop-filter .45s ease;
}
nav#main-nav.scrolled{ height: var(--nav-h); }

@media (max-width:768px){
  nav#main-nav,
  nav#main-nav.scrolled{ padding:0 24px; height: var(--nav-h); }
}

/* ==========================================================================
   6. LIQUID GLASS
   Applied only to surfaces that sit over photography or moving content —
   glass over a flat ground reads as plain grey. Falls back to solid where
   backdrop-filter is unsupported.
   ========================================================================== */
@supports ((backdrop-filter: blur(4px)) or (-webkit-backdrop-filter: blur(4px))){

  .glass{
    position:relative;
    background: var(--glass-tint);
    -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-sat));
    backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-sat));
    box-shadow: inset 0 1px 0 var(--glass-edge), var(--glass-shadow);
    overflow:hidden;
    isolation:isolate;
  }

  /* The drifting specular sheen — the "liquid" part.
     transform-only, so it composites on the GPU and never triggers layout. */
  .glass::after{
    content:'';
    position:absolute; inset:-40% -60%;
    pointer-events:none; z-index:0;
    background:linear-gradient(
      105deg,
      transparent 30%,
      rgba(255,255,255,.10) 44%,
      rgba(255,255,255,.38) 50%,
      rgba(255,255,255,.10) 56%,
      transparent 70%
    );
    transform:translate3d(-45%,0,0);
    animation: glass-sheen 9s var(--ease) infinite;
  }
  .glass > *{ position:relative; z-index:1; }

  @keyframes glass-sheen{
    0%   { transform:translate3d(-45%,0,0); }
    55%  { transform:translate3d(45%,0,0); }
    100% { transform:translate3d(45%,0,0); }
  }

  /* --- nav: turns to glass once you scroll past the hero --- */
  nav#main-nav.scrolled{
    background: var(--glass-tint);
    -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-sat));
    backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-sat));
    box-shadow: inset 0 -1px 0 rgba(28,22,18,.06), 0 4px 24px rgba(28,22,18,.06);
    border-bottom-color: transparent;
  }

  /* --- hero ghost button: glass over the slideshow --- */
  .btn-ghost{
    background: rgba(255,255,255,.10);
    -webkit-backdrop-filter: blur(12px) saturate(1.4);
    backdrop-filter: blur(12px) saturate(1.4);
    border-color: rgba(250,247,244,.42);
    box-shadow: inset 0 1px 0 rgba(255,255,255,.28);
  }
  .btn-ghost:hover{
    background: rgba(255,255,255,.18);
    border-color: rgba(250,247,244,.85);
  }

  /* --- language toggle --- */
  .lang-toggle{
    background: rgba(255,255,255,.32);
    -webkit-backdrop-filter: blur(10px) saturate(1.4);
    backdrop-filter: blur(10px) saturate(1.4);
  }

  /* --- mobile menu: frosted over the page instead of a flat fill --- */
  .mobile-menu{
    background: var(--glass-tint-strong);
    -webkit-backdrop-filter: blur(26px) saturate(1.8);
    backdrop-filter: blur(26px) saturate(1.8);
  }

  /* --- portfolio hover overlay: frosted panel over the frame --- */
  .portfolio-thumb-overlay{
    -webkit-backdrop-filter: blur(2px) saturate(1.2);
    backdrop-filter: blur(2px) saturate(1.2);
  }
}

/* Fallback where backdrop-filter is unsupported — stay solid and legible */
@supports not ((backdrop-filter: blur(4px)) or (-webkit-backdrop-filter: blur(4px))){
  nav#main-nav.scrolled{ background: rgba(250,247,244,.97); }
  .mobile-menu{ background: #FAF7F4; }
  .btn-ghost{ background: rgba(28,22,18,.28); }
}

/* Blur is the most expensive thing on the page — ease off on phones,
   where the GPU budget is smallest and the surfaces are smaller anyway. */
@media (max-width:768px), (pointer:coarse){
  :root{ --glass-blur: 12px; --glass-sat: 1.45; }
  .mobile-menu{
    -webkit-backdrop-filter: blur(18px) saturate(1.5);
    backdrop-filter: blur(18px) saturate(1.5);
  }
  .glass::after{ animation-duration: 11s; }
}

/* ==========================================================================
   7. Interaction vocabulary — a directional wipe, extending the one good
   idea already in the CSS (the service-card top bar). No new colours.
   ========================================================================== */
.btn-primary,
.nav-cta,
.form-submit,
.package-cta{
  position:relative;
  overflow:hidden;
  isolation:isolate;
  transition: transform .25s var(--ease), box-shadow .25s var(--ease), opacity .2s;
}
.btn-primary::after,
.nav-cta::after,
.form-submit::after,
.package-cta::after{
  content:'';
  position:absolute; inset:0; z-index:-1;
  background: rgba(0,0,0,.16);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform .38s var(--ease);
}
.btn-primary:hover::after,
.nav-cta:hover::after,
.form-submit:hover::after,
.package-cta:hover::after{ transform: scaleX(1); }

.btn-primary:hover,
.nav-cta:hover,
.form-submit:hover{ opacity:1; transform: translateY(-2px); box-shadow: 0 6px 20px rgba(232,88,10,.28); }

/* Pressed feedback — the site had none, so taps felt inert */
.btn-primary:active,
.btn-ghost:active,
.nav-cta:active,
.form-submit:active,
.package-cta:active,
.portfolio-thumb:active{ transform: translateY(1px) scale(.985); }

/* Portfolio frames — a slow push-in on hover */
.portfolio-thumb img{ transition: transform .7s var(--ease); }
.portfolio-thumb:hover img{ transform: scale(1.045); }

/* ==========================================================================
   8. Touch devices have no hover — reveal what was hover-only
   ========================================================================== */
@media (hover: none){
  .portfolio-thumb-overlay{
    opacity:1;
    background:linear-gradient(to top, rgba(13,13,13,.82) 0%, transparent 46%);
  }
  .service-card::before{ transform: scaleX(1); }
}

/* ==========================================================================
   9. Cross-document view transitions — the EN ↔ 中文 switch stops flashing
   ========================================================================== */
@view-transition{ navigation: auto; }

.nav-logo  { view-transition-name: site-logo; }
.hero-title{ view-transition-name: hero-head; }

::view-transition-old(root),
::view-transition-new(root){
  animation-duration:.34s;
  animation-timing-function: var(--ease);
}

/* ==========================================================================
   10. Reduced motion — now covers the two infinite animations too
   ========================================================================== */
@media (prefers-reduced-motion: reduce){
  html{ scroll-behavior: auto; }

  .hero-slide{ animation:none; opacity:1; }
  .hero-slide:not(:first-child){ display:none; }
  .hero-scroll-line{ animation:none; opacity:.6; }
  .filmstrip-track{ animation:none; }
  .glass::after{ animation:none; }

  .anim, .anim-grid > *,
  html.js .anim, html.js .anim-grid > *{
    opacity:1 !important; transform:none !important; transition:none !important;
  }
  .portfolio-thumb img,
  .btn-primary, .nav-cta, .form-submit, .package-cta{ transition:none; }
  .portfolio-thumb:hover img{ transform:none; }
}

/* ==========================================================================
   11. The liquid sheen, on the real glass surfaces
   Attached to selectors that already exist, so no markup change is needed.
   transform-only and pointer-events:none — composites on the GPU, never
   intercepts a click, never triggers layout.
   ========================================================================== */
@supports ((backdrop-filter: blur(4px)) or (-webkit-backdrop-filter: blur(4px))){

  nav#main-nav.scrolled,
  .mobile-menu{ overflow:hidden; }

  nav#main-nav.scrolled::after,
  .mobile-menu.open::after{
    content:'';
    position:absolute; inset:-50% -60%;
    pointer-events:none; z-index:0;
    background:linear-gradient(
      105deg,
      transparent 30%,
      rgba(255,255,255,.10) 44%,
      rgba(255,255,255,.40) 50%,
      rgba(255,255,255,.10) 56%,
      transparent 70%
    );
    transform:translate3d(-45%,0,0);
    animation: glass-sheen 9s var(--ease) infinite;
  }

  /* Keep the actual content above the sheen */
  nav#main-nav.scrolled > *,
  .mobile-menu > *{ position:relative; z-index:1; }
}

@media (prefers-reduced-motion: reduce){
  nav#main-nav.scrolled::after,
  .mobile-menu.open::after{ animation:none; opacity:.3; }
}

/* Screen-reader-only text (used by the stat counters to keep the real value) */
.screen-reader-text{
  position:absolute !important;
  width:1px; height:1px; padding:0; margin:-1px;
  overflow:hidden; clip:rect(0,0,0,0); white-space:nowrap; border:0;
}

/* <picture> wrappers must fill the frame exactly as the bare <img> did */
.portfolio-thumb picture{ display:block; width:100%; height:100%; }
.portfolio-thumb picture img{ width:100%; height:100%; object-fit:cover; display:block; }

/* @view-transition can't live inside a media query — disable the animation
   itself for reduced-motion users instead. */
@media (prefers-reduced-motion: reduce){
  ::view-transition-group(*),
  ::view-transition-old(*),
  ::view-transition-new(*){ animation: none !important; }
}

/* The About portrait had a gradient fading its lower 40% into the page.
   Removed at Rob's request — the photo now runs full height in both languages. */
.about-photo-wrap::after{ display:none; }
