/* ==========================================================================
   Porta Productions — motion-gsap.css
   Hidden/pre-animation states. These exist ONLY when html.gs is set by
   motion-gsap.js, so a JS failure or reduced-motion leaves the page fully
   visible. Nothing here changes layout — no CLS.
   ========================================================================== */
:root{
  --m1:cubic-bezier(.2,.7,.2,1);   /* house ease */
  --m2:cubic-bezier(.16,1,.3,1);   /* expo-out, big moments */
}

/* page holds a beat, then fades in once fonts + first paint settle */
html.gs body{opacity:0;}
html.gs.gs-ready body{opacity:1;transition:opacity .5s var(--m1);}

/* ---- pre-states ---------------------------------------------------- */
/* `.in` is pre-revealed in the markup (the hero block) and is owned by the
   hero timeline, not the batch — hiding it here would blank the headline. */
html.gs .reveal:not(.in){opacity:0;}
html.gs .gs-line{display:block;}
html.gs .gs-lmask{display:block;overflow:hidden;}
html.gs .rule{transform:scaleX(0);transform-origin:0 50%;}
html.gs .gs-wipe{clip-path:inset(0 0 100% 0);}
html.gs .gs-img-wrap{overflow:hidden;}

/* ---- scroll progress hairline in the header ------------------------ */
#gs-prog{position:fixed;top:0;left:0;height:2px;width:100%;transform:scaleX(0);transform-origin:0 50%;
  background:linear-gradient(90deg,var(--accent),var(--hi));z-index:90;pointer-events:none;opacity:.85;}

/* ---- hero 3D atmosphere canvas ------------------------------------- */
#hero canvas.hero3d{position:absolute;inset:0;width:100%;height:100%;z-index:-1;pointer-events:none;
  mix-blend-mode:screen;opacity:0;transition:opacity 1.2s var(--m1);}
#hero canvas.hero3d.on{opacity:1;}

/* ---- pointer affordances ------------------------------------------- */
html.gs .gs-tilt{transform-style:preserve-3d;will-change:transform;}
.gs-glare{position:absolute;inset:0;z-index:5;pointer-events:none;opacity:0;
  background:radial-gradient(420px circle at var(--gx,50%) var(--gy,50%),rgba(255,255,255,.16),transparent 62%);}

/* ---- sticky booking bar (appears after the hero, hides at contact) --- */
#gs-book{position:fixed;left:0;right:0;bottom:0;z-index:85;
  display:flex;align-items:center;justify-content:space-between;gap:18px;
  padding:13px clamp(18px,5vw,40px);
  background:rgba(9,13,19,.9);-webkit-backdrop-filter:blur(14px);backdrop-filter:blur(14px);
  border-top:1px solid var(--line);
  /* the hide transform is owned by GSAP (gs.set yPercent:105), NOT by this
     rule — declaring it here too made GSAP parse it as a starting offset
     and stack a second 105% on top, parking the bar off screen for good.
     The bar is created by JS, so it can never appear without GSAP. */
  will-change:transform;}
#gs-book .gs-book-tx{font-family:var(--sans);font-weight:300;font-size:12px;letter-spacing:.2em;
  text-transform:uppercase;color:var(--platinum);}
#gs-book .gs-book-tx b{font-weight:400;color:#fff;}
#gs-book .gs-book-cta{display:flex;gap:10px;flex:none;}
#gs-book .btn{padding:10px 20px;font-size:11.5px;}
@media(max-width:620px){
  /* On a 664px-tall phone the bar was taking 89px — 13% of the screen — because
     "Book a 20-minute call" wrapped onto a second line. The minutes are a nice
     detail on desktop and a tax on mobile, so they drop out and the buttons are
     held to a single line. */
  #gs-book{padding:9px 14px;gap:8px;}
  #gs-book .gs-book-tx{display:none;}
  #gs-book .gs-book-cta{flex:1;}
  #gs-book .btn{flex:1;text-align:center;padding:12px 8px;white-space:nowrap;
    font-size:11px;letter-spacing:.12em;}
  #gs-book .gs-min{display:none;}
}

/* ---- respect the user -------------------------------------------- */
@media (prefers-reduced-motion: reduce){
  html.gs body,html.gs .reveal,html.gs .gs-wipe,html.gs .rule{opacity:1!important;transform:none!important;clip-path:none!important;}
  #gs-prog,#hero canvas.hero3d{display:none!important;}
}

/* nav link for the section currently in view */
html.gs nav.links a.gs-active{color:#fff;}
html.gs nav.links a:not(.btn).gs-active::after{left:0;right:0;}

/* heading masks must not clip descenders */
html.gs .sec-head h2 .gs-lmask{padding-bottom:.06em;margin-bottom:-.06em;}

/* A fixed header means an in-page jump lands with the section's first line
   hidden behind it. Every anchor target keeps clear of the header instead. */
html.gs section[id], html.gs #hero { scroll-margin-top: 84px; }
@media (max-width:1080px){ html.gs section[id] { scroll-margin-top: 72px; } }
