/* ==========================================================================
   Archerfish Media — shared stylesheet
   Design tokens per the project style guide (final, adopted).
   ========================================================================== */

:root{
  /* color tokens */
  --abyss: #0b2038;
  --trench: #071427;
  --current: #0e6fa6;
  --current-hover: #0b597f;
  --current-active: #083f5b;
  --reef: #0d9488;
  --link-active: #0a5a82;

  /* dedicated CTA/action color — distinct from the brand blue used for links,
     headings and icons, so primary buttons don't blend into the rest of the
     page. Reef becomes an action color, not just a hover accent. */
  --cta: #0d9488;
  --cta-hover: #0b7d72;
  --cta-active: #08635b;
  --cta-ring: #0e6fa6;
  --mist: #f4f8fb;
  --foam: #e8f1f4;
  --white: #ffffff;
  --ink: #1c2b3a;
  --slate: #5c7080;

  /* type */
  --font-head: "Plus Jakarta Sans", -apple-system, "Segoe UI", Roboto, Helvetica Neue, Arial, sans-serif;
  --font-body: "Roboto", -apple-system, "Segoe UI", Helvetica Neue, Arial, sans-serif;

  /* layout */
  --container: 1200px;
  --radius: 12px;
  --shadow: 0 4px 20px rgba(10, 25, 47, 0.06);
}

*, *::before, *::after{ box-sizing: border-box; }
html{ scroll-behavior: smooth; }
body{
  margin: 0;
  font-family: var(--font-body);
  color: var(--ink);
  background: var(--white);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}
img{ max-width: 100%; display: block; }
.container{ max-width: var(--container); margin: 0 auto; padding: 0 24px; }

h1, h2, h3, h4{
  font-family: var(--font-head);
  color: var(--abyss);
  margin: 0 0 16px;
  text-wrap: balance;
}
h1{ font-weight: 800; font-size: clamp(36px, 6vw, 64px); line-height: 1.1; letter-spacing: -1.5px; }
h2{ font-weight: 700; font-size: clamp(28px, 4vw, 48px); line-height: 1.2; letter-spacing: -0.5px; }
h3{ font-weight: 600; font-size: clamp(20px, 2.4vw, 24px); line-height: 1.25; }
p{ margin: 0 0 16px; color: var(--slate); }
.on-dark p, .on-dark h1, .on-dark h2, .on-dark h3{ color: var(--mist); }
.on-dark p{ color: rgba(244, 248, 251, 0.75); }

/* ==========================================================================
   Links
   ========================================================================== */
a{
  color: var(--current);
  text-decoration: none;
  font-weight: 500;
}
a:hover{ color: var(--reef); text-decoration: underline; }
a:active{ color: var(--link-active); text-decoration: underline; }
a:visited{ color: var(--slate); }
a:focus-visible{ outline: 2px solid var(--current); outline-offset: 3px; border-radius: 2px; }

/* ==========================================================================
   Buttons
   ========================================================================== */
.btn{
  display: inline-block;
  font-family: var(--font-body);
  font-weight: 500;
  font-size: 15px;
  color: var(--white) !important;
  background: var(--cta);
  padding: 16px 40px;
  border-radius: var(--radius);
  border: none;
  cursor: pointer;
  text-decoration: none !important;
  transition: background-color .15s ease, transform .15s ease, box-shadow .15s ease;
  box-shadow: 0 1px 2px rgba(3,10,20,.08);
}
.btn:hover{ background: var(--cta-hover); color: var(--white) !important; transform: translateY(-1px); box-shadow: 0 10px 22px -8px rgba(8,99,91,.55); }
.btn:active{ background: var(--cta-active); transform: translateY(1px); box-shadow: none; }
.btn:focus-visible{ outline: 3px solid var(--cta-ring); outline-offset: 2px; }
.btn--sm{ padding: 12px 28px; font-size: 14px; }

/* ==========================================================================
   Header / nav
   ========================================================================== */
.site-header{
  position: sticky;
  top: 0;
  z-index: 50;
  background: var(--white);
}
.site-header .container{
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding-top: 22px;
  padding-bottom: 22px;
  transition: padding-top .32s cubic-bezier(.22,.61,.36,1), padding-bottom .32s cubic-bezier(.22,.61,.36,1);
}
.logo{ display: inline-flex; align-items: center; text-decoration: none !important; }
.logo img{
  height: 44px;
  width: auto;
  display: block;
}

/* The white header area dips into the hero along a curve — lower/deeper at
   the center than at the edges — instead of ending on a flat line. Starts
   exactly at the header's real bottom edge (top: 100%) and extends 30px
   down into the hero, so it rides along automatically as the header's own
   height changes on scroll. */
.header-edge{
  position: absolute;
  left: 0; right: 0;
  top: 100%;
  height: 30px;
  line-height: 0;
  pointer-events: none;
}
.header-edge svg{ display: block; width: 100%; height: 100%; }
.header-edge-fill{ fill: var(--white); }
.header-edge-line{
  fill: none;
  stroke: var(--foam);
  stroke-width: 1.5px;
  vector-effect: non-scaling-stroke;
}

/* The nav bar itself compacts once you've scrolled a little (padding
   tightens from 22px to 12px) — .is-scrolled is toggled in main.js with a
   scroll-position dead zone (grows back only once you've scrolled back up
   near the top) so it can't flicker rapidly back and forth right at a
   single threshold. The logo stays full size (44px) throughout; it just
   stays vertically centered in the shorter box via the flex align-items
   on .container above, rather than shrinking with it. */
.site-header.is-scrolled .container{ padding-top: 12px; padding-bottom: 12px; }
@media (prefers-reduced-motion: reduce){
  .site-header .container, .logo img{ transition: none; }
}

.nav{
  display: flex;
  align-items: center;
  gap: 36px;
}
.nav-links{
  display: flex;
  align-items: center;
  gap: 32px;
  list-style: none;
  margin: 0;
  padding: 0;
}
.nav-links a{
  color: var(--ink);
  font-weight: 500;
  font-size: 15px;
  text-decoration: none;
}
.nav-links a{ position: relative; }
.nav-links a::after{
  content: "";
  position: absolute;
  left: 0; right: 100%;
  bottom: -4px;
  height: 2px;
  background: var(--current);
  transition: right .2s ease;
}
.nav-links a:hover{ color: var(--current); text-decoration: none; }
.nav-links a:hover::after{ right: 0; }

.nav-toggle{
  display: none;
  background: none;
  border: none;
  cursor: pointer;
  padding: 6px;
}
.nav-toggle span{
  display: block;
  width: 24px;
  height: 2px;
  background: var(--abyss);
  margin: 5px 0;
  transition: transform .2s ease, opacity .2s ease;
}

@media (max-width: 860px){
  .nav-toggle{ display: block; }
  .nav{
    position: fixed;
    inset: 68px 0 0 0;
    background: var(--white);
    flex-direction: column;
    align-items: flex-start;
    padding: 24px;
    gap: 24px;
    transform: translateX(100%);
    transition: transform .2s ease;
    border-top: 1px solid var(--foam);
  }
  .nav.is-open{ transform: translateX(0); }
  .nav-links{ flex-direction: column; align-items: flex-start; gap: 18px; }
  .nav .btn{ width: 100%; text-align: center; }
}

/* ==========================================================================
   Section bands
   ========================================================================== */
section{ padding: 88px 0; position: relative; }
@media (max-width: 640px){ section{ padding: 56px 0; } }

.bg-mist{ background: var(--mist); }
.bg-white{ background: var(--white); }
.bg-foam{ background: var(--foam); }
.bg-abyss{ background: var(--abyss); }
.bg-trench{ background: var(--trench); }


.eyebrow{
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 13px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--current);
  margin: 0 0 14px;
}
.on-dark .eyebrow{ color: var(--reef); }

/* ==========================================================================
   Hero — full-bleed photo background, floating photo treatment
   ========================================================================== */
.hero{
  position: relative;
  overflow: hidden;
  padding: 0;
  background-color: var(--abyss);
}
.hero-bg{
  position: absolute;
  inset: 0;
  background-image: url("https://www.archerfishmedia.com/TEST-SERVER/archerfish/wordpress/wp-content/uploads/2026/05/archerfish-media-hero-background-full-size.webp");
  background-size: cover;
  background-position: center 65%;
  transform: scale(1.08); /* headroom so the scroll-driven blur never shows an edge */
  filter: blur(var(--scroll-blur, 0px));
  will-change: filter;
}
@media (prefers-reduced-motion: reduce){
  .hero-bg{ filter: none !important; }
}
.hero-scrim{
  position: absolute;
  inset: 0;
  background:
    linear-gradient(115deg, rgba(7,20,39,.95) 0%, rgba(7,20,39,.82) 38%, rgba(11,32,56,.5) 65%, rgba(11,32,56,.22) 100%),
    linear-gradient(0deg, rgba(7,20,39,.5), transparent 30%);
}
.hero-inner{
  position: relative;
  z-index: 2;
  padding: 128px 0 96px;
}
.hero-grid{
  display: grid;
  grid-template-columns: 1.05fr 1fr;
  gap: 64px;
  align-items: center;
}
@media (max-width: 900px){ .hero-grid{ grid-template-columns: 1fr; } .hero-inner{ padding: 96px 0 76px; } }
.hero-copy p{ max-width: 46ch; font-size: 17px; }
.hero-actions{ display: flex; gap: 16px; flex-wrap: wrap; margin-top: 28px; }

.hero-photo-wrap{ position: relative; padding: 0 8px 44px 30px; }
.hero-photo-blob{
  position: absolute;
  width: 115%; height: 115%;
  top: -8%; left: -12%;
  background: radial-gradient(circle at 32% 28%, rgba(13,148,136,.55), transparent 62%);
  filter: blur(36px);
  z-index: 0;
  pointer-events: none;
}
@media (prefers-reduced-motion: no-preference){
  .hero-photo-blob{ animation: blob-breathe 7s ease-in-out infinite; }
}
@keyframes blob-breathe{
  0%, 100%{ opacity: .85; transform: scale(1); }
  50%{ opacity: 1; transform: scale(1.06); }
}
.hero-photo{
  position: relative;
  z-index: 1;
  /* organic blob crop, restored — border-radius corners are mathematically
     tangent-smooth on their own, so the jagged edge traced back to rotating
     this clipped/overflow:hidden element, which some browsers rasterize the
     clip mask for without full antialiasing. Dropping the rotation (below)
     keeps the same asymmetric silhouette but renders a genuinely clean line. */
  border-radius: 46% 54% 52% 48% / 48% 45% 55% 52%;
  overflow: hidden;
  box-shadow: 0 34px 70px -24px rgba(2,8,18,.65), inset 0 0 0 1.5px rgba(244,248,251,.35);
  aspect-ratio: 4 / 3.4;
}
.hero-photo img{
  width: 100%; height: 100%;
  object-fit: cover;
  display: block;
  /* flipped horizontally so the archerfish's water jet aims left, back toward the headline.
     Source photo has its own soft light vignette fading out at the edges — zoomed in enough
     here to crop past that fade so only the fully-saturated scene shows inside the blob, giving
     one clean, consistent edge instead of the crop line and the photo's own fade fighting each other. */
  transform: scaleX(-1) scale(1.55);
}
.hero-chip{
  position: absolute;
  z-index: 2;
  display: flex;
  align-items: baseline;
  gap: 10px;
  background: rgba(244,248,251,0.12);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  border: 1px solid rgba(244,248,251,0.28);
  border-radius: 16px;
  padding: 16px 22px;
  color: var(--mist);
  box-shadow: 0 22px 44px -18px rgba(2,8,18,.55);
  opacity: 0;
  pointer-events: none;
}
.hero-chip .chip-value{ font-family: var(--font-head); font-weight: 800; font-size: 28px; line-height: 1; }
.hero-chip .chip-label{ font-size: 12px; text-transform: uppercase; letter-spacing: .05em; opacity: .8; max-width: 12ch; }

/* Three stat chips crossfade in and out, taking turns around the photo, on a
   shared 15s loop — each occupies its own third of the cycle, with a short
   gap between so they never overlap. */
.hero-chip--a{ left: -8px; bottom: 0; }
.hero-chip--b{ right: 2px; top: 8%; max-width: 200px; }
.hero-chip--c{ left: -10px; top: 34%; max-width: 190px; }

@media (prefers-reduced-motion: no-preference){
  .hero-chip--a{ animation: stat-chip-a 15s ease-in-out infinite; }
  .hero-chip--b{ animation: stat-chip-b 15s ease-in-out infinite; }
  .hero-chip--c{ animation: stat-chip-c 15s ease-in-out infinite; }
}
@media (prefers-reduced-motion: reduce){
  .hero-chip--a{ opacity: 1; }
  .hero-chip--b, .hero-chip--c{ display: none; }
}
@keyframes stat-chip-a{
  0%, 100%{ opacity: 0; transform: translateY(8px); }
  4%, 26%{ opacity: 1; transform: translateY(0); }
  31%{ opacity: 0; transform: translateY(-8px); }
}
@keyframes stat-chip-b{
  0%, 33%, 100%{ opacity: 0; transform: translateY(8px); }
  37%, 59%{ opacity: 1; transform: translateY(0); }
  64%{ opacity: 0; transform: translateY(-8px); }
}
@keyframes stat-chip-c{
  0%, 67%, 100%{ opacity: 0; transform: translateY(8px); }
  71%, 93%{ opacity: 1; transform: translateY(0); }
  97%{ opacity: 0; transform: translateY(-8px); }
}
@media (max-width: 640px){
  .hero-chip--b{ top: -10px; right: 2px; }
  .hero-chip--c{ top: auto; bottom: -10px; right: 2px; left: auto; }
}

/* wave section divider */
.wave{ position: absolute; left: -2%; width: 104%; line-height: 0; z-index: 3; pointer-events: none; }
.wave--bottom{ bottom: -1px; }
.wave svg{ width: 100%; height: 64px; display: block; }
@media (max-width: 640px){ .wave svg{ height: 34px; } }
@media (prefers-reduced-motion: no-preference){
  .wave svg{ animation: wave-drift 9s ease-in-out infinite; }
}
@keyframes wave-drift{
  0%, 100%{ transform: translateX(0); }
  50%{ transform: translateX(1.5%); }
}

/* ==========================================================================
   Scroll-reveal — progressive enhancement, only when JS ran and motion is fine
   ========================================================================== */
@media (prefers-reduced-motion: no-preference){
  html.js .reveal{
    opacity: 0;
    transform: translateY(24px);
    transition: opacity .65s cubic-bezier(.2,.7,.2,1), transform .65s cubic-bezier(.2,.7,.2,1);
  }
  html.js .reveal.is-visible{ opacity: 1; transform: var(--settle, none); }
  html.js .reveal--load{ transition-delay: .1s; }

  .bento-grid > .reveal:nth-child(1){ transition-delay: 0ms; }
  .bento-grid > .reveal:nth-child(2){ transition-delay: 90ms; }
  .bento-grid > .reveal:nth-child(3){ transition-delay: 160ms; }
  .bento-grid > .reveal:nth-child(4){ transition-delay: 230ms; }
  .bento-grid > .reveal:nth-child(5){ transition-delay: 300ms; }

  .testimonial-grid > .reveal:nth-child(1){ transition-delay: 0ms; }
  .testimonial-grid > .reveal:nth-child(2){ transition-delay: 110ms; }
  .testimonial-grid > .reveal:nth-child(3){ transition-delay: 220ms; }

  .metrics-grid > .reveal:nth-child(1){ transition-delay: 0ms; }
  .metrics-grid > .reveal:nth-child(2){ transition-delay: 100ms; }
  .metrics-grid > .reveal:nth-child(3){ transition-delay: 200ms; }
}

/* ==========================================================================
   Services overview — staggered with the hero (hero: copy left / photo right;
   this section flips it: light target visual left / copy right)
   ========================================================================== */
/* overflow-x (not full overflow:hidden) so the fish's off-screen slide-in
   below doesn't push the page's horizontal scroll width, while anything
   that needs vertical breathing room in this section stays uncropped. */
.overview{ overflow-x: hidden; }
.overview-grid{
  display: grid;
  grid-template-columns: 0.85fr 1.15fr;
  align-items: center;
  gap: 40px;
}
.overview-copy{ grid-column: 2; grid-row: 1; }
.overview-visual{
  grid-column: 1;
  grid-row: 1;
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 260px;
}
@media (max-width: 860px){
  .overview-grid{ grid-template-columns: 1fr; gap: 8px; }
  .overview-copy{ grid-column: 1; grid-row: 1; }
  .overview-visual{ display: none; }
}

/* ==========================================================================
   Precision-targeting graphic — a scoped bullseye with a water stream that
   draws in and lands as the section scrolls into view (--target-progress,
   set in main.js). Echoes the archerfish's own trick and the headline's
   "Targeted to Your Customers." The scroll sequence now has two acts: the
   fish itself slides in from off-screen first (progress 0 → 0.22), then the
   water stream/impact sequence plays out (remapped to fill the remaining
   0.22 → 1 as --stream-progress, so it always finishes by the same scroll
   point the old single-phase version did).
   ========================================================================== */
.target-visual-frame{ position: relative; width: 232px; height: 232px; }
@media (max-width: 1080px){ .target-visual-frame{ width: 192px; height: 192px; } }
.target-graphic{ position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }

/* Stream/impact choreography runs on this instead of --target-progress
   directly, rescaled to start only once the fish has finished sliding in.
   Defined on the whole section (not just .overview-visual) so the headline
   copy — a sibling, not a descendant, of the visual — can also read it. */
.overview{ --stream-progress: max(0, min(1, calc((var(--target-progress, 0) - 0.22) / 0.78))); }

/* The archerfish itself — your own homepage illustration, cropped tight to
   just the fish. Anchored by its mouth tip (not its center) via a matching
   transform-origin, so it sits right at the stream's origin point and, once
   rotated to aim more toward the target, pivots around that same point
   rather than swinging away from where the water needs to start. It sits
   above the SVG in paint order so the stream visually emerges from behind
   its mouth. */
.target-fish-slide{
  position: absolute;
  left: 4.6%;
  top: 91.5%;
  width: 58%;
  aspect-ratio: 429 / 229;
  z-index: 2;
  transform-origin: 99.8% 31.9%;
  transform: translate(-99.8%, -31.9%) rotate(-20deg);
  pointer-events: none;
}
@media (max-width: 1080px){ .target-fish-slide{ width: 52%; } }
.target-fish-slide img{ width: 100%; height: 100%; display: block; }

/* Motion-safe visitors get the entrance: the fish slides in from off-screen
   left as the section scrolls into view; the rotation stays fixed at -20deg
   throughout so it doesn't also spin while it travels. Reduced-motion
   visitors get the base rule above only — fish already in its resting spot. */
@media (prefers-reduced-motion: no-preference){
  .target-fish-slide{
    transform: translate(-99.8%, -31.9%) rotate(-20deg) translateX(calc((1 - min(1, var(--target-progress, 0) / 0.22)) * -100vw));
  }
}

.target-ring{ transform-origin: 130px 130px; }

/* gentle ambient life even before the visitor scrolls */
@media (prefers-reduced-motion: no-preference){
  .target-ring:nth-of-type(3){ animation: target-ring-breathe 4.5s ease-in-out infinite; }
}
@keyframes target-ring-breathe{
  0%, 100%{ opacity: .55; }
  50%{ opacity: .32; }
}

/* Bubbles standing in for the old crosshair ticks — reuses the hero's own
   particle-float keyframe so the motion language matches site-wide. */
.target-bubble:nth-of-type(1){ animation-delay: 0s; }
.target-bubble:nth-of-type(2){ animation-delay: 1.6s; }
.target-bubble:nth-of-type(3){ animation-delay: .8s; }
.target-bubble:nth-of-type(4){ animation-delay: 2.4s; }
@media (prefers-reduced-motion: no-preference){
  .target-bubble{ animation: particle-float 6s ease-in-out infinite; }
}

/* Continuous ripple pulses from the bullseye, independent of the scroll-linked
   landing sequence below — ambient life, same precedent as the ring breathe. */
.target-ripple{ transform-origin: 130px 130px; opacity: 0; }
@media (prefers-reduced-motion: no-preference){
  .target-ripple{ animation: target-ripple-pulse 3.2s ease-out infinite; }
  .target-ripple--b{ animation-delay: 1.6s; }
}
@keyframes target-ripple-pulse{
  0%{ transform: scale(.72); opacity: .45; }
  100%{ transform: scale(1.85); opacity: 0; }
}

/* Base state = the "settled" look (stream fully drawn, impact landed). This is
   what a prefers-reduced-motion visitor sees, full stop — nothing below this
   block depends on --target-progress. */
.stream-droplet{ opacity: .85; }
.stream-lead{
  offset-path: path('M12,238 Q71,195 130,130');
  offset-distance: 100%;
  offset-rotate: 0deg;
  opacity: .9;
}
.target-impact{
  transform-origin: 130px 130px;
  transform: scale(1);
  opacity: .5;
}
.target-dot{
  transform-origin: 130px 130px;
  transform: scale(1.15);
  transition: transform .2s ease-out;
}

/* Motion-safe visitors get the scroll-linked version instead: once the fish
   has slid into place, the stream draws in and the lead droplet travels the
   arc as --stream-progress (derived from --target-progress above) goes
   0 → 1, landing with a small flare. */
@media (prefers-reduced-motion: no-preference){
  .stream-droplet--1{ opacity: calc(max(0, min(var(--stream-progress, 0), 0.15) - 0)     * 5.667); }
  .stream-droplet--2{ opacity: calc(max(0, min(var(--stream-progress, 0), 0.27) - 0.12)  * 5.667); }
  .stream-droplet--3{ opacity: calc(max(0, min(var(--stream-progress, 0), 0.39) - 0.24)  * 5.667); }
  .stream-droplet--4{ opacity: calc(max(0, min(var(--stream-progress, 0), 0.51) - 0.36)  * 5.667); }
  .stream-droplet--5{ opacity: calc(max(0, min(var(--stream-progress, 0), 0.63) - 0.48)  * 5.667); }
  .stream-droplet--6{ opacity: calc(max(0, min(var(--stream-progress, 0), 0.75) - 0.60)  * 5.667); }
  .stream-lead{
    offset-distance: calc(var(--stream-progress, 0) * 100%);
    opacity: calc(min(var(--stream-progress, 0), 0.08) * 12);
  }
  .target-impact{
    transform: scale(calc(0.55 + max(0, var(--stream-progress, 0) - 0.86) * 7));
    opacity: calc(max(0, var(--stream-progress, 0) - 0.86) * 7);
  }
  .target-dot{ transform: scale(calc(1 + max(0, var(--stream-progress, 0) - 0.86) * 0.85)); }

  /* Headline eases in steadily across the whole stream sequence (starting as
     soon as the fish has slid into place) rather than snapping in during a
     narrow window, but is still timed to finish exactly on --stream-progress
     reaching 1 — the same instant the impact flare fully lands — so the two
     read as connected without the color-in itself feeling rushed. Starts as
     a muted, unfinished-looking grey and resolves to the h2's real color
     (var(--abyss), same as every other heading on the site). color-mix()
     degrades safely: unsupported browsers just keep the plain var(--abyss)
     color already set by the sitewide h1–h4 rule. */
  .overview-copy .section-head h2{
    color: color-mix(in srgb, var(--abyss) calc(var(--stream-progress, 0) * 100%), #9aa4af);
  }
}

/* ==========================================================================
   Stat strip (inline, within services-overview section)
   ========================================================================== */
.stat-strip{
  display: flex;
  gap: 48px;
  flex-wrap: wrap;
  margin-top: 40px;
  padding-top: 32px;
  border-top: 1px solid var(--foam);
}
.stat-item{ display: flex; align-items: flex-start; gap: 14px; }
.stat-icon{
  flex-shrink: 0;
  width: 40px; height: 40px;
  border-radius: 10px;
  background: var(--foam);
  color: var(--current);
  display: flex; align-items: center; justify-content: center;
}
.stat-icon svg{ width: 20px; height: 20px; }
.stat-strip .stat-value{
  position: relative;
  /* Without this, the ::before glow's z-index:-1 has no local stacking
     context to stay contained in — .stat-value sits inside several
     ancestors that are all z-index:auto/no-stacking-context, so the
     negative z-index escapes all the way to the document root and paints
     behind the entire page (including this very section's own white
     background) instead of just behind this number. Same stacking-context
     gotcha as the Core Capabilities card glow elsewhere on the site, fixed
     the same way there. */
  isolation: isolate;
  font-family: var(--font-head);
  font-weight: 800;
  font-size: 40px;
  color: var(--current);
  line-height: 1;
  margin-bottom: 6px;
}
.stat-strip .stat-label{ font-size: 14px; color: var(--slate); max-width: 20ch; }

/* A soft back-glow behind each number, lighting up the same instant the
   water-stream's droplet lands on the target graphic beside it (and the
   counters themselves start counting) — see .is-landed, toggled once in
   main.js off the same trigger the impact flare and headline color-in
   already use. Ties the landing moment to these two numbers visually, not
   just by timing. Permanent once triggered, matching the counters
   themselves (which don't reset if you scroll back up either). */
.stat-strip .stat-value::before{
  content: "";
  position: absolute;
  inset: -16px -20px;
  z-index: -1;
  border-radius: 16px;
  background: radial-gradient(65% 65% at 30% 45%,
    color-mix(in srgb, var(--current) 30%, transparent) 0%, transparent 72%);
  opacity: 0;
  transform: scale(.82);
  transition: opacity .6s ease, transform .6s ease;
  pointer-events: none;
}
.stat-strip.is-landed .stat-value::before{
  opacity: 1;
  transform: scale(1);
}
@media (prefers-reduced-motion: reduce){
  /* No scroll-linked landing moment for these visitors (see main.js), so
     the glow is simply always on rather than never appearing. */
  .stat-strip .stat-value::before{ opacity: 1; transform: scale(1); }
}

/* ==========================================================================
   How We Can Help — subtle water-surface pattern, faint center / stronger edges
   ========================================================================== */
/* Wave height the texture's clip-path (set in main.js) is drawn to match —
   keep in sync with the fixed heights other .wave svg elements on the page use. */
.services-help{ --wave-h: 64px; }
@media (max-width: 640px){ .services-help{ --wave-h: 34px; } }

.services-help .water-pattern{
  position: absolute;
  /* No JS = no bleed, flat top (same as the section's own edge) — safe default.
     Once main.js confirms it can compute + apply the matching clip-path, html.js
     below lets this bleed up above the section's own top edge by --wave-h, so
     the wavy cap is the literal same texture/tone as the section body, not a
     second, separately-rendered approximation that can never quite match. */
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 0;
  pointer-events: none;
  /* The actual cause of the horizontal seam: .services-help's own foam
     background-color (bg-foam) only fills the SECTION's own box — it does
     not extend into the bled area above it, since that's a child element
     rendered outside its parent's box. So the translucent texture below
     this line was compositing over foam (its intended backdrop), while the
     bled portion above the section's real top edge was compositing over
     whatever sits behind it instead (the previous section's white) — a
     genuine, structural hard edge exactly at the section's top edge, not
     just a matter of intensity or hue.

     Giving this element its own foam backing fixes that IN THEORY — except
     opacity applies to an element and everything painted inside it as one
     group, so putting opacity here would have made the new foam backing
     translucent too, letting the same white-vs-foam inconsistency bleed
     right back through. So the backing lives here at full strength, and
     the opacity + mask (which should only affect the texture, not what's
     behind it) move to the svg child below instead — the clipped wave
     shape, bled portion and section body alike, now always has a fully
     opaque foam base, with only the texture layered semi-transparently on
     top of that constant base. */
  background-color: var(--foam);
}
.services-help .water-pattern svg{
  display: block; width: 100%; height: 100%;
  opacity: .35;
  /* rx/ry = 50% means the ellipse's radius exactly reaches every edge midpoint
     (top/bottom/left/right) at the 100% distance mark. The wavy cap (above
     the section's real top edge, via the bleed) sits only ~64px into that
     radius, so it always lands in the highest-alpha part of the mask —
     spreading the stops out (70%→65%, 92%→99%) fixed the hard seam, but the
     cap still hit close to full mask strength while the body around the
     heading sits much fainter (diluted almost to the plain foam color).
     Blue + teal composited via feBlend "screen" reads distinctly GREEN at
     full strength (screen(#0e6fa6,#0d9488) ≈ a cyan-green) but reads pale
     blue once heavily diluted by the white/foam page background at low
     alpha — so the cap and the body weren't just different intensities of
     the same color, they read as different HUES. Capping the mask's opaque
     stop at 55% alpha (instead of solid black = 100%) caps how strong the
     texture can get anywhere, including at the cap, so it never gets
     saturated enough to read as green — same color recipe throughout. */
  -webkit-mask-image: radial-gradient(50% 50% at 50% 50%, transparent 65%, rgba(0,0,0,.55) 99%);
  mask-image: radial-gradient(50% 50% at 50% 50%, transparent 65%, rgba(0,0,0,.55) 99%);
}
html.js .services-help .water-pattern{ top: calc(-1 * var(--wave-h)); }
.services-help > .container{ position: relative; z-index: 1; }

/* ==========================================================================
   Cards — services
   ========================================================================== */
.section-head{ max-width: 640px; margin: 0 0 48px; }
.section-head p{ text-wrap: balance; }

/* asymmetric bento grid — one featured card, four supporting */
.bento-grid{
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-auto-rows: minmax(160px, auto);
  grid-auto-flow: dense;
  gap: 20px;
  align-items: stretch;
}
@media (max-width: 900px){ .bento-grid{ grid-template-columns: repeat(2, 1fr); grid-auto-rows: minmax(180px, auto); } }
@media (max-width: 600px){ .bento-grid{ grid-template-columns: 1fr; grid-auto-rows: auto; } }

.service-card{
  position: relative;
  background: var(--white);
  border-radius: 20px;
  box-shadow: var(--shadow);
  padding: 30px;
  display: flex;
  flex-direction: column;
  transition: transform .18s ease, box-shadow .18s ease;
}
.service-card:hover{ transform: translateY(-3px); box-shadow: 0 14px 32px -12px rgba(10,25,47,.16); }

/* "How We Can Help" — a very light, sequential edge-highlight as the grid
   first scrolls into view: each card's outline briefly brightens, one
   after another in order, then eases back to normal (see main.js's
   edgeLightObserver). A separate ::after overlay rather than touching
   box-shadow directly, so it never fights the hover lift/shadow above or
   the featured card's own background. Deliberately slow + low-opacity —
   "barely noticeable" was the ask. */
.bento-grid .service-card::after{
  content: "";
  position: absolute;
  inset: -1px;
  border-radius: inherit;
  box-shadow: 0 0 0 1px transparent;
  opacity: 0;
  pointer-events: none;
  transition: opacity 1.1s ease, box-shadow 1.1s ease;
}
.bento-grid .service-card.is-edge-lit::after{
  opacity: 1;
  box-shadow:
    0 0 0 1px color-mix(in srgb, var(--current) 32%, transparent),
    0 0 26px -6px color-mix(in srgb, var(--current) 26%, transparent);
}
.service-card.featured{
  grid-column: span 2;
  grid-row: span 2;
  background: linear-gradient(155deg, var(--abyss) 0%, #0f3f63 100%);
  color: var(--mist);
  justify-content: flex-end;
  position: relative;
  overflow: hidden;
  /* Extra breathing room on the sides beyond the base card's 30px, since
     this card runs noticeably wider than the others (spans 2 columns). */
  padding-left: 44px;
  padding-right: 44px;
}
.service-card.featured::before{
  content: "";
  position: absolute; inset: 0;
  background: radial-gradient(circle at 85% -10%, rgba(13,148,136,.4), transparent 55%);
}
.service-card.featured h3, .service-card.featured p{ position: relative; }
.service-card.featured h3{ color: var(--mist); font-size: clamp(22px,2.6vw,28px); }
.service-card.featured p{ color: rgba(244,248,251,.78); }
.service-card.featured .service-icon{ background: rgba(244,248,251,.14); position: relative; }
.service-card.featured .service-icon svg{ stroke: var(--mist); }

/* Three supporting highlights under the featured card's paragraph — fills
   part of the card's previously-empty lower area with real, scannable copy
   rather than just visual filler. */
.featured-highlights{ list-style: none; margin: 0 0 6px; padding: 0; display: flex; flex-direction: column; gap: 12px; position: relative; }
.featured-highlights li{ position: relative; padding-left: 28px; font-size: 14.5px; line-height: 1.4; color: rgba(244,248,251,.85); }
.featured-highlights li::before{
  content: "✓";
  position: absolute; left: 0; top: 0;
  width: 18px; height: 18px; line-height: 18px; text-align: center;
  border-radius: 50%;
  background: rgba(244,248,251,.14);
  color: #7fd9cf;
  font-size: 11px; font-weight: 700;
}

/* Closing line under the checklist — sums the card up and works in the
   "how" (AI-assisted development + modern tooling) behind the "what" above. */
.featured-summary{
  margin: 16px 0 0;
  padding-top: 16px;
  border-top: 1px solid rgba(244,248,251,.16);
  font-size: 14px;
  line-height: 1.5;
  color: rgba(244,248,251,.82);
}
@media (max-width: 900px){ .service-card.featured{ grid-column: span 2; grid-row: span 1; } }
@media (max-width: 600px){
  .service-card.featured{ grid-column: span 1; padding-left: 30px; padding-right: 30px; }
}

.service-icon{
  width: 44px; height: 44px;
  border-radius: 10px;
  background: var(--mist);
  display: flex; align-items: center; justify-content: center;
  margin-bottom: 20px;
  flex-shrink: 0;
}
.service-icon svg{ width: 22px; height: 22px; stroke: var(--current); }
.service-card h3{ margin-bottom: 8px; }
.service-card p{ font-size: 14.5px; margin-bottom: 12px; }
.service-card .learn-more{ font-size: 14px; font-weight: 600; margin-top: auto; display: inline-block; transition: transform .18s ease; }
.service-card .learn-more:hover{ transform: translateX(3px); }

/* ==========================================================================
   Testimonials
   ========================================================================== */
.testimonial-grid{
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  /* start (not the grid default, stretch) so a card with more content —
     the Cape Beach Dog traffic chart below — can be taller without forcing
     the other two cards to stretch and match it. */
  align-items: start;
  gap: 24px;
}
@media (max-width: 900px){ .testimonial-grid{ grid-template-columns: 1fr; } }
.testimonial-card{
  position: relative;
  background: var(--white);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 32px;
  transition: transform .2s ease, box-shadow .2s ease;
}
.testimonial-card:hover{
  transform: var(--settle, translateY(0)) translateY(-4px);
  box-shadow: 0 20px 40px -16px rgba(10,25,47,.2);
}
/* Sequential edge-highlight sweep (see main.js's setupEdgeLightSweep) —
   same ::after-overlay technique as the bento grid above, kept separate
   from box-shadow so it never fights the hover lift/shadow just above. */
.testimonial-card::after{
  content: "";
  position: absolute;
  inset: -1px;
  border-radius: inherit;
  box-shadow: 0 0 0 1px transparent;
  opacity: 0;
  pointer-events: none;
  transition: opacity 1.1s ease, box-shadow 1.1s ease;
}
.testimonial-card.is-edge-lit::after{
  opacity: 1;
  box-shadow:
    0 0 0 1px color-mix(in srgb, var(--current) 32%, transparent),
    0 0 26px -6px color-mix(in srgb, var(--current) 26%, transparent);
}
.testimonial-card .stars{ color: var(--reef); letter-spacing: 2px; margin-bottom: 16px; font-size: 14px; }
.testimonial-card blockquote{
  margin: 0 0 20px;
  font-family: var(--font-head);
  font-weight: 600;
  font-size: 18px;
  color: var(--ink);
  line-height: 1.4;
}
.testimonial-card .attribution{ font-size: 13.5px; color: var(--slate); }
.testimonial-card .attribution b{ display: block; color: var(--ink); font-weight: 600; }

/* Real Google Analytics chart backing the Cape Beach Dog stat — this card
   runs taller than its neighbors as a result (see align-items: start on
   .testimonial-grid, above, so the other two cards don't stretch to match). */
.testimonial-chart{ margin-top: 22px; padding-top: 20px; border-top: 1px solid var(--foam); }
.testimonial-chart img{ display: block; width: 72%; max-width: 240px; height: auto; margin: 0 auto; border-radius: 8px; border: 1px solid var(--foam); }

/* Real key stat pulled from each case study, called out above the quote —
   turns a plain testimonial into a small case-study card backed by an
   actual number, not just praise. */
.testimonial-stat{
  display: inline-flex; align-items: baseline; gap: 7px;
  background: var(--foam); border-radius: 999px; padding: 6px 14px 6px 12px;
  margin-bottom: 18px;
}
.testimonial-stat-value{ font-family: var(--font-head); font-weight: 800; font-size: 16px; color: var(--current); }
.testimonial-stat-label{ font-size: 12.5px; font-weight: 600; color: var(--link-active); }

/* The client's real logo alongside the attribution. Logos are horizontal
   wordmarks, not square icons — sized by height with width left free
   (object-fit: contain, no crop) rather than forced into a square, so the
   actual logo shape shows instead of being clipped into a small tile. */
.testimonial-footer{ display: flex; align-items: center; gap: 12px; }
.testimonial-thumb{ display: flex; align-items: center; height: 28px; max-width: 108px; flex-shrink: 0; }
.testimonial-thumb img{ display: block; height: 100%; width: auto; max-width: 108px; object-fit: contain; object-position: left center; }
/* middle card as the focal point — slightly elevated and bolder shadow.
   Stored as --settle so the scroll-reveal entrance (below) can compose with
   it instead of clobbering it once the card is done animating in. */
.testimonial-card{ transform: var(--settle, none); }
.testimonial-grid > .testimonial-card:nth-child(2){
  --settle: translateY(-14px);
  box-shadow: 0 20px 44px -16px rgba(10,25,47,.18);
}
.testimonial-grid > .testimonial-card:nth-child(1){ --settle: rotate(-1deg); }
.testimonial-grid > .testimonial-card:nth-child(3){ --settle: rotate(1deg); }
@media (max-width: 900px){
  .testimonial-grid > .testimonial-card{ --settle: translateY(0); }
}

/* ==========================================================================
   Metrics band
   ========================================================================== */
.metrics-band{ overflow: hidden; }
.metrics-band > .container{ position: relative; z-index: 1; }

.metrics-grid{
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 32px;
  text-align: center;
}
@media (max-width: 640px){ .metrics-grid{ grid-template-columns: 1fr; gap: 40px; } }
.metric .metric-value{
  font-family: var(--font-head);
  font-weight: 800;
  font-size: clamp(36px, 5vw, 56px);
  color: var(--mist);
  line-height: 1;
  margin-bottom: 10px;
}
.metric .metric-label{ font-size: 14px; color: rgba(244,248,251,.7); text-transform: uppercase; letter-spacing: .05em; }

/* ==========================================================================
   CTA band — full-bleed archerfish photo with gradient scrim
   ========================================================================== */
.cta-band{
  text-align: center;
  background-image: url("https://www.archerfishmedia.com/TEST-SERVER/archerfish/wordpress/wp-content/uploads/2026/06/Archerfish_shooting_water_at_bug2.jpg");
  background-size: cover;
  background-position: center;
  padding: 112px 0;
  overflow: hidden;
}
.cta-band::before{
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  background: linear-gradient(180deg, rgba(7,20,39,.88) 0%, rgba(11,32,56,.93) 100%);
}
.cta-band > .container{ position: relative; z-index: 1; }
.cta-band .section-head{ margin-left: auto; margin-right: auto; }
.cta-band p{ margin-left: auto; margin-right: auto; }

/* ==========================================================================
   Footer — photo texture with Trench gradient overlay
   ========================================================================== */
.site-footer{
  padding: 0;
  background-image: url("https://www.archerfishmedia.com/TEST-SERVER/archerfish/wordpress/wp-content/uploads/2026/06/footer-background-1600.webp");
  background-size: cover;
  background-position: center;
  position: relative;
}
.site-footer::before{
  content: "";
  position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(7,20,39,.9), rgba(7,20,39,.97));
}
.site-footer > .container{ position: relative; z-index: 1; padding-top: 56px; padding-bottom: 32px; }
.footer-top{
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 32px;
  flex-wrap: wrap;
  padding-bottom: 32px;
  border-bottom: 1px solid rgba(244,248,251,0.12);
}
.footer-brand .logo img{ height: 26px; }
.footer-brand p{ max-width: 34ch; margin-top: 12px; font-size: 14px; }
.footer-links{ display: flex; gap: 28px; list-style: none; margin: 0; padding: 0; }
.footer-links a{ color: rgba(244,248,251,.8); font-size: 14px; font-weight: 500; }
.footer-links a:hover{ color: var(--reef); }
.footer-bottom{
  padding-top: 24px;
  font-size: 13px;
  color: rgba(244,248,251,.55);
}

/* ==========================================================================
   Services page — hero: procedural "underwater light rays" treatment.
   No real underwater/light-ray photo exists in the site's media library
   (checked the live media inventory), so this is built the same way the
   "How We Can Help" water texture was: layered, brand-toned SVG/CSS rather
   than a stock photo — vibrant near the surface, darkening with depth, with
   a vignette that keeps the copy reading forward of the effect, not lost in
   it. Swap in a real photo later by replacing .hero-depths' background.
   ========================================================================== */
.hero--services .hero-inner{ padding: 148px 0 120px; }
.hero-copy--center{ max-width: 760px; margin: 0 auto; text-align: center; }
.hero-copy--center p{ margin-left: auto; margin-right: auto; }
.hero-copy--center .hero-actions{ justify-content: center; }
.hero-copy--center .eyebrow{ display: block; }
/* Reef teal (the default on-dark eyebrow color) reads too close to the
   underwater background's own teal/blue tones here — low contrast, hard to
   read. White instead, since nothing in this hero's palette competes with it. */
.hero--services .eyebrow{ color: var(--mist); }

/* Depth gradient: brighter, teal-lit near the top where light enters,
   settling into Abyss/Trench by the bottom — the core "depth" cue. */
.hero-depths{
  position: absolute; inset: 0; z-index: 0;
  background:
    radial-gradient(120% 85% at 50% -12%, rgba(98,196,229,.5), transparent 58%),
    linear-gradient(180deg, #1a5077 0%, #0f3f63 28%, var(--abyss) 60%, var(--trench) 100%);
}

/* God-rays: tapered beams fanning down from a point above the frame,
   screened for glow, softly blurred. Drifts very slowly; still under
   prefers-reduced-motion. */
.hero-rays{
  position: absolute; inset: 0; z-index: 1;
  width: 100%; height: 100%;
  mix-blend-mode: screen;
  opacity: .6;
  pointer-events: none;
}
@media (prefers-reduced-motion: no-preference){
  .hero-rays{ animation: rays-drift 14s ease-in-out infinite; }
}
@keyframes rays-drift{
  0%, 100%{ transform: translateX(0) rotate(0deg); }
  50%{ transform: translateX(1.2%) rotate(.4deg); }
}

/* Caustic shimmer near the surface — reuses the exact feTurbulence recipe
   proven out on "How We Can Help" (Current + Reef, screened), just brighter
   and confined to the hero's own box (no cross-section bleed, so none of
   that section's seam risk applies here). */
.hero-caustics{
  position: absolute; inset: 0; z-index: 1;
  pointer-events: none;
  opacity: .3;
  -webkit-mask-image: linear-gradient(180deg, #000 0%, transparent 65%);
  mask-image: linear-gradient(180deg, #000 0%, transparent 65%);
}
.hero-caustics svg{ display: block; width: 100%; height: 100%; }

/* Floating particulate — a handful of soft bokeh points at varied depth
   (size/blur/opacity) so the water reads as volumetric, not flat. */
.hero-particles{ position: absolute; inset: 0; z-index: 1; pointer-events: none; overflow: hidden; }
.hero-particle{
  position: absolute;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(244,248,251,.9), rgba(244,248,251,0) 70%);
  filter: blur(1px);
}
@media (prefers-reduced-motion: no-preference){
  .hero-particle{ animation: particle-float 10s ease-in-out infinite; }
}
@keyframes particle-float{
  0%, 100%{ transform: translateY(0); }
  50%{ transform: translateY(-14px); }
}

/* Vignette: darkens toward the lower-center where the copy sits, so the
   headline reads forward of the effect instead of competing with it, while
   the corners stay brighter/vibrant. */
.hero--services .hero-scrim{
  background:
    radial-gradient(60% 55% at 50% 62%, rgba(7,20,39,.6), transparent 75%),
    linear-gradient(180deg, rgba(7,20,39,.12) 0%, rgba(7,20,39,.42) 68%, rgba(7,20,39,.7) 100%);
}
.hero--services .hero-inner{ position: relative; z-index: 2; }

/* ==========================================================================
   Services page — Core capabilities (4 even pillars, plain 2×2 — unlike
   Home's bento, none of these should visually dominate the others)
   ========================================================================== */
/* isolation: isolate keeps this section's own internal layering (texture,
   per-card glows) self-contained and not fighting anything outside it. The
   hero-to-section seam above is no longer handled here at all — see the
   hero's own .wave--bottom markup in the HTML, which now paints this same
   texture itself rather than trying to have this section bleed upward past
   its own top edge into the hero's territory (that approach never actually
   painted on top: a section positioned with z-index:auto, like the hero,
   still keeps its own positioned descendants — like its wave, at explicit
   z-index:3 — winning paint order against a later sibling section
   regardless of that sibling's own higher z-index). */
.capabilities{ --wave-h: 64px; position: relative; z-index: 5; isolation: isolate; }
@media (max-width: 640px){ .capabilities{ --wave-h: 34px; } }
.capabilities > .container{ position: relative; z-index: 1; }

/* Faint caustic texture bleeding behind the whole grid — reuses the hero's
   feTurbulence recipe, self-contained within this section (no bleed past
   its own box, so none of the "How We Can Help" seam considerations apply
   here) and kept very low-opacity so it reads as ambient depth, not noise. */
.capability-texture{
  position: absolute; inset: 0; z-index: 0; pointer-events: none;
  opacity: .24;
}
/* Lighten + soften the texture right as the tile block below sits centered
   in the viewport (see updateCapabilityFocus in main.js, which drives
   --capability-focus from 0 up to 1 and back down to 0 as you scroll through
   the section), so the content gets a subtle moment of extra focus rather
   than competing with a static, equally-sharp backdrop the whole time.
   Kept deliberately small — 3px of blur and a touch of added brightness at
   peak — and off entirely for reduced-motion, where the texture just stays
   at its normal resting look. */
.capability-texture svg{
  display: block; width: 100%; height: 100%;
  filter: blur(calc(var(--capability-focus, 0) * 3px)) brightness(calc(1 + var(--capability-focus, 0) * .35));
  will-change: filter;
}

@media (prefers-reduced-motion: reduce){
  .capability-texture svg{ filter: none !important; }
}

.capability-grid{
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 20px;
}
@media (max-width: 640px){ .capability-grid{ grid-template-columns: 1fr; } }

/* Per-card accent color — reuses the existing 2-hue (Current/Reef) system
   plus the existing --link-active token rather than introducing new hues,
   so the grid stays inside the ocean palette while each card reads as its
   own pillar. --cro sits tonally between Current and Reef. */
.service-card--web{ --card-accent: var(--current); }
.service-card--seo{ --card-accent: var(--reef); }
.service-card--cro{ --card-accent: #0d8297; }
.service-card--brand{ --card-accent: var(--link-active); }

/* Icon badges: flat mist squares → soft circular gradient badges, to match
   the hero's added vibrancy. */
.capability-grid .service-icon{
  width: 52px; height: 52px;
  border-radius: 50%;
  background: radial-gradient(120% 120% at 30% 20%,
    color-mix(in srgb, var(--card-accent, var(--current)) 55%, white 20%) 0%,
    color-mix(in srgb, var(--card-accent, var(--current)) 92%, black 12%) 100%);
  box-shadow: 0 10px 22px -10px color-mix(in srgb, var(--card-accent, var(--current)) 65%, transparent);
}
.capability-grid .service-icon svg{ width: 24px; height: 24px; stroke: var(--mist); }

/* Hover: a light lift plus a soft glow in the card's own accent color —
   deliberately toned down from an earlier, punchier pass (smaller lift, a
   lower color-mix percentage, and a softer/lower-opacity shadow) so it reads
   as a gentle acknowledgement rather than a strong pop, especially now that
   each card already carries its own resting glow/border (see below). */
.capability-grid .service-card{ position: relative; }
.capability-grid .service-card:hover{
  transform: translateY(-3px);
  box-shadow:
    0 16px 32px -20px color-mix(in srgb, var(--card-accent, var(--current)) 28%, transparent),
    0 10px 22px -14px rgba(10,25,47,.10);
}

/* Sequential edge-highlight sweep (see main.js's setupEdgeLightSweep) — the
   same one-shot, in-order effect used on Home, applied here in each card's
   own --card-accent color instead of one fixed hue, so it reads as part of
   this grid's existing per-card color system. A ::after overlay (::before
   is already the resting "framed" glow above) so it layers independently
   of both that glow and the hover state. */
.capability-grid .service-card::after{
  content: "";
  position: absolute;
  inset: -1px;
  border-radius: inherit;
  box-shadow: 0 0 0 1px transparent;
  opacity: 0;
  pointer-events: none;
  transition: opacity 1.1s ease, box-shadow 1.1s ease;
}
.capability-grid .service-card.is-edge-lit::after{
  opacity: 1;
  box-shadow:
    0 0 0 1px color-mix(in srgb, var(--card-accent, var(--current)) 38%, transparent),
    0 0 26px -6px color-mix(in srgb, var(--card-accent, var(--current)) 32%, transparent);
}

/* "Framed" look for each box against the now-more-visible water texture
   behind the grid: a soft accent-colored glow bleeding out from behind each
   card (painted via a negative-inset, negative-z-index pseudo so it hides
   under the card's own opaque white background and only shows past the
   card's edges, into the gaps/texture) plus a thin gradient-tinted border —
   both driven by the same --card-accent token each card already sets, so
   every box reads as "held" in its own color without new hues or a new
   background image. Stays solid white/readable — only the edges pick up
   color, the dense tag-pill content inside is untouched. */
.capability-grid .service-card{
  border: 1px solid transparent;
  background:
    linear-gradient(var(--white), var(--white)) padding-box,
    linear-gradient(155deg,
      color-mix(in srgb, var(--card-accent, var(--current)) 45%, transparent) 0%,
      color-mix(in srgb, var(--card-accent, var(--current)) 6%, transparent) 55%) border-box;
}
.capability-grid .service-card::before{
  content: "";
  position: absolute;
  inset: -16px;
  z-index: -1;
  border-radius: 30px;
  background: radial-gradient(120% 120% at 25% 15%,
    color-mix(in srgb, var(--card-accent, var(--current)) 40%, transparent) 0%,
    transparent 70%);
  opacity: .6;
  pointer-events: none;
}
/* On hover only: the lift above uses `transform`, and `transform` makes the
   card establish its own local stacking context — which changes where this
   ::before glow paints. At rest (no transform, no new stacking context) it
   escapes to the section's context and stays tucked behind every card's
   opaque background, only peeking out past the edges into the gaps. On
   hover it instead becomes scoped to the card's own (newly-created) context,
   painting as a wash directly on the card's own background, under the text
   — much more visible than intended, dark enough to fight the copy's
   contrast. Rather than reworking the lift to avoid ever creating that
   context, this specifically lightens the glow only while it's in that
   more-visible position, so hover still gives a soft acknowledgement
   without darkening the text on top of it. */
.capability-grid .service-card:hover::before{
  opacity: .2;
  background: radial-gradient(120% 120% at 25% 15%,
    color-mix(in srgb, var(--card-accent, var(--current)) 22%, transparent) 0%,
    transparent 70%);
}

.capability-tags{ display: flex; flex-wrap: wrap; gap: 8px; margin-top: auto; padding-top: 4px; }
.capability-tags span{
  font-size: 12px; font-weight: 600; color: var(--current);
  background: var(--mist); border-radius: 999px; padding: 5px 12px;
}
.capability-grid .service-card--web .capability-tags span{ color: var(--card-accent); }
.capability-grid .service-card--seo .capability-tags span{ color: var(--card-accent); }
.capability-grid .service-card--cro .capability-tags span{ color: var(--card-accent); }
.capability-grid .service-card--brand .capability-tags span{ color: var(--card-accent); }

/* ==========================================================================
   Services page — The Archerfish Workflow (3 steps, connected)
   ========================================================================== */
#workflow{ scroll-margin-top: 100px; overflow: hidden; }
.workflow-glow{
  position: absolute; left: 50%; top: 40%; z-index: 0; pointer-events: none;
  width: 640px; height: 640px; transform: translate(-50%, -50%);
  background: radial-gradient(circle, rgba(13,148,136,.22), transparent 68%);
}
.workflow .container{ position: relative; z-index: 1; }
.workflow .section-head{ max-width: 640px; margin-left: auto; margin-right: auto; text-align: center; }

.workflow-steps{
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 32px;
  position: relative;
  margin-top: 24px;
  margin-bottom: 40px;
}
/* connecting line through the three circles, desktop only */
.workflow-steps::before{
  content: "";
  position: absolute;
  top: 23px; left: calc(100% / 6); right: calc(100% / 6);
  height: 1.5px;
  background: rgba(244,248,251,.18);
}
.workflow-step{ position: relative; text-align: center; }
.workflow-step .step-num{
  width: 46px; height: 46px; margin: 0 auto 20px;
  border-radius: 50%;
  background: var(--cta);
  color: var(--white);
  font-family: var(--font-head); font-weight: 800; font-size: 17px;
  display: flex; align-items: center; justify-content: center;
  position: relative; z-index: 1;
  box-shadow: 0 0 0 6px var(--abyss);
}
.workflow-step h3{ font-size: 19px; }
.workflow-step p{ font-size: 14.5px; max-width: 30ch; margin: 0 auto; }

@media (max-width: 760px){
  .workflow-steps{ grid-template-columns: 1fr; gap: 36px; text-align: left; }
  .workflow-steps::before{ top: 0; bottom: 0; left: 22px; right: auto; width: 1.5px; height: auto; }
  .workflow-step{ text-align: left; padding-left: 64px; }
  .workflow-step .step-num{ position: absolute; left: 0; top: 0; margin: 0; }
  .workflow-step p{ margin: 0; }
}

/* ==========================================================================
   Services page — FAQ (native <details>, no JS required)
   ========================================================================== */
.faq-list{ max-width: 760px; margin: 0 auto; display: flex; flex-direction: column; gap: 14px; }
.faq-item{
  background: var(--white);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 6px 26px;
}
.faq-item summary{
  list-style: none;
  cursor: pointer;
  padding: 20px 0;
  display: flex; align-items: center; justify-content: space-between; gap: 20px;
  font-family: var(--font-head); font-weight: 600; font-size: 16.5px; color: var(--ink);
}
.faq-item summary::-webkit-details-marker{ display: none; }
.faq-item summary:focus-visible{ outline: 2px solid var(--current); outline-offset: 4px; border-radius: 4px; }
.faq-chevron{
  flex-shrink: 0;
  width: 20px; height: 20px;
  border-radius: 50%;
  background: var(--mist);
  display: flex; align-items: center; justify-content: center;
  transition: transform .2s ease, background-color .2s ease;
}
.faq-chevron svg{ width: 11px; height: 11px; stroke: var(--current); }
.faq-item[open] .faq-chevron{ transform: rotate(180deg); background: var(--foam); }
.faq-answer{ padding: 0 0 22px; margin-top: -6px; }
.faq-answer p{ margin: 0; font-size: 14.5px; }
.faq-answer p + p{ margin-top: 10px; }
@media (prefers-reduced-motion: no-preference){
  .faq-item summary{ transition: color .15s ease; }
  .faq-item summary:hover{ color: var(--current); }
}

/* ==========================================================================
   Services page — Discovery call (doubles as the CTA band; also establishes
   the shared form-field styling Contact will reuse for its larger form)
   ========================================================================== */
.discovery-grid{
  display: grid;
  grid-template-columns: 1fr 0.9fr;
  gap: 56px;
  align-items: center;
}
@media (max-width: 900px){ .discovery-grid{ grid-template-columns: 1fr; gap: 40px; } }
.discovery-copy .featured-highlights{ margin-top: 28px; }

.discovery-form-card{
  background: var(--white);
  border-radius: var(--radius);
  box-shadow: 0 24px 60px -20px rgba(2,8,18,.5);
  padding: 32px;
}
.discovery-form-card h3{ color: var(--ink); font-size: 18px; margin-bottom: 4px; }
.discovery-form-card .form-note{ color: var(--slate); font-size: 13.5px; margin-bottom: 20px; }

.form-field{ margin-bottom: 16px; }
.form-field label{
  display: block; font-size: 13px; font-weight: 600; color: var(--ink);
  margin-bottom: 6px;
}
.form-input{
  width: 100%;
  font-family: var(--font-body);
  font-size: 15px;
  color: var(--ink);
  background: var(--mist);
  border: 1.5px solid transparent;
  border-radius: 10px;
  padding: 13px 14px;
  transition: border-color .15s ease, background-color .15s ease;
}
.form-input::placeholder{ color: var(--slate); opacity: .7; }
.form-input:hover{ background: var(--foam); }
.form-input:focus{ outline: none; border-color: var(--current); background: var(--white); }
.form-input:focus-visible{ outline: none; }
.discovery-form-card .btn{ width: 100%; text-align: center; margin-top: 4px; }

/* ==========================================================================
   About page — hero: a deliberately different procedural treatment from
   Services' hero. Same underwater family (feTurbulence caustics, brand
   tones, a vignette that keeps copy forward), but darker/stiller and with
   no god-rays — "deep, still water" rather than "sunlit surface," to match
   a page about roots and time instead of one driving toward an action
   below the fold. Slow-rising bubbles stand in for the drifting particles.
   ========================================================================== */
.hero--about .hero-inner{ padding: 148px 0 120px; }
.hero--about .eyebrow{ color: var(--mist); }

.hero--about .hero-depths{
  position: absolute; inset: 0; z-index: 0;
  background:
    radial-gradient(130% 70% at 50% -18%, rgba(63,127,163,.28), transparent 60%),
    linear-gradient(180deg, #12324f 0%, var(--abyss) 48%, var(--trench) 100%);
}
/* Second, distinct light-ray recipe: warm/golden rather than Services'
   cyan, an asymmetric single-shaft composition (weighted left, via the
   polygon x-coordinates in the HTML) rather than a centered fan, lower
   opacity, and a slower drift — light reaching down into deep water,
   rather than Services' bright near-surface glare. */
.hero-rays--about{
  position: absolute; inset: 0; z-index: 1;
  width: 100%; height: 100%;
  mix-blend-mode: screen;
  opacity: .75;
  pointer-events: none;
}
@media (prefers-reduced-motion: no-preference){
  .hero-rays--about{ animation: rays-drift-about 20s ease-in-out infinite; }
}
@keyframes rays-drift-about{
  0%, 100%{ transform: translateX(0) rotate(0deg); }
  50%{ transform: translateX(-1.4%) rotate(-.35deg); }
}

.hero--about .hero-caustics{
  position: absolute; inset: 0; z-index: 1;
  pointer-events: none;
  opacity: .22;
  -webkit-mask-image: linear-gradient(180deg, #000 0%, transparent 70%);
  mask-image: linear-gradient(180deg, #000 0%, transparent 70%);
}
.hero--about .hero-caustics svg{ display: block; width: 100%; height: 100%; }

.hero-bubbles{ position: absolute; inset: 0; z-index: 1; pointer-events: none; overflow: hidden; }
.hero-bubble{
  position: absolute;
  border-radius: 50%;
  background: radial-gradient(circle at 35% 30%, rgba(244,248,251,.85), rgba(244,248,251,.15) 70%, transparent);
  opacity: .5;
}
@media (prefers-reduced-motion: no-preference){
  .hero-bubble{ animation: bubble-rise linear infinite; }
}
@keyframes bubble-rise{
  0%{ transform: translateY(0); opacity: 0; }
  10%{ opacity: .55; }
  90%{ opacity: .35; }
  100%{ transform: translateY(-620px); opacity: 0; }
}

.hero--about .hero-scrim{
  background:
    radial-gradient(58% 55% at 50% 60%, rgba(7,20,39,.55), transparent 75%),
    linear-gradient(180deg, rgba(7,20,39,.18) 0%, rgba(7,20,39,.4) 68%, rgba(7,20,39,.68) 100%);
}
.hero--about .hero-inner{ position: relative; z-index: 2; }

/* ==========================================================================
   About page — Our Story. Founding date + flagship numbers folded into real
   prose rather than a second animated stats band (Home's metrics band
   already owns that). The two-date rail encodes something actually true
   (two real dates on a real timeline), not a decorative marker.
   ========================================================================== */
.origin-story{ scroll-margin-top: 90px; }
.origin-grid{
  display: grid;
  grid-template-columns: 90px 1fr;
  gap: 40px;
  max-width: 820px;
  margin: 0 auto;
}
@media (max-width: 760px){
  .origin-grid{ grid-template-columns: 1fr; }
  .origin-timeline{ flex-direction: row !important; height: auto !important; margin-bottom: 28px; }
  .origin-line{ width: auto !important; height: 2px !important; min-height: 0 !important; margin: 0 14px !important; }
}
.origin-timeline{
  display: flex; flex-direction: column; align-items: center;
  padding-top: 6px;
}
.origin-line{
  flex: 1; width: 2px; min-height: 120px; margin: 12px 0;
  background: linear-gradient(var(--current), var(--reef));
  border-radius: 2px;
}
.origin-year{
  font-family: var(--font-head); font-weight: 800; font-size: 13.5px;
  color: var(--current); white-space: nowrap;
}
.origin-year--end{ color: var(--reef); }
.origin-copy p{ font-size: 16px; color: var(--slate); margin-bottom: 16px; max-width: 62ch; }
.origin-copy p:last-child{ margin-bottom: 0; }
.origin-copy strong{ color: var(--ink); font-weight: 700; }

/* ==========================================================================
   About page — Why "Archerfish." New section; explains the precision
   metaphor Services' Workflow copy already leans on without spelling out.
   Side-by-side layout: a real photo (kept per your earlier photo-realism
   call) in its own card, with a purpose-built diagram drawn over it —
   illustrating the refraction "illusion" vs. the corrected shot the copy
   describes — next to the actual copy.
   ========================================================================== */
.archerfish-name{ overflow: hidden; }
.archerfish-grid{
  display: grid;
  grid-template-columns: 1.05fr 1fr;
  align-items: center;
  gap: 56px;
}
@media (max-width: 900px){ .archerfish-grid{ grid-template-columns: 1fr; gap: 36px; } }

.archerfish-copy{ max-width: 62ch; }
.archerfish-copy p{ color: rgba(244,248,251,.82); max-width: 62ch; }
.archerfish-copy p + p{ margin-top: 14px; }
.archerfish-copy--centered{ max-width: 700px; margin: 0 auto; text-align: center; }
.archerfish-copy--centered p{ margin-left: auto; margin-right: auto; }
.archerfish-copy--centered .eyebrow{ display: block; }

/* The photo card — bigger and more deliberate than the old full-width
   banner, with a premium glow frame so it reads as a considered piece of
   the layout rather than a background image. */
.archerfish-photo-card{
  position: relative;
  aspect-ratio: 4 / 3;
  border-radius: 20px;
  overflow: hidden;
  background: var(--trench);
  box-shadow: 0 30px 70px -24px rgba(0,0,0,.55);
}
.archerfish-photo-card::after{
  content: "";
  position: absolute; inset: -1px;
  border-radius: inherit;
  box-shadow: 0 0 0 1px rgba(255,255,255,.08), 0 0 46px -6px color-mix(in srgb, var(--reef) 45%, transparent);
  pointer-events: none;
}
.archerfish-photo{
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; object-position: 50% 38%;
  display: block;
  transform: scale(1.04);
}
/* A very slow ambient drift — barely perceptible, just enough to keep the
   card from feeling like a static screenshot. Off entirely for reduced
   motion, same as every other ambient loop on the site. */
@media (prefers-reduced-motion: no-preference){
  .archerfish-photo{ animation: archerfish-photo-drift 24s ease-in-out infinite alternate; }
}
@keyframes archerfish-photo-drift{
  0%{ transform: scale(1.04) translate(0, 0); }
  100%{ transform: scale(1.1) translate(-1.2%, -1%); }
}
.archerfish-photo-scrim{
  position: absolute; inset: 0;
  background:
    linear-gradient(180deg, rgba(7,20,39,.05) 0%, rgba(7,20,39,.25) 55%, rgba(7,20,39,.6) 100%),
    linear-gradient(90deg, rgba(7,20,39,.35) 0%, rgba(7,20,39,0) 35%);
}
.archerfish-diagram{ position: absolute; inset: 0; width: 100%; height: 100%; color: rgba(244,248,251,.7); }

/* The correction — same beaded-stream + impact-flare technique as Home's
   target graphic, new geometry. Base rule = the settled/landed look, which
   is what reduced-motion visitors see, full stop — beads are transient
   (only meaningful mid-animation) so they stay hidden here; the lead
   droplet + impact flare + dot are what represent the "landed" state. */
.af-bead{ opacity: 0; }
.af-lead{
  offset-path: path('M129.1,160.1 Q232.1,103.2 335,60');
  offset-distance: 100%;
  opacity: .95;
}
.af-impact{ transform-origin: 335px 60px; transform: scale(1); opacity: .55; }
.af-dot{ transform-origin: 335px 60px; transform: scale(1.15); }

@media (prefers-reduced-motion: no-preference){
  .af-bead, .af-lead, .af-impact, .af-dot{
    opacity: 0;
  }

  /* Each bead is a brief pulse (fade in, then back out) centered on its own
     point in the scroll range, with a small gap to its neighbors — so only
     one is ever on screen at a time, chasing along the path, rather than
     accumulating into a static dotted trail that's still there once the
     shot lands. All six are fully faded out well before the impact flare
     begins, so by the time the animation completes only the target shows. */
  .af-bead--1{ opacity: calc(min(clamp(0, (var(--af-progress, 0) - 0.275) / 0.045, 1), clamp(0, (0.365 - var(--af-progress, 0)) / 0.045, 1)) * .9); }
  .af-bead--2{ opacity: calc(min(clamp(0, (var(--af-progress, 0) - 0.375) / 0.045, 1), clamp(0, (0.465 - var(--af-progress, 0)) / 0.045, 1)) * .9); }
  .af-bead--3{ opacity: calc(min(clamp(0, (var(--af-progress, 0) - 0.475) / 0.045, 1), clamp(0, (0.565 - var(--af-progress, 0)) / 0.045, 1)) * .9); }
  .af-bead--4{ opacity: calc(min(clamp(0, (var(--af-progress, 0) - 0.575) / 0.045, 1), clamp(0, (0.665 - var(--af-progress, 0)) / 0.045, 1)) * .9); }
  .af-bead--5{ opacity: calc(min(clamp(0, (var(--af-progress, 0) - 0.675) / 0.045, 1), clamp(0, (0.765 - var(--af-progress, 0)) / 0.045, 1)) * .9); }
  .af-bead--6{ opacity: calc(min(clamp(0, (var(--af-progress, 0) - 0.775) / 0.045, 1), clamp(0, (0.865 - var(--af-progress, 0)) / 0.045, 1)) * .9); }
  .af-lead{
    offset-distance: calc(clamp(0, (var(--af-progress, 0) - 0.28) / 0.62, 1) * 100%);
    opacity: calc(clamp(0, (var(--af-progress, 0) - 0.28) / 0.06, 1) * .95);
  }
  .af-impact{
    transform: scale(calc(0.55 + clamp(0, (var(--af-progress, 0) - 0.9) / 0.1, 1) * 4));
    opacity: calc(clamp(0, (var(--af-progress, 0) - 0.9) / 0.1, 1) * .55);
  }
  .af-dot{
    transform: scale(calc(1 + clamp(0, (var(--af-progress, 0) - 0.9) / 0.1, 1) * .85));
    opacity: calc(clamp(0, (var(--af-progress, 0) - 0.9) / 0.1, 1));
  }
}

/* ==========================================================================
   About page — What We Believe. Same shape as the old 5-value grid, new
   copy. A stacked icon+text list (not boxed cards) so this page reads as
   its own thing next to Services' Core Capabilities grid.
   ========================================================================== */
.beliefs-list{
  display: flex; flex-direction: column;
  max-width: 640px; margin: 0 auto;
}
.belief-item{
  display: flex; gap: 22px; align-items: flex-start;
  padding: 28px 0;
  border-bottom: 1px solid rgba(11,32,56,.1);
}
.belief-copy{ flex: 1 1 auto; min-width: 0; }
.belief-item:last-child{ border-bottom: none; padding-bottom: 4px; }
.belief-icon{
  position: relative;
  width: 44px; height: 44px; border-radius: 50%; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  background: color-mix(in srgb, var(--current) 12%, white);
  color: var(--current);
  transition: transform .5s ease;
}
.belief-icon svg{ width: 20px; height: 20px; }
.belief-icon--reef{ background: color-mix(in srgb, var(--reef) 14%, white); color: var(--reef); }

/* Each belief's icon badge picks up a soft, brief glow ring the first time
   that item scrolls into view — one at a time, at the reader's own scroll
   pace (see main.js), rather than a fixed stagger across the whole list,
   since this is read one item at a time rather than taken in at a glance
   like a grid. Uses currentColor so the ring automatically matches
   whichever accent (Current blue or Reef teal) that item's icon already
   uses, with no extra per-item class needed. */
.belief-icon::after{
  content: "";
  position: absolute;
  inset: -6px;
  border-radius: 50%;
  box-shadow: 0 0 0 1px transparent;
  opacity: 0;
  pointer-events: none;
  transition: opacity 1s ease, box-shadow 1s ease;
}
.belief-item.is-active .belief-icon{ transform: scale(1.06); }
.belief-item.is-active .belief-icon::after{
  opacity: 1;
  box-shadow:
    0 0 0 1px color-mix(in srgb, currentColor 45%, transparent),
    0 0 22px -4px color-mix(in srgb, currentColor 40%, transparent);
}
.belief-copy h3{
  font-family: var(--font-head); font-weight: 700; font-size: 16.5px;
  color: var(--ink); margin: 0 0 6px;
}
.belief-copy p{ font-size: 14.5px; color: var(--slate); margin: 0; max-width: 52ch; }

/* ==========================================================================
   Contact page — built from scratch (the live page's form has no working
   backend, a placeholder phone number, and an unrelated stock photo — none
   of it worth porting). Hero reuses the shared underwater-rays recipe
   (.hero-depths/.hero-rays/.hero-caustics/.hero-particles/.hero-scrim are
   already page-agnostic base classes — only the SVGs' own gradient/filter
   ids and shapes differ per page), angled so the rays converge toward the
   form card sitting in the hero's upper right, per your direction to keep
   this in the same family as Services/About rather than invent a fourth
   distinct treatment.
   ========================================================================== */
.hero--contact{
  /* Overrides the base .hero's overflow:hidden — the form card is meant to
     hang slightly below the hero's own bottom edge into the next section.
     z-index + isolation is the same fix used for Core Capabilities' wave
     cap: this section's own wave--bottom sits at z-index:3, and without an
     explicit stacking context here that 3 would otherwise beat this
     section's default painting order against the *next* section too. */
  overflow: visible;
  z-index: 5;
  isolation: isolate;
}
.hero--contact .hero-inner{
  z-index: 4; /* above this hero's own wave (3), inside the isolated context above */
  padding: 108px 0 56px;
}
/* .hero-grid's default align-items:center vertically centers both columns
   within the row — harmless when both columns are similar height, but the
   row height here is dictated by the card (via hero-form-col's own
   align-self:start + negative margin), so centering the copy against that
   put its exact vertical position at the mercy of how the headline
   happened to wrap at a given viewport width. At some widths that pushed
   the subhead's last line down far enough to sit under the hero's own
   wave — which dips down toward the middle of its curve — clipping it.
   Anchoring the copy to the top too makes its position predictable
   (always right under the top padding) regardless of row height. */
.hero--contact .hero-copy{ align-self: start; }
/* The base .wave is deliberately oversized (104% wide, -2% left) as a
   rendering-safety margin that normally gets trimmed by the hero's own
   overflow:hidden. This hero needs overflow:visible instead (see above),
   which was letting that 2% oversize leak past the real viewport edge and
   add a horizontal scrollbar to the whole page — the only element actually
   found overflowing when this was measured. Sized back to exactly 100%
   here, since there's no clipping left to rely on. */
.hero--contact .wave--bottom{ left: 0; width: 100%; }
/* That same 100%-with-no-buffer sizing has a side effect the base .wave
   never has to worry about: the base .wave svg also drifts slightly via
   the wave-drift animation (translateX up to 1.5%), which is exactly what
   the 104%/-2% oversize on every other hero is there to absorb — the
   drifting SVG is still fully covered by the wave's own oversized box, so
   nothing behind it is ever exposed. Here, with the buffer removed, that
   same drift slides the SVG right and uncovers a sliver of the hero's own
   dark background at the left edge for part of every cycle (worse, given
   this hero's overflow:visible, the SVG also pushes past the right edge at
   the same moment, which is its own latent horizontal-overflow risk). This
   hero can't have it both ways — a moving wave needs slack on both sides to
   move into, and slack here means exposing either a gap or an overflow — so
   the safest fix is to just not move it: freeze this one wave in its
   resting position instead of trying to buffer a drift this section can't
   safely absorb. */
.hero--contact .wave--bottom svg{ animation: none; transform: none; }
@media (max-width: 900px){ .hero--contact .hero-inner{ padding: 96px 0 48px; } }
.hero--contact .eyebrow{ color: var(--mist); } /* same contrast fix as Services/About */

.hero-form-col{ position: relative; align-self: start; margin-bottom: -132px; }
/* The card now hangs deep enough into the next section that the section's
   own default top padding (88px, same as every other section) isn't
   enough clearance — its heading was sitting underneath the card's own
   bottom edge. Padded out specifically here rather than raising the base
   `section` padding site-wide. */
#next{ padding-top: 172px; }
@media (max-width: 900px){ #next{ padding-top: 88px; } } /* card doesn't hang past the hero once stacked — no extra clearance needed */
@media (max-width: 900px){
  .hero-form-col{ margin-bottom: 0; }
  /* The card no longer hangs below the hero once the grid stacks to one
     column, so there's no need for the escape hatch that makes that
     possible — restore the base .hero's normal clipping. Without this,
     the glow's negative insets below (sized for the wide gap next to the
     card in the two-column layout) instead bleed past the now-full-width
     column and blow out the page's horizontal scroll. */
  .hero--contact{ overflow: hidden; }
  .hero-card-glow{ inset: 0; height: 100%; }
}

/* Soft screened glow behind the card — reinforces "the light is landing
   here" without needing the rays themselves to be pixel-perfect. */
.hero-card-glow{
  position: absolute; z-index: 0; pointer-events: none;
  /* Bleeds left/up into the dark background next to the card, where the
     effect actually reads. Deliberately NOT bled out to the right — that
     side sits close to the container's outer edge, and a wide right-side
     bleed here was overflowing the viewport horizontally at exactly the
     margin the container has left to give it (confirmed via scrollWidth
     vs. innerWidth at several viewport sizes; fixed by keeping the right
     inset small instead of matching the left/top bleed). */
  inset: -16% 0 auto -24%; height: 145%;
  background: radial-gradient(62% 62% at 68% 20%, rgba(234,246,255,.85), transparent 72%);
  filter: blur(30px);
  mix-blend-mode: screen;
}

.contact-form-card{
  position: relative; z-index: 1;
  background: var(--white);
  border-radius: var(--radius);
  box-shadow: 0 30px 74px -22px rgba(2,8,18,.55);
  padding: 24px 26px 22px;
}
.contact-form-card h2{ color: var(--ink); font-size: 17px; margin-bottom: 3px; }
.contact-form-card .form-note{ color: var(--slate); font-size: 13px; margin-bottom: 14px; }
.contact-form-card .btn{ width: 100%; text-align: center; margin-top: 2px; }
/* Condensed field spacing + a 2-up row layout (Name/Email, then
   Company/What-do-you-need) so the card is meaningfully shorter than one
   field per line — per your call that a shorter hero mattered more than
   keeping the card fully contained above the fold. */
.contact-form-card .form-field{ margin-bottom: 12px; }
.form-row{ display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.form-row .form-field{ margin-bottom: 0; }
.form-row + .form-field, .form-field + .form-row{ margin-top: 12px; }
@media (max-width: 480px){ .form-row{ grid-template-columns: 1fr; gap: 12px; } }

/* "What do you need?" — a multi-select checkbox group styled as toggle pills
   (reuses the .capability-tags pill language elsewhere on the site) instead
   of a single-choice <select>, since a visitor's needs are rarely just one
   thing. A <fieldset>/<legend> pairing, not a <label>, since there's no
   longer one control for a label to point at — styled to match the existing
   field-label look so the swap doesn't read as a different component. */
.checkbox-fieldset{ border: none; margin: 0; padding: 0; }
.checkbox-fieldset legend{
  display: block; font-size: 13px; font-weight: 600; color: var(--ink);
  margin-bottom: 8px; padding: 0; width: 100%;
}
.checkbox-group{ display: flex; flex-wrap: wrap; gap: 8px; }
.checkbox-pill{ position: relative; display: inline-flex; cursor: pointer; }
.checkbox-pill input{
  position: absolute; inset: 0; width: 100%; height: 100%;
  margin: 0; opacity: 0; cursor: pointer;
}
.checkbox-pill span{
  display: inline-flex; align-items: center;
  font-size: 13.5px; color: var(--ink); background: var(--mist);
  border: 1.5px solid transparent; border-radius: 999px; padding: 9px 16px;
  transition: background-color .15s ease, border-color .15s ease, color .15s ease;
}
.checkbox-pill input:hover + span{ background: var(--foam); }
.checkbox-pill input:focus-visible + span{ outline: 2px solid var(--current); outline-offset: 2px; }
.checkbox-pill input:checked + span{ background: var(--current); border-color: var(--current); color: #fff; }

/* Honeypot: positioned off-screen (not display:none/visibility:hidden,
   which some bots specifically check for and skip) so it's invisible and
   unreachable to real visitors, but still a real, fillable input to a bot
   that blindly fills every field on the page. */
.hp-field{ position: absolute; left: -9999px; top: -9999px; width: 1px; height: 1px; overflow: hidden; margin: 0; }

/* Inline success/error message shown after a contact-form submit (see
   main.js's fetch handler in contact-handler.php's setup). Hidden by
   default via the [hidden] attribute until JS has something to say. */
.form-status{
  margin: 0 0 16px;
  padding: 12px 14px;
  border-radius: 10px;
  font-size: .92rem;
  font-weight: 600;
}
.form-status--ok{ background: color-mix(in srgb, var(--reef) 12%, var(--white)); color: var(--reef); }
.form-status--error{ background: color-mix(in srgb, #C0392B 10%, var(--white)); color: #C0392B; }

/* .form-field/.form-input already exist (built generically for Services'
   Discovery form); these add the select/textarea variants Contact needs. */
select.form-input{
  appearance: none; -webkit-appearance: none; -moz-appearance: none;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%235C7080' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'><path d='M6 9l6 6 6-6'/></svg>");
  background-repeat: no-repeat;
  background-position: right 14px center;
  background-size: 13px;
  padding-right: 38px;
  cursor: pointer;
}
select.form-input:invalid{ color: var(--slate); }
.contact-form-card .form-input{ padding: 11px 13px; }
textarea.form-input{ resize: vertical; min-height: 72px; line-height: 1.5; }

/* ---------- What Happens After You Hit Send — a light-background variant
   of Services' numbered Workflow steps (same connected-circle structure;
   the ring color just needs to match this section's white background
   instead of Workflow's dark one, so it's its own small class set rather
   than a literal reuse). ---------- */
.next-steps{
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 32px;
  position: relative; margin-top: 24px;
}
/* "Connect the dots": a faint dashed line sits between the 3 numbers at
   rest; as the section scrolls into view, a solid line in the same color
   as the numbers themselves grows left→right over it (--connect-progress,
   0→1, computed in main.js off the section's own scroll position), and
   each number picks up a brief glow ring right as the fill reaches it
   (--num-lit per number, ramped rather than a hard on/off snap, so it
   reads as the line *reaching* that dot rather than an unrelated flicker).
   Both lines share the exact same left/right insets (100%/6 from each
   edge) as the 3 evenly-spaced column centers below, so the fill's 0/50/100%
   points land exactly on dot 1/2/3. */
.next-steps::before{
  content: ""; position: absolute; top: 23px; left: calc(100% / 6); right: calc(100% / 6);
  height: 0; border-top: 1.5px dashed rgba(11,32,56,.2);
}
.next-steps::after{
  content: ""; position: absolute; top: 23px; left: calc(100% / 6);
  height: 1.5px; width: calc((100% - (100% / 6) * 2) * var(--connect-progress, 0));
  background: var(--cta);
  pointer-events: none;
}
.next-step{ position: relative; text-align: center; }
/* Extra clearance before the case-study proof-point below, so it reads as
   its own separate moment rather than a fourth step tacked onto the 1/2/3. */
.next-steps + .proof-point{ margin-top: 88px; }
.next-step .step-num{
  position: relative;
  width: 46px; height: 46px; margin: 0 auto 20px;
  border-radius: 50%;
  background: var(--cta);
  color: var(--white);
  font-family: var(--font-head); font-weight: 800; font-size: 17px;
  display: flex; align-items: center; justify-content: center;
  z-index: 1;
  box-shadow: 0 0 0 6px var(--white);
  transform: scale(calc(1 + var(--num-lit, 0) * .08));
}
.next-step .step-num::after{
  content: "";
  position: absolute;
  inset: -6px;
  border-radius: 50%;
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--cta) 55%, transparent),
    0 0 20px -2px color-mix(in srgb, var(--cta) 55%, transparent);
  opacity: var(--num-lit, 0);
  pointer-events: none;
}
.next-step h3{ font-size: 17px; margin-bottom: 6px; }
.next-step p{ font-size: 14px; color: var(--slate); max-width: 30ch; margin: 0 auto; }
@media (max-width: 760px){
  .next-steps{ grid-template-columns: 1fr; gap: 36px; text-align: left; }
  .next-steps::before{
    top: 0; bottom: 0; left: 22px; right: auto; width: 0; height: auto;
    border-top: none; border-left: 1.5px dashed rgba(11,32,56,.2);
  }
  .next-steps::after{
    top: 0; left: 22px; width: 1.5px;
    height: calc((100% - (100% / 6) * 2) * var(--connect-progress, 0));
  }
  .next-step{ text-align: left; padding-left: 64px; }
  .next-step .step-num{ position: absolute; left: 0; top: 0; margin: 0; }
  .next-step p{ margin: 0; }
}
@media (prefers-reduced-motion: reduce){
  .next-steps::after{ width: 100%; }
  @media (max-width: 760px){ .next-steps::after{ width: 1.5px; height: 100%; } }
  .next-step .step-num::after{ opacity: 1; }
}

/* ==========================================================================
   Case Studies page
   ========================================================================== */
.case-spotlight-section{ position: relative; overflow: hidden; padding-bottom: 88px; }
.case-spotlight{
  display: grid;
  grid-template-columns: 1.1fr 1fr;
  gap: 56px;
  align-items: center;
}
.case-spotlight--reverse .case-copy{ order: 2; }
.case-spotlight--reverse .case-visual{ order: 1; }
@media (max-width: 860px){
  .case-spotlight{ grid-template-columns: 1fr; gap: 32px; }
  .case-spotlight--reverse .case-copy{ order: 1; }
  .case-spotlight--reverse .case-visual{ order: 2; }
}

.case-copy .eyebrow{ margin-bottom: 10px; }
.case-copy .case-stat{ margin-bottom: 18px; }
.case-copy .stars{ color: var(--reef); letter-spacing: 2px; margin-bottom: 16px; font-size: 15px; }
.case-copy blockquote{
  margin: 0 0 20px;
  font-family: var(--font-head);
  font-weight: 700;
  font-size: 26px;
  color: var(--ink);
  line-height: 1.35;
  max-width: 20ch;
}
.case-copy .attribution{ font-size: 14.5px; color: var(--slate); }
.case-copy .attribution b{ display: block; color: var(--ink); font-weight: 700; font-size: 15.5px; margin-bottom: 2px; }

.case-visual{ display: flex; justify-content: center; }
.case-logo-panel{
  position: relative;
  width: 100%;
  max-width: 360px;
  aspect-ratio: 4 / 3;
  border-radius: var(--radius);
  background: var(--foam);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 40px;
  box-shadow: var(--shadow);
}
.case-logo-panel img{ display: block; width: 100%; height: auto; max-height: 100px; object-fit: contain; }

.case-chart-panel{
  position: relative;
  width: 100%;
  max-width: 360px;
  border-radius: var(--radius);
  background: var(--white);
  box-shadow: var(--shadow);
  padding: 28px;
}
.case-logo-sm{ height: 30px; margin-bottom: 18px; }
.case-logo-sm img{ display: block; height: 100%; width: auto; object-fit: contain; object-position: left center; }
.case-chart-img{ display: block; width: 100%; height: auto; border-radius: 8px; border: 1px solid var(--foam); }

/* Each case study's real proof — its logo/chart panel and its stat pill —
   picks up a very soft focus glow as that section scrolls to center in the
   viewport, then eases back down as you scroll on. Driven by --case-focus
   (0→1→0 per section, computed in main.js the same way Services' own
   --capability-focus already is for its section). Increasing the focal
   point on whichever case study is actually in view, rather than a static
   look the whole way down the page. */
.case-logo-panel::after, .case-chart-panel::after{
  content: "";
  position: absolute;
  inset: -12px;
  border-radius: inherit;
  box-shadow: 0 0 34px 4px color-mix(in srgb, var(--current) 30%, transparent);
  opacity: var(--case-focus, 0);
  pointer-events: none;
  transition: opacity .3s ease;
}
.case-copy .case-stat{
  box-shadow: 0 0 0 calc(var(--case-focus, 0) * 3px) color-mix(in srgb, var(--current) 25%, transparent);
  transition: box-shadow .3s ease;
}

/* Generic arrow link — same hover-shift affordance as .service-card's
   "Learn more" links, but usable outside a card (e.g. Home's case-study
   teaser, linking out to the dedicated Case Studies page). */
.link-arrow{ display: inline-flex; align-items: center; gap: 6px; font-weight: 600; transition: transform .18s ease; }
.link-arrow:hover{ transform: translateX(3px); }
.testimonial-more{ text-align: center; margin-top: 40px; }

/* Small proof-point callout — reused (with different content) on Services,
   About, and Contact: a single real stat tied to one Case Studies client,
   linking to that client's full spotlight. Deliberately lighter than a full
   testimonial card — a supporting credibility note, not a repeated section. */
.proof-point{
  display: flex;
  align-items: center;
  gap: 18px;
  flex-wrap: wrap;
  background: var(--foam);
  border-radius: var(--radius);
  padding: 22px 28px;
  margin-top: 48px;
  max-width: 700px;
}
.proof-point-stat{ font-family: var(--font-head); font-weight: 800; font-size: 28px; color: var(--current); white-space: nowrap; line-height: 1; }
/* Contact's version of this stat is a short phrase, not a number — the
   shared rule above assumes a compact value like "50+" and forces it onto
   one line, which a phrase like "Our phone won't stop ringing" would blow
   out of the card at 28px. Smaller and free to wrap, still bold/branded. */
.proof-point-stat--wrap{ white-space: normal; font-size: 21px; line-height: 1.2; max-width: 260px; }
.proof-point-text{ font-size: 14px; color: var(--slate); line-height: 1.5; }
.proof-point-text b{ color: var(--ink); }
.proof-point .link-arrow{ margin-left: auto; font-size: 14px; white-space: nowrap; }
@media (max-width: 640px){
  .proof-point{ padding: 20px; }
  .proof-point .link-arrow{ margin-left: 0; }
}
.proof-point--onfoam{ background: var(--white); box-shadow: var(--shadow); }

/* Featured variant — Services' +2200% case-study callout, made to stand out
   as its own moment rather than a quiet aside: bigger, on-brand gradient,
   an icon, and a real title line instead of a bare number + small caption. */
.proof-point--featured{
  max-width: 820px;
  padding: 36px 40px;
  gap: 22px;
  background: linear-gradient(135deg, var(--current), var(--reef));
  box-shadow: 0 28px 60px -22px rgba(13, 148, 136, .45);
}
.proof-point--featured .proof-point-icon{
  width: 56px;
  height: 56px;
  border-radius: 14px;
  background: rgba(255, 255, 255, .18);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
.proof-point--featured .proof-point-icon svg{ width: 28px; height: 28px; }
.proof-point--featured .proof-point-body{ flex: 1 1 260px; }
.proof-point--featured .proof-point-title{
  font-family: var(--font-head);
  font-weight: 800;
  font-size: clamp(22px, 2.6vw, 28px);
  line-height: 1.15;
  color: #fff;
  margin: 0 0 6px;
}
.proof-point--featured .proof-point-text{ color: rgba(255, 255, 255, .88); }
.proof-point--featured .proof-point-text b{ color: #fff; }
.proof-point--featured .link-arrow{ color: #fff; }
.proof-point--featured .link-arrow:hover{ color: var(--mist); }
@media (max-width: 640px){
  .proof-point--featured{ padding: 28px; }
}
/* Forces a specific title onto one line above mobile widths (used when a
   title's exact wording needs to read as a single line, not wrap) — left
   free to wrap on narrow phones where there isn't room for it. */
@media (min-width: 641px){
  .proof-point-title--nowrap{ white-space: nowrap; }
}

/* Every .wave divider is deliberately oversized (104% wide, -2% left) as a
   rendering-safety margin meant to be trimmed by its own section — the hero
   already does this. Two later sections (both on Home) were missing that
   clip, letting the oversize leak past the real viewport edge and add a
   faint horizontal scrollbar site-wide. Applied generically rather than
   patching those two by name, so no future section with a wave can end up
   with the same gap. Excludes .hero explicitly since Contact's hero
   deliberately sets overflow:visible for its floating form card. */
section:not(.hero):has(> .wave){ overflow: hidden; }
