/* =========================================================================
   APEX SOLUTIONS — immersive build
   Palette is carried over verbatim from the v2 site tokens. Dark only: the
   WebGL layer is lit for a dark void and a light theme would need a second
   set of shader constants for no real gain on a site like this.
   ========================================================================= */

:root {
  /* ---- brand (unchanged from v2) ---- */
  --green:        #2ecc71;
  --green-600:    #23b863;
  --green-dark:   #0e5c3a;
  --green-soft:   rgba(46, 204, 113, .12);
  --bg:           #0a120e;
  --text:         #ffffff;
  --muted:        #a9bbb1;   /* 9.4:1 on --bg */
  --on-accent:    #0a1510;
  --surface:      #16241e;
  --surface-2:    #1d2f27;
  --surface-3:    #25382f;
  --footer-bg:    #071009;
  --glass:        rgba(10, 18, 14, .72);

  --line:         rgba(255, 255, 255, .12);
  --line-soft:    rgba(255, 255, 255, .07);

  /* ---- geometry ---- */
  --radius:       16px;
  --radius-sm:    10px;
  --container:    1240px;
  --header-h:     76px;

  /* ---- motion ---- */
  --ease-out:     cubic-bezier(.16, 1, .3, 1);      /* ease-out-quint */
  --ease-soft:    cubic-bezier(.22, 1, .36, 1);

  --font: "Space Grotesk", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;

  /* ---- semantic z-index scale: never raw 999 ---- */
  --z-canvas:  0;
  --z-base:    1;
  --z-raised:  10;
  --z-sticky:  50;
  --z-header:  100;
  --z-menu:    200;
  --z-cursor:  300;
}

/* ---------- reset ---------- */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }

html {
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--header-h) + 16px);
  -webkit-text-size-adjust: 100%;
  overflow-x: clip;
}

body {
  font-family: var(--font);
  font-size: 17px;
  line-height: 1.65;
  color: var(--text);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: clip;
  overflow-wrap: break-word;
}

img, svg, video { display: block; max-width: 100%; }
a { color: inherit; text-decoration: none; }
ul, ol { list-style: none; padding: 0; }
button { font-family: inherit; cursor: pointer; border: 0; background: none; color: inherit; }
strong { font-weight: 600; color: var(--text); }

:focus-visible {
  outline: 3px solid var(--green);
  outline-offset: 3px;
  border-radius: 4px;
}

.skip-link {
  position: absolute; left: 12px; top: -60px; z-index: var(--z-cursor);
  background: var(--green); color: var(--on-accent);
  padding: 10px 16px; border-radius: 8px; font-weight: 600;
  transition: top .2s var(--ease-soft);
}
.skip-link:focus { top: 12px; }

.container {
  width: 100%;
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: clamp(20px, 4vw, 40px);
}

.visually-hidden {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* =========================================================================
   WebGL canvas — fixed behind everything, content scrolls over it
   ========================================================================= */

#gl {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: var(--z-canvas);
  display: block;
  pointer-events: none;   /* never steals clicks from the content layer */
}

/* Static fallback backdrop. Default-ON so the page has depth even if the
   module never executes at all (JS blocked, parse error, old browser) —
   a class-gated fallback would leave those users staring at a flat void.
   The live scene fades it out once it has actually booted. */
body::before {
  content: "";
  position: fixed; inset: 0; z-index: var(--z-canvas);
  background:
    radial-gradient(60% 50% at 50% 38%, rgba(46, 204, 113, .16), transparent 70%),
    radial-gradient(40% 40% at 78% 72%, rgba(14, 92, 58, .3), transparent 72%),
    var(--bg);
  pointer-events: none;
  transition: opacity .9s var(--ease-soft);
}
html.gl-ready body::before { opacity: 0; }

/* Content sits above the canvas. */
.site-header, main, .site-footer { position: relative; z-index: var(--z-base); }

/* =========================================================================
   Custom cursor
   ========================================================================= */

.cursor { pointer-events: none; }
.cursor__dot, .cursor__ring {
  position: fixed; top: 0; left: 0;
  z-index: var(--z-cursor);
  pointer-events: none;
  opacity: 0;
  will-change: transform;
}
html.has-cursor .cursor__dot,
html.has-cursor .cursor__ring { opacity: 1; }

.cursor__dot {
  width: 5px; height: 5px;
  background: var(--green);
  border-radius: 50%;
  transition: opacity .3s;
}

/* The trailing element is the Apex mark rather than a circle — the A is
   already a pointer shape, so the brand doubles as the cursor.

   Done as a mask on the existing element rather than by swapping in an SVG:
   the cursor markup is duplicated across all 14 pages, and a mask keeps this
   to one rule. The path is the mark's silhouette — outer triangle with the
   leg notch removed via evenodd — matching assets/img/logo-mark.svg. */
.cursor__ring {
  width: 26px; height: 26px;
  border: 0;
  border-radius: 0;
  background: rgba(46, 204, 113, .62);
  -webkit-mask: var(--apex-cursor) center / contain no-repeat;
          mask: var(--apex-cursor) center / contain no-repeat;
  transition: opacity .3s, background-color .3s var(--ease-out);
}
:root {
  --apex-cursor: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'%3E%3Cpath fill='%23fff' fill-rule='evenodd' d='M32 5 L60 58 L4 58 Z M32 31 L21.5 58 L42.5 58 Z'/%3E%3C/svg%3E");
}
.cursor__ring.is-hot { background: var(--green); }

/* Real cursor stays hidden only while ours is live and only on fine pointers. */
@media (hover: hover) and (pointer: fine) {
  html.has-cursor,
  html.has-cursor a,
  html.has-cursor button { cursor: none; }
}
@media (pointer: coarse) {
  .cursor__dot, .cursor__ring { display: none; }
}

/* =========================================================================
   Header
   ========================================================================= */

.site-header {
  position: fixed; top: 0; left: 0; right: 0;
  height: var(--header-h);
  z-index: var(--z-header);
  display: flex; align-items: center;
  transition: background-color .4s var(--ease-soft), backdrop-filter .4s, border-color .4s;
  border-bottom: 1px solid transparent;
}
.site-header.is-scrolled {
  background: var(--glass);
  backdrop-filter: blur(14px) saturate(140%);
  -webkit-backdrop-filter: blur(14px) saturate(140%);
  border-bottom-color: var(--line-soft);
}

.nav { display: flex; align-items: center; gap: 32px; width: 100%; }

.brand { display: inline-flex; align-items: center; gap: 12px; margin-right: auto; }
.brand__mark { width: 34px; height: 34px; }
.brand__text { display: flex; flex-direction: column; line-height: 1; }
.brand__name { font-weight: 700; letter-spacing: .06em; font-size: 17px; }
.brand__sub {
  font-size: 9.5px; font-weight: 500;
  letter-spacing: .34em; color: var(--green); margin-top: 3px;
}

.nav__links { display: flex; align-items: center; gap: 30px; }
.nav__links > a, .nav__item > a {
  font-size: 14.5px; font-weight: 500; color: var(--muted);
  transition: color .25s var(--ease-soft);
  display: inline-flex; align-items: center; gap: 5px;
}
.nav__links > a:hover, .nav__item > a:hover { color: var(--text); }

.nav__item { position: relative; }
.nav__chev { transition: transform .3s var(--ease-soft); }
.nav__item:hover .nav__chev { transform: rotate(180deg); }

.nav__dropdown {
  position: absolute; top: calc(100% + 14px); left: -18px;
  min-width: 272px; padding: 8px;
  background: var(--surface-2);
  border: 1px solid var(--line-soft);
  border-radius: var(--radius);
  box-shadow: 0 24px 60px -24px rgba(0, 0, 0, .7);
  opacity: 0; visibility: hidden; transform: translateY(-8px);
  transition: opacity .28s var(--ease-out), transform .28s var(--ease-out), visibility .28s;
}
.nav__item:hover .nav__dropdown,
.nav__item:focus-within .nav__dropdown {
  opacity: 1; visibility: visible; transform: translateY(0);
}
.nav__dropdown a {
  display: block; padding: 11px 14px; border-radius: var(--radius-sm);
  font-size: 14px; color: var(--muted);
  transition: background-color .2s, color .2s;
}
.nav__dropdown a:hover { background: rgba(255, 255, 255, .05); color: var(--text); }

.nav__toggle {
  display: none; width: 44px; height: 44px;      /* 44px touch target */
  flex-direction: column; justify-content: center; align-items: center; gap: 5px;
}
.nav__toggle span {
  display: block; width: 20px; height: 1.5px; background: var(--text);
  transition: transform .3s var(--ease-out), opacity .2s;
}
body.nav-open .nav__toggle span:nth-child(1) { transform: translateY(6.5px) rotate(45deg); }
body.nav-open .nav__toggle span:nth-child(2) { opacity: 0; }
body.nav-open .nav__toggle span:nth-child(3) { transform: translateY(-6.5px) rotate(-45deg); }

.mobile-menu {
  position: fixed; inset: var(--header-h) 0 auto 0;
  z-index: var(--z-menu);
  background: var(--surface);
  border-bottom: 1px solid var(--line-soft);
  padding: 20px clamp(20px, 4vw, 40px) 28px;
  display: flex; flex-direction: column; gap: 4px;
  transform: translateY(-12px); opacity: 0; visibility: hidden;
  transition: opacity .3s var(--ease-out), transform .3s var(--ease-out), visibility .3s;
}
body.nav-open .mobile-menu { opacity: 1; visibility: visible; transform: translateY(0); }
.mobile-menu a {
  padding: 14px 0; font-size: 18px; font-weight: 500;
  border-bottom: 1px solid var(--line-soft);
}
.mobile-menu .btn { margin-top: 18px; border-bottom: 0; }

/* =========================================================================
   Buttons
   ========================================================================= */

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 9px;
  padding: 14px 26px; min-height: 48px;
  border-radius: 999px;
  font-size: 15px; font-weight: 600; letter-spacing: .01em;
  transition: background-color .3s var(--ease-soft), color .3s var(--ease-soft),
              border-color .3s var(--ease-soft), box-shadow .3s var(--ease-soft);
  will-change: transform;
}
.btn--primary {
  background: var(--green); color: var(--on-accent);
  box-shadow: 0 12px 40px -14px rgba(46, 204, 113, .7);
}
.btn--primary:hover { background: #3fd982; box-shadow: 0 16px 52px -14px rgba(46, 204, 113, .85); }
.btn--ghost {
  border: 1px solid var(--line);
  color: var(--text);
  backdrop-filter: blur(6px);
}
.btn--ghost:hover { border-color: var(--green); color: var(--green); }
.btn--lg { padding: 17px 34px; min-height: 56px; font-size: 16px; }
.btn--block { width: 100%; }

.link-arrow {
  display: inline-flex; align-items: center; gap: 8px;
  color: var(--green); font-weight: 600; font-size: 15px;
}
.link-arrow span { transition: transform .3s var(--ease-out); }
.link-arrow:hover span { transform: translateX(5px); }

/* =========================================================================
   Typography
   ========================================================================= */

h1, h2, h3 { text-wrap: balance; font-weight: 600; }
p { text-wrap: pretty; }

.display {
  /* Ceiling is 4.8rem rather than the 6rem cap: the hero copy shares the
     viewport with the 3D mark on the right, so the text column is narrower
     than a full-bleed hero and a larger size forces "The back office," to
     wrap mid-phrase. */
  font-size: clamp(2.5rem, 7vw, 4.8rem);
  line-height: 1.0;
  letter-spacing: -0.035em;                  /* floor is -0.04em */
  font-weight: 700;
}

.section__title {
  font-size: clamp(1.9rem, 4.4vw, 3.1rem);
  line-height: 1.1;
  letter-spacing: -0.025em;
}

.lede {
  font-size: clamp(1.05rem, 1.6vw, 1.3rem);
  line-height: 1.6;
  color: var(--muted);
  max-width: 62ch;
}

.prose { max-width: 68ch; color: var(--muted); }
.prose strong { color: var(--text); }

/* =========================================================================
   Sections — spacing is deliberately uneven to create rhythm
   ========================================================================= */

.section { position: relative; padding-block: clamp(88px, 12vw, 168px); }
.section--tight { padding-block: clamp(64px, 8vw, 108px); }
.section--rule { border-top: 1px solid var(--line-soft); }

/* A scrim behind text-heavy sections so body copy always clears 4.5:1
   against whatever the canvas is doing behind it. */
.scrim { position: relative; }
.scrim::before {
  content: "";
  position: absolute; inset: -8% -12%;
  background: radial-gradient(60% 60% at 50% 50%, rgba(10, 18, 14, .92), rgba(10, 18, 14, 0) 72%);
  z-index: -1;
  pointer-events: none;
}

/* =========================================================================
   Hero
   ========================================================================= */

.hero {
  min-height: 100svh;
  display: flex; align-items: center;
  padding-top: var(--header-h);
  position: relative;
}
/* The text column is deliberately narrow on wide viewports: the right half
   belongs to the 3D mark. Body copy must never overlap the geometry — green
   text on green shading fails contrast no matter how the scene is lit. */
.hero__inner { max-width: 720px; }
@media (max-width: 859px) { .hero__inner { max-width: 100%; } }

.hero__kicker {
  display: inline-flex; align-items: center; gap: 10px;
  font-size: 13px; font-weight: 500; color: var(--muted);
  margin-bottom: 28px;
}
.hero__kicker::before {
  content: ""; width: 28px; height: 1px; background: var(--green);
}

/* Intro sequence: the hero copy waits out the logo assemble, then rises in.
   Only ever applied by JS, and the class is cleared by a timer scheduled at
   the same moment it is added — so this can delay the copy, never withhold
   it. Without JS the rule never matches and the hero renders normally. */
.intro-active .hero__inner {
  opacity: 0;
  transform: translateY(18px);
}
.hero__inner {
  opacity: 1;
  transform: none;
  transition: opacity .9s var(--ease-out) .1s, transform 1s var(--ease-out) .1s;
}
.intro-active .hero__scroll { opacity: 0; transition: opacity .5s; }

@media (prefers-reduced-motion: reduce) {
  .intro-active .hero__inner { opacity: 1; transform: none; }
}

.hero__title { margin-bottom: 26px; }
.hero__title em {
  font-style: normal;
  color: var(--green);          /* solid, not a gradient fill */
}

.hero__lede { margin-bottom: 40px; }
.hero__cta { display: flex; flex-wrap: wrap; gap: 14px; }

.hero__scroll {
  position: absolute; left: 50%; bottom: 34px;
  transform: translateX(-50%);
  display: flex; flex-direction: column; align-items: center; gap: 10px;
  font-size: 11px; letter-spacing: .22em; text-transform: uppercase;
  color: var(--muted);
}
.hero__scroll i {
  display: block; width: 1px; height: 42px;
  background: linear-gradient(var(--green), transparent);
  animation: scrollPulse 2.4s var(--ease-soft) infinite;
}
@keyframes scrollPulse {
  0%, 100% { transform: scaleY(.4); transform-origin: top; opacity: .4; }
  50%      { transform: scaleY(1);  transform-origin: top; opacity: 1; }
}

/* =========================================================================
   Services — deliberately NOT a uniform card grid. The first item spans
   wide, the rest sit in an asymmetric arrangement so the eye has somewhere
   to go rather than scanning four identical boxes.
   ========================================================================= */

.services { display: grid; gap: 18px; grid-template-columns: repeat(6, 1fr); }

.service {
  position: relative;
  padding: clamp(28px, 3.4vw, 44px);
  border: 1px solid var(--line-soft);
  border-radius: var(--radius);
  background: rgba(22, 36, 30, .5);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  transition: border-color .4s var(--ease-soft), background-color .4s var(--ease-soft),
              transform .5s var(--ease-out);
  overflow: hidden;
}
.service::after {
  /* a light that tracks in from the top edge on hover — replaces the
     side-stripe accent, which is banned and always looks bolted on */
  content: "";
  position: absolute; top: 0; left: 0; right: 0; height: 1px;
  background: linear-gradient(90deg, transparent, var(--green), transparent);
  opacity: 0; transition: opacity .4s var(--ease-soft);
}
.service:hover {
  border-color: rgba(46, 204, 113, .34);
  background: rgba(29, 47, 39, .62);
  transform: translateY(-4px);
}
.service:hover::after { opacity: 1; }

.service--wide { grid-column: span 6; }
.service--half { grid-column: span 3; }
.service--third { grid-column: span 2; }

.service__n {
  font-size: 12px; font-weight: 600; color: var(--green);
  letter-spacing: .16em; margin-bottom: 18px; display: block;
}
.service__title { font-size: clamp(1.25rem, 2.2vw, 1.75rem); margin-bottom: 12px; letter-spacing: -.02em; }
.service__text { color: var(--muted); font-size: 15.5px; max-width: 54ch; margin-bottom: 22px; }

/* =========================================================================
   Cursor spotlight
   -------------------------------------------------------------------------
   --mx/--my are written by initFocusLink() only while an element is hovered.
   The fallback 50% keeps the gradient centred if JS never runs, and the
   whole layer is opacity 0 until .is-lit, so there is nothing to see and
   nothing to composite when idle.
   ========================================================================= */

.service, .insight, .post, .faq__item { position: relative; isolation: isolate; }

.service::before,
.insight::before,
.post::before,
.faq__item::before {
  content: "";
  position: absolute; inset: 0;
  z-index: -1;
  border-radius: inherit;
  background: radial-gradient(
    circle 260px at var(--mx, 50%) var(--my, 50%),
    rgba(46, 204, 113, .16),
    rgba(46, 204, 113, .05) 42%,
    transparent 70%
  );
  opacity: 0;
  transition: opacity .45s var(--ease-soft);
  pointer-events: none;
}
.service.is-lit::before,
.insight.is-lit::before,
.post.is-lit::before,
.faq__item.is-lit::before { opacity: 1; }

/* The metric numbers get a glow rather than a spotlight — they have no
   surface to light, only a figure. */
.metric__v { transition: text-shadow .45s var(--ease-soft); }
.metric__v.is-lit { text-shadow: 0 0 26px rgba(46, 204, 113, .55); }

@media (prefers-reduced-motion: reduce) {
  .service::before, .insight::before, .post::before, .faq__item::before { display: none; }
}

/* =========================================================================
   Metrics — inline row, not the big-number hero-metric template
   ========================================================================= */

.metrics {
  display: grid; gap: clamp(28px, 4vw, 56px);
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  border-top: 1px solid var(--line-soft);
  padding-top: clamp(36px, 4vw, 56px);
}
.metric__v {
  font-size: clamp(2.2rem, 4vw, 3.2rem); font-weight: 700;
  letter-spacing: -.03em; line-height: 1; color: var(--green);
  font-variant-numeric: tabular-nums;
}
.metric__l { margin-top: 12px; color: var(--muted); font-size: 14.5px; max-width: 26ch; }

/* =========================================================================
   Tool marquee
   ========================================================================= */

.marquee {
  overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
          mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
}
/* Two identical sets, each carrying its own trailing gap, so translating
   -50% lands exactly on the seam. A single flat row of 16 with `gap` is
   short one gap at the wrap and visibly hitches once per cycle. */
.marquee__track { display: flex; width: max-content; animation: slide 34s linear infinite; }
.marquee__set { display: flex; align-items: center; gap: 68px; padding-right: 68px; }
.marquee img { height: 30px; width: auto; opacity: .5; filter: grayscale(1) brightness(2.4); transition: opacity .3s; }
.marquee img:hover { opacity: .9; }
@keyframes slide { to { transform: translateX(-50%); } }
.marquee:hover .marquee__track { animation-play-state: paused; }

/* =========================================================================
   Methodology steps — numbers are earned here: this IS an ordered sequence,
   and the order carries information. (Numbering parallel items would just be
   scaffolding.) A connecting rule runs behind them on wide viewports.
   ========================================================================= */

.steps {
  display: grid; gap: clamp(26px, 3vw, 34px);
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  position: relative;
}
.steps::before {
  content: "";
  position: absolute; left: 0; right: 0; top: 19px; height: 1px;
  background: linear-gradient(90deg, var(--green-dark), var(--line-soft));
  opacity: .55;
}
@media (max-width: 700px) { .steps::before { display: none; } }

.step { position: relative; }
.step__num {
  display: inline-flex; align-items: center; justify-content: center;
  width: 38px; height: 38px; border-radius: 50%;
  background: var(--bg); border: 1px solid rgba(46, 204, 113, .4);
  color: var(--green); font-size: 13px; font-weight: 700;
  margin-bottom: 18px; position: relative; z-index: var(--z-base);
}
.step h3 { font-size: 1.1rem; letter-spacing: -.015em; margin-bottom: 9px; }
.step p { color: var(--muted); font-size: 15px; }

/* =========================================================================
   Why tiles — six short items. Deliberately un-carded: six identical boxes
   is the pattern the homepage already spends, and repeating it flattens the
   page into one texture.
   ========================================================================= */

.why-grid { display: grid; gap: clamp(28px, 3.4vw, 44px); grid-template-columns: repeat(auto-fit, minmax(268px, 1fr)); }
.why-tile h3 {
  font-size: 1.06rem; letter-spacing: -.012em; margin-bottom: 9px;
  display: flex; align-items: baseline; gap: 10px;
}
.why-tile h3::before {
  content: ""; flex: none;
  width: 7px; height: 7px; border-radius: 50%; background: var(--green);
  transform: translateY(-2px);
}
.why-tile p { color: var(--muted); font-size: 15px; padding-left: 17px; }
.why-tile em { font-style: italic; color: var(--text); }

/* =========================================================================
   Capability rows — two counter-scrolling pill tracks
   ========================================================================= */

.cap-rows { display: grid; gap: 14px; }
.cap-row {
  overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
          mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
}
.cap-row__track { display: flex; width: max-content; animation: slide 44s linear infinite; }
.cap-row--rev .cap-row__track { animation-direction: reverse; }
.cap-row__set { display: flex; gap: 13px; padding-right: 13px; }
.cap-row li {
  white-space: nowrap;
  padding: 11px 24px;
  border: 1px solid var(--line-soft);
  border-radius: 999px;
  background: rgba(22, 36, 30, .55);
  color: var(--muted);
  font-size: 15px;
}
.cap-row:hover .cap-row__track { animation-play-state: paused; }

/* =========================================================================
   Solutions — a ruled list, not more cards. The page already spends its card
   budget on the four service lines; repeating the pattern flattens hierarchy.
   ========================================================================= */

.solutions { display: grid; border-top: 1px solid var(--line-soft); }
.solution {
  display: flex; align-items: center; justify-content: space-between; gap: clamp(20px, 4vw, 60px);
  padding: clamp(24px, 3vw, 34px) clamp(0px, 1.5vw, 20px);
  border-bottom: 1px solid var(--line-soft);
  transition: background-color .35s var(--ease-soft), padding-left .35s var(--ease-out);
}
.solution:hover { background: rgba(46, 204, 113, .05); padding-left: clamp(12px, 2.2vw, 28px); }

/* Descriptive rows that are NOT links. Same rhythm, no interactive
   affordance — a hover shift on something unclickable reads as a broken
   link, and a "Learn more" that only opens a contact form is worse. */
.solution--static { cursor: default; }
.solution--static:hover { background: none; padding-left: clamp(0px, 1.5vw, 20px); }
.solution__body h3 { font-size: clamp(1.08rem, 1.8vw, 1.3rem); letter-spacing: -.015em; margin-bottom: 7px; }
.solution__body p { color: var(--muted); font-size: 15px; max-width: 58ch; }
.solution__more { flex: none; color: var(--green); font-weight: 600; font-size: 14.5px; display: inline-flex; gap: 7px; align-items: center; }
.solution__more span { transition: transform .3s var(--ease-out); }
.solution:hover .solution__more span { transform: translateX(5px); }
@media (max-width: 640px) {
  .solution { flex-direction: column; align-items: flex-start; gap: 14px; }
}

/* =========================================================================
   Insights
   ========================================================================= */

.posts { display: grid; gap: 22px; grid-template-columns: repeat(auto-fit, minmax(290px, 1fr)); }
.post {
  display: flex; flex-direction: column;
  border-radius: var(--radius); overflow: hidden;
  border: 1px solid var(--line-soft);
  background: rgba(22, 36, 30, .5);
  transition: border-color .4s var(--ease-soft), transform .5s var(--ease-out);
}
.post:hover { border-color: rgba(46, 204, 113, .34); transform: translateY(-4px); }
.post__media { aspect-ratio: 16 / 10; overflow: hidden; background: var(--surface-2); position: relative; }
.post__media img {
  width: 100%; height: 100%; object-fit: cover;
  /* Duotone, part 1: flatten to luminance. Placeholder photos are random
     subjects — desaturating and tinting them is what makes a mismatched set
     read as one deliberate system. Remove the filter + ::after once real
     brand photography lands. */
  filter: grayscale(1) contrast(1.08) brightness(.7);
  transition: transform .8s var(--ease-out), filter .8s var(--ease-out);
}
.post__media::after {
  /* Duotone, part 2: green in the midtones via colour blending. */
  content: "";
  position: absolute; inset: 0;
  background: linear-gradient(160deg, var(--green) 0%, var(--green-dark) 78%);
  mix-blend-mode: color;
  opacity: .62;
  pointer-events: none;
  transition: opacity .8s var(--ease-out);
}
.post:hover .post__media img { transform: scale(1.05); filter: grayscale(1) contrast(1.08) brightness(.82); }
.post:hover .post__media::after { opacity: .42; }
.post__body { padding: 26px 24px 28px; display: flex; flex-direction: column; gap: 10px; flex: 1; }
.post__tag { font-size: 12px; font-weight: 600; letter-spacing: .14em; text-transform: uppercase; color: var(--green); }
.post__title { font-size: 1.2rem; letter-spacing: -.02em; line-height: 1.28; }
.post__text { color: var(--muted); font-size: 14.5px; flex: 1; }

/* =========================================================================
   Inner-page hero — shorter than the homepage's 100svh so content starts
   above the fold. Inner pages are read, not landed on.
   ========================================================================= */

.page-hero {
  padding-top: calc(var(--header-h) + clamp(56px, 8vw, 104px));
  padding-bottom: clamp(40px, 6vw, 72px);
  position: relative;
}
.page-hero__inner { max-width: 800px; }
.page-hero__title { margin-bottom: 22px; font-size: clamp(2.1rem, 5.4vw, 3.6rem); line-height: 1.04; letter-spacing: -.03em; font-weight: 700; }
.page-hero__lede { color: var(--muted); font-size: clamp(1.02rem, 1.5vw, 1.22rem); max-width: 62ch; }

.crumbs { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; font-size: 13px; color: var(--muted); margin-bottom: 24px; }
.crumbs a { color: var(--muted); transition: color .2s; }
.crumbs a:hover { color: var(--green); }
.crumbs span[aria-current] { color: var(--text); }
.crumbs i { font-style: normal; opacity: .5; }

/* =========================================================================
   Long-form article
   ========================================================================= */

.article { max-width: 72ch; }
.article > * + * { margin-top: 1.35em; }
.article p, .article li { color: var(--muted); font-size: 1.05rem; line-height: 1.75; }
.article h2 {
  color: var(--text); font-size: clamp(1.5rem, 2.8vw, 2.05rem);
  letter-spacing: -.022em; line-height: 1.18;
  margin-top: 2.2em; margin-bottom: .1em;
}
.article h3 {
  color: var(--text); font-size: clamp(1.15rem, 2vw, 1.4rem);
  letter-spacing: -.015em; margin-top: 1.9em; margin-bottom: .1em;
}
.article strong { color: var(--text); }
.article a:not(.btn) { color: var(--green); text-decoration: underline; text-underline-offset: 3px; text-decoration-thickness: 1px; }
.article ul, .article ol { padding-left: 1.15em; }
.article ul li { list-style: disc; margin-top: .5em; }
.article ol { counter-reset: n; }
.article ol li { list-style: decimal; margin-top: .5em; }
.article blockquote {
  /* full border + tint, not a left stripe */
  border: 1px solid rgba(46, 204, 113, .26);
  background: rgba(46, 204, 113, .06);
  border-radius: var(--radius);
  padding: clamp(20px, 3vw, 30px);
}
.article blockquote p { color: var(--text); font-size: 1.1rem; }
.article blockquote p:first-child { margin-top: 0; }
.article hr { border: 0; border-top: 1px solid var(--line-soft); margin-block: 2.4em; }

.article__meta { display: flex; flex-wrap: wrap; gap: 14px; align-items: center; color: var(--muted); font-size: 13.5px; margin-bottom: 8px; }
.article__meta .dot { opacity: .5; }

/* =========================================================================
   Forms
   ========================================================================= */

.form { display: grid; gap: 18px; }
.form__row { display: grid; gap: 18px; grid-template-columns: 1fr 1fr; }
.field { display: flex; flex-direction: column; gap: 8px; }
.field label { font-size: 13.5px; font-weight: 600; color: var(--text); }
.field .opt { color: var(--muted); font-weight: 400; }

.field input, .field select, .field textarea {
  width: 100%;
  padding: 13px 15px;
  min-height: 48px;
  font: inherit;
  font-size: 15.5px;
  color: var(--text);
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  transition: border-color .25s var(--ease-soft), background-color .25s var(--ease-soft);
}
.field textarea { min-height: 128px; resize: vertical; line-height: 1.6; }
.field input::placeholder, .field textarea::placeholder { color: var(--muted); opacity: 1; }  /* 7:1 on the field bg */
.field input:hover, .field select:hover, .field textarea:hover { border-color: rgba(255, 255, 255, .22); }
.field input:focus, .field select:focus, .field textarea:focus {
  outline: none; border-color: var(--green); background: var(--surface-3);
  box-shadow: 0 0 0 3px rgba(46, 204, 113, .16);
}
.field select {
  appearance: none;
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M2 4l4 4 4-4' fill='none' stroke='%23a9bbb1' stroke-width='1.6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 14px center;
  background-size: 12px;
  padding-right: 38px;
}
.field select option { background: var(--surface-2); color: var(--text); }

/* Honeypot. Moved off-screen rather than display:none — a bot that skips
   hidden inputs would slip past the trap /api/lead checks before its rate
   limiter. Class name matches the original markup. */
.hp-field {
  position: absolute !important;
  left: -9999px; top: auto;
  width: 1px; height: 1px; overflow: hidden;
}

.field__label-row { display: flex; align-items: center; gap: 2px; }

.form__status { font-size: 14.5px; min-height: 1.4em; }
.form__status.ok  { color: var(--green); }
.form__status.err { color: #ff8a7a; }          /* 6.4:1 on --bg */
.form__status a   { color: var(--green); text-decoration: underline; }

.hint-tip {
  width: 18px; height: 18px; border-radius: 50%;
  border: 1px solid var(--line); color: var(--muted);
  font-size: 11px; font-weight: 700; line-height: 1;
  display: inline-flex; align-items: center; justify-content: center;
  vertical-align: middle; margin-left: 6px; position: relative;
}
.hint-tip:hover, .hint-tip:focus-visible { border-color: var(--green); color: var(--green); }
.hint-tip__bubble {
  position: absolute; bottom: calc(100% + 8px); left: 50%; transform: translateX(-50%);
  width: max-content; max-width: 240px; padding: 9px 12px;
  background: var(--surface-3); border: 1px solid var(--line-soft);
  border-radius: var(--radius-sm); color: var(--muted);
  font-size: 12.5px; font-weight: 400; line-height: 1.5; text-align: left;
  opacity: 0; visibility: hidden; transition: opacity .2s, visibility .2s;
  z-index: var(--z-raised);
}
.hint-tip:hover .hint-tip__bubble,
.hint-tip:focus-visible .hint-tip__bubble { opacity: 1; visibility: visible; }

@media (max-width: 640px) { .form__row { grid-template-columns: 1fr; } }

/* =========================================================================
   FAQ accordion
   ========================================================================= */

.faq { display: grid; gap: 10px; }
.faq__item { border: 1px solid var(--line-soft); border-radius: var(--radius); background: rgba(22, 36, 30, .5); overflow: hidden; transition: border-color .3s var(--ease-soft); }
.faq__item.open { border-color: rgba(46, 204, 113, .3); }
.faq__q {
  width: 100%; text-align: left;
  display: flex; align-items: center; justify-content: space-between; gap: 18px;
  padding: 20px clamp(18px, 2.4vw, 26px);
  font-size: 16px; font-weight: 600; color: var(--text);
  min-height: 56px;
}
.faq__q::after {
  content: ""; flex: none;
  width: 11px; height: 11px;
  border-right: 1.6px solid var(--green); border-bottom: 1.6px solid var(--green);
  transform: rotate(45deg) translate(-2px, -2px);
  transition: transform .32s var(--ease-out);
}
.faq__item.open .faq__q::after { transform: rotate(225deg) translate(-2px, -2px); }
.faq__a { max-height: 0; overflow: hidden; transition: max-height .38s var(--ease-out); }
/* Padding lives on the children so the panel's own scrollHeight (which the
   JS writes into max-height) already accounts for it. */
.faq__a > * { padding: 0 clamp(18px, 2.4vw, 26px) 22px; color: var(--muted); font-size: 15.5px; line-height: 1.7; }
.faq__item h3 { margin: 0; font-size: inherit; font-weight: inherit; }

/* =========================================================================
   Two-column content layouts
   ========================================================================= */

.split-2 { display: grid; gap: clamp(32px, 5vw, 64px); grid-template-columns: 1fr 1fr; align-items: start; }
.split-sticky { position: sticky; top: calc(var(--header-h) + 28px); }
@media (max-width: 900px) {
  .split-2 { grid-template-columns: 1fr; }
  .split-sticky { position: static; }
}

/* Bulleted capability lists — no side stripes, just a green marker */
.checks { display: grid; gap: 13px; }
.checks li { display: flex; gap: 12px; align-items: flex-start; color: var(--muted); font-size: 15.5px; }
.checks li::before {
  content: ""; flex: none; margin-top: .55em;
  width: 6px; height: 6px; border-radius: 50%; background: var(--green);
}

/* =========================================================================
   Insight cards — text-only. CMS-published articles carry no image, so a
   media-led card would render half-empty for exactly the content the client
   controls. The JS-injected cards use this same markup.
   ========================================================================= */

.insights__grid { display: grid; gap: 20px; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); }
.insight {
  display: flex; flex-direction: column; gap: 12px;
  padding: clamp(26px, 3vw, 36px);
  border: 1px solid var(--line-soft);
  border-radius: var(--radius);
  background: rgba(22, 36, 30, .5);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  transition: border-color .4s var(--ease-soft), background-color .4s var(--ease-soft), transform .5s var(--ease-out);
}
.insight:hover { border-color: rgba(46, 204, 113, .34); background: rgba(29, 47, 39, .62); transform: translateY(-4px); }
.insight__tag { font-size: 12px; font-weight: 600; letter-spacing: .14em; text-transform: uppercase; color: var(--green); }
.insight h3 { font-size: clamp(1.12rem, 1.8vw, 1.32rem); letter-spacing: -.018em; line-height: 1.26; }
.insight p { color: var(--muted); font-size: 15px; flex: 1; }
.insight__more { color: var(--green); font-weight: 600; font-size: 14.5px; display: inline-flex; gap: 7px; align-items: center; }
.insight__more span { transition: transform .3s var(--ease-out); }
.insight:hover .insight__more span { transform: translateX(5px); }

/* =========================================================================
   CTA
   ========================================================================= */

.cta { text-align: center; }
.cta__inner { max-width: 760px; margin-inline: auto; }
.cta h2 { margin-bottom: 18px; }
.cta p { color: var(--muted); margin-bottom: 34px; font-size: 1.08rem; }

/* =========================================================================
   Footer
   ========================================================================= */

.site-footer { background: var(--footer-bg); border-top: 1px solid var(--line-soft); padding-block: clamp(56px, 7vw, 84px) 32px; }
.footer__grid {
  display: grid; gap: 44px;
  grid-template-columns: 1.6fr 1fr 1fr 1fr;
}
.footer__slogan { color: var(--green); font-weight: 600; margin: 18px 0 10px; }
.footer__brand p { color: var(--muted); font-size: 14.5px; max-width: 40ch; }
.footer__col h3 { font-size: 12px; letter-spacing: .18em; text-transform: uppercase; color: var(--text); margin-bottom: 18px; }
.footer__col li { margin-bottom: 11px; }
.footer__col a { color: var(--muted); font-size: 14.5px; transition: color .2s; }
.footer__col a:hover { color: var(--green); }
.footer__bottom {
  display: flex; justify-content: space-between; flex-wrap: wrap; gap: 12px;
  margin-top: clamp(44px, 5vw, 64px); padding-top: 26px;
  border-top: 1px solid var(--line-soft);
  color: var(--muted); font-size: 13.5px;
}

/* =========================================================================
   Motion — reveals enhance an already-visible default.
   Offsets only apply once .js-motion is on <html>, so with JS blocked
   (or in a headless renderer) everything renders in its final state.
   ========================================================================= */

/* The hidden state lives in .pre, which JS only ever applies to elements that
   are BELOW the fold at init. Nothing is hidden by CSS alone.

   The obvious version of this — hide every [data-reveal] in CSS and let an
   observer reveal them — ships a blank page to anything that renders without
   scrolling (headless capture, link-preview bots, an observer that misfires).
   Hiding only what is already off-screen means the worst case is invisible
   content staying invisible, which costs nothing. */

[data-reveal] { transition: opacity .9s var(--ease-out), transform .9s var(--ease-out); }
[data-reveal].pre { opacity: 0; transform: translateY(26px); }
[data-reveal][data-delay="1"] { transition-delay: .1s; }
[data-reveal][data-delay="2"] { transition-delay: .2s; }
[data-reveal][data-delay="3"] { transition-delay: .3s; }

.split__w { display: inline-block; overflow: hidden; vertical-align: bottom; padding-bottom: .06em; }
.split__i { display: inline-block; transition: transform 1s var(--ease-out); }
.split.pre .split__i { transform: translateY(105%); }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
  .marquee__track { animation: none; }
  .hero__scroll i { animation: none; opacity: .7; }
  /* reveals never applied — .js-motion is not added under reduced motion */
}

/* =========================================================================
   Responsive
   ========================================================================= */

@media (max-width: 1000px) {
  .footer__grid { grid-template-columns: 1fr 1fr; }
  .footer__brand { grid-column: span 2; }
  .service--half, .service--third { grid-column: span 6; }
}

/* ---------- tablet ---------- */
@media (max-width: 860px) {
  .nav__links, .nav__actions { display: none; }
  .nav__toggle { display: flex; }
  .hero { min-height: 92svh; }
  .hero__scroll { display: none; }

  /* Below this width the hero copy goes full-bleed and the 3D mark sits
     directly behind it rather than beside it. Without a scrim, white text
     lands on lit green geometry and drops under 4.5:1. */
  .hero__inner { position: relative; }
  .hero__inner::before {
    content: "";
    position: absolute; inset: -6% -8%;
    background: radial-gradient(72% 62% at 42% 50%, rgba(10, 18, 14, .93), rgba(10, 18, 14, 0) 76%);
    z-index: -1;
    pointer-events: none;
  }

  /* Long service headings need more room once cards go full-width. */
  .service__text { max-width: none; }
  .split-2 { gap: clamp(28px, 5vw, 40px); }
}

/* ---------- small tablet / large phone ---------- */
@media (max-width: 700px) {
  .steps { gap: 30px; }
  .cap-row li { padding: 10px 18px; font-size: 14px; }
  .cap-row__set { gap: 10px; padding-right: 10px; }
  .page-hero { padding-top: calc(var(--header-h) + 44px); }
}

/* ---------- phone ---------- */
@media (max-width: 560px) {
  body { font-size: 16px; }
  .footer__grid { grid-template-columns: 1fr; }
  .footer__brand { grid-column: span 1; }
  .btn { width: 100%; }
  .hero__cta { flex-direction: column; align-items: stretch; }

  /* Tighten the vertical rhythm: the desktop scale wastes most of a phone
     screen on empty space between sections. */
  .section { padding-block: clamp(56px, 14vw, 88px); }
  .section--tight { padding-block: clamp(44px, 10vw, 64px); }
  .service { padding: 24px 20px; }
  .insight { padding: 24px 20px; }
  .article p, .article li { font-size: 1rem; }
  .metrics { gap: 30px; }

  /* iOS zooms the page in when a focused input is under 16px. */
  .field input, .field select, .field textarea { font-size: 16px; }
}

/* Very small phones: stop long service/tool names forcing a horizontal
   scrollbar on the whole document. */
@media (max-width: 380px) {
  .container { padding-inline: 16px; }
  .display { font-size: clamp(2rem, 10vw, 2.5rem); }
  .brand__sub { letter-spacing: .22em; }
}
