/*-------------------------------------------------------
  Motion (see src/js/motion.js and thrive_motion_templates() in functions/enqueue.php)
  Pre-JS states and the layout the recipes need. Two flags:
    <html class="has-gsap">   set in the head before first paint, dropped by motion.js when GSAP is
                              unavailable or reduced motion is on, and by a head timer if the script
                              never runs: everything hidden here hangs off it, so content never stays hidden
    <body class="has-motion"> server-side, on every template that loads the bundle: layout rules that are
                              harmless without the script (fixed header, stacking) hang off it
  Nothing here is scoped to the home page's wrapper, so the same sheet serves the next templates.
-------------------------------------------------------*/

/* (not on a back/forward navigation: the hero is shown as it is and the entrance is skipped, see the head flag) */
@media (prefers-reduced-motion: no-preference) {
  .has-gsap:not(.gsap-no-entrance) .section-hero-banner .hero-banner-content .container-medium > *,
  .has-gsap:not(.gsap-no-entrance) .section-hero-banner .hero-banner-canvas,
  .has-gsap:not(.gsap-no-entrance) .section-hero-banner .shape-hand-wrap,
  .has-gsap:not(.gsap-no-entrance) .section-hero-banner .scroll-down,
  /* service pages: the landing banner's copy column (the image stays painted: it is the LCP element, and the
     entrance only scales it) */
  .has-gsap:not(.gsap-no-entrance) .section-landing-banner.is-first .col-1 > * {
    opacity: 0;
  }
  /* title pages (about, contact, what-we-do, the archives and category pages): the title block is the hero (title
     words rise on load, the background shapes pop; the circle round "digital" on the about page is drawn by the
     script once the words have landed, so it starts invisible) */
  .has-gsap:not(.gsap-no-entrance) .section-intro .circled-text svg,
  .has-gsap:not(.gsap-no-entrance) .section-intro h1,
  .has-gsap:not(.gsap-no-entrance) .section-title h1,
  .has-gsap:not(.gsap-no-entrance) .section-title .h1,
  .has-gsap:not(.gsap-no-entrance) .section-title .background-svg,
  /* the simpler title blocks: thank-you pages (copy inside the title section), search banner, 404, author */
  .has-gsap:not(.gsap-no-entrance) .page-thank-you .section-title .general-content > *,
  .has-gsap:not(.gsap-no-entrance) .section-page-banner h1,
  .has-gsap:not(.gsap-no-entrance) .section-404 .general-content > *,
  .has-gsap:not(.gsap-no-entrance) .page-author > .section-content h3 {
    opacity: 0;
  }
  /* breadcrumb pill: slides in with whichever entrance the page has (the script shows it at once if none runs) */
  .has-gsap:not(.gsap-no-entrance) .section-breadcrumbs .flex {
    opacity: 0;
  }
  /* project pages: the overview (title, tags, excerpt, button) is the hero */
  .has-gsap:not(.gsap-no-entrance) .single-portfolio .section-overview .general-content > * {
    opacity: 0;
  }
  /* articles (lab, blog): the title block is the hero; the featured image under it is never hidden (LCP) */
  .has-gsap:not(.gsap-no-entrance) .single-post .section-content .container-xsmall.tacenter > * {
    opacity: 0;
  }
  /* ...and, until the script has built (html.gsap-built), the content of every section after the page's hero: the
     one under the fold is on screen from the first paint, and the build would otherwise snap it from shown to its
     hidden start state before playing it in. Section backgrounds stay, only their content is held back. */
  .has-gsap:not(.gsap-built) .section-landing-banner.is-first ~ div > *,
  .has-gsap:not(.gsap-built) .section-intro ~ div > *,
  .has-gsap:not(.gsap-built) .section-title ~ div > *,
  /* project pages: everything after the overview, except a full-width image straight under it, which is usually
     the largest thing on the first screen (the LCP) and is animated by transform only, never hidden */
  .has-gsap:not(.gsap-built) .single-portfolio .section-overview ~ div:not(.section-overview + .section-image) > *,
  /* articles: the related-service card, the author card and the "keep reading" section (the body itself is not animated) */
  .has-gsap:not(.gsap-built) .single-post .related-service,
  .has-gsap:not(.gsap-built) .single-post .author-info,
  .has-gsap:not(.gsap-built) .single-post .section-content ~ div > *,
  .has-gsap:not(.gsap-built) .page-author > .section-content ~ div > * {
    opacity: 0;
  }
  /* ...but not the default pages' content (legal text, the quote and payment forms): that is reading matter and a
     form, left exactly as it is, so it must never be held back either */
  .has-gsap:not(.gsap-built) .page-default .section-title ~ div > * {
    opacity: 1;
  }
}
/* about: the theme draws the circle round "digital" with a CSS keyframe when it scrolls into view (animation.css);
   on the motion page the script draws it at the right moment in the title entrance instead */
.has-motion .page-about .circled-text svg path { animation: none !important; }
/* contact: the title's sprite shapes overshoot their resting size as they pop in (back ease); the SVG must not clip
   them at its edges meanwhile (the donut lost its bottom) */
.has-motion .section-title .background-svg,
.has-motion .section-title .background-svg svg { overflow: visible; }
/* Gravity Forms renders a form that has conditional logic with display:none and shows it once its script has applied
   the rules (after the deferred scripts). Until then the box it sits in keeps a working height, so the page below
   does not jump when the form arrives (the script fades the form in at that moment, see formReveal()) */
.has-motion .page-default .section-content > .general-content:has(> .gform_wrapper[style*="none"]),
.has-motion .form-wrap:has(> .gform_wrapper[style*="none"]) { min-height: 70vh; }
/* contact: the map zooms in from a touch larger; the section clips it. The map's transform makes it a stacking layer
   that would paint over the pin and the maps link (both absolute, z-index auto): lift them above it */
.has-motion .section-street-map { overflow: hidden; }
.has-motion .section-street-map .map-pin { z-index: 1; } /* the maps button gets its z-index in theme.css */

/* Lenis smooth scroll (classes are set on <html> by Lenis itself; `lenis-smooth` only exists mid-scroll in 1.3,
   so the always-on rules hang off `lenis`) */
html.lenis, html.lenis body { height: auto; scroll-behavior: auto !important; } /* the theme sets smooth on body; Lenis must own it */
.lenis [data-lenis-prevent] { overscroll-behavior: contain; }
.lenis.lenis-stopped { overflow: hidden; }

/* reading progress: a thin bar under the top edge that fills with the scroll */
.gsap-progress {
  position: fixed; top: 0; left: 0; z-index: 2000001; width: 100%; height: 4px;
  background: var(--blue, #3182ff); transform-origin: 0 50%; transform: scaleX(0); pointer-events: none;
}

/* theme.css gives every <a> `transition: all 0.3s`. On motion pages links keep their colour transitions but never
   transition opacity or transform: a link the script sets to its hidden start state otherwise FADES out over 0.3s
   instead of snapping (the hero buttons, then the portfolio filter tags: on screen for a few frames, gone, then
   animated in), and a scrubbed tween fights the transition on every frame. No link hover in the theme moves or
   fades, so nothing is lost. */
.has-motion a {
  transition-property: background-color, border-color, color, box-shadow, fill, stroke;
}

/* the hero pins while the next section slides up over it: the sections after it sit on top of the pinned layer.
   Two rules, not one list: once pinned, the hero sits inside a ScrollTrigger .pin-spacer, so the sections are that
   spacer's siblings, and a browser without :has() must still get the plain sibling rule */
.has-motion .section-hero-banner ~ div:not(.pin-spacer) { position: relative; z-index: 2; }
.has-motion .pin-spacer:has(> .section-hero-banner) ~ div:not(.pin-spacer) { position: relative; z-index: 2; }
.has-motion .section-hero-banner { z-index: 1; }
/* HOME ONLY: the theme's home header is absolute until it turns white, then fixed; with the hero pinned the two look
   the same, and keeping it fixed lets the white state switch anywhere in the scroll without the header jumping.
   Other templates keep the theme's own header (fixed, white from 50px) untouched. */
body.home.has-motion header { position: fixed; }
/* the white background is a layer under the header content whose opacity the script scrubs in over the last
   stretch of the hero (the theme's timed 0.15s fade spanned hundreds of pixels of content at smooth-scroll
   speed and read as a flicker; a hard cut read as a flash) */
body.home.has-motion header { transition: none; --header-bg: 0; }
body.home.has-motion header.scrolled { background: transparent; }
body.home.has-motion header::before {
  content: ''; position: absolute; top: 0; right: 0; bottom: 0; left: 0; z-index: -1;
  background: var(--white); opacity: var(--header-bg); pointer-events: none;
}
/* phones get no scrubbed fade (the hero is not pinned there): the white layer simply follows the scrolled state */
@media screen and (max-width: 720px) {
  body.home.has-motion header.scrolled { --header-bg: 1; }
}
/* sideways entrances (service cards from x +140, copy blocks from x +60) poke past the right edge at tablet widths.
   The theme's body { overflow-x: hidden } only stops the panning: mobile Chrome still widens the layout viewport to the
   overflowing content, and the fixed header (width 100%) grows past the screen with it. `clip` clips without making
   the wrapper a scroll container, so the pinned (position: fixed) sections are unaffected. */
@supports (overflow: clip) {
  .has-motion .page-front, .has-motion .page-service, .has-motion .page-about, .has-motion .page-contact, .has-motion .page-service-list { overflow-x: clip; }
}
/* the two sections that pass over the pinned hero must be opaque, or it shows through (the service cards sit on the page colour) */
.has-motion .section-service-boxes { background-color: var(--light-grey); }

/* headings split into words (hero lead, footer call to action) or masked lines (section headings) */
.gsap-word,
.gsap-line,
.gsap-line-inner {
  /* the theme styles spans inside headings as sub-labels; the words must look like the heading itself */
  font: inherit !important;
  text-transform: inherit !important;
  letter-spacing: inherit !important;
  line-height: inherit !important;
  color: inherit !important;
  text-shadow: inherit;
}
.gsap-word { display: inline-block; white-space: pre; }
.gsap-line { display: block; overflow: hidden; padding-bottom: 0.12em; margin-bottom: -0.12em; }
.gsap-line-inner { display: block; }

/* box an image or video settles inside (about photo, two-column media, full-width image, related project images) */
.gsap-curtain-wrap { position: relative; display: block; overflow: hidden; }
.gsap-curtain-wrap > img, .gsap-curtain-wrap > video, .gsap-curtain-wrap > .portfolio-post-image { display: block; }
/* related projects, service list cards: the image link becomes the clipping box (it is inline in the theme) */
.has-motion .section-related-portfolio .post-item > a:has(> .gsap-curtain-wrap),
.has-motion .section-portfolio-posts .post-item > a:has(> .gsap-curtain-wrap),
.has-motion .section-service-list .page-item > a:has(> .gsap-curtain-wrap) { display: block; }

/* project cards: the link clips the image (parallax + hover zoom) to the same arch; no title underline on hover */
.portfolio-grid .thumbnail-item > a { display: block; overflow: hidden; transform: translateZ(0); isolation: isolate; }
.portfolio-grid .thumbnail-item > a img { display: block; backface-visibility: hidden; }
.portfolio-grid .thumbnail-item a:hover h4,
.portfolio-grid .thumbnail-item a:hover .h4 { text-decoration: none; }

/* project track: on wide screens the picked cards sit in one row and the section pins while the row rides the scroll
   sideways (the class is added by the script, so phones and reduced motion keep the plain grid) */
.gsap-h-scroll .section-featured-portfolio {
  overflow: hidden; padding-top: 40px; padding-bottom: 40px;
  /* pinned just under the fixed header, filling the rest of the viewport so nothing blank shows under it;
     heading, row and button sit as one centred block (the theme's container margins are `auto`, which a flex
     column would otherwise turn into big gaps) */
  min-height: calc(100vh - var(--header-height)); box-sizing: border-box; display: flex; flex-direction: column; justify-content: center;
}
.gsap-h-scroll .section-featured-portfolio > * { margin-top: 0; margin-bottom: 0; }
.gsap-h-scroll .section-featured-portfolio > .general-content { margin-bottom: clamp(40px, 5vh, 70px); }
.gsap-h-scroll .section-featured-portfolio .portfolio-grid {
  display: flex; flex-wrap: nowrap; gap: 40px; align-items: flex-start;
  width: max-content; max-width: none; margin-left: max(30px, calc((100vw - 1400px) / 2)); padding-right: 30px;
  will-change: transform;
}
/* the images rest zoomed in and shifted left (the scroll parallax and hover zoom work inside that margin); set here
   from the first paint, so a build that lands while the visitor is already scrolling never snaps the images from
   plain to zoomed */
.has-gsap.gsap-h-scroll .section-featured-portfolio .thumbnail-item > a img { transform: translateX(-6%) scale(1.15); }
/* card width capped by the viewport height too, so the row always fits between heading and button */
.gsap-h-scroll .section-featured-portfolio .portfolio-grid .thumbnail-item { flex: 0 0 auto; width: clamp(280px, min(38vw, 52vh), 840px); }
.gsap-h-scroll .section-featured-portfolio > .container-small:last-child { margin-top: clamp(40px, 5vh, 70px); }
.gsap-h-scroll .section-featured-portfolio .portfolio-view-all { margin-top: 0; }

/* service card highlight that follows the pointer (content sits above it at z-index 9, shapes below at -9) */
.service-item .gsap-glare {
  position: absolute; top: 0; right: 0; bottom: 0; left: 0; z-index: 1;
  border-radius: inherit; pointer-events: none; opacity: 0;
  background: radial-gradient(circle at var(--gx, 50%) var(--gy, 50%), rgba(255, 255, 255, 0.06), rgba(255, 255, 255, 0) 55%);
}

/* service card titles stay links, with no underline on hover (the tilt is the hover cue); keyboard focus keeps the theme's underline */
.has-motion .service-item .service-title-link:hover,
.has-motion .service-item a:hover h4,
.has-motion .service-item a:hover .h4 { text-decoration: none; }
