/* Self-hosted — the site makes zero external requests. */
/* Sora is a variable font (wght 400-800). ONE face with a weight RANGE: the browser
   interpolates 400/600/700 from the single file. Pinning discrete weights to it would
   render every face at the file's default instance (400) and flatten the hierarchy. */
@font-face{font-family:"Sora";src:url("/fonts/sora.woff2") format("woff2");font-weight:400 700;font-style:normal;font-display:swap;}
/* Chakra Petch is static — one face per weight. 400 is required: several inherited
   rules (.nav-links a, .card .num, .foot-legal a, .foot small, .mobile-nav a) use
   --tech at the default weight, and trialogic.io loads 400 too. Without it the
   browser substitutes 500 and our nav/labels render heavier than the sister site. */
@font-face{font-family:"Chakra Petch";src:url("/fonts/chakra-petch-400.woff2") format("woff2");font-weight:400;font-style:normal;font-display:swap;}
@font-face{font-family:"Chakra Petch";src:url("/fonts/chakra-petch-500.woff2") format("woff2");font-weight:500;font-style:normal;font-display:swap;}
@font-face{font-family:"Chakra Petch";src:url("/fonts/chakra-petch-600.woff2") format("woff2");font-weight:600;font-style:normal;font-display:swap;}
:root{
  --black:#080A0C; --panel:#0C1116; --surface:#111820; --gunmetal:#252C35;
  --line:#212B35; --line-2:#2C3944;
  --teal:#00D6D6; --aqua:#79FFFF; --cyan:#00808A;
  --white:#FFFFFF; --text:#E7F1F2; --text-2:#A6B6BD; --muted:#7E919A;
  --sans:"Sora",system-ui,-apple-system,sans-serif;
  --tech:"Chakra Petch",ui-monospace,monospace;
  --maxw:1160px; --gutter:clamp(22px,5vw,64px);
}
*{box-sizing:border-box;}
html{scroll-behavior:smooth;}
@media (prefers-reduced-motion:reduce){html{scroll-behavior:auto;}}
body{margin:0;background:var(--black);color:var(--text);font-family:var(--sans);
  font-size:17px;line-height:1.62;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;}
a{color:inherit;}
img{display:block;max-width:100%;}
.wrap{max-width:var(--maxw);margin:0 auto;padding:0 var(--gutter);}
.eyebrow{font-family:var(--tech);font-size:12px;font-weight:500;letter-spacing:.26em;
  text-transform:uppercase;color:var(--teal);margin:0;}

/* Buttons */
.btn{display:inline-flex;align-items:center;gap:10px;font-family:var(--tech);font-size:13px;
  font-weight:600;letter-spacing:.08em;text-transform:uppercase;text-decoration:none;cursor:pointer;
  padding:14px 24px;border-radius:3px;border:1px solid transparent;
  transition:transform .15s,box-shadow .2s,background .2s,border-color .2s,color .2s;}
.btn:active{transform:translateY(1px);}
.btn-primary{background:var(--teal);color:#04181a;border-color:var(--teal);}
.btn-primary:hover{background:var(--aqua);border-color:var(--aqua);box-shadow:0 0 28px rgba(0,214,214,.35);}
.btn-ghost{background:transparent;color:var(--text);border-color:var(--line-2);}
.btn-ghost:hover{border-color:var(--teal);color:var(--white);}

/* Header */
header{position:sticky;top:0;z-index:60;background:rgba(8,10,12,.72);
  backdrop-filter:saturate(140%) blur(10px);border-bottom:1px solid var(--line);}
.nav{display:flex;align-items:center;justify-content:space-between;height:66px;}
.brand{display:flex;align-items:center;gap:12px;text-decoration:none;}
.brand .bn{font-family:var(--tech);font-weight:600;font-size:19px;letter-spacing:.14em;color:var(--white);}
.brand .bn b{color:var(--teal);font-weight:600;}
.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}
.nav-links{display:flex;align-items:center;gap:26px;}
.nav-links a{font-family:var(--tech);font-size:12px;letter-spacing:.12em;text-transform:uppercase;
  text-decoration:none;color:var(--text-2);transition:color .2s;}
.nav-links a:hover{color:var(--teal);}
.nav-links a.active{color:var(--white);}
/* Was `color:#fff !important` — white on --teal is ~1.8:1, and this is the primary CTA.
   The !important was load-bearing, not sloppiness: `.nav-links a` (0,1,1) sets --text-2
   and beats `.btn-primary` (0,1,0), so simply dropping the declaration hands the button
   grey-on-teal — worse. Fixed with specificity instead: `.nav-links a.nav-cta` is (0,2,1),
   so it beats both `.nav-links a` and its :hover, and no !important is needed anywhere. */
.nav-links a.nav-cta{padding:10px 18px;background:var(--teal);color:#04181a;border-color:var(--teal);}
@media (max-width:860px){ .nav-links a:not(.nav-cta){display:none;} }

/* Hero (home) */
.hero{position:relative;overflow:hidden;border-bottom:1px solid var(--line);
  background:radial-gradient(120% 90% at 82% -10%,rgba(0,214,214,.14),transparent 55%),
             radial-gradient(90% 70% at 0% 110%,rgba(0,128,138,.12),transparent 55%),var(--black);}
.hero .wrap{position:relative;z-index:2;padding-top:clamp(48px,8vw,96px);padding-bottom:clamp(48px,8vw,96px);}
.hero h1{font-family:var(--sans);font-weight:700;font-size:clamp(38px,6.6vw,72px);line-height:1.03;
  letter-spacing:-0.025em;color:var(--white);margin:20px 0 0;max-width:19ch;}
.hero h1 .hl,.page-hero h1 .hl{color:var(--teal);}
.hero .lede{font-size:clamp(17px,2.1vw,21px);color:var(--text-2);max-width:56ch;margin:26px 0 0;line-height:1.55;}
.hero-cta{display:flex;gap:18px;flex-wrap:wrap;margin-top:36px;}
/* Forked from trialogic.io as a row of short uppercase trust chips (<span> + <i> dot).
   Our markup is a <ul> of sentence-length feature bullets, so the original `.trust span`
   and `.trust i` matched nothing: no teal dots, and the copy sat at 12px uppercase with
   .14em tracking. Retargeted to <li>, dot moved to ::before, and the uppercase/tracking
   dropped — sentences are not chips. */
.trust{margin-top:40px;display:flex;flex-direction:column;gap:12px;list-style:none;padding:0;
  font-family:var(--tech);font-size:13px;font-weight:400;color:var(--muted);}
.trust li{display:flex;align-items:center;gap:11px;}
.trust li::before{content:"";flex:none;width:6px;height:6px;border-radius:50%;
  background:var(--teal);box-shadow:0 0 10px var(--teal);}

/* Page hero with photo */
.page-hero{position:relative;overflow:hidden;border-bottom:1px solid var(--line);min-height:300px;display:flex;align-items:center;}
/* .page-hero-img pruned: it was forked for a background photo we never sourced (the stock
   licence question went unanswered). Prune = enforcement — a dead slot invites someone to
   fill it with the wrong thing. The ::after gradient wash below still carries the hero
   without a photo. */
.page-hero::after{content:"";position:absolute;inset:0;z-index:1;
  background:linear-gradient(135deg,rgba(0,214,214,.09) 0%,transparent 60%),
             linear-gradient(to right,rgba(8,10,12,.65) 0%,transparent 75%);}
.page-hero .wrap{position:relative;z-index:2;padding-top:clamp(40px,6vw,72px);padding-bottom:clamp(40px,6vw,72px);}
.page-hero h1{font-family:var(--sans);font-weight:700;font-size:clamp(32px,5.2vw,58px);
  line-height:1.06;letter-spacing:-0.022em;color:var(--white);margin:16px 0 0;max-width:22ch;}
.page-hero p{color:var(--text-2);font-size:clamp(16px,1.8vw,19px);margin:18px 0 0;max-width:52ch;}

/* Sections */
section.block{padding:clamp(40px,6vw,72px) 0;border-bottom:1px solid var(--line);}
.head{max-width:64ch;}
.head h2{font-family:var(--sans);font-weight:600;font-size:clamp(28px,4.4vw,44px);line-height:1.12;
  letter-spacing:-0.02em;color:var(--white);margin:16px 0 0;}
.head p{color:var(--text-2);font-size:clamp(17px,2vw,20px);margin:20px 0 0;max-width:60ch;}
.head p b,.head p strong{color:var(--white);font-weight:600;}

/* Feature split (home gap section) */
.feature-split .wrap{display:grid;grid-template-columns:1fr 1fr;gap:clamp(32px,5vw,80px);align-items:center;}
@media (max-width:780px){.feature-split .wrap{grid-template-columns:1fr;}}
/* .split-img pruned: its concept — the CRM/CTMS gap — became the DiagramGap SVG instead
   of a stock photo, so this slot will never have an asset. */

/* Tagline strip */
.strip{border-bottom:1px solid var(--line);background:var(--panel);}
.strip .wrap{padding:26px 0;text-align:center;}
.strip .t{font-family:var(--tech);font-weight:600;font-size:clamp(15px,2.6vw,24px);letter-spacing:.16em;text-transform:uppercase;color:var(--white);}
.strip .t .d{color:var(--teal);}

/* Service cards */
.grid{margin-top:52px;display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:18px;}
.card{position:relative;background:linear-gradient(180deg,#0D141B,#0A0F14);border:1px solid var(--line);
  border-radius:12px;padding:28px;transition:border-color .25s,transform .25s,box-shadow .25s;overflow:hidden;text-decoration:none;display:block;}
.card::before{content:"";position:absolute;left:0;top:0;height:2px;width:100%;
  background:linear-gradient(90deg,var(--teal),transparent);opacity:0;transition:opacity .25s;}
.card:hover{border-color:var(--line-2);transform:translateY(-3px);box-shadow:0 18px 40px rgba(0,0,0,.4);}
.card:hover::before{opacity:1;}
.card .num{font-family:var(--tech);font-size:12px;letter-spacing:.14em;color:var(--teal);}
.card h3{font-family:var(--sans);font-weight:600;font-size:21px;color:var(--white);margin:14px 0 0;line-height:1.2;}
.card p{color:var(--text-2);margin:11px 0 0;font-size:15.5px;}

/* Approach steps */
.steps{margin-top:52px;display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));
  border:1px solid var(--line);border-radius:12px;overflow:hidden;}
.step{padding:30px 26px;border-right:1px solid var(--line);background:var(--panel);}
.step:last-child{border-right:0;}
.step .n{font-family:var(--tech);font-size:26px;font-weight:600;color:var(--teal);letter-spacing:.04em;}
.step h3{font-family:var(--sans);font-weight:600;font-size:18px;color:var(--white);margin:12px 0 0;}
.step p{color:var(--text-2);margin:8px 0 0;font-size:14.5px;}
@media (max-width:760px){.step{border-right:0;border-bottom:1px solid var(--line);}.step:last-child{border-bottom:0;}}

/* Industries */
.ind{margin-top:48px;display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:16px;}
/* Left bar is --line, not --teal: .ind only ever holds ROADMAP products, and teal is the
   emphasis colour reserved for what ships. /platform deliberately strips teal from these
   same three; the two pages must not disagree about whether unshipped items get accented. */
.ind div{border:1px solid var(--line);border-left:2px solid var(--line);border-radius:8px;padding:22px;
  background:var(--panel);font-family:var(--sans);font-weight:600;font-size:17px;color:var(--white);}
.ind div small{display:block;font-family:var(--tech);font-weight:400;font-size:12px;letter-spacing:.08em;
  color:var(--muted);margin-top:8px;text-transform:uppercase;}

/* About / bio */
.about-grid{display:grid;grid-template-columns:1fr 380px;gap:clamp(40px,6vw,100px);align-items:start;}
@media (max-width:820px){.about-grid{grid-template-columns:1fr;}}
.about-bio p{color:var(--text-2);font-size:clamp(16px,1.9vw,19px);margin:20px 0 0;max-width:64ch;line-height:1.65;}
/* Match <strong> too — the bio uses semantic <strong>, and `b` alone would leave the
   two load-bearing facts ("fourteen years... at Covance", "RPM Technologies") in body
   grey. Same fix already applied to `.head p b,.head p strong`. */
.about-bio p b,.about-bio p strong{color:var(--white);}
/* .about-img was forked for a RECTANGULAR photo: 12px radius, 1px border, object-fit
   cover at 420px, brightness(.8) saturate(.85). The actual asset is a 420x420
   TRANSPARENT CUTOUT, so those rules boxed a floating cutout and dimmed his face.
   trialogic.io renders this same file as a circle, no border, no filter. Matched. */
.portrait{position:sticky;top:90px;display:flex;justify-content:center;}
.portrait img{width:100%;max-width:300px;height:auto;aspect-ratio:1;border-radius:50%;object-fit:cover;
  object-position:center top;background:var(--panel);}
/* height:auto is load-bearing, not decorative. The <img> carries width="420"
   height="420" attributes (correct -- reserves layout space, avoids CLS), which the
   HTML spec maps to a UA-origin `height:420px` presentational hint. This rule sets
   width (resolved to 300px) and aspect-ratio, but never set height -- so height fell
   through to that 420px hint. With width AND height both already definite from other
   declarations, aspect-ratio:1 had nothing left to compute: rendered box was 300x420,
   a 5:7 oval, not a circle. height:auto vacates the height property so aspect-ratio
   actually drives it. Measured via getBoundingClientRect at 1280 and 390 -- a 5:7
   oval with border-radius:50% still reads as "roundish" in a screenshot, so this did
   not show up by eye at either width until the numbers were pulled. */
@media (max-width:820px){.portrait{position:static;justify-content:flex-start;}}

/* About links */
.about-links{margin-top:36px;display:flex;gap:16px;flex-wrap:wrap;}

/* CTA block */
.cta-block{position:relative;overflow:hidden;border-bottom:1px solid var(--line);
  background:radial-gradient(90% 140% at 50% 0%,rgba(0,214,214,.16),transparent 60%),var(--panel);}
.cta-block .wrap{padding:clamp(40px,6vw,72px) 0;text-align:center;}
.cta-block h2{font-family:var(--sans);font-weight:700;font-size:clamp(28px,4.6vw,48px);line-height:1.08;
  letter-spacing:-0.02em;color:var(--white);margin:16px auto 0;max-width:20ch;}
.cta-block p{color:var(--text-2);margin:20px auto 0;max-width:48ch;font-size:18px;}
.cta-block .btn{margin-top:34px;}

/* Footer */
footer{padding:44px 0;}
.foot{display:flex;align-items:flex-start;justify-content:space-between;gap:24px;flex-wrap:wrap;}
.foot .bn{font-family:var(--tech);font-weight:600;font-size:17px;letter-spacing:.14em;color:var(--white);}
.foot .bn b{color:var(--teal);}
.foot .tag{font-family:var(--tech);font-size:11px;letter-spacing:.24em;text-transform:uppercase;color:var(--muted);margin-top:8px;}
.foot-legal{display:flex;gap:20px;flex-wrap:wrap;}
.foot-legal a{font-family:var(--tech);font-size:12px;letter-spacing:.08em;text-transform:uppercase;text-decoration:none;color:var(--text-2);}
.foot-legal a:hover{color:var(--teal);}
.foot small{display:block;font-family:var(--tech);font-size:12px;color:var(--muted);letter-spacing:.06em;margin-top:14px;}

/* Reveal */
.reveal{opacity:0;transform:translateY(18px);transition:opacity .7s ease,transform .7s ease;}
.reveal.in{opacity:1;transform:none;}
@media (prefers-reduced-motion:reduce){.reveal{opacity:1;transform:none;transition:none;}}
:focus-visible{outline:2px solid var(--teal);outline-offset:3px;border-radius:2px;}

/* Mobile nav */
.burger{display:none;flex-direction:column;justify-content:center;gap:5px;
  width:36px;height:36px;background:none;border:none;cursor:pointer;padding:4px;flex:none;}
.burger span{display:block;height:2px;background:var(--text);border-radius:2px;
  transition:transform .25s,opacity .25s,width .25s;}
.burger.open span:nth-child(1){transform:translateY(7px) rotate(45deg);}
.burger.open span:nth-child(2){opacity:0;}
.burger.open span:nth-child(3){transform:translateY(-7px) rotate(-45deg);}
.mobile-nav{display:none;flex-direction:column;gap:0;background:rgba(8,10,12,.97);
  border-bottom:1px solid var(--line);padding:12px var(--gutter) 20px;}
.mobile-nav.open{display:flex;}
.mobile-nav a{font-family:var(--tech);font-size:13px;letter-spacing:.12em;text-transform:uppercase;
  text-decoration:none;color:var(--text-2);padding:14px 0;border-bottom:1px solid var(--line);}
.mobile-nav a:last-child{border-bottom:0;}
.mobile-nav .btn-primary{background:transparent;border-color:transparent;color:var(--text-2);padding:14px 0;border-radius:0;box-shadow:none;}
.mobile-nav a:hover{color:var(--teal);}
@media (max-width:860px){
  .burger{display:flex;}
  .nav-links a:not(.nav-cta){display:none;}
  .nav-cta{display:none;}
}
@media (min-width:861px){
  .mobile-nav{display:none !important;}
}

.callout { background:var(--panel);border:1px solid var(--line);border-left:3px solid var(--teal);
  border-radius:8px;padding:20px 24px;margin:16px 0 0; }
.callout p { margin:0; }
.callout p + p { margin-top:10px; }

/* Diagrams. Inline SVG so it inherits the custom properties and themes with the page;
   an exported raster could not use --teal, could not be read by a screen reader, and
   would not be crisp at 2x. viewBox scales it; the wrapper only handles narrow screens,
   where a wide schematic must scroll inside itself rather than force the body sideways. */
.dgm{margin-top:40px;overflow-x:auto;}
.dgm svg{width:100%;height:auto;min-width:520px;display:block;}
.dgm figcaption{margin-top:14px;font-family:var(--tech);font-size:12px;letter-spacing:.06em;
  color:var(--muted);min-width:0;}

/* Constellation backdrop, forked from trialogic.io. .hero is already position:relative
   with overflow:hidden, and .hero .wrap is already z-index:2, so this sits behind the
   copy without touching either. */
#net{position:absolute;inset:0;width:100%;height:100%;z-index:0;}

/* --- Specificity corrections (must stay last) --- */

/* .eyebrow is (0,1,0) and loses to .head p / .page-hero p / .cta-block p, all (0,1,1).
   17 of 21 eyebrows on the site sat inside one of those, so the section labels rendered
   at 17-20px in --text-2 grey instead of 12px teal — the accent was gone from nearly
   every section while every text assertion still passed. p.eyebrow ties at (0,1,1) and
   wins on source order, so this block has to remain at the end of the file. */
p.eyebrow{font-family:var(--tech);font-size:12px;font-weight:500;letter-spacing:.26em;
  text-transform:uppercase;color:var(--teal);margin:0;max-width:none;}
