/* GENERATED by _build/make-blog-css.js from assets/css/site.css — do not edit.
   Edit site.css, then re-run the script. */
/* ════════════════════════════════════════════════════════════════
   ABACUS BPO — SHARED DESIGN SYSTEM
   Extracted from the homepage master (navbar.html) so every page
   belongs to the same ecosystem. Tokens → shell (nav/footer) →
   shared components → interior-page sections → responsive.
   ════════════════════════════════════════════════════════════════ */

/* ── TOKENS ─────────────────────────────────────────────── */
:root {
  --blue:        #00529e;
  --blue-dark:   #003d75;
  --blue-light:  #e8f2fc;
  --green:       #8abb2a;
  --green-dark:  #6a9420;
  --navy:        #0a1628;
  --text:        #1a2332;
  --muted:       #5a6778;
  --border:      #dde3ec;
  --surface:     #f5f8fc;
  --white:       #ffffff;
  --ease:        cubic-bezier(0.4, 0, 0.2, 1);
  --t:           0.2s;
}

/* ── RESET ──────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html { scroll-behavior: smooth; }
body {
  font-family: 'Plus Jakarta Sans', -apple-system, BlinkMacSystemFont, sans-serif;
  background: var(--white);
  color: var(--text);
  overflow-x: hidden;
  padding-top: 14px; /* white frame above the page hero */
}
a { text-decoration: none; color: inherit; }
button { cursor: pointer; border: none; background: none; font-family: inherit; color: inherit; }
ul { list-style: none; }
img { max-width: 100%; }

/* ════════════════════════════════════════════════════════
   NAVBAR (shared shell)
   ════════════════════════════════════════════════════════ */
.nav-wrap {
  position: fixed;
  top: 28px;
  left: 0; right: 0;
  padding: 0 130px;
  z-index: 600;
}
.navbar {
  position: relative;
  display: flex;
  align-items: center;
  background: rgba(255,255,255,0);
  backdrop-filter: blur(0px) saturate(100%);
  -webkit-backdrop-filter: blur(0px) saturate(100%);
  border: 1px solid rgba(255,255,255,0);
  border-radius: 100px;
  padding: 8px 8px 8px 20px;
  height: 60px;
  box-shadow: 0 4px 32px rgba(0,0,0,0), inset 0 1px 0 rgba(255,255,255,0);
  transition:
    background .5s var(--ease),
    border-color .5s var(--ease),
    box-shadow .5s var(--ease),
    backdrop-filter .5s var(--ease),
    -webkit-backdrop-filter .5s var(--ease);
}
.navbar.scrolled {
  background: rgba(255,255,255,.13);
  backdrop-filter: blur(22px) saturate(160%);
  -webkit-backdrop-filter: blur(22px) saturate(160%);
  border-color: rgba(255,255,255,.25);
  box-shadow: 0 4px 32px rgba(0,0,0,.2), inset 0 1px 0 rgba(255,255,255,.18);
}
.navbar.past-hero {
  background: rgba(255,255,255,.9);
  backdrop-filter: blur(22px) saturate(160%);
  -webkit-backdrop-filter: blur(22px) saturate(160%);
  border-color: var(--border);
  box-shadow: 0 6px 28px rgba(10,22,40,.12), inset 0 1px 0 rgba(255,255,255,.6);
}
.navbar.past-hero .nav-link            { color: var(--text); }
.navbar.past-hero .nav-link:hover      { color: var(--blue); background: var(--surface); }
.navbar.past-hero .nav-link.active     { color: var(--green); }
.navbar.past-hero .nav-link.is-open    { color: var(--blue); background: var(--surface); }
.navbar.past-hero .nav-hamburger       { background: rgba(10,22,40,.06); }
.navbar.past-hero .nav-hamburger:hover { background: rgba(10,22,40,.12); }
.navbar.past-hero .nav-hamburger span  { background: var(--text); }

.nav-logo {
  display: flex;
  align-items: center;
  gap: 9px;
  margin-right: 24px;
  flex-shrink: 0;
  color: white;
  font-size: 15.5px;
  font-weight: 500;
  letter-spacing: -.01em;
  transform: translateX(-26px);
  transition: transform .6s var(--ease);
}
.navbar.scrolled .nav-logo { transform: translateX(0); }
.nav-logo__mark { width: auto; height: 32px; flex-shrink: 0; object-fit: contain; }

.nav-list {
  display: flex;
  align-items: center;
  gap: 1px;
  flex: 1;
  justify-content: center;
  transform: translateX(var(--menu-shift, 130px));
  transition: transform .6s var(--ease);
}
.navbar.scrolled .nav-list { transform: translateX(0); }
.nav-item { position: static; }

.nav-link {
  display: flex;
  align-items: center;
  gap: 5px;
  color: rgba(255,255,255,.82);
  font-size: 13.5px;
  font-weight: 500;
  padding: 8px 13px;
  border-radius: 100px;
  transition: color var(--t) var(--ease), background var(--t) var(--ease);
  white-space: nowrap;
  cursor: pointer;
}
.nav-link:hover              { color: white; background: rgba(255,255,255,.1); }
.nav-link.active             { color: var(--green); }
.nav-link.is-open            { color: white; background: rgba(255,255,255,.1); }
.nav-link.is-open .nav-chev  { transform: rotate(180deg); opacity: 1; }
.nav-chev {
  width: 13px; height: 13px;
  opacity: .6;
  flex-shrink: 0;
  transition: transform var(--t) var(--ease), opacity var(--t) var(--ease);
}

.nav-right {
  margin-left: auto;
  opacity: 0;
  transform: translateX(14px) scale(.94);
  pointer-events: none;
  transition: opacity .45s var(--ease), transform .45s var(--ease);
}
.navbar.scrolled .nav-right { opacity: 1; transform: none; pointer-events: auto; }
.nav-cta {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  background: var(--green);
  color: var(--white);
  font-size: 13.5px;
  font-weight: 500;
  padding: 10px 22px;
  border-radius: 100px;
  white-space: nowrap;
  transition: background var(--t) var(--ease), transform var(--t) var(--ease);
}
.nav-cta:hover { background: #9dcc30; transform: translateY(-1px); }
.nav-cta svg   { width: 13px; height: 13px; color: var(--white); }

/* Interior pages: hero is shorter, so the pill starts as glass over the
   dark hero panel; JS still swaps .past-hero once it clears the hero. */

/* ── MEGA PANELS ────────────────────────────────────────── */
.mega-panel {
  position: absolute;
  top: calc(100% + 14px);
  background: var(--white);
  border: 1px solid var(--border);
  border-radius: 24px;
  box-shadow: 0 8px 16px -4px rgba(0,0,0,.07), 0 40px 80px -20px rgba(0,30,80,.18);
  opacity: 0;
  pointer-events: none;
  transform: translateY(-10px);
  transition: opacity var(--t) var(--ease), transform var(--t) var(--ease);
}
.mega-panel.open { opacity: 1; pointer-events: all; transform: translateY(0); }
/* Invisible bridge across the 14px gap between the pill and the panel, so
   moving the cursor trigger → panel never leaves the hover chain. Only
   catches the pointer while the panel is open (panel is pointer-events:none
   until .open), so it never blocks clicks on the page behind it. */
.mega-panel::before {
  content: '';
  position: absolute;
  left: 0; right: 0;
  top: -18px;
  height: 18px;
}
.mega-panel--wide  { left: 0; right: 0; }
.mega-panel--narrow       { width: 460px; }
.mega-panel--narrow-wide  { width: 760px; }
.panel-body { display: flex; padding: 32px 28px; gap: 0; }
.p-col {
  flex: 1;
  min-width: 0;
  padding-right: 28px;
  margin-right: 28px;
  border-right: 1px solid var(--border);
}
.p-col:last-child, .p-col.no-divider { border-right: none; padding-right: 0; margin-right: 0; }
.p-col__label {
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: .11em;
  text-transform: uppercase;
  color: var(--muted);
  padding: 0 10px;
  margin-bottom: 10px;
  min-height: 16px;
}
.m-item {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 11px 10px;
  border-radius: 12px;
  transition: background var(--t) var(--ease);
  cursor: pointer;
}
.m-item:hover { background: var(--surface); }
.m-icon {
  width: 40px; height: 40px;
  border-radius: 10px;
  background: var(--blue-light);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  transition: background var(--t) var(--ease);
}
.m-item:hover .m-icon      { background: var(--blue); }
.m-icon svg { width: 18px; height: 18px; color: var(--blue); transition: color var(--t) var(--ease); }
.m-item:hover .m-icon svg  { color: white; }
.m-text strong { display: block; font-size: 13.5px; font-weight: 500; color: var(--text); line-height: 1.3; }
.m-text span   { display: block; font-size: 12px; color: var(--muted); margin-top: 3px; line-height: 1.5; }

.p-featured {
  width: 220px;
  flex-shrink: 0;
  background: linear-gradient(148deg, #0d2040 0%, #003d75 100%);
  border-radius: 16px;
  padding: 28px 22px;
  display: flex;
  flex-direction: column;
  gap: 14px;
  margin-left: 8px;
  align-self: stretch;
  justify-content: space-between;
}
.feat-eyebrow { font-size: 10px; font-weight: 500; letter-spacing: .12em; text-transform: uppercase; color: rgba(255,255,255,.4); }
.feat-stat { font-size: 36px; font-weight: 600; color: white; line-height: 1; letter-spacing: -.03em; }
.feat-stat span { display: block; font-size: 12px; font-weight: 400; color: rgba(255,255,255,.4); margin-top: 6px; letter-spacing: 0; }
.feat-heading { font-size: 15px; font-weight: 500; color: white; line-height: 1.4; letter-spacing: -.01em; }
.feat-body { font-size: 12.5px; color: rgba(255,255,255,.5); line-height: 1.7; }
.feat-cta {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  background: var(--green);
  color: var(--navy);
  font-size: 13px;
  font-weight: 500;
  padding: 11px 18px;
  border-radius: 100px;
  width: fit-content;
  transition: background var(--t) var(--ease);
}
.feat-cta:hover { background: #9dcc30; }
.feat-cta svg   { width: 13px; height: 13px; }

/* ── HAMBURGER + MOBILE MENU ────────────────────────────── */
.nav-hamburger {
  display: none;
  flex-direction: column;
  gap: 5px;
  padding: 10px;
  border-radius: 100px;
  cursor: pointer;
  margin-left: auto;
  background: rgba(255,255,255,.08);
  transition: background var(--t) var(--ease);
}
.nav-hamburger:hover { background: rgba(255,255,255,.18); }
.nav-hamburger span {
  display: block;
  width: 22px; height: 2px;
  background: rgba(255,255,255,.85);
  border-radius: 2px;
  transition: all var(--t) var(--ease);
}
.mobile-nav {
  display: none;
  position: fixed;
  top: calc(28px + 60px + 12px);
  left: 130px;
  right: 130px;
  background: rgba(8,18,36,.97);
  backdrop-filter: blur(22px);
  -webkit-backdrop-filter: blur(22px);
  border-radius: 20px;
  border: 1px solid rgba(255,255,255,.1);
  padding: 12px;
  flex-direction: column;
  gap: 1px;
  max-height: calc(100vh - 110px);
  overflow-y: auto;
  z-index: 700;
}
.mobile-nav.open { display: flex; }
/* Phones: cheaper glass. Mobile INP (CrUX, 2026-10-05) was 213 ms, and on
   low-end Android the cost of a tap is mostly the repaint that follows it.
   backdrop-filter re-blurs everything behind the element on every frame it
   changes; animating it is about the most expensive paint there is. The
   menu panel is 97% opaque, so its blur was invisible; the pill keeps a
   lighter blur and simply snaps between states instead of animating it. */
@media (max-width: 760px) {
  .mobile-nav { backdrop-filter: none; -webkit-backdrop-filter: none; }
  .navbar { transition: background .5s var(--ease), border-color .5s var(--ease), box-shadow .5s var(--ease); }
  .navbar.scrolled, .navbar.past-hero {
    backdrop-filter: blur(12px);
    -webkit-backdrop-filter: blur(12px);
  }
}
.mob-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  color: rgba(255,255,255,.8);
  font-size: 14.5px;
  font-weight: 500;
  padding: 11px 14px;
  border-radius: 10px;
  cursor: pointer;
  transition: background var(--t) var(--ease);
  user-select: none;
}
.mob-row:hover  { background: rgba(255,255,255,.07); }
.mob-row.active { color: var(--green); }
.mob-row svg    { opacity: .45; width: 14px; height: 14px; flex-shrink: 0; transition: transform var(--t) var(--ease); }
.mob-row.expanded svg { transform: rotate(180deg); opacity: .8; }
.mob-sub { display: none; flex-direction: column; gap: 1px; padding: 2px 0 4px 12px; }
.mob-sub.open { display: flex; }
.mob-sub a {
  display: flex;
  align-items: center;
  gap: 10px;
  color: rgba(255,255,255,.52);
  font-size: 13.5px;
  font-weight: 400;
  padding: 8px 14px;
  border-radius: 8px;
  transition: color var(--t) var(--ease), background var(--t) var(--ease), padding var(--t) var(--ease);
}
.mob-sub a::before {
  content: '';
  flex-shrink: 0;
  width: 5px; height: 5px;
  border-radius: 50%;
  background: var(--green);
  opacity: .55;
  transition: all var(--t) var(--ease);
}
.mob-sub a:hover { color: rgba(255,255,255,.95); background: rgba(255,255,255,.05); padding-left: 18px; }
.mob-sub a:hover::before { opacity: 1; width: 8px; height: 2px; border-radius: 2px; }
.mob-cta {
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--green);
  color: var(--navy);
  font-size: 14px;
  font-weight: 500;
  padding: 13px;
  border-radius: 999px;
  margin-top: 8px;
  transition: background var(--t) var(--ease);
  cursor: pointer;
}
.mob-cta:hover { background: #9dcc30; }

/* ════════════════════════════════════════════════════════
   SHARED CTA — pill with arrow-in-circle fill effect
   ════════════════════════════════════════════════════════ */
.cta-fx {
  position: relative; overflow: hidden;
  display: inline-flex; align-items: center; gap: 12px;
  border-radius: 999px !important;
  --fx-fg: var(--blue);
  --fx-circle: 40px;
  --fx-pad: 6px;
}
.cta-fx__t { position: relative; z-index: 2; transition: color .35s var(--ease); white-space: nowrap; }
.cta-fx__i {
  position: relative; z-index: 2; flex-shrink: 0;
  width: var(--fx-circle); height: var(--fx-circle); border-radius: 50%;
  background: #fff; color: var(--fx-fg);
  display: inline-flex; align-items: center; justify-content: center;
}
.cta-fx__i svg { display: block; width: 15px; height: 15px; transition: transform var(--t) var(--ease); }
.cta-fx::before {
  content: ''; position: absolute; z-index: 1;
  top: var(--fx-pad); bottom: var(--fx-pad);
  width: var(--fx-circle); background: #fff; border-radius: 999px;
  transition: width .45s var(--ease);
}
.cta-fx:hover .cta-fx__t { color: var(--fx-fg); }
.cta-fx:hover::before { width: calc(100% - 2 * var(--fx-pad)); }
.cta-fx:hover .cta-fx__i svg { transform: translateX(2px); }
.cta-fx { padding: var(--fx-pad) var(--fx-pad) var(--fx-pad) var(--fx-lead, 26px) !important; gap: 12px !important; }
.cta-fx::before { right: var(--fx-pad); }
.cta-fx .cta-fx__i svg { color: var(--fx-fg); }
@media (prefers-reduced-motion: reduce) {
  .cta-fx::before, .cta-fx__t, .cta-fx__i svg { transition: none; }
}
.feat-cta.cta-fx { --fx-fg: var(--navy); }
.nav-cta.cta-fx  { --fx-fg: var(--navy); --fx-circle: 28px; --fx-pad: 5px; --fx-lead: 18px; }

/* Glass buttons (used on dark heroes) */

/* Solid green CTA with glowing ring (statement CTA on homepage) */
@property --cta-angle { syntax: '<angle>'; initial-value: 0deg; inherits: false; }
.reveal-cta {
  position: relative;
  isolation: isolate;
  display: inline-flex;
  align-items: center;
  gap: 12px;
  background: var(--green);
  color: #fff;
  font-size: 16px;
  font-weight: 500;
  letter-spacing: -.01em;
  padding: 17px 34px;
  border-radius: 100px;
  box-shadow: 0 8px 22px rgba(138,187,42,.32);
  transition: transform var(--t) var(--ease), box-shadow var(--t) var(--ease), background var(--t) var(--ease);
}
.reveal-cta:hover {
  background: #93c52e;
  transform: translateY(-2px);
  box-shadow: 0 12px 30px rgba(138,187,42,.45), 0 0 22px rgba(138,187,42,.35);
}
.reveal-cta::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: inherit;
  padding: 2px;
  background: conic-gradient(from var(--cta-angle),
    transparent 0%, transparent 55%,
    rgba(255,255,255,.4) 70%, #ffffff 80%, #eaffc0 86%,
    rgba(255,255,255,.4) 92%, transparent 100%);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask-composite: exclude;
  opacity: 0;
  transition: opacity .3s var(--ease);
}
/* Touch browsers latch :hover on the last-tapped element, so this ring span
   up and kept spinning forever on mobile while desktop only span on real
   hover. Gate it on a pointer that can actually hover, so the animation
   means the same thing on both. */
@media (hover: hover) and (pointer: fine) {
  .reveal-cta:hover::before { opacity: 1; animation: cta-spin 1.6s linear infinite; }
}
@keyframes cta-spin { to { --cta-angle: 360deg; } }
.reveal-cta svg { width: 18px; height: 18px; transition: transform var(--t) var(--ease); }
.reveal-cta:hover svg { transform: translateX(3px); }

/* Solid blue CTA */

/* Outline pill on dark backgrounds */
.btn-outline-dark {
  display: inline-flex; align-items: center; gap: 12px;
  width: fit-content;
  color: #fff; font-size: 15px; font-weight: 500;
  padding: 14px 28px;
  border: 1px solid rgba(255,255,255,.3); border-radius: 100px;
  transition: background var(--t) var(--ease), color var(--t) var(--ease), border-color var(--t) var(--ease);
}
.btn-outline-dark svg { width: 16px; height: 16px; transition: transform var(--t) var(--ease); }
.btn-outline-dark:hover { background: #fff; color: var(--navy); border-color: #fff; }
.btn-outline-dark:hover svg { transform: translateX(3px); }

/* ════════════════════════════════════════════════════════
   SECTION PRIMITIVES (eyebrow / titles / heads)
   ════════════════════════════════════════════════════════ */
.wrap       { max-width: 1180px; margin: 0 auto; padding: 0 40px; }

.sec-eyebrow {
  display: inline-flex; align-items: center; gap: 9px;
  font-size: 12px; font-weight: 600;
  letter-spacing: .18em; text-transform: uppercase;
  color: var(--blue); margin-bottom: 22px;
}
/* Pin the dot to the first line rather than centring it on the whole flex box:
   a long eyebrow ("Driving Progress with Every Insight") wraps to two lines on
   a phone and the dot floated to the middle of both. calc() reproduces the
   centred position within a single normal line box. */
.sec-eyebrow::before {
  content: ''; width: 7px; height: 7px; border-radius: 50%; background: var(--green);
  flex-shrink: 0; align-self: flex-start; margin-top: calc((1.25em - 7px) / 2);
}

.sec-title {
  font-size: clamp(28px, 4vw, 50px);
  font-weight: 600;
  line-height: 1.12;
  letter-spacing: -.03em;
  color: var(--text);
}
.sec-title em          { font-style: normal; color: var(--blue); }
.sec-title em.g        { color: var(--green); }
/* Long titles — a 10-word-plus headline stacks to five lines at the full
   clamp and overpowers the copy beside it. Opt in per section, don't shrink
   the global scale. */
.sec-head { max-width: 780px; margin: 0 auto 56px; text-align: center; }

/* ════════════════════════════════════════════════════════
   SCROLL-REVEAL UTILITIES (data-reveal / stagger)
   ════════════════════════════════════════════════════════ */
[data-reveal] {
  opacity: 0;
  transform: translateY(26px);
  transition: opacity .8s var(--ease), transform .8s var(--ease);
  transition-delay: var(--rd, 0s);
  will-change: opacity, transform;
}
[data-reveal="left"]  { transform: translateX(-34px); }
[data-reveal="right"] { transform: translateX(34px); }
[data-reveal="scale"] { transform: scale(.94); }
[data-reveal].is-in   { opacity: 1; transform: none; }
/* Below the two-column breakpoint the horizontal variants have nowhere to
   slide from: a stacked `.split__media` already fills the gutter, so a 34px
   X offset simply hangs off the right edge of the document until the element
   reveals. Slide those in vertically instead. */
@media (max-width: 980px) {
  [data-reveal="left"], [data-reveal="right"] { transform: translateY(26px); }
}
/* Above the fold, nothing waits for JavaScript. A [data-reveal] element is
   invisible until site.js (78 KB, end of body) has loaded, run its
   IntersectionObserver and faded it in over .8 s — so every inner page's
   hero headline, and the blog's hero image, could not paint (and could not
   count as LCP) until then. Hero content now paints with the first frame;
   the entrance is a CSS-only rise that never hides it. */
.page-hero [data-reveal], .bp-hero-img[data-reveal] {
  opacity: 1; transform: none; transition: none;
  animation: heroRise .7s var(--ease) both;
}
@keyframes heroRise { from { transform: translateY(14px); } to { transform: none; } }
@media (prefers-reduced-motion: reduce) {
  [data-reveal] { opacity: 1 !important; transform: none !important; transition: none; animation: none !important; }
}

/* Word-by-word statement reveal (homepage pattern, reusable) */
.reveal-word { color: rgba(26,35,50,.16); transition: color .45s var(--ease); }
.reveal-word.is-on { color: var(--text); }

/* ════════════════════════════════════════════════════════
   PAGE HERO (interior pages) — inset dark rounded panel that
   mirrors the homepage hero frame, sized to content.
   ════════════════════════════════════════════════════════ */
.page-hero {
  position: relative;
  margin: 0 14px 14px;
  border-radius: 28px;
  overflow: hidden;
  background:
    radial-gradient(90% 120% at 85% -10%, rgba(0,82,158,.55), transparent 55%),
    radial-gradient(70% 90% at 0% 110%, rgba(138,187,42,.16), transparent 55%),
    linear-gradient(150deg, #0e1f3a 0%, #0a1628 62%);
}
/* isolate so `screen` blends against this hero's own gradient and nothing
   further back in the page. */
/* Ambient background loop (page-hero--video). The clip is white UI on a
   black field, so `screen` drops the black to nothing and only its light
   lands on the gradient — the blue stays the blue, it just gains motion.
   Masked away from the lower-left so the copy never fights it. */
.page-hero__bg {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  z-index: 0;
  opacity: .17;
  mix-blend-mode: screen;
  pointer-events: none;
  -webkit-mask-image: radial-gradient(115% 95% at 50% 0%, #000 18%, rgba(0,0,0,.5) 58%, transparent 92%);
          mask-image: radial-gradient(115% 95% at 50% 0%, #000 18%, rgba(0,0,0,.5) 58%, transparent 92%);
}
@media (prefers-reduced-motion: reduce) {
  /* Only the moving one goes — a still backdrop is not motion, and pulling
     it would strip the banner hero back to a bare gradient. */
  video.page-hero__bg { display: none; }
}
/* Photographic backdrop (banner hero). A photo is not the white-on-black UI
   clip the rule above was tuned for: screen alone lifts the whole navy into
   a grey haze and the bright windows blow out. Luminosity keeps the hero's
   own blue and lets only the picture's light and shade through, and the
   linear mask fades it out under the stat strip so nothing competes there. */
img.page-hero__bg {
  opacity: .16;
  mix-blend-mode: luminosity;
  -webkit-mask-image: linear-gradient(to bottom, #000 0%, rgba(0,0,0,.75) 52%, transparent 94%);
          mask-image: linear-gradient(to bottom, #000 0%, rgba(0,0,0,.75) 52%, transparent 94%);
}

/* ════════════════════════════════════════════════════════
   BANNER HERO — centered copy over a photographic backdrop,
   no side or below visual. Service pages use this where the
   split hero's 481×380 right column cropped a wide room shot
   into a portrait of whoever stood centre frame.
   ════════════════════════════════════════════════════════ */
/* Even three-track grid rather than a flex row: the stat labels run to very
   different lengths across the twelve service pages (CX's “CSAT points gained
   for a super app client through tailored CX solutions” against Inbound's
   “24/7”), and a flex row overflows on the long ones and wraps the third stat
   onto a line of its own. Fixed tracks let each label wrap inside its own
   column instead. Capped narrower than the copy so the rule above the strip
   reads as a footer to the hero, not a full-width divider. */
/* faint dot texture */
.page-hero::after {
  content: '';
  position: absolute; inset: 0;
  background-image: radial-gradient(rgba(255,255,255,.10) 1px, transparent 1px);
  background-size: 26px 26px;
  -webkit-mask-image: linear-gradient(160deg, rgba(0,0,0,.5), transparent 55%);
          mask-image: linear-gradient(160deg, rgba(0,0,0,.5), transparent 55%);
  pointer-events: none;
}
.page-hero__inner {
  position: relative; z-index: 2;
  max-width: 1180px;
  margin: 0 auto;
  padding: 168px 56px 84px;
}
.page-hero__inner--center { text-align: center; display: flex; flex-direction: column; align-items: center; }
.crumbs {
  display: flex; align-items: center; flex-wrap: wrap; gap: 8px;
  font-size: 12.5px; font-weight: 500;
  color: rgba(255,255,255,.55);
  margin-bottom: 26px;
}
.crumbs a { color: rgba(255,255,255,.55); transition: color var(--t) var(--ease); }
.crumbs a:hover { color: #fff; }
.crumbs svg { width: 12px; height: 12px; opacity: .5; }
.crumbs .cur { color: var(--green); }

.page-hero__eyebrow {
  display: inline-flex; align-items: center; gap: 8px;
  background: rgba(138,187,42,.18);
  border: 1px solid rgba(138,187,42,.35);
  color: #c8e87a;
  font-size: 12px; font-weight: 500;
  letter-spacing: .08em; text-transform: uppercase;
  padding: 6px 16px; border-radius: 100px;
  margin-bottom: 22px;
  width: fit-content;
}
.page-hero__title {
  font-size: clamp(34px, 4.2vw, 56px);
  font-weight: 600;
  color: #fff;
  letter-spacing: -.03em;
  line-height: 1.08;
  margin-bottom: 18px;
}
.page-hero__title em { font-style: normal; color: var(--green); }
.page-hero__sub {
  font-size: 17px;
  color: rgba(255,255,255,.78);
  max-width: 560px;
  line-height: 1.65;
  margin-bottom: 32px;
}
.page-hero__inner--center .page-hero__sub { margin-left: auto; margin-right: auto; }

/* hero stat strip */

/* Split hero: the stat strip lives inside the narrow left copy column,
   where a wrapping flex row dropped the third stat onto a cramped,
   divider-less second line. Lay them out as an even three-track grid so
   they always sit side by side, each with room for its label to wrap. */

/* hero visual placeholder (right column of split heroes) */

/* Real-photo variants — fill placeholder blocks, drop the dashed chrome */

/* ════════════════════════════════════════════════════════
   SHOWCASE HERO (Solutions) — centered copy stacked above a
   full-width product screenshot. Solutions sell a dashboard, and
   the split hero's right column crops it too hard to read.
   ════════════════════════════════════════════════════════ */

/* the screenshot itself — sits on a soft glow, floats on a shadow */
.hero-showcase { position: relative; margin: 56px auto 0; max-width: 1178px; }
/* Scroll-linked reveal — the panel stays tucked under the copy until
   the visitor starts scrolling, then rises into place. The class is
   added by site.js, so with JS off (or reduced motion) the dashboard
   is simply visible from the start. --reveal is driven 0→1 there. */
.hero-showcase.is-scroll-reveal {
  --reveal: 0;
  opacity: var(--reveal);
  transform: translateY(calc((1 - var(--reveal)) * 76px)) scale(calc(.955 + .045 * var(--reveal)));
  transform-origin: 50% 0;
  will-change: opacity, transform;
}
.hero-showcase::before {
  content: '';
  position: absolute; left: 6%; right: 6%; top: -4%; bottom: -6%;
  background: radial-gradient(58% 60% at 50% 45%, rgba(0,82,158,.6), transparent 72%);
  filter: blur(46px);
  pointer-events: none;
}
/* live product dashboard, framed. Authored on a 1178x621 canvas that
   scales itself to the frame, so the ratio here must match it. The
   embed is decoration — pointer-events stay with the page. */
.hero-showcase__embed {
  display: block; width: 100%; aspect-ratio: 1178 / 621;
  border: 0; pointer-events: none;
}
/* no screenshot supplied yet — keep the dashed placeholder language */

/* ── CUTOUT VARIANT ──────────────────────────────────────
   Some solutions lead with a transparent-PNG banner instead of a
   framed screenshot. It carries no card chrome, is held to a medium
   width so it reads as artwork rather than a hero takeover, and sits
   flush on the hero floor — its bottom edge blurred away into the
   background so the crop never lands as a hard line. */
/* Artwork that stands on the hero's floor rather than hovering above it:
   the section's bottom padding goes, so the image's base meets the hero's
   bottom edge exactly. Opt-in per page — most showcase artwork wants the
   breathing room this removes. */
/* The artwork carries only ~1% transparent padding on its top edge, so
   this margin is very nearly the whole gap under the stat strip. */
/* softer, lower glow — it lights the artwork instead of framing a card */
/* the light pool the figure stands in — a blurred wash under the fade */

/* ── BARE VARIANT ────────────────────────────────────────
   Transparent-alpha artwork that arrives with its own chrome — a device
   mockup carrying its own bezel and drop shadow. It keeps the full
   showcase width, because the product UI inside the bezel still has to
   be readable, but drops the card frame: a bordered, lit rectangle
   around a device that floats free of it reads as a mistake. No bottom
   fade either — unlike the cutout, this artwork runs to its own hard
   edge, so a fade would dissolve the device instead of landing it. */

/* ── WIDGET VARIANT · AI KNOWLEDGE SEARCH ────────────────
   Knowledge Base leads with the search working rather than a picture
   of it: a question types itself in and the ranked articles answer.
   Live markup rather than an iframe embed, because the bar is glass
   and backdrop-filter cannot reach the page behind an iframe.
   Purely decorative — pointer-events stay with the page. */

/* the glass shell — reads the hero gradient through it */

/* the white search card inside the glass */
@keyframes kbCaret { 0%, 49% { opacity: 1 } 50%, 100% { opacity: 0 } }

/* the answers — glass cards that fade up as each result lands */
.kb-ask__card {
  background: rgba(255,255,255,.06);
  border: 1px solid rgba(255,255,255,.12);
  border-radius: 16px;
  padding: 16px 16px 14px;
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  text-align: left;
}
/* is-live is added by site.js, so with JS off the three answers are
   simply there instead of stuck at opacity 0 */

/* no JS / reduced motion: the demo sits in its answered state */

/* ════════════════════════════════════════════════════════
   SHOWCASE WIDGET · UNIFIED AI HELPDESK (hd-ai)
   Port of the client's Claude Design loop, wearing the same glass
   shell as .kb-ask above because it sits on the same dark hero.

   Every element's resting state is its ANSWERED state — the sequence
   is layered on top with `both` fill, so the delays hold each piece
   back rather than opacity:0 being the default. That is what lets
   reduced motion and JS-off both land somewhere sensible.
   ════════════════════════════════════════════════════════ */
.hd-ai { position: relative; text-align: left; }

/* ── header ── */

/* ── two columns: conversation + assistant rail ── */

/* ── the customer message ── */
/* keywords get picked out as the assistant parses the question */

/* ── the grounded reply ── */
/* the answer wipes in left-to-right, as if it were being written */

/* ── send confirmation ── */

/* ── assistant rail ── */
/* the four transient status lines share one row and cross-fade through
   it; only the closing "Active" line rests visible */
/* the search sweep — a band of light dragged down the result list */
/* the ring that fires when KB-104 is picked */

/* ── the wire from the matched article into the reply ──
   site.js measures the two endpoints and writes the path; with JS off
   there is no `d` and the svg simply draws nothing. */

@keyframes hdUp     { from { opacity: 0; transform: translateY(12px) } to { opacity: 1; transform: none } }
@keyframes hdPop    { 0% { opacity: 0; transform: scale(.6) } 60% { opacity: 1; transform: scale(1.12) } 100% { opacity: 1; transform: none } }
@keyframes hdFade   { 0% { opacity: 0; transform: translateY(5px) } 16% { opacity: 1; transform: none } 82% { opacity: 1; transform: none } 100% { opacity: 0; transform: translateY(-5px) } }
@keyframes hdKw     { from { background-size: 0% 100% } to { background-size: 100% 100% } }
@keyframes hdReveal { from { clip-path: inset(0 102% 0 0); opacity: .15 } to { clip-path: inset(0 0 0 0); opacity: 1 } }
@keyframes hdPulse  { 0%, 100% { opacity: .4; transform: scale(.85) } 50% { opacity: 1; transform: scale(1.15) } }
@keyframes hdSweep  { 0% { opacity: 0; transform: translateY(0) } 18% { opacity: 1 } 82% { opacity: .85 } 100% { opacity: 0; transform: translateY(170px) } }
@keyframes hdDraw   { from { stroke-dashoffset: 100; opacity: 0 } 20% { opacity: 1 } to { stroke-dashoffset: 0; opacity: 1 } }
@keyframes hdTravel { 0% { stroke-dashoffset: 100; opacity: 0 } 12% { opacity: 1 } 88% { opacity: 1 } 100% { stroke-dashoffset: 0; opacity: 0 } }
@keyframes hdZoom   { 0%, 86% { transform: scale(1) } 93% { transform: scale(.978) } 100% { transform: scale(1) } }

/* reduced motion: the panel simply sits in its answered state */
@media (prefers-reduced-motion: reduce) {
  .hd-ai * { animation: none !important; }
}

/* A desktop dashboard scaled to phone width is unreadable, so below the
   tablet breakpoint the frame becomes a swipeable window onto the
   screenshot at a legible scale instead of a shrunken thumbnail. */
@media (max-width: 760px) {
  /* the cutout is artwork, not a dashboard — it just scales down. Same for
     the bare device mockup: the scrollable window is for a raw screenshot
     that fills its frame, and panning a laptop bezel sideways reads as a
     bug, so the whole mockup shrinks to fit instead. */
  /* 760px keeps the embed above its own 720px flow-mode threshold, so
     it stays the real dashboard rather than reflowing to a mobile one. */
  .hero-showcase__embed { width: 760px; max-width: none; }
}

/* ════════════════════════════════════════════════════════
   VIDEO SECTION — product walkthrough
   Held inside the page container with the usual gutters rather than
   run full-bleed, on a dark band so the frame reads as a screen.
   No native controls: hover plays a short muted preview, a click
   starts it properly, and the only chrome is one play/pause button.
   ════════════════════════════════════════════════════════ */

/* the player */
/* The still frame rides above the video as its own layer rather than
   the poster attribute, so returning to idle is a fade instead of a
   load() that would throw away everything already buffered. */

/* the one control. Sits centre-stage while idle, shrinks into the
   corner once the visitor has started the video for real. */
/* a muted preview is running — the button steps out of the way */
/* started for real: small corner control, revealed on hover or focus */

/* a light scrim keeps the button legible over a bright frame */

/* ════════════════════════════════════════════════════════
   IMAGE PLACEHOLDER (light sections) — homepage svc-visual
   ════════════════════════════════════════════════════════ */
.ph {
  position: relative;
  border-radius: 18px;
  overflow: hidden;
  background:
    radial-gradient(120% 120% at 30% 0%, rgba(0,82,158,.06), transparent 60%),
    var(--white);
  border: 1px dashed rgba(0,82,158,.22);
  display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 14px;
  color: var(--muted);
  min-height: 240px;
}
.ph::before {
  content: ''; position: absolute; inset: 0;
  background-image:
    linear-gradient(rgba(10,22,40,.035) 1px, transparent 1px),
    linear-gradient(90deg, rgba(10,22,40,.035) 1px, transparent 1px);
  background-size: 26px 26px; pointer-events: none;
}
/* Real-photo variants drop the placeholder chrome. Restated here because the
   .ph base block above is declared later than the .ph--photo rule and would
   otherwise win on source order — the dashed hairline only shows on artwork
   that doesn't bleed to the frame edge. */


/* ════════════════════════════════════════════════════════
   FEATURE / SERVICE CARD GRIDS
   ════════════════════════════════════════════════════════ */

/* Big service card with image placeholder (homepage svc-card) */

/* Compact icon feature card */

/* Checklist rows — each point sits in its own quiet card so the
   three items read as a tidy set instead of a dense stack. */

/* ════════════════════════════════════════════════════════
   PROCESS TIMELINE (numbered steps, reveal on scroll)
   ════════════════════════════════════════════════════════ */
.steps { position: relative; display: grid; grid-template-columns: repeat(4, 1fr); gap: 26px; counter-reset: step; }

.step {
  position: relative;
  background: var(--white);
  border: 1px solid var(--border);
  border-radius: 22px;
  padding: 30px 26px;
  transition: box-shadow var(--t) var(--ease), transform var(--t) var(--ease), border-color var(--t) var(--ease);
}
.step:hover { border-color: rgba(0,82,158,.25); box-shadow: 0 24px 60px -28px rgba(0,30,80,.24); transform: translateY(-3px); }
.step h3 { font-size: 17.5px; font-weight: 600; color: var(--text); margin-bottom: 9px; letter-spacing: -.01em; }
.step p  { font-size: 14px; line-height: 1.65; color: var(--muted); }
/* The parallax drift is decorative — drop it entirely when the user has
   asked for reduced motion, rather than just shortening it. */
@media (prefers-reduced-motion: reduce) {
  .split__media .ph { transform: none; will-change: auto; }
}

/* ════════════════════════════════════════════════════════
   SPLIT SECTION (image + copy, alternating)
   ════════════════════════════════════════════════════════ */
.split { display: grid; grid-template-columns: 1.02fr .98fr; gap: 64px; align-items: center; }
.split__media { position: relative; }
/* Parallax drift — JS writes --parallax in px as the section crosses the
   viewport. Deliberately small (±18px): enough to feel alive on scroll,
   not enough to read as a gimmick on a corporate page. */
.split__media .ph { will-change: transform; transform: translate3d(0, var(--parallax, 0px), 0); }
.split__media .ph {
  aspect-ratio: 4 / 3.2;
  border-radius: 28px;
  border-bottom-right-radius: clamp(70px, 9vw, 130px);
  min-height: 0;
}
/* Square artwork — composed edge-to-edge on a 1:1 canvas, so the 4:3.2 crop
   and the big corner cut would eat the composition. True square, small radius. */
/* Native-ratio artwork — a tall composition the landscape default would cut
   in half. The frame takes its height from the image rather than cropping to
   a ratio, so the picture is shown whole at its own proportions. */
/* Per-image frame ratio — for photography whose subject the default 4:3.2
   landscape box crops badly, or which sits so much shorter than the copy
   beside it that the section reads lopsided. Unlike .ph--square and
   .ph--native this keeps the frame's signature corner cut; only the box's
   proportions change, via --ph-ratio on the element. The doubled .ph
   .ph--ratio is deliberate: it has to outrank `.split--flip .split__media
   .ph` in the ≤980px block below, which would otherwise drag every flipped
   visual back to 16:10 and crop a portrait photo through the face. */

/* ════════════════════════════════════════════════════════
   OMNICHANNEL HUB — a radial "one helpdesk, every channel"
   diagram used as the media for a split section. A central
   Abacus core with eight channel nodes orbiting it; dashed
   connectors light up in sequence (driven by site.js). Sits
   on the light section background, so it keeps the brand
   blue/green rather than the hero's inverted palette.
   ════════════════════════════════════════════════════════ */
.ch-hub-svg { position: absolute; inset: 0; width: 100%; height: 100%; z-index: 1; }
.ch-hub-svg path { stroke: rgba(0,82,158,.18); stroke-width: 1.5; stroke-dasharray: 5 6; fill: none; }
.ch-hub-svg path.lit {
  stroke: var(--green); stroke-dasharray: none; stroke-width: 2.2;
  filter: drop-shadow(0 0 6px rgba(138,187,42,.6));
}
@keyframes hubPulse {
  0%,100% { transform: translate(-50%,-50%) scale(1); opacity: 1; }
  50%     { transform: translate(-50%,-50%) scale(1.3); opacity: 0; }
}
/* tighten the orbiting cards where the column gets narrow */
@media (prefers-reduced-motion: reduce) {
  .ch-hub-svg path.lit { transition: none; }
}

/* ════════════════════════════════════════════════════════
   STATS BAND (counter animation)
   ════════════════════════════════════════════════════════ */

/* ════════════════════════════════════════════════════════
   INDUSTRY CHIPS BAND (homepage ind-section)
   ════════════════════════════════════════════════════════ */

/* ════════════════════════════════════════════════════════
   TESTIMONIAL (single centered quote)
   ════════════════════════════════════════════════════════ */
.tst-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--border); cursor: pointer; transition: background var(--t) var(--ease), width var(--t) var(--ease); }
.tst-dot.is-active { width: 28px; border-radius: 5px; background: var(--blue); }

/* ════════════════════════════════════════════════════════
   FAQ ACCORDION
   ════════════════════════════════════════════════════════ */
.faq-item {
  background: var(--white);
  border: 1px solid var(--border);
  border-radius: 18px;
  overflow: hidden;
  transition: border-color var(--t) var(--ease), box-shadow var(--t) var(--ease);
}
.faq-item.open { border-color: rgba(0,82,158,.3); box-shadow: 0 18px 44px -24px rgba(0,30,80,.22); }
.faq-q {
  width: 100%;
  display: flex; align-items: center; justify-content: space-between; gap: 18px;
  text-align: left;
  font-size: 16.5px; font-weight: 600; color: var(--text);
  padding: 22px 26px;
  letter-spacing: -.01em;
}
.faq-q:hover { color: var(--blue); }
.faq-a {
  max-height: 0;
  overflow: hidden;
  transition: max-height .4s var(--ease);
}

/* ════════════════════════════════════════════════════════
   CASE STUDY CARDS (dark, homepage pattern) + listing grid
   ════════════════════════════════════════════════════════ */

/* ── Case listing tiles (compact, three-up) ──────────────────
   The banner card above is one-per-row by design. The listing needs a shape
   that survives a growing case count, so the same content runs vertically:
   image, headline, the one number worth leading with, then tags. The whole
   tile is the anchor — a 340px card does not need a separate hit target. */
/* Fade the photo into the card body so the join never reads as a hard seam. */
/* Tags sit above the CTA and push it to the floor, so CTAs line up across a
   row even when titles wrap to different depths. */

/* Case study detail: metric bento */

/* ── Case study: Verified Results ────────────────────────────
   The live pages print a figure, a small unit beside it, the metric
   name and a one-line gloss. Some entries are qualitative and carry
   no figure at all, so --soft centres the label on its own. */
/* auto-fit so 4, 5 and 6-metric studies all lay out evenly without a
   bespoke column count per page */

/* Case study: solution cards carry the live page's capability chips.
   .case-tag is white-on-transparent for the navy hero and case cards, so it
   is invisible on a light card — these need the light-surface colours. */

/* Case study: The Client Context — values like "$3.1 Billion" and
   "Since 2017" are not countable, so this is a static band. */

/* Prose block for case study narrative */
.prose { max-width: 760px; margin: 0 auto; }
.prose .sec-eyebrow { margin-bottom: 14px; }
/* <em> is the accent-colour convention sitewide, not italics — .sec-title
   already does this, and the case-study closing heading is a .prose h2. */
.prose h2 em { font-style: normal; color: var(--blue); }
.prose h2 { font-size: clamp(24px, 2.6vw, 32px); font-weight: 600; letter-spacing: -.02em; color: var(--text); margin: 44px 0 16px; }
.prose h2:first-child { margin-top: 0; }
.prose p  { font-size: 16px; line-height: 1.75; color: var(--muted); margin-bottom: 16px; }
.prose strong { color: var(--text); font-weight: 600; }
.prose ul { margin: 0 0 16px; padding: 0; display: flex; flex-direction: column; gap: 10px; }
.prose ul li {
  position: relative;
  padding-left: 28px;
  font-size: 15.5px; line-height: 1.65; color: var(--muted);
}
.prose ul li::before {
  content: '';
  position: absolute; left: 4px; top: 9px;
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--green);
}

/* ════════════════════════════════════════════════════════
   TABS (pill switcher)
   ════════════════════════════════════════════════════════ */
.tabs { display: flex; justify-content: center; flex-wrap: wrap; gap: 8px; margin-bottom: 44px; }
.tab-btn {
  font-size: 14px; font-weight: 600;
  color: var(--muted);
  padding: 11px 22px;
  border-radius: 100px;
  border: 1px solid var(--border);
  background: var(--white);
  transition: all var(--t) var(--ease);
}
.tab-btn:hover { color: var(--blue); border-color: rgba(0,82,158,.3); }
.tab-btn.is-active { background: var(--navy); color: #fff; border-color: var(--navy); }
.tab-pane { display: none; }
.tab-pane.is-active { display: block; animation: paneIn .45s var(--ease); }
@keyframes paneIn { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: none; } }

/* ════════════════════════════════════════════════════════
   CONTACT (cf-*) — shared conversion section
   ════════════════════════════════════════════════════════ */
@keyframes cfPulse {
  0%, 100% { box-shadow: 0 0 0 3px rgba(138,187,42,.30); }
  50%      { box-shadow: 0 0 0 8px rgba(138,187,42,0); }
}
.cf-card {
  position: relative;
  background: var(--white);
  border: 1px solid var(--border);
  border-radius: 18px;
  box-shadow: 0 34px 80px -36px rgba(10,22,40,.32);
  padding: 44px 40px 36px;
  overflow: hidden;
}
.cf-card::before {
  content: '';
  position: absolute; top: 0; left: 0; right: 0;
  height: 4px;
  background: linear-gradient(90deg, var(--blue) 0%, #1a7fd4 45%, var(--green) 100%);
}
 .cf-select {
  width: 100%;
  font-family: inherit;
  font-size: 14.5px;
  color: var(--text);
  background: var(--white);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 13px 15px;
  transition: border-color var(--t) var(--ease), box-shadow var(--t) var(--ease);
  outline: none;
}
 .cf-select:focus { border-color: var(--blue); box-shadow: 0 0 0 3px rgba(0,82,158,.12); }
.cf-select {
  appearance: none; -webkit-appearance: none;
  color: #9aa6b6;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%235a6778' stroke-width='2.5'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 15px center;
  padding-right: 40px;
  cursor: pointer;
}
.cf-select.has-value, .cf-select option { color: var(--text); }
/* Cloudflare Turnstile — renders only where data-turnstile.js carries a
   site key. Centred over the full-width submit button, and reserving its
   own height (the widget is ~65px) so the button does not jump down the
   card the moment the challenge finishes loading. */
.cf-turnstile {
  display: flex; justify-content: center;
  min-height: 65px;
  margin: 4px 0 18px;
}
.cf-turnstile iframe { max-width: 100%; }
/* The apply form's button is left-aligned next to a "prefer email?" note,
   not full width like the contact form's, so the widget lines up with the
   fields rather than centring over them. */

/* The submit button spans the form. It used to sit right-aligned at its
   text width, which read as a secondary control on a card this wide and
   left the eye hunting for it after the last field. */
.cf-actions { display: block; }
.cf-submit {
  display: block;
  width: 100%;
  text-align: center;
  background: var(--blue);
  color: #fff;
  font-family: inherit;
  font-size: 15px;
  font-weight: 600;
  padding: 15px 34px;
  border-radius: 999px;
  cursor: pointer;
  transition: background var(--t) var(--ease), transform var(--t) var(--ease), box-shadow var(--t) var(--ease);
}
.cf-submit:hover { background: var(--blue-dark); transform: translateY(-1px); box-shadow: 0 12px 24px -10px rgba(0,82,158,.5); }

/* ════════════════════════════════════════════════════════
   FINAL CTA BAND (dark, pre-footer)
   ════════════════════════════════════════════════════════ */
.cta-band { background: var(--white); padding: 0 14px 14px; }
.cta-band__panel {
  position: relative;
  overflow: hidden;
  border-radius: 28px;
  background:
    radial-gradient(90% 130% at 88% -20%, rgba(0,82,158,.6), transparent 55%),
    radial-gradient(70% 100% at 8% 115%, rgba(138,187,42,.22), transparent 55%),
    linear-gradient(150deg, #0e1f3a 0%, #0a1628 62%);
  padding: 92px 48px;
  text-align: center;
}
.cta-band__panel::after {
  content: '';
  position: absolute; inset: 0;
  background-image: radial-gradient(rgba(255,255,255,.10) 1px, transparent 1px);
  background-size: 26px 26px;
  -webkit-mask-image: linear-gradient(160deg, rgba(0,0,0,.5), transparent 60%);
          mask-image: linear-gradient(160deg, rgba(0,0,0,.5), transparent 60%);
  pointer-events: none;
}
.cta-band__inner { position: relative; z-index: 1; max-width: 720px; margin: 0 auto; }
.cta-band__title {
  font-size: clamp(30px, 4vw, 50px);
  font-weight: 600;
  letter-spacing: -.03em;
  line-height: 1.1;
  color: #fff;
}
.cta-band__title em { font-style: normal; color: var(--green); }
.cta-band__sub { margin-top: 18px; font-size: 16.5px; line-height: 1.7; color: rgba(255,255,255,.75); }
.cta-band__ctas { display: flex; justify-content: center; gap: 14px; flex-wrap: wrap; margin-top: 36px; }
.cta-band__note { margin-top: 22px; font-size: 13px; color: rgba(255,255,255,.5); }

/* ════════════════════════════════════════════════════════
   RELATED PAGES STRIP (internal linking)
   ════════════════════════════════════════════════════════ */
/* Two-up variants. These MUST live above the responsive overrides below:
   same specificity, so source order decides, and the media queries need to
   win. Previously these were inline style attributes, which no media query
   can beat — the cards stayed 2-up at 375px and got squeezed. */

/* ════════════════════════════════════════════════════════
   TEAM GRID (leadership)
   ════════════════════════════════════════════════════════ */
/* Fixed ratio rather than a min-height, so all five portraits crop to the
   same frame and the row of cards lines up whatever the source dimensions.
   The dashed rule belongs to the placeholder state — a real photo sits
   flush against the card body. */

/* ════════════════════════════════════════════════════════
   BADGE / CERT CARDS (security & compliance)
   ════════════════════════════════════════════════════════ */
/* odd card count: the last one spans the row instead of leaving a gap */

/* ════════════════════════════════════════════════════════
   COMPARISON TABLE (why abacus)
   ════════════════════════════════════════════════════════ */

/* Unsupplied client fact — deliberately loud so it cannot ship unnoticed */

/* ── ENGAGEMENT MODEL LIST (inside .usecase columns) ─────── */

/* ── TRUST BAND (dark contrast anchor) ───────────────────── */

/* ════════════════════════════════════════════════════════
   TIMELINE (about page journey)
   ════════════════════════════════════════════════════════ */
/* The dot is pulled back out of the item by exactly the rail's padding, so
   its centre lands on the rail. Keep the two in one variable: when the
   padding shrank at <=768px the hard-coded -34px stayed put and every dot
   drifted 6px left of the rail, half of it off the canvas edge. */

/* ════════════════════════════════════════════════════════
   FOOTER (scoped, from homepage)
   ════════════════════════════════════════════════════════ */
.abacus-footer,
.abacus-back-to-top {
  --af-bg:           #191823;
  --af-bg-elevated:  #20202c;
  --af-blue:         #00529e;
  --af-blue-light:   #4d8fd1;
  --af-green:        #8abb2a;
  --af-green-dark:   #6a9420;
  --af-text:         #f4f5f8;
  --af-muted:        #9ea3b3;
  --af-muted-soft:   #6f7585;
  --af-border:       rgba(255, 255, 255, 0.08);
  --af-border-strong:rgba(255, 255, 255, 0.16);
  --af-ease:         cubic-bezier(0.4, 0, 0.2, 1);
  --af-t:            0.25s;
}
.abacus-footer, .abacus-footer *, .abacus-footer *::before, .abacus-footer *::after { box-sizing: border-box; }
.abacus-footer ul, .abacus-footer li, .abacus-footer h3, .abacus-footer h4, .abacus-footer p, .abacus-footer nav { margin: 0; padding: 0; }
.abacus-footer ul { list-style: none; }
.abacus-footer a { text-decoration: none; color: inherit; }
.abacus-footer button, .abacus-back-to-top { cursor: pointer; border: none; background: none; font-family: inherit; color: inherit; }
.abacus-footer {
  position: relative;
  font-family: 'Plus Jakarta Sans', -apple-system, BlinkMacSystemFont, sans-serif;
  font-size: 16px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  background:
    radial-gradient(ellipse at top left, rgba(0, 82, 158, 0.22), transparent 55%),
    radial-gradient(ellipse at bottom right, rgba(138, 187, 42, 0.10), transparent 55%),
    linear-gradient(180deg, #20202c 0%, #191823 45%, #100f17 100%);
  color: var(--af-text);
  padding: 80px 0 0;
  overflow: hidden;
}
.abacus-footer::before {
  content: '';
  position: absolute; top: 0; left: 0; right: 0; height: 1px;
  background: linear-gradient(90deg, transparent, rgba(255,255,255,0.12), transparent);
}
.abacus-footer::after {
  content: '';
  position: absolute; top: -200px; right: -200px;
  width: 500px; height: 500px;
  background: radial-gradient(circle, rgba(0, 82, 158, 0.18), transparent 70%);
  pointer-events: none;
}
.abacus-footer .footer-glow {
  position: absolute; bottom: -150px; left: -150px;
  width: 400px; height: 400px;
  background: radial-gradient(circle, rgba(138, 187, 42, 0.10), transparent 70%);
  pointer-events: none;
}
.abacus-footer .footer-container { position: relative; max-width: 1280px; margin: 0 auto; padding: 0 40px; z-index: 1; }
.abacus-footer .footer-grid { display: grid; grid-template-columns: 1.4fr repeat(4, 1fr); gap: 48px; padding-bottom: 56px; }
.abacus-footer .footer-brand .logo { display: block; height: 52px; width: auto; margin-bottom: 24px; }
.abacus-footer .footer-brand p { font-size: 14px; color: var(--af-muted); line-height: 1.7; margin-bottom: 24px; max-width: 320px; }
.abacus-footer .contact-list { display: flex; flex-direction: column; gap: 12px; }
.abacus-footer .contact-list li { display: flex; align-items: flex-start; gap: 12px; font-size: 13.5px; color: var(--af-muted); line-height: 1.6; }
.abacus-footer .contact-list svg { flex: 0 0 16px; width: 16px; height: 16px; margin-top: 2px; stroke: #81bb2a; }
.abacus-footer .contact-list a:hover { color: var(--af-text); }
.abacus-footer .footer-col h4 {
  font-size: 13px; font-weight: 700; letter-spacing: 0.08em;
  text-transform: uppercase; color: #fff; margin-bottom: 20px;
  position: relative; padding-bottom: 12px;
}
.abacus-footer .footer-col h4::after {
  content: ''; position: absolute; left: 0; bottom: 0;
  width: 28px; height: 2px; background: var(--af-green); border-radius: 2px;
}
.abacus-footer .footer-col ul { display: flex; flex-direction: column; gap: 10px; }
.abacus-footer .footer-col a {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 13.5px; color: var(--af-muted);
  transition: color var(--af-t) var(--af-ease), transform var(--af-t) var(--af-ease);
}
.abacus-footer .footer-col a::before {
  content: ''; width: 0; height: 1px; background: var(--af-blue-light);
  transition: width var(--af-t) var(--af-ease);
}
.abacus-footer .footer-col a:hover { color: var(--af-green); transform: translateX(2px); }
.abacus-footer .footer-col a:hover::before { width: 8px; background: var(--af-green); }
.abacus-footer .footer-social { display: flex; gap: 10px; margin-top: 28px; }
.abacus-footer .footer-social a {
  display: inline-flex; align-items: center; justify-content: center;
  width: 38px; height: 38px;
  border: 1px solid var(--af-border-strong); border-radius: 10px;
  color: var(--af-muted); transition: all var(--af-t) var(--af-ease);
}
.abacus-footer .footer-social a:hover { color: #fff; background: var(--af-green); border-color: var(--af-green); transform: translateY(-2px); }
.abacus-footer .footer-social svg { width: 16px; height: 16px; fill: currentColor; }
.abacus-footer .footer-badges {
  display: flex; flex-wrap: wrap; gap: 14px; padding: 22px 0;
  border-top: 1px solid var(--af-border); border-bottom: 1px solid var(--af-border);
}
.abacus-footer .af-badge {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 8px 14px; font-size: 12px; font-weight: 500; color: var(--af-muted);
  background: rgba(255,255,255,0.03); border: 1px solid var(--af-border);
  border-radius: 999px;
}
.abacus-footer .af-badge-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--af-green); box-shadow: 0 0 8px var(--af-green); }
.abacus-footer .footer-bottom { display: flex; justify-content: space-between; align-items: center; padding: 22px 0 28px; flex-wrap: wrap; gap: 16px; }
.abacus-footer .footer-bottom p { font-size: 13px; color: var(--af-muted-soft); }
.abacus-footer .footer-legal { display: flex; gap: 22px; flex-wrap: wrap; }
.abacus-footer .footer-legal a { font-size: 13px; color: var(--af-muted-soft); transition: color var(--af-t) var(--af-ease); }
.abacus-footer .footer-legal a:hover { color: var(--af-text); }
.abacus-back-to-top {
  position: fixed; bottom: 28px; right: 28px;
  width: 44px; height: 44px; border-radius: 12px;
  background: var(--af-blue); color: #fff;
  display: inline-flex; align-items: center; justify-content: center;
  box-shadow: 0 10px 30px rgba(0, 82, 158, 0.4);
  opacity: 0; transform: translateY(20px); pointer-events: none;
  transition: all var(--af-t) var(--af-ease); z-index: 50;
}
.abacus-back-to-top.visible { opacity: 1; transform: translateY(0); pointer-events: auto; }
.abacus-back-to-top:hover { background: #003d75; transform: translateY(-2px); }
.abacus-footer .footer-col .toggle-icon { display: none; }

/* Footer responsive — the five-across grid never collapsed on this sheet, so
   on a phone four of the five columns were laid out past the right edge and
   clipped away by `.abacus-footer { overflow: hidden }`. Mirrors the rules the
   homepage carries in its own inline copy; site.js already wires the accordion. */
@media (max-width: 1100px) {
  .abacus-footer .footer-grid { grid-template-columns: 1fr 1fr 1fr; }
  .abacus-footer .footer-brand { grid-column: 1 / -1; }
}
@media (max-width: 720px) {
  .abacus-footer { padding-top: 56px; }
  .abacus-footer .footer-container { padding: 0 22px; }
  .abacus-footer .footer-grid { grid-template-columns: 1fr; gap: 0; padding-bottom: 24px; }
  .abacus-footer .footer-brand { padding-bottom: 32px; border-bottom: 1px solid var(--af-border); margin-bottom: 8px; }
  .abacus-footer .footer-col { border-bottom: 1px solid var(--af-border); }
  .abacus-footer .footer-col h4 {
    margin-bottom: 0; padding: 18px 0; cursor: pointer;
    display: flex; justify-content: space-between; align-items: center;
  }
  .abacus-footer .footer-col h4::after { display: none; }
  .abacus-footer .footer-col .toggle-icon {
    display: inline-block; font-size: 20px; font-weight: 400; line-height: 1;
    transition: transform var(--af-t) var(--af-ease);
  }
  .abacus-footer .footer-col.open .toggle-icon { transform: rotate(45deg); }
  .abacus-footer .footer-col ul {
    max-height: 0; overflow: hidden;
    transition: max-height 0.35s var(--af-ease), padding 0.35s var(--af-ease);
  }
  .abacus-footer .footer-col.open ul { max-height: 600px; padding: 4px 0 18px; }
  /* The last accordion row already draws a rule; the badge strip's own
     border-top would double it. */
  .abacus-footer .footer-badges { border-top: none; }
  .abacus-footer .footer-bottom { justify-content: flex-start; flex-direction: column; align-items: flex-start; }
  .abacus-footer .footer-legal { gap: 16px; }
  .abacus-back-to-top { bottom: 20px; right: 20px; }
}

/* ════════════════════════════════════════════════════════
   JOB BOARD (careers)
   ════════════════════════════════════════════════════════ */

/* ── Job detail page ─────────────────────────────────────────
   Two columns: the spec reads as a document on the left, and the facts
   a candidate re-checks while reading (shift, experience, reference)
   stay pinned on the right so "what were the hours again?" never costs
   a scroll back to the top. */
/* Direct child only - the reference is also a <b>, inline mid-sentence, and
   a blanket display:block drops it onto a line of its own. */

@media (max-width: 1024px) {
  /* Unpin on narrow screens: a sticky panel in a single column just
     covers the text it is meant to support. */
}

/* ════════════════════════════════════════════════════════
   OFFICE CARDS (contact page)
   ════════════════════════════════════════════════════════ */
/* Google Maps embed in place of the old "Map / Photo Placeholder" block.
   Google renders its logo and "Map data ©… / Terms" along the bottom of the
   frame and they must not be obscured, so the pill sits top-left, clear of
   them. On desktop the frame stays interactive - Google gates wheel-zoom
   behind ctrl, so it never steals a page scroll - but on a touch screen a
   one-finger drag pans the map instead of scrolling the page, so there it is
   inert and the pill is the way out to a real, pannable map. */

/* ════════════════════════════════════════════════════════
   EDITORIAL STATEMENT (scroll word-reveal, big whitespace)
   ════════════════════════════════════════════════════════ */

/* ════════════════════════════════════════════════════════
   USE CASES — divided columns, no card boxes (airy)
   ════════════════════════════════════════════════════════ */
/* The column count is driven by how many cards the section has:
   useCasesSection() emits `usecases--<n>`. Services and solutions
   run three; the industry "Who We Serve" blocks run four, and were
   being forced into the hardcoded three-column grid below, which
   orphaned the fourth card onto a second row still carrying the
   left divider and indent meant for an inner column.

   Dividers are ROW-aware rather than :first-child/:last-child, so
   the first card of every row loses its rule and sits flush to the
   wrap and the last one sits flush right — whatever the row count.
   Each breakpoint restates that nth-child pair for the column count
   it just set, because a 3n rule left over from a wider breakpoint
   would otherwise draw a divider mid-row.

   Base is the stacked one-column list, so the column ladders below
   are all min-width and nothing has to be unset on small screens. */

/* 2-up - the four-card industry grids get a tablet tier of their own,
   because stacking four full-width cards is a long scroll on a 768px
   screen and three columns would only orphan the fourth again. */

/* 3-up - the default for every section that is not a four-card set.
   A five- or six-card section would wrap here correctly too. */

/* 4-up - one clean row. 1080px is where four columns still leave each
   card enough measure to read; below it the 2-up tier takes over. */

/* ════════════════════════════════════════════════════════
   INTEGRATIONS — chips (airy, scannable)
   ════════════════════════════════════════════════════════ */
.integrations { display: flex; flex-wrap: wrap; justify-content: center; gap: 12px; max-width: 860px; margin: 0 auto; }
/* At desktop scale the chips are one airy row; at 375px each one eats most of
   the line, so the list breaks into a ragged one-and-a-half-per-row column.
   Smaller chips let two sit side by side and read as a set again. */
@media (max-width: 600px) {
  .integrations { gap: 8px; }
}

@media (max-width: 900px) {
  /* .usecases is one column by default now - see USE CASES above. */
  /* Trust footprint: 4 → 2 columns, dividers follow suit */
}

/* ════════════════════════════════════════════════════════
   GENERIC SECTION SPACING
   ════════════════════════════════════════════════════════ */
.sec       { padding: 96px 0 104px; }
.sec--white   { background: var(--white); }

/* ════════════════════════════════════════════════════════
   RESPONSIVE
   ════════════════════════════════════════════════════════ */
@media (max-width: 1280px) {
  .nav-wrap { padding: 0 60px; }
  .mobile-nav { left: 60px; right: 60px; }
}
@media (max-width: 1100px) {
  .nav-wrap { padding: 0 32px; }
  .nav-link { font-size: 13px; padding: 8px 11px; }
  .nav-logo { margin-right: 14px; }
  .mobile-nav { left: 32px; right: 32px; }
  .steps { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 1024px) {
  .nav-wrap { padding: 0 24px; }
  .nav-list        { display: none; }
  .nav-right       { display: none; }
  .nav-hamburger   { display: flex; }
  .navbar          { padding: 8px 8px 8px 18px; }
  .mobile-nav      { left: 24px; right: 24px; }
  .nav-logo        { transform: none; margin-right: 0; }
}
@media (max-width: 980px) {
  .split { grid-template-columns: 1fr; gap: 44px; max-width: 640px; margin: 0 auto; }
  .split__media .ph { aspect-ratio: 16 / 10; }
}
@media (max-width: 768px) {
  .nav-wrap { padding: 0 16px; top: 16px; }
  .mobile-nav { left: 16px; right: 16px; top: calc(16px + 60px + 10px); }
  .wrap { padding: 0 22px; }
  .sec { padding: 64px 0 72px; }
  .sec-head { margin-bottom: 40px; }
  .page-hero__inner { padding: 140px 26px 60px; }
  .hero-showcase { margin-top: 40px; }
  /* The banner's three-track grid holds at this width — only the type and
     gutters come down, so three stats stay on one line on a phone. */
  .cf-card { padding: 28px 22px; }
  .cta-band__panel { padding: 64px 26px; }
  .steps { grid-template-columns: 1fr; }
  /* The default 40px circle + 2x6px padding makes a 52px pill that dwarfs
     the 15px copy beside it on a 375px screen. Shrink the tokens, not the
     font: 32 + 12 = 44px, still the minimum comfortable touch target.
     .btn-primary.cta-fx pins its own 38px circle at (0,2,0), so it needs
     matching specificity or hero CTAs stay 8px taller than the rest.
     .nav-cta.cta-fx is deliberately left alone — already smaller at 28px. */
  .cta-fx { --fx-circle: 32px; --fx-lead: 20px; }
  .faq-q { font-size: 15px; padding: 18px 20px; }
}
@media (max-width: 600px) {
  /* A four-up grid still held two columns here: ~160px each, which broke card
     copy to one or two words a line and let long words ("Re-engineering") push
     the second column past the wrap. One column per row on a phone. */
  /* Cap the label so it wraps to two short lines instead of stretching the
     badge across ~85% of the image it is meant to sit on. */
  .page-hero { margin: 0 10px 10px; border-radius: 22px; }
  .page-hero__title { font-size: clamp(30px, 8vw, 38px); }
}
@media (max-width: 480px) {
  .nav-wrap { padding: 0 12px; top: 12px; }
  .navbar { height: 56px; padding: 6px 6px 6px 14px; }
  .nav-logo__mark { height: 28px !important; }
  .nav-hamburger { padding: 9px; }
  .nav-hamburger span { width: 20px; }
  .mobile-nav { left: 12px; right: 12px; top: calc(12px + 56px + 10px); border-radius: 16px; padding: 10px; }
  .mob-row { font-size: 14px; padding: 10px 12px; }
  .mob-sub a { font-size: 13px; padding: 7px 12px; }
  .hero-showcase { margin-top: 32px; }
}


/* ══════════════════════════════════════════════════════════
   LEADERSHIP PAGE (ported design)
   Scoped entirely under .ldx. The source page uses .container,
   .btn-primary, .team-grid and .tag, all of which already mean
   something else here — the prefix keeps the two stylesheets from
   reaching into each other. :root is retargeted to .ldx for the
   same reason: --navy/--text/--border/--white/--ease all exist in
   this file with different values.
   ══════════════════════════════════════════════════════════ */
.ldx {
      --primary:        #00529e;
      --primary-dark:   #003d75;
      --primary-light:  #e8f2fc;
      --secondary:      #8abb2a;
      --secondary-dark: #6a9420;
      --secondary-light:#f0f7e0;
      --navy:           #0a1628;
      --text:           #1a2332;
      --text-muted:     #5a6778;
      --border:         #dde3ec;
      --bg-soft:        #f5f8fc;
      --white:          #ffffff;

      
      --max-w: 1180px;
      --gutter: 20px;
      --col: calc((var(--max-w) - 11 * var(--gutter)) / 12);

      
      --ease: cubic-bezier(0.4, 0, 0.2, 1);
      --dur:  0.28s;}
.ldx .filter-tab {
      font-size: 13px;
      font-weight: 500;
      color: var(--text-muted);
      padding: 8px 16px;
      border-radius: 8px;
      transition: all var(--dur) var(--ease);
      cursor: pointer;
      white-space: nowrap;}
.ldx .filter-tab.active, .ldx .filter-tab:hover {
      background: var(--white);
      color: var(--primary);
      font-weight: 600;
      box-shadow: 0 1px 3px rgba(0,0,0,.08);}
.ldx .leader-card {
      position: relative;
      background: var(--white);
      border: 1px solid var(--border);
      border-radius: 16px;
      overflow: hidden;
      transition: all var(--dur) var(--ease);
      cursor: pointer;
      display: flex;
      flex-direction: column;}
.ldx .leader-card:hover {
      border-color: rgba(0,82,158,.25);
      box-shadow: 0 4px 8px -2px rgba(0,0,0,.08), 0 20px 40px -8px rgba(0,82,158,.14);
      transform: translateY(-4px);}
.ldx .leader-card.hidden { display: none;}
.ldx .tag {
      font-size: 11px;
      font-weight: 500;
      background: var(--secondary-light);
      color: var(--secondary-dark);
      border: 1px solid rgba(138,187,42,.25);
      padding: 3px 10px;
      border-radius: 100px;}
.ldx .modal__header {
      display: grid;
      grid-template-columns: 280px 1fr;
      min-height: 280px;}
.ldx .modal__visual {
      background: var(--primary-dark);
      border-radius: 24px 0 0 0;
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: flex-end;
      padding: 32px 28px;
      position: relative;
      overflow: hidden;}
.ldx .modal__visual-photo {
      position: absolute;
      inset: 0;
      width: 100%;
      height: 100%;
      object-fit: cover;
      object-position: center top;
      display: block;}
.ldx .modal__visual::after {
      content: '';
      position: absolute;
      inset: 0;
      background: linear-gradient(to top,
        rgba(0,12,40,.92) 0%,
        rgba(0,12,40,.5) 40%,
        transparent 70%);
      pointer-events: none;
      z-index: 1;}
.ldx .modal__visual-name, .ldx .modal__visual-title, .ldx .modal__visual-exp { position: relative; z-index: 2;}
.ldx .modal__visual-name {
      position: relative;
      z-index: 2;
      font-size: 20px;
      font-weight: 700;
      color: var(--white);
      text-align: center;
      letter-spacing: -.01em;
      line-height: 1.2;}
.ldx .modal__visual-title {
      position: relative;
      z-index: 2;
      font-size: 12px;
      color: rgba(255,255,255,.6);
      text-align: center;
      margin-top: 4px;}
.ldx .modal__visual-exp {
      position: relative;
      z-index: 2;
      margin-top: 10px;
      background: rgba(138,187,42,.2);
      border: 1px solid rgba(138,187,42,.35);
      color: #c8e87a;
      font-size: 11px;
      font-weight: 600;
      padding: 4px 12px;
      border-radius: 100px;}
.ldx .modal__info {
      padding: 36px 40px 36px 36px;
      border-bottom: 1px solid var(--border);}
.ldx .modal__kpi-row {
      display: grid;
      grid-template-columns: repeat(3, 1fr);
      gap: 1px;
      background: var(--border);
      border-radius: 12px;
      overflow: hidden;
      margin-bottom: 24px;}
.ldx .modal__kpi {
      background: var(--bg-soft);
      padding: 16px 20px;
      text-align: center;}
.ldx .modal__kpi-val {
      font-size: 24px;
      font-weight: 800;
      color: var(--primary);
      letter-spacing: -.02em;
      line-height: 1;}
.ldx .modal__kpi-val sup { font-size: 14px; font-weight: 600;}
.ldx .modal__kpi-lbl {
      font-size: 11px;
      color: var(--text-muted);
      font-weight: 500;
      margin-top: 4px;}
.ldx .modal__body {
      padding: 32px 40px;}
.ldx .modal__section { margin-bottom: 28px;}
.ldx .modal__section:last-child { margin-bottom: 0;}
.ldx .modal__section-title {
      font-size: 11px;
      font-weight: 600;
      letter-spacing: .1em;
      text-transform: uppercase;
      color: var(--text-muted);
      margin-bottom: 14px;
      display: flex;
      align-items: center;
      gap: 8px;}
.ldx .modal__section-title::after {
      content: '';
      flex: 1;
      height: 1px;
      background: var(--border);}
.ldx .modal__bio-text {
      font-size: 14.5px;
      color: var(--text-muted);
      line-height: 1.75;}
.ldx .modal__bio-text p + p { margin-top: 14px;}
.ldx .modal__tags {
      display: flex;
      flex-wrap: wrap;
      gap: 8px;}
.ldx .modal__tag {
      font-size: 12px;
      font-weight: 500;
      padding: 5px 14px;
      border-radius: 100px;
      border: 1px solid rgba(0,82,158,.2);
      background: var(--primary-light);
      color: var(--primary);}
.ldx .modal__tag.green {
      background: var(--secondary-light);
      border-color: rgba(138,187,42,.25);
      color: var(--secondary-dark);}
.ldx .fade-up {
      opacity: 0;
      transform: translateY(24px);
      transition: opacity 0.6s var(--ease), transform 0.6s var(--ease);}
.ldx .fade-up.visible {
      opacity: 1;
      transform: translateY(0);}
.ldx .fade-up:nth-child(2) { transition-delay: 0.1s;}
.ldx .fade-up:nth-child(3) { transition-delay: 0.2s;}
.ldx .fade-up:nth-child(4) { transition-delay: 0.3s;}
@media (max-width: 768px) {
.ldx .modal__header { grid-template-columns: 1fr;}
.ldx .modal__visual {
        border-radius: 24px 24px 0 0;
        min-height: 400px;
        padding: 0 28px 36px;
        justify-content: flex-end;}
.ldx .modal__visual::after {
        background: linear-gradient(to top,
          rgba(0,12,40,.95) 0%,
          rgba(0,12,40,.55) 38%,
          transparent 65%);}
.ldx .modal__kpi-row { grid-template-columns: repeat(3, 1fr);}
.ldx .modal__info { padding: 24px;}
.ldx .modal__body { padding: 24px;}
}
@media (max-width: 480px) {
.ldx .modal__kpi-row { grid-template-columns: 1fr;}
}
/* Integration overrides for the ported leadership design ─────────────
   The source page pairs Inter with Playfair Display for two headings.
   This site loads Plus Jakarta Sans only, so those rules were resolving
   to Times — a serif that appears nowhere else here. Both headings take
   the site's own type instead of pulling in a second webfont for them. */

/* ── in-copy SEO links (client sheet 2026-08-12): match surrounding copy ── */

/* ── legal prose (privacy policy) ── */
.prose { max-width: 800px; margin: 0 auto; font-size: 16.5px; line-height: 1.75; color: var(--ink-soft, #3c4a5d); }
.prose h2 { font-size: 26px; font-weight: 700; letter-spacing: -.02em; margin: 2.2em 0 .6em; color: var(--ink, #0e1b2c); }
.prose h3 { font-size: 20px; font-weight: 700; margin: 1.8em 0 .5em; color: var(--ink, #0e1b2c); }
.prose h4 { font-size: 17px; font-weight: 600; margin: 1.5em 0 .4em; color: var(--ink, #0e1b2c); }
.prose p { margin: 0 0 1em; }
.prose ul, .prose ol { margin: 0 0 1.2em; padding-left: 1.4em; }
.prose li { margin: 0 0 .5em; }
.prose li p { margin: 0 0 .4em; }
.prose a { color: var(--blue, #1657ff); text-decoration: underline; text-underline-offset: 3px; }
/* The legal-prose `h2 { margin: 2.2em 0 }` above also lands on the narrative
   sections of the case studies, where the h2 follows an eyebrow rather than a
   paragraph — stacking 57px of heading margin under the eyebrow's own 14px and
   leaving a hole between the two. The eyebrow is the heading's own kicker. */
.prose .sec-eyebrow + h2 { margin-top: 0; }

/* ════════════════════════════════════════════════════════
   HUB LISTING CARDS (/services/ and /solutions/)
   Image cards grouped under category headers - light-surface
   counterpart of .case-tile, reusing its media treatment.
   ════════════════════════════════════════════════════════ */
/* The solutions hub inherits its child pages' hero art, which is a set of
   device mockups rendered on transparency rather than photography. `cover`
   sliced the laptop out of frame on every card (and left an all-white band at
   phone widths); these need to be shown whole, on a tinted plate. */

/* 2- and 4-item hub categories sit in two wider columns so rows stay full */

/* ── CAREERS: APPLICATION FORM ─────────────────────────────── */
/* ── one height for every single-line control ──────────────────────
   Identical padding is not identical height: a <select> and an
   <input type="date"> each carry their own intrinsic line box, so the
   same 11px padding rendered 44px for the two dropdowns and the date
   and 42px for every text field beside them. Two pixels is small
   enough to look like a mistake rather than a choice, and it read as
   one — the dropdowns sat lower than the fields they share a row with.
   State the height instead of hoping three widget types agree on it.
   File and checkbox inputs are their own controls and keep out of it. */

/* The searchable city box is a text input dressed as a dropdown, so it
   needs the same arrow as the plain ones or the two sit side by side
   looking like different controls. One chevron, drawn once. */
/* the hidden original behind the enhanced city box must not grow one */
.af-field select.ss__native { height: 1px; background-image: none; padding: 0; }
.af-file__text { font-size: 14px; color: var(--muted); line-height: 1.4; }
.af-file__text b { color: var(--text); font-weight: 600; }
.af-file__text small { display: block; font-size: 12px; color: var(--muted); margin-top: 3px; }
/* .btn-primary is built for the dark hero (translucent white on navy);
   on this light section it needs to be a solid brand button instead. */
@keyframes afspin { to { transform: rotate(360deg); } }
.af-msg {
  margin-top: 16px; font-size: 14px; line-height: 1.6; padding: 11px 14px; border-radius: 10px;
  background: rgba(0,82,158,.06); color: var(--blue-dark, #003c74);
}

/* ══════════════════════════════════════════════════════════════════
   SEARCHABLE SELECT (apply form → current city)

   The native <select> stays in the DOM holding the value and is hidden
   only once JS has replaced it, so with the script blocked the form
   still shows a working dropdown rather than nothing at all.
   ══════════════════════════════════════════════════════════════════ */
.ss { position: relative; display: block; min-width: 0; }
.ss__native { position: absolute; opacity: 0; width: 1px; height: 1px; pointer-events: none; }
.ss__input { width: 100%; padding-right: 38px !important; cursor: text; }
.ss__caret {
  position: absolute; right: 12px; top: 50%; transform: translateY(-50%);
  width: 18px; height: 18px; color: var(--muted, #5b6b7b); pointer-events: auto;
  cursor: pointer; display: grid; place-items: center;
}
.ss__caret svg { width: 18px; height: 18px; transition: transform .16s ease; }
.ss.is-open .ss__caret svg { transform: rotate(180deg); }

.ss__list {
  position: absolute; z-index: 60; top: calc(100% + 6px); left: 0; right: 0;
  max-height: 268px; overflow-y: auto; margin: 0; padding: 6px;
  list-style: none; background: #fff; border: 1px solid var(--border);
  border-radius: 12px; box-shadow: 0 16px 44px rgba(10, 22, 40, .16);
}
.ss__list[hidden] { display: none; }
.ss__opt {
  padding: 9px 12px; border-radius: 8px; font-size: 14.5px; line-height: 1.35;
  cursor: pointer; color: var(--text);
}
.ss__opt.is-active, .ss__opt:hover { background: var(--blue); color: #fff; }
.ss__group {
  padding: 9px 12px 5px; font-size: 11.5px; font-weight: 800; letter-spacing: .06em;
  text-transform: uppercase; color: var(--muted, #5b6b7b); pointer-events: none;
}
.ss__none { padding: 12px; font-size: 13.5px; color: var(--muted, #5b6b7b); }

/* on a phone the list must not run off the bottom of the viewport */
@media (max-width: 640px) { .ss__list { max-height: 46vh; } }
