/* The Frosted Pixel homepage. All photography is generated placeholder artwork and every
   metric and testimonial is illustrative - swap in real assets before launch. */

/* ---- fonts: self-hosted (2026-10-20), no request ever goes to Google. The
   latin woff2 subsets from Google Fonts (all SIL Open Font License), in
   assets/fonts/. A face only downloads when a page uses it (Inter is only the
   campaign demo's). Hanken Grotesk is preloaded in every page head. ---- */
@font-face { font-family: 'Hanken Grotesk'; font-style: normal; font-weight: 400 700; font-display: swap;
  src: url(fonts/hanken-grotesk-latin-var.woff2) format('woff2'); }
@font-face { font-family: 'JetBrains Mono'; font-style: normal; font-weight: 400 500; font-display: swap;
  src: url(fonts/jetbrains-mono-latin-var.woff2) format('woff2'); }
@font-face { font-family: 'IBM Plex Mono'; font-style: normal; font-weight: 400; font-display: swap;
  src: url(fonts/ibm-plex-mono-latin-400.woff2) format('woff2'); }
@font-face { font-family: 'IBM Plex Mono'; font-style: normal; font-weight: 500; font-display: swap;
  src: url(fonts/ibm-plex-mono-latin-500.woff2) format('woff2'); }
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 400 700; font-display: swap;
  src: url(fonts/inter-latin-var.woff2) format('woff2'); }

:root { --shellh: 0px; }
*, *::before, *::after { box-sizing: border-box; }
body { margin: 0; background: #F7F9FC; -webkit-font-smoothing: antialiased; }
img, svg { max-width: 100%; }

/* ============================================================
   SHARED VISUAL COMPONENT LIBRARY
   Components read tokens, so a band that overrides the tokens
   restyles everything inside it - that is how the dark acts work.
   ============================================================ */
.fp { --k-sf:#fff; --k-sf2:#F1F4F3; --k-ink:#101614; --k-mu:#63736E; --k-line:rgba(16,22,20,.12);
      --k-acc:#1C7A63; --k-acc2:#2F5D8A; --k-r:10px; --k-sh:0 16px 34px -22px rgba(16,22,20,.3);
      /* film grain, tiled behind every ground: dark speckle for light bands, light for dark bands */
      --grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.05 0'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/svg%3E");
      --grainw: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.04 0'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/svg%3E"); }



/* ---- placeholder photography ---- */
.fp-ph { position: relative; overflow: hidden; background: var(--k-sf2); border-radius: var(--k-r); isolation: isolate; }
.fp-ph::before { content: ""; position: absolute; inset: 0; z-index: 0;
  background:
    radial-gradient(120% 90% at 12% 8%, var(--p1, #9FD8C6) 0%, transparent 58%),
    radial-gradient(100% 80% at 88% 22%, var(--p2, #7FA6C9) 0%, transparent 55%),
    radial-gradient(120% 100% at 60% 100%, var(--p3, #2E4A45) 0%, transparent 62%),
    linear-gradient(150deg, var(--p4, #43665E) 0%, var(--p5, #16211F) 100%); }
.fp-ph::after { content: ""; position: absolute; inset: 0; z-index: 2; pointer-events: none; opacity: .30; mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.75' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E"); }
.fp-ph > svg { position: relative; z-index: 1; width: 100%; height: 100%; display: block; }
.fp-ph .tag { position: absolute; z-index: 3; left: 10px; bottom: 9px; font-family: 'IBM Plex Mono', monospace; font-size: 8.5px; letter-spacing: .04em; text-transform: uppercase; color: rgba(255,255,255,.72); background: rgba(0,0,0,.28); backdrop-filter: blur(3px); padding: 3px 7px; border-radius: 3px; }
.fp-ph.pw-c { --p1:#B8CFE8; --p2:#8FA8C4; --p3:#1E2C3E; --p4:#3F5871; --p5:#0F161F; }


/* ---- analytics dashboard ---- */



.fp-chat-b { padding: 14px; display: grid; gap: 9px; }





/* ---- scroll reveal: bigger travel, slower ease (the refs move ~100px) ---- */
/* ---- page entrance: inner pages load as a sequence, not a cut. The chrome
   paints instantly, the page-header elements rise one after another, and the
   first section follows while the heading is still settling - overlapping
   delays, so nothing waits around. The homepage keeps its own hero
   choreography. One motion source: retime every page from these tokens ---- */
#site { --load-t: .7s; --load-e: cubic-bezier(.16,.6,.18,1); --load-y: 22px; --load-stag: 90ms; }
html.js-anim:not(.fp-wait) body:not([data-page="home"]) #site .phead .wrap > *,
html.js-anim:not(.fp-wait) body:not([data-page="home"]) #site main > :not(.phead):not(.phband) {
  animation: fpload var(--load-t) var(--load-e) both; }
html.js-anim:not(.fp-wait) body:not([data-page="home"]) #site .phband .wrap > * {
  animation: fpload var(--load-t) var(--load-e) both; }
html.js-anim:not(.fp-wait) body:not([data-page="home"]) #site .phead .wrap > :nth-child(2) { animation-delay: var(--load-stag); }
html.js-anim:not(.fp-wait) body:not([data-page="home"]) #site .phead .wrap > :nth-child(3) { animation-delay: calc(var(--load-stag) * 2); }
html.js-anim:not(.fp-wait) body:not([data-page="home"]) #site .phead .wrap > :nth-child(4) { animation-delay: calc(var(--load-stag) * 3); }
html.js-anim:not(.fp-wait) body:not([data-page="home"]) #site .phead .wrap > :nth-child(n+5) { animation-delay: calc(var(--load-stag) * 4); }
html.js-anim:not(.fp-wait) body:not([data-page="home"]) #site main > :not(.phead):not(.phband) { animation-delay: calc(var(--load-stag) * 4); }
/* the band carries only the page name, so the section under it takes the
   beat the lead would have had inside a .phead rather than waiting for the
   full four-step delay the rest of the page runs on */
html.js-anim:not(.fp-wait) body:not([data-page="home"]) #site .phband + * { animation-delay: var(--load-stag); }
/* every entrance is keyed on :not(.fp-wait), so it starts the moment the page
   is shown rather than while it is still held hidden for loading - before,
   a fast load showed it half-way through, a slow one finished, so how the
   page arrived depended on the connection (James 2026-10-20: rough on iPad) */
/* starts at .01, not 0: an element that first paints at opacity 0 and then
   fades in on the compositor is never repainted, so Chrome never reports it
   as the largest contentful paint (PageSpeed: NO_LCP). .01 looks the same */
@keyframes fpload { from { opacity: .01; transform: translateY(var(--load-y)); } }
@media (prefers-reduced-motion: reduce) {
  html.js-anim:not(.fp-wait) body:not([data-page="home"]) #site .phead .wrap > *,
  html.js-anim:not(.fp-wait) body:not([data-page="home"]) #site .phband .wrap > *,
  html.js-anim:not(.fp-wait) body:not([data-page="home"]) #site main > :not(.phead):not(.phband) { animation: none; }
}

.rv { opacity: 1; transform: none; }
html.js-anim .rv { opacity: 0; transform: translateY(34px); transition: opacity .8s cubic-bezier(.16,.6,.18,1), transform .8s cubic-bezier(.16,.6,.18,1); }
html.js-anim .rv.in { opacity: 1; transform: none; }
 html.js-anim .rv.d2 { transition-delay: .18s }
 
/* ---- auto-stagger: a .rv container with data-stag animates its CHILDREN
   in sequence instead of fading as one slab ---- */
html.js-anim .rv[data-stag] { opacity: 1; transform: none; }
html.js-anim .rv[data-stag] > * { opacity: 0; transform: translateY(34px); transition: opacity .8s cubic-bezier(.16,.6,.18,1), transform .8s cubic-bezier(.16,.6,.18,1); }
html.js-anim .rv[data-stag].in > * { opacity: 1; transform: none; }
html.js-anim .rv[data-stag] > *:nth-child(2) { transition-delay: .09s }
html.js-anim .rv[data-stag] > *:nth-child(3) { transition-delay: .18s }
html.js-anim .rv[data-stag] > *:nth-child(4) { transition-delay: .27s }
html.js-anim .rv[data-stag] > *:nth-child(5) { transition-delay: .36s }
html.js-anim .rv[data-stag] > *:nth-child(6) { transition-delay: .45s }
html.js-anim .rv[data-stag] > *:nth-child(n+7) { transition-delay: .54s }

/* touch screens (James 2026-10-20: on a phone things "jump or flash" as they
   load on the FAQ page): a flick moves a block from the bottom edge to the
   middle of the screen in a fraction of the .8s reveal, so the 34px rise
   showed as a jump against the scroll and the fade as a flash. On touch the
   reveal starts a little before the block enters (site.js reveals 12% of the
   screen early there), rises 18px over .6s and the stagger is halved, so a
   block is mostly settled by the time it is in view */
@media (hover: none) {
  html.js-anim .rv:not(.in), html.js-anim .rv[data-stag]:not(.in) > * { transform: translateY(18px); }
  html.js-anim .rv, html.js-anim .rv[data-stag] > * { transition-duration: .6s, .6s; }
  html.js-anim .rv[data-stag] > *:nth-child(2) { transition-delay: .05s }
  html.js-anim .rv[data-stag] > *:nth-child(3) { transition-delay: .1s }
  html.js-anim .rv[data-stag] > *:nth-child(4) { transition-delay: .15s }
  html.js-anim .rv[data-stag] > *:nth-child(5) { transition-delay: .2s }
  html.js-anim .rv[data-stag] > *:nth-child(6) { transition-delay: .25s }
  html.js-anim .rv[data-stag] > *:nth-child(n+7) { transition-delay: .3s }
}

@media (prefers-reduced-motion: reduce) {
  html.js-anim .rv, html.js-anim .rv[data-stag] > * { opacity: 1; transform: none; transition: none; }
}

#site { --k-sf:#FFFFFF; --k-sf2:#EEF2F9; --k-ink:#0B1B33; --k-mu:#45556E; --k-line:rgba(11,27,51,.13);
      --k-acc:#2C5FD8; --k-acc2:#47A045; --k-r:8px; --k-sh:0 16px 34px -22px rgba(11,27,51,.3);
      --bg:#F7F9FC; --cb:#2C5FD8; --nvy:#0A1730; --lime:#9FE870;
      /* heavier grains for the crew-style field: visible speckle, not a wash */
      --grainx: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.08 0'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
      --graind: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='150' height='150'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.75' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0.02 0 0 0 0 0.07 0 0 0 0 0.2 0 0 0 0.07 0'/%3E%3C/filter%3E%3Crect width='150' height='150' filter='url(%23n)'/%3E%3C/svg%3E");
  background: var(--grain), var(--bg);
  color: var(--k-ink);
  font-family: 'Hanken Grotesk', 'Segoe UI', system-ui, sans-serif; font-size: 17px; line-height: 1.6; }
#site .wrap { max-width: 1240px; margin: 0 auto; padding: 0 30px; }
/* the page ground behind the dark hero: elastic overscroll at the top must
   show dark, never a white flash above the hero */
body[data-page="home"] { background: #00010A; }
/* inner pages that open on the dark band get the same dark ground */
body.dkhero:not([data-page="home"]) { background: var(--nvy, #0A1730); }
#site h1,#site h2,#site h3,#site h4 { font-weight: 600; letter-spacing: -.038em; text-wrap: balance; margin: 0; color: var(--k-ink); }
#site a:focus-visible, #site button:focus-visible { outline: 2px solid var(--cb); outline-offset: 3px; }
/* one hover motion for every button on the site, defined once: lift by
   --btn-lift over --btn-t. Variant rules below may only change colour -
   never the motion */
#site { --btn-lift: -2px; --btn-t: .18s; }

/* ---- the house underline ----
   One wipe, one timing, everywhere a link underlines itself on hover: the
   rule grows from the left on the same curve the nav bar and the footer
   links already used, which were .25s and .3s respectively and now share a
   token. It is painted as a background gradient rather than
   text-decoration so its width is animatable at all.

   --ul-tail holds the rule back from the right-hand edge. Several of these
   links are inline-flex with the lottie arrow after the text, and the
   underline has no business running under an arrow, so those set the tail
   to the arrow's own advance - width plus the flex gap - and the wipe stops
   exactly where the text does.

   To give any other link the same behaviour, add class="uline". */
#site { --ul-dur: .3s; --ul-ease: cubic-bezier(.2,.7,.25,1); --ul-h: 1px; --ul-gap: 2px;
  --arr-w: 15px; --arr-gap: 9px; --ul-tail: 0px; }
#site .uline,
#site footer ul a, #site .fvb .meta a, #site .fbot a {
  text-decoration: none; padding-bottom: var(--ul-gap);
  background-image: linear-gradient(currentColor, currentColor);
  background-repeat: no-repeat; background-position: 0 100%;
  background-size: 0 var(--ul-h);
  transition: color var(--ul-dur) var(--ul-ease), background-size var(--ul-dur) var(--ul-ease); }
#site .uline:hover,
#site footer ul a:hover, #site .fvb .meta a:hover, #site .fbot a:hover { background-size: calc(100% - var(--ul-tail)) var(--ul-h); }
/* Links that carry the lottie arrow stop the rule short of it. They are also
   inline-flex, which makes their content box the full line box - so the
   half-leading under the text pushed the rule about 3px further from the
   word than on the plain inline footer links. Normal leading collapses the
   box back onto the glyph box, and every underline then sits the same
   --ul-gap below its text wherever it appears. */
@media (prefers-reduced-motion: reduce) {
  #site .uline, #site footer ul a, #site .fvb .meta a, #site .fbot a { transition: none; }
}
/* Links that carry the lottie arrow all share the case studies page's
   "View case study" underline (James 2026-10-12): a 2px rule in the link's
   colour that draws under the text AND the arrow - .6s outExpo in, .5s out.
   Any new link with <i class="arr" data-arrow> gets it automatically;
   buttons, pills and image links are left out. */
#site a:has(> .arr[data-arrow]):not(.btn):not(.fwshot):not(.f2-lk),
#site h3 > a:has(> .arr[data-arrow]) { position: relative; text-decoration: none; padding-bottom: 7px; line-height: normal; }
#site a:has(> .arr[data-arrow]):not(.btn):not(.fwshot):not(.f2-lk)::after {
  content: ""; position: absolute; left: 0; bottom: 0; height: 2px; width: 0; background: currentColor;
  transition: width .5s cubic-bezier(.19,1,.22,1); }
#site a:has(> .arr[data-arrow]):not(.btn):not(.fwshot):not(.f2-lk):hover::after,
#site a:has(> .arr[data-arrow]):not(.btn):not(.fwshot):not(.f2-lk):focus-visible::after { width: 100%; transition-duration: .6s; }
#site a:has(> .arr[data-arrow]) .arr svg [stroke] { stroke: currentColor; }
@media (prefers-reduced-motion: reduce) { #site a:has(> .arr[data-arrow])::after { transition: none; } }
#site button.btn { appearance: none; -webkit-appearance: none; border: 0; cursor: pointer; font: inherit; }
#site .btn { display: inline-flex; align-items: center; gap: 9px; font-family: inherit; font-size: 15px; letter-spacing: -.01em; font-weight: 600; padding: 14px 26px; border-radius: 6px; text-decoration: none; transition: transform var(--btn-t), box-shadow var(--btn-t), background var(--btn-t), border-color var(--btn-t), color var(--btn-t); }
#site .btn:hover, #site .bk:hover { transform: translateY(var(--btn-lift)); }
#site .btn.wh { background: #fff; color: var(--nvy); box-shadow: 0 14px 30px -18px rgba(4,12,30,.7); }
#site .btn.gh { border: 1px solid rgba(255,255,255,.55); color: #fff; }
#site .btn.gh:hover { background: rgba(255,255,255,.1); }
#site .btn.dk { border: 1px solid rgba(11,27,51,.35); color: var(--nvy); }
#site .btn.dk:hover { background: rgba(11,27,51,.06); }
#site .btn.cb { background: var(--cb); color: #fff; box-shadow: 0 14px 30px -18px rgba(44,95,216,.8); }
#site .btn.cb:hover, #site .bk:hover { background: #2450BE; }

/* ============ NAV + MEGAMENU (thunderclap pattern) ============ */
/* the empty [data-nav] placeholder holds the bar's exact final height, so the
   deferred mount never grows the document - late growth above the viewport is
   what let the browser anchor a fresh load slightly below the top. --navh is
   declared here per breakpoint so pre-JS layout equals post-JS layout; the JS
   measurement overrides it inline once the bar exists */
:root { --navh: 77px; }
@media (max-width: 620px) { :root { --navh: 65px; } }
@media (max-width: 430px) { :root { --navh: 57px; } }
#site > [data-nav] { height: var(--navh, 77px); }
#site .nv { position: sticky; top: var(--shellh, 0px); z-index: 90; color: #33465F;
  background: transparent; border-bottom: 1px solid rgba(11,27,51,.07);
  transition: background .35s ease, border-color .35s ease, color .35s ease, transform .35s ease, box-shadow .35s ease; }
#site .nv.scrolled { background: rgba(252,253,255,.9); -webkit-backdrop-filter: blur(14px) saturate(150%); backdrop-filter: blur(14px) saturate(150%); border-bottom-color: rgba(11,27,51,.1); box-shadow: 0 18px 40px -32px rgba(11,27,51,.5); }
#site .nv.mmopen { background: #FCFDFF; border-bottom-color: rgba(11,27,51,.1); }
#site .nv.hide { transform: translateY(-115%); }
@media (prefers-reduced-motion: reduce) { #site .nv.hide { transform: none; } }
#site .nvrow { display: flex; align-items: center; gap: 26px; height: 76px; padding: 0 30px; max-width: 1240px; margin: 0 auto; }
#site .nv .lg { display: block; margin-right: auto; color: var(--nvy); flex: none; }
#site .nv .lg svg { display: block; height: 34px; width: auto; }
#site .mn { display: flex; align-items: center; gap: 4px; }
#site .mn > a, #site .mi > .mtrig { appearance: none; background: transparent; border: 0; cursor: pointer; font: inherit; font-size: 14.5px; font-weight: 500; color: inherit; text-decoration: none; padding: 9px 13px; border-radius: 5px; display: inline-flex; align-items: center; gap: 6px; transition: background .16s, color .16s; }
#site .mn > a:hover, #site .mi > .mtrig:hover { background: rgba(11,27,51,.06); color: var(--nvy); }
#site .mi > .mtrig svg { width: 10px; height: 10px; transition: transform .2s; }
#site .mi > .mtrig[aria-expanded="true"] { background: rgba(44,95,216,.09); color: var(--cb); }
#site .mi > .mtrig[aria-expanded="true"] svg { transform: rotate(180deg); }
#site .bk { display: inline-flex; align-items: center; font-family: inherit; font-size: 14.5px; letter-spacing: -.01em; font-weight: 600; background: var(--cb); color: #fff; text-decoration: none; padding: 11px 20px; border-radius: 6px; white-space: nowrap; transition: transform var(--btn-t), background var(--btn-t), color var(--btn-t); }
html.mmlock { overflow: hidden; padding-right: var(--sbw, 0px); }

/* over the dark hero the whole nav system runs dark until scrolled;
   any other scroll position gets the standard light glass chrome */
#site .nv.ondark:not(.scrolled) { color: #E4EAF6; border-bottom-color: rgba(255,255,255,.09); }
#site .nv.ondark:not(.scrolled) .lg { color: #FFFFFF; }
#site .nv.ondark:not(.scrolled) .mn > a:hover,
#site .nv.ondark:not(.scrolled) .mi > .mtrig:hover { background: rgba(255,255,255,.09); color: #fff; }
#site .nv.ondark:not(.scrolled) .mi > .mtrig[aria-expanded="true"] { background: rgba(255,255,255,.13); color: #fff; }
#site .nv.ondark:not(.scrolled) .mn > a::after,
#site .nv.ondark:not(.scrolled) .mi > .mtrig::after { background: #7FA4F2; }
#site .nv.ondark:not(.scrolled) .burger { border-color: rgba(255,255,255,.3); }
#site .nv.ondark:not(.scrolled) .burger span { background: #fff; }
#site .nv.ondark.mmopen:not(.scrolled), #site .nv.ondark.dropen:not(.scrolled) { background: #070D1B; border-bottom-color: rgba(255,255,255,.1); }
#site .nv.ondark:not(.scrolled) .mm { background: #070D1B; border-top-color: rgba(255,255,255,.07); border-bottom-color: rgba(255,255,255,.12); box-shadow: 0 40px 74px -36px rgba(0,0,0,.85); }
#site .nv.ondark:not(.scrolled) .mmh { color: #fff; }
#site .nv.ondark:not(.scrolled) .mms { color: #C9D6E9; }
#site .nv.ondark:not(.scrolled) .mmi:hover { background: rgba(255,255,255,.06); }
#site .nv.ondark:not(.scrolled) .mmi .ic { background: rgba(255,255,255,.07); border-color: rgba(255,255,255,.13); }
#site .nv.ondark:not(.scrolled) .mmi .ic svg { stroke: #7FA4F2; }
#site .nv.ondark:not(.scrolled) .mmi b { color: #FFFFFF; }
#site .nv.ondark:not(.scrolled) .mmi i { color: #C9D6E9; }
#site .nv.ondark:not(.scrolled) .mmpromo { background: rgba(255,255,255,.05); border-color: rgba(255,255,255,.13); }
#site .nv.ondark:not(.scrolled) .mmpromo .mmt { color: #fff; }
#site .nv.ondark:not(.scrolled) .mmpromo p { color: #C9D6E9; }
#site .nv.ondark:not(.scrolled) .mmpromo a { color: #9FBCF7; }
#site .nv.ondark:not(.scrolled) .mmviz { border-color: rgba(255,255,255,.1);
  background: linear-gradient(rgba(214,224,240,.06) 1px, transparent 1px), linear-gradient(90deg, rgba(214,224,240,.06) 1px, transparent 1px), #0B1526;
  background-size: 22px 22px; }
#site .nv.ondark:not(.scrolled) .mmviz .bx rect { fill: rgba(255,255,255,.04); stroke: rgba(255,255,255,.3); }
#site .nv.ondark:not(.scrolled) .mmviz text { fill: #C9D6E9; }
#site .nv.ondark:not(.scrolled) .mmviz .go text { fill: #9FE870; }
#site .nv.ondark:not(.scrolled) .mmviz .go rect { stroke: #9FE870; fill: rgba(159,232,112,.08); }
#site .nv.ondark:not(.scrolled) .mmviz .cut rect { stroke: rgba(255,255,255,.2); }
#site .nv.ondark:not(.scrolled) .mmviz .cut text { fill: rgba(201,214,233,.62); }
#site .nv.ondark:not(.scrolled) .drawer:not([hidden]) { background: #070D1B; border-bottom-color: rgba(255,255,255,.12); }
#site .nv.ondark:not(.scrolled) .drawer .top a { color: #FFFFFF; }
#site .nv.ondark:not(.scrolled) .drawer .top a[aria-current="page"] { color: #9FBCF7; }
#site .nv.ondark:not(.scrolled) .drawer .dsx { color: #FFFFFF; border-bottom-color: rgba(255,255,255,.12); }
#site .nv.ondark:not(.scrolled) .drawer .svc { border-bottom-color: rgba(255,255,255,.12); }
#site .nv.ondark:not(.scrolled) .drawer .svc a { color: #DCE4F2; border-bottom-color: rgba(255,255,255,.08); }
#site .nv.ondark:not(.scrolled) .drawer .dmail { color: #AEBDD4; }
#site .nv.ondark:not(.scrolled) .drawer .dmail a { color: #9FBCF7; }
#site .mm { position: absolute; left: 0; right: 0; top: 100%; background: #FCFDFF; border-top: 1px solid rgba(11,27,51,.08); border-bottom: 1px solid rgba(11,27,51,.12); box-shadow: 0 40px 74px -36px rgba(11,27,51,.42);
  opacity: 0; transform: translateY(-10px); pointer-events: none;
  transition: opacity .18s ease, transform .2s cubic-bezier(.2,.7,.25,1), background .35s ease; }
#site .mm.open { opacity: 1; transform: none; pointer-events: auto; }
#site .mm[hidden] { display: none; }
#site .mmg { display: grid; grid-template-columns: 1fr 1fr 320px; gap: 44px; padding: 34px 30px 38px; max-width: 1240px; margin: 0 auto; }
#site .mmh { margin: 0 0 4px; font-size: 16.5px; font-weight: 700; letter-spacing: -.02em; color: var(--nvy); }
#site .mms { margin: 0 0 18px; font-size: 14.5px; color: #55657D; max-width: 34ch; }
#site .mmcol { display: grid; gap: 4px; align-content: start; }
#site .mmi { display: flex; align-items: center; gap: 13px; text-decoration: none; padding: 9px 10px; margin: 0 -10px; border-radius: 8px; transition: background .16s; }
#site .mmi:hover { background: #F1F5FC; }
#site .mmi .ic { flex: none; width: 38px; height: 38px; border-radius: 9px; background: #EEF2F9; border: 1px solid rgba(11,27,51,.09); display: grid; place-items: center; }
#site .mmi .ic svg { width: 18px; height: 18px; stroke: var(--cb); stroke-width: 1.6; fill: none; stroke-linecap: round; stroke-linejoin: round; }
#site .mmi b { display: block; font-size: 14.5px; font-weight: 600; letter-spacing: -.015em; color: var(--nvy); }
#site .mmi i { display: block; font-style: normal; font-size: 12.5px; color: #55657D; }
#site .mmpromo { background: #EEF3FC; border: 1px solid rgba(11,27,51,.09); border-radius: 12px; padding: 20px; align-self: start; }
#site .mmviz { margin-bottom: 16px; border-radius: 8px; overflow: hidden; border: 1px solid rgba(11,27,51,.08);
  background: linear-gradient(rgba(11,27,51,.045) 1px, transparent 1px), linear-gradient(90deg, rgba(11,27,51,.045) 1px, transparent 1px), #F7FAFF;
  background-size: 22px 22px; }
#site .mmviz svg { display: block; width: 100%; height: auto; }
#site .mmviz .bx rect { fill: #fff; stroke: rgba(11,27,51,.3); stroke-dasharray: 4 3; }
#site .mmviz text { font-family: 'JetBrains Mono', monospace; font-size: 8px; letter-spacing: .04em; fill: #5B6C86; text-anchor: middle; }
#site .mmviz .ln { fill: none; stroke: rgba(44,95,216,.45); stroke-dasharray: 3 4; }
#site .mmviz .hub { fill: var(--cb); }
#site .mmviz .go rect { fill: rgba(101,163,63,.1); stroke: #47A045; }
#site .mmviz .go text { fill: #2F7A2E; font-weight: 700; font-size: 9px; }
#site .mmviz .cut rect { fill: transparent; stroke: rgba(11,27,51,.22); stroke-dasharray: 3 3; }
#site .mmviz .cut text { fill: rgba(51,70,95,.45); }
/* keep pace promo: the project line levels off, the Keep pace line compounds */
#site .mmviz.kp .ax { fill: none; stroke: rgba(11,27,51,.22); stroke-width: 1.2; }
#site .mmviz.kp .kpa { fill: rgba(71,160,69,.12); }
#site .mmviz.kp .kpl { fill: none; stroke: #47A045; stroke-width: 2.5; stroke-linecap: round; }
#site .mmviz.kp .pjl { fill: none; stroke: rgba(44,95,216,.6); stroke-width: 2; stroke-dasharray: 4 4; }
#site .mmviz.kp .d { fill: #fff; stroke: #47A045; stroke-width: 2; }
#site .mmviz.kp .pje { fill: #7EA4F6; }
#site .mmviz.kp .end { fill: #47A045; transform-box: fill-box; transform-origin: center; animation: mmend 2.2s ease-out infinite; }
@keyframes mmend { 0% { stroke: rgba(71,160,69,.55); stroke-width: 0; } 100% { stroke: rgba(71,160,69,0); stroke-width: 14px; } }
#site .nv.ondark:not(.scrolled) .mmviz.kp .ax { stroke: rgba(255,255,255,.25); }
#site .nv.ondark:not(.scrolled) .mmviz.kp .kpl, #site .nv.ondark:not(.scrolled) .mmviz.kp .d { stroke: #9FE870; }
#site .nv.ondark:not(.scrolled) .mmviz.kp .d { fill: #0A1730; }
#site .nv.ondark:not(.scrolled) .mmviz.kp .kpa { fill: rgba(159,232,112,.12); }
#site .nv.ondark:not(.scrolled) .mmviz.kp .end { fill: #9FE870; }
@media (prefers-reduced-motion: reduce) { #site .mmviz.kp .end { animation: none; } }
#site .mmpromo .mmt { margin: 0 0 6px; color: var(--nvy); font-size: 17px; font-weight: 600; line-height: 1.3; letter-spacing: -.02em; }
#site .mmpromo p { margin: 0 0 14px; font-size: 13px; line-height: 1.55; color: #45556E; }
#site .mmpromo a { display: inline-flex; align-items: center; gap: var(--arr-gap);
  font-size: 14px; font-weight: 600; letter-spacing: -.01em; color: var(--cb); text-decoration: none; }
#site .mmpromo .arr svg [stroke] { stroke: currentColor; }
@media (max-width: 620px) {
  #site .nvrow { gap: 12px; height: 64px; padding: 0 18px; }
  #site .nv .lg svg { height: 26px; }
  #site .bk { padding: 9px 14px; font-size: 13px; }
}
/* very narrow phones: the bar CTA gives way to the burger, and the drawer
   carries a full-width Book a call instead */
@media (max-width: 430px) {
  #site .nvrow { gap: 10px; height: 56px; padding: 0 14px; }
  #site .nv .lg svg { height: 24px; }
  #site .bk { display: none; }
}
@media (max-width: 940px) { #site .mn { display: none; } #site .mm { display: none !important; } }
@media (max-width: 1080px) { #site .mmg { grid-template-columns: 1fr 1fr; } #site .mmpromo { display: none; } }

/* ============ HERO FIELD (dark: 44px blocks under a cobalt glow) ============ */
#site .heroband { min-height: calc(100vh - var(--shellh, 44px)); min-height: calc(100svh - var(--shellh, 44px));
  display: flex; flex-direction: column; position: relative; isolation: isolate; color: #EAF0FA;
  margin-top: calc(-1 * var(--navh, 77px)); padding-top: var(--navh, 77px);
  background:
    radial-gradient(ellipse 72% 520px at 50% calc(100% - 200px), rgba(84,131,220,.46), rgba(8,11,22,.93) 96%),
    var(--graind) #00010A; }
/* the grid is a field of real blocks (site.js "homepage hero blocks"), so
   the ones under the mouse light up on desktop, like the case study heroes;
   before the script runs (or without it) the old hairline grid shows */
#site .heroband:not(:has(.hbk)) { background:
    linear-gradient(rgba(214,224,240,.05) 1px, transparent 1px),
    linear-gradient(90deg, rgba(214,224,240,.05) 1px, transparent 1px),
    radial-gradient(ellipse 72% 520px at 50% calc(100% - 200px), rgba(84,131,220,.46), rgba(8,11,22,.93) 96%),
    var(--graind) #00010A;
  background-size: 44px 44px, 44px 44px, auto, auto; }
#site .hbk { position: absolute; inset: 0; z-index: -1; overflow: hidden; pointer-events: none; }
#site .hbk i { position: absolute; width: 42px; height: 42px; border-radius: 3px; background: rgba(214,224,240,.035);
  transition: background-color .35s ease-out, box-shadow .35s ease-out; }
#site .hbk i.hl { background: rgba(84,131,255,var(--h)); box-shadow: 0 0 16px rgba(84,131,255,calc(var(--h) * .35)); transition: none; }
/* touch screens: the same blocks painted as one background (site.js .bgf) */
#site .hbk.bgf { background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='44' height='44'%3E%3Crect x='1' y='1' width='42' height='42' rx='3' fill='rgb(214,224,240)' fill-opacity='.035'/%3E%3C/svg%3E") 0 0 / 44px 44px repeat; }
/* the blocks carry on into the top of the "What we do" band and fade out
   down it (and as it turns light on scroll), in place of its hairline grid */
#site .blkband .hbk2 { z-index: 0;
  -webkit-mask-image: linear-gradient(to bottom, rgb(0 0 0 / calc(1 - var(--lts, 0))) 0, rgb(0 0 0 / calc((1 - var(--lt, 0)) * .6)) 280px, transparent 46%);
  mask-image: linear-gradient(to bottom, rgb(0 0 0 / calc(1 - var(--lts, 0))) 0, rgb(0 0 0 / calc((1 - var(--lt, 0)) * .6)) 280px, transparent 46%); }
#site .blkband:has(.hbk2)::after { display: none; }

/* every study: a centred main stage plus a bottom rail that carries the
   eye across the seam into the section below */
#site .hv { display: none; }
#site .hv.on { display: flex; flex-direction: column; flex: 1; min-height: 0; }
#site .heroband h1 { color: #fff; background: linear-gradient(0deg, #C4D3EA, #FFFFFF 80%);
  -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent; }
#site .heroband .tlink { color: #fff; border-bottom-color: rgba(255,255,255,.34); }
#site .heroband .tlink:hover { color: #AFC8FF; border-color: #AFC8FF; }
/* from .01 for the same reason as fpload: the hero text must count as the LCP */

/* shared hero furniture */
#site .hbtns { display: flex; gap: 12px; align-items: center; flex-wrap: wrap; }
#site .tlink { font-size: 14.5px; font-weight: 600; color: var(--nvy); text-decoration: none; border-bottom: 1.5px solid rgba(11,27,51,.22); padding-bottom: 2px; transition: color .18s, border-color .18s; }
#site .tlink:hover { color: var(--cb); border-color: var(--cb); }

/* ============ DARK BLOCK GRID (thunderclap screenshot) ============ */
#site .blkband { position: relative; color: #45556E; padding: clamp(64px, 7vw, 96px) 0;
  --k-sf:#FFFFFF; --k-sf2:#EEF2F9; --k-ink:#0B1B33; --k-mu:#45556E; --k-line:rgba(11,27,51,.13);
  --k-acc:#2C5FD8; --k-acc2:#47A045; --k-warn:#8A5A12; --k-sh:0 16px 34px -22px rgba(11,27,51,.28);
  background: var(--grain), var(--bg); }
#site .blkband::before { content: ""; position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background:
    radial-gradient(ellipse 72% 520px at 50% -200px, rgba(84,131,220,.46), rgba(8,11,22,.93) 96%),
    var(--graind) #00010A;
  opacity: calc(1 - var(--lt, 0)); transition: opacity .22s linear; }
/* seam continuity: instead of fading the whole overlay uniformly (which
   leaves a step against the still-dark hero above), hold the overlay fully
   opaque at the seam and let the scroll-driven fade run down the band. The
   top pixel always equals the hero, so no line can ever appear. The hold is
   280px, not the 460px it started at: at 460 the run reached past the section
   heading, so "What we do" and its paragraph sat in the murk until the very
   end of the scroll. 280 clears the copy while still covering the seam. */
@supports (mask-image: linear-gradient(rgb(0 0 0 / calc(1 - 0.5)), #000)) {
  #site .blkband::before { opacity: 1; transition: none;
    -webkit-mask-image: linear-gradient(to bottom, rgb(0 0 0 / calc(1 - var(--lts, 0))) 0, rgb(0 0 0 / calc(1 - var(--lt, 0))) 280px, rgb(0 0 0 / calc(1 - var(--lt, 0))) 100%);
    mask-image: linear-gradient(to bottom, rgb(0 0 0 / calc(1 - var(--lts, 0))) 0, rgb(0 0 0 / calc(1 - var(--lt, 0))) 280px, rgb(0 0 0 / calc(1 - var(--lt, 0))) 100%); }
}
#site .blkband::after { content: ""; position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background:
    linear-gradient(rgba(214,224,240,.05) 1px, transparent 1px) 0 var(--gridoff, 0px) / 44px 44px,
    linear-gradient(90deg, rgba(214,224,240,.05) 1px, transparent 1px) 0 0 / 44px 44px;
  -webkit-mask-image: linear-gradient(to bottom, #000, transparent 46%);
  mask-image: linear-gradient(to bottom, #000, transparent 46%);
  opacity: calc(1 - var(--lt, 0)); transition: opacity .22s linear; }
#site .blkband > .wrap { position: relative; z-index: 1; }
@media (prefers-reduced-motion: reduce) {
  #site .blkband::before, #site .blkband::after, #site .blkband h2, #site .blkband .bhead p { transition: none; }
}
/* section headings (James 2026-10-20: "cramped up against the left"): the
   heading block may run to 760px (it was 58ch, about 552px) so a long
   heading takes two lines, not three; the line under it keeps its reading
   measure */
#site .blkband .bhead p, #site .cmp .bhead p, #site .faq .bhead p, #site .whyband .bhead p { max-width: 60ch; text-wrap: pretty; }
#site .blkband .bhead { max-width: 760px; margin-bottom: clamp(28px, 3.4vw, 44px); }
#site .blkband h2 { color: var(--dkh2, #F4F8FF); transition: color .12s linear; font-size: clamp(2.1rem, 4.4vw, 3.3rem); line-height: 1.02; }
#site .blkband .bhead p { margin: 18px 0 0; color: var(--dkp, #A9B8D0); transition: color .12s linear; }
/* bento grid: rows alternate 7/5 - 5/7 - 7/5 so the six cards read as a
   composed layout rather than a fixed grid */
#site .blocks { display: grid; grid-template-columns: repeat(12, 1fr); gap: 16px; }
#site .blocks .block:nth-child(1), #site .blocks .block:nth-child(4), #site .blocks .block:nth-child(5) { grid-column: span 7; }
#site .blocks .block:nth-child(2), #site .blocks .block:nth-child(3), #site .blocks .block:nth-child(6) { grid-column: span 5; }
@media (max-width: 900px) { #site .blocks .block { grid-column: 1 / -1 !important; } }
/* thunderclap-style entrance: each card rises as it enters the viewport
   (the second card of a row a beat later), then its media panel slides in
   from the right and any floating overlay follows.
   Every step is a keyframe animation filled BACKWARDS, and nothing is
   pre-hidden: the resting state of a card and its panel is visible, and
   the animation only reaches back to hide them for its own duration. Two
   reasons. A forwards-filling animation never stops applying, which keeps
   the card on its own compositor layer for the life of the page - that is
   what left some panels blank until a click or a text selection forced a
   repaint. And an entrance that is additive can't strand content: if the
   reveal never fires, the card simply sits there, already readable. */
html.js-anim #site .block.rv { opacity: 1; transform: none; transition: border-color .25s, transform .25s, box-shadow .25s; }
html.js-anim #site .block.rv.in { animation: fpcardin .7s cubic-bezier(.5,1,.89,1) backwards; }
html.js-anim #site .block.rv:nth-child(even).in { animation-delay: .08s; }
@keyframes fpcardin { from { opacity: 0; transform: translateY(30px); } }
html.js-anim #site .block.rv.in .bmedia > * { animation: fpmediain 1s cubic-bezier(.25,1,.5,1) .25s backwards; }
@keyframes fpmediain { from { opacity: 0; transform: translateX(12%); } }
@media (prefers-reduced-motion: reduce) {
  html.js-anim #site .block.rv.in,
  html.js-anim #site .block.rv.in .bmedia > *,
  html.js-anim #site .block.rv.in .seoviz .fl { animation: none; }
}
#site .block { background: var(--k-sf); border: 1px solid var(--k-line); border-radius: 8px; display: flex; flex-direction: column; min-width: 0; min-height: 440px; overflow: clip; transition: border-color .25s, transform .25s; }
#site .block:hover { border-color: rgba(11,27,51,.28); transform: translateY(-3px); box-shadow: var(--k-sh); }
/* titles run the full width of the card - the wide cards have room for a
   long service name on one or two lines, and balancing keeps the lines
   even when one does wrap. Body copy keeps a readable measure but is no
   longer held back from the card's own edge */
#site .block h3 { color: var(--k-ink); font-size: 1.45rem; letter-spacing: -.025em; max-width: none; text-wrap: balance; }
/* on the services index each card routes to its own page. The arrow nudges
   from anywhere on the card, so the whole card reads as the target even
   though only the link is clickable */
/* ---- per-service accents ----------------------------------------
   Each card owns an accent from the studio's icon palette, and every
   widget inside reads --k-acc, so one line recolours a whole panel */
#site .blocks .block:nth-child(1) { --k-acc: #65A33F; }   /* leaf    - keep pace */
#site .blocks .block:nth-child(2) { --k-acc: #2C5FD8; }   /* cobalt  - strategy */
#site .blocks .block:nth-child(3) { --k-acc: #17879B; }   /* teal    - workflows */
#site .blocks .block:nth-child(4) { --k-acc: #47A045; }   /* green   - agents */
#site .blocks .block:nth-child(5) { --k-acc: #C08A2D; }   /* amber   - app builds */
#site .blocks .block:nth-child(6) { --k-acc: #5254C4; }            






/* every service card's graphic is the same height on a wide screen, so the
   two cards in a row match and no card has a short panel floating in space
   (James 2026-10-11) */
@media (min-width: 901px) {
}

#site .gc-card { align-self: flex-start; display: grid; gap: 3px; padding: 11px 14px 12px 40px; border-radius: 12px; background: #fff; border: 1px solid color-mix(in srgb, var(--k-acc) 40%, transparent);
  position: relative; max-width: 78%; }
#site .gc-card::before { content: ""; position: absolute; left: 13px; top: 13px; width: 16px; height: 16px; border-radius: 50%; background: var(--k-acc)
  url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M4.5 8.2l2.2 2.2 4.8-4.8' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / 100% no-repeat; }
#site .gc-card b { font-size: 14px; color: var(--k-ink); }
#site .gc-card span { font-size: 13px; color: var(--k-mu); }
#site .gc-typing { align-self: flex-start; display: none; gap: 4px; padding: 12px 14px; border-radius: 12px; background: #fff; border: 1px solid var(--k-line); }
#site .gc-typing i { width: 6px; height: 6px; border-radius: 50%; background: var(--k-mu); animation: gctype 1s infinite; }
#site .gc-typing i:nth-child(2) { animation-delay: .15s; }
#site .gc-typing i:nth-child(3) { animation-delay: .3s; }
@keyframes gctype { 0%, 60%, 100% { opacity: .3; transform: none; } 30% { opacity: 1; transform: translateY(-3px); } }
@media (max-width: 560px) {
  #site .gchat .fp-bub, #site .gc-card { max-width: 90%; }
}

/* .lit: the same block grid on a light ground (services page) - the dark
   scroll overlay and its grid are homepage-only choreography */
#site .blkband.lit::before, #site .blkband.lit::after { display: none; }
#site .phead + .blkband.lit, #site .phband + .blkband.lit { padding-top: clamp(20px, 2.6vw, 36px); }

#site .why { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1px; background: var(--k-line); border: 1px solid var(--k-line); }
@media (max-width: 940px) { #site .why { grid-template-columns: 1fr 1fr; } }
@media (max-width: 600px) { #site .why { grid-template-columns: 1fr; } }
#site .why .cell { position: relative; background: #FDFEFF; padding: 36px 32px 40px; overflow: hidden; }
#site .why .cell::before { content: ""; position: absolute; inset: 0; opacity: 0; transition: opacity .35s; pointer-events: none;
  background: radial-gradient(260px circle at var(--mx, 50%) var(--my, 50%), rgba(44,95,216,.13), transparent 68%); }
#site .why .cell:hover::before { opacity: 1; }
#site .why .cell > * { position: relative; z-index: 1; }
#site .why h3 { font-size: 1.25rem; line-height: 1.2; letter-spacing: -.022em; margin-bottom: 9px; }
#site .why .cell p { margin: 0; font-size: 14.5px; line-height: 1.62; color: var(--k-mu); max-width: 40ch; }
/* every symptom names the practice that fixes it, and links straight to it.
   The arrow is the site's lottie one (.arr), so it draws itself on hover
   exactly as the case-study links do - no css nudge needed */
#site .why .cell.go { background: #E7EEFB; }
#site .why .cell.go::before { background: radial-gradient(260px circle at var(--mx, 50%) var(--my, 50%), rgba(44,95,216,.2), transparent 68%); }
#site .why .cell.go h3 a { display: inline-flex; align-items: center; gap: 10px; color: inherit; text-decoration: none; }
/* the heading runs bigger than a body link, so its arrow scales with it -
   same 15:9.4 ratio as everywhere else */
#site .why .cell.go h3 .arr { width: 18px; height: 11.3px; }

/* ============ CTA + FOOTER ============ */
#site .ctasec { padding: clamp(30px, 4vw, 56px) 0 clamp(48px, 6vw, 78px); }
#site .ctacard { text-align: center; border-radius: 22px; padding: clamp(48px, 6vw, 76px) clamp(24px, 5vw, 66px); box-shadow: 0 36px 74px -36px rgba(11,27,51,.55);
  position: relative; overflow: clip; color: #EAF1FF;
  background:
    linear-gradient(118deg, rgba(255,255,255,.05) 0 31%, rgba(255,255,255,0) 31.7%),
    linear-gradient(295deg, rgba(8,24,64,.17) 0 24%, rgba(8,24,64,0) 24.8%),
    linear-gradient(62deg, rgba(255,255,255,.04) 0 13%, rgba(255,255,255,0) 13.7%),
    radial-gradient(54% 62% at 12% 6%, rgba(126,164,246,.5), transparent 62%),
    radial-gradient(48% 56% at 88% 28%, rgba(13,39,105,.52), transparent 62%),
    radial-gradient(42% 54% at 52% 100%, rgba(13,39,105,.36), transparent 60%),
    var(--grainx), var(--graind), var(--cb); }
#site .ctacard h2 { color: #fff; font-size: clamp(2rem, 4.4vw, 3.4rem); line-height: 1.02; max-width: 20ch; margin: 0 auto 30px; }
#site .ctacard .fine { margin: 22px 0 0; font-family: 'JetBrains Mono', monospace; font-size: 11px; letter-spacing: .03em; text-transform: uppercase; color: rgba(234,241,255,.66); }
#site footer { background: var(--nvy); color: rgba(255,255,255,.75); }
#site footer .fw { max-width: 1240px; margin: 0 auto; padding: 40px 30px 0; }
#site .fblurb { margin: 0 0 20px; font-size: 13.5px; line-height: 1.6; max-width: 34ch; }
#site footer .fh { margin: 0 0 14px; color: #EDF2FC; font-size: 13px; font-weight: 600; letter-spacing: .03em; text-transform: uppercase; margin-bottom: 14px; }
#site footer ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 9px; }
#site footer ul a, #site .fvb .meta a, #site .fbot a { color: rgba(255,255,255,.78); }
#site footer ul a { font-size: 13.5px; }
#site footer ul a:hover, #site .fvb .meta a:hover, #site .fbot a:hover { color: #fff; }
#site .sub p { margin: 0 0 12px; font-size: 12.5px; line-height: 1.55; }
#site .fine { font-size: 10.5px; color: rgba(255,255,255,.5); margin: 10px 0 0; }
#site .fbot { display: flex; align-items: center; justify-content: space-between; gap: 12px 24px; flex-wrap: wrap; border-top: 1px solid rgba(214,228,255,.1); padding: 20px 0 26px; font-size: 12.5px; color: rgba(255,255,255,.58); }
#site .fbot ul { list-style: none; display: flex; gap: 20px; margin: 0; padding: 0; font-size: 12.5px; }

/* ---- megamenu motion: panel drop, staggered tiles, icon micro-moves ---- */
@keyframes sitemmIn { from { opacity: 0; transform: translateY(-10px); } to { opacity: 1; transform: none; } }
@keyframes sitemmItem { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: none; } }
html.js-anim #site .mm:not([hidden]) { animation: sitemmIn .32s cubic-bezier(.2,.7,.25,1); }
html.js-anim #site .mm:not([hidden]) .mmi { animation: sitemmItem .45s cubic-bezier(.16,.6,.18,1) both; }
html.js-anim #site .mm:not([hidden]) .mmcol .mmi:nth-of-type(1) { animation-delay: .05s }
html.js-anim #site .mm:not([hidden]) .mmcol .mmi:nth-of-type(2) { animation-delay: .11s }
html.js-anim #site .mm:not([hidden]) .mmcol .mmi:nth-of-type(3) { animation-delay: .17s }
html.js-anim #site .mm:not([hidden]) .mmcol .mmi:nth-of-type(4) { animation-delay: .23s }
html.js-anim #site .mm:not([hidden]) .mmpromo { animation: sitemmItem .5s .14s cubic-bezier(.16,.6,.18,1) both; }
#site .mn > a, #site .mi > .mtrig { position: relative; }
#site .mn > a::after, #site .mi > .mtrig::after { content: ""; position: absolute; left: 13px; right: 13px; bottom: 5px; height: 2px; border-radius: 1px; background: var(--cb); transform: scaleX(0) translateZ(0); transform-origin: left; will-change: transform; transition: transform var(--ul-dur) var(--ul-ease); }
#site .mn > a:hover::after, #site .mi > .mtrig:hover::after, #site .mi > .mtrig[aria-expanded="true"]::after { transform: scaleX(1) translateZ(0); }
#site .mmi .ic { transition: background .2s, border-color .2s; }
#site .mmi .ic svg { transition: transform .25s cubic-bezier(.34,1.56,.64,1); }
#site .mmi:hover .ic { background: #E1EAFB; border-color: rgba(44,95,216,.42); }
#site .mmi:hover .ic svg { transform: scale(1.14) rotate(-5deg); }
#site .mmi b { transition: color .15s; }
#site .mmi:hover b { color: var(--cb); }
@media (prefers-reduced-motion: reduce) {
  html.js-anim #site .mm:not([hidden]), html.js-anim #site .mm:not([hidden]) .mmi, html.js-anim #site .mm:not([hidden]) .mmpromo { animation: none; }
  #site .mmi .ic svg, #site .mn > a::after, #site .mi > .mtrig::after { transition: none; }
  #site .mm { transition: background .35s ease; opacity: 1; transform: none; }
}

/* ---- locked footer (brand card) ---- */
#site .fvb { background: radial-gradient(56% 64% at 88% 4%, rgba(44,95,216,.15), transparent 60%), radial-gradient(52% 58% at 6% 98%, rgba(44,95,216,.11), transparent 62%), var(--grainw), #081120; }
#site .fvb .top { display: grid; grid-template-columns: 1.5fr 1fr 1fr 1fr; gap: 40px; padding: 34px 0 48px; }
@media (max-width: 900px) { #site .fvb .top { grid-template-columns: 1fr 1fr; gap: 32px; } }
@media (max-width: 560px) { #site .fvb .top { grid-template-columns: 1fr; } }
#site .fvb .lgw svg { display: block; height: 36px; width: auto; color: #fff; margin-bottom: 20px; }
#site .fvb .meta { display: grid; gap: 9px; font-size: 13.5px; color: rgba(255,255,255,.75); justify-items: start; }
#site .fvb .fblurb { margin-bottom: 22px; }

#site .chips { display: flex; flex-wrap: wrap; gap: 8px; }
#site .chips i { font-style: normal; font-family: 'JetBrains Mono', monospace; font-size: 10.5px; letter-spacing: .03em;
  text-transform: uppercase; padding: 6px 13px; border-radius: 100px; }

/* Default: dark ink on a light surface. These chips are reused inside
   case-study side cards, so the light treatment is the base and the cobalt
   band overrides it below. */
#site .chips i { border: 1px solid rgba(11,27,51,.22); color: #33465F; background: rgba(44,95,216,.05); }
/* chips inside the what-we-do block cards. On desktop the row is capped to
   a single line: the sets are written to fit, and the cap guarantees a
   stray wrap can never open a second row whatever the font metrics do */
#site .block .chips { margin-top: 16px; }
@media (min-width: 901px) { #site .block .chips { max-height: 32px; overflow: hidden; } }

/* ---- process: four steps as a track ----
   The steps run across rather than down, each hanging off a single rule and
   marked by a node - the same node-and-rail language as the pipeline graphic
   in the service cards, so the section belongs to the rest of the site
   rather than to the numbered-list layout every consultancy uses. */
#site .pband { color: #8FA3C4; padding: clamp(64px, 7vw, 96px) 0;
  background: radial-gradient(46% 42% at 10% 0%, rgba(44,95,216,.2), transparent 60%), var(--grainw), var(--nvy); }
#site .pband .bhead { max-width: 760px; margin-bottom: clamp(24px, 3vw, 38px); }
#site .pband h2 { color: #fff; font-size: clamp(2.1rem, 4.4vw, 3.3rem); line-height: 1.02; }
#site .pband .bhead p { margin: 18px 0 0; }
#site .psteps { --pgap: clamp(18px, 2.6vw, 36px); display: grid; grid-template-columns: repeat(4, 1fr);
  gap: 0 var(--pgap); border-top: 1px solid rgba(126,164,246,.3); }
#site .prow { --f: 1; position: relative; padding: 28px 0 0; }
/* box-sizing is border-box site-wide, so 10px is the node's outer diameter and
   its centre is 5px in. The line itself sits flush against the top of .prow's
   own box (a 1px border occupying -1px to 0), so centring on it is
   -(1 + diameter) / 2 - here -(1 + 10) / 2 = -5.5px */
#site .prow::before { content: ""; position: absolute; left: 0; top: -5.5px; z-index: 1;
  width: 10px; height: 10px; border-radius: 50%; background: #7EA4F6; border: 2px solid #7EA4F6;
  box-shadow: 0 0 0 4px rgba(126,164,246,.16), 0 0 14px rgba(126,164,246,.55);
  transition: background .35s, border-color .35s, box-shadow .35s, transform .25s; }
/* the lit part of the rail: --f (0 to 1) is set from the scroll position, so
   the line draws itself left to right as the section comes into view. It runs
   on past the column to meet the next node */
#site .prow::after { content: ""; position: absolute; left: 0; right: calc(-1 * var(--pgap)); top: -1px; height: 2px;
  background: linear-gradient(90deg, rgba(126,164,246,.5), #BCD0FB); transform-origin: left; transform: scaleX(var(--f));
  transition: transform .18s linear; }
#site .prow:last-child::after { right: 0; }
/* with script on, a step stays quiet until the rail reaches it */
html.js-anim #site .prow:not(.on)::before { background: var(--nvy); border-color: rgba(126,164,246,.5); box-shadow: none; }
html.js-anim #site .prow.on::before { animation: procping .9s ease-out; }
@keyframes procping { 0% { box-shadow: 0 0 0 0 rgba(126,164,246,.7), 0 0 14px rgba(126,164,246,.55); } 100% { box-shadow: 0 0 0 14px rgba(126,164,246,0), 0 0 14px rgba(126,164,246,.55); } }
/* hover or focus a step: its node swells and the step lifts a little */
#site .prow:hover::before, #site .prow:focus-within::before { transform: scale(1.35); box-shadow: 0 0 0 5px rgba(126,164,246,.22), 0 0 20px rgba(126,164,246,.8); }
@media (max-width: 900px) {
  #site .psteps { grid-template-columns: repeat(2, 1fr); row-gap: 30px; border-top: 0; }
  #site .prow { border-top: 1px solid rgba(126,164,246,.3); }
  #site .prow::after, #site .prow:last-child::after { right: 0; }
}
@media (max-width: 560px) { #site .psteps { grid-template-columns: 1fr; row-gap: 24px; } }
/* ---- two ways to work ----
   Fork 2 (pv-a2) on the homepage and Fork 1 (pv-a1) on the Keep pace page
   (chosen 2026-10-19; Fork 3 and Switch 1-3 were deleted with the "Two ways"
   lab). Each plays once it is on screen (.go, set by site.js). Blue is a
   project, lime is Keep pace. */
#site .pv { display: none; margin-top: clamp(30px, 3.6vw, 50px); }
#site .pv.on { display: block; }
#site .kpways { margin-bottom: clamp(48px, 6vw, 80px); }
#site .pband .bhead p { color: #A7B7D4; max-width: 62ch; line-height: 1.65; }
#site .pv .tg { margin: 0 0 6px; font-size: 13.5px; font-weight: 700; letter-spacing: .03em; text-transform: uppercase; color: #7EA4F6; }
#site .pv .kp .tg { color: #9FE870; }
#site .pv .k { margin: 0 0 6px; font-family: 'JetBrains Mono', monospace; font-size: 12.5px; color: #7EA4F6; }
#site .pv .bfy { display: grid; gap: 8px; margin: 16px 0 0; padding-top: 14px; border-top: 1px solid rgba(126,164,246,.16); }
#site .pv .bfy div { display: grid; grid-template-columns: 76px 1fr; gap: 12px; align-items: baseline; }
#site .pv .bfy dt { font-size: 12.5px; font-weight: 700; letter-spacing: .03em; text-transform: uppercase; color: #8FA3C4; }
#site .pv .bfy dd { margin: 0; color: #DCE6F8; font-size: 14px; line-height: 1.45; }
/* shared glass card */
#site .pv .glass { border-radius: 16px; border: 1px solid rgba(126,164,246,.22); background: linear-gradient(180deg, rgba(255,255,255,.06), rgba(255,255,255,.02)); }
#site .pv .glass.kp { border-color: rgba(159,232,112,.42); box-shadow: 0 26px 60px -34px rgba(159,232,112,.4);
  background: linear-gradient(150deg, rgba(159,232,112,.1), rgba(44,95,216,.12) 60%, rgba(255,255,255,.02)); }

/* ===== FORK 1 ===== */
#site .f1 { display: grid; grid-template-columns: minmax(250px, 300px) 110px 1fr; grid-template-rows: 560px; align-items: center; }
#site .f1-start { position: relative; padding: 20px 22px 24px; border-radius: 16px; background: rgba(255,255,255,.035); border: 1px solid rgba(126,164,246,.18); }
#site .f1-start::after { content: ""; position: absolute; right: -8px; top: 50%; width: 14px; height: 14px; margin-top: -7px; border-radius: 50%; background: #7EA4F6; box-shadow: 0 0 0 5px rgba(126,164,246,.16); }
#site .f1-cap { margin: 0 0 14px; font-size: 12.5px; font-weight: 700; letter-spacing: .03em; text-transform: uppercase; color: #7EA4F6; }
#site .f1-step { position: relative; display: flex; gap: 14px; }
#site .f1-step + .f1-step { margin-top: 20px; }
#site .f1-step > i { flex: none; width: 12px; height: 12px; margin-top: 3px; border-radius: 50%; background: var(--nvy); border: 2px solid #7EA4F6; }
#site .f1-step:first-of-type::after { content: ""; position: absolute; left: 5px; top: 19px; bottom: -18px; width: 2px; background: rgba(126,164,246,.35); }
#site .f1-step b { display: block; color: #fff; font-size: 16px; font-weight: 600; letter-spacing: -.015em; }
#site .f1-step span { display: block; margin-top: 4px; color: #A7B7D4; font-size: 13.5px; line-height: 1.55; }
#site .f1-y { display: block; width: 110px; height: 560px; overflow: visible; }
#site .f1-y path { fill: none; stroke-width: 2; }
#site .f1-y path { stroke-dasharray: 1 1; }
#site .f1-y .a { stroke: rgba(126,164,246,.8); }
#site .f1-y .b { stroke: rgba(159,232,112,.8); }
#site .f1-y .run { stroke-width: 4; stroke-linecap: round; stroke-dasharray: .14 .86; stroke-dashoffset: .14; opacity: 0; }
#site .f1-y .ra { stroke: #E3ECFF; }
#site .f1-y .rb { stroke: #E6FFD4; }
#site .f1-ends { position: relative; align-self: stretch; display: grid; grid-template-rows: 1fr 1fr; }
#site .f1-c { position: relative; align-self: center; padding: 18px 22px 18px 24px; border-radius: 16px; border: 1px solid rgba(126,164,246,.24);
  background: linear-gradient(180deg, rgba(255,255,255,.065), rgba(255,255,255,.02)); }
#site .f1-c.kp { border-color: rgba(159,232,112,.42); box-shadow: 0 26px 60px -34px rgba(159,232,112,.45);
  background: linear-gradient(150deg, rgba(159,232,112,.11), rgba(44,95,216,.12) 60%, rgba(255,255,255,.02)); }
#site .f1-c::before { content: ""; position: absolute; left: -8px; top: 50%; width: 14px; height: 14px; margin-top: -7px; border-radius: 50%; background: #7EA4F6; box-shadow: 0 0 0 5px rgba(126,164,246,.16); }
#site .f1-c.kp::before { background: #9FE870; box-shadow: 0 0 0 5px rgba(159,232,112,.18); }
#site .f1-top { display: flex; justify-content: space-between; align-items: flex-start; gap: 18px; }
#site .f1-top b { display: block; color: #fff; font-size: clamp(1.12rem, 1.5vw, 1.28rem); font-weight: 600; letter-spacing: -.018em; }
#site .spark { flex: none; width: 120px; height: 44px; overflow: visible; }
#site .spark .sl { fill: none; stroke-width: 2.5; stroke-linecap: round; stroke-linejoin: round; stroke: #7EA4F6; stroke-dasharray: 1 1; }
#site .kp .spark .sl { stroke: #9FE870; }
#site .f1-d { margin: 8px 0 0; color: #A7B7D4; font-size: 14px; line-height: 1.55; max-width: 62ch; }
#site .f1-br { position: absolute; left: 26px; top: 50%; z-index: 2; translate: 0 -50%; margin: 0; padding: 4px 12px 4px 9px; border-radius: 100px;
  background: var(--nvy); border: 1px solid rgba(159,232,112,.45); font-size: 12.5px; font-weight: 600; color: #9FE870; white-space: nowrap; }
#site .f1-br::before { content: ""; display: inline-block; width: 6px; height: 6px; margin: 0 8px 3px 2px; border-right: 2px solid currentColor; border-bottom: 2px solid currentColor; transform: rotate(45deg); }
/* room round "Can grow into Keep pace" so it never touches a card (James 2026-10-19): the
   cards step apart (the project up 10px, Keep pace down 13px from their row centres, which
   still fits Keep pace inside its row), the pill sits 4px higher, and the cards' dots move
   back by the same amounts so they still meet the ends of the branches */
#site .f1-c.pj { margin-bottom: 20px; }
#site .f1-c.kp { margin-top: 26px; }
#site .f1-c.pj::before { margin-top: 3px; }
#site .f1-c.kp::before { margin-top: -20px; }
#site .f1-br { margin-top: -4px; }
html.js-anim #site .pv-a1 .f1-y .a, html.js-anim #site .pv-a1 .f1-y .b { stroke-dashoffset: 1; transition: stroke-dashoffset .8s cubic-bezier(.6,0,.2,1) .5s; }
html.js-anim #site .pv-a1 .f1-c, html.js-anim #site .pv-a1 .f1-br { opacity: 0; transform: translateX(-10px); transition: opacity .55s, transform .55s cubic-bezier(.2,.7,.2,1); }
html.js-anim #site .pv-a1 .f1-c.pj { transition-delay: 1.15s; }
html.js-anim #site .pv-a1 .f1-c.kp { transition-delay: 1.3s; }
html.js-anim #site .pv-a1 .f1-br { transition-delay: 1.8s; }
html.js-anim #site .pv-a1 .spark .sl { stroke-dashoffset: 1; transition: stroke-dashoffset 1.2s cubic-bezier(.5,0,.3,1) 1.7s; }
html.js-anim #site .pv-a1.go .f1-y .a, html.js-anim #site .pv-a1.go .f1-y .b, html.js-anim #site .pv-a1.go .spark .sl { stroke-dashoffset: 0; }
html.js-anim #site .pv-a1.go .f1-c, html.js-anim #site .pv-a1.go .f1-br { opacity: 1; transform: none; }
html.js-anim #site .pv-a1.go .f1-y .ra { animation: forkrun 3.6s linear 2.4s 1; }
html.js-anim #site .pv-a1.go .f1-y .rb { animation: forkrun 3.6s linear 2.4s infinite; }
html.js-anim #site .pv-a1.go .f1-c.kp { animation: forkhit 3.6s ease-out 2.4s infinite; }
@keyframes forkrun { 0% { stroke-dashoffset: .14; opacity: 0; } 6% { opacity: 1; } 34% { opacity: 1; } 40%, 100% { stroke-dashoffset: -.86; opacity: 0; } }
@keyframes forkhit { 0%, 36%, 100% { border-color: rgba(159,232,112,.42); } 44% { border-color: #9FE870; } }
@media (max-width: 900px) {
  #site .f1 { grid-template-columns: 1fr; grid-template-rows: none; gap: 16px; }
  #site .f1-start::after, #site .f1-c::before, #site .f1-y { display: none; }
  #site .f1-ends { grid-template-rows: none; gap: 14px; }
  #site .f1-c.pj, #site .f1-c.kp { margin: 0; }
  #site .f1-br { position: static; translate: none; justify-self: start; margin: 0 0 8px 18px; }
  #site .spark { width: 84px; height: 32px; }
}

html.js-init * { transition: none !important; }
/* set in each page head and cleared at the end of site.js: the page stays
   unpainted (the browser keeps the previous page on screen) until the nav,
   footer and reveal states are all in place */
html.fp-wait #site { visibility: hidden; }




@media (prefers-reduced-motion: reduce) {
  html.js-anim #site .pv * { animation: none !important; transition: none !important; }
}

@media (prefers-reduced-motion: reduce) {
  html.js-anim #site .prow.on::before { animation: none; }
  #site .prow::after, #site .ptxt, #site .prow::before { transition: none; }
}

/* ---- comparison table ---- */
#site .cmp { padding: clamp(64px, 7vw, 96px) 0; }
#site .cmp .bhead { max-width: 760px; margin-bottom: clamp(26px, 3.2vw, 40px); }
#site .cmp h2 { font-size: clamp(2.1rem, 4.4vw, 3.3rem); line-height: 1.02; }
#site .cmp .bhead p { margin: 18px 0 0; color: var(--k-mu); }
#site .cmpwrap { overflow-x: auto; }
#site .cmp table { width: 100%; min-width: 780px; border-collapse: collapse; }
#site .cmp th, #site .cmp td { text-align: left; padding: 17px 22px; border-bottom: 1px solid var(--k-line); font-size: 14.5px; line-height: 1.5; vertical-align: middle; }
#site .cmp thead th { border-bottom: 1px solid rgba(11,27,51,.26); padding-top: 15px; padding-bottom: 15px; vertical-align: middle; }
#site .cmp thead th.oth { font-weight: 600; color: var(--k-ink); font-size: 15px; }
#site .cmp td:first-child, #site .cmp tbody th { font-weight: 400; font-family: 'JetBrains Mono', monospace; font-size: 11px; letter-spacing: .04em; text-transform: uppercase; color: var(--k-mu); white-space: nowrap; }
#site .cmp .hi { background: #E7EEFB; border-left: 1px solid rgba(44,95,216,.25); border-right: 1px solid rgba(44,95,216,.25); }
#site .cmp thead .hi { border-top: 2px solid var(--cb); }
#site .cmp tbody tr:last-child .hi { border-bottom: 2px solid var(--cb); }
#site .cmp .hi b { color: var(--k-ink); font-weight: 600; }
#site .cmp .tick { display: inline-block; margin-right: 9px; color: var(--k-acc2); font-weight: 700; }
#site .cmp td.mut { color: var(--k-mu); }
#site .cmp thead .hi svg { display: block; height: 25px; width: auto; color: var(--nvy); margin: 2px 0; }
/* a drawn tick (svg) in place of the typed one, as on the Keep pace page */
#site .cmp .tick svg { display: inline-block; width: 15px; height: 15px; vertical-align: -2px; fill: none; stroke: currentColor; stroke-width: 2.4; stroke-linecap: round; stroke-linejoin: round; }

/* ---- quote band ---- */
#site .quote { background: var(--grain), #E7EEFB; padding: clamp(56px, 6vw, 82px) 0; }
#site .quote .wrap { text-align: center; }
/* This quote runs to 67 words, a full testimonial rather than a one-line
   pull-quote - the old 38ch/2.15rem/600-weight treatment was tuned for a
   single punchy sentence and would set this as several lines of oversized
   bold type. Sized down to a paragraph and widened to match. */
#site .quote blockquote { margin: 0 auto 30px; font-size: clamp(1.1rem, 1.7vw, 1.4rem); font-weight: 500; letter-spacing: -.008em; line-height: 1.6; color: var(--k-ink); max-width: 74ch; text-wrap: balance; }
#site .quote blockquote span { color: var(--cb); font-weight: 600; }

/* ---- faq accordions ---- */
#site .faq { padding: clamp(64px, 7vw, 96px) 0; }
#site .faq .bhead { max-width: 760px; margin-bottom: clamp(22px, 3vw, 34px); }
#site .faq h2 { font-size: clamp(2.1rem, 4.4vw, 3.3rem); line-height: 1.02; }
#site .qgrid { display: grid; grid-template-columns: 1fr 1fr; gap: 0 54px; align-items: start; }
@media (max-width: 860px) { #site .qgrid { grid-template-columns: 1fr; } }
/* one motion source for every FAQ accordion on the site (homepage, FAQ page,
   service pages): panel height and icon share --faq-t / --faq-e. Browsers
   without ::details-content support simply toggle instantly */
#site { --faq-t: .3s; --faq-e: cubic-bezier(.2,.7,.25,1); interpolate-size: allow-keywords; }
#site .qi::details-content { block-size: 0; overflow-y: clip;
  transition: block-size var(--faq-t) var(--faq-e), content-visibility var(--faq-t) allow-discrete; }
#site .qi[open]::details-content { block-size: auto; }
/* one divider style for every .qi row, wherever it appears - homepage,
   standalone FAQ page, service-page mini FAQs. Reads from --k-line so a
   single change here (or to the token) restyles all of them together. */
#site .qi { border-bottom: 1px solid var(--k-line); }
#site .qi summary { list-style: none; cursor: pointer; display: flex; align-items: baseline; justify-content: space-between; gap: 20px; padding: 19px 0; font-size: 16.5px; font-weight: 600; letter-spacing: -.015em; }
#site .qi summary::-webkit-details-marker { display: none; }
#site .faq.lt2 .qi summary { color: var(--k-ink); }
#site .qi summary i { font-style: normal; flex: none; align-self: center; color: #7EA4F6; transition: transform var(--faq-t) var(--faq-e); }
#site .qi summary i svg { display: block; width: 13px; height: 13px; }
#site .qi[open] summary i { transform: rotate(180deg); }
#site .faq.lt2 .qi summary:hover i { color: var(--cb); }
#site .qi > p { margin: 0; padding: 0 0 20px; font-size: 14.5px; line-height: 1.65; max-width: 58ch; }
#site .faq.lt2 .qi > p { color: var(--k-mu); }
@media (prefers-reduced-motion: reduce) { #site .qi summary i, #site .qi::details-content { transition: none; } }


/* ============================================================
   INNER PAGES
   Every rule below is scoped to #site and reuses the same tokens,
   hairlines and type scale as the homepage.
   ============================================================ */

/* ---- page header: sits under the transparent nav, same wash as the hero ---- */
#site .phead { position: relative; margin-top: calc(-1 * var(--navh, 77px));
  padding: calc(var(--navh, 77px) + clamp(46px, 6vw, 86px)) 0 clamp(28px, 3.2vw, 44px);
  background: var(--grain), var(--bg); }
/* the section directly under a page header sits close to it - the header's
   own bottom padding already provides the breathing room */
#site .phead + .sec { padding-top: clamp(18px, 2.2vw, 30px); }
#site .phead h1 { font-size: clamp(2.3rem, 5.1vw, 4rem); line-height: 1.02; max-width: 17ch; }
#site .phead .lead { margin: 20px 0 0; max-width: 56ch; font-size: clamp(1.02rem, 1.5vw, 1.16rem); line-height: 1.65; color: #42536E; }
#site .crumb { margin: 0 0 20px; font-size: 15px; font-weight: 500; letter-spacing: .01em; color: #55657D; }
#site .crumb a { color: #55657D; text-decoration: none; }
#site .crumb a:hover { color: var(--cb); }
#site .crumb span { margin: 0 8px; opacity: .55; }

/* generic light section */
#site .sec { padding: clamp(56px, 6.4vw, 88px) 0; }
#site .sec.tint, #site .cmp.tint { background: var(--grain), #E7EEFB; }
/* the highlight column is normally #E7EEFB - the same value as the tint -
   so on a tinted ground it has to go white or it disappears into it */
#site .cmp.tint .hi { background: #fff; }
#site .sec h2 { font-size: clamp(1.8rem, 3.6vw, 2.7rem); line-height: 1.04; max-width: 22ch; }

/* ---- case-study hero: "Frame: Build" (picked 2026-10-12) ----
   A hairline frame in the Vercel manner: the page edges drawn as lines
   with small crosshairs where they meet, a fine 44px grid fading in from
   the corner of the title panel with brand blocks stacked up from the
   details row (.csbk cells built by site.js "case study hero blocks":
   placed one by one on load, static when motion is reduced, cobalt on
   hover), and the project file as one row of ruled cells. The frame sits
   on the 1180px content edges every section below uses. Same markup on all six
   case study pages: crumbbar, then .cshead > div (h1, lead) + aside.pfile */
#site .phead.hasbar { padding-top: var(--navh, 77px); padding-bottom: 0; overflow-x: clip; border-bottom: 1px solid var(--k-line); }
#site .phead.hasbar + .sec { padding-top: clamp(48px, 5.6vw, 80px); }
#site .crumbbar { border-top: 1px solid var(--k-line); border-bottom: 1px solid var(--k-line); }
#site .crumbbar .wrap, #site .phead.hasbar .cshead { width: calc(100% - 60px); max-width: 1180px; }
#site .crumbbar .wrap { display: flex; align-items: center; justify-content: space-between; gap: 18px;
  padding: 14px clamp(20px, 3.4vw, 44px); border-inline: 1px solid var(--k-line); }
#site .crumbbar .crumb { margin: 0; font-size: 14px; }
#site .cbmeta { margin: 0; display: flex; align-items: center; gap: 8px; font-size: 13.5px; font-weight: 500; color: var(--k-mu); white-space: nowrap; }
@media (max-width: 560px) { #site .cbmeta { display: none; } }

#site .phead.hasbar .cshead { position: relative; display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 0; align-items: stretch;
  padding: 0; border-inline: 1px solid var(--k-line); }
#site .cshead > div { grid-column: 1 / -1; position: relative; isolation: isolate;
  padding: clamp(64px, 7.4vw, 112px) clamp(20px, 3.4vw, 44px) clamp(52px, 5.8vw, 84px); }
#site .cshead > div::before { content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none;
  background-image: linear-gradient(to right, rgba(11,27,51,.055) 1px, transparent 1px), linear-gradient(to bottom, rgba(11,27,51,.055) 1px, transparent 1px);
  background-size: 44px 44px; background-position: right 0 bottom 0;
  -webkit-mask-image: radial-gradient(70% 110% at 100% 100%, #000 0%, transparent 80%); mask-image: radial-gradient(70% 110% at 100% 100%, #000 0%, transparent 80%); }
#site .csbk { position: absolute; inset: 0; z-index: -1; overflow: hidden; pointer-events: none; }
#site .csbk i { position: absolute; width: 43px; height: 43px; border-radius: 3px; background: var(--nvy); opacity: var(--o); pointer-events: none;
  transition: opacity .45s, background-color .45s; }
#site .csbk i.cb { background: var(--cb); }
/* hover only where a real pointer hovers - a tap on a phone never sticks */
@media (hover: hover) and (pointer: fine) {
  #site .csbk i.hl { opacity: var(--h); background: var(--cb); transition-duration: 0s; }
}
@media (prefers-reduced-motion: no-preference) { html.js-anim #site .csbk i.st { animation: csbk .55s cubic-bezier(.2,.75,.25,1) var(--d, 0s) backwards; } }
@keyframes csbk { from { opacity: 0; translate: 0 -14px; } }
#site .phead.hasbar .lead a { color: var(--nvy); text-decoration: underline; text-decoration-color: rgba(44,95,216,.45); text-underline-offset: 3px; }
#site .phead.hasbar .lead a:hover { color: var(--cb); }
#site .cshead > div::after { content: ""; position: absolute; left: -100vw; right: -100vw; bottom: 0; height: 1px; background: var(--k-line); }
#site .phead.hasbar h1 { font-size: clamp(2.4rem, 5.2vw, 4.4rem); line-height: 1; max-width: 17ch; }
#site .phead.hasbar .lead { max-width: 60ch; margin-top: 24px; }
#site .cshead::before, #site .cshead::after { content: ""; position: absolute; z-index: 2; width: 13px; height: 13px; pointer-events: none;
  background: linear-gradient(var(--k-ink), var(--k-ink)) center / 13px 1px no-repeat, linear-gradient(var(--k-ink), var(--k-ink)) center / 1px 13px no-repeat; opacity: .55; }
#site .cshead::before { top: -7px; left: -7px; }
#site .cshead::after { bottom: -7px; right: -7px; }

/* the project file: a mono label in the panel's corner, then ruled cells */
#site .pfile { display: contents; }
#site .pfh { position: absolute; z-index: 1; top: 22px; right: clamp(20px, 3.4vw, 44px); display: flex; gap: 10px; margin: 0;
  font-family: 'JetBrains Mono', monospace; font-size: 12.5px; letter-spacing: .02em; text-transform: uppercase; color: var(--k-mu); }
#site .pfh b { font-weight: 500; color: var(--k-ink); }
#site .pfile .pfr { display: flex; flex-direction: column; gap: 8px; min-width: 0; padding: 22px clamp(16px, 2vw, 26px) 26px; }
#site .pfile .pfr:nth-child(2) { padding-left: clamp(20px, 3.4vw, 44px); }
#site .pfile .pfr + .pfr { border-left: 1px solid var(--k-line); }
#site .pfile .pfr > span:first-child { font-size: 13.5px; font-weight: 500; color: var(--k-mu); }
#site .pfile .pfr b, #site .pfile .pfr .pflink { font-size: 15px; font-weight: 500; letter-spacing: -.01em; line-height: 1.5; color: var(--nvy); }
#site .pfile .pfr b.lv { display: inline-flex; align-items: center; gap: 9px; }
#site .pfile .pfr .pflink { color: var(--cb); text-decoration: none; overflow-wrap: anywhere; }
#site .pfile .pfr .pflink:hover { text-decoration: underline; text-underline-offset: 3px; }
#site .pfile .chips { display: flex; flex-wrap: wrap; gap: 0 .3em; }
#site .pfile .chips i { padding: 0; border: 0; border-radius: 0; background: none; font-family: inherit; text-transform: none; font-style: normal; font-size: 15px; font-weight: 500; line-height: 1.5; letter-spacing: -.01em; color: var(--k-ink); }
#site .pfile .chips i:not(:last-child)::after { content: ","; }

/* live indicator: lime dot, soft pulse */
#site .lvdot { width: 8px; height: 8px; flex: none; border-radius: 50%; background: #9FE870; box-shadow: 0 0 0 3px rgba(159,232,112,.25); }
html.js-anim #site .lvdot { animation: fplv 2.4s ease-in-out infinite; }
@keyframes fplv { 0%, 100% { box-shadow: 0 0 0 2px rgba(159,232,112,.35); } 50% { box-shadow: 0 0 0 5px rgba(159,232,112,.12); } }
@media (prefers-reduced-motion: reduce) { html.js-anim #site .lvdot { animation: none; } }

@media (max-width: 920px) {
  #site .phead.hasbar .cshead { grid-template-columns: 1fr 1fr; }
  #site .cshead > div::before { background-position: right 0 top -1px;
    -webkit-mask-image: radial-gradient(64% 100% at 100% 0%, #000 0%, transparent 78%); mask-image: radial-gradient(64% 100% at 100% 0%, #000 0%, transparent 78%); }
  #site .pfile .pfr, #site .pfile .pfr:nth-child(2) { padding: 18px clamp(20px, 3.4vw, 44px) 20px; }
  #site .pfile .pfr + .pfr { border-left: 0; }
  #site .pfile .pfr:nth-child(odd) { border-left: 1px solid var(--k-line); }
  #site .pfile .pfr:nth-child(n+4) { border-top: 1px solid var(--k-line); }
  #site .pfile .pfr:nth-child(6) { grid-column: 1 / -1; border-left: 0; }
}
@media (max-width: 560px) {
  #site .crumbbar .wrap, #site .phead.hasbar .cshead { width: 100%; border-inline: 0; }
  #site .crumbbar .wrap { padding-inline: 30px; }
  #site .cshead::before, #site .cshead::after { display: none; }
  #site .cshead > div { padding: 64px 30px 48px; }
  #site .pfh { top: 20px; left: 30px; right: auto; }
  #site .pfile .pfr, #site .pfile .pfr:nth-child(2) { padding: 16px 16px 18px 30px; }
  #site .pfile .pfr:nth-child(odd) { padding-left: 16px; }
  #site .pfile .pfr:nth-child(6) { padding-left: 30px; }
}

@media (prefers-reduced-motion: no-preference) { html { scroll-behavior: smooth; } }

/* ---- filters ---- */
#site .filters { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: clamp(22px, 2.6vw, 32px); }
#site .filters button { appearance: none; cursor: pointer; font: inherit; font-size: 13.5px; font-weight: 500; color: #33465F;
  background: #fff; border: 1px solid rgba(11,27,51,.14); border-radius: 100px; padding: 9px 17px; transition: background .18s, border-color .18s, color .18s; }
#site .filters button:hover { border-color: rgba(44,95,216,.5); color: var(--cb); }
#site .filters button.on { background: var(--nvy); border-color: var(--nvy); color: #fff; }


#site .fwshot img { display: block; width: 100%; height: auto; aspect-ratio: 600 / 380; object-fit: cover; object-position: top;
  border-radius: 14px; border: 1px solid rgba(11,27,51,.12);
  box-shadow: 0 30px 60px -34px rgba(11,27,51,.4); transition: transform .25s, box-shadow .25s; }
/* only the image and the text link open a case study - the surrounding row
   is plain content. Hovering the image raises it and reveals the same
   "View case study" pill both entry points share */
#site a.fwshot { position: relative; display: block; }
#site a.fwshot:hover img, #site a.fwshot:focus-visible img { transform: translateY(-4px); box-shadow: 0 40px 70px -36px rgba(11,27,51,.5); }
#site .fwview { position: absolute; inset: 0; display: grid; place-items: center; border-radius: 14px;
  background: rgba(11,27,51,.3); opacity: 0; transition: opacity var(--btn-t) ease, transform .25s; }
#site .fwview b { display: inline-flex; align-items: center; gap: 9px; font-size: 13.5px; font-weight: 600; letter-spacing: -.01em; color: var(--nvy);
  background: #fff; border-radius: 100px; padding: 12px 22px; box-shadow: 0 14px 30px -12px rgba(11,27,51,.5);
  transform: translateY(6px) scale(.96); transition: transform var(--btn-t) ease; }
/* the tint rises with the image, so no light strip shows along its top */
#site a.fwshot:hover .fwview, #site a.fwshot:focus-visible .fwview { opacity: 1; transform: translateY(-4px); }
#site a.fwshot:hover .fwview b, #site a.fwshot:focus-visible .fwview b { transform: none; }
@media (prefers-reduced-motion: reduce) {
  #site a.fwshot:hover img, #site a.fwshot:focus-visible img { transform: none; }
  #site .fwview b, #site a.fwshot:hover .fwview { transform: none; }
}
/* the "View case study" link mirrors the live site's project link: ink text,
   the lottie arrow, and an underline that draws in on hover */
/* underline timing mirrors the live IX2 action: grow to 100% over .6s
   outExpo on hover, shrink back over .5s on leave */
/* the lottie arrow renders into .arr - same file, size and -45deg rotation
   as the live site's .project-link-arrow (15px wide, pointing up-right) */
#site .arr { display: inline-block; flex: none; width: var(--arr-w); height: 9.4px; transform: rotate(-45deg); font-style: normal; }
#site .arr svg { display: block; width: 100%; height: 100%; }
/* the animation ships with a black stroke baked in, which suits the dark
   case-study links. On a coloured link it takes the link's own colour */
#site .why .wfix .arr svg [stroke], #site .why .cell.go h3 .arr svg [stroke],
#site .block .bmore .arr svg [stroke] { stroke: currentColor; }
#site .lvdot.prep { background: #E2A93B; box-shadow: 0 0 0 3px rgba(226,169,59,.2); }




/* ---- results row ---- */
#site .resrow { display: grid; grid-template-columns: repeat(3, 1fr); border-top: 1px solid rgba(11,27,51,.16); border-left: 1px solid rgba(11,27,51,.16); }
@media (max-width: 720px) { #site .resrow { grid-template-columns: 1fr; } }
#site .resrow div { border-right: 1px solid rgba(11,27,51,.16); border-bottom: 1px solid rgba(11,27,51,.16); padding: 26px 26px 28px; }
#site .resrow .n { margin: 0; font-size: clamp(2.2rem, 4vw, 3.1rem); font-weight: 600; letter-spacing: -.04em; line-height: 1; color: var(--cb); font-variant-numeric: tabular-nums; }
#site .resrow .k { margin: 12px 0 0; font-size: 15.5px; line-height: 1.55; color: var(--k-mu); max-width: 30ch; }

/* ---- long-form prose ---- */
#site .prose { max-width: 68ch; }
#site .prose h2 { max-width: none; font-size: clamp(1.45rem, 2.6vw, 1.95rem); line-height: 1.14; margin: clamp(34px, 4vw, 52px) 0 14px; }
#site .prose h2:first-child { margin-top: 0; }
#site .prose p { margin: 0 0 17px; font-size: 1.03rem; line-height: 1.75; color: #3D4E68; }
#site .prose ul { margin: 0 0 17px; padding-left: 20px; }
#site .prose li { font-size: 1.03rem; line-height: 1.7; color: #3D4E68; margin-bottom: 9px; }
#site .prose li::marker { color: var(--cb); }
#site .prose strong { color: var(--nvy); font-weight: 600; }
#site .pullq { margin: clamp(32px, 4vw, 46px) 0; padding: 4px 0 4px 26px; border-left: 3px solid var(--cb); }
#site .pullq p { margin: 0 0 12px; font-size: clamp(1.15rem, 2vw, 1.45rem); font-weight: 600; line-height: 1.38; letter-spacing: -.022em; color: var(--nvy); }
#site .pullq .who { margin: 0; font-size: 13px; color: var(--k-mu); }
#site .aside-stack { display: grid; gap: 16px; align-content: start; }
#site .sidecard { background: #fff; border: 1px solid rgba(11,27,51,.1); border-radius: 14px; padding: 22px 24px 24px; }
#site .sidecard h3 { font-size: 1rem; letter-spacing: -.015em; margin-bottom: 12px; }
#site .sidecard ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 9px; }
#site .sidecard li { font-size: 13.5px; line-height: 1.55; color: var(--k-mu); }
#site .splitwrap { display: grid; grid-template-columns: 1.6fr .8fr; gap: clamp(32px, 4.4vw, 64px); align-items: start; }
@media (max-width: 900px) { #site .splitwrap { grid-template-columns: 1fr; } }

/* ---- next / prev ---- */
#site .nextrow { display: flex; align-items: center; justify-content: space-between; gap: 20px; flex-wrap: wrap;
  border-top: 1px solid rgba(11,27,51,.12); padding-top: 26px; margin-top: clamp(36px, 4vw, 56px); }
#site .nextrow .lb { margin: 0 0 6px; font-family: 'JetBrains Mono', monospace; font-size: 12.5px; letter-spacing: .04em; text-transform: uppercase; color: #55657D; }
#site .nextrow a { font-size: 1.15rem; font-weight: 600; letter-spacing: -.022em; color: var(--nvy); text-decoration: none; }
#site .nextrow a:hover { color: var(--cb); }

/* ---- faq page groups ---- */
#site .qgroup { margin-bottom: clamp(30px, 3.6vw, 48px); }
#site .qgroup > h3 { font-size: 13px; font-weight: 600; letter-spacing: .03em; text-transform: uppercase;
  color: var(--cb); margin-bottom: 6px; padding-bottom: 12px; border-bottom: 1px solid rgba(11,27,51,.4); }

/* ---- about ---- */
#site .duo { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(24px, 3.4vw, 52px); }
@media (max-width: 820px) { #site .duo { grid-template-columns: 1fr; } }
#site .ticklist { list-style: none; margin: 0; padding: 0; display: grid; gap: 13px; }
#site .ticklist li { position: relative; padding-left: 30px; font-size: 15px; line-height: 1.6; color: #3D4E68; }
#site .ticklist li::before { content: ""; position: absolute; left: 0; top: 7px; width: 15px; height: 9px; border-left: 2px solid var(--k-acc2); border-bottom: 2px solid var(--k-acc2); transform: rotate(-45deg); }
#site .ticklist.no li::before { border-color: #B0BCCD; width: 13px; height: 13px; border: 0; border-top: 2px solid #B0BCCD; top: 12px; transform: none; }

#site .cform { background: #fff; border: 1px solid rgba(11,27,51,.1); border-radius: 18px; padding: clamp(24px, 3vw, 38px); box-shadow: 0 30px 62px -42px rgba(11,27,51,.4); }
#site .frow { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
@media (max-width: 620px) { #site .frow { grid-template-columns: 1fr; } }
#site .field { display: grid; gap: 7px; margin-bottom: 16px; }
#site .field label { font-size: 13.5px; font-weight: 600; letter-spacing: -.01em; color: #33465F; }
#site .field input, #site .field textarea, #site .field select {
  font: inherit; font-size: 15px; color: var(--nvy); background: #FBFCFE; border: 1px solid rgba(11,27,51,.16); border-radius: 8px; padding: 12px 14px; width: 100%; transition: border-color .18s, box-shadow .18s; }
#site .field textarea { min-height: 132px; resize: vertical; }
/* one fixed height and line-height, so a box never grows or shrinks when Chrome previews
   an autofill suggestion in its own font (that moved the rows below); 16px on touch screens,
   as iOS zooms the page into any field under 16px */
#site .field input, #site .field .fpdd-btn { box-sizing: border-box; height: 50px; line-height: 24px; }
#site .field textarea { box-sizing: border-box; line-height: 1.6; }
@media (hover: none), (pointer: coarse) { #site .field input, #site .field textarea, #site .field .fpdd-btn { font-size: 16px; } }
#site .field input:focus, #site .field textarea:focus, #site .field select:focus {
  outline: none; border-color: var(--cb); box-shadow: 0 0 0 3px rgba(44,95,216,.14); }
/* Notion-style dropdown (site.js "dropdowns", ported from the BYO hub):
   the native select stays in the form, hidden; .fpdd-btn shows it and opens
   .fpdd-pop, a small floating list with a tick beside the current choice. */
#site .field select { appearance: none; -webkit-appearance: none; cursor: pointer; }
#site select.fpdd-native { display: none !important; }
#site .field .fpdd-btn { font: inherit; font-size: 15px; color: var(--nvy); text-align: left; cursor: pointer; width: 100%; padding: 12px 40px 12px 14px;
  background: #FBFCFE url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5l5 5 5-5' fill='none' stroke='%2333465F' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") no-repeat right 15px center;
  border: 1px solid rgba(11,27,51,.16); border-radius: 8px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; transition: border-color .18s, box-shadow .18s; }
#site .field .fpdd-btn.is-empty { color: #7D8BA0; }
#site .field .fpdd-btn:hover { border-color: rgba(11,27,51,.28); }
#site .field .fpdd-btn:focus-visible, #site .field .fpdd-btn.is-open { outline: none; border-color: var(--cb); box-shadow: 0 0 0 3px rgba(44,95,216,.14); }
.fpdd-pop { position: fixed; z-index: 10000; background: #fff; border-radius: 10px; padding: 5px; overflow-y: auto; overscroll-behavior: contain;
  box-shadow: 0 0 0 1px rgba(15,15,15,.06), 0 3px 6px rgba(15,15,15,.08), 0 9px 24px rgba(15,15,15,.14);
  font-family: "Hanken Grotesk", "Segoe UI", system-ui, sans-serif; font-size: 14.5px; color: #37352F; transform-origin: top left; animation: fpdd-in .16s cubic-bezier(.16,1,.3,1); }
.fpdd-pop.is-above { transform-origin: bottom left; animation-name: fpdd-in-up; }
.fpdd-pop.is-closing { animation: fpdd-out .1s ease-in forwards; pointer-events: none; }
.fpdd-pop:focus { outline: none; }
@keyframes fpdd-in { from { opacity: 0; transform: translateY(-6px) scale(.96); } to { opacity: 1; transform: none; } }
@keyframes fpdd-in-up { from { opacity: 0; transform: translateY(6px) scale(.96); } to { opacity: 1; transform: none; } }
@keyframes fpdd-out { to { opacity: 0; transform: scale(.97); } }
.fpdd-opt { display: flex; align-items: center; gap: 10px; padding: 8px 10px; border-radius: 6px; cursor: pointer; line-height: 1.35; user-select: none; }
.fpdd-opt span { flex: 1; min-width: 0; }
.fpdd-opt.is-active { background: rgba(55,53,47,.07); }
.fpdd-opt.is-selected { font-weight: 600; color: #0B1B33; }
.fpdd-opt.is-empty { color: #8A94A3; }
.fpdd-opt svg { width: 15px; height: 15px; color: #2C5FD8; flex: none; }
@media (prefers-reduced-motion: reduce) { .fpdd-pop, .fpdd-pop.is-above { animation: none; } }
/* a follow-up field that slides open when a matching choice is picked */
#site .fpreveal { display: grid; grid-template-rows: 1fr; transition: grid-template-rows .32s cubic-bezier(.2,.7,.2,1), opacity .25s; }
#site .fpreveal > * { min-height: 0; overflow: hidden; overflow: clip; overflow-clip-margin: 4px; }
#site .fpreveal.is-shut { grid-template-rows: 0fr; opacity: 0; }
#site .fpreveal[hidden] { display: none; }
#site .field input::placeholder, #site .field textarea::placeholder { color: #7D8BA0; }
#site .cform .btn { margin-top: 6px; }
#site .formnote { margin: 14px 0 0; font-size: 14px; line-height: 1.55; color: var(--k-mu); }
#site .formmsg { margin: 16px 0 0; padding: 13px 15px; border-radius: 8px; background: #EEF3FC; border: 1px solid rgba(44,95,216,.24); font-size: 14px; color: var(--nvy); }
#site .formmsg[hidden] { display: none; }
#site .steps { list-style: none; margin: 0; padding: 0; display: grid; gap: 16px; counter-reset: st; }
#site .steps li { position: relative; padding-left: 38px; font-size: 14px; line-height: 1.6; color: var(--k-mu); counter-increment: st; }
#site .steps li strong { display: block; color: var(--nvy); font-size: 14.5px; font-weight: 600; margin-bottom: 3px; }
#site .steps li::before { content: counter(st, decimal-leading-zero); position: absolute; left: 0; top: 1px;
  font-family: 'JetBrains Mono', monospace; font-size: 11px; color: var(--cb); }

/* ============================================================
   MOBILE NAVIGATION
   Below 940px the inline menu and megamenu are hidden, so the
   burger and drawer below are the only way through the site.
   ============================================================ */
#site .burger { display: none; appearance: none; cursor: pointer; background: transparent; border: 1px solid rgba(11,27,51,.16);
  border-radius: 8px; width: 42px; height: 42px; padding: 0; flex: none; align-items: center; justify-content: center; gap: 5px; flex-direction: column;
  transition: background .18s, border-color .18s; }
#site .burger:hover { border-color: rgba(11,27,51,.32); }
#site .burger span { display: block; width: 18px; height: 2px; border-radius: 2px; background: var(--nvy);
  transition: transform .26s cubic-bezier(.2,.7,.25,1), opacity .2s; }
#site .burger[aria-expanded="true"] span:first-child { transform: translateY(3.5px) rotate(45deg); }
#site .burger[aria-expanded="true"] span:last-child { transform: translateY(-3.5px) rotate(-45deg); }
#site .drawer { display: none; opacity: 0; transform: translateY(-8px);
  transition: opacity .18s ease, transform .2s cubic-bezier(.2,.7,.25,1); }
#site .drawer.open { opacity: 1; transform: none; }
#site .drawer[hidden] { display: none; }
@media (max-width: 940px) {
  #site .burger { display: flex; }
  /* the open drawer owns the whole viewport below the bar */
  #site .drawer:not([hidden]) { display: block; position: absolute; left: 0; right: 0; top: 100%;
    height: calc(100vh - var(--navh, 77px) - var(--shellh, 0px));
    height: calc(100dvh - var(--navh, 77px) - var(--shellh, 0px));
    background: #FCFDFF; border-top: 1px solid rgba(11,27,51,.08);
    overflow-y: auto; -webkit-overflow-scrolling: touch; }
  #site .drawer .dw { max-width: 1240px; margin: 0 auto; padding: 10px 22px 30px; }
  #site .drawer a { display: block; text-decoration: none; }
  #site .drawer .top a, #site .drawer .dsx { font-size: 1.28rem; font-weight: 600; letter-spacing: -.024em; color: var(--nvy);
    padding: 13px 0; border-bottom: 1px solid rgba(11,27,51,.09); }
  #site .drawer .top a[aria-current="page"] { color: var(--cb); }
  #site .drawer .dsx { appearance: none; background: transparent; border-left: 0; border-right: 0; border-top: 0; cursor: pointer;
    width: 100%; display: flex; align-items: center; justify-content: space-between; font-family: inherit; text-align: left; }
  #site .drawer .dsx svg { width: 12px; height: 12px; flex: none; transition: transform .2s; }
  #site .drawer .dsx[aria-expanded="true"] svg { transform: rotate(180deg); }
  #site .drawer .svc { border-bottom: 1px solid rgba(11,27,51,.09); padding: 4px 0 8px; }
  #site .drawer .svc:not([hidden]) { animation: dsvcin .22s ease; }
  #site .drawer .svc a { font-size: 15px; font-weight: 500; color: #33465F; padding: 10px 0 10px 14px; }
  #site .drawer .btn { display: inline-flex; width: auto; margin-top: 26px; }
  #site .drawer .dmail { margin: 16px 0 0; font-size: 13.5px; color: var(--k-mu); }
  #site .drawer .dmail a { display: inline; color: var(--cb); font-weight: 600; }
  /* the bar itself goes solid while the drawer is open */
  #site .nv.dropen { background: #FCFDFF; border-bottom-color: rgba(11,27,51,.1); }
}
@keyframes dsvcin { from { opacity: 0; transform: translateY(-5px); } }
@media (prefers-reduced-motion: reduce) {
  #site .burger span { transition: none; }
  #site .drawer { transition: none; opacity: 1; transform: none; }
  #site .drawer .svc:not([hidden]) { animation: none; }
  #site .drawer .dsx svg { transition: none; }
}

/* roomier touch targets on small screens */
@media (max-width: 620px) {
  #site footer ul { gap: 4px; }
  #site footer ul a { display: inline-block; padding: 7px 0; }
  #site .fbot ul { gap: 18px; }
  #site .fbot a { display: inline-block; padding: 6px 0; }
  #site .tlink { display: inline-block; padding: 6px 0; }
  #site .filters button { padding: 11px 17px; }
}


/* ---- faq search ---- */
#site .faqsearch { position: relative; max-width: 460px; margin: 26px 0 0; }
#site .faqsearch > svg { position: absolute; left: 17px; top: 50%; transform: translateY(-50%); width: 17px; height: 17px;
  stroke: #42536E; fill: none; stroke-width: 1.9; stroke-linecap: round; pointer-events: none; }
#site .faqsearch input { width: 100%; font: inherit; font-size: 15px; color: var(--nvy); background: #fff;
  border: 1.5px solid rgba(11,27,51,.26); border-radius: 100px; padding: 14px 48px 14px 46px;
  box-shadow: 0 1px 2px rgba(11,27,51,.06), 0 18px 34px -24px rgba(11,27,51,.55); transition: border-color .18s, box-shadow .18s; }
#site .faqsearch input:hover { border-color: rgba(11,27,51,.4); }
#site .faqsearch input::placeholder { color: #55657D; }
#site .faqsearch input:focus { outline: none; border-color: var(--cb); box-shadow: 0 0 0 3px rgba(44,95,216,.14); }
#site .faqsearch input::-webkit-search-cancel-button, #site .faqsearch input::-webkit-search-decoration { -webkit-appearance: none; appearance: none; }
#site .faqsearch button { position: absolute; right: 9px; top: 50%; transform: translateY(-50%); width: 30px; height: 30px;
  border: 0; border-radius: 50%; background: rgba(11,27,51,.07); color: #42536E; font-size: 17px; line-height: 1; cursor: pointer;
  display: grid; place-items: center; transition: background .16s, color .16s; }
#site .faqsearch button:hover { background: rgba(11,27,51,.14); color: var(--nvy); }
#site .faqsearch button[hidden] { display: none; }
#site .faqcount { margin: 14px 0 0; font-size: 13.5px; color: #42536E; }
#site .faqcount[hidden] { display: none; }
#site .faqcount b { color: var(--nvy); font-weight: 600; }
#site .faqcount a { color: var(--cb); font-weight: 600; }
#site .qgroup[hidden], #site .qi[hidden] { display: none; }


/* ============================================================
   STICKY SIDE RAIL
   The case-study aside follows the reader down the article.
   Static below the breakpoint, and on short viewports where a
   pinned column would be taller than the screen.
   ============================================================ */
@media (min-width: 901px) {
  #site .splitwrap > .aside-stack { position: sticky; top: calc(var(--navh, 77px) + 48px); align-self: start; }
  /* JS adds .railscroll only when the rail is genuinely taller than the
     viewport - a rail that fits must never own the wheel */
  #site .splitwrap > .aside-stack.railscroll { max-height: calc(100vh - var(--navh, 77px) - 96px);
    overflow-y: auto; scrollbar-width: thin; }
}

/* ---- results / quotes ---- */
#site .quotes { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; }
@media (max-width: 900px) { #site .quotes { grid-template-columns: 1fr 1fr; } }
@media (max-width: 620px) { #site .quotes { grid-template-columns: 1fr; } }







/* ---- the dashboard, trimmed for narrow screens ----
   At 760px the panel goes single column and everything below the fold of a
   phone is repetition: the strip repeats the median reply, and the 14 day
   chart tells the same before-and-after story the comparison bars already
   tell in two rows. What survives is the queue moving a lead from new to
   booked, the 38s against the old 4 hours, and the conversion figure. */
@media (max-width: 560px) {
}



/* the canvas: dotted ground, wires underneath, nodes on top */
#site .vzc { position: relative; isolation: isolate;
  background: radial-gradient(rgba(11,27,51,.15) 1px, transparent 1.3px) 0 0 / 20px 20px, #F7F9FD; }
#site .vzw { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; pointer-events: none; z-index: 0; }
#site .vzw path { fill: none; stroke-linecap: round; }
#site .vzw .w { stroke: rgba(11,27,51,.22); stroke-width: 1.5; }
#site .vzw .w.ghost { stroke: none; }
/* a packet is one short dash riding a wire: pathLength is 100, so a 7 unit
   dash on a 200 unit period shows once, then rests while the offset holds */
#site .vzw .p, #site .vzw .pg { stroke: var(--cb); stroke-width: 2.6; stroke-dasharray: 7 193; stroke-dashoffset: 7;
  animation: vzrun var(--d, 4s) var(--dl, 0s) infinite cubic-bezier(.45,.05,.4,.95); }
#site .vzw .pg { stroke-width: 8; opacity: .16; }
@keyframes vzrun { 0% { stroke-dashoffset: 7; } 84%, 100% { stroke-dashoffset: -100; } }

#site .ico { width: 21px; height: 21px; fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }
html.js-anim #site .vn em.tty span { animation: vztty 9s steps(var(--n)) infinite; }
html.js-anim #site .vn em.tty span::after { animation: vzttyc 9s steps(var(--n)) infinite; }
@keyframes vztty { 0%, 31% { opacity: 1; } 33.3%, 100% { opacity: 0; } }
@keyframes vzttyc { 0% { transform: translateX(0); } 14%, 100% { transform: translateX(calc(var(--n) * 1ch + 1px)); } }
/* data to and from the script travels as a short burst of bits rather than one dash */
#site .vzw .p.bits { stroke: #3E9A3C; stroke-dasharray: 1.4 1.4 1.4 1.4 1.4 193; stroke-linecap: butt; }
#site .vzw .pg.bits { stroke: #3E9A3C; stroke-dasharray: 7 193; }

/* message bubbles: ride a wire on an offset-path that site.js sets */
#site .msg { position: absolute; left: 0; top: 0; z-index: 3; display: none; pointer-events: none; white-space: nowrap;
  font-size: 13.5px; font-weight: 600; letter-spacing: -.005em; line-height: 1; color: var(--k-ink);
  padding: 8px 13px; border-radius: 100px; background: #fff; border: 1px solid rgba(44,95,216,.38);
  box-shadow: 0 10px 22px -10px rgba(11,27,51,.5); offset-rotate: 0deg; offset-distance: 10%; opacity: 0; }
#site .msg.on { display: block; }
/* rides the middle 80% of its wire so it leaves and arrives beside the nodes, not on top of them */
html.js-anim #site .msg.on { animation: vzmsg var(--d, 9s) var(--dl, 0s) infinite linear; }
@keyframes vzmsg { 0% { offset-distance: 10%; opacity: 0; } 3% { opacity: 1; } 14% { offset-distance: 90%; opacity: 1; } 17%, 100% { offset-distance: 90%; opacity: 0; } }

/* stacked up to 760px (2026-10-20): between 561 and 760 the three columns
   were too narrow and cut the node labels off */
@media (prefers-reduced-motion: reduce) {
  html.js-anim #site .vzw .p, html.js-anim #site .vzw .pg { animation: none; }
  html.js-anim #site .vn em.tty span, html.js-anim #site .vn em.tty span::after { animation: none; }
  #site .msg { display: none !important; }
}

/* real product screenshots */
#site .shot { border: 1px solid rgba(11,27,51,.12); border-radius: 14px; overflow: hidden; background: #fff;
  box-shadow: 0 16px 36px -24px rgba(11,27,51,.22); }
#site .shot .bar { display: flex; align-items: center; gap: 7px; padding: 10px 14px; background: #EEF2F9; border-bottom: 1px solid rgba(11,27,51,.1); }
#site .shot .bar i { width: 9px; height: 9px; border-radius: 50%; background: rgba(11,27,51,.16); }
#site .shot .bar span { margin-left: 8px; font-family: 'JetBrains Mono', monospace; font-size: 10px; color: #45556E;
  background: #fff; border: 1px solid rgba(11,27,51,.1); border-radius: 4px; padding: 3px 10px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
#site .shot img { display: block; width: 100%; height: auto; }
#site .shotcap { max-width: 72ch; margin: 18px 2px 0; font-size: 15px; line-height: 1.6; color: var(--k-mu); }
/* a phone beside two desktop screens */
#site .shotpair { display: grid; grid-template-columns: minmax(0, .36fr) minmax(0, 1fr); gap: clamp(20px, 3vw, 40px); align-items: center; }
#site .shotpair .phone { margin: 0; padding: 9px; border-radius: 34px; background: #0A1730; box-shadow: 0 30px 60px -32px rgba(11,27,51,.55); max-width: 300px; justify-self: center; }
#site .shotpair .phone img { display: block; width: 100%; height: auto; border-radius: 26px; }
@media (max-width: 760px) { #site .shotpair { grid-template-columns: 1fr; } #site .shotpair .phone { max-width: 240px; } }


#site .schow .schead, #site .scmapsec .schead, #site .sccrit .schead, #site .scfaq .schead { max-width: 56ch; margin-bottom: clamp(24px, 3vw, 38px); }
#site .schow h2, #site .scmapsec h2, #site .sccrit h2, #site .scfaq h2 { font-size: clamp(1.8rem, 3.4vw, 2.5rem); }



/* mini faq on the light ground */
#site .scfaq { padding: 0 0 clamp(48px, 6vw, 80px); }
#site .scfaq .qgrid { border-top: 1px solid rgba(11,27,51,.14); padding-top: 4px; }
#site .scfaq .qi { border-color: rgba(11,27,51,.14); }
#site .scfaq .qi summary { color: var(--k-ink); }
#site .scfaq .qi summary:hover i { color: var(--cb); }
#site .scfaq .qi > p { color: #4E5A70; }


#site .kpl { margin: 0 0 8px; font-size: 12.5px; font-weight: 700; letter-spacing: .03em; text-transform: uppercase; color: var(--k-mu); }


#site .kpi { display: grid; place-items: center; width: 40px; height: 40px; margin-bottom: 16px; border-radius: 11px;
  background: color-mix(in srgb, var(--k-acc) 13%, transparent); color: color-mix(in srgb, var(--k-acc) 80%, #0B1B33); }
#site .kpi svg { width: 21px; height: 21px; fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }



#site .sacrumb { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 10px; margin: 0; font-size: 14px; font-weight: 600; color: var(--k-ink); }
#site .sacrumb a { color: var(--k-mu); font-weight: 500; text-decoration: none; transition: color .2s; }
#site .sacrumb a:hover { color: var(--cb); }
#site .sacrumb span[aria-hidden] { color: #A9B5C8; font-weight: 400; }

/* ---- cookie banner (placeholder shell - see site.js) ----
   The first-visit bar is bottom-anchored rather than a modal, so it never
   blocks the page. "Settings" (on the bar, or the footer link) opens a
   centred dialog with a switch for analytics. Inside the safe area on phones. */
#site .ckbar { position: fixed; left: 0; right: 0; bottom: 0; z-index: 90;
  padding: 0 clamp(12px, 3vw, 24px) calc(clamp(12px, 3vw, 24px) + env(safe-area-inset-bottom, 0px));
  opacity: 0; transform: translateY(14px);
  transition: opacity var(--ul-dur) var(--ul-ease), transform var(--ul-dur) var(--ul-ease); }
#site .ckbar.on { opacity: 1; transform: none; }
#site .ckin { max-width: 1180px; margin: 0 auto; display: flex; align-items: center;
  justify-content: space-between; gap: clamp(16px, 3vw, 36px);
  padding: clamp(16px, 1.8vw, 20px) clamp(18px, 2.2vw, 26px);
  background: #FFFFFF; border: 1px solid rgba(11,27,51,.13); border-radius: var(--k-r);
  box-shadow: 0 26px 60px -28px rgba(11,27,51,.5); }
#site .ckin p { margin: 0; font-size: 13.5px; line-height: 1.55; color: #46587A; max-width: 78ch; }
#site .ckin p a { color: var(--cb); font-weight: 600; text-decoration: none; }
#site .ckin p a:hover { text-decoration: underline; text-underline-offset: 2px; }
#site .ckbtns { flex: none; display: flex; gap: 10px; }
#site .ckbar .btn { padding: 11px 18px; font-size: 14px; }
@media (max-width: 720px) {
  #site .ckin { display: grid; gap: 14px; }
  #site .ckbtns { justify-content: flex-start; }
}
#site .cklink { appearance: none; border: 0; background: none; cursor: pointer; padding: 11px 8px; font: inherit; font-size: 14px; font-weight: 600; color: #46587A; }
#site .cklink:hover { color: var(--cb); }

/* the settings dialog: centred over a soft blurred veil */
#site .ckm { position: fixed; inset: 0; z-index: 95; display: grid; place-items: center; padding: 20px;
  background: rgba(10,23,48,.42); -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
  opacity: 0; transition: opacity .28s var(--ul-ease); }
#site .ckm.on { opacity: 1; }
#site .ckm[hidden] { display: none; }
#site .ckm-card { position: relative; width: 100%; max-width: 500px; max-height: calc(100vh - 40px); overflow: auto; outline: none;
  padding: clamp(24px, 4vw, 34px); border-radius: 20px; background: #fff; border: 1px solid rgba(11,27,51,.1);
  box-shadow: 0 50px 100px -40px rgba(10,23,48,.6), 0 0 0 6px rgba(255,255,255,.08);
  transform: translateY(14px) scale(.97); transition: transform .4s cubic-bezier(.2,.8,.2,1); }
#site .ckm.on .ckm-card { transform: none; }
#site .ckm-x { position: absolute; right: 14px; top: 14px; display: grid; place-items: center; width: 34px; height: 34px; border: 0; border-radius: 50%; background: #F1F4F9; color: #46587A; cursor: pointer; transition: background .2s; }
#site .ckm-x:hover { background: #E3E9F3; }
#site .ckm-x svg { width: 14px; height: 14px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; }
#site .ckm-ic { display: grid; place-items: center; width: 48px; height: 48px; border-radius: 14px; background: linear-gradient(140deg, #EAF0FD, #F0F8EE); border: 1px solid rgba(44,95,216,.16); }
#site .ckm-ic svg { width: 24px; height: 24px; fill: none; stroke: var(--cb); stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
#site .ckm-card h3 { margin: 18px 0 6px; font-size: 1.45rem; letter-spacing: -.02em; color: var(--k-ink); }
#site .ckm-sub { margin: 0; font-size: 14.5px; line-height: 1.55; color: #4E5A70; }
#site .ckm-rows { display: grid; gap: 10px; margin: 22px 0 24px; }
#site .ckm-row { display: flex; align-items: center; justify-content: space-between; gap: 16px; padding: 15px 16px; border-radius: 14px; background: #F6F8FC; border: 1px solid rgba(11,27,51,.07); }
#site label.ckm-row { cursor: pointer; transition: border-color .2s, background .2s; }
#site label.ckm-row:hover { border-color: rgba(44,95,216,.3); }
#site .ckm-row b { display: block; font-size: 15px; color: var(--k-ink); }
#site .ckm-row span { display: block; margin-top: 3px; font-size: 13.5px; line-height: 1.45; color: #45556E; }
#site .ckm-row em { flex: none; font-style: normal; font-size: 12.5px; font-weight: 600; padding: 4px 10px; border-radius: 100px; background: #E7F3E4; color: #3E8A2C; }
/* the switch */
#site .ckm-sw { appearance: none; -webkit-appearance: none; flex: none; position: relative; width: 44px; height: 26px; margin: 0; border-radius: 100px; background: #C9D3E3; cursor: pointer; transition: background .25s; }
#site .ckm-sw::after { content: ""; position: absolute; left: 3px; top: 3px; width: 20px; height: 20px; border-radius: 50%; background: #fff; box-shadow: 0 2px 5px rgba(11,27,51,.3); transition: transform .25s cubic-bezier(.3,.7,.3,1); }
#site .ckm-sw:checked { background: var(--cb); }
#site .ckm-sw:checked::after { transform: translateX(18px); }
#site .ckm-sw:focus-visible { outline: 2px solid var(--cb); outline-offset: 3px; }
#site .ckm-foot { display: flex; align-items: center; justify-content: space-between; gap: 14px; flex-wrap: wrap; padding-top: 18px; border-top: 1px solid rgba(11,27,51,.08); }
#site .ckm-foot a { font-size: 14px; font-weight: 600; color: var(--cb); text-decoration: none; }
#site .ckm-foot a:hover { text-decoration: underline; text-underline-offset: 2px; }
#site .ckm-foot > span { display: flex; gap: 10px; }
#site .ckm .btn { padding: 11px 18px; font-size: 14px; }
@media (max-width: 480px) {
  #site .ckm { align-items: end; padding: 12px; }
  #site .ckm-foot > span { width: 100%; }
  #site .ckm-foot .btn { flex: 1; justify-content: center; }
}
@media (prefers-reduced-motion: reduce) { #site .ckbar, #site .ckm, #site .ckm-card { transition: none; } }


/* ============================================================
   CONTACT PAGE
   Pitch and proof on the left, the form in a white card on the
   right, side by side from the top of the page - so the form is
   reachable without scrolling and the reasons to send it sit
   beside it rather than above it.
   ============================================================ */
#site .cpage { padding: clamp(48px, 6vw, 88px) 0 clamp(56px, 7vw, 96px); }
#site .co-grid { display: grid; grid-template-columns: 1fr 1.08fr; gap: clamp(36px, 6vw, 96px); align-items: start; }

#site .co-intro h2 { font-size: clamp(2rem, 3.6vw, 2.9rem); line-height: 1.02; letter-spacing: -.034em;
  margin: 0; max-width: 12ch; }
#site .co-lead { margin: 26px 0 0; max-width: 46ch; font-size: clamp(1.02rem, 1.4vw, 1.14rem);
  line-height: 1.7; color: #42536E; }
#site .co-mail { margin: 22px 0 0; font-size: 15px; line-height: 1.7; color: #42536E; }
#site .co-mail a { color: var(--k-ink); font-weight: 600; }
/* the three steps from form to call, on a line, the first one filled -
   you are here. On load the line draws across and each step follows it in,
   then the first node keeps a slow, faint pulse (chosen 2026-10-11 over
   Icons and Cards) */
#site .co-steps { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; list-style: none; margin: 30px 0 0; padding: 24px 0 0; border-top: 1px solid var(--k-line); }
#site .co-steps li { position: relative; padding-top: 26px; }
#site .co-steps li::before { content: ""; position: absolute; left: 4px; top: 0; z-index: 1; width: 12px; height: 12px; border-radius: 50%; background: #F7F9FC; border: 2px solid var(--cb); box-sizing: border-box; }
#site .co-steps li:first-child::before { background: var(--cb); box-shadow: 0 0 0 5px rgba(44,95,216,.14); }
#site .co-steps li:not(:last-child)::after { content: ""; position: absolute; left: 16px; right: -14px; top: 5px; height: 2px; transform-origin: 0 50%; background: linear-gradient(90deg, rgba(44,95,216,.5), rgba(44,95,216,.18)); }
#site .co-steps b { display: block; font-size: 15px; letter-spacing: -.015em; }
#site .co-steps span { display: block; margin-top: 3px; font-size: 13px; line-height: 1.45; color: var(--k-mu); }
/* keyed on :not(.fp-wait) like the page entrances, so the steps start when the
   page is shown, not while it is still hidden: an animation that began under
   the fp-wait hold never interpolated in WebKit - it held its start value for
   the whole run and snapped to the end (James 2026-10-20: on a phone the steps
   "just appear one by one" with no fade; Chrome was fine). Measured in
   Playwright WebKit: opacity 0 until the animation finished, 1 after; with the
   prefix it fades as drawn. The explicit end keyframes are belt and braces */
html.js-anim:not(.fp-wait) #site .co-steps li { animation: cstep .6s cubic-bezier(.25,1,.5,1) both; }
html.js-anim:not(.fp-wait) #site .co-steps li::after { animation: csline .7s cubic-bezier(.5,0,.2,1) both; }
html.js-anim:not(.fp-wait) #site .co-steps li:first-child::before { animation: cspulse 2.8s ease-in-out 1.6s infinite; }
html.js-anim:not(.fp-wait) #site .co-steps li:nth-child(1) { animation-delay: .35s; }
html.js-anim:not(.fp-wait) #site .co-steps li:nth-child(1)::after { animation-delay: .6s; }
html.js-anim:not(.fp-wait) #site .co-steps li:nth-child(2) { animation-delay: .85s; }
html.js-anim:not(.fp-wait) #site .co-steps li:nth-child(2)::after { animation-delay: 1.1s; }
html.js-anim:not(.fp-wait) #site .co-steps li:nth-child(3) { animation-delay: 1.35s; }
@keyframes cstep { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
@keyframes csline { from { transform: scaleX(0); } to { transform: scaleX(1); } }
@keyframes cspulse { 0%, 100% { box-shadow: 0 0 0 5px rgba(44,95,216,.14); } 50% { box-shadow: 0 0 0 8px rgba(44,95,216,.06); } }
@media (prefers-reduced-motion: reduce) {
  html.js-anim:not(.fp-wait) #site .co-steps li, html.js-anim:not(.fp-wait) #site .co-steps li::after, html.js-anim:not(.fp-wait) #site .co-steps li:first-child::before { animation: none; }
}
@media (max-width: 460px) {
  #site .co-steps { grid-template-columns: 1fr; gap: 18px; }
  #site .co-steps li { padding: 0 0 0 26px; }
  /* the dot is centred on the 24px title line (James 2026-10-20: the dots sat too high on phones), and the line runs from its bottom to the top of the next dot */
  #site .co-steps li::before { left: 0; top: 6px; }
  #site .co-steps li:not(:last-child)::after { left: 5px; right: auto; top: 18px; bottom: -24px; width: 2px; height: auto; transform-origin: 50% 0; background: rgba(44,95,216,.3); }
  @keyframes csline { from { transform: scaleY(0); } to { transform: scaleY(1); } }
}

/* a real client's words, carrying the credibility slot that a
   bigger agency would fill with a logo wall */
#site .cq { margin: 26px 0 0; padding: 20px 22px; border-radius: 14px;
  background: var(--k-sf2); border: 1px solid var(--k-line); }
#site .cq blockquote { margin: 0 0 14px; font-size: 15px; line-height: 1.6; letter-spacing: -.008em; color: var(--k-ink); }
#site .cq figcaption b { display: block; font-size: 14px; letter-spacing: -.01em; }
#site .cq figcaption span { display: block; font-size: 13px; color: var(--k-mu); margin-top: 2px; }

#site .co-card { background: #fff; border: 1px solid rgba(11,27,51,.09); border-radius: 18px;
  padding: clamp(24px, 3vw, 40px); box-shadow: 0 26px 56px -40px rgba(4,12,30,.26); } /* softer shadow (James 2026-10-20) */
#site .co-card .field { margin-bottom: 16px; }
#site .co-card .frow { gap: 16px; }
#site .co-card textarea { min-height: 148px; }
#site .co-card .btn.cb { width: 100%; justify-content: center; margin-top: 6px;
  box-shadow: 0 8px 16px -10px rgba(44,95,216,.5); }

/* the testimonial is the grid's third child (after the form in the markup),
   so on phones it comes after the form (James 2026-10-20); on desktop it is
   placed back under the intro, in the left column, with the form spanning
   both rows */
@media (min-width: 941px) {
  #site .co-grid { grid-template-rows: auto 1fr; row-gap: 0; }
  #site .co-grid > .co-intro { grid-column: 1; grid-row: 1; }
  #site .co-grid > .co-card { grid-column: 2; grid-row: 1 / span 2; }
  #site .co-grid > .cq { grid-column: 1; grid-row: 2; align-self: start; }
}
@media (max-width: 940px) { #site .co-grid { grid-template-columns: 1fr; gap: 40px; } #site .co-grid > .cq { margin-top: 0; } }


/* ============================================================
   ABOUT PAGE
   A dark opening band, then the homepage comparison component
   turned on the origin story - four jobs, before the systems
   were built and after - and the story itself alongside it.
   ============================================================ */
/* the page head: the site's dark band, carrying just the page name.
   .phband, not .pband - .pband is the homepage's four-step process band.
   Shared by about, services, case studies and the FAQs - one source, so
   the four inner pages open identically */
#site .phband { position: relative; color: #A9B8D0; margin-top: calc(-1 * var(--navh, 77px));
  padding: calc(var(--navh, 77px) + clamp(48px, 6vw, 84px)) 0 clamp(44px, 5.5vw, 76px);
  background: radial-gradient(72% 95% at 8% 0%, rgba(44,95,216,.12), transparent 68%), var(--grainw), var(--nvy); }
#site .phband { text-align: center; }
#site .phband h1 { color: #fff; font-size: clamp(2.2rem, 4.6vw, 3.6rem); line-height: 1.02;
  letter-spacing: -.034em; margin: 0; }

/* a line under the title, where a page has one */
/* the band ends on two soft waves - a translucent blue one behind a paper one
   that carries the page grain, so there is no hard edge into the content */
#site .phband { padding-bottom: calc(clamp(44px, 5.5vw, 76px) + clamp(20px, 4.9vw, 70px)); }
#site .phband::before, #site .phband::after { content: ""; position: absolute; left: 0; right: 0; bottom: -1px; height: clamp(26px, 6.25vw, 90px); pointer-events: none; }
/* the wave scales with the width, so it keeps the same gentle slope on phones */
#site .phband::before { background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1440 90' preserveAspectRatio='none'%3E%3Cpath d='M0 30 C 300 70 560 80 820 40 S 1260 0 1440 22 V90 H0Z' fill='%237EA4F6' fill-opacity='.35'/%3E%3C/svg%3E") bottom / 100% 100% no-repeat; }
#site .phband::after { background: var(--grain), #F7F9FC;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1440 90' preserveAspectRatio='none'%3E%3Cpath d='M0 52 C 240 92 480 92 720 58 S 1200 10 1440 44 V90 H0Z'/%3E%3C/svg%3E") bottom / 100% 100% no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1440 90' preserveAspectRatio='none'%3E%3Cpath d='M0 52 C 240 92 480 92 720 58 S 1200 10 1440 44 V90 H0Z'/%3E%3C/svg%3E") bottom / 100% 100% no-repeat; }
/* a faint field of drifting pixels behind the title (site.js "pixel drift").
   Layering: canvas at the bottom, the waves over it, the title on top */
#site .phband .pxfield { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; z-index: 0; }
#site .phband::before, #site .phband::after { z-index: 1; }
#site .phband .wrap { position: relative; z-index: 2; }

/* ---- the intro under the band ----
   The band carries the name alone, so the lead moves below it: centred on
   its own (.mid), or paired with whatever the page needs beside it - a
   search field, a project index ---- */
#site .pintro { padding: clamp(34px, 4.2vw, 56px) 0 0; }
#site .pintro.mid { text-align: center; }
#site .pintro.mid .lead, #site .pintro.mid .faqsearch { margin-inline: auto; }
#site .pintro + .sec { padding-top: clamp(40px, 4.6vw, 64px); }

/* the intro: one image beside the story */
#site .abintro { padding-top: clamp(40px, 5vw, 72px); }
#site .ab-grid { display: grid; grid-template-columns: .82fr 1.18fr; gap: clamp(30px, 4.6vw, 72px); align-items: start; }
/* the picture pins beside the story as it scrolls - lower on the screen than
   just under the nav (site.js "about: real work" sets the top so it sits
   around the middle of the window, level with the text being read) */
#site .ab-media { position: sticky; top: calc(var(--navh, 77px) + 24px); }
/* the crop is biased above centre so the face survives when the box is
   shorter than the source and the crop eats the top and bottom */
#site .ab-media img { display: block; width: 100%; height: clamp(320px, 47vw, 600px);
  object-fit: cover; object-position: 50% 22%; border-radius: 18px; }
#site .ab-copy h2 { font-size: clamp(1.9rem, 3.6vw, 2.9rem); line-height: 1.06; letter-spacing: -.032em;
  margin: 0 0 22px; max-width: 18ch; }
#site .ab-copy p { margin: 0 0 20px; font-size: 1.02rem; line-height: 1.75; color: #3D4E68; max-width: 62ch; }
/* the opening line is an introduction, not a paragraph - it gets its own weight */
#site .ab-open { font-size: 1.14rem !important; font-weight: 600; letter-spacing: -.018em; color: var(--k-ink) !important; }
#site .ab-copy .btn { margin-top: 6px; }
/* Single column. The portrait is capped at 380px - unbounded it stretches the
   full width of a tablet and dwarfs the story. width:100% is load-bearing: an
   auto margin suppresses grid stretch, so without a definite width the box
   shrink-to-fits the image's own ratio and lands narrower than its column. */
@media (max-width: 860px) {
  #site .ab-grid { grid-template-columns: 1fr; }
  #site .ab-media { position: static; width: 100%; max-width: 380px; }
  #site .ab-media img { height: clamp(320px, 62vw, 460px); }
}
/* Tablet and wide phone: the capped image leaves slack either side, so the
   whole block centres rather than hugging one edge of a much wider column. */
@media (min-width: 561px) and (max-width: 860px) {
  #site .ab-media { margin-inline: auto; }
  #site .ab-copy { text-align: center; }
  #site .ab-copy h2, #site .ab-copy p { margin-inline: auto; }
}
/* Narrow phone: the column is barely wider than the image, so there is no
   slack to centre into - left aligned, matching every other page. */
@media (max-width: 560px) {
  #site .ab-media { margin-inline: 0; }
}

/* ---- about: real work in place of the photo (chosen 2026-10-11 over Journey,
   Results, Brand mark and Build log) - real screenshots of things built,
   fanned like prints on a desk; hover or tap brings one forward */
#site .aw-stack { position: relative; aspect-ratio: 1 / .96; }
#site .aw-c { position: absolute; width: 78%; margin: 0; background: #fff; border-radius: 12px; overflow: hidden;
  border: 1px solid rgba(11,27,51,.1); box-shadow: 0 2px 4px rgba(11,27,51,.05), 0 30px 50px -30px rgba(11,27,51,.55);
  transform: rotate(var(--r)); transition: transform .5s cubic-bezier(.25,1,.5,1), box-shadow .4s; }
#site .aw-c img { display: block; width: 100%; height: auto; aspect-ratio: 16 / 10.5; object-fit: cover; object-position: 50% 0; }
#site .aw-bar { display: flex; gap: 5px; padding: 8px 10px; background: #F1F4F9; border-bottom: 1px solid rgba(11,27,51,.07); }
#site .aw-bar i { width: 8px; height: 8px; border-radius: 50%; background: rgba(11,27,51,.15); }
#site .aw-c figcaption { padding: 9px 12px 10px; font-size: 13px; font-weight: 500; color: var(--k-ink); border-top: 1px solid rgba(11,27,51,.07); }
#site .aw-ph { width: 33%; border-radius: 20px; border: 5px solid #0B1B33; }
#site .aw-ph img { aspect-ratio: 9 / 17; }
#site .aw-ph figcaption { display: none; }
#site .aw-c:hover { z-index: 5; transform: translateY(-8px) rotate(0deg) scale(1.03); box-shadow: 0 4px 8px rgba(11,27,51,.06), 0 50px 70px -36px rgba(11,27,51,.6); }
#site .aw-cap { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 12px 20px; margin: 18px 0 0; padding-top: 16px; border-top: 1px solid rgba(11,27,51,.1); }
#site .aw-cap p { margin: 0; }
#site .aw-cap b { display: block; font-size: 17px; font-weight: 600; letter-spacing: -.01em; color: var(--k-ink); }
#site .aw-cap span { display: block; margin-top: 2px; font-size: 15px; line-height: 1.5; color: var(--k-mu); }
#site .aw-cap a { display: inline-flex; align-items: center; gap: 8px; font-size: 15px; color: var(--cb); font-weight: 600; text-decoration: none; white-space: nowrap; }
#site .aw-cap a .arr svg [stroke] { stroke: currentColor; }
@media (max-width: 860px) {
  #site .abc { max-width: 460px; }
}
#site .ab-media .abc img { height: auto; border-radius: 0; }
#site .aw-c img:not([style]) { object-position: 50% 0; }

/* ============================================================
   DESIGN LAB (temporary)
   Candidate designs James is flicking between with the floating
   switcher site.js adds (case
   study pages: the hero). Each candidate is a body class over the
   same markup. Once one is picked, fold it into the rules above and
   delete this block and the lab in site.js.
   ============================================================ */
/* below the cookie bar (90) so it never covers the consent buttons */
#site .lab { position: fixed; left: 50%; bottom: 16px; z-index: 89; transform: translateX(-50%); max-width: calc(100% - 24px);
  display: flex; align-items: center; gap: 2px; padding: 5px; overflow-x: auto; scrollbar-width: none;
  background: rgba(10,23,48,.92); -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px);
  border: 1px solid rgba(255,255,255,.14); border-radius: 100px; box-shadow: 0 18px 40px -16px rgba(0,0,0,.6); }
#site .lab::-webkit-scrollbar { display: none; }
#site .lab > span { flex: none; padding: 0 10px 0 12px; font-size: 13px; font-weight: 700; color: #8FA3C4; white-space: nowrap; }
#site .lab button { appearance: none; border: 0; background: transparent; cursor: pointer; flex: none; font: inherit; font-size: 13.5px; font-weight: 600;
  line-height: 1; color: #C9D6E9; padding: 9px 14px; border-radius: 100px; white-space: nowrap; transition: background .18s, color .18s; }
#site .lab button:hover { color: #fff; background: rgba(255,255,255,.08); }
#site .lab button[aria-pressed="true"] { background: #fff; color: var(--nvy); }
#site .lab button:focus-visible { outline: 2px solid #AFC8FF; outline-offset: 2px; }

/* ---- case study pages: the body below the hero ("Blocks", picked 2026-10-12) ----
   Carries the Frame: Build hero down the page: hairline boxes with
   crosshair corners, mono labels, square markers stepping down like the
   logo, and a small line icon on every heading - site.js "case study
   icons" sets data-ic from the heading text. The demos, maps, flowcharts,
   charts and screenshots keep their own styles; the CTA band and footer
   are shared and untouched. Every section's .wrap already sits on the same
   1180px content edges as the hero frame (see the hero block) */
#site main > .sec.tint:has(.nextrow) { background: none; }
/* when the next link stands alone, no tall empty band above it */
#site main > .sec.tint:has(> .wrap > .nextrow:first-child) { padding-top: 0; }
#site main > .sec.tint > .wrap > .nextrow:first-child { margin-top: 0; }
#site { --cs-cross: linear-gradient(var(--k-ink), var(--k-ink)) center / 13px 1px no-repeat, linear-gradient(var(--k-ink), var(--k-ink)) center / 1px 13px no-repeat; }

/* heading icons: one line set, navy, 1.5 stroke */
#site [data-ic="brief"] { --ic: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%230A1730' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6.5 3h7.5l4 4v14h-11.5z'/%3E%3Cpath d='M14 3v4h4M9.5 12h5M9.5 16h5'/%3E%3C/svg%3E"); }
#site [data-ic="approach"] { --ic: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%230A1730' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='6' cy='18' r='2'/%3E%3Ccircle cx='18' cy='6' r='2'/%3E%3Cpath d='M8 18h6.5a3 3 0 0 0 0-6h-5a3 3 0 0 1 0-6H16'/%3E%3C/svg%3E"); }
#site [data-ic="build"] { --ic: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%230A1730' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 3l8 4.5v9L12 21l-8-4.5v-9z'/%3E%3Cpath d='M4 7.5l8 4.5 8-4.5M12 12v9'/%3E%3C/svg%3E"); }
#site [data-ic="design"] { --ic: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%230A1730' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 20l3.5-1 11-11a2.1 2.1 0 0 0-3-3l-11 11z'/%3E%3Cpath d='M14 6.5l3 3'/%3E%3C/svg%3E"); }
#site [data-ic="results"] { --ic: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%230A1730' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 20h16'/%3E%3Cpath d='M7 16v-3M12 16V9M17 16V5'/%3E%3C/svg%3E"); }
#site [data-ic="why"] { --ic: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%230A1730' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 3.5l2.6 5.3 5.9.9-4.3 4.1 1 5.8L12 16.9l-5.2 2.7 1-5.8-4.3-4.1 5.9-.9z'/%3E%3C/svg%3E"); }
#site [data-ic="fit"] { --ic: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%230A1730' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M10 14a4 4 0 0 0 5.7 0l3-3A4 4 0 0 0 13 5.3l-1 1'/%3E%3Cpath d='M14 10a4 4 0 0 0-5.7 0l-3 3a4 4 0 0 0 5.7 5.7l1-1'/%3E%3C/svg%3E"); }
#site [data-ic="flow"] { --ic: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%230A1730' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='3.5' width='7' height='6' rx='1.2'/%3E%3Crect x='14' y='14.5' width='7' height='6' rx='1.2'/%3E%3Cpath d='M6.5 9.5V14a3 3 0 0 0 3 3H14'/%3E%3C/svg%3E"); }
#site [data-ic="page"] { --ic: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%230A1730' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='4' width='18' height='16' rx='2'/%3E%3Cpath d='M3 8.5h18M13 12.5h5M13 16h3M6.5 12.5h3.5v3.5H6.5z'/%3E%3C/svg%3E"); }
#site [data-ic="stack"] { --ic: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%230A1730' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 3.5l9 4.5-9 4.5L3 8z'/%3E%3Cpath d='M3 12.5l9 4.5 9-4.5M3 16.5l9 4.5 9-4.5'/%3E%3C/svg%3E"); }
#site [data-ic="list"] { --ic: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%230A1730' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 7l2 2 3.5-3.5M4 16l2 2 3.5-3.5M13 8h7M13 17h7'/%3E%3C/svg%3E"); }
#site [data-ic="you"] { --ic: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%230A1730' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 5h16v11H10l-6 4z'/%3E%3Cpath d='M8 9.5h8M8 12.5h5'/%3E%3C/svg%3E"); }
#site [data-ic="live"] { --ic: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%230A1730' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M14 4h6v6M20 4l-9 9'/%3E%3Cpath d='M18 14v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h5'/%3E%3C/svg%3E"); }
#site [data-ic="season"] { --ic: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%230A1730' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3.5' y='5' width='17' height='15.5' rx='2'/%3E%3Cpath d='M3.5 9.5h17M8 3v4M16 3v4'/%3E%3Cpath d='M6.5 17.5c2-3 3.5-3 5 0s3 3 5.5-2'/%3E%3C/svg%3E"); }
#site [data-ic="next"] { --ic: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%232C5FD8' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 12h15M13.5 6.5L19 12l-5.5 5.5'/%3E%3C/svg%3E"); }
#site .pullq { --ic: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%230A1730' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M10 6.5C6.5 7.5 4.5 10 4.5 13.5V18h5v-5H7c0-2.3 1.2-3.8 3-4.6zM19.5 6.5C16 7.5 14 10 14 13.5V18h5v-5h-2.5c0-2.3 1.2-3.8 3-4.6z'/%3E%3C/svg%3E"); }
#site :is(.splitwrap .prose > h2, .fdhead > div > h2)[data-ic]::before { content: ""; display: block; width: 24px; height: 24px; margin-bottom: 14px; background: var(--ic) center / contain no-repeat; }

/* prose: square bullets stepping down like the logo */
#site .splitwrap .prose > ul:not([class]) { list-style: none; padding-left: 0; }
#site .splitwrap .prose > ul:not([class]) > li { position: relative; padding-left: 24px; }
#site .splitwrap .prose > ul:not([class]) > li::before { content: ""; position: absolute; left: 2px; top: .52em; width: 8px; height: 8px; border-radius: 2px; background: var(--nvy); }
/* every bullet a step lighter than the one before, then the rest stay at the lightest step (no jump back to black on long lists) */
#site .splitwrap .prose > ul:not([class]) > li:nth-child(2)::before { opacity: .74; }
#site .splitwrap .prose > ul:not([class]) > li:nth-child(3)::before { opacity: .52; }
#site .splitwrap .prose > ul:not([class]) > li:nth-child(4)::before { opacity: .36; }
#site .splitwrap .prose > ul:not([class]) > li:nth-child(n+5)::before { opacity: .24; }
/* side card lists of more than one line get the same stepped square bullets */
#site .sidecard ul:has(li + li) > li { position: relative; padding-left: 20px; }
#site .sidecard ul:has(li + li) > li::before { content: ""; position: absolute; left: 1px; top: .55em; width: 7px; height: 7px; border-radius: 2px; background: var(--nvy); }
#site .sidecard ul:has(li + li) > li:nth-child(2)::before { opacity: .74; }
#site .sidecard ul:has(li + li) > li:nth-child(3)::before { opacity: .52; }
#site .sidecard ul:has(li + li) > li:nth-child(4)::before { opacity: .36; }
#site .sidecard ul:has(li + li) > li:nth-child(n+5)::before { opacity: .24; }

/* results row: hairline cells, a square marker on each, crosshair corners */
#site .resrow { position: relative; border-color: var(--k-line); }
#site .resrow div { border-color: var(--k-line); }
#site .resrow .n { color: var(--nvy); }
#site .resrow div::before { content: ""; display: block; width: 9px; height: 9px; margin-bottom: 20px; border-radius: 2px; background: var(--nvy); }
#site .resrow div:nth-child(2)::before { opacity: .55; }
#site .resrow div:nth-child(3)::before { opacity: .3; }
#site :is(.resrow, .aside-stack)::before, #site :is(.resrow, .aside-stack)::after { content: ""; position: absolute; z-index: 1; width: 13px; height: 13px;
  background: var(--cs-cross); opacity: .55; pointer-events: none; }
#site :is(.resrow, .aside-stack)::before { top: -7px; left: -7px; }
#site :is(.resrow, .aside-stack)::after { bottom: -7px; right: -7px; }

/* the side column: one hairline box of ruled notes, sticky beside the
   prose on desktop (the sticky rule sits with the case study layout above) */
#site .aside-stack { gap: 0; border: 1px solid var(--k-line); background: rgba(255,255,255,.6); }
@media (max-width: 900px) { #site .aside-stack { position: relative; } }
/* the sticky column follows the nav: under it while it shows, near the top
   once it slides away on the way down (same .35s ease as the bar) */
@media (min-width: 901px) and (prefers-reduced-motion: no-preference) {
  #site .splitwrap > .aside-stack { transition: top .35s ease; }
  #site:has(.nv.hide) .splitwrap > .aside-stack { top: 48px; }
}
#site .splitwrap > .aside-stack.railscroll::before, #site .splitwrap > .aside-stack.railscroll::after { display: none; }
#site .sidecard { background: none; border: 0; border-radius: 0; padding: 24px 26px 26px; }
#site .sidecard + .sidecard { border-top: 1px solid var(--k-line); }
#site .sidecard h3 { display: flex; align-items: center; gap: 11px; margin-bottom: 14px; font-size: 17.5px; font-weight: 600; line-height: 1.3;
  letter-spacing: -.015em; color: var(--k-ink); }
#site .sidecard h3[data-ic]::before { content: ""; width: 20px; height: 20px; flex: none; background: var(--ic) center / contain no-repeat; }
#site .sidecard li { font-size: 14px; }
#site .sidecard .chips i { font-size: 12.5px; background: #fff; border-radius: 4px; }

/* captions, quote and the next row */
#site .shotcap { display: flex; gap: 12px; }
#site .shotcap::before { content: ""; width: 8px; height: 8px; flex: none; margin-top: .55em; border-radius: 2px; background: var(--nvy); opacity: .45; }
#site main .pullq { max-width: none !important; padding: 0; border: 0; }
#site .pullq::before { content: ""; display: block; width: 26px; height: 26px; margin-bottom: 18px; background: var(--ic) center / contain no-repeat; }
#site .pullq p { max-width: 36ch; font-size: clamp(1.3rem, 2.3vw, 1.7rem); }
#site .pullq .who { font-size: 13.5px; }
#site main .nextrow { border-top-color: var(--k-line) !important; }
#site .nextrow .lb { display: flex; align-items: center; gap: 9px; font-size: 12.5px; letter-spacing: .02em; color: var(--k-mu); }
#site .nextrow .lb[data-ic]::before { content: ""; width: 16px; height: 16px; flex: none; background: var(--ic) center / contain no-repeat; }

/* ---- locked case study cards (case-studies.html 07 the outreach system, in progress under
   NDA, and 08 The Espresso Den, private - James 2026-10-18). The card shows, but its picture
   is blurred under a padlock and clicking opens a small popup instead of a page. Built for
   speed (James: "this loads slowly"): the blurred pictures are static (07 is a pre-blurred
   still of the campaign demo, assets/img/outreach-card-locked.webp; 08 a small drawn mock with
   one fixed blur), nothing animates the blur, and the popup shows at once - only the card
   fades in over 100ms. The password version is parked in reference-designs/locked-password-popup.html ---- */
#site button.fwshot { position: relative; display: block; width: 100%; padding: 0; border: 0; background: none; font: inherit; color: inherit; text-align: left; cursor: pointer; }
#site .lkpop { position: fixed; inset: 0; z-index: 400; display: grid; place-items: center; padding: 16px; background: rgba(11,27,51,.42); }
#site .lkpop[hidden] { display: none; }
#site .lkpop-c:focus { outline: none; }
#site .lkpop-c { position: relative; width: min(440px, 100%); max-height: calc(100vh - 32px); overflow: auto; padding: 30px 28px 26px; border-radius: 16px; background: #fff; text-align: center;
  box-shadow: 0 30px 70px -30px rgba(11,27,51,.55); animation: lkin .1s ease-out; }
@keyframes lkin { from { opacity: 0; } }
#site .lkpop h2 { margin: 0 0 10px; font-size: 1.35rem; }
#site .lkpop p { margin: 0 auto; max-width: 36ch; font-size: 15px; line-height: 1.6; color: var(--k-mu); }
@media (prefers-reduced-motion: reduce) { #site .lkpop-c { animation: none; }  }

/* case study cards on touch screens and phones (James 2026-10-18): there is no hover there,
   so a small "View case study" tag sits in each image's corner all the time; the link under
   the card stays the standard underlined arrow link (a big pill was too heavy) */
@media (hover: none), (max-width: 760px) {
  #site a.fwshot .fwview { opacity: 1; inset: auto 10px 10px auto; background: none; transform: none; }
  #site a.fwshot .fwview b { gap: 6px; padding: 6px 11px; font-size: 13px; transform: none; box-shadow: 0 6px 16px -8px rgba(11,27,51,.45); }
  #site a.fwshot .fwview b .arr { width: 14px; height: 9px; }
}

      
#site .sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }

/* ============================================================
   case studies worth a look - a row of three case study cards
   under the FAQs on service pages with no single matching case
   study (James 2026-10-18). Reuses .fwshot / .fwview from the
   case-studies cards.
   ============================================================ */
#site .csmore { padding: clamp(40px, 4vw, 56px) 0 clamp(56px, 6vw, 88px); }
#site .csm-head { display: flex; align-items: baseline; justify-content: space-between; gap: 16px 32px; flex-wrap: wrap;
  margin-bottom: clamp(24px, 3vw, 36px); }
#site .csm-head h2 { margin: 0; font-size: clamp(1.8rem, 3.4vw, 2.5rem); line-height: 1.08; letter-spacing: -.035em; color: #0B1B33; }
#site .csm-all, #site .csm-go { display: inline-flex; align-items: center; gap: 8px; font-size: 15px; font-weight: 600; color: #0B1B33; text-decoration: none; }
#site .csm-row { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: clamp(20px, 2.6vw, 36px); }
#site .csm-c { display: flex; flex-direction: column; min-width: 0; }
#site .csm-c .fwshot { position: relative; display: block; border-radius: 14px; overflow: hidden; }
#site .csm-c h3 { margin: 22px 0 0; font-size: 1.2rem; line-height: 1.3; letter-spacing: -.02em; }
#site .csm-c h3 a { color: #0B1B33; text-decoration: none; }
#site .csm-c p { margin: 8px 0 0; font-size: 15px; line-height: 1.6; color: #4A5A73; flex: 1; }
#site .csm-go { margin-top: 16px; align-self: flex-start; }
@media (max-width: 900px) {
  #site .csm-row { grid-template-columns: minmax(0, 1fr); gap: 40px; }
}


/* homepage hero workflow mesh, toned down (James 2026-10-19: "too
   distracting"): packets, flying messages and the typing lines all run
   about 1.8x slower, the packet is thinner and its glow fainter */
html.js-anim #site .vzw .p, html.js-anim #site .vzw .pg { animation-duration: calc(var(--d, 4s) * 1.8); animation-delay: calc(var(--dl, 0s) * 1.8); }
#site .vzw .p { stroke-width: 2.2; }
#site .vzw .pg { stroke-width: 6; opacity: .08; }
html.js-anim #site .msg.on { animation-duration: calc(var(--d, 9s) * 1.8); animation-delay: calc(var(--dl, 0s) * 1.8); }
html.js-anim #site .vn em.tty span, html.js-anim #site .vn em.tty span::after { animation-duration: 16s; }
@media (prefers-reduced-motion: reduce) {
  html.js-anim #site .vzw .p, html.js-anim #site .vzw .pg, html.js-anim #site .msg.on, html.js-anim #site .vn em.tty span, html.js-anim #site .vn em.tty span::after { animation: none; }
}
#site .cf-hp { display: none !important; }

/* ============ MOBILE FIXES (2026-10-20) ============ */
/* mobile handoff: on phones and touch screens site.js "dark-to-light
   handoff" gives the "What we do" band .lmode and one class step instead
   of a per-frame scroll scrub (which repainted the whole band and lagged
   even on a fast iPhone). Once the band's top passes 36% of the window it
   gets .lt1 (the dark overlay fades) and .lt2 (the dark seam held at its
   top and the block field fade, the heading colours flip) together, over
   .6s. Opacity only, static masks, so the compositor does the work */
#site .blkband.lmode { isolation: isolate; }
#site .blkband.lmode::before { -webkit-mask-image: none; mask-image: none; opacity: 1; transition: opacity .9s cubic-bezier(.4,0,.2,1); }
#site .blkband.lmode.lt1::before { opacity: 0; }
#site .blkband.lmode.lmode::after { display: block; z-index: -1; opacity: 1; transition: opacity .9s cubic-bezier(.4,0,.2,1);
  background: radial-gradient(ellipse 72% 520px at 50% -200px, rgba(84,131,220,.46), rgba(8,11,22,.93) 96%), var(--graind) #00010A;
  -webkit-mask-image: linear-gradient(to bottom, #000, transparent 280px); mask-image: linear-gradient(to bottom, #000, transparent 280px); }
#site .blkband.lmode.lmode.lt2::after { opacity: 0; }
#site .blkband.lmode .hbk2 { transition: opacity .9s cubic-bezier(.4,0,.2,1);
  -webkit-mask-image: linear-gradient(to bottom, #000 0, rgb(0 0 0 / .6) 280px, transparent 46%);
  mask-image: linear-gradient(to bottom, #000 0, rgb(0 0 0 / .6) 280px, transparent 46%); }
#site .blkband.lmode.lt2 .hbk2 { opacity: 0; }
#site .blkband.lmode h2 { color: #F4F8FF; transition: color .8s cubic-bezier(.4,0,.2,1); }
#site .blkband.lmode .bhead p { color: #A9B8D0; transition: color .8s cubic-bezier(.4,0,.2,1); }
#site .blkband.lmode.lt2 h2 { color: #0B1B33; }
#site .blkband.lmode.lt2 .bhead p { color: #5A6B85; }
@media (prefers-reduced-motion: reduce) {
  #site .blkband.lmode::before, #site .blkband.lmode.lmode::after, #site .blkband.lmode .hbk2,
  #site .blkband.lmode h2, #site .blkband.lmode .bhead p { transition: none; }
}
/* scroll-driven handoff (2026-10-20, James: the class step looked brisk and
   rough on an iPad): on touch screens whose browser has scroll-driven
   animations, site.js gives the band .lsd instead of .lmode and the same
   layers fade with the scroll itself, like the desktop scrub - but as CSS
   animations on a view timeline, opacity only on statically masked layers,
   so the compositor runs them and no script runs per frame. The ranges match
   the desktop scrub: the dark overlay fades while the band's top travels
   from 84% to 12% of the window (cover 16vh to 88vh). The dark seam held at
   its top does not fade (that left a line against the still-dark hero): it
   shrinks up into the seam with a transform, its top pixel always the
   hero's colour, from 33.6% until the band's top reaches the top of the
   window (cover 66.4vh to 100vh), when the hero has gone; the block field
   goes with it. The heading (cover 72vh to 82vh) and its line (58vh to
   72vh) change colour as the ground behind each passes half dark */
#site .blkband.lsd { isolation: isolate; view-timeline: --wwd block; }
#site .blkband.lsd::before { -webkit-mask-image: none; mask-image: none; transition: none; will-change: opacity;
  animation: wwd-out linear both; animation-timeline: --wwd; animation-range: cover 16vh cover 88vh; }
#site .blkband.lsd.lsd::after { display: block; z-index: -1; transition: none; will-change: transform; transform-origin: 50% 0;
  background: radial-gradient(ellipse 72% 520px at 50% -200px, rgba(84,131,220,.46), rgba(8,11,22,.93) 96%), var(--graind) #00010A;
  -webkit-mask-image: linear-gradient(to bottom, #000, transparent 280px); mask-image: linear-gradient(to bottom, #000, transparent 280px);
  animation: wwd-seam linear both; animation-timeline: --wwd; animation-range: cover 66.4vh cover 100vh; }
#site .blkband.lsd .hbk2 { will-change: opacity;
  -webkit-mask-image: linear-gradient(to bottom, #000 0, rgb(0 0 0 / .6) 280px, transparent 46%);
  mask-image: linear-gradient(to bottom, #000 0, rgb(0 0 0 / .6) 280px, transparent 46%);
  animation: wwd-out linear both; animation-timeline: --wwd; animation-range: cover 66.4vh cover 100vh; }
#site .blkband.lsd h2 { transition: none; animation: wwd-h2 linear both; animation-timeline: --wwd; animation-range: cover 72vh cover 82vh; }
#site .blkband.lsd .bhead p { transition: none; animation: wwd-p linear both; animation-timeline: --wwd; animation-range: cover 58vh cover 72vh; }
@keyframes wwd-out { from { opacity: 1; } to { opacity: 0; } }
@keyframes wwd-seam { from { transform: none; } to { transform: scaleY(0); } }
@keyframes wwd-h2 { from { color: #F4F8FF; } to { color: #0B1B33; } }
@keyframes wwd-p { from { color: #A9B8D0; } to { color: #5A6B85; } }
/* the hero mesh stops once the hero is off screen (site.js .hoff) */
html.js-anim #site .heroband.hoff .vzw .p, html.js-anim #site .heroband.hoff .vzw .pg, html.js-anim #site .heroband.hoff .msg.on,
html.js-anim #site .heroband.hoff .vn em.tty span, html.js-anim #site .heroband.hoff .vn em.tty span::after { animation-play-state: paused; }
/* the two looping paint animations (the mesh's wires, the pipeline card's
   pulsing dot) get their own small layers, so each frame repaints only them
   and not the whole page around them */
#site .vzw, #site .gpipe li.on::before { will-change: transform; }
/* no live blur under the scrolled bar on touch screens: re-blurring the
   page behind it every frame is costly on phones; a near-solid bar instead */
@media (hover: none), (max-width: 760px) {
  #site .nv.scrolled { -webkit-backdrop-filter: none; backdrop-filter: none; }
  #site .nv.scrolled:not(.dropen):not(.mmopen) { background: rgba(252,253,255,.97); }
}

/* hero mesh on phones (stacked rows under 560px): the code node's typing
   line was still shown there (em.tty outranked the "em { display: none }"),
   which made "Stock script" taller and pushed its icon and label out of line
   with the two agents; it is hidden like the other second lines, and every
   node's icon and label start at the top so a row lines up (both now up to 760px, with the stacked mesh) */

/* comparison table scroll hint (site.js "comparison tables"): while the
   table overflows its box, the edge with more to see fades (a static mask
   on the scroll box), and a mono "Swipe to see more" line with a drawn
   arrow sits above it until it has been scrolled once */
@property --cmpl { syntax: '<length>'; inherits: false; initial-value: 0px; }
@property --cmpr { syntax: '<length>'; inherits: false; initial-value: 0px; }
#site .cmpwrap.ovx { --cmpl: 0px; --cmpr: 0px; transition: --cmpl .25s ease, --cmpr .25s ease;
  -webkit-mask-image: linear-gradient(to right, transparent, #000 var(--cmpl), #000 calc(100% - var(--cmpr)), transparent);
  mask-image: linear-gradient(to right, transparent, #000 var(--cmpl), #000 calc(100% - var(--cmpr)), transparent); }
#site .cmpwrap.ovx.more-r { --cmpr: 56px; }
#site .cmpwrap.ovx.more-l { --cmpl: 36px; }
#site .cmphint { display: none; }
#site .cmphint.on { display: flex; align-items: center; justify-content: flex-end; gap: 9px; margin: 0 0 12px;
  font-family: 'JetBrains Mono', monospace; font-size: 12.5px; line-height: 1.3; letter-spacing: .04em; text-transform: uppercase;
  color: #45556E; transition: opacity .3s ease; }
#site .cmphint svg { display: block; width: 22px; height: 12px; flex: none; color: var(--cb); }
html.js-anim #site .cmphint.on.go svg { animation: cmpnudge 1.4s ease-in-out .3s 3; }
@keyframes cmpnudge { 0%, 100% { transform: none; } 50% { transform: translateX(5px); } }
#site .cmphint.done { opacity: 0; }
@media (prefers-reduced-motion: reduce) {
  #site .cmpwrap.ovx { transition: none; }
  html.js-anim #site .cmphint.on.go svg { animation: none; }
}

/* footer: text a step larger at every width, and on phones the blurb runs
   the full width of the screen instead of a 34ch column */
#site .fblurb { font-size: 14.5px; }
#site footer ul a, #site .fvb .meta { font-size: 14.5px; }
#site footer .fh { font-size: 14px; }
#site .fbot, #site .fbot ul { font-size: 13.5px; }
@media (max-width: 760px) { #site .fblurb { max-width: none; } }

/* mobile drawer: cover the window to its last pixel (the drawer hangs from
   inside the bar's 1px bottom border, so it fell 1px short and the page
   showed through; the shadow below also covers a toolbar resize on iOS),
   and a legible email line */
@media (max-width: 940px) {
  #site .drawer:not([hidden]) {
    height: calc(100vh - var(--navh, 77px) - var(--shellh, 0px) + 1px);
    height: calc(100dvh - var(--navh, 77px) - var(--shellh, 0px) + 1px);
    overscroll-behavior: contain; box-shadow: 0 80px 0 0 #FCFDFF; }
  #site .nv.ondark:not(.scrolled) .drawer:not([hidden]) { box-shadow: 0 80px 0 0 #070D1B; }
  #site .drawer .dmail { font-size: 15.5px; line-height: 1.5; }
}

/* contact: stacked name and company fields keep the form's 16px rhythm
   (the row gap added to the field margin made it 32px), and the heading
   runs the full width once the page is one column */
@media (max-width: 620px) { #site .frow, #site .co-card .frow { row-gap: 0; } }
@media (max-width: 940px) { #site .co-intro h2 { max-width: none; } }

/* phone menu: a softer shadow under "Get in touch" and more room above
   "Or email" (James 2026-10-20) */
#site .drawer .btn, #site .drawer .btn:hover { padding: 12px 22px; box-shadow: 0 6px 14px -10px rgba(44,95,216,.6); }
#site .drawer .dmail { margin-top: 28px; }
