/* port.css — port-authored behaviour CSS. Reimplements Webflow IX2 states with
 * values recovered from the captured ixData (webflow.schunk.a29dd4a398a5bc80).
 * The webflow.css authority file is never edited beyond its 3 URL rewrites.
 * Easings: outQuart = cubic-bezier(.165,.84,.44,1)  outQuint = cubic-bezier(.23,1,.32,1)
 */

/* --- Fade-up (IX2 a-223 "Fade In Bottom": y20px/op0 -> 0/1, 1400ms outQuart).
 * Initial state gated on html.js so a JS-off render shows final content
 * (matches live behaviour: IX2 applies initial states from JS). --- */
html.js [data-anim="fade"] {
  opacity: 0;
  transform: translate3d(0, 20px, 0);
}
html.js [data-anim="fade"].is-inview {
  opacity: 1;
  transform: translate3d(0, 0, 0);
  transition:
    opacity 1.4s cubic-bezier(0.165, 0.84, 0.44, 1),
    transform 1.4s cubic-bezier(0.165, 0.84, 0.44, 1);
}

/* --- Logo marquee (IX2 a-239/a-240, PAGE_START, loop, linear).
 * Implemented in px per tier: one set + one flex gap. Percentages are NOT
 * exact here (3 sets have only 2 inter-set gaps -> track 3800px, 33.333% =
 * 1266.67px != 1300px). <=767 uses the corrected 880px travel with the live
 * velocity (98 px/s) preserved — deliberate divergence, see DEVIATIONS DL-027. --- */
.clients-logos-grid {
  will-change: transform;
  animation: port-marquee-1300 15s linear infinite;
}
@keyframes port-marquee-1300 { to { transform: translate3d(-1300px, 0, 0); } }
@keyframes port-marquee-980  { to { transform: translate3d(-980px, 0, 0); } }
@keyframes port-marquee-880  { to { transform: translate3d(-880px, 0, 0); } }
@media screen and (max-width: 991px) {
  .clients-logos-grid { animation: port-marquee-980 10s linear infinite; }
}
@media screen and (max-width: 767px) {
  .clients-logos-grid { animation: port-marquee-880 8.98s linear infinite; }
}

/* --- Parallax targets (IX2 a-139; transform driven from interactions.js).
 * .cta-contact-image, .services-hero-image and .about-hero-image are further
 * live targets via their own class-keyed interactions. .case-hero-image is the
 * a-242 pin target (also driven from interactions.js). --- */
.image-cover-parallax, .cta-contact-image,
.services-hero-image, .about-hero-image,
.case-hero-image { will-change: transform; }

/* --- Button dual-text slide (IX2 a-228 reimpl; .button-inner-text-hover sits
 * at top:100% in webflow.css; both texts ride up one line-height on hover) --- */
.button-inner-text,
.button-inner-text-hover {
  transition: transform 0.5s cubic-bezier(0.23, 1, 0.32, 1);
}
.button:hover .button-inner-text,
.button:hover .button-inner-text-hover {
  transform: translate3d(0, -100%, 0);
}

/* --- Label-link dual-text slide (IX2 a-230/a-231 "Label Link Hover", 500ms
 * outQuint: both texts ride up one line-height, same mechanics as buttons) --- */
.label-inner .label-text,
.label-inner .label-text-hover {
  transition: transform 0.5s cubic-bezier(0.23, 1, 0.32, 1);
}
.label-link:hover .label-text,
.label-link:hover .label-text-hover {
  transform: translate3d(0, -100%, 0);
}

/* --- Hover underlines (IX2 line interactions; bases are width:0% in webflow.css) --- */
.navbar-menu-item-line,
.nav-item-line,
.subnav-item-line {
  transition: width 0.5s cubic-bezier(0.23, 1, 0.32, 1);
}
.navbar-menu-item:hover .navbar-menu-item-line,
.nav-item:hover .nav-item-line,
.subnav-item:hover .subnav-item-line { width: 100%; }
.button-text-line {
  width: 100%;
  transition: width 0.4s cubic-bezier(0.23, 1, 0.32, 1);
}
.button-text:hover .button-text-line { width: 0%; }

/* --- Mobile menu (IX2 a-172/a-173: 500ms outQuart; captured initial state was
 * display:none / opacity:0 / translateY(10px)) --- */
.mobile-menu {
  opacity: 0;
  transform: translate3d(0, 10px, 0);
  transition:
    opacity 0.5s cubic-bezier(0.165, 0.84, 0.44, 1),
    transform 0.5s cubic-bezier(0.165, 0.84, 0.44, 1);
}
.mobile-menu.is-open {
  opacity: 1;
  transform: translate3d(0, 0, 0);
}
.mobile-menu-toggle-line {
  transition: transform 0.5s cubic-bezier(0.165, 0.84, 0.44, 1), width 0.5s cubic-bezier(0.165, 0.84, 0.44, 1);
}
.mobile-menu-toggle.is-open ._01 { transform: translate3d(0, 9.5px, 0) rotate(-45deg); }
.mobile-menu-toggle.is-open ._02 { width: 0%; }
.mobile-menu-toggle.is-open ._03 { transform: translate3d(0, -9.5px, 0) rotate(45deg); }

/* --- Anchor scrolling (webflow.js eased-scrolls; nearest native equivalent) --- */
html { scroll-behavior: smooth; }

/* --- Contact new-build layout (design/contact-new-layout.png, DL-054).
 * The mockup's hero is a ~.5fr/1fr split and its offices media row is
 * ~1fr/.6fr; webflow.css has no two-column grid at either ratio that also
 * stacks at the template breakpoints. Only grid-template-columns is
 * overridden — stacking still comes from webflow.css's own <=991 (hero) /
 * <=767 (offices) display:flex variants, which make column values moot
 * there. Scoped to contact-only wrappers; .section-contact-offices is a
 * rule-less hook class used purely as scope. --- */
.contact-hero-grid { grid-template-columns: .5fr 1fr; }
.section-contact-offices .home-mission-grid-right { grid-template-columns: 1fr .6fr; }

/* --- Contact page background unification (#f9f4ea, sampled from the mockup;
 * not a palette token — DL-054/DL-061). Three jobs in one colour:
 * 1. body repaint: webflow.css >=1440 flips .body to navy (template quirk,
 *    shipped verbatim — DL-061). On this reference-less page that made the
 *    transparent light navbar illegible and a hover on the invisible Pages
 *    toggle flashed the dropdown's "More Templates" button over the hero.
 *    Contact-only; ported pages keep the faithful navy band.
 * 2. hero section + card share the colour — card is border-defined, no fill
 *    difference, as in the mockup.
 * 3. input wells match the card (mockup shows no lighter fill; ours sat
 *    darker via --form-default--background). :focus keeps the border-colour
 *    affordance from webflow.css but not the darker fill. --- */
body:has(.section-contact-hero) { background-color: #f9f4ea; }
.section-contact-hero { background-color: #f9f4ea; }
.contact-hero-grid-right-inner > .card { background-color: #f9f4ea; }
.section-contact-hero .form-input,
.section-contact-hero .form-input:focus { background-color: #f9f4ea; }

/* --- The capped card rides the right container edge so the hero's content
 * width matches the offices section's full-container rows below it
 * (.contact-hero-grid-right centres its child by default). Desktop only —
 * in the <=991 stack a right-shifted card under left-aligned text reads
 * broken. --- */
@media screen and (min-width: 992px) {
  .section-contact-hero .contact-hero-grid-right { align-items: flex-end; }
}

/* --- Light-navbar legibility at >=1440 (DL-064; supersedes DL-061's
 * "ported pages keep the navy band" for the CONTENT of the bar only).
 * webflow.css flips .body navy at >=1440; the light navbar is transparent, so
 * every light-chrome page painted dark menu items and the dark Nikka SVG onto
 * navy. Client-directed divergence: reuse the homepage's own inverse
 * mechanism — the same --navbar-default-inverse--* tokens .navbar-menu-item.inverse
 * resolves to — and swap in the white In Tandem PNG (the homepage navbar
 * asset). Scoped to the light header (.header:not(.absolute); home chrome is
 * already inverse) and off contact, whose body stays #f9f4ea at >=1440
 * (DL-061 repaint) and keeps its dark treatment. Below 1440 the band is cream
 * and the dark treatment already reads — untouched. --- */
.navbar-logo-image.port-logo-inverse { display: none; }
@media screen and (min-width: 1440px) {
  body:not(:has(.section-contact-hero)) .header:not(.absolute) .navbar-menu-item {
    color: var(--navbar-default-inverse--text-color);
  }
  body:not(:has(.section-contact-hero)) .header:not(.absolute) .navbar-menu-item:hover {
    color: var(--navbar-default-inverse--text-color-hover);
  }
  body:not(:has(.section-contact-hero)) .header:not(.absolute) .navbar-menu-item-line {
    background-color: var(--navbar-default-inverse--border-color);
  }
  body:not(:has(.section-contact-hero)) .header:not(.absolute) .navbar-logo-image {
    display: none;
  }
  body:not(:has(.section-contact-hero)) .header:not(.absolute) .navbar-logo-image.port-logo-inverse {
    display: block;
  }
}

/* --- Custom radio/checkbox icons are flex items inside .form-radio /
 * .form-checkbox with no shrink guard; multi-line labels squash them
 * (measured 10.125px on the consent checkbox). Template never pairs them
 * with long labels; the contact form does (DL-062). --- */
.form-radio-icon, .form-checkbox-icon { flex-shrink: 0; }

/* --- Chrome autofill paints its own light-blue background/text over
 * .form-input; repaint to the contact card colour so filled fields keep the
 * cream treatment (production fix — contact form is the only form). --- */
.form-input:-webkit-autofill,
.form-input:-webkit-autofill:hover,
.form-input:-webkit-autofill:focus {
  -webkit-box-shadow: 0 0 0 1000px #f9f4ea inset;
  -webkit-text-fill-color: var(--form-default--text-color);
  caret-color: var(--form-default--text-color);
}
