/* KSBC — motion layer
   ---------------------------------------------------------------------------
   Everything here is gated behind .km-ready, which _motion.js puts on <html>.
   If the script fails to load, is blocked, or the visitor has asked for less
   motion, none of these rules apply and the page renders fully visible. The
   reveal must never be the reason content cannot be read.

   The easing is cubic-bezier(.16,1,.3,1) — a long expo-out. It moves almost
   its whole distance in the first third of the duration and then settles.
   That deceleration, plus a duration near a second, is what reads as calm
   rather than snappy; short linear transitions are what make a page feel
   like a template.                                                          */

:root{
  --km-ease:cubic-bezier(.16,1,.3,1);
  --km-dur:.9s;
}

/* ── scroll reveal ─────────────────────────────────────────────────────────
   Travel is deliberately short (22px) and paired with a barely-there scale.
   Elements that slide a long way draw attention to the animation itself;
   the intent here is that the reader notices the content, not the entrance. */
.km-ready [data-reveal]{
  opacity:0;
  transform:translateY(22px) scale(.988);
  will-change:opacity,transform;
}
.km-ready [data-reveal].km-in{
  opacity:1;
  transform:none;
  transition:opacity var(--km-dur) var(--km-ease),
             transform var(--km-dur) var(--km-ease);
}
/* Stagger is applied as a delay class rather than inline styles so the whole
   effect can be disabled by removing one class from <html>. */
.km-ready [data-reveal].km-d1.km-in{transition-delay:.07s;}
.km-ready [data-reveal].km-d2.km-in{transition-delay:.14s;}
.km-ready [data-reveal].km-d3.km-in{transition-delay:.21s;}
.km-ready [data-reveal].km-d4.km-in{transition-delay:.28s;}
.km-ready [data-reveal].km-d5.km-in{transition-delay:.35s;}

/* ── hover hairline ────────────────────────────────────────────────────────
   A short accent rule that grows from zero on hover. This is the only place
   the clay moves, which is what keeps it feeling like a response rather than
   decoration. position:relative is added here because these cards are plain
   blocks with no absolutely-positioned children to disturb. */
.exp-card,.sv-card,.cta-opt,.why-card,.client-block{position:relative;}
.exp-card:after,.sv-card:after,.cta-opt:after,.why-card:after{
  content:'';
  position:absolute;
  left:0;
  bottom:0;
  height:2px;
  width:0;
  background:var(--gold);
  transition:width .55s var(--km-ease);
}
.exp-card:after,.why-card:after{left:32px;bottom:24px;}
.sv-card:after,.cta-opt:after{left:28px;bottom:18px;}
.exp-card:hover:after,.sv-card:hover:after,.cta-opt:hover:after,.why-card:hover:after{width:38px;}

/* ── card lift ─────────────────────────────────────────────────────────────
   3px is enough to register as "this responds"; more starts to feel like a
   game UI. The shadow carries most of the effect. */
.km-ready .sv-card,.km-ready .cta-opt,.km-ready .tx-card,.km-ready .t-card{
  transition:transform .45s var(--km-ease),box-shadow .45s var(--km-ease),background .3s;
}
.km-ready .sv-card:hover,.km-ready .cta-opt:hover,
.km-ready .tx-card:hover,.km-ready .t-card:hover{
  transform:translateY(-3px);
  box-shadow:0 14px 34px rgba(0,0,0,.09);
}

/* ── nav condense ──────────────────────────────────────────────────────────
   The bar tightens and gains a hairline once the page has moved. It gives
   the reader a persistent signal of scroll depth without a progress bar. */
.km-ready #nav{
  /* A fixed backdrop blur forces the page behind the navigation to be
     recomposited while scrolling. The almost-opaque fill looks the same but
     is substantially cheaper to paint. */
  -webkit-backdrop-filter:none;
  backdrop-filter:none;
  transition:background .3s var(--km-ease),
             border-color .5s var(--km-ease),
             box-shadow .3s var(--km-ease);
}
.km-ready #nav.km-scrolled{
  height:50px;
  background:rgba(250,250,250,.97);
  box-shadow:0 1px 0 rgba(0,0,0,.05);
}
.km-ready body.home #nav.km-solid{
  -webkit-backdrop-filter:none;
  backdrop-filter:none;
  background:rgba(250,250,250,.97);
}

/* ── parallax ──────────────────────────────────────────────────────────────
   Applied only to full-bleed imagery. The transform is written by script on
   rAF; the element declares nothing here except its compositing hint. */
.km-ready [data-parallax]{will-change:transform;}

/* ── counted figures ───────────────────────────────────────────────────────
   Tabular numerals stop the box from jittering horizontally while digits
   change — without this the label underneath appears to wobble. */
.km-ready [data-count]{font-variant-numeric:tabular-nums;}

/* ── respect the system setting ────────────────────────────────────────────
   Belt and braces: _motion.js already refuses to run under this setting, but
   a stylesheet can be cached separately from a script, so the CSS states its
   own opt-out too. */
@media (prefers-reduced-motion:reduce){
  .km-ready [data-reveal]{opacity:1;transform:none;transition:none;}
  .km-ready .sv-card,.km-ready .cta-opt,.km-ready .tx-card,.km-ready .t-card,
  .km-ready #nav,.exp-card:after,.sv-card:after,.cta-opt:after,.why-card:after{
    transition:none;
  }
  .km-ready [data-parallax]{transform:none!important;}
}
