/* Loaded after the original styles: resolves duplicate/contradictory rules without changing the planned layout. */
#header{z-index:1000}.navbar-collapse.show{display:block}.menu-toggle.is-open span:nth-child(1){transform:translateY(7px) rotate(45deg)}.menu-toggle.is-open span:nth-child(2){opacity:0}.menu-toggle.is-open span:nth-child(3){transform:translateY(-7px) rotate(-45deg)}
.hero-bg img,.hero-bg video{width:100%;height:100%;object-fit:cover;object-position:center}.hero-title{opacity:1}.work-card .work-content>*{opacity:1;transform:none}.work-card .work-image img{display:block;width:100%;height:100%;min-height:460px;object-fit:cover}.services-list{list-style:none;padding:0}.footer-menu{list-style:none;padding:0}
@media(max-width:991px){.navbar-collapse{background:#fff;padding:1rem}.work-card{height:auto;min-height:auto;padding:3rem 1.25rem}.work-image img{height:auto!important;min-height:260px!important}.services{padding-bottom:4rem}.cube-wrapper{width:100%;height:340px}}

/*==================================================================
SERVICES (cube section): left accent line beside the intro copy,
now that the cube is its own section without the old text list.
==================================================================*/
.services-intro{position:relative;padding-left:28px;padding-right:60px}
.services-intro h2{margin-bottom:30px}
.services-intro p{margin-bottom:0}
.section-line{position:absolute;left:0;top:6px;bottom:6px;width:2px;background:var(--primary)}

/*==================================================================
OFFERINGS: dedicated services grid section (below the cube section)
using the six-service copy provided.
==================================================================*/
.offerings{padding:140px 0;background-color: #fff;}
.offerings .section-title{margin-top:14px;margin-bottom:0}
.offerings-grid{margin-top:60px;row-gap:40px}
.offering-card{height:100%;padding:44px 34px;border:1px solid rgba(0,0,0,.08);border-radius:20px;transition:.35s;background-color:transparent}
.offering-card:hover{border-color:transparent;box-shadow:0 30px 80px rgba(0,0,0,.08);transform:translateY(-6px)}
.offering-number{display:block;font-family:var(--heading);font-weight:800;font-size:1.1rem;color:var(--primary);margin-bottom:18px}
.offering-card h3{font-size:1.35rem;margin-bottom:14px}
.offering-card p{font-size:1rem;line-height:1.65;color:var(--text-light);margin:0}

/*==================================================================
FIX: offering cards were controlled entirely by a GSAP ScrollTrigger
that set them to opacity:0 up front and relied on a scroll event to
reveal them. If that trigger never fired for any reason (GSAP load
timing, layout shifted by the pinned cube section above, etc.) the
cards had no other defined state and stayed invisible permanently.
Cards are now visible by default (see .offering-card above); this
"reveal-ready" state is opt-in, added by JS only once it has actually
verified it can observe and reveal each card via IntersectionObserver.
==================================================================*/
/* FIX: same "flash visible then fade to invisible on every page load"
bug as .story-media-img in custom-updates.css -- transition was
declared on the base .reveal-ready rule, so the JS class-add itself
(going from unstyled opacity:1 to opacity:0) animated as a fade-OUT.
Transition now only applies to the intentional reveal (.is-visible). */
.offering-card.reveal-ready{opacity:0;transform:translateY(45px)}
.offering-card.reveal-ready.is-visible{opacity:1;transform:translateY(0);transition:opacity .6s ease,transform .6s ease}
@media(prefers-reduced-motion:reduce){.offering-card.reveal-ready{opacity:1;transform:none;transition:none}}

/*==================================================================
SHOWREEL: video container after About Us.
==================================================================*/
.showreel{padding:60px 0 140px}
.showreel-frame{position:relative;width:100%;aspect-ratio:16/9;border-radius:24px;overflow:hidden;background:#0b0b0c;box-shadow:0 40px 100px rgba(0,0,0,.15)}
.showreel-video{display:block;width:100%;height:100%;object-fit:cover;background:#0b0b0c}
@media(max-width:576px){.showreel-frame{border-radius:14px}}

/*==================================================================
HERO: 100vh, full-bleed background image, headline vertically and
horizontally centered as two lines (per updated design direction).
==================================================================*/
.hero{display:flex;align-items:center}
.hero-inner{align-items:center;text-align:center}
.hero-row,.hero-row-1,.hero-row-2{justify-content:center}
.hero-line-wrap,.hero-row-1 .hero-line-wrap,.hero-row-2 .hero-line-wrap{justify-content:center}
.hero-title{text-align:center;font-size:clamp(2.5rem,4.5vw,4.5rem)}

/*==================================================================
FIX: hero-bg was never positioned as a full-bleed background layer
(no position/inset rule existed anywhere in the whole codebase), so
the image sat inline in normal document flow instead of sitting
full-bleed behind the headline.
==================================================================*/
.hero-bg{position:absolute;inset:0;z-index:0;width:100%;height:100%}
.hero-bg img,.hero-bg video{position:absolute;inset:0}
.hero .container-fluid{position:relative;z-index:1}

/*==================================================================
FIX: .cube-wrapper had no position:relative, so its ::before glow
(position:absolute) was positioning itself against the nearest
positioned ancestor up the tree instead of centering on the cube.
This is the "cube placement is not correct" issue.
==================================================================*/
.cube-wrapper{position:relative}

/*==================================================================
FIX: #services is pinned by GSAP (fixed position) for a long scroll
distance, but was using the generic .section padding (140px top +
bottom) plus its row's natural content height — together taller
than 100vh. Since the pinned element is confined to one viewport,
the vertically-centered cube ended up sitting low / getting clipped.
Constraining the section to exactly 100vh with flex centering keeps
the cube reliably centered while pinned.
==================================================================*/
@media(min-width:992px){#services.services{padding:0;height:100vh;display:flex;align-items:center}#services.services .container{width:100%}}

/*==================================================================
CUBE: crisp, non-rounded corners on every face (was 28px radius).
==================================================================*/
.face{border-radius:0}

/*==================================================================
FIX: "About Us" (#story) had an explicit height:220vh on top of
ibd.js pinning the whole section for a shorter 120% scroll distance.
That double-counted scroll space, so once the pin released there was
still ~1 empty viewport of the section left to scroll through before
the next section appeared. ibd.js now pins .story-pin (the actual
100vh box) directly, so ScrollTrigger's own pin-spacer supplies the
exact scroll length needed — #story no longer needs a manual height.
==================================================================*/
#story.story{height:auto}

/*==================================================================
MOBILE NAV: the 80px pill border-radius on .navbar works for the
slim desktop bar, but once the dropdown list opened underneath it on
mobile the same pill shape wrapped around a much taller block,
producing a lopsided capsule instead of a clean menu. Below 992px
the bar gets a normal rounded-rect radius, the dropdown becomes a
proper full-width card with its own soft entrance, and the nav
list/CTA stack full-width and legible instead of being squeezed into
pill-shaped rows.
==================================================================*/
@media(max-width:991px){
  .navbar{border-radius:20px}
  .navbar-collapse:not(.show){display:none}
  .navbar-collapse.show{
    display:block;
    margin-top:14px;
    border-radius:16px;
    box-shadow:0 20px 50px rgba(0,0,0,.1);
    animation:navDrop .3s ease;
  }
  .navbar-nav{flex-direction:column;align-items:stretch;width:100%;gap:2px}
  .nav-link{width:100%;padding:14px 18px!important}
  .nav-indicator{display:none}
  .btn-nav{display:block;width:100%;text-align:center;margin:14px 0 0}
}
@keyframes navDrop{from{opacity:0;transform:translateY(-8px)}to{opacity:1;transform:translateY(0)}}

/*==================================================================
FIX: page-wide horizontal scroll on mobile, which also dragged the
fixed header sideways ("menu bar goes out of scroll"). Root cause:
.story::before and .selected-work::after are 700px glow blobs with
negative offsets (e.g. right:-250px) and neither section clipped its
own overflow, so the blobs bled past the viewport edge.

IMPORTANT: the fix is NOT html/body { overflow-x: hidden }. That was
tried here previously (and independently re-added in a couple of the
other stylesheets — see mobile-stability.css / custom-updates.css,
now removed) because it does stop the horizontal scrollbar. But
GSAP's own docs call this out specifically: overflow-x:hidden on
<html> or <body> is a known cause of position:fixed breaking on iOS
Safari, because html/body stop being the page's real scrolling
element. Every position:fixed thing on the page inherits that bug —
the fixed header, AND the ScrollTrigger-pinned mobile cube, which is
pinned via position:fixed under the hood. That's the "cube not
playing with GSAP on mobile" report: the pin can't hold position
reliably once html/body carry overflow-x:hidden.

Fix instead by clipping only the two sections that actually produce
the overflow, plus one dedicated wrapper (#ibd-scroll-guard, added
around <body>'s content — see index.html) that carries
overflow-x:hidden without ever being html or body itself. A plain div
does not trigger the Safari fixed-position bug, so this contains the
same horizontal bleed with none of the side effects.
==================================================================*/
#ibd-scroll-guard{overflow-x:hidden;width:100%}
.story,.selected-work{overflow:hidden}

/*==================================================================
FIX: case studies (and several other rows — the services/cube intro,
impact stats, contact info, footer columns) never stacked properly
below their breakpoint. The markup only uses col-lg-*/col-md-* with
no col-12 fallback; Bootstrap scopes those width rules inside their
own min-width media query, so below it the column gets literally no
width rule and sits as a shrink-to-fit flex item next to its sibling
instead of dropping to its own line. Forcing 100% width below each
breakpoint restores normal stacking everywhere this pattern is used.
==================================================================*/
@media(max-width:991px){[class*="col-lg-"]{flex:0 0 100%;width:100%;max-width:100%}}
@media(max-width:767px){[class*="col-md-"]{flex:0 0 100%;width:100%;max-width:100%}}

/*==================================================================
CLIENTS: single-row logo carousel (replaces the old triple
marquee rows). Pure CSS animation so it still runs even if the
GSAP CDN script fails to load.
==================================================================*/
.logo-carousel{position:relative;overflow:hidden;margin:40px 0;-webkit-mask-image:linear-gradient(90deg,transparent,#000 8%,#000 92%,transparent);mask-image:linear-gradient(90deg,transparent,#000 8%,#000 92%,transparent)}
.logo-carousel-track{display:flex;align-items:center;gap:90px;width:max-content;animation:logo-carousel-scroll 30s linear infinite}
.logo-carousel:hover .logo-carousel-track{animation-play-state:paused}
.logo-carousel-track img{flex:none;width:200px;opacity:1.05;filter:grayscale(0%);transition:.35s}
.logo-carousel-track img:hover{opacity:1;filter:none;transform:scale(1.08)}
@keyframes logo-carousel-scroll{from{transform:translateX(0)}to{transform:translateX(-50%)}}
@media(prefers-reduced-motion:reduce){.logo-carousel-track{animation:none}}
@media(max-width:576px){.logo-carousel-track{gap:45px}.logo-carousel-track img{height:32px}}

/*==================================================================
STORY: word-by-word chaining. Words start slightly dim and are
brightened one at a time by JS as the section is scrolled through
(see story() in ibd.js). Reduced-motion / no-JS users still get the
full, readable paragraph at normal opacity via this fallback.
==================================================================*/
.story-word-item{display:inline;transition:opacity .1s linear}
@media(prefers-reduced-motion:reduce){.story-word-item{opacity:1!important}}
