/* Local fidelity fixes for layout differences caused by running outside Webflow. */
html,
body[data-theme="white"] {
  background: #fff;
  color: #090909;
}

/* Base and non-hovered heading states for the mobile accordion live near the end
   of this file. Every other state this rule used to also list (:hover,
   :focus-within, .brand-hover-service, .brand-selected-service) is shadowed by
   later rules in this file that resolve to the same or a different color, so
   only the :has(item-button-list) branch is still load-bearing here - it has
   no equivalent anywhere else and outranks everything below via :has()'s own
   specificity, regardless of source order. */
.header__dropdown-content [data-role="accordion-item"]:has([data-role="item-button-list"] .button) > [data-role="accordion-summary"] [data-role="category-heading"] {
  color: var(--accent-test-color, #DB4361) !important;
  -webkit-text-fill-color: var(--accent-test-color, #DB4361) !important;
  -webkit-text-stroke: 0 var(--accent-test-color, #DB4361) !important;
  text-stroke: 0 var(--accent-test-color, #DB4361) !important;
}

/* Absolute final state for desktop services dropdown.
   JS owns the single active row via .brand-active-service; all Webflow
   hover/open/active colors are neutralized so the list cannot turn blue
   or highlight multiple rows. Only :focus-within and .w--open still need to be
   listed here - every other state this rule used to also cover (base, :hover,
   .active, .is-active, .js--active, .brand-hover-service, .brand-selected-service)
   is repainted pink by the "one reliable pink highlight layer" rule further
   down this file, so listing them here too was dead weight. */
.header__dropdown-content [data-role="accordion-item"]:focus-within > [data-role="accordion-summary"] [data-role="category-heading"],
.header__dropdown-content [data-role="accordion-item"].w--open > [data-role="accordion-summary"] [data-role="category-heading"] {
  color: transparent !important;
  -webkit-text-fill-color: transparent !important;
  -webkit-text-stroke: 1px rgba(9, 9, 9, 0.38) !important;
  text-stroke: 1px rgba(9, 9, 9, 0.38) !important;
}

.header__dropdown-content [data-role="accordion-item"].brand-active-service > [data-role="accordion-summary"] [data-role="category-heading"] {
  color: var(--accent-test-color, #DB4361) !important;
  -webkit-text-fill-color: var(--accent-test-color, #DB4361) !important;
  -webkit-text-stroke: 0 var(--accent-test-color, #DB4361) !important;
  text-stroke: 0 var(--accent-test-color, #DB4361) !important;
}

:root,
body {
  --accent-test-color: #DB4361;
  --blue: #DB4361;
  --color-blue: #DB4361;
  --color-accent: #DB4361;
  --color-primary: #DB4361;
}

/* Article filters: replace the original blue selected state with Fisheye pink. */
.navigation-tag.w--current,
.navigation-tag[aria-current="page"] {
  background-color: var(--accent-test-color, #DB4361) !important;
  border-color: var(--accent-test-color, #DB4361) !important;
  color: #fff !important;
}

.navigation-tag:not(.w--current):hover,
.navigation-tag:not(.w--current):focus-visible {
  border-color: var(--accent-test-color, #DB4361) !important;
  color: var(--accent-test-color, #DB4361) !important;
}

[data-role="article-card"][hidden] {
  display: none !important;
}

/* Two-level FAQ used by the virtual-tour service page. */
.grouped-faq__topics {
  width: 100%;
}

.grouped-faq__topic {
  border-top: 1px solid var(--color-text-dark-10, rgba(9, 9, 9, 0.1));
}

.grouped-faq__topic:last-child {
  border-bottom: 1px solid var(--color-text-dark-10, rgba(9, 9, 9, 0.1));
}

.grouped-faq__topic-button {
  align-items: center;
  appearance: none;
  background: transparent;
  border: 0;
  color: inherit;
  cursor: pointer;
  display: grid;
  font: inherit;
  gap: clamp(1rem, 2vw, 2rem);
  grid-template-columns: 3rem minmax(0, 1fr) 1.5rem;
  padding: clamp(1.35rem, 2vw, 2rem) 0;
  text-align: left;
  width: 100%;
}

.grouped-faq__topic-number {
  color: var(--accent-test-color, #DB4361);
  font-size: 0.875rem;
}

.grouped-faq__topic-title {
  font-size: clamp(1.5rem, 2.5vw, 2.75rem);
  font-weight: 600;
  line-height: 1.08;
  margin: 0;
}

.grouped-faq__topic-icon {
  height: 1.25rem;
  position: relative;
  width: 1.25rem;
}

.grouped-faq__topic-icon::before,
.grouped-faq__topic-icon::after {
  background: currentColor;
  content: "";
  height: 1px;
  left: 0;
  position: absolute;
  top: 50%;
  transition: transform 240ms ease;
  width: 100%;
}

.grouped-faq__topic-icon::after {
  transform: rotate(90deg);
}

.grouped-faq__topic.is-open .grouped-faq__topic-button {
  color: var(--accent-test-color, #DB4361);
}

.grouped-faq__topic.is-open .grouped-faq__topic-icon::after {
  transform: rotate(0deg);
}

.grouped-faq__topic-panel {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 320ms cubic-bezier(0.16, 1, 0.3, 1);
}

.grouped-faq__topic.is-open .grouped-faq__topic-panel {
  grid-template-rows: 1fr;
}

.grouped-faq__topic-panel-inner {
  min-height: 0;
  overflow: hidden;
}

.grouped-faq__topic .article-faq__faq-items {
  padding-bottom: clamp(1.5rem, 3vw, 3rem);
  padding-left: clamp(2rem, 6vw, 7rem);
}

@media (max-width: 767px) {
  .grouped-faq__topic-button {
    grid-template-columns: 2rem minmax(0, 1fr) 1.25rem;
  }

  .grouped-faq__topic .article-faq__faq-items {
    padding-left: 0;
  }
}

@media (prefers-reduced-motion: reduce) {
  .grouped-faq__topic-panel,
  .grouped-faq__topic-icon::after {
    transition: none;
  }
}

html {
  scrollbar-color: var(--accent-test-color) #242424 !important;
}

::-webkit-scrollbar-thumb {
  background-color: var(--accent-test-color) !important;
  border-color: var(--accent-test-color) !important;
}

::-webkit-scrollbar-thumb:hover,
::-webkit-scrollbar-thumb:active {
  background-color: var(--accent-test-color) !important;
}

::-webkit-scrollbar-track {
  background-color: #242424 !important;
}

.header,
[data-role="header"] {
  opacity: 1 !important;
  transition: background-color 220ms ease, color 220ms ease, backdrop-filter 220ms ease !important;
  visibility: visible !important;
  z-index: 1000 !important;
}

/* Keep the Services dropdown functional without dimming the page behind it. */
.header__dropdown-background {
  background: transparent !important;
  background-color: transparent !important;
}

.header .svg-flex svg,
.header .copy-email svg,
.header .header__network-icon svg {
  color: currentColor;
}

.header .button.header__button,
.header .button--white.header__button {
  background: #fff !important;
  border-color: rgba(9, 9, 9, 0.32) !important;
  color: #090909 !important;
}

/* Match the desktop CTA to the header navigation's white/black color state. */
.header .button.header__item-button {
  background: transparent !important;
  border-color: currentColor !important;
  box-shadow: inset 0 0 0 1px currentColor !important;
  color: inherit !important;
  transition: border-color 220ms ease, box-shadow 220ms ease, color 220ms ease !important;
}

.button:not(.button--white):not(.button--outline):not(.button--outline-light):not(.header-button--gray),
.cta .button,
[data-role="calendly-button"],
[data-role="book-button"],
[data-role="pdf-button"],
[data-role="contact-content"] .button:not(.button--outline),
.cookie-banner__button {
  background-color: var(--accent-test-color) !important;
  border-color: var(--accent-test-color) !important;
  color: #fff !important;
}

.arrow-icon,
.categories__menu-item.services-scroll-current .replica-service-wordmark path {
  color: var(--accent-test-color) !important;
}

/* Catch the few original blue Webflow icon assets that do not inherit text color. */
.arrow-icon,
.arrow-icon--lg,
.service-hero__arrow-wrapper .arrow-icon,
.section__heading-wrapper .arrow-icon {
  background-color: transparent !important;
  border-color: transparent !important;
  filter: brightness(0) saturate(100%) invert(39%) sepia(78%) saturate(994%) hue-rotate(302deg) brightness(92%) contrast(88%) !important;
}

.arrow-icon::before,
.arrow-icon::after,
.arrow-icon--lg::before,
.arrow-icon--lg::after {
  background-color: transparent !important;
  border-color: var(--accent-test-color) !important;
}

svg [fill="#243AFF"],
svg [fill="#243aff"] {
  fill: var(--accent-test-color) !important;
}

svg [stroke="#243AFF"],
svg [stroke="#243aff"] {
  stroke: var(--accent-test-color) !important;
}

.faq-icon,
.article-faq__faq-icon,
[data-role="item-icon"] {
  color: #c7c7c7 !important;
}

.faq-icon svg path,
.faq-icon svg line,
.faq-icon svg polyline,
.article-faq__faq-icon svg path,
.article-faq__faq-icon svg line,
.article-faq__faq-icon svg polyline,
[data-role="item-icon"] svg path,
[data-role="item-icon"] svg line,
[data-role="item-icon"] svg polyline {
  stroke: currentColor !important;
}

.faq-item:hover .faq-icon,
.faq-item:focus-within .faq-icon,
.faq-item.active .faq-icon,
.faq-item.is-active .faq-icon,
.faq-item.w--open .faq-icon,
.faq-item[aria-expanded="true"] .faq-icon,
.faq-item[data-open="true"] .faq-icon,
.article-faq__faq-item:hover .article-faq__faq-icon,
.article-faq__faq-item:focus-within .article-faq__faq-icon,
.article-faq__faq-item.active .article-faq__faq-icon,
.article-faq__faq-item.is-active .article-faq__faq-icon,
.article-faq__faq-item.w--open .article-faq__faq-icon,
.article-faq__faq-item[aria-expanded="true"] .article-faq__faq-icon,
.article-faq__faq-item[data-open="true"] .article-faq__faq-icon,
[data-role="item"]:hover [data-role="item-icon"],
[data-role="item"]:focus-within [data-role="item-icon"],
[data-role="item"].active [data-role="item-icon"],
[data-role="item"].is-active [data-role="item-icon"],
[data-role="item"].w--open [data-role="item-icon"],
[data-role="item"][aria-expanded="true"] [data-role="item-icon"],
[data-role="item"][data-open="true"] [data-role="item-icon"] {
  color: var(--accent-test-color) !important;
}

.text-marker {
  color: var(--accent-test-color) !important;
}

.header__dropdown-heading {
  transition: color 180ms ease !important;
}

.header__dropdown-content [data-role="category-heading"] {
  color: transparent !important;
  -webkit-text-fill-color: transparent !important;
  -webkit-text-stroke-color: rgba(9, 9, 9, 0.38) !important;
  text-stroke-color: rgba(9, 9, 9, 0.38) !important;
}

.header__dropdown-content [data-role="accordion-item"]:hover [data-role="category-heading"],
.header__dropdown-content [data-role="accordion-item"]:focus-within [data-role="category-heading"],
.header__dropdown-content [data-role="accordion-item"].brand-hover-service [data-role="category-heading"],
.header__dropdown-content [data-role="accordion-item"].brand-selected-service [data-role="category-heading"] {
  color: var(--accent-test-color) !important;
  -webkit-text-fill-color: var(--accent-test-color) !important;
  -webkit-text-stroke-color: var(--accent-test-color) !important;
  text-stroke-color: var(--accent-test-color) !important;
}

.header__dropdown-content:has([data-role="accordion-item"]:hover) [data-role="accordion-item"].brand-selected-service:not(:hover) [data-role="category-heading"] {
  color: transparent !important;
  -webkit-text-fill-color: transparent !important;
  -webkit-text-stroke-color: rgba(9, 9, 9, 0.38) !important;
  text-stroke-color: rgba(9, 9, 9, 0.38) !important;
}

.header__dropdown-cms-item.active .header__dropdown-heading,
.header__dropdown-cms-item.is-active .header__dropdown-heading,
.header__dropdown-cms-item.w--open .header__dropdown-heading,
.header__dropdown-cms-item[aria-expanded="true"] .header__dropdown-heading,
.header__dropdown-content .header__dropdown-cms-item.active .header__dropdown-heading,
.header__dropdown-content .header__dropdown-cms-item.is-active .header__dropdown-heading,
.header__dropdown-content .header__dropdown-cms-item.w--open .header__dropdown-heading,
.header__dropdown-content .header__dropdown-cms-item[aria-expanded="true"] .header__dropdown-heading,
[data-role="accordion-item"].active [data-role="category-heading"],
[data-role="accordion-item"].is-active [data-role="category-heading"],
[data-role="accordion-item"].w--open [data-role="category-heading"],
[data-role="accordion-item"][aria-expanded="true"] [data-role="category-heading"],
.header__dropdown [data-role="category-heading"][style*="#243"],
.header__dropdown [data-role="category-heading"][style*="36, 58, 255"],
.header__dropdown [data-role="category-heading"][style*="rgb(36, 58, 255)"],
.header__dropdown-content [data-role="category-heading"][style*="#243"],
.header__dropdown-content [data-role="category-heading"][style*="#2440"],
.header__dropdown-content [data-role="category-heading"][style*="36,58,255"],
.header__dropdown-content [data-role="category-heading"][style*="36, 58, 255"],
.header__dropdown-content [data-role="category-heading"][style*="rgb(36,58,255)"],
.header__dropdown-content [data-role="category-heading"][style*="rgb(36, 58, 255)"] {
  color: var(--accent-test-color) !important;
  -webkit-text-fill-color: var(--accent-test-color) !important;
  -webkit-text-stroke-color: var(--accent-test-color) !important;
  text-stroke-color: var(--accent-test-color) !important;
}

.header__dropdown .button.header-button--gray:hover,
.header__dropdown .button.header-button--gray:focus,
.header__dropdown .button.header-button--gray:focus-visible,
.header__dropdown .button.header-button--gray:active,
.header__dropdown .button.header-button--gray.active,
.header__dropdown .button.header-button--gray.is-active,
.header__dropdown .button.header-button--gray.w--current,
.header__dropdown .button.header-button--gray[aria-current="page"],
.header__dropdown-content .button.header-button--gray:hover,
.header__dropdown-content .button.header-button--gray:focus,
.header__dropdown-content .button.header-button--gray:focus-visible,
.header__dropdown-content .button.header-button--gray:active,
.header__dropdown-content .button.header-button--gray.active,
.header__dropdown-content .button.header-button--gray.is-active,
.header__dropdown-content .button.header-button--gray.w--current,
.header__dropdown-content .button.header-button--gray[aria-current="page"] {
  background: var(--accent-test-color) !important;
  background-color: var(--accent-test-color) !important;
  border-color: var(--accent-test-color) !important;
  color: #fff !important;
}

.header__dropdown .button.header-button--gray:hover *,
.header__dropdown .button.header-button--gray:focus *,
.header__dropdown .button.header-button--gray:focus-visible *,
.header__dropdown .button.header-button--gray:active *,
.header__dropdown .button.header-button--gray.active *,
.header__dropdown .button.header-button--gray.is-active *,
.header__dropdown .button.header-button--gray.w--current *,
.header__dropdown-content .button.header-button--gray:hover *,
.header__dropdown-content .button.header-button--gray:focus *,
.header__dropdown-content .button.header-button--gray:focus-visible *,
.header__dropdown-content .button.header-button--gray:active *,
.header__dropdown-content .button.header-button--gray.active *,
.header__dropdown-content .button.header-button--gray.is-active *,
.header__dropdown-content .button.header-button--gray.w--current * {
  color: #fff !important;
  stroke: currentColor !important;
}

/* Re-tint the original cursor/ambient glow from blue to the brand pink. */
.why__blur,
[data-role="blur"] {
  filter: hue-rotate(128deg) saturate(1.45) brightness(0.98) !important;
}

.section.works .works__lightening,
.section.works .works__lightening--light,
main[data-component-id="works-cases"] .works__lightening {
  display: none !important;
  background: transparent !important;
  filter: none !important;
  opacity: 0 !important;
}

.works__lightening,
.works__lightening--light {
  background:
    radial-gradient(
      circle,
      rgba(219, 67, 97, 0.24) 0%,
      rgba(219, 67, 97, 0.14) 28%,
      rgba(219, 67, 97, 0.04) 58%,
      rgba(219, 67, 97, 0) 72%
    ) !important;
}

/* Removed homepage modules requested by client. */
section[data-component-id="partners"].section.partners,
section.section--rendering {
  display: none !important;
}

/* Keep the post-portfolio homepage flow from flashing into the original dark theme on hard refresh. */
.section.section--partner.section--bg-dark,
.section.section--pt0.section--bg-dark,
.section.section--pt0.section--bg-dark .section.clients,
.section.section--pt0.section--bg-dark .clients__container,
.section.section--pt0.section--bg-dark .faq-wrapper,
.section.section--pt0.section--bg-dark .faq-items {
  background: #fff !important;
  color: #090909 !important;
}

.section.section--partner.section--bg-dark .heading,
.section.section--partner.section--bg-dark .text,
.section.section--partner.section--bg-dark .text-md,
.section.section--pt0.section--bg-dark .heading,
.section.section--pt0.section--bg-dark .text,
.section.section--pt0.section--bg-dark .text-md,
.section.section--pt0.section--bg-dark .faq-heading,
.section.section--pt0.section--bg-dark .faq-count-number {
  color: #090909 !important;
}

.home-portfolio-filter {
  display: flex;
  flex-wrap: wrap;
  gap: 0.625rem;
  margin-top: clamp(1.5rem, 3vw, 3rem);
  position: relative;
  z-index: 6;
}

.home-portfolio-filter__button {
  appearance: none;
  border: 1px solid rgba(9, 9, 9, 0.18);
  border-radius: 999px;
  background: #fff;
  color: #090909;
  cursor: pointer;
  font: inherit;
  font-size: clamp(0.875rem, 0.86vw, 1rem);
  line-height: 1;
  min-height: 2.55rem;
  padding: 0.72rem 1.2rem;
  transition: background-color 220ms ease, border-color 220ms ease, color 220ms ease,
    transform 220ms ease;
  white-space: nowrap;
}

.home-portfolio-filter__button:hover {
  transform: translateY(-1px);
  border-color: rgba(9, 9, 9, 0.38);
}

.home-portfolio-filter__button.is-active {
  background: var(--accent-test-color);
  border-color: var(--accent-test-color);
  color: #fff;
}

.home-portfolio-original-hidden {
  display: none !important;
}

/* This grid used to force itself full-bleed with the usual
   `margin-left: calc(50% - 50vw); width: 100vw` trick. That was both
   redundant and actively broken here:

   - Redundant, because its parent (section.section.articles-body) is
     already a full-width block starting at x=0. There is no .container
     ancestor to break out of - measured, not assumed.
   - Broken, because 100vw counts the classic scrollbar but the 50% does
     not. On a 1440px window with a 15px scrollbar the grid rendered
     1440px wide starting at -7.5px, i.e. hanging half a scrollbar off
     the left edge and overflowing the document by the full 15px. The
     page-level overflow-x:hidden hid the horizontal scrollbar, which is
     why the overflow test never caught it - but the leftmost column was
     genuinely clipped, and its caption sat ~7px closer to the screen
     edge than intended.

   Letting it size naturally gives exactly the same full-width result
   without the scrollbar error. */
.home-portfolio-filter-grid {
  align-items: flex-start;
  display: flex;
  gap: 0;
  margin-left: 0;
  margin-top: 0;
  position: relative;
  width: auto;
  z-index: 5;
}

.home-portfolio-filter-grid[hidden] {
  display: none !important;
}

.home-portfolio-filter-column {
  display: flex;
  flex: 0 0 33.333333%;
  flex-direction: column;
  min-width: 0;
}

.home-portfolio-filter-grid .gallery-item,
.home-portfolio-filter-card {
  break-inside: avoid;
  display: block;
  margin: 0;
  overflow: hidden;
  position: relative !important;
  transform: none !important;
  width: 100% !important;
}

.home-portfolio-filter-grid .gallery-item__wrapper,
.home-portfolio-filter-grid .gallery-item__image-box,
.home-portfolio-filter-grid .gallery-item__image-wrapper {
  height: auto !important;
  min-height: 0 !important;
  width: 100% !important;
}

.home-portfolio-filter-grid .gallery-item__image {
  display: block;
  height: auto !important;
  min-height: 0 !important;
  object-fit: cover;
  position: relative !important;
  width: 100% !important;
}

.home-portfolio-filter-grid .gallery-item__image--absolute {
  inset: 0;
  position: absolute !important;
}

/* Hover-preview video: hidden (showing the static image beneath) until
   home-portfolio-filter.js's hover listener adds is-video-active, so
   the video never has a reason to visually appear - or need to have
   loaded - before the user actually hovers the card. */
.home-portfolio-filter-grid .gallery-item__image-wrapper video.gallery-item__image--absolute {
  opacity: 0;
  transition: opacity 220ms cubic-bezier(0.22, 1, 0.36, 1);
}

.home-portfolio-filter-grid .home-portfolio-filter-card.is-video-active .gallery-item__image-wrapper video.gallery-item__image--absolute {
  opacity: 1;
}

@media (prefers-reduced-motion: reduce) {
  .home-portfolio-filter-grid .gallery-item__image-wrapper video.gallery-item__image--absolute {
    transition: none;
  }
}

.home-portfolio-filter-grid .gallery-item__info {
  background: #fff;
  color: #090909;
  opacity: 1 !important;
  padding: 0.75rem 1.25rem 1.15rem;
  position: relative;
  transform: none !important;
}

/* The grid is deliberately edge-to-edge, so a caption's 1.25rem inset is
   measured from the screen edge rather than from the page's text column.
   At laptop/desktop widths that reads as the project names hanging off the
   left edge while every other section on the page starts ~2rem further in.

   Only the OUTER edges need correcting - an inner column's caption should
   stay aligned to its own image. The value is the same expression
   .container uses for its gutter (from the Webflow stylesheet), so these
   captions line up with ordinary page content at every width instead of
   tracking a second, hand-picked scale that would drift from it.

   max() keeps the original 1.25rem as a floor: below ~1180px the site
   gutter is smaller than 1.25rem, and without the floor this would pull
   the captions further LEFT on phones - the opposite of the fix. Mobile
   therefore keeps exactly its current 20px. */
.home-portfolio-filter-column:first-child .gallery-item__info {
  padding-left: max(1.25rem, clamp(1rem, 0.6359rem + 1.5534vw, 2.5rem));
}

.home-portfolio-filter-column:last-child .gallery-item__info {
  padding-right: max(1.25rem, clamp(1rem, 0.6359rem + 1.5534vw, 2.5rem));
}

.home-portfolio-filter-grid .text--gallery-name {
  color: #090909;
  font-weight: 700;
}

@media (max-width: 991px) {
  .home-portfolio-filter-column {
    flex-basis: 50%;
  }
}

@media (max-width: 767px) {
  .home-portfolio-filter {
    align-items: center;
    flex-wrap: wrap;
    gap: 0.45rem;
    justify-content: flex-start;
    margin-left: 0;
    margin-right: 0;
    max-width: 100%;
    overflow-x: visible;
    padding-bottom: 0;
  }

  .home-portfolio-filter__button {
    flex: 0 1 auto;
    font-size: 0.84rem;
    min-height: 2.25rem;
    padding: 0.62rem 0.95rem;
    white-space: nowrap;
  }

  .home-portfolio-filter-column {
    flex-basis: 100%;
  }
}

.categories__menu-item.services-scroll-current .replica-service-wordmark path {
  stroke: #fff !important;
}

.section.works {
  --color-background-dark: #fff;
  --color-text-white: #090909;
  --color-text-black: #090909;
  background: #fff !important;
  color: #090909 !important;
}

.section.works .works__container,
.section.works [data-component-id="gallery-masonry"],
.section.works .gallery-works,
.section.works .services__list-wrapper {
  background: #fff !important;
  color: #090909 !important;
}

.section.works .section__header-subtitle,
.section.works .heading,
.section.works .section__header-description {
  color: #090909 !important;
}

.section.works .text-marker {
  color: var(--accent-test-color) !important;
}

/* Scoped to .section.works specifically (the homepage's portfolio preview) -
   .gallery-works is a shared component class also used unscoped on the
   actual Gallery page, which gets its own separate full-bleed treatment
   below (body.body-with-gallery ...). Without this scope, linking this
   stylesheet site-wide would have forced the real Gallery page's masonry
   into the same 100vw layout unintentionally. */
@media screen and (min-width: 1281px) {
  .section.works .gallery-works,
  .section.works .gallery-works > .services__list-wrapper,
  .section.works .gallery-works .services__masonry-grid {
    box-sizing: border-box;
    /* 100%, not 100vw - see the scrollbar note on the gallery-page rule
       above. The enclosing section is already full width; 100vw would add
       the scrollbar's width on top of it. */
    width: 100% !important;
    min-width: 100%;
    max-width: none !important;
  }
}

/* Gallery page: make the project masonry match the homepage Portfolio treatment. */
body.body-with-gallery .section.articles-body.cases-body {
  background: #fff !important;
  overflow: hidden !important;
  padding-left: 0 !important;
  padding-right: 0 !important;
}

body.body-with-gallery .section.articles-body.cases-body .gallery-works,
body.body-with-gallery .section.articles-body.cases-body .services__list-wrapper,
body.body-with-gallery .section.articles-body.cases-body .gallery-item-list-wrapper,
body.body-with-gallery .section.articles-body.cases-body .gallery-item-list,
body.body-with-gallery .section.articles-body.cases-body .services__masonry-grid {
  background: transparent !important;
  box-sizing: border-box !important;
  margin-left: 0 !important;
  margin-right: 0 !important;
  max-width: none !important;
  padding-left: 0 !important;
  padding-right: 0 !important;
  /* 100%, not 100vw - the enclosing section is already full width
     (clientWidth), whereas 100vw additionally counts the scrollbar and so
     pushed the right-hand 15px of the gallery masonry underneath it. Same
     bug as .secton.categories / .home-portfolio-filter-grid; here it was
     invisible because the page's overflow-x:hidden clipped the excess
     rather than showing a scrollbar. */
  width: 100% !important;
}

body.body-with-gallery .section.articles-body.cases-body .gallery-item,
body.body-with-gallery .section.articles-body.cases-body .gallery-item__wrapper,
body.body-with-gallery .section.articles-body.cases-body .gallery-item__image-box {
  background: transparent !important;
  border: 0 !important;
  box-shadow: none !important;
  box-sizing: border-box !important;
  margin: 0 !important;
  outline: 0 !important;
  padding: 0 !important;
}

body.body-with-gallery .section.articles-body.cases-body .gallery-item__image {
  display: block !important;
  margin: 0 !important;
  width: 100% !important;
}

@media screen and (min-width: 992px) {
  .header__dropdown-layout {
    column-gap: clamp(2.5rem, 3vw, 4.5rem) !important;
    grid-template-columns: minmax(0, 40%) minmax(0, 24%) minmax(0, 36%) !important;
  }

  .header__dropdown-cms,
  .header__dropdown-cms-list {
    min-width: 0;
  }

  .header__dropdown-items {
    grid-column: 1;
    grid-row: 1;
    padding-left: clamp(1rem, 2vw, 2.5rem);
  }

  /* overflow:hidden here (from Webflow's own captured CSS) combined with an
     auto height that collapses to near-0 - since its only content is
     absolutely positioned and doesn't contribute to normal-flow height - was
     visually cropping the square media slot below to a fraction of its real
     size. The element still measured full-size via getBoundingClientRect
     (layout geometry), which is why this was invisible to automated
     checks and only showed up as a visibly cropped image in a real browser. */
  .header__dropdown-main-data {
    align-items: start;
    column-gap: clamp(2rem, 3vw, 4rem);
    display: grid !important;
    grid-template-columns: minmax(0, 42%) minmax(0, 58%);
    overflow: visible !important;
    padding-left: clamp(1.5rem, 2.5vw, 3rem);
  }

  .header__dropdown-description-wrapper {
    display: contents !important;
  }

  .header__dropdown-description-wrapper > .text {
    grid-column: 1;
    grid-row: 2;
    margin-top: 1.35rem;
    max-width: 32rem;
  }

  /* align-self:center (grid alignment within the row 1/span-2 track) fixed
     the image escaping its container, but left top/bottom margins uneven -
     the grid row's own computed height doesn't line up with the panel's
     actual visual edges (it's derived from implicit row-track sizing, which
     doesn't necessarily distribute symmetrically around the panel's real
     padding). .header__dropdown-container sits between the wrapper and the
     panel and is also position:relative (Webflow's own ".container"
     utility, inert top/left/right/bottom:0 - confirmed nothing else depends
     on it as a positioning anchor), which would otherwise intercept
     positioning first; set to static below so it steps out of the way and
     .header__dropdown-content (the panel itself, position:absolute)
     becomes the containing block. Also pulled the wrapper out of the grid
     entirely (grid-column/grid-row/align-self all removed) -
     grid-template-columns on .header__dropdown-main-data is a fixed
     42%/58% split (minmax, not auto), so it doesn't collapse or reflow now
     that nothing occupies column 2 in normal flow.

     Centering itself uses top:0/bottom:0 with auto margins rather than
     top:50% + translateY(-50%): measured in a real browser, the computed
     top:50% value didn't match 50% of the panel's actual rect height by
     any consistent math (panel is display:flex with content-derived
     height, which the spec treats as not "definitely" sized for
     percentage-resolution purposes, even though it's itself
     position:absolute with a concrete laid-out height) - so the
     percentage reference itself is unreliable here. top:0/bottom:0 are
     literal zero offsets, not percentages, so they don't depend on that
     ambiguous reference at all; auto margins then split the real leftover
     space between the wrapper's fixed height and the panel's actual
     rendered top/bottom edges equally. */
  .header__dropdown-container {
    position: static !important;
  }

  .header__dropdown-image-wrapper {
    bottom: 0;
    height: var(--service-image-size);
    margin-bottom: auto;
    margin-top: auto;
    overflow: visible !important;
    position: absolute !important;
    /* right is set per breakpoint below, not here - see the comment above
       the 992-1279px override for why a single fluid value can't track it. */
    top: 0;
    width: var(--service-image-size);
  }

  /* Square media slot: all service preview images are 1:1. The wrapper
     above is now exactly --service-image-size in both dimensions and
     positioned directly (top:50%/translateY(-50%) + right, anchored to
     .header__dropdown-container's real height), so this inner element just
     fills it edge-to-edge from top:0/right:0 - no separate centering math
     needed at this level.

     Width and height are both set to the SAME explicit --service-image-size
     value rather than using `aspect-ratio: 1 / 1` with `height: auto`. The
     aspect-ratio approach measured square in this environment's automated
     checks but rendered as a ~1.5:1 rectangle in a real browser (width
     tracked the max-width cap correctly; height did not follow from it) -
     a known trouble spot where aspect-ratio interacts unreliably with
     absolutely positioned elements across browsers. Setting both dimensions
     to the same literal value sidesteps that derivation entirely. */
  .header__dropdown-image-wrapper {
    --service-image-size: clamp(18rem, 25vw, 30rem);
  }

  .header__dropdown-image-wrapper .header__service-image-wrapper,
  .header__dropdown-image-wrapper .header__service-image {
    border-radius: 0.35rem;
    bottom: auto !important;
    height: var(--service-image-size) !important;
    left: auto !important;
    object-fit: cover;
    right: 0 !important;
    top: 0 !important;
    transform: none;
    width: var(--service-image-size) !important;
  }

  .header__dropdown-heading {
    font-size: clamp(2.45rem, 2.65vw, 3.65rem) !important;
    letter-spacing: -0.055em;
    line-height: 1.08;
    white-space: nowrap;
  }

  .header__dropdown-heading-wrapper,
  .header__dropdown-items,
  .header__dropdown-description-wrapper {
    min-width: 0;
  }

  .header__dropdown-items-list .button {
    max-width: 100%;
    white-space: nowrap;
  }

  .header__dropdown-main-data-text {
    overflow: hidden;
    text-overflow: ellipsis;
  }
}

@media screen and (min-width: 992px) and (max-width: 1279px) {
  .header__dropdown-layout {
    column-gap: 1rem !important;
    grid-template-columns: minmax(0, 40%) minmax(0, 27%) minmax(0, 33%) !important;
  }

  .header__dropdown-heading {
    font-size: clamp(1.85rem, 2.25vw, 2.25rem) !important;
    letter-spacing: -0.055em;
    line-height: 1.08;
  }

  .header__dropdown-items {
    padding-left: 0.75rem;
  }

  .header__dropdown-main-data {
    column-gap: 1.4rem;
    grid-template-columns: minmax(0, 45%) minmax(0, 55%);
    padding-left: 1rem;
  }

  .header__dropdown-description-wrapper > .text {
    font-size: 0.95rem;
    line-height: 1.35;
    margin-top: 1rem;
  }

  .header__dropdown-image-wrapper {
    --service-image-size: clamp(14rem, 25vw, 20rem);
  }

  /* right is tuned to match the top/bottom auto-margin gap (which comes
     from real box geometry, not a formula) rather than a generic fluid
     clamp - the panel's height is driven by text reflow, not a smooth
     function of viewport width, so a single vw-based value can't track it
     across the whole 992px+ range. Fitted linearly against the vertical
     gap measured at this band's own two edges (992px and 1279px). */
  .header__dropdown-image-wrapper {
    right: calc(211px - 12.5vw);
  }

  .header__dropdown-items-list {
    align-items: flex-start;
    display: flex;
    flex-direction: column;
    gap: 0.55rem;
  }

  .header__dropdown-items-list .button {
    max-width: 100%;
    white-space: nowrap;
  }

  .header__dropdown-main-data-text {
    font-size: 0.9rem;
  }
}

@media screen and (min-width: 1280px) and (max-width: 1439px) {
  .header__dropdown-layout {
    column-gap: 1.4rem !important;
    grid-template-columns: minmax(0, 40%) minmax(0, 25%) minmax(0, 35%) !important;
  }

  .header__dropdown-heading {
    font-size: clamp(2.1rem, 2.35vw, 2.9rem) !important;
  }

  .header__dropdown-image-wrapper {
    --service-image-size: clamp(16rem, 24vw, 24rem);
  }

  /* Same approach as the 992-1279px band, fitted against this band's own
     edges (1280px and 1439px). */
  .header__dropdown-image-wrapper {
    right: calc(217px - 11.67vw);
  }
}

@media screen and (min-width: 1440px) {
  .header__dropdown-main-data {
    align-content: start;
  }

  .header__dropdown-image-wrapper {
    --service-image-size: 24rem;
  }

  /* --service-image-size is fixed above (no longer scaling with vw at this
     band), but the panel keeps growing taller with viewport width here
     (more text-wrap headroom in the fixed-percentage columns), so the
     vertical gap still grows with width even though the image doesn't.
     Fitted against gaps measured at 1440px and 1920px; clamped so it
     doesn't run away on ultra-wide viewports beyond that. */
  .header__dropdown-image-wrapper {
    right: clamp(2.5rem, calc(6.08vw - 44.5px), 5rem);
  }
}

.categories__menu .heading-svgs {
  display: none !important;
}

.replica-service-label {
  display: block;
  height: 1.03em;
  left: 0;
  line-height: 1;
  pointer-events: none;
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: max-content;
  white-space: nowrap;
}

.replica-service-wordmark {
  display: block;
  height: 1.03em;
  overflow: visible;
}

.replica-service-wordmark path {
  fill: transparent;
  stroke: rgba(255, 255, 255, 0.9);
  stroke-width: 1;
  transition: fill 0.3s ease;
}

.categories__menu .heading-box {
  position: relative;
  width: 0;
}

.categories__menu-item.services-scroll-current .categories__item-body {
  overflow: visible;
}

.categories__menu-item.active:not(.services-scroll-current) {
  margin-bottom: 0;
}

.categories__menu-item:hover .replica-service-label,
.categories__menu-item.services-scroll-current .replica-service-label {
  color: #fff;
}

.categories__menu-item:hover .replica-service-wordmark path,
.categories__menu-item.services-scroll-current .replica-service-wordmark path {
  fill: #fff;
}

body.services-stage-active .header,
body.services-stage-active [data-role="header"] {
  background: transparent !important;
  backdrop-filter: none !important;
  box-shadow: none !important;
  color: #fff !important;
  left: 0 !important;
  mix-blend-mode: normal;
  opacity: 1 !important;
  position: fixed !important;
  right: 0 !important;
  top: 0 !important;
  transform: translate3d(0, 0, 0) !important;
  visibility: visible !important;
  z-index: 1000 !important;
}

body.services-stage-active .header .container,
body.services-stage-active .header__nav-wrapper,
body.services-stage-active .header__nav-inner,
body.services-stage-active .header__wrapper {
  background: transparent !important;
  opacity: 1 !important;
  transform: translate3d(0, 0, 0) !important;
  visibility: visible !important;
}

body.services-stage-active .header__item-link,
body.services-stage-active .header__dropdown-text,
body.services-stage-active .header__contacts-item-title,
body.services-stage-active .header__contacts-item-description,
body.services-stage-active .header__network-link,
body.services-stage-active .header__contact,
body.services-stage-active .header__part,
body.services-stage-active .header .text-sm {
  color: rgba(255, 255, 255, 0.92) !important;
}

body.services-stage-active .header .svg-flex svg,
body.services-stage-active .header .copy-email svg,
body.services-stage-active .header .header__network-icon svg {
  color: currentColor !important;
}

body.services-stage-active .header .button.header__button,
body.services-stage-active .header .button--white.header__button {
  background: var(--accent-test-color) !important;
  border-color: var(--accent-test-color) !important;
  color: #fff !important;
}

@media screen and (min-width: 768px) {

  /* The margin/width pair here used to be `calc(50% - 50vw)` / `100vw`,
     which suffers the same scrollbar mismatch documented on
     .home-portfolio-filter-grid above: 100vw counts the classic scrollbar,
     the 50% does not, so on a 1440px window with a 15px scrollbar this
     section rendered 1440px wide starting at -7.5px. Its parent (main.main)
     is already a full-width block at x=0 with no padding, so plain
     auto/100% margins give the identical full-bleed result with no
     overhang. */
  .secton.categories {
    margin-left: 0 !important;
    margin-right: 0 !important;
    min-height: min(330vh, 2600px);
    overflow: visible;
    position: relative;
    width: auto !important;
  }

  .secton.categories .categories__inner {
    align-items: center;
    display: flex;
    height: 100vh;
    margin-left: 0 !important;
    margin-right: 0 !important;
    min-height: 720px;
    max-width: none !important;
    padding-left: 0 !important;
    padding-right: 0 !important;
    position: sticky;
    top: 0;
    /* 100% of the (now correctly sized) .secton.categories, not 100vw -
       see the scrollbar note on that section above. */
    width: 100% !important;
    z-index: 2;
  }

  .secton.categories .categories__body {
    align-items: center;
    display: flex;
    min-height: 100vh;
    position: relative;
    width: 100%;
  }

  .secton.categories .categories__menu {
    left: clamp(19rem, 24.2vw, 32rem);
    margin-left: 0;
    max-width: min(34rem, 34vw);
    padding-top: 0;
    position: absolute;
    top: 50%;
    transform: translateY(-49%);
    z-index: 4;
  }

  .secton.categories .categories__header {
    margin-bottom: clamp(0.45rem, 1vh, 0.85rem);
    max-width: 33rem;
  }

  .secton.categories .categories__header-text {
    max-width: 31.5rem;
  }

  .secton.categories .categories__header-text h2,
  .secton.categories .categories__header-text p,
  .secton.categories .categories__header-wrapper,
  .secton.categories .categories__menu-number,
  .secton.categories .categories__item-content,
  .secton.categories .categories__item-links {
    color: #fff !important;
    text-shadow: 0 0.04em 0.8em rgba(0, 0, 0, 0.32);
  }

  .secton.categories .categories__header-text h2 {
    font-size: clamp(1rem, 1vw, 1.18rem);
    font-weight: 700;
    line-height: 1.08;
    margin-bottom: 0.45rem;
  }

  .secton.categories .categories__header-text p {
    font-size: clamp(0.95rem, 0.98vw, 1.08rem);
    line-height: 1.12;
  }

  .secton.categories .categories__header-wrapper {
    margin-top: clamp(0.85rem, 1.45vh, 1.15rem);
  }

  .secton.categories .categories__item-header.categories__item-header--sm {
    align-items: center;
    cursor: pointer;
    gap: clamp(0.8rem, 1vw, 1.05rem);
    min-height: clamp(2.35rem, 4.45vh, 3.25rem);
    padding: 0;
  }

  .secton.categories .categories__menu-item {
    opacity: 0.78;
    transform: translateY(0);
    transition:
      opacity 620ms cubic-bezier(0.22, 1, 0.36, 1),
      transform 620ms cubic-bezier(0.22, 1, 0.36, 1),
      margin 620ms cubic-bezier(0.22, 1, 0.36, 1);
  }

  .secton.categories .categories__menu-item.services-scroll-current {
    opacity: 1;
    transform: translateY(-0.15rem);
  }

  .secton.categories .categories__menu-item.services-scroll-current {
    margin-bottom: clamp(0.35rem, 0.9vh, 0.75rem);
  }

  .secton.categories .replica-service-label {
    font-size: clamp(2.65rem, 3.25vw, 4.15rem) !important;
  }

  .secton.categories .categories__item-body {
    display: none !important;
    height: auto !important;
    max-height: 0 !important;
    max-width: 31rem;
    opacity: 0 !important;
    overflow: hidden !important;
    pointer-events: none !important;
    transform: translate3d(0, 0.65rem, 0);
    transition:
      opacity 540ms cubic-bezier(0.22, 1, 0.36, 1),
      transform 640ms cubic-bezier(0.22, 1, 0.36, 1) !important;
    visibility: hidden !important;
  }

  .secton.categories .categories__menu-item.services-scroll-current .categories__item-body {
    display: block !important;
    max-height: 32rem !important;
    opacity: 0 !important;
    overflow: visible !important;
    pointer-events: auto !important;
    transform: translate3d(0, 0.65rem, 0);
    transition:
      opacity 620ms cubic-bezier(0.22, 1, 0.36, 1) 90ms,
      transform 720ms cubic-bezier(0.22, 1, 0.36, 1) 60ms !important;
    visibility: visible !important;
  }

  .secton.categories .categories__menu-item.services-scroll-current .categories__item-body.services-body-visible {
    opacity: 1 !important;
    transform: translate3d(0, 0, 0);
  }

  .secton.categories .categories__item-content.categories__item-content--sm {
    padding-bottom: clamp(0.55rem, 1vh, 0.85rem);
    padding-top: clamp(0.32rem, 0.7vh, 0.55rem);
  }

  .secton.categories .categories__item-content {
    font-size: clamp(0.92rem, 0.95vw, 1.08rem);
    line-height: 1.18;
  }

  .secton.categories .categories__item-links {
    align-items: center !important;
    display: flex !important;
    flex-wrap: wrap;
    gap: clamp(1.2rem, 1.75vw, 2rem);
    margin-top: clamp(1rem, 1.5vh, 1.45rem);
  }

  .secton.categories .categories__item-links a,
  .secton.categories .categories__item-links .services-inline-link {
    align-items: center !important;
    background: transparent !important;
    border: 0 !important;
    border-bottom: 1px solid rgba(255, 255, 255, 0.72) !important;
    border-radius: 0 !important;
    box-shadow: none !important;
    color: #fff !important;
    display: inline-flex !important;
    font-size: clamp(0.9rem, 0.82vw, 1rem) !important;
    font-weight: 700 !important;
    height: auto !important;
    justify-content: flex-start !important;
    line-height: 1.25 !important;
    min-height: 0 !important;
    min-width: 0 !important;
    opacity: 1 !important;
    padding: 0 0 0.18em !important;
    padding-left: 0 !important;
    padding-right: 0 !important;
    text-decoration: none !important;
    text-shadow: 0 0.04em 0.8em rgba(0, 0, 0, 0.36);
    transform: none !important;
    transition: border-color 180ms ease, opacity 180ms ease !important;
    visibility: visible !important;
    width: auto !important;
  }

  .secton.categories .categories__item-links a div,
  .secton.categories .categories__item-links .services-inline-link div {
    align-items: center;
    display: inline-flex;
    gap: 0.32em;
  }

  .secton.categories .categories__item-links a div::after,
  .secton.categories .categories__item-links .services-inline-link div::after {
    content: "→";
    display: inline-block;
    font-weight: 700;
    line-height: 1;
  }

  .secton.categories .categories__item-links a:hover,
  .secton.categories .categories__item-links .services-inline-link:hover {
    border-bottom-color: #fff !important;
    opacity: 0.82 !important;
  }

  .secton.categories .categories__bg-overlay,
  .secton.categories .categories__color-overlay {
    background: rgba(0, 0, 0, 0.52) !important;
  }

  .secton.categories .categories__bg-assets,
  .secton.categories .categories__item-asset,
  .secton.categories .categories__item-asset img,
  .secton.categories .categories__item-asset video {
    left: 0 !important;
    min-height: 100vh;
    right: 0 !important;
    /* Same scrollbar reason as the section itself - these fill the
       categories stage, which is now correctly clientWidth rather than
       100vw, so 100vw here would hang them off the right edge. */
    width: 100% !important;
  }

  .secton.categories .categories__item-asset {
    opacity: 0 !important;
    pointer-events: none !important;
    transition:
      opacity 980ms cubic-bezier(0.22, 1, 0.36, 1),
      visibility 0s linear 980ms !important;
    visibility: hidden !important;
  }

  .secton.categories .categories__item-asset.services-asset-current {
    opacity: 1 !important;
    transition:
      opacity 1120ms cubic-bezier(0.22, 1, 0.36, 1),
      visibility 0s linear 0s !important;
    visibility: visible !important;
  }

  .secton.categories .categories__item-asset.services-asset-leaving {
    pointer-events: none !important;
    visibility: visible !important;
  }

  .secton.categories .categories__item-asset.services-asset-leaving .categories__bg-asset-img:first-child,
  .secton.categories .categories__item-asset.services-asset-leaving .categories__bg-asset-mobile-img:first-child {
    opacity: 1 !important;
    visibility: visible !important;
  }

  .secton.categories .categories__item-asset:not(.services-asset-current) .categories__bg-asset-img,
  .secton.categories .categories__item-asset:not(.services-asset-current) .categories__bg-asset-mobile-img {
    visibility: visible !important;
  }

  .secton.categories .categories-circle,
  .secton.categories .categories-circle1 {
    display: none !important;
    opacity: 0 !important;
    visibility: hidden !important;
  }

  .secton.categories .replica-service-wordmark path {
    fill: transparent !important;
    stroke: rgba(255, 255, 255, 0.44) !important;
    stroke-width: 1 !important;
    transition:
      fill 620ms cubic-bezier(0.22, 1, 0.36, 1),
      stroke 620ms cubic-bezier(0.22, 1, 0.36, 1),
      opacity 620ms cubic-bezier(0.22, 1, 0.36, 1) !important;
  }

  .secton.categories .categories__menu-item:hover .replica-service-wordmark path,
  .secton.categories .categories__menu-item.services-scroll-current .replica-service-wordmark path {
    fill: #fff !important;
    stroke: #fff !important;
  }

  .secton.categories .categories__menu-item:not(.services-scroll-current):hover .replica-service-wordmark path {
    fill: transparent !important;
    stroke: rgba(255, 255, 255, 0.44) !important;
  }

  .secton.categories .categories__menu-item:not(.services-scroll-current) .replica-service-label,
  .secton.categories .categories__menu-item:not(.services-scroll-current):hover .replica-service-label {
    color: transparent !important;
  }

  .secton.categories .categories__menu-item:not(.services-scroll-current) .replica-service-wordmark path {
    fill: transparent !important;
    stroke: rgba(255, 255, 255, 0.44) !important;
  }

  @media screen and (max-width: 1180px) {
    .secton.categories .categories__menu {
      left: clamp(14rem, 22.5vw, 20rem);
      margin-left: 0;
    }
  }
}

@media screen and (max-width: 767px) {
  .categories__menu {
    padding-left: 0;
    padding-right: 0;
  }

  .categories__menu-item.services-scroll-current {
    margin-bottom: 0.25rem;
  }

  .categories__item-header.categories__item-header--sm {
    align-items: flex-start;
    gap: 1.05rem;
    justify-content: flex-start;
    padding-left: 1.5rem;
    padding-right: 1.5rem;
    width: 100%;
  }

  .categories__menu .heading-box {
    flex: 1 1 auto;
    min-width: 0;
    width: auto;
  }

  .replica-service-label {
    font-size: 36px !important;
    left: 0;
    max-width: none;
    overflow: visible;
    top: 50%;
  }

  .replica-service-wordmark {
    max-width: none;
  }

  .categories__item-body {
    padding-left: 1.5rem;
    padding-right: 1.5rem;
    width: 100% !important;
  }

  .categories__item-content.categories__item-content--sm {
    padding-bottom: 1.2rem;
    padding-top: 1rem;
    width: 100%;
  }

  .categories__item-links {
    gap: 1.5rem;
    width: 100%;
  }

  .cta {
    left: 1.5rem;
    right: auto;
  }

  [class^="b24-widget-button"],
  [class*=" b24-widget-button"] {
    display: none !important;
  }
}

/* Services dropdown: one reliable pink highlight layer.
   The original heading stays as the gray outline; this overlay is the only
   filled state, so hover/selected cannot stack or fall back to Webflow blue. */
.header__dropdown-content [data-role="accordion-item"] > [data-role="accordion-summary"] [data-role="category-heading"] {
  color: transparent !important;
  position: relative !important;
  -webkit-text-fill-color: transparent !important;
  -webkit-text-stroke: 1px rgba(9, 9, 9, 0.38) !important;
  text-stroke: 1px rgba(9, 9, 9, 0.38) !important;
}

/* The .brand-heading-fill span and the [data-role="category-heading"]::after clone
   were an abandoned crossfade overlay: nothing in the repo ever creates that span
   or the data-brand-label attribute it read, and brand-accent-guard.js actively
   strips both. Their definitions and opacity states are gone. This neutraliser
   stays deliberately — it is the only thing suppressing any ::after that the
   Webflow or CDN stylesheets might define on these headings. */
.header__dropdown-content [data-role="category-heading"]::after {
  content: none !important;
  display: none !important;
}

.header__dropdown-content [data-role="accordion-item"].brand-hover-service > [data-role="accordion-summary"] [data-role="category-heading"],
.header__dropdown-content [data-role="accordion-item"].brand-selected-service > [data-role="accordion-summary"] [data-role="category-heading"],
.header__dropdown-content [data-role="accordion-item"].js--active > [data-role="accordion-summary"] [data-role="category-heading"],
.header__dropdown-content [data-role="accordion-item"].active > [data-role="accordion-summary"] [data-role="category-heading"],
.header__dropdown-content [data-role="accordion-item"].is-active > [data-role="accordion-summary"] [data-role="category-heading"],
.header__dropdown-content [data-role="accordion-item"]:hover > [data-role="accordion-summary"] [data-role="category-heading"] {
  color: var(--accent-test-color, #DB4361) !important;
  -webkit-text-fill-color: var(--accent-test-color, #DB4361) !important;
  -webkit-text-stroke: 0 var(--accent-test-color, #DB4361) !important;
  text-stroke: 0 var(--accent-test-color, #DB4361) !important;
}

.header__dropdown-content:has([data-role="accordion-item"]:hover) [data-role="accordion-item"].brand-selected-service:not(:hover) > [data-role="accordion-summary"] [data-role="category-heading"],
.header__dropdown-content:has([data-role="accordion-item"]:hover) [data-role="accordion-item"]:not(:hover) > [data-role="accordion-summary"] [data-role="category-heading"] {
  color: transparent !important;
  -webkit-text-fill-color: transparent !important;
  -webkit-text-stroke: 1px rgba(9, 9, 9, 0.38) !important;
  text-stroke: 1px rgba(9, 9, 9, 0.38) !important;
}

/* Services dropdown: highlight the hovered/active service name.
   The five visible names are the TABS (.header__dropdown-tab, role="tab") in the
   left column — not the [data-role="accordion-item"] tabpanels that every rule
   above targets. Those panels are zero-height in the right column, which is why
   the earlier attempts never showed up on screen.

   The remote header component already moves .js--active / aria-selected onto the
   hovered tab and swaps the panel with it, so hover state and rest state both
   fall out of .js--active for free. Only the colour was missing: rule 207 forces
   every heading in the dropdown transparent and nothing ever repainted the tabs.

   This mirrors the source site's own intent (base = outline, active = solid fill,
   text-shadow off), substituting the brand accent for its --white.
   Only the two COLOURS change between states — the stroke stays 1px throughout
   and fades to transparent rather than collapsing to 0 width. Keeping every
   animated value a colour is what lets the two states crossfade smoothly; it
   also overrides the inherited `transition: color 180ms ease` from
   .header__dropdown-heading (line 204), which would otherwise snap the stroke
   while the fill was still fading. */
.header__dropdown-content .header__dropdown-tab [data-role="category-heading"] {
  color: transparent !important;
  -webkit-text-fill-color: transparent !important;
  -webkit-text-stroke-width: 1px !important;
  -webkit-text-stroke-color: rgba(9, 9, 9, 0.38) !important;
  transition: -webkit-text-fill-color 260ms cubic-bezier(0.4, 0, 0.2, 1),
              -webkit-text-stroke-color 260ms cubic-bezier(0.4, 0, 0.2, 1),
              color 260ms cubic-bezier(0.4, 0, 0.2, 1) !important;
}

.header__dropdown-content .header__dropdown-tab.js--active [data-role="category-heading"],
.header__dropdown-content .header__dropdown-tab[aria-selected="true"] [data-role="category-heading"],
.header__dropdown-content .header__dropdown-tab:hover [data-role="category-heading"] {
  color: var(--accent-test-color, #DB4361) !important;
  -webkit-text-fill-color: var(--accent-test-color, #DB4361) !important;
  -webkit-text-stroke-color: transparent !important;
  text-shadow: none !important;
}

/* Guarantees a single highlight: while any tab is hovered, the previously active
   one reverts even if the component has not yet moved .js--active. */
.header__dropdown-tabs:has(.header__dropdown-tab:hover) .header__dropdown-tab:not(:hover) [data-role="category-heading"] {
  color: transparent !important;
  -webkit-text-fill-color: transparent !important;
  -webkit-text-stroke-color: rgba(9, 9, 9, 0.38) !important;
}

@media (prefers-reduced-motion: reduce) {
  .header__dropdown-content .header__dropdown-tab [data-role="category-heading"] {
    transition: none !important;
  }
}

/* "Why Partner" section (homepage): the intro paragraph and the 6-box
   "ways" grid were placed in column 2 of a 2-column grid whose column 1
   is never used, leaving a ~500px dead gap on the left that the heading
   (which correctly spans both columns) doesn't have. Span them the same
   way the heading already does. */
#w-node-d0dc8924-2089-e2c6-aced-0b82591cd930-89c208f0,
#w-node-b88234fa-cee5-01d4-58e9-d203efcf00d6-89c208f0 {
  grid-column: 1 / -1 !important;
}

/* Each item's title already reserves a real, styled slot before it (a
   sized, block-level <p>) that ships empty in the capture - restoring it
   as a step number makes this read as the sequence it actually
   describes (inputs -> execution -> ... -> result) instead of six
   unordered feature cards. */
.partner-ways-item__title p.text-md:first-child {
  color: var(--accent-test-color, #DB4361) !important;
  -webkit-text-fill-color: var(--accent-test-color, #DB4361) !important;
  font-size: 1.5rem;
  font-weight: 600;
  letter-spacing: -0.02em;
  margin-bottom: 0.25rem;
}

/* Homepage section spacing: several fluid paddings (works section, the
   masonry-to-CTA gap, and the clients-quote section) were sized well past
   what a clean transition needs - roughly 135px, 80px/111px, and 108px
   at desktop widths - reading as dead space rather than pacing,
   especially since neighboring sections already touch with zero gap of
   their own. Scaled down while keeping them fluid so mobile doesn't lose
   breathing room. */
.section.works.overflow-hidden {
  padding-top: clamp(2.5rem, 1.5rem + 4vw, 4.5rem) !important;
  padding-bottom: clamp(2.5rem, 1.5rem + 4vw, 4.5rem) !important;
}

.section.works.overflow-hidden > .section.articles-body.cases-body {
  padding-bottom: clamp(1.5rem, 1rem + 2vw, 3rem) !important;
}

.section.clients.section--clients-pt-md {
  padding-top: clamp(2rem, 1rem + 3vw, 4rem) !important;
}

/* Partner-logo spacing follows viewport width, not viewport height. Flex
   wrapping keeps every full row on the established column rhythm while
   justify-content centers any partially filled final row automatically. */
.clients__grid-list {
  --clients-logo-padding: clamp(12px, 1.25vw, 26px);
  display: flex !important;
  flex-wrap: wrap !important;
  justify-content: center !important;
  column-gap: 0 !important;
  row-gap: clamp(20px, 1.75vw, 34px) !important;
  align-items: center !important;
}

.clients__grid-item {
  flex: 0 0 12.5% !important;
  box-sizing: border-box !important;
  padding-right: var(--clients-logo-padding) !important;
  padding-left: var(--clients-logo-padding) !important;
  min-width: 0 !important;
  height: auto !important;
}

.clients__grid-item-link {
  display: flex !important;
  align-items: center !important;
  justify-content: center !important;
  width: 100% !important;
  height: auto !important;
  aspect-ratio: 164 / 84 !important;
}

.clients__grid-item-image {
  display: block !important;
  width: 100% !important;
  max-width: 164px !important;
  height: auto !important;
  max-height: 84px !important;
  object-fit: contain !important;
}

@media (max-width: 1199.98px) {
  .clients__grid-list {
    --clients-logo-padding: clamp(11px, 1.5vw, 18px);
    row-gap: clamp(20px, 2.5vw, 30px) !important;
  }

  .clients__grid-item {
    flex-basis: 16.6666% !important;
  }
}

@media (max-width: 899.98px) {
  .clients__grid-item {
    flex-basis: 25% !important;
  }
}

@media (max-width: 599.98px) {
  .clients__grid-list {
    --clients-logo-padding: clamp(7px, 2vw, 11px);
    row-gap: clamp(18px, 5vw, 26px) !important;
  }

  .clients__grid-item {
    flex-basis: 33.333333% !important;
  }
}

@media (max-width: 379.98px) {
  .clients__grid-item {
    flex-basis: 50% !important;
  }
}

/* Fourth oversized gap in the same family: works-section's own bottom
   padding (above) plus this section's ~174px top padding stacked into
   ~250px of dead space between the "Check our portfolio" CTA and the
   "Why Partner" heading below it. */
.section.section--partner.section--bg-dark {
  padding-top: clamp(3rem, 2rem + 3vw, 5rem) !important;
  /* padding-bottom wasn't part of the earlier top-padding fix and is
     still the remote stylesheet's original ~103px - trimmed to match
     the same scale as the top padding now gets. */
  padding-bottom: clamp(2.5rem, 1.5rem + 3vw, 4.5rem) !important;
}

/* Two content-block gaps inside this section (heading-to-intro,
   intro-to-grid) measured 60px and 72px respectively at 1280px width -
   on top of the section's own padding and the heading fix above, still
   part of why the whole block read as oversized. Tightened to a single
   consistent, more proportionate rhythm. */
.partner__content.rendering__content--mb-sm,
.partner__content.rendering__content--mb-md {
  margin-bottom: clamp(1.5rem, 1rem + 1.5vw, 2.5rem) !important;
}

/* "Why Partner with Our 3D Architectural Visualization Studio" (59
   characters) uses the same sitewide heading--xxl scale as every other
   section title (clamp up to 5.625rem/90px) - fine for short titles
   like "Selected Works", but a sentence this long at that size always
   wraps to 2-3 lines regardless of container width (confirmed: still
   wraps at 1825px container width on a 1920px screen, so it's the
   font-size causing the wrap, not available space) - a single heading
   eating 208-270px of vertical space is the single largest contributor
   to this section measuring taller than the viewport itself at every
   width tested (1076px tall at 1280x800, 1112px at 1920x1080). Scoped
   to .heading--partner specifically (a dedicated class already unique
   to this one heading) rather than heading--xxl sitewide, since other
   section titles using that shared scale are short enough not to have
   this problem - shrinking the scale for all of them would be an
   unrelated, unrequested change.
   Needs the full .heading.heading--xxl.heading--partner combination
   (three classes) to actually win: an earlier fix in this file already
   reasserts .heading.heading--xxl (two classes) at !important for the
   sitewide 1440px-shrink bug, which otherwise beats a plain
   .heading--partner selector on specificity alone despite this rule
   being later in the file - same cascade trap as the categories
   heading earlier this session. */
.heading.heading--xxl.heading--partner {
  font-size: clamp(2rem, 1.5rem + 1.8vw, 3.375rem) !important;
}

/* Same class of bug, different section: "Our team is dedicated to
   building strong, long-lasting relationships with our partners." (88
   characters, the longest heading on the page) wraps to 5 lines at
   69px font - 347px of vertical space for one sentence, the single
   biggest contributor after the 63-logo grid below it to this section
   measuring ~1980px tall at 1280x800. Same fix, same reasoning: shrink
   this one heading's scale instead of heading--xxl sitewide. */
.heading.heading--xxl.heading--short-width {
  font-size: clamp(1.75rem, 1.25rem + 1.8vw, 3rem) !important;
}

/* Laptop-tier fixes (MacBook Air 13" range, ~992-1439px). The remote
   stylesheet has no distinct tier for this range: most rules either use
   a single unconditional clamp() tuned against a ~1920px canvas (already
   80-95% scaled up by 1280px) or jump straight from a ≤991px "tablet"
   rule to a ≥1440px "desktop" rule, so 992-1439px silently inherits
   whichever end is closer. Verified each override live at 992/1280/1440
   before adding. */

/* Keep the six-step "Why Partner" module compact on laptop displays.
   Three columns avoid a third card row, while the reduced type, padding,
   and gaps prevent narrower cards from turning the section into a tall
   stack. Large desktop sizing remains unchanged from 1600px upward. */
@media (min-width: 1100px) and (max-width: 1599px) {
  .section.section--partner.section--bg-dark {
    padding-top: 2.75rem !important;
    padding-bottom: 2.75rem !important;
  }

  .heading.heading--xxl.heading--partner {
    font-size: clamp(2.25rem, 1.5rem + 1vw, 2.5rem) !important;
  }

  .partner__content.rendering__content--mb-sm,
  .partner__content.rendering__content--mb-md {
    margin-bottom: 1.25rem !important;
  }

  .partner__content .text-md--max45ch {
    max-width: 52ch !important;
    font-size: 0.9375rem !important;
    line-height: 1.35em !important;
  }

  .partner-ways-list {
    grid-template-columns: repeat(3, minmax(0, 1fr)) !important;
    column-gap: 0.75rem !important;
    row-gap: 0.75rem !important;
  }

  .partner-ways-item {
    gap: 0.75rem !important;
    justify-content: flex-start !important;
    padding: 0.875rem !important;
  }

  .partner-ways-item__title p.text-md:first-child {
    margin-bottom: 0.125rem !important;
    font-size: 1.125rem !important;
  }

  .partner-ways-item .text-new-lg {
    font-size: 1.25rem !important;
  }

  .partner-ways-item > .text-md.color-text-gray {
    font-size: 0.9375rem !important;
    line-height: 1.35em !important;
  }
}

/* Footer: .footer__wrapper only switches from a stacked column (logo
   above the nav grid) to a side-by-side row at min-width:1440px, so the
   MacBook Air's default 1280px viewport gets a footer taller than its
   own viewport (858px measured vs an 832px screen). Row layout fits
   fine as low as 992px once the link-grid's minmax(min-content,1fr)
   columns are allowed to actually shrink (they don't by default - the
   min-content floor makes the grid overflow past the viewport edge
   instead of narrowing, silently clipped by an ancestor's overflow:
   hidden) and the logo block's width is capped to leave room for them. */
@media (min-width: 992px) and (max-width: 1439px) {
  .footer__wrapper {
    flex-direction: row !important;
    align-items: flex-start !important;
    justify-content: space-between !important;
    gap: 2.5rem !important;
  }

  .footer__brand {
    flex: 0 0 auto !important;
    max-width: 320px !important;
  }

  .footer__link-grid {
    grid-template-columns: repeat(3, minmax(0, auto)) !important;
    column-gap: 2.5rem !important;
  }
}

/* Sitewide "shrinks at 1440px" bugs: each of these properties has an
   unconditional base clamp() (or fixed value) that grows correctly up
   through 1439px, then a @media(min-width:1440px) rule in the remote
   stylesheet that computes a SMALLER value - a specificity tie decided
   by source order (headings), or a plain wrong clamp/value on the
   1440px-only rule (everything else) - so text and spacing visibly
   shrink the instant the viewport crosses 1440px, which is exactly
   backwards. Confirmed live: every one of these converges to the exact
   value the site already shows at 1920px+ once the base rule is left to
   keep running past 1440px uninterrupted, so reasserting the base
   formula here changes nothing above ~1920px. */
@media (min-width: 1440px) {
  .heading.heading--xxl,
  .text-xxl.text-center.works__text-xxl {
    font-size: clamp(2.5rem, 1.742rem + 3.24vw, 5.625rem) !important;
  }

  .text-xl.text-xl--bold {
    font-size: 2.75rem !important;
  }

  .text-sm {
    font-size: clamp(0.875rem, 0.845rem + 0.13vw, 1rem) !important;
  }

  .link-md {
    font-size: clamp(1.5rem, 1.379rem + 0.52vw, 2rem) !important;
  }

  .header {
    padding-block: clamp(1.563rem, 1.244rem + 1.36vw, 2.875rem) !important;
  }

  .button {
    padding: 1rem 1.5rem !important;
  }

  .big-text-paragraph {
    font-size: clamp(2.5rem, 1.779rem + 3.21vw, 5.625rem) !important;
  }
}

/* .section.big-text's own padding is part of the general "tuned for a
   ~1920px canvas" pattern, same family as the works/partner/clients
   padding fixes above: the unconditional base clamp alone already
   reaches ~188px/side by 1280px - 39.5% of the section's total height
   for a single paragraph - and keeps growing past 1440px too. Applied
   unconditionally like those three fixes (no mobile-specific rule exists
   for this selector to preserve, confirmed via styleSheets scan). */
.section.big-text {
  padding-block: clamp(2.5rem, 1.5rem + 4vw, 5rem) !important;
}

/* Header logo's left margin: .container's gutter is a two-part system
   that isn't actually consistent - a padding-inline clamp() that maxes
   out around 40px by ~1920px, PLUS an unrelated side effect where the
   container's own max-width is capped at 120rem (1920px), so on any
   monitor wider than that the leftover space becomes a big automatic
   centering margin instead of real padding. That's why the logo sits
   with a lot of breathing room on an ultra-wide screen but only ~30px
   on a laptop - the gap isn't a deliberate scaling value, it's an
   accident of where the centering kicks in. Giving the header's own
   container a fixed gutter makes the logo's distance from the edge the
   same at every width from tablet up, rather than shrinking on
   laptops and jumping on ultra-wide monitors. Scoped to the header only
   for now - the same fix is applied to the hero's container below with
   the same value, since it showed the identical symptom (30px on a
   laptop, ballooning to 353px on a 2560px-wide monitor) for the same
   reason - using the same gutter keeps the logo/wordmark aligned to
   the same left edge at the top of the page. */
@media (min-width: 768px) {
  .header .container,
  .hero .container {
    max-width: 100% !important;
    padding-left: 4rem !important;
    padding-right: 4rem !important;
  }
}

/* Pinned services showcase ("categories" section): the intro text block
   plus 5 menu items - one of them expanded with a full paragraph and
   links when active - adds up to as much as 864px tall (confirmed with
   the "Exterior Render" item active, the longest one), which comfortably
   fits a 1080px-tall desktop monitor but overflows a MacBook Air's
   832px viewport by ~32px on both edges at once, since the section is
   scroll-pinned to exactly the viewport height. This is a viewport
   HEIGHT problem, not a width one - confirmed fine on a 1920x1080
   monitor - so it's scoped by max-height rather than max-width, leaving
   every wide/tall desktop display untouched. Trimming just the gap
   between items already recovers 60px, more than the deficit.
   min-width:768px matches services-scroll-experiment.js's own
   DESKTOP_QUERY - below that width items never expand/collapse at all
   (a different, simpler mobile layout), so this would otherwise clash
   with mobile's already-tuned gap for no reason. */
/* The real fixed header (measured 123-146px tall across 768-2560px
   viewport widths, z-index:1000) sits on top of everything, but this
   section's sticky-pinned content starts flush at the very top of the
   viewport with zero awareness of it - its own heading ("Professional
   3D Architectural Rendering Services...") renders literally inside the
   header's own band, reading as overlapping/broken text at any screen
   size, not just short ones.
   Originally used var(--header-height), a live custom property the
   site's own remote script sets - but found it can drift out of sync
   with the header's real current height (confirmed: at one viewport it
   resolved 20px short of the header's actual measured height, which is
   exactly the overlap this rule exists to prevent). Since this
   calculation is load-bearing for "content must never overlap the
   header," it shouldn't depend on a third-party value that isn't
   guaranteed fresh. 10rem (160px) is comfortably above the tallest
   measured header across every width that matters here, so it always
   clears with room to spare instead of being exactly right sometimes.
   padding-top alone doesn't work here: .categories__body is
   min-height:100vh with justify-content:center, so it vertically
   centers its content within the FULL viewport height regardless of
   padding - when content is taller than the centered box, it overflows
   symmetrically past the padding on both sides instead of respecting
   it. Shrinking the box itself (100vh minus the header) and shifting it
   down by the same amount makes the centering happen within the
   correct, already-header-excluded space instead. Scoped to
   .categories__body specifically, not .categories__inner, since the
   latter also wraps the full-bleed background photo layers, which must
   stay flush to the true top. */
@media (min-width: 768px) {
  .categories__body {
    min-height: calc(100vh - 10rem) !important;
    height: calc(100vh - 10rem) !important;
    margin-top: 10rem !important;
  }
}

/* The menu column's own width (min(34rem, 34vw), narrower still below
   1180px - only 435px at a 1280px viewport) is what forces every
   item's paragraph onto more lines than it needs. It's position:
   absolute with width:auto, so it shrink-to-fits around its widest
   child instead of actually using the space max-width allows - one of
   the ghost-list SVG wordmark labels (e.g. "LiDAR Virtual Tour") turns
   out to be that widest child, silently capping the real-world width at
   ~500px even when max-width alone is set much higher. Explicit width
   (not just max-width) is required to escape that and actually reach
   the requested value.
   A second, independent cap sits one level deeper: .categories__item-body
   (the wrapper around the active item's description/links) has its own
   max-width (~496px) from the remote stylesheet, so widening
   .categories__menu alone was silently capped again right below it -
   confirmed by measurement: the description's rendered width never
   moved past ~520px no matter how wide .categories__menu was set.
   Originally split by width tier (560px desktop / 820px laptop) on the
   theory that desktop shouldn't change - but desktop was still cutting
   text off mid-sentence with the "View services" link pushed out
   entirely, which reads as broken regardless of screen size. Widened
   universally instead: 820px brings the longest descriptions from 11
   natural lines down to 8 (see the clamp rule below, which now shows
   that full 8 lines on desktop instead of cutting at 5). */
/* .categories__menu's own left offset (the remote stylesheet's
   left:clamp(19rem, 24.2vw, 32rem)) stays clamped at its 304px floor
   for every width up to ~1260px - so a flat 900px column genuinely
   doesn't fit in the 768-1024px tablet band (confirmed: real,
   reproducible horizontal overflow at 992px, menu right edge landing
   125px past the viewport). min() against a viewport-relative formula
   instead of a flat px value: caps at 900px once there's room (matches
   every width this was tested at, 1280px and up, exactly as before),
   but automatically narrows below that so it's mathematically
   guaranteed to fit at any width, continuously - no separate tablet
   tier to get wrong the way every earlier threshold in this file did. */
@media (min-width: 768px) {
  .categories__menu {
    width: min(900px, calc(100vw - 21rem)) !important;
    max-width: min(900px, calc(100vw - 21rem)) !important;
  }

  .categories__item-body {
    width: min(900px, calc(100vw - 21rem)) !important;
    max-width: min(900px, calc(100vw - 21rem)) !important;
  }
}

@media (min-width: 768px) {
  /* Previously gated to max-height:900px on the theory that taller
     viewports always have "enough room" for this not to matter. Wrong -
     a real MacBook Air running Chrome at a scaled resolution (e.g.
     1512x982 or 1680x1050 under "More Space") reports an innerHeight
     well above 900px while still being a real, constrained laptop
     screen, so this entire block silently never applied and the module
     reverted to centered/unclamped behavior every time - which is
     exactly what overlapped the header and ran the active item's full,
     unclamped paragraph off the bottom of the screen. There is no
     viewport-height threshold that reliably separates "safe" from
     "not safe" here, so this now applies unconditionally at every
     desktop width, matching the actual requirement: fits one screen,
     structurally guaranteed, on any device. */
  .categories__menu {
    gap: 0.5rem !important;
    /* Hard safety net on top of every spacing/clamp trim below: no
       matter how the exact numbers work out on a given device (font
       rendering, real browser-chrome height, anything not accounted
       for), the module can never grow taller than the header-excluded
       viewport height and physically cannot overflow past the header or
       off the bottom of the screen. This is the real design requirement
       - "every service fits on one screen" - guaranteed structurally,
       not just by getting every measurement exactly right.
       Was max-height:100% (relative to .categories__body's own
       calc(100vh - 10rem) height) until testing an aggressively short
       viewport (1280x650) turned up a real, reproducible case where
       .categories__body's OWN computed height didn't match its own
       height:calc(100vh - 10rem) formula - it measured 560px, 70px
       taller than the 490px every direct probe of the formula agreed
       on, for reasons that didn't resolve to any single competing CSS
       rule in the cascade. Since max-height:100% inherits whatever the
       parent's height actually resolves to, that discrepancy leaked
       straight through into a real overflow. Pointing max-height at the
       same calc(100vh - 10rem) formula directly - not at the parent's
       reported height - makes the safety net self-sufficient: it no
       longer matters whether .categories__body's own height computes
       correctly, only that the formula itself is right, which is
       directly verifiable and was. */
    max-height: calc(100vh - 10rem) !important;
    overflow-y: hidden !important;
    /* Setting overflow-y without overflow-x has a CSS spec quirk: the
       unset axis (overflow-x, default "visible") gets force-computed to
       "auto" instead, so it silently becomes independently scrollable.
       One of the faded inactive "ghost" list items is 571px wide against
       this box's 560px desktop width - an 11px overflow that's
       invisible on its own (it's just a translucent background label)
       but was enough to spawn a real horizontal scrollbar, styled in
       the site's own accent color. Only showed at the narrower 560px
       desktop tier, never at the wider 820px laptop tier, which is why
       it read as "desktop only" and easy to miss until a full,
       uncropped screenshot caught it. overflow-x:hidden closes the
       same gap overflow-y already covers - the stray 11px just clips
       invisibly now, same as any other overflow this safety net
       absorbs. */
    overflow-x: hidden !important;
  }

  .categories__header {
    gap: 0.375rem !important;
  }

  .categories__menu-item.active .categories__item-body {
    gap: 0.625rem !important;
  }

  /* Even with every spacing trim above, the active item's own
     description paragraph (naturally ~5-8 lines at the 820px width
     above) is still the single largest remaining block. Split by tier
     below instead of one universal number: the laptop tier is measured
     right against its margin (0px to spare at 1280x800 with a 6th
     line), so it stays clamped to the 5 lines already confirmed safe
     there; the desktop tier has enough spare margin (200px+) to just
     show all 8 lines every description actually needs - full text, no
     cut, nothing left clamped. */
  .categories__menu-item.active .categories__item-content--sm {
    display: -webkit-box !important;
    -webkit-box-orient: vertical !important;
    overflow: hidden !important;
  }
}

/* .categories__menu is position:absolute with its own
   top:50%/transform:translateY(-49%) centering from the remote
   stylesheet (not a flex child, so .categories__body's justify-content
   never applies to it). That centering is only risky on the laptop
   tier, where margins run as tight as 8px with the worst-case item
   active - content taller than the box would overflow symmetrically
   there, pushing back up behind the header. Pinning to top:0 (grow only
   downward, never back up) is scoped to that tier alone. Desktop has
   200px+ of margin at every width and item tested, so centering there
   is provably safe and was the original, correct-looking design - "up
   near the header with a dead zone below" was this fix overcorrecting
   a laptop-only risk onto screens that never had it. */
/* Every fixed-threshold approach tried this session (max-height:900px
   tier, min-width:1920px tier) broke the same way: some real device
   landed on the wrong side of the guessed boundary, because CSS has no
   way to see physical screen size - only viewport pixels, which a
   laptop and a desktop monitor can both report in overlapping ranges
   depending on display scaling. No threshold was ever going to hold up
   against every device.
   Dropping threshold-guessing entirely. Every size that drives this
   module's total height - each of the 5 numbered rows, the heading
   font-size, the description font-size, the number label font-size,
   the gaps between items - is now a pure vh (percent of viewport
   height) value instead of a fixed px one. That makes the module's
   total height an approximately constant PROPORTION of the available
   viewport height by construction, on every device, with no per-device
   branching required: a short viewport gets smaller text and shorter
   rows (same safe proportion as always); a tall viewport gets bigger
   text and taller rows (filling the screen instead of leaving dead
   space below a fixed-size block that stopped growing). This is what
   "one screen module, responsive, on any screen" requires structurally
   - content sized as a fraction of the screen, not a fixed pixel size
   competing against a screen dimension CSS can't reliably detect.
   The row height's vh rate (6.5vh) is deliberately set above the
   heading font-size's own rate (4.6vh): the visible glyph is an SVG
   sized off an inherited em from that font-size (roughly 1.03x it, see
   the earlier note on .replica-service-label below), so the row needs
   to grow faster than the glyph or adjacent items start overlapping
   again, exactly as measured earlier this session when font-size alone
   was scaled without also scaling its row.
   Pinned to top:0 rather than centered while the fill ratio was
   unpredictable - the whole point of the shift below is that it no
   longer is. .categories__menu can now never render taller than
   .categories__body's own height (the max-height:calc(100vh - 10rem)
   safety net a few rules down), so centering a box that's guaranteed
   to fit inside its container can only ever distribute slack evenly
   above and below - it can't push the top above the header the way
   centering an unbounded box could. Top-pinning at high fill ratios
   (the common case, ~85-90%) barely differs from centering, but at
   the low end of the fill range (tall/short-aspect viewports, ~70%)
   top-pinning left a large, obviously unintentional-looking gap only
   at the bottom - reads as "stuck to the top" instead of sitting in
   the module's own space the way the design intends.
   top:50% very nearly reintroduced the exact overflow this whole
   safety net exists to prevent: at 1280x650 it rendered 110px past the
   bottom of the viewport. top:50% resolves against the CONTAINING
   BLOCK's height - .categories__body's own reported height, the same
   value already proven unreliable at short viewports (measured 560px
   against a formula every direct probe agreed should be 490px). The
   max-height fix above sidesteps that by computing directly off
   100vh instead of trusting the parent's height; centering needs the
   same treatment. .categories__body's top edge is reliably at 10rem
   from the viewport top (margin-top read correctly every time this was
   checked, only height didn't) and its bottom edge is always exactly
   the viewport bottom by construction (10rem margin + (100vh - 10rem)
   height = 100vh) - so the true vertical center of the available space,
   in viewport coordinates, is (10rem + 100vh) / 2. Converting to
   .categories__menu's own containing-block-relative `top` (subtract
   .categories__body's top offset, 10rem) gives 50vh - 5rem. The
   translateY(-50%) half is untouched - that percentage resolves
   against the element's OWN height, a different and reliably-correct
   calculation, not the parent's. */
@media (min-width: 768px) {
  .categories__menu {
    top: calc(50vh - 5rem) !important;
    transform: translateY(-50%) !important;
    gap: clamp(4px, 0.7vh, 14px) !important;
  }

  .categories__header {
    gap: clamp(3px, 0.5vh, 10px) !important;
  }

  .categories__menu-item.active .categories__item-body {
    gap: clamp(5px, 0.9vh, 16px) !important;
  }

  .categories__menu .categories__item-header {
    height: clamp(38px, 6.5vh, 100px) !important;
    min-height: clamp(38px, 6.5vh, 100px) !important;
  }

  .categories__menu .heading.heading--xxl.replica-service-label {
    font-size: clamp(24px, 4.6vh, 100px) !important;
  }

  .categories__menu .categories__item-content--sm {
    font-size: clamp(11px, 1.6vh, 26px) !important;
  }

  .categories__menu .categories__menu-number .text-sm {
    font-size: clamp(11px, 1.7vh, 24px) !important;
  }

  .categories__menu-item.active .categories__item-content--sm {
    -webkit-line-clamp: 5 !important;
  }
}

/* /services' category-tabs hero (.services-hero, data-component-id
   "services-hero") is unconditionally min-height:100vh with its content
   flex-centered - a deliberate full-screen effect at desktop, where the
   tabs + description + preview image lay out side-by-side and genuinely
   fill most of the screen (confirmed: only ~130-170px of slack out of
   ~800px at 1280px+, normal breathing room). Below the point where that
   layout switches to stacked (matches this file's existing 991px tablet
   tier), the same content collapses to a short list of 5 tab labels -
   but the box stays locked to full viewport height regardless, so the
   short stack ends up centered in the middle of a mostly-empty screen
   (confirmed: ~46% dead space at 390px, ~44% at 768px). Dropping the
   forced height below 992px lets the section size to its own content
   plus its existing padding instead. */
@media (max-width: 991px) {
  .services-hero {
    min-height: 0 !important;
  }
}

/* The two big faint arcs behind the bottom of the homepage are decoration -
   .reviews-circles holds nothing but .reviews-circle1 and .reviews-circle2
   (verified: zero links, buttons, inputs or text inside). They are
   absolutely positioned and ~1120px tall, so they hang well past their
   wrapper and land on top of whatever follows.

   Until the "Our process" section was removed they overlapped that section,
   which had nothing clickable in the overlap, so nobody noticed. With it
   gone the FAQ moved up underneath them and the arcs began swallowing the
   clicks on its first two questions - the third and below sat past the
   arcs' bottom edge and kept working, which is exactly the pattern that got
   reported. Confirmed with elementFromPoint: at the first two headings the
   topmost element was DIV.reviews-circle2, not the accordion.

   Decoration should never be a click target, so it opts out of hit-testing
   entirely rather than being nudged around with z-index - the arcs are
   meant to sit behind content at every viewport, and pointer-events is the
   property that actually says that. */
.reviews-circles,
.reviews-circles * {
  pointer-events: none;
}

/* The FAQ is the next block after the client-logo grid, and that grid is the
   last in-flow child of .circle-wrapper, so the two ended up flush against
   each other with no separation at all (measured: 0px between the logo
   section's bottom edge and the FAQ's top). Give the FAQ its own top spacing
   on the pages where it follows that grid.

   Scoped via .circle-wrapper, which exists only on the two homepages, so the
   FAQ on service pages - where it already has the spacing its own template
   gives it - is untouched. Uses the same clamp shape as the other
   section-rhythm rules in this file rather than a fixed pixel value. */
.circle-wrapper ~ [data-component-id="article-faq"],
.circle-wrapper + * + [data-component-id="article-faq"] {
  padding-top: clamp(2.5rem, 1.5rem + 4vw, 4.5rem);
}

/* Third and last instance of the 100vw-vs-scrollbar bug (see the notes on
   .home-portfolio-filter-grid and .secton.categories above). The hero
   video is sized `width: 100vw; max-width: 100vw` in two places - the
   Webflow stylesheet, and again in the per-page inline <style> block - so
   on a 1440px window with a 15px scrollbar it painted 1440px inside a
   1425px section, pushing 15px under the scrollbar and off the right edge.

   Its parent (section.section.hero) is already a full-width block at x=0
   with no padding, so 100% is exactly equivalent minus the error.

   Overridden here rather than edited in place because the inline copy is
   baked into all 310 pages; one rule in the override layer beats
   rewriting a <style> block per page. !important is required to outrank
   the inline block regardless of source order - that block is not itself
   !important, so this wins cleanly without an escalation war. */
.section.hero .hero__video {
  max-width: 100% !important;
  width: 100% !important;
}
/* Portfolio cards: load and play the supplied preview only on interaction. */
[data-portfolio-hover-video] {
  position: relative;
  overflow: hidden;
}

[data-portfolio-hover-video] .gallery-item__image-wrapper {
  position: relative;
  overflow: hidden;
}

.portfolio-hover-video {
  position: absolute;
  inset: 0;
  z-index: 1;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  pointer-events: none;
  transition: opacity 220ms ease;
}

[data-portfolio-hover-video].is-video-playing .portfolio-hover-video {
  opacity: 1;
}

[data-portfolio-hover-video] .works__item-link-wrapper,
[data-portfolio-hover-video] .gallery-item__link,
[data-portfolio-hover-video] .works__item-info-wrapper,
[data-portfolio-hover-video] .gallery-item__info {
  z-index: 2;
}

@media (prefers-reduced-motion: reduce), (hover: none) {
  .portfolio-hover-video {
    display: none;
  }
}

/* The main Cases page uses the same free-flowing masonry rhythm as the
   homepage portfolio. CSS columns let differently proportioned covers pack
   naturally instead of forcing every three cards into a rigid shared row. */
main[data-component-id="works-cases"]:not([data-cases="inner"]) .works-masonry-grid {
  column-count: 3;
  column-gap: 0;
  display: block !important;
  /* Ignore the legacy Masonry script’s fixed container height. */
  height: auto !important;
}

main[data-component-id="works-cases"]:not([data-cases="inner"]) .works__item--masonry-item--new {
  break-inside: avoid;
  /* Legacy Masonry also writes top/left offsets on load and resize. */
  inset: auto !important;
  display: inline-block !important;
  height: auto !important;
  margin: 0 !important;
  position: relative !important;
  transform: none !important;
  vertical-align: top;
  width: 100% !important;
}

main[data-component-id="works-cases"]:not([data-cases="inner"]) .works__item--masonry-item--new[hidden] {
  display: none !important;
}

main[data-component-id="works-cases"]:not([data-cases="inner"]) .works__item-image {
  display: block;
  height: auto !important;
  position: relative !important;
  width: 100% !important;
}

/* Keep the Cases filters in one shared flex flow. "All" is a sibling of
   the CMS-backed <nav>, so the original nested flex layout treated it as a
   separate column and dropped it onto a row by itself. Flattening the two
   structural wrappers makes all six pills wrap and align as one group. */
main[data-component-id="works-cases"]:not([data-cases="inner"]) .navigation-wrapper--cases {
  align-content: flex-end;
  align-items: center;
  display: flex !important;
  flex-wrap: wrap !important;
  gap: 0.625rem;
  justify-content: flex-end;
}

main[data-component-id="works-cases"]:not([data-cases="inner"]) .navigation-wrapper--cases > .navigation--cases,
main[data-component-id="works-cases"]:not([data-cases="inner"]) .navigation-wrapper--cases .navigation-tags--cases {
  display: contents !important;
}

main[data-component-id="works-cases"]:not([data-cases="inner"]) .navigation-wrapper--cases .navigation-tag-wrapper {
  flex: 0 0 auto;
  margin: 0 !important;
}

@media (max-width: 991px) {
  main[data-component-id="works-cases"]:not([data-cases="inner"]) .works-masonry-grid {
    column-count: 2;
  }
}

@media (max-width: 767px) {
  main[data-component-id="works-cases"]:not([data-cases="inner"]) .works-masonry-grid {
    column-count: 1;
  }
}

/* Mobile UI polish shared by the public pages. Keep this layer deliberately
   small: it improves touch sizing and narrow-screen rhythm without changing
   the desktop compositions or the content hierarchy. */
@media (max-width: 991px) {
  /* The compact navigation remains active through the tablet breakpoint. */
  .header__burger {
    background-color: var(--accent-test-color, #DB4361) !important;
  }
}

@media (max-width: 767px) {
  /* Long service labels were clipping against the right edge at 375px. */
  .replica-service-label,
  .categories__menu .heading.heading--xxl.replica-service-label {
    font-size: clamp(1.75rem, 8vw, 2rem) !important;
    line-height: 1.02 !important;
  }

  .categories__item-header.categories__item-header--sm,
  .categories__item-body {
    padding-left: 1rem;
    padding-right: 1rem;
  }

  .categories__item-links {
    flex-wrap: wrap;
    gap: 0.75rem 1.25rem;
  }

  .categories__item-links .services-inline-link {
    align-items: center;
    display: inline-flex;
    min-height: 2.75rem;
  }

  /* Filters remain compact, but every pill now meets a comfortable tap size. */
  .home-portfolio-filter__button,
  main[data-component-id="works-cases"]:not([data-cases="inner"]) .navigation-tag {
    align-items: center;
    display: inline-flex;
    justify-content: center;
    min-height: 2.75rem;
  }

  main[data-component-id="works-cases"]:not([data-cases="inner"]) .navigation-wrapper--cases {
    gap: 0.5rem;
    justify-content: center;
  }

  /* Slightly tighter process cards preserve readability while reducing the
     long stack on phones. */
  .partner-ways-list {
    gap: 0.75rem !important;
  }

  .partner-ways-item {
    padding: 1.25rem 1rem !important;
  }

  /* Pagination and the footer jump link were visually small touch targets.
     The latter also sat directly on top of the footer divider. */
  .pagination-button,
  .footer__bottom-link-to--desktop-hidden {
    align-items: center;
    display: flex !important;
    justify-content: center;
    min-height: 2.75rem;
  }

  .footer__bottom-link-to--desktop-hidden {
    border: 1px solid rgba(255, 255, 255, 0.46);
    border-radius: 999px;
    margin-bottom: 1.25rem;
    justify-self: center;
    margin-left: auto;
    margin-right: auto;
    padding-left: 1.25rem;
    padding-right: 1.25rem;
    width: auto;
  }
}

/* Project detail: full-width interactive tours and a stable related-project grid. */
.project-tour { width: 100%; margin-bottom: 0; }
.project-tour iframe { display: block; width: 100%; height: min(80svh, 960px); min-height: 420px; border: 0; background: #eee; }
.project-tour__open { display: inline-flex; align-items: center; justify-content: center; min-height: 48px; margin-top: 1.5rem; padding: .875rem 1.5rem; border-radius: 999px; background: #db4361; color: #fff !important; font-size: 1rem; font-weight: 600; text-decoration: none; }
.project-tour__open:hover { background: #bd304e; }
.project-tour__open:focus-visible { outline: 3px solid #090909; outline-offset: 4px; }
.case-main .cases-page-body { padding-bottom: clamp(3rem, 6vw, 6rem) !important; }
.case-main .cases-page-body__gallery { opacity: 1 !important; }
.project-related { gap: 0 !important; padding-top: 0 !important; padding-bottom: clamp(3rem, 6vw, 6rem) !important; }
.project-related h2 { margin-bottom: clamp(1.5rem, 3vw, 3rem); }
.project-related > .container { padding-top: 0; padding-bottom: 0; }
.project-related-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 2px; }
.project-related-card { display: block; color: inherit; text-decoration: none; }
.project-related-card .gallery-item__image-wrapper { aspect-ratio: 3 / 4; position: relative; overflow: hidden; }
.project-related-card img { width: 100%; height: 100%; object-fit: cover; }
.project-related-card__caption { padding: 1rem; }
.project-related-card h3 { margin: 0 0 .5rem; font-size: 1.4rem; }
.project-view-link { display: block; margin-top: .75rem; color: var(--brand); }
@media (max-width: 991px) { .project-related-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 767px) {
  .project-tour iframe { height: 65svh; min-height: 360px; }
  .case-main .case { display: flex; flex-direction: column; }
  .case-main .cases-page-header { order: 1; }
  .case-main .case__nav { display: block; position: static; order: 2; width: auto; height: auto; align-self: flex-start; inset: auto; transform: none; margin: 0 1rem 1rem; }
  .case-main .cases-page-body { order: 3; }
  .case-main .case__nav-links { position: static; inset: auto; transform: none; display: flex; flex-direction: row; gap: 1rem; width: fit-content; padding: .75rem 1rem; }
  .case-main .case__nav-line { display: none; }
  .project-related-card h3 { font-size: 1.1rem; }
}

/* Service hub uses the same Fisheye service content as the homepage. */
.service-hub-title { padding-top: clamp(8rem, 15vw, 13rem); padding-bottom: 3rem; }
.service-hub { margin-top: 0; }

/* Final v1 usability pass: clear controls and comfortable mobile touch targets. */
.clients__grid-item-link:not(a) { cursor: default; }
.case-main .case__nav-links { background: #eeeeee; }
.case-main .case__nav-link { color: #141414; min-width: 44px; min-height: 44px; display: inline-flex; align-items: center; justify-content: center; }
.case-main .case__nav-link:hover { color: #d33b60; }
a:focus-visible, button:focus-visible { outline: 2px solid #d33b60; outline-offset: 4px; }
@media (max-width: 767px) {
  [data-component-id="cookie-banner"] { padding: 12px 16px; gap: 10px; font-size: 14px; line-height: 1.4; }
  [data-component-id="cookie-banner"] .text-sm { font-size: 14px; line-height: 1.4; }
  [data-component-id="cookie-banner"] [data-role="button"] { min-height: 44px; }
}
@media (min-width: 768px) {
  .case-main .cases-page-header__description { padding-right: 7rem; }
}
