/* =========================================================
   SkillLab — Design tokens
   ========================================================= */
:root{
  --navy-950:#06102a;
  --navy-925:#081431;
  --navy-900:#03194e;
  --navy-810:#091a41;
  --navy-800:#0d1c40;
  --blue-600:#2361ff;
  --blue-500:#2a64f6;
  --blue-200:#c4d4fd;
  --blue-100:#d4e0fd;
  --blue-tint:#bdd0ff;
  --neutral-900:#242d35;
  --neutral-800:#36424a;
  --border-default:#cfd5dc;
  --border-dark-subtle:#162958;
  --border-dark-mid:#425da0;
  --border-testimonial:#cce0ff;
  --bg-primary:#f3f4f6;
  --card-tint-a:#f9fbff;
  --card-tint-b:#f0f4ff;
  /* Solutions page: the glow behind the assembly diagram. Needs its own
     token rather than reusing --card-tint-b, which is light-only and has
     no dark override. */
  --assembly-glow:#eef3ff;
  --white:#ffffff;

  /* The brand blue expressed as an r,g,b triplet, for the rgba() glows that
     can't take a hex. Solution pages override these (see "Per-solution
     accent" at the end of this file); on index.html they stay brand blue,
     so tokenising them changed nothing visually. */
  --accent-rgb:35,97,255;
  --spark-color:#9fc0ff;
  --spark-rgb:159,192,255;
  --hero-wash-rgb:20,42,94;

  --font-sans:'Noto Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif;

  --ease-premium: cubic-bezier(.16,1,.3,1);
  /* Reveal-on-scroll duration: deliberately unhurried. At the old 1.12s a
     normal scroll speed would carry a section most of the way into view
     before the fade/slide finished, so it read as "already settled"
     rather than as motion you could actually watch happen. */
  --dur-md: 1.7s;
  --dur-sm: 0.7s;
  /* Grouped cards ([data-reveal-item] — value props, stats, tabs, case
     cards, footer columns) get their own shorter duration instead of
     inheriting --dur-md. At 1.7s each, a 150ms stagger barely separates
     them — item 2 starts while item 1 is only 9% through its fade, so a
     row of cards reads as one soft blob of motion instead of a visible
     one-after-another sequence. Short enough that each card is mostly
     done before the next one starts. */
  --dur-item: 0.7s;

  --pad-section: clamp(24px, 8vw, 150px);
  --gap-section: clamp(48px, 8vw, 80px);
  --radius-lg: 16px;
  --radius-md: 12px;
  --radius-sm: 8px;
  --max-width: 1400px;

  /* Theme-aware surfaces — the hero/modular/footer stay permanently dark by
     design in both modes; only the "light" sections swap here. */
  color-scheme: light;
  --surface-page:#ffffff;
  --surface-header:rgba(255,255,255,.7);
  --surface-header-scrolled:rgba(255,255,255,.85);
  --surface-muted:#f3f4f6;
  --surface-card:#ffffff;
  --value-card-bg:#f9fbff;
  --text-heading:#03194e;
  --text-body:#242d35;
  --text-muted:#36424a;
  --border-subtle:#cfd5dc;
  --border-testimonial-c:#cce0ff;
  --header-shadow:rgba(3,25,78,.06);
  --card-shadow:rgba(3,25,78,.12);
  --logo-filter:none;
  --stats-number:#242d35;
  --stats-label:#4a5b67;
  --stats-card-border:#d3e3fc;
  --stats-card-bg:linear-gradient(145deg, #ffffff 0%, #f7faff 100%);
  /* Custom-property (not a plain url()) so the dark override below can
     swap the whole value, chevron color included — a background-image
     can't be recolored with currentColor/filter without extra markup. */
  --select-chevron:url('data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="none"%3E%3Cpath d="M4 6L8 10L12 6" stroke="%23425DA0" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/%3E%3C/svg%3E');
}

:root[data-theme="dark"]{
  color-scheme: dark;
  --assembly-glow:rgba(var(--accent-rgb),.14);
  --surface-page:#0a0f1c;
  --surface-header:rgba(10,15,28,.72);
  --surface-header-scrolled:rgba(10,15,28,.9);
  --surface-muted:#0d1322;
  --surface-card:#111a2e;
  --value-card-bg:#111a2e;
  --text-heading:#eef2fb;
  --text-body:#cbd4e6;
  --text-muted:#93a2bd;
  --border-subtle:#26314a;
  --border-testimonial-c:#233a63;
  --header-shadow:rgba(0,0,0,.3);
  --card-shadow:rgba(0,0,0,.4);
  --logo-filter:brightness(0) invert(1);
  --stats-number:#eef2fb;
  --stats-label:#93a2bd;
  --stats-card-border:#26314a;
  --stats-card-bg:#111a2e;
  --select-chevron:url('data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="none"%3E%3Cpath d="M4 6L8 10L12 6" stroke="%2393A2BD" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/%3E%3C/svg%3E');
}

/* =========================================================
   Reset
   ========================================================= */
*,*::before,*::after{box-sizing:border-box;}
html{scroll-behavior:smooth;-webkit-text-size-adjust:100%;}
body{
  margin:0;
  font-family:var(--font-sans);
  color:var(--text-body);
  background:var(--surface-page);
  transition:background-color 0.56s ease, color 0.56s ease;
  -webkit-font-smoothing:antialiased;
  text-rendering:optimizeLegibility;
}
img{max-width:100%;display:block;}
a{color:inherit;text-decoration:none;}
ul{list-style:none;margin:0;padding:0;}
h1,h2,h3,p{margin:0;}
button{font:inherit;cursor:pointer;}
input{font:inherit;}
.sr-only{
  position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;
  clip:rect(0,0,0,0);white-space:nowrap;border:0;
}

@media (prefers-reduced-motion: reduce){
  html{scroll-behavior:auto;}
  *,*::before,*::after{animation-duration:.001ms !important;animation-iteration-count:1 !important;transition-duration:.001ms !important;scroll-behavior:auto !important;}
}

/* =========================================================
   Reveal-on-scroll system
   ========================================================= */
[data-reveal],
[data-reveal-item]{
  opacity:0;
  transition-delay:var(--d, 0ms);
  will-change:opacity, transform;
}
/* Scoped to [data-reveal] specifically — [data-reveal-group] containers
   also carry a data-reveal-type attribute (read by JS for their children's
   stagger), and an unscoped selector here would match the group itself,
   leaving it permanently offset since a group never gets .is-visible. */
/* Travel distance bumped alongside the longer duration — a slower
   animation over a short 28px hop reads as sluggish rather than
   graceful, so the motion needs more room to actually be seen. */
[data-reveal]{transition:opacity var(--dur-md) var(--ease-premium), transform var(--dur-md) var(--ease-premium);}
[data-reveal][data-reveal-type="up"]{transform:translateY(44px);}
[data-reveal][data-reveal-type="fade"]{transform:none;}
[data-reveal][data-reveal-type="fade-scale"]{transform:scale(.94);}
/* Shorter --dur-item (not --dur-md) so a stagger between siblings actually
   reads as one-after-another instead of one long overlapping blur. This is
   the FALLBACK for any [data-reveal-item] whose component has no hover
   transition of its own (e.g. .footer-col).
   Components that DO declare their own `transition` shorthand for a hover
   effect (.value-card, .stat-card, .case-card, .badge) merge opacity +
   transform into THAT shorthand directly instead of relying on this rule
   — a shorthand `transition` always wins or loses as a whole for equal
   specificity, so a later, unrelated shorthand here would otherwise
   silently discard this rule's opacity entry and its --d stagger delay
   entirely (this is exactly what caused cards to pop in sync instead of
   staggered — not a duration/timing tuning issue). !important would
   "fix" that for opacity/transform specifically, but at the cost of
   silently breaking that OTHER component's own box-shadow/border-color/
   background-color hover transitions instead (same root cause, same
   winner-takes-all behavior, just moved to different properties) — so
   any *new* card component with its own hover transition needs to merge
   opacity + transform into it by hand, the same way the four above do;
   see the comment on .value-card for the exact pattern to copy. */
[data-reveal-item]{
  transform:translateY(34px);
  transition:opacity var(--dur-item) var(--ease-premium), transform var(--dur-item) var(--ease-premium);
}

[data-reveal].is-visible,
[data-reveal-item].is-visible{
  opacity:1;
  transform:none;
}

/* =========================================================
   Buttons
   ========================================================= */
.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:8px;
  padding:20px 24px;
  border-radius:var(--radius-sm);
  font-weight:700;font-size:18px;line-height:24px;
  border:1px solid transparent;
  transition:transform 0.35s var(--ease-premium), filter 0.35s ease, box-shadow 0.49s ease, background-color 0.35s ease;
}
.btn-primary{
  background:var(--blue-500);color:#fff;
}
.btn-primary:hover{filter:brightness(1.08);transform:translateY(-2px);}
.btn-primary:active{transform:translateY(0);}
.btn-glow{box-shadow:0 0 8px rgba(var(--accent-rgb),.6);}
.btn-glow:hover{box-shadow:0 0 22px rgba(var(--accent-rgb),.8);}
.btn-outline{
  background:transparent;color:#fff;border-color:var(--blue-100);
}
.btn-outline:hover{background:rgba(255,255,255,.08);transform:translateY(-2px);}
.header-cta .btn{padding:11px 18px;font-size:15px;}

/* =========================================================
   Header
   ========================================================= */
.site-header{
  position:sticky;top:0;z-index:100;
  background:var(--surface-header);
  backdrop-filter:blur(0px);
  border-bottom:1px solid transparent;
  transition:background-color 0.49s ease, border-color 0.49s ease, backdrop-filter 0.49s ease, box-shadow 0.49s ease;
}
.site-header.is-scrolled{
  background:var(--surface-header-scrolled);
  backdrop-filter:blur(14px);
  border-bottom-color:var(--border-subtle);
  box-shadow:0 8px 24px var(--header-shadow);
}
.header-inner{
  max-width:var(--max-width);margin:0 auto;
  display:flex;align-items:center;justify-content:space-between;
  padding:16px var(--pad-section);
  transition:padding 0.49s var(--ease-premium);
}
.site-header.is-scrolled .header-inner{padding-top:11px;padding-bottom:11px;}
.brand{display:inline-flex;}
.brand img{transition:transform 0.42s var(--ease-premium);}
.brand:hover img{transform:scale(1.03);}

/* Two-tone raster logo (navy + gradient blue "AI") can't use the old
   single-color invert-filter trick — a CSS invert would scramble its hues
   instead of just flipping lightness. Ship both a color and a pre-made
   white version instead, and swap which is visible by theme, the same way
   the sun/moon toggle icons already do. */
/* Plain display toggling (not the crossfade-style absolute positioning
   this started as) — there's no animated transition between the two
   images, just a hard swap on theme change, and only one is ever in flow
   at a time, so the container sizes itself correctly from whichever one
   is actually showing. */
.logo-swap{display:inline-flex;}
.logo-swap .logo-white{display:none;}
[data-theme="dark"] .logo-swap .logo-color{display:none;}
[data-theme="dark"] .logo-swap .logo-white{display:block;}

.header-actions{display:flex;align-items:center;gap:12px;}

.nav-desktop{display:flex;align-items:center;gap:24px;}
.nav-link{
  display:inline-flex;align-items:center;gap:2px;
  background:none;border:0;padding:0;
  font-size:15px;color:var(--text-heading);
  position:relative;
}
.nav-link.is-active{font-weight:800;}
.nav-link:not(.is-active)::after{
  content:"";position:absolute;left:0;right:0;bottom:-6px;height:2px;
  background:var(--blue-500);transform:scaleX(0);transform-origin:left;
  transition:transform 0.42s var(--ease-premium);
}
.nav-link:not(.is-active):hover::after{transform:scaleX(1);}

/* Chevron icon: the exported asset is a right-pointing arrow (Figma composes
   it into a chevron-down via rotate+flip at render time); a fixed square
   wrapper keeps the rotated footprint centered without stretching it. */
.chevron-wrap{
  width:16px;height:16px;flex-shrink:0;
  display:inline-flex;align-items:center;justify-content:center;
  transition:transform 0.35s ease;
}
.chevron-icon{width:7px;height:11.5px;transform:rotate(-90deg) scaleX(-1);display:block;filter:var(--logo-filter);transition:filter 0.56s ease;}
/* "Components & APIs" has no real menu yet — kept its old decorative
   hover-nudge (distinct from the Solutions dropdown's open-state rotate
   below) so it isn't left with no hover feedback at all. */
.nav-dropdown--placeholder:hover .chevron-wrap{transform:translateY(2px);}

/* Solutions dropdown. Opens on hover/focus-within for mouse and keyboard
   users, AND toggles via .is-open (set by initNavDropdown() in script.js)
   for click/tap — :hover alone doesn't fire on click in every browser
   (notably Safari doesn't focus a clicked button), so relying on it only
   would leave a click-only user unable to open this at all. */
.nav-item{position:relative;}
.nav-dropdown-menu{
  position:absolute;top:100%;left:50%;
  transform:translateX(-50%);
  width:300px;
  /* Padding, not a positioned gap, bridges the space between the button
     and the menu below — a real gap (e.g. top:calc(100% + 8px)) would be
     a dead zone the cursor has to cross without hovering anything,
     closing the menu before it arrives. Padding stays part of this
     element's own hoverable box, so there's no dead zone at all. */
  padding-top:12px;
  opacity:0;visibility:hidden;pointer-events:none;
}
.nav-dropdown-menu-inner{
  background:var(--surface-card);border:1px solid var(--border-subtle);
  border-radius:var(--radius-md);box-shadow:0 20px 48px var(--card-shadow);
  padding:10px;display:flex;flex-direction:column;gap:2px;
  transform:translateY(-8px);
  transition:opacity 0.28s ease, transform 0.35s var(--ease-premium);
}
.nav-item:hover .nav-dropdown-menu,
.nav-item:focus-within .nav-dropdown-menu,
.nav-item.is-open .nav-dropdown-menu{
  opacity:1;visibility:visible;pointer-events:auto;
}
.nav-item:hover .nav-dropdown-menu-inner,
.nav-item:focus-within .nav-dropdown-menu-inner,
.nav-item.is-open .nav-dropdown-menu-inner{
  transform:translateY(0);
}
.nav-item:hover .chevron-wrap,
.nav-item:focus-within .chevron-wrap,
.nav-item.is-open .chevron-wrap{transform:rotate(180deg);}
.nav-dropdown-item{
  display:block;padding:12px 14px;border-radius:var(--radius-sm);
  font-size:15px;font-weight:600;color:var(--text-body);
  transition:background-color 0.2s ease, color 0.2s ease;
}
.nav-dropdown-item:hover,
.nav-dropdown-item:focus-visible{background:var(--surface-muted);color:var(--blue-500);}

/* Theme toggle */
.theme-toggle{
  display:inline-flex;align-items:center;justify-content:center;
  width:38px;height:38px;border-radius:50%;flex-shrink:0;
  border:1px solid var(--border-subtle);background:transparent;color:var(--text-heading);
  transition:background-color 0.42s ease, border-color 0.42s ease, transform 0.56s var(--ease-premium), color 0.42s ease;
}
.theme-toggle:hover{background:rgba(42,100,246,.1);transform:rotate(-14deg);}
.theme-toggle svg{width:18px;height:18px;}
.theme-toggle .icon-moon{display:none;}
[data-theme="dark"] .theme-toggle .icon-sun{display:none;}
[data-theme="dark"] .theme-toggle .icon-moon{display:block;}

.nav-toggle{
  display:none;flex-direction:column;justify-content:center;gap:5px;
  width:40px;height:40px;background:none;border:0;
}
.nav-toggle span{display:block;width:22px;height:2px;background:var(--text-heading);transition:transform 0.42s var(--ease-premium), opacity 0.42s ease, background-color 0.42s ease;margin:0 auto;}
.nav-toggle[aria-expanded="true"] span:nth-child(1){transform:translateY(7px) rotate(45deg);}
.nav-toggle[aria-expanded="true"] span:nth-child(2){opacity:0;}
.nav-toggle[aria-expanded="true"] span:nth-child(3){transform:translateY(-7px) rotate(-45deg);}

.nav-mobile{
  display:none;
  max-height:0;overflow:hidden;
  transition:max-height 0.56s var(--ease-premium);
}
/* Was a flat 460px — enough for the old 4-link list, but not once
   Solutions can expand into 6 extra sub-links on top of that. A generous
   viewport-relative cap plus internal scroll means it can never clip
   the bottom of the menu (CTA button included) on any real device,
   without needing to hand-tune a taller magic number. Only overrides
   overflow-y (the base rule's overflow:hidden still holds overflow-x),
   so collapsed state still hides everything as before. */
.nav-mobile.is-open{max-height:min(80vh, 620px);overflow-y:auto;}
.nav-mobile-inner{display:flex;flex-direction:column;gap:4px;padding:0 24px 24px;}
.nav-mobile .nav-link{padding:12px 4px;font-size:18px;}
.nav-mobile .btn{margin-top:10px;}
.nav-mobile-theme{
  display:flex;align-items:center;gap:10px;
  padding:12px 4px;margin-top:4px;border-top:1px solid var(--border-subtle);
  color:var(--text-heading);font-size:15px;
}
.nav-mobile-theme .theme-toggle{margin-left:auto;}

/* Solutions accordion inside the mobile menu — same 6 links as the
   desktop dropdown, expand/collapse in place since there's no hover on
   touch. */
.nav-mobile-toggle{width:100%;justify-content:space-between;}
.nav-mobile-toggle .chevron-wrap{transition:transform 0.35s var(--ease-premium);}
.nav-mobile-group.is-open .nav-mobile-toggle .chevron-wrap{transform:rotate(180deg);}
.nav-mobile-submenu{
  max-height:0;overflow:hidden;
  display:flex;flex-direction:column;
  transition:max-height 0.42s var(--ease-premium);
}
.nav-mobile-group.is-open .nav-mobile-submenu{max-height:360px;}
.nav-mobile-sublink{
  padding:10px 4px 10px 18px;font-size:16px;color:var(--text-muted);
  border-left:2px solid var(--border-subtle);margin-left:2px;
  transition:color 0.2s ease, border-color 0.2s ease;
}
.nav-mobile-sublink:hover,
.nav-mobile-sublink:focus-visible{color:var(--blue-500);border-color:var(--blue-500);}

/* =========================================================
   Hero
   ========================================================= */
.hero{
  position:relative;overflow:hidden;
  background:linear-gradient(116deg, #06102a 0%, #142a5e 100%);
}

/* Background: the same fine blue-line mesh used on the modular panel and
   value-prop section, faded out toward the edges so it reads as ambient
   texture rather than a hard-edged tile. */
.hero-mesh{
  position:absolute;inset:0;z-index:0;
  background-image:url('assets/bg-pattern-panel.png');
  background-size:200px 200px;
  opacity:.16;
  -webkit-mask-image:radial-gradient(120% 100% at 50% 40%, black 40%, transparent 100%);
  mask-image:radial-gradient(120% 100% at 50% 40%, black 40%, transparent 100%);
}

/* Sparkling "data" lines: thin bright streaks that travel across the mesh,
   one axis at a time, echoing the grid they move on. Pure CSS so it stays
   cheap — no video decode, no canvas. */
.hero-sparks{
  position:absolute;inset:0;z-index:1;overflow:hidden;pointer-events:none;
}
.spark{
  position:absolute;opacity:0;
  mix-blend-mode:screen;
  will-change:transform,opacity;
}
.spark-h{
  top:var(--pos);left:-24%;width:24%;height:1px;
  background:linear-gradient(90deg, transparent, var(--spark-color) 50%, transparent);
  box-shadow:0 0 6px 1px rgba(var(--spark-rgb),.7);
  animation:spark-travel-h var(--dur) linear infinite;
  animation-delay:var(--delay);
}
.spark-v{
  left:var(--pos);top:-24%;height:24%;width:1px;
  background:linear-gradient(180deg, transparent, var(--spark-color) 50%, transparent);
  box-shadow:0 0 6px 1px rgba(var(--spark-rgb),.7);
  animation:spark-travel-v var(--dur) linear infinite;
  animation-delay:var(--delay);
}
@keyframes spark-travel-h{
  0%{transform:translateX(0);opacity:0;}
  10%{opacity:.85;}
  90%{opacity:.85;}
  100%{transform:translateX(516%);opacity:0;}
}
@keyframes spark-travel-v{
  0%{transform:translateY(0);opacity:0;}
  10%{opacity:.85;}
  90%{opacity:.85;}
  100%{transform:translateY(516%);opacity:0;}
}
@media (prefers-reduced-motion: reduce){
  .spark{animation:none;display:none;}
}

/* A soft navy scrim keeps the mesh/sparks subordinate to the headline —
   lighter than the old video scrim since there's no footage to tame, just
   brand-consistent depth and a gentle vignette toward the copy. */
.hero-tint{
  position:absolute;inset:0;z-index:2;
  background:
    radial-gradient(60% 55% at 50% 42%, rgba(6,16,42,.35) 0%, rgba(4,11,30,.55) 60%, rgba(4,11,30,.72) 100%),
    linear-gradient(116deg, rgba(6,16,42,.3) 0%, rgba(var(--hero-wash-rgb),.22) 100%);
}

.hero-inner{
  position:relative;z-index:3;
  max-width:var(--max-width);margin:0 auto;
  display:flex;align-items:center;justify-content:center;
  padding:var(--pad-section);
  min-height:min(85vh, 760px);
}
/* Placeholder "solution coming soon" page reuses the hero's mesh/spark
   background for brand consistency, but has far less to say than the
   real homepage hero — a shorter section keeps it from feeling like an
   empty stretch of background. */
.wip-hero .hero-inner{min-height:min(64vh, 560px);}
.hero-copy{
  width:100%;max-width:760px;
  display:flex;flex-direction:column;align-items:center;gap:40px;
  text-align:center;
}
.hero-copy h1{
  display:flex;flex-direction:column;align-items:center;
  font-size:clamp(30px, 4vw, 44px);
  letter-spacing:-1px;color:#fff;
  text-shadow:0 4px 28px rgba(0,0,0,.4);
}
.hero-copy h1 .light{font-weight:300;line-height:1.25;}
.hero-copy h1 .bold{font-weight:700;line-height:1.25;}
.hero-sub{color:var(--blue-tint);font-size:20px;line-height:1.5;text-shadow:0 2px 16px rgba(0,0,0,.35);}
.hero-actions{display:flex;gap:16px;flex-wrap:wrap;justify-content:center;}

/* Typewriter headline */
/* min-height pinned to the .bold line-height on purpose: as an inline-flex
   container this doesn't size itself from line-height the way flowed text
   would, so once the text is fully erased only the (shorter) cursor is left
   to determine the row's height — the row quietly shrinks a few px until
   typing resumes and the text's line-height takes back over. Pinning it
   stops that shift outright. */
.typewriter{display:inline-flex;align-items:baseline;min-height:1.25em;}
.typewriter-text{white-space:pre-wrap;}
.typewriter-cursor{
  display:inline-block;width:3px;height:.85em;margin-left:5px;
  background:currentColor;border-radius:1px;
  animation:caretBlink 1s step-end infinite;
  vertical-align:text-bottom;
}
@keyframes caretBlink{0%,49%{opacity:1;}50%,100%{opacity:0;}}
@media (prefers-reduced-motion: reduce){
  .typewriter-cursor{animation:none;opacity:1;}
}

/* =========================================================
   Trusted-by strip
   ========================================================= */
.trusted{
  background:var(--surface-muted);
  transition:background-color 0.56s ease;
  padding:28px 19px;
  display:flex;flex-direction:column;align-items:center;gap:16px;
}
.trusted-label{font-size:clamp(20px,2.4vw,28px);color:var(--text-body);}

/* Seven marks is too many to wrap gracefully at every width, and the
   Figma update calls for continuous horizontal motion rather than a
   static row. Two identical <ul> tracks sit side by side inside a
   flex wrapper; animating the wrapper left by exactly one track's
   width loops seamlessly since the second track picks up pixel-for-
   pixel where the first left off. Edges fade via mask so logos ease
   in/out of view instead of hard-cutting at the container bounds. */
.trusted-marquee{
  width:100%;max-width:1400px;overflow:hidden;
  -webkit-mask-image:linear-gradient(90deg, transparent 0, black 64px, black calc(100% - 64px), transparent 100%);
  mask-image:linear-gradient(90deg, transparent 0, black 64px, black calc(100% - 64px), transparent 100%);
}
.trusted-marquee-track{
  display:flex;width:max-content;
  animation:trusted-scroll 34s linear infinite;
}
.trusted-marquee:hover .trusted-marquee-track{animation-play-state:paused;}
/* The track holds two back-to-back copies of the same list, so it is
   exactly double the width of one copy — shifting by -50% (not -100%,
   which would scroll clean past both copies and flash empty space
   before snapping back) lands precisely on the second copy's start,
   which is pixel-identical to the first copy's start. Loop never runs
   out of logos to show. */
@keyframes trusted-scroll{
  0%{transform:translateX(0);}
  100%{transform:translateX(-50%);}
}
.trusted-logos{
  display:flex;flex-wrap:nowrap;gap:clamp(40px,6vw,72px);
  align-items:center;justify-content:flex-start;
  padding-right:clamp(40px,6vw,72px);
}
.trusted-logos li{
  height:34px;display:flex;align-items:center;
  filter:grayscale(1);opacity:.75;
  transition:filter 0.49s ease, opacity 0.49s ease, transform 0.49s ease;
}
.trusted-logos li:hover{filter:grayscale(0);opacity:1;transform:translateY(-2px);}
/* Dark theme's trusted strip sits on a near-black surface, so a
   grayscaled navy/black mark (World Bank, EBRD, the Ukraine ministry
   icon) would nearly vanish — invert flips it light. Deliberately no
   brightness boost here: a previous version pushed brightness to 1.7
   on top of the invert, which blew the Argentina seal's engraved
   white-on-navy linework out to a blank white disc. Plain grayscale +
   invert keeps that internal contrast intact. */
[data-theme="dark"] .trusted-logos li{filter:grayscale(1) invert(1);}
[data-theme="dark"] .trusted-logos li:hover{filter:grayscale(0) invert(0);}
.trusted-logos img{height:100%;width:auto;max-width:150px;object-fit:contain;}

@media (prefers-reduced-motion: reduce){
  .trusted-marquee-track{animation:none;width:100%;}
  .trusted-marquee-track .trusted-logos:nth-child(2){display:none;}
  .trusted-marquee{-webkit-mask-image:none;mask-image:none;}
  .trusted-logos{flex-wrap:wrap;justify-content:center;padding-right:0;}
}

/* =========================================================
   Impact stats — light, theme-aware like values/cases (this one
   reads as a bright "proof" panel, not a dark statement section).
   Sizing/spacing/colors match the Figma spec (node 5104:8041)
   directly rather than the site's general clamp scale, since this
   section's numbers are deliberately much larger than anything
   else on the page.
   ========================================================= */
.stats{
  position:relative;
  background:var(--surface-page);
  transition:background-color .56s ease;
  padding:var(--pad-section);
}
.stats-head{
  display:flex;flex-direction:column;align-items:flex-start;
  max-width:1100px;margin:0 auto clamp(48px,8vw,100px);
}
.stats-logo{margin:0 0 16px;}
.stats-logo img{display:block;}
.stats-heading{
  font-size:clamp(28px,4.6vw,54px);font-weight:300;line-height:1.2;
  text-align:left;
  background:linear-gradient(108deg, #030f4a 4%, #2a64f6 85%);
  -webkit-background-clip:text;background-clip:text;color:transparent;
}
/* The navy start of the light-mode gradient reads fine on white but is
   nearly invisible against the dark surface — swap to the same
   white-to-light-blue treatment the other dark sections already use. */
[data-theme="dark"] .stats-heading{
  background:linear-gradient(159deg,#fff 0%,#97b4ff 87%);
  -webkit-background-clip:text;background-clip:text;
}
.stats-grid{
  max-width:1100px;margin:0 auto;
  display:flex;flex-wrap:wrap;gap:32px;justify-content:flex-start;
}
.stat-card{
  flex:0 0 auto;
  background:var(--stats-card-bg);border:1px solid var(--stats-card-border);
  border-radius:20px;
  padding:28px;text-align:left;
  /* opacity/transform merged in for the same reason as .value-card —
     see the comment there. */
  transition:
    opacity var(--dur-item) var(--ease-premium) var(--d,0ms),
    transform var(--dur-item) var(--ease-premium) var(--d,0ms),
    box-shadow .55s var(--ease-premium) 0s,
    border-color .5s ease 0s,
    background-color .5s ease 0s;
}
.stat-card:hover{
  transform:translateY(-6px);border-color:var(--blue-200);
  box-shadow:0 16px 32px var(--card-shadow);
}
.stat-number{
  display:flex;align-items:baseline;justify-content:flex-start;flex-wrap:wrap;
  font-size:clamp(34px,4.2vw,58px);font-weight:700;line-height:1;
  font-variant-numeric:tabular-nums;
  color:var(--stats-number);
}
.stat-label{margin-top:12px;font-size:clamp(18px,1.8vw,24px);color:var(--stats-label);}
/* The "+"/"K" suffix reads lighter than the digits in the source design —
   a bold 58px number with a Light-weight "+" trailing it. */
.odo-static{font-weight:400;}

/* Odometer digit reels: each reel is a 1em-tall window (overflow:hidden)
   onto a strip of "0123456789" repeated several times. Landing position is
   always a few full loops plus the target digit, so every reel visibly
   spins — including ones whose target digit is 0 — rather than only the
   digits that "need" to move. Built by JS from each stat's data-value
   (digits become reels, anything else — commas, "+", "K" — becomes a
   static .odo-static glyph alongside them). */
.odo-digit{
  position:relative;display:inline-block;overflow:hidden;
  height:1em;width:.6em;
}
.odo-strip{
  display:flex;flex-direction:column;
  transform:translateY(0);
  transition:transform 1.5s cubic-bezier(.16,.85,.2,1);
  transition-delay:var(--odo-delay, 0ms);
}
.odo-strip span{display:block;height:1em;line-height:1em;}
.odo-static{display:inline-block;}

/* =========================================================
   Value props
   ========================================================= */
.values{position:relative;padding:var(--gap-section) var(--pad-section);}
.values-bg{
  position:absolute;inset:0;z-index:0;
  background-image:url('assets/bg-grid-values.png');
  background-size:200px 200px;
  opacity:.1;
  -webkit-mask-image:linear-gradient(to bottom, black, transparent);
  mask-image:linear-gradient(to bottom, black, transparent);
}
.section-head{
  position:relative;z-index:1;
  max-width:900px;margin:0 auto var(--gap-section);
  text-align:center;display:flex;flex-direction:column;gap:16px;
}
.section-head h2{font-size:clamp(24px,2.8vw,36px);font-weight:700;color:var(--text-heading);}
.section-head p{font-size:clamp(15px,1.4vw,18px);color:var(--text-muted);line-height:1.5;}
.values .section-head{margin-bottom:48px;}

.value-cards{
  position:relative;z-index:1;
  max-width:960px;margin:0 auto;
  display:grid;grid-template-columns:repeat(3,1fr);gap:20px;
}
.value-card{
  background:var(--value-card-bg);border:1px solid var(--border-subtle);
  border-radius:var(--radius-lg);
  padding:32px 24px;display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:18px;text-align:center;aspect-ratio:3/4.2;
  /* opacity/transform merged in here (rather than left to the generic
     [data-reveal-item] rule) specifically so the reveal stagger
     (var(--d)) survives: this shorthand and that rule's both apply at
     equal specificity, and a shorthand always wins/loses as a whole
     — the later one here would otherwise silently discard the earlier
     rule's transition-delay for every property, box-shadow included,
     which is exactly what caused cards to pop in sync instead of
     staggered. Explicit 0s delay on the hover-only properties keeps
     hover feedback instant rather than inheriting the reveal stagger. */
  transition:
    opacity var(--dur-item) var(--ease-premium) var(--d,0ms),
    transform var(--dur-item) var(--ease-premium) var(--d,0ms),
    box-shadow 0.56s var(--ease-premium) 0s,
    border-color 0.56s ease 0s,
    background-color 0.56s ease 0s;
}
.value-card:hover{transform:translateY(-8px);box-shadow:0 24px 48px var(--card-shadow);border-color:var(--blue-200);}
.value-icon{position:relative;width:120px;height:86px;flex-shrink:0;}
.value-icon img{position:absolute;inset:0;width:100%;height:100%;object-fit:contain;transition:transform 0.7s var(--ease-premium);}
.value-card:hover .value-icon img{transform:translateY(-4px) scale(1.03);}
.value-card h3{font-size:19px;font-weight:600;color:var(--text-body);}
.value-card p{font-size:15px;line-height:1.5;color:var(--text-body);}

/* =========================================================
   Modular infrastructure (dark)
   ========================================================= */
.modular{
  position:relative;overflow:hidden;
  background:var(--navy-950);
  padding:var(--gap-section) var(--pad-section) calc(var(--gap-section) + 56px);
  display:flex;flex-direction:column;align-items:center;gap:var(--gap-section);
}
.modular-blob{position:absolute;pointer-events:none;z-index:0;animation:drift 30.8s ease-in-out infinite alternate;}
.modular-blob img{width:100%;height:100%;display:block;}
.modular-blob--br{right:-341px;bottom:-357px;width:740px;height:740px;animation-duration:36.4s;}
.modular-blob--tl{left:-380px;top:-370px;width:583px;height:583px;animation-duration:28s;animation-delay:-8.4s;}
@keyframes drift{
  0%{transform:translate(0,0) scale(1);}
  100%{transform:translate(-18px,14px) scale(1.04);}
}
.modular-title{
  position:relative;z-index:1;
  max-width:1100px;text-align:center;
  font-size:clamp(28px,4.5vw,54px);line-height:1.2;
  background:linear-gradient(159deg,#fff 0%,#97b4ff 87%);
  -webkit-background-clip:text;background-clip:text;color:transparent;
}
.modular-title .w-semibold{font-weight:600;}
.modular-title .w-light{font-weight:300;}

.modular-body{
  position:relative;z-index:1;width:100%;max-width:var(--max-width);
  display:flex;gap:24px;align-items:center;flex-wrap:wrap;
}
.badge-grid{
  display:flex;flex-wrap:wrap;gap:20px;flex:1 1 556px;max-width:556px;align-content:flex-start;
}
.badge{
  display:flex;align-items:center;gap:16px;
  padding:16px;border-radius:var(--radius-md);
  border:1px solid var(--border-dark-subtle);
  background:transparent;cursor:pointer;
  flex:1 1 240px;
  /* opacity/transform merged in for the same reason as .value-card —
     see the comment there. */
  transition:
    opacity var(--dur-item) var(--ease-premium) var(--d,0ms),
    transform var(--dur-item) var(--ease-premium) var(--d,0ms),
    border-color 0.56s ease 0s,
    box-shadow 0.56s ease 0s,
    background-color 0.56s ease 0s;
}
.badge:focus-visible{outline:2px solid var(--blue-500);outline-offset:2px;}
.badge:hover{border-color:var(--blue-500);box-shadow:0 0 16px rgba(var(--accent-rgb),.5);transform:translateY(-4px);background:var(--navy-810);}
.badge--lit{border-color:var(--blue-500);background:var(--navy-810);}
.badge--wide{flex-basis:100%;max-width:100%;}
.badge-icon{position:relative;width:72px;height:54px;flex-shrink:0;}
.badge-label{font-size:20px;color:#fff;line-height:1.3;}

.modular-panel{
  flex:1 1 320px;position:relative;overflow:hidden;
  border:1px solid var(--border-dark-mid);border-radius:var(--radius-md);
  background:var(--navy-810);align-self:center;
  padding:40px;display:flex;flex-direction:column;gap:20px;
}
.modular-panel .btn{position:relative;z-index:1;align-self:flex-start;}
.modular-panel::before{
  content:"";position:absolute;inset:0;
  background-image:url('assets/bg-pattern-panel.png');background-size:200px 200px;
  opacity:.04;pointer-events:none;
}
.modular-panel h3{
  position:relative;font-size:clamp(18px,1.9vw,22px);font-weight:700;line-height:1.3;
  color:#fff;
  transition:opacity 0.28s ease;
}
.modular-panel p{
  position:relative;font-size:16px;line-height:1.5;color:var(--blue-tint);
  transition:opacity 0.28s ease;
}
.modular-panel h3.is-swapping,
.modular-panel p.is-swapping{opacity:0;}

/* Fill/outline layered icons (Figma exports two stacked layers per illustration) */
.illus-fill,.illus-outline{position:absolute;inset:0;width:100%;height:100%;object-fit:contain;}

/* =========================================================
   Success cases
   ========================================================= */
.cases{background:var(--surface-muted);padding:var(--gap-section) var(--pad-section);transition:background-color 0.56s ease;}
.case-cards{
  max-width:var(--max-width);margin:0 auto;
  display:grid;grid-template-columns:repeat(3,1fr);gap:20px;
}
.case-card{
  position:relative;margin:0;
  background:var(--surface-card);border:1px solid var(--border-testimonial-c);
  border-radius:var(--radius-lg);overflow:hidden;
  padding:32px;display:flex;flex-direction:column;gap:24px;
  aspect-ratio:3/3.35;
  /* opacity/transform merged in for the same reason as .value-card —
     see the comment there. */
  transition:
    opacity var(--dur-item) var(--ease-premium) var(--d,0ms),
    transform var(--dur-item) var(--ease-premium) var(--d,0ms),
    box-shadow 0.56s var(--ease-premium) 0s,
    background-color 0.56s ease 0s,
    border-color 0.56s ease 0s;
}
.case-card:hover{transform:translateY(-6px);box-shadow:0 24px 48px var(--card-shadow);}
.case-card p{font-size:18px;line-height:1.5;color:var(--text-body);position:relative;z-index:1;flex:1;}
.case-card hr{border:none;border-top:1px solid var(--border-subtle);width:100%;margin:0;}
.case-card footer{display:flex;gap:12px;align-items:flex-start;}
.case-card footer img{width:66px;height:66px;border-radius:8px;object-fit:cover;flex-shrink:0;}
.case-card footer div{display:flex;flex-direction:column;font-size:16px;line-height:1.5;}
.case-card cite{font-style:normal;font-weight:500;color:var(--text-body);}
.case-card footer span{font-style:italic;color:var(--text-muted);}
.quote-mark{
  position:absolute;font-size:100px;font-weight:700;color:var(--text-heading);opacity:.04;
  line-height:1;pointer-events:none;
}
[data-theme="dark"] .quote-mark{opacity:.08;}
.quote-mark--open{top:-16px;left:30px;}
.quote-mark--close{bottom:-40px;right:30px;}

/* =========================================================
   Footer
   ========================================================= */
.site-footer{position:relative;overflow:hidden;background:var(--navy-925);}
.footer-top{
  position:relative;z-index:1;
  max-width:var(--max-width);margin:0 auto;
  padding:var(--pad-section) var(--pad-section) clamp(72px,10vw,92px);
  display:flex;flex-wrap:wrap;gap:60px;justify-content:space-between;
}
.footer-newsletter{display:flex;flex-direction:column;gap:16px;width:100%;max-width:332px;}
.footer-newsletter p{color:#fff;font-size:16px;line-height:24px;}
.newsletter-form{display:flex;gap:0;border:1px solid var(--blue-tint);border-radius:8px;overflow:hidden;background:var(--navy-800);}
.newsletter-form input{
  flex:1;min-width:0;background:transparent;border:0;color:var(--blue-tint);
  font-size:16px;padding:0 0 0 24px;
}
.newsletter-form input::placeholder{color:var(--blue-tint);opacity:.8;}
.newsletter-form input:focus{outline:none;}
.newsletter-form button{
  background:var(--blue-tint);border:0;padding:12px;display:flex;align-items:center;
  transition:background-color 0.42s ease, transform 0.42s ease;
}
.newsletter-form button:hover{background:#fff;transform:translateX(2px);}
.social-btn{
  width:48px;height:48px;border:1px solid var(--blue-tint);border-radius:8px;
  display:flex;align-items:center;justify-content:center;
  transition:background-color 0.42s ease, transform 0.42s ease;
}
.social-btn:hover{background:rgba(189,208,255,.12);transform:translateY(-2px);}

.footer-links{display:flex;flex-wrap:wrap;gap:60px;}
.footer-col{display:flex;flex-direction:column;gap:20px;}
.footer-col-title{font-weight:700;font-size:18px;color:#fff;}
.footer-col a{
  font-size:20px;color:var(--blue-tint);position:relative;width:fit-content;
  transition:color 0.42s ease;
}
.footer-col a:hover{color:#fff;}
.footer-col a::after{
  content:"";position:absolute;left:0;right:0;bottom:-2px;height:1px;background:currentColor;
  transform:scaleX(0);transform-origin:left;transition:transform 0.42s var(--ease-premium);
}
.footer-col a:hover::after{transform:scaleX(1);}

.footer-wordmark{
  position:relative;width:100%;max-width:1206px;margin:0 auto;
  opacity:0;transform:scale(.98);
  transition:opacity 1.54s var(--ease-premium), transform 1.54s var(--ease-premium);
}
.footer-wordmark.is-visible{opacity:1;transform:scale(1);}
.footer-wordmark img{width:100%;height:auto;display:block;}

/* =========================================================
   Back to top
   ========================================================= */
.to-top{
  position:fixed;right:24px;bottom:24px;z-index:90;
  width:48px;height:48px;border-radius:50%;
  background:var(--blue-500);color:#fff;border:0;
  display:flex;align-items:center;justify-content:center;
  box-shadow:0 8px 24px rgba(var(--accent-rgb),.4);
  opacity:0;visibility:hidden;transform:translateY(12px);
  transition:opacity 0.49s ease, transform 0.49s var(--ease-premium), visibility 0.49s ease;
}
.to-top.is-visible{opacity:1;visibility:visible;transform:translateY(0);}
.to-top:hover{filter:brightness(1.1);}
.to-top svg{width:22px;height:22px;}

/* =========================================================
   Contact modal
   ========================================================= */
/* Sits above everything else on the page, header included (z-index 100),
   so it can never be tucked behind a sticky nav or the back-to-top button. */
.contact-overlay{
  position:fixed;inset:0;z-index:200;
  display:flex;align-items:center;justify-content:center;
  padding:24px;
  opacity:0;visibility:hidden;
  transition:opacity 0.42s var(--ease-premium), visibility 0s linear 0.42s;
}
.contact-overlay.is-open{
  opacity:1;visibility:visible;
  transition:opacity 0.42s var(--ease-premium);
}
.contact-backdrop{
  position:absolute;inset:0;
  background:rgba(4,10,26,.62);
  backdrop-filter:blur(16px);-webkit-backdrop-filter:blur(16px);
}
:root[data-theme="dark"] .contact-backdrop{background:rgba(2,6,16,.72);}

/* Fixed to the page corner (not the card) per spec, so it stays put even
   if the panel scrolls internally on short viewports. Comes in a beat
   after the backdrop so the eye lands on the blur first, then the exit. */
.contact-close{
  position:fixed;top:28px;right:28px;z-index:201;
  width:48px;height:48px;border-radius:50%;
  display:flex;align-items:center;justify-content:center;
  background:rgba(255,255,255,.08);border:1px solid rgba(255,255,255,.28);color:#fff;
  opacity:0;visibility:hidden;transform:translateY(-10px);
  transition:opacity 0.4s var(--ease-premium), transform 0.4s var(--ease-premium), background-color 0.28s ease, visibility 0s linear 0.4s;
}
.contact-overlay.is-open .contact-close{
  opacity:1;visibility:visible;transform:translateY(0);
  transition:opacity 0.4s var(--ease-premium) 0.14s, transform 0.4s var(--ease-premium) 0.14s, background-color 0.28s ease;
}
.contact-close:hover{background:rgba(255,255,255,.18);transform:rotate(90deg);}
.contact-close svg{width:20px;height:20px;}

.contact-dialog{
  position:relative;z-index:1;width:100%;max-width:640px;
  max-height:calc(100vh - 48px);
}
.contact-panel{
  position:relative;width:100%;max-height:calc(100vh - 48px);overflow-y:auto;
  background:var(--surface-card);border:1px solid var(--border-subtle);
  border-radius:var(--radius-lg);
  padding:clamp(28px,4vw,48px);
  box-shadow:0 32px 80px rgba(3,10,30,.45);
  transform:scale(.94) translateY(18px);opacity:0;
  transition:transform 0.5s var(--ease-premium), opacity 0.4s var(--ease-premium);
}
.contact-overlay.is-open .contact-panel{
  transform:scale(1) translateY(0);opacity:1;
  transition:transform 0.56s var(--ease-premium) 0.1s, opacity 0.48s var(--ease-premium) 0.1s;
}

.contact-eyebrow{font-size:14px;font-weight:700;letter-spacing:.04em;text-transform:uppercase;color:var(--blue-500);}
.contact-panel h2{margin-top:6px;font-size:clamp(24px,3vw,32px);color:var(--text-heading);}
.contact-sub{margin-top:10px;font-size:16px;line-height:1.5;color:var(--text-muted);max-width:46ch;}

.field-grid{display:grid;grid-template-columns:1fr 1fr;gap:18px;margin:28px 0 6px;}
.field{display:flex;flex-direction:column;gap:8px;}
.field--full{grid-column:1/-1;}
.field-label{font-size:14px;font-weight:600;color:var(--text-muted);}
.field input,.field select,.field textarea{
  background:var(--surface-muted);border:1px solid var(--border-subtle);border-radius:var(--radius-sm);
  padding:13px 16px;font-size:16px;font-family:inherit;color:var(--text-heading);
  transition:border-color .28s ease, box-shadow .28s ease, background-color .28s ease;
}
.field textarea{resize:vertical;min-height:96px;line-height:1.5;}
.field select{
  appearance:none;-webkit-appearance:none;
  background-image:var(--select-chevron);background-repeat:no-repeat;background-position:right 16px center;background-size:14px;
  padding-right:42px;
}
.field select:invalid{color:var(--text-muted);}
.field input:focus,.field select:focus,.field textarea:focus{
  outline:none;border-color:var(--blue-500);box-shadow:0 0 0 4px rgba(var(--accent-rgb),.14);background:var(--surface-card);
}
.field input::placeholder,.field textarea::placeholder{color:var(--text-muted);opacity:.7;}

.contact-actions{display:flex;justify-content:flex-end;gap:12px;margin-top:28px;}
.btn-cancel{background:transparent;color:var(--text-muted);border-color:var(--border-subtle);}
.btn-cancel:hover{background:var(--surface-muted);color:var(--text-heading);}

/* display:flex only applies while NOT hidden — an unconditional
   .contact-success{display:flex} would outrank the [hidden] attribute's
   own display:none (same specificity, later in source order wins),
   leaving it visibly bleeding through under the form. */
.contact-success{text-align:center;flex-direction:column;padding:12px 0 4px;}
.contact-success:not([hidden]){display:flex;align-items:center;}
.success-badge{
  width:64px;height:64px;border-radius:50%;
  background:rgba(var(--accent-rgb),.12);color:var(--blue-500);
  display:flex;align-items:center;justify-content:center;margin-bottom:22px;
  transform:scale(0);transition:transform 0.5s var(--ease-premium) 0.1s;
}
.contact-success:not([hidden]) .success-badge{transform:scale(1);}
.success-badge svg{width:28px;height:28px;}
.contact-success h2{font-size:clamp(22px,2.8vw,28px);color:var(--text-heading);}
.contact-success p{margin-top:12px;font-size:16px;line-height:1.55;color:var(--text-muted);max-width:40ch;}
.contact-success .btn{margin-top:28px;min-width:160px;}

/* =========================================================
   Responsive
   ========================================================= */
@media (max-width:1080px){
  .nav-desktop, .header-cta{display:none;}
  .nav-toggle{display:flex;}
  .nav-mobile{display:block;}
  .hero-inner{min-height:0;padding:64px var(--pad-section);}
  .hero-copy{max-width:100%;}
  .value-cards, .case-cards{grid-template-columns:1fr;}
  .value-card, .case-card{height:auto !important;aspect-ratio:auto !important;}
  .case-card p{flex:none !important;}
  .modular-body{flex-direction:column;}
  .badge-grid{max-width:100%;}
  .stats-grid{gap:20px;}
}

@media (max-width:640px){
  .header-inner{padding-top:20px;padding-bottom:20px;}
  .hero-copy{gap:32px;}
  .hero-actions{flex-direction:column;align-items:stretch;}
  .badge{flex-basis:100%;}
  .footer-top{flex-direction:column;}
  .trusted-logos{gap:28px;}
  .stats-grid{flex-direction:column;align-items:stretch;}
  .field-grid{grid-template-columns:1fr;}
  .contact-close{top:16px;right:16px;width:44px;height:44px;}
  .contact-actions{flex-direction:column-reverse;}
  .contact-actions .btn{width:100%;}
}

/* =========================================================
   SOLUTIONS PAGE (solution.html)
   ---------------------------------------------------------
   Everything below is scoped to solution.html's own sections and
   is unused on index.html. The page reuses the hero mesh/spark
   treatment, .btn, .section-head and the contact modal as-is.
   ========================================================= */

/* --- Hero ------------------------------------------------- */
/* Marks which solution the page is currently showing in the header's
   Solutions menu, so the menu isn't a list of six identical-looking links
   with no sense of where you already are. Set from the page script, since
   the page serves all six. */
.nav-dropdown-item[aria-current="page"],
.nav-mobile-sublink[aria-current="page"]{
  color:var(--blue-500);font-weight:600;
}

.sol-hero .hero-inner{min-height:min(56vh, 480px);}
.sol-hero-copy{gap:24px;max-width:860px;}
.sol-eyebrow{
  font-size:13px;font-weight:600;letter-spacing:.14em;text-transform:uppercase;
  color:var(--blue-tint);text-shadow:0 2px 16px rgba(0,0,0,.35);
}
.sol-hero-copy h1{
  display:block;font-size:clamp(32px, 4.6vw, 54px);font-weight:700;line-height:1.14;
}
.sol-hero-copy .hero-sub{font-size:clamp(17px, 1.7vw, 21px);}

/* --- Tab strip -------------------------------------------- */
/* Permanently dark like the hero above and the modular section on the
   home page, so the switcher reads as part of the hero block rather
   than as the first light section of the page body. */
.sol-switch{
  background:var(--navy-950);
  /* Vertical padding is deliberately light: .sol-tabs carries its own
     inner padding (see there) and the two add up to the strip's height. */
  padding:clamp(4px, 0.8vw, 10px) var(--pad-section);
  border-bottom:1px solid var(--border-dark-subtle);
  /* Sticks so the reader can jump between solutions without scrolling
     back up — the strip is the page's primary navigation. --header-h is
     measured in JS: the header shrinks when scrolled, so a hardcoded
     offset would either overlap it or leave a gap. */
  position:sticky;top:var(--header-h, 58px);z-index:40;
}
.sol-switch-inner{
  max-width:var(--max-width);margin:0 auto;
  position:relative;
}
/* Scroll affordance: at narrow widths the six tabs overflow, and without
   this the strip just looks cropped rather than scrollable. */
.sol-switch-inner::after{
  content:'';position:absolute;top:0;right:0;bottom:0;width:44px;
  pointer-events:none;
  background:linear-gradient(90deg, rgba(6,16,42,0) 0%, var(--navy-950) 100%);
  opacity:0;transition:opacity .3s ease;
}
.sol-switch-inner.is-overflowing::after{opacity:1;}
.sol-tabs{
  list-style:none;margin:0;
  /* This padding is not cosmetic — it is the room the tabs need to move
     into. Scrolling horizontally forces a clipping overflow-y, so without
     it the hover lift, the active tab's glow and the focus ring were all
     sliced off at the container's edges, which is what made each tab look
     cropped on hover. */
  padding:14px 16px;
  display:flex;
  /* Horizontal scroll rather than wrap: six tabs would stack into three
     rows on a phone and push the content below off the first screen. */
  overflow-x:auto;overflow-y:hidden;
  scrollbar-width:none;-webkit-overflow-scrolling:touch;
  scroll-snap-type:x proximity;
}
.sol-tabs::-webkit-scrollbar{display:none;}

/* Centred when the tabs fit, still scrollable from the true start when they
   don't. Two zero-width flex items with auto margins split the free space
   between them; when there is no free space the autos resolve to 0. Plain
   justify-content:center would instead make the leftmost tabs unreachable
   once the strip overflows, which is the whole reason for this trick. */
.sol-tabs::before,
.sol-tabs::after{content:'';flex:0 0 auto;margin:auto;}

/* Spacing via margin rather than `gap`: gap would also apply around the two
   centring pseudo-elements above, silently adding ~20px of dead width to a
   strip that only just fits six tabs. */
.sol-tabs li{flex:0 0 auto;scroll-snap-align:start;}
.sol-tabs li + li{margin-left:8px;}
.sol-tab{
  display:flex;align-items:center;gap:11px;
  padding:10px 10px;min-height:64px;
  background:var(--navy-900);border:1px solid var(--border-dark-subtle);
  border-radius:var(--radius-md);cursor:pointer;text-align:left;
  font-family:inherit;
  transition:border-color .3s var(--ease-premium), background-color .3s var(--ease-premium),
             transform .3s var(--ease-premium), box-shadow .3s var(--ease-premium);
}
.sol-tab:hover{border-color:var(--blue-500);background:var(--navy-810);transform:translateY(-2px);}
.sol-tab:focus-visible{outline:2px solid var(--blue-500);outline-offset:2px;}
.sol-tab--on{
  border-color:var(--blue-500);background:var(--navy-810);
  box-shadow:0 0 18px rgba(var(--accent-rgb),.35);
}
/* Same two-layer illustrations as the home page's .badge-icon, and
   deliberately a SQUARE box: these SVGs have a 100x100 viewBox, so under
   object-fit:contain a non-square box letterboxes the glyph — a 32x28 box
   drew it at 28px against the badge's 54px, which read as a different,
   much smaller icon instead of the same one at a smaller size. */
.sol-tab-icon{position:relative;width:38px;height:38px;flex-shrink:0;}
.sol-tab-label{
  font-size:15px;line-height:1.3;color:#fff;font-weight:500;white-space:nowrap;
}

/* The strip scrolls horizontally, which forces overflow-y to a clipping
   value — so the reveal system's default 24px downward offset would animate
   each tab in from behind a clipped edge. Fade only here. */
.sol-tabs [data-reveal-item]{transform:none;}

/* --- Description + assembly canvas ------------------------ */
.sol-canvas-section{
  background:var(--surface-page);
  padding:var(--gap-section) var(--pad-section);
  transition:background-color .56s ease;
}
.sol-canvas-inner{
  max-width:var(--max-width);margin:0 auto;
  display:flex;flex-direction:column;gap:clamp(40px, 5vw, 72px);
}
/* Centred copy. Deliberately text-align rather than align-items:center —
   as a column flex container the latter would shrink each child's box to
   fit-content, so the paragraph's measure (and therefore its line breaks)
   would depend on its own text rather than staying a predictable 900px. */
.sol-desc{
  max-width:900px;margin:0 auto;
  display:flex;flex-direction:column;gap:18px;
  text-align:center;
}
.sol-desc h2{
  font-size:clamp(24px, 2.8vw, 36px);font-weight:700;color:var(--text-heading);
  line-height:1.2;
}
.sol-desc p{font-size:clamp(16px, 1.5vw, 19px);line-height:1.65;color:var(--text-body);}
/* Swapping tabs replaces the text outright. Rather than a timed
   fade-out/fade-in two-step, the JS re-adds .is-swap after a reflow to
   restart this animation, which reads as a soft settle-in. */
.sol-desc.is-swap h2{animation:solFadeUp .5s var(--ease-premium) both;}
.sol-desc.is-swap p{animation:solFadeUp .5s var(--ease-premium) 80ms both;}

@keyframes solFadeUp{
  from{opacity:0;transform:translateY(12px);}
  to{opacity:1;transform:none;}
}

.sol-assembly{margin:0;display:flex;flex-direction:column;gap:20px;}
.assembly-caption{
  display:flex;align-items:baseline;gap:10px;flex-wrap:wrap;
  font-size:13px;letter-spacing:.12em;text-transform:uppercase;
}
.assembly-caption-label{color:var(--text-muted);font-weight:600;}
.assembly-caption-count{color:var(--blue-600);font-weight:700;letter-spacing:.06em;}

.assembly-stage{
  position:relative;
  display:flex;flex-direction:column;
  /* The gap is the room the connector wires are drawn into. */
  gap:clamp(64px, 8vw, 104px);
  padding:clamp(20px, 3vw, 36px);
  border:1px solid var(--border-subtle);border-radius:var(--radius-lg);
  background:
    radial-gradient(120% 90% at 50% 0%, var(--assembly-glow) 0%, transparent 70%),
    var(--surface-card);
  transition:border-color .56s ease, background-color .56s ease;
}

.assembly-chips{
  list-style:none;margin:0;padding:0;
  /* Flex, not grid, on purpose: a grid with a fixed column count orphans
     the 5th of five components onto a row of its own, which breaks the
     "one row feeding one platform" read the wires depend on. Flex items
     shrink to keep the row intact, and a row that genuinely can't fit
     wraps centered instead of left-orphaned. */
  display:flex;flex-wrap:wrap;gap:16px;justify-content:center;
  position:relative;z-index:2;
}
.assembly-chip{
  flex:1 1 180px;min-width:0;max-width:360px;
  display:flex;flex-direction:column;gap:8px;
  padding:18px;
  border:1px solid var(--stats-card-border);border-radius:var(--radius-md);
  background:var(--value-card-bg);
  box-shadow:0 10px 24px -18px var(--card-shadow);
  /* Assembly entrance: each chip drops into place on a --i stagger.
     Held in the "before" state until .is-assembled lands on the stage,
     so a tab switch replays it from the top. */
  opacity:0;transform:translateY(-18px) scale(.96);
  transition:opacity .5s var(--ease-premium), transform .5s var(--ease-premium),
             border-color .3s ease, box-shadow .3s ease;
  transition-delay:calc(var(--i, 0) * 90ms);
}
.assembly-stage.is-assembled .assembly-chip{opacity:1;transform:none;}
.chip-name{font-size:16px;font-weight:600;line-height:1.35;color:var(--text-heading);}
.chip-desc{font-size:14px;line-height:1.55;color:var(--text-muted);}

.assembly-wires{
  position:absolute;inset:0;width:100%;height:100%;
  pointer-events:none;z-index:1;overflow:visible;
}
.assembly-wires .wire{
  fill:none;stroke:var(--blue-500);stroke-width:1.8;stroke-linecap:round;
  opacity:.72;
  /* Drawn on with a dash sweep. The length is unknown at author time, so
     a generous fixed dash covers every path this diagram produces. */
  stroke-dasharray:1200;stroke-dashoffset:1200;
  transition:stroke-dashoffset .85s var(--ease-premium);
  transition-delay:calc(320ms + var(--i, 0) * 90ms);
}
.assembly-stage.is-assembled .assembly-wires .wire{stroke-dashoffset:0;}
.assembly-wires .wire-dot,
.assembly-wires .wire-hub{
  fill:var(--blue-500);opacity:0;
  transition:opacity .4s ease;
  transition-delay:calc(320ms + var(--i, 0) * 90ms);
}
.assembly-stage.is-assembled .assembly-wires .wire-dot,
.assembly-stage.is-assembled .assembly-wires .wire-hub{opacity:1;}

.assembly-foundation{
  position:relative;z-index:2;
  display:flex;flex-direction:column;gap:8px;align-items:center;text-align:center;
  padding:clamp(20px, 2.6vw, 30px);
  border-radius:var(--radius-md);
  border:1px solid var(--border-dark-mid);
  background:linear-gradient(135deg, var(--navy-900) 0%, var(--navy-950) 100%);
  box-shadow:0 0 32px -12px rgba(var(--accent-rgb),.5);
  opacity:0;transform:translateY(18px);
  transition:opacity .6s var(--ease-premium), transform .6s var(--ease-premium);
}
.assembly-stage.is-assembled .assembly-foundation{opacity:1;transform:none;}
.foundation-label{
  font-size:12px;font-weight:600;letter-spacing:.14em;text-transform:uppercase;
  color:var(--blue-tint);
}
.foundation-name{font-size:clamp(24px, 2.6vw, 32px);font-weight:700;color:#fff;line-height:1.1;}
.foundation-desc{max-width:64ch;font-size:15px;line-height:1.6;color:var(--blue-tint);}

/* --- Use cases -------------------------------------------- */
.sol-usecases{
  background:var(--surface-muted);
  padding:var(--gap-section) var(--pad-section);
  transition:background-color .56s ease;
}
.usecase-cards{
  list-style:none;margin:clamp(28px, 4vw, 44px) auto 0;padding:0;
  max-width:var(--max-width);
  display:grid;gap:20px;
  grid-template-columns:repeat(auto-fit, minmax(300px, 1fr));
}
.usecase-card{
  position:relative;
  display:flex;flex-direction:column;gap:12px;
  padding:clamp(22px, 2.4vw, 30px);
  border:1px solid var(--border-subtle);border-radius:var(--radius-lg);
  background:var(--surface-card);
  /* Reveal state (.is-in) and the hover lift share one transition
     shorthand on purpose — see the note by .value-card: a second
     shorthand on the same element silently replaces the first. */
  opacity:0;transform:translateY(26px);
  transition:opacity var(--dur-item) var(--ease-premium) calc(var(--i, 0) * 110ms),
             transform var(--dur-item) var(--ease-premium) calc(var(--i, 0) * 110ms),
             box-shadow .3s ease 0s, border-color .3s ease 0s;
}
.usecase-card.is-in{opacity:1;transform:none;}
.usecase-card.is-in:hover{
  border-color:var(--stats-card-border);
  box-shadow:0 24px 48px -24px var(--card-shadow);
}
.usecase-num{
  font-size:13px;font-weight:700;letter-spacing:.1em;color:var(--blue-600);
}
.usecase-card h3{
  font-size:clamp(17px, 1.7vw, 20px);font-weight:600;line-height:1.35;
  color:var(--text-heading);
}
.usecase-card p{font-size:15px;line-height:1.6;color:var(--text-body);}

/* --- Closing CTA ------------------------------------------ */
.sol-cta{
  background:var(--navy-950);
  padding:var(--gap-section) var(--pad-section);
}
.sol-cta-inner{
  max-width:var(--max-width);margin:0 auto;
  display:flex;align-items:center;justify-content:space-between;gap:32px;flex-wrap:wrap;
}
.sol-cta-copy{display:flex;flex-direction:column;gap:10px;max-width:620px;}
.sol-cta-copy h2{font-size:clamp(22px, 2.4vw, 32px);font-weight:700;color:#fff;line-height:1.2;}
.sol-cta-copy p{font-size:17px;line-height:1.55;color:var(--blue-tint);}
.sol-cta-actions{display:flex;gap:14px;flex-wrap:wrap;}

/* --- Responsive ------------------------------------------- */
/* Below this width the chips can no longer sit in one readable row, so the
   wires become a stack of near-identical curves — more visual noise than
   signal. The stacked cards already read as a list feeding the foundation
   block underneath them. */
@media (max-width: 1024px){
  .assembly-wires{display:none;}
  .assembly-stage{gap:28px;}
  .assembly-chip{flex:1 1 calc(50% - 8px);max-width:none;}
}

@media (max-width: 860px){
  .sol-switch{padding-left:16px;padding-right:16px;}
  .sol-tabs{padding:12px 12px;}
  .sol-tabs li + li{margin-left:8px;}
  .sol-tab{min-height:58px;padding:9px 10px;gap:9px;}
  .sol-tab-icon{width:32px;height:32px;}
  .sol-tab-label{font-size:14px;}
  .sol-cta-inner{flex-direction:column;align-items:flex-start;}
  .sol-cta-actions .btn{flex:1 1 auto;}
}

@media (max-width: 620px){
  .assembly-chip{flex-basis:100%;}
  .assembly-stage{padding:16px;}
  .sol-cta-actions{width:100%;flex-direction:column;}
  .sol-cta-actions .btn{width:100%;justify-content:center;text-align:center;}
}

@media (prefers-reduced-motion: reduce){
  .assembly-chip,
  .assembly-foundation,
  .usecase-card{opacity:1;transform:none;transition:none;}
  .assembly-wires .wire{stroke-dashoffset:0;transition:none;}
  .assembly-wires .wire-dot,
  .assembly-wires .wire-hub{opacity:1;transition:none;}
  .sol-desc.is-swap h2, .sol-desc.is-swap p{animation:none;}
}

/* =========================================================
   PER-SOLUTION ACCENT (solution.html only)
   ---------------------------------------------------------
   Each solution gets its own shade of blue. `data-solution` is set on
   <html> by the page script, so every block here only ever matches on
   solution.html — index.html never sets the attribute and keeps the brand
   palette exactly as it was.

   All six stay in the blue family on purpose: hue moves a long way, but
   saturation and lightness stay close, so they read as siblings rather
   than six different brands. Only one is ever on screen at a time, which
   is why neighbouring hues can sit this close and still feel clearly
   different as you switch tabs.

   Two ink variants per solution, not one: --blue-600 is used only for
   small bold text (.usecase-num, .assembly-caption-count), so it needs a
   DARKENED accent on light surfaces and a LIGHTENED one on dark surfaces.
   Using the vivid accent for both would drop that text to roughly 2.4:1
   against the dark card background. --blue-500 is the vivid one and drives
   borders, outlines, fills, buttons and the connector wires.
   ========================================================= */

/* Remap the brand tokens the page already consumes rather than re-styling
   each component: one indirection here and the hero wash, spark lines, tab
   highlight, wires, foundation glow, buttons, eyebrow and footer all follow. */
:root[data-solution]{
  --blue-500:var(--sol-accent);
  --blue-600:var(--sol-ink);
  --blue-tint:var(--sol-tint);
  --accent-rgb:var(--sol-accent-rgb);
  --spark-color:var(--sol-tint);
  --spark-rgb:var(--sol-tint-rgb);
  --hero-wash-rgb:var(--sol-wash-rgb);
  --assembly-glow:var(--sol-glow-light);
}
/* Higher specificity than both :root[data-theme="dark"] and
   :root[data-solution], so it wins regardless of source order. */
:root[data-theme="dark"][data-solution]{
  --blue-600:var(--sol-ink-dark);
  --assembly-glow:rgba(var(--sol-accent-rgb),.14);
}

/* Royal blue — the brand blue itself, so the default solution is unchanged. */
:root[data-solution="career-guidance"]{
  --sol-accent:#2361ff;   --sol-accent-rgb:35,97,255;
  --sol-ink:#1d4fd7;      --sol-ink-dark:#7d9cff;
  --sol-tint:#bdd0ff;     --sol-tint-rgb:189,208,255;
  --sol-wash-rgb:20,42,94;
  --sol-glow-light:#eef3ff;
}
/* Azure — lighter and sky-leaning. */
:root[data-solution="labor-intermediation"]{
  --sol-accent:#0f7ae0;   --sol-accent-rgb:15,122,224;
  --sol-ink:#0a5aa8;      --sol-ink-dark:#63b4f5;
  --sol-tint:#b3daff;     --sol-tint-rgb:179,218,255;
  --sol-wash-rgb:10,48,86;
  --sol-glow-light:#eaf5ff;
}
/* Teal-blue — the cyan end of the range. */
:root[data-solution="skill-passport"]{
  --sol-accent:#0d97a8;   --sol-accent-rgb:13,151,168;
  --sol-ink:#076d7a;      --sol-ink-dark:#4fc7d6;
  --sol-tint:#a8e4ec;     --sol-tint-rgb:168,228,236;
  --sol-wash-rgb:8,54,62;
  --sol-glow-light:#e8f8fa;
}
/* Indigo — the violet end of the range. */
:root[data-solution="job-platforms"]{
  --sol-accent:#5a46e8;   --sol-accent-rgb:90,70,232;
  --sol-ink:#4433b8;      --sol-ink-dark:#9d90ff;
  --sol-tint:#cdc4ff;     --sol-tint-rgb:205,196,255;
  --sol-wash-rgb:34,26,86;
  --sol-glow-light:#f2effe;
}
/* Cobalt — deeper and more sober than royal. */
:root[data-solution="education-skilling"]{
  --sol-accent:#1c56b8;   --sol-accent-rgb:28,86,184;
  --sol-ink:#16418c;      --sol-ink-dark:#7aa5f0;
  --sol-tint:#b6ccf5;     --sol-tint-rgb:182,204,245;
  --sol-wash-rgb:14,36,80;
  --sol-glow-light:#ecf2fd;
}
/* Steel blue — desaturated, the most restrained of the six. */
:root[data-solution="labor-intelligence"]{
  --sol-accent:#3d6ea8;   --sol-accent-rgb:61,110,168;
  --sol-ink:#2c5480;      --sol-ink-dark:#8fb4d8;
  --sol-tint:#c2d6ea;     --sol-tint-rgb:194,214,234;
  --sol-wash-rgb:20,38,60;
  --sol-glow-light:#eef4fa;
}

/* The foundation slab picks up a wash of the accent over its navy, so the
   diagram's anchor is themed too rather than staying uniformly navy. */
:root[data-solution] .assembly-foundation{
  background:
    linear-gradient(135deg, rgba(var(--sol-accent-rgb),.30) 0%, rgba(var(--sol-accent-rgb),.06) 55%, transparent 100%),
    linear-gradient(135deg, var(--navy-900) 0%, var(--navy-950) 100%);
  border-color:rgba(var(--sol-accent-rgb),.55);
}

/* Ease the accent between solutions instead of snapping it. Custom
   properties don't animate, so the transitions go on the properties that
   consume them — and only on elements that SURVIVE a tab switch. The chips,
   wires and use-case cards are torn down and rebuilt on every switch, so
   they start out at the new accent already and need nothing here. The
   foundation slab is re-run through its own opacity fade for the same
   reason, which is also why its gradient is left to snap: background-image
   isn't interpolable anyway, and the fade hides the change.

   .btn already transitions background-color (see .btn), so the CTA and
   header buttons ease on their own. */
/* The solution's own heading takes the accent — the single highest-impact
   spot, and what makes the page read as themed rather than as the brand
   page with a recoloured button. Uses --blue-600 (the ink variant, 6:1+ in
   both themes) rather than the vivid --blue-500, which would be too light
   for a heading this size on white.

   Deliberately just this one heading: "Use cases" and the card titles stay
   neutral, so the accent marks the page's subject instead of colouring
   every piece of text on it. */
:root[data-solution] .sol-desc h2{color:var(--blue-600);}

.sol-desc h2,
.assembly-caption-count{transition:color .45s ease;}
.sol-eyebrow,
.sol-hero-copy .hero-sub,
.sol-cta-copy p,
.foundation-label,
.foundation-desc{transition:color .45s ease;}
:root[data-solution] .assembly-foundation{
  transition:opacity .6s var(--ease-premium), transform .6s var(--ease-premium),
             border-color .45s ease;
}
