/* ==========================================================================
   JCweb.TECH — GSAP motion layer, sitewide
   --------------------------------------------------------------------------
   Ported from prototypes/src/jc-motion.css. This half is everything that is
   NOT tied to a homepage element ID: the ScrollSmoother shell, the loader,
   SplitText's plumbing, and the magnetic-button surface. Homepage scenes —
   hero, the dip to black, Selected work, services, CTA — live in jc-home.css.

   Nothing here restyles the site. Every rule either serves the animation or
   hands GSAP a box model it can move; the page's own Bricks CSS is untouched.

   Guarded on `html.jc-motion`, which the pre-paint boot script in
   functions.php adds only when the visitor has not asked for reduced motion.
   With the class absent every rule below is inert and the page renders as
   plain Bricks output.
   ========================================================================== */

:root {
  --jc-header-h: 84px;
  --jc-ink: #0b0b0c;
}

/* ScrollSmoother drives the scroll position itself; native smooth scrolling
   fights it and produces a rubber-band. */
html.jc-motion { scroll-behavior: auto !important; }

/* --------------------------------------------------------------------------
   1. ScrollSmoother shell
   --------------------------------------------------------------------------
   #brx-header has to stay OUTSIDE #smooth-content: the content is moved with
   a transform, and a transformed ancestor breaks `position: fixed` and
   `position: sticky` for everything inside it. jc-motion.js does the move —
   a pure reparent, no markup or styling change — and these rules only cover
   for the padding the header no longer occupies in flow.
   -------------------------------------------------------------------------- */
html.jc-motion #smooth-wrapper { overflow: hidden; }
html.jc-motion #smooth-content {
  padding-top: var(--jc-header-h);
  will-change: transform;
}

/* Outside the smoothed content the header can no longer rely on Bricks'
   scroll-driven `position` switch, so it is simply fixed from the start. Its
   own sticky styling, markup and mobile nav are untouched. */
html.jc-motion #brx-header.brx-sticky,
html.jc-motion #brx-header.brx-sticky.on-scroll { position: fixed; top: 0; }

/* Below the smoother breakpoint jc-motion.js never creates the smoother, so
   #smooth-content is a plain div that nothing transforms — the compositor hint
   is dead weight and the wrapper does not need to clip.

   The header is NOT handed back to Bricks here, though: the rule above is
   unconditional, so `position: fixed` still applies and the header still owns
   no space in flow. The padding therefore has to stay, or the first section
   starts underneath it — which is exactly what happened when this layer
   shipped.

   Below 768px the first section carries the gap itself, as a Bricks
   `_margin:mobile_landscape` of var(--SP__Header_Clearance) — the floating pill
   is meant to sit over a gap there rather than have the page start flush
   against it. 768px is Bricks' own mobile_landscape edge; the smoother starts
   at 992px, and the 768-991px band in between is what this padding covers. */
html.jc-motion.jc-no-smoother #smooth-content { padding-top: var(--jc-header-h); will-change: auto; }
html.jc-motion.jc-no-smoother #smooth-wrapper { overflow: visible; }

@media (max-width: 767px) {
  html.jc-motion.jc-no-smoother #smooth-content { padding-top: 0; }
}

/* --------------------------------------------------------------------------
   2. Loader
   --------------------------------------------------------------------------
   The markup is printed by functions.php so it paints on the first frame.
   `jc-motion-loader` is added by the same boot script and only when the loader
   is actually going to play — first visit of the session, not automation, not
   reduced motion — so on every other path this is one hidden div.

   Note the two classes are separate on purpose. `jc-booting` is what hides the
   page and it comes off as the dissolve starts, so the page is already there
   behind the holes the first cells cut; `jc-motion-loader` is what keeps the
   panel displayed and survives until JS removes the element.
   -------------------------------------------------------------------------- */
.jc-loader { display: none; }

html.jc-motion-loader .jc-loader {
  display: flex;
  position: fixed; inset: 0; z-index: 10000;
  background: var(--jc-ink); color: #fff;
  flex-direction: column; justify-content: center; align-items: center;
  padding: clamp(20px, 3vw, 44px);
}

/* The dissolve surface.
   ---------------------
   The panel exits by breaking into a grid of ~18px squares that clear one by
   one, so the page is revealed THROUGH the panel rather than from under it. A
   canvas rather than a few thousand divs: at this cell size a 1080p viewport
   is ~6,400 cells, and `clearRect` on one element is the only version of that
   which composites in a frame.

   It stays empty and unsized until jc-motion.js reaches the exit — on the way
   in the panel's own `background` is what paints, which is why the loader
   still shows correctly on the very first frame before any script has run.
   At handover the canvas is filled with the same ink and the background is
   dropped to transparent in the same tick, so the swap has no seam.

   `pointer-events: none` because the panel is over the whole page for ~1.9 s
   and a stray click on the way out should reach what is behind it. */
.jc-loader__mask {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  display: block; pointer-events: none;
}

/* Everything the visitor reads sits above the mask and fades as one. */
.jc-loader__inner {
  position: relative; z-index: 1;
  display: flex; flex-direction: column; align-items: center;
}

/* Repeat visit: the panel and its dissolve, none of the wait. The mark and the
   bar are the entrance, and an entrance is only worth playing once a session —
   but the panel itself still has a job on every view, which is covering the
   hero while the motion layer stages it. So the contents go and the ink field
   stays. `display: none` rather than opacity: nothing here is measured, and it
   must not be able to flash on the frame before jc-motion.js reaches it. */
html.jc-loader-quick .jc-loader__inner { display: none; }

/* The monogram, behind a clip so it can rise into place the way every line of
   type on this site does. The padding (cancelled by an equal negative margin,
   as on the SplitText masks above) moves the clip edge clear of the mark, so
   subpixel rounding at rest cannot shave a row off the bottom of the glyph. */
.jc-loader__mark {
  overflow: hidden; line-height: 0;
  padding-bottom: 3px; margin-bottom: -3px;
}
/* Mark and bar are sized off the same viewport slope so their ratio holds at
   every width. Clamped independently they drift: at 390px the mark bottomed
   out at 104px while the bar sat at its 320px maximum, and a bar three times
   the width of the logo reads as the logo having shrunk. The mark is set 30%
   below the bar's slope, so it sits at roughly 2.6x the mark throughout. */
.jc-loader__svg {
  display: block;
  width: clamp(84px, 10.5vw, 137px); height: auto;
  color: #fff;
}

/* Nothing may paint before the loader lifts. `visibility` rather than
   `display`, so everything still lays out and can be measured — the hero
   timeline needs real geometry the moment the panel goes. */
html.jc-motion.jc-booting body { background: var(--jc-ink); }
html.jc-motion.jc-booting #smooth-wrapper,
html.jc-motion.jc-booting #brx-content,
html.jc-motion.jc-booting #brx-footer,
html.jc-motion.jc-booting #brx-header { visibility: hidden; }

/* A real bar rather than the hairline it replaced: 8px of track, so it reads
   as an application loading its own chrome, and the only progress indicator
   the panel has — there is no percentage counter.

   Corners are square, and stated rather than left to the initial value so a
   future global radius cannot leak into them: the panel's whole exit is a grid
   of hard-edged squares, and a rounded bar sitting above it belongs to a
   different drawing. It sits at a fixed measure rather than the full panel
   width so it reads as part of the mark instead of as a frame around the
   viewport. */
.jc-loader__track {
  margin-top: clamp(28px, 3.4vw, 48px);
  height: 8px;
  width: clamp(220px, 29vw, 336px); max-width: 100%;
  background: rgba(255, 255, 255, 0.14);
  border-radius: 0;
  position: relative; overflow: hidden;
}
.jc-loader__track i {
  position: absolute; inset: 0;
  background: #fff;
  border-radius: 0;
  transform: scaleX(0); transform-origin: 0 50%;
}

/* --------------------------------------------------------------------------
   3. Split-text plumbing
   --------------------------------------------------------------------------
   SplitText's `mask` wrapper clips at the line box, which cuts the tails off
   descenders on the display face. A little padding on the mask (cancelled by
   an equal negative margin) moves the clip edge clear of them without moving
   the text.
   -------------------------------------------------------------------------- */
/* The mask's class is NOT `jc-line-mask`. SplitText builds it by appending
   `-mask` to every WORD of the line class — `className.replace(/(\b\w+\b)/g,
   "$1-mask")` — and a hyphen is not a word character, so `jc-line` becomes
   `jc-mask-line-mask`. */
.jc-mask-line-mask { padding-bottom: 0.16em; margin-bottom: -0.16em; }
.jc-line, .jc-word, .jc-char { will-change: transform, opacity; }

/* SplitText copies the element's computed `text-align` onto the line wrapper
   and the mask as an inline style, and these splits are `autoSplit: false` —
   so the value is whatever the layout was at split time and never updates.
   Cross a breakpoint after load (a devtools device toggle, a phone rotating)
   and the lines keep the alignment of the width they were split at.
   Inheriting instead is a no-op on first paint and correct at every width
   after; `!important` is what it takes to beat the inline style. */
.jc-line, .jc-mask-line-mask { text-align: inherit !important; }

/* A char split turns every letter into its own inline-block, and the browser
   will happily break a line between two of them — a word split has no such
   thing as an unbreakable word any more. On the homepage hero that showed
   between 1025px and 1199px, where the headline row is a hair wider than the
   card's content box: "Strategic" and "partner" each dropped their last letter
   onto a second line. Restoring nowrap on the WORD wrapper puts the word back
   to being the atom it was before the split, so the row overflows into the
   card's generous side padding instead (20px of 75px at its worst, still
   symmetric and well inside the card), exactly as the unsplit text does with
   the motion layer off.

   The wrapper only exists because splitChars() asks for `type: 'chars,words'`;
   line splits never build one, so this reaches the four char-split headings
   and nothing else. Measured at 360-1600px: no other width moves a pixel. */
.jc-word { white-space: nowrap; }

/* --------------------------------------------------------------------------
   4. Magnetic buttons
   --------------------------------------------------------------------------
   GSAP writes the transform; all this does is stop the button's own hover
   transition fighting it. `.btn__main` already carries
   `transition: color 0.36s …` from its global class, which does not touch
   transform, so nothing has to be overridden — only the compositor hinted.
   Pointer-coarse devices never get the effect (jc-motion.js gates it), so the
   hint is scoped to fine pointers too.
   -------------------------------------------------------------------------- */
html.jc-motion.jc-fine-pointer .btn__main { will-change: transform; }

/* --------------------------------------------------------------------------
   5. Footer link nudge
   --------------------------------------------------------------------------
   Kept from the prototype: a pure-CSS hover the motion layer does not drive,
   but which belongs to the same family of movement.
   -------------------------------------------------------------------------- */
html.jc-motion .footer-service--item svg {
  transition: transform 0.36s cubic-bezier(0.6, 0.19, 0.51, 1.01);
}
html.jc-motion .footer-service--item:hover svg { transform: translateX(5px); }

/* --------------------------------------------------------------------------
   6. Reduced motion — the page as it was, nothing hidden
   --------------------------------------------------------------------------
   Belt and braces. The boot script already withholds `jc-motion` under
   reduced motion, so none of the above applies; this covers the case where
   the preference is switched on after load.
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .jc-loader { display: none !important; }
}
