/* ==========================================================================
   JCweb.TECH — GSAP motion layer, homepage
   --------------------------------------------------------------------------
   Ported from prototypes/src/jc-motion.css, sections 0, 5, 8 and 9. Everything
   here is tied to a homepage element ID or to a section only the homepage has.
   The sitewide shell, the loader and SplitText's plumbing are in jc-motion.css.

   Not ported: the pinned card deck (§6 in the prototype) and the deck read-out.
   #how-we-help keeps its static layout and its own six Bricks `fadeInUp`
   interactions, untouched. Two rules from the deck's block do survive, and
   they are marked where they appear.

   MOTION ONLY. The static appearance of #selected-work moved out of this file
   on 2026-08-27 and onto fifteen Bricks global classes, so it is editable from
   the builder; §2 below documents them and the traps that came with them. What
   is left here is state the motion layer owns: `--jc-dark`, the band, and the
   `will-change` hints.
   ========================================================================== */

/* --------------------------------------------------------------------------
   0. Take the intro away from the Bricks interaction layer
   --------------------------------------------------------------------------
   Eight elements had their interactions stripped in the builder so GSAP can
   own them: the five hero elements, whose `_interactions` rows were cleared,
   and the three #our-services cards, which had the shared `.fade-in-up` global
   class removed. (The class itself carries no styling and is still in use on
   ten other pages, so it was left alone.)

   Stripping an interaction takes `data-interaction-hidden-on-load` with it, so
   this is belt-and-braces rather than load-bearing — a safety net in case a
   strip is ever undone in the builder.

   It MUST stay scoped to those eight IDs. The prototype shipped the rule
   unscoped, and applied globally here it would defeat the six #how-we-help
   reveals we are deliberately keeping: they rely on Bricks staging them at
   opacity 0.
   -------------------------------------------------------------------------- */
.bricks-is-frontend :is(
  #brxe-yxytds, #brxe-kknfki, #brxe-kaisja, #brxe-reuuox, #brxe-bpuhat,
  #brxe-pnugzh, #brxe-kuytld, #brxe-deiifh
):not(.brx-animated)[data-interaction-hidden-on-load] { opacity: 1; }

/* The hero button carries its own `heroBtnIn` keyframe from the container's
   custom CSS. Killing the keyframe is enough, and it has to be done without
   `!important` on the opacity: that would also beat GSAP's inline value and
   the button could never be staged. */
html.jc-motion #brxe-yqbzuc > .brxe-button {
  animation: none !important;
  opacity: 1;
}

/* --------------------------------------------------------------------------
   1. Hero
   -------------------------------------------------------------------------- */
html.jc-motion #brxe-yqbzuc { will-change: transform; }

/* The headline words are flex items on a centred row, so they get no line mask
   at all — the characters flip up in 3D instead, which needs no clipping, but
   does need somewhere to flip in. */
html.jc-motion #brxe-yxytds,
html.jc-motion #brxe-kknfki,
html.jc-motion #brxe-reuuox { perspective: 900px; }

/* The portrait sits inside the headline row and leans toward the pointer. */
html.jc-motion #brxe-uikmdm { perspective: 800px; padding-left: 0.16em; }
html.jc-motion #brxe-kaisja { will-change: transform; transform-origin: 50% 85%; }

/* "Strategic" and "partner" are separate elements, spaced on desktop by the
   portrait that sits between them. Below 1024px the portrait leaves the row,
   and the trailing   that should have covered for it is eaten by
   SplitText — the two words run together as "Strategicpartner". */
@media (max-width: 1024px) {
  html.jc-motion #brxe-tazmcs { column-gap: 0.25em; }
}

/* --------------------------------------------------------------------------
   2. Selected work — and the dip to black that introduces it
   --------------------------------------------------------------------------
   What goes dark is a BAND, not the page: jc-home.js wraps #how-we-help and
   #selected-work in one `.jc-band` element at boot and that is what carries the
   background. It matters. A page-wide dip has to be paid back — every section
   it reaches has to give up its own colour, and the light has to come up again
   before the next one needs its own. A band just stops: the black runs out at
   the portfolio's last edge and #our-services starts in its own #F5F5F5 on the
   very next pixel, which is what a section boundary looks like anyway.

   `--jc-dark` is the whole transition: one number, 0 (band as normal) through
   to 1 (lights out), written by a single driver in jc-home.js and read by every
   rule that has to change suit as the band goes under. It ramps once and then
   stays at 1 — there is no way back up. Registering it as a `<number>` keeps
   the computed value a bare number, which is what `calc()` wants.

   The prototype's second variable, `--jc-under`, is NOT ported: it existed
   only for the header pill's ring, and the header stays exactly as it is.
   -------------------------------------------------------------------------- */
@property --jc-dark {
  syntax: "<number>";
  inherits: true;
  initial-value: 0;
}
/* Also declared plainly, so the driver still has something to write to on a
   browser that ignores @property. */
:root { --jc-dark: 0; }

/* The band. White is not a stand-in here: it is what `body` already paints, so
   at --jc-dark: 0 the band is invisible and #how-we-help sits on the page
   exactly as it did before. Only sections INSIDE the band have to be
   transparent — #how-we-help already is, and .jc-work is made so below. */
html.jc-motion .jc-band {
  background-color: color-mix(in srgb, #000 calc(var(--jc-dark) * 100%), var(--clr-white));
}

/* #how-we-help's intro column is the only dark ink the dip passes over, and it
   is deliberately left alone. The prototype faded it out ahead of the murk
   (`--jc-ink-fade`, an opacity ramp on #brxe-fvjrad that emptied by --jc-dark
   0.62) on the reasoning that dark ink has to be gone before the band is.
   Dropped on review 2026-08-27: the column reads better staying fully opaque
   and letting its own near-black ink meet the band's — it goes quiet because
   the contrast runs out, which is a thing paint does, rather than because
   something faded it. Nothing else consumed the variable, so it is gone too.

   The six feature CARDS never needed it either: they are black already, so they
   hold full contrast the whole way down and then dissolve into the band at the
   exact moment it reaches black.

   Except for their silhouette. A hairline ring, scaled by --jc-dark, is
   what stops the stack of black cards dissolving into a black band and leaving
   only the text floating.

   This is the one rule kept from the prototype's pinned-deck block. Its
   `min-height: var(--jc-card-h)` and padding override are NOT kept — those
   belonged to the deck, which is not ported, and #how-we-help keeps its own
   static layout. */
html.jc-motion .jc_feature_card.brxe-block {
  box-shadow: 0 0 0 1px rgb(255 255 255 / calc(var(--jc-dark) * 0.13));
}

/* -- the section ------------------------------------------------------- */

/* Everything that paints #selected-work now lives on Bricks GLOBAL CLASSES,
   not here — so it can be edited from the builder like the rest of the site.
   `bricks/list-global-classes` shows all fifteen; they are:

     jc-work                    the section: dark fallback + the two beats of padding
     jc-work__label             "Portfolio"
     jc-work__heading           the h2 (and the two inline .jc-work__heading-line spans)
     jc-work__list              the ul
     jc-work-row                the row grid, its hover, and both reflows
     jc-work-row__thumb         the 124x84 clipping box
     jc-work-row__thumb-img     the desaturated image inside it
     jc-work-row__main          )
     jc-work-row__meta          ) grid-area holders, no styling of their own
     jc-work-row__name          the h3
     jc-work-row__collab        "w/ Something Familiar"
     jc-work-row__tags          the tag ul
     jc-work-row__tag           the glass pill (was `.jc-work-row__tags li`)
     jc-work-row__desc          the description
     jc-work-row__year

   Two things could not follow them and are still here, below: the band and the
   dip that drive the section (above), and the `will-change` hints — both are
   motion-layer state, meaningless without jc-home.js.

   Traps worth keeping, because Bricks strips comments from a class's custom CSS
   the moment it re-serialises the block:

   - .jc-work / html.jc-motion .jc-work — the section's own dark is the NO-JS
     fallback, and it MUST stay the same colour the band dips to (line 109) or
     the two paths disagree. Both are pure black: --clr-black on the class,
     a literal #000 in the color-mix. Tried on --Colours__Text_Colour_Headings
     (#1f1b18, the site's own near-black) on 2026-08-27 and reverted the same
     day — if either is ever moved again, move both.

   - .jc-work__heading width: 100% is load-bearing. .brxe-container is a flex
     column with align-items: flex-start, so without it the h2 is only as wide
     as the word "Selected", the second line's percentage indent resolves
     against that, and SplitText's line mask clips it — the heading renders as
     "Selectec / Project".

   - .jc-work-row grid columns use minmax(0, …), never a bare fr: an fr track's
     automatic minimum is its min-content width, so "abodusstudents.com" at 24px
     refuses to shrink and pushes the row apart from the inside.

   - .jc-work-row's two reflows stayed in the class's custom CSS rather than
     becoming responsive controls, because grid-template-areas has no Bricks
     control and the first boundary is 1199px, which Bricks has no breakpoint
     for (its stops are 1279 / 1024 / 767). That boundary is load-bearing:
     verified at 1030px, the four-column row wraps "abodusstudents.com"
     mid-domain and breaks every tag list onto two lines. Adding a 1199px
     breakpoint site-wide would let it become a normal responsive control.

   - .jc-work-row hover is a literal #242422, not a palette rung: --clr-black-l-2
     is #2e2e2e, a 23-point lift off the row's #171717 where a 10-point lift is
     wanted. The row should read as warming under the pointer, not lighting up.

   - .jc-work-row transition is spelled out rather than var(--transition__default):
     that token starts with `all`, so the shorthand would expand to
     `background-color all 0.3s …` — two properties in one value, invalid, and
     the row would lose its transition entirely.

   - .jc-work-row__tag is display: block, not a flex item: `text-box` is ignored
     on an anonymous flex item, and without the trim the pill stands 50px tall
     instead of 34px. Its padding is 11/23, not Figma's 10/22, because Figma
     draws a 32px box with the 1px stroke aligned OUTSIDE it — the pill really
     measures 34px, and the stroke is drawn by ::before rather than a border, so
     its 1px is folded into the padding. Figma node 3520:3906.

   - .jc-work-row__thumb-img hover (full colour, 1.18 scale) lives on
     .jc-work-row, because the row is what gets hovered. 1.18 eats 7.6% off
     every edge; the two lockups are letterboxed by prototypes/src/thumbs.py so
     they have that margin to give. */

html.jc-motion .jc-work__heading,
html.jc-motion .jc-work-row { will-change: transform, opacity; }


/* --------------------------------------------------------------------------
   3. Services
   -------------------------------------------------------------------------- */
html.jc-motion #our-services { overflow: hidden; }
html.jc-motion #brxe-adlhll > li { will-change: transform; perspective: 1400px; }
html.jc-motion .product_card { will-change: transform; transform-style: preserve-3d; }

/* The clip that lets the render drift inside its frame costs this figure both
   of its intrinsic sizes, so both have to be handed back explicitly:

   - WIDTH: the figure is a flex item on a column with `align-items: flex-start`,
     so it is sized shrink-to-fit — `overflow` alone collapsed it from the card's
     full width (443px) to the image's fit-content width (285px). Pinned to 100%.
   - HEIGHT: `.product_card__body` carries `height: 100%`, which asks for the
     whole card, so the two items are over-constrained and both shrink. Normally
     the figure refuses, because a flex item's automatic minimum size floors it
     at min-content — but `overflow: hidden` makes it a scroll container and the
     spec zeroes that floor. The body then took 400px of a 600px card and the
     figure was squashed to 200px around a 311px image, hiding a third of the
     render. `flex-shrink: 0` puts the floor back, so all the shrink lands on
     the body exactly as it does on the static page. */
html.jc-motion .product_card__img.brxe-image {
  overflow: hidden;
  width: 100%;
  flex: 0 0 auto;
}
html.jc-motion .product_card__img.brxe-image img {
  width: 100%; height: auto; display: block;
  will-change: transform;
}

/* --------------------------------------------------------------------------
   4. CTA banner + footer
   -------------------------------------------------------------------------- */
/* The wrapper is the clipping box, so the parallax and the drift go on the
   image inside it. Moving the figure instead opens a gap along the banner
   edge. */
html.jc-motion .CTA_banner__img_wrapper { overflow: hidden; }
html.jc-motion .CTA_banner__img.brxe-image { will-change: transform; }
