/* ==========================================================================
   ACB Technologies — motion layer

   Everything in this file is ADDITIVE. Once any animation settles, the
   element matches the static design in style.css exactly: no rule here
   changes a resting layout, colour, size or position. Motion is expressed
   only through `opacity` and `transform` (plus `box-shadow` on hover), so
   nothing reflows.

   Three safety gates:
     1. `.js-anim` is set on <html> by js/animate.js. Without JS, nothing is
        ever hidden — the page renders as the plain static design.
     2. js/animate.js refuses to add that class when the visitor prefers
        reduced motion.
     3. The catch-all at the bottom neutralises every remaining transition.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Scroll reveal

   js/animate.js observes [data-reveal] and adds .is-in as each element
   arrives, then flips the attribute to "done" once the transition has
   settled so the element drops out of these rules entirely — that is what
   lets the hover states further down keep control of `transform`.
   -------------------------------------------------------------------------- */
.js-anim [data-reveal="up"],
.js-anim [data-reveal="scene"] { opacity: 0; }

.js-anim [data-reveal="up"]    { transform: translateY(20px); }
.js-anim [data-reveal="scene"] { transform: translateY(26px) scale(.99); }

.js-anim [data-reveal="up"].is-in,
.js-anim [data-reveal="scene"].is-in {
  opacity: 1;
  transform: none;
  transition: opacity .75s cubic-bezier(.22, .61, .36, 1) var(--d, 0s),
              transform .75s cubic-bezier(.22, .61, .36, 1) var(--d, 0s);
}

/* --------------------------------------------------------------------------
   2. Header settles in on load
   -------------------------------------------------------------------------- */
@keyframes acbNavIn {
  from { opacity: 0; transform: translateY(-10px); }
}
.js-anim .nav__logo      { animation: acbNavIn .6s cubic-bezier(.22, .61, .36, 1) both; }
.js-anim .nav__links li  { animation: acbNavIn .55s cubic-bezier(.22, .61, .36, 1) both; }
.js-anim .nav__links li:nth-child(1) { animation-delay: .08s; }
.js-anim .nav__links li:nth-child(2) { animation-delay: .14s; }
.js-anim .nav__links li:nth-child(3) { animation-delay: .20s; }
.js-anim .nav__links li:nth-child(4) { animation-delay: .26s; }

/* --------------------------------------------------------------------------
   3. Navigation links — underline wipes out from the left on hover
   -------------------------------------------------------------------------- */
.nav__link { position: relative; }
.nav__link::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: -7px;
  height: 1.5px;
  border-radius: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform .3s cubic-bezier(.22, .61, .36, 1);
}
.nav__link:hover::after,
.nav__link:focus-visible::after { transform: scaleX(1); }

.nav__logo img { transition: transform .4s cubic-bezier(.22, .61, .36, 1); }
.nav__logo:hover img { transform: scale(1.04); }

/* --------------------------------------------------------------------------
   4. Buttons — the documented colour inversion, plus a lift
   -------------------------------------------------------------------------- */
.btn {
  transition: background-color .18s ease,
              color .18s ease,
              box-shadow .25s ease,
              transform .18s cubic-bezier(.22, .61, .36, 1);
}
.btn:hover,
.btn:focus-visible {
  transform: translateY(-2px);
  box-shadow: inset 0 0 0 1px var(--border), 0 10px 22px rgba(19, 39, 62, .14);
}
.btn:active { transform: translateY(0); transition-duration: .08s; }

/* --------------------------------------------------------------------------
   5. Cards — lift, and the meta rule extends into the accent colour
   -------------------------------------------------------------------------- */
.why-card,
.value-card,
.capability,
.spotlight__aside {
  transition: transform .4s cubic-bezier(.22, .61, .36, 1),
              box-shadow .4s ease,
              border-color .4s ease;
}
.why-card:hover,
.value-card:hover,
.capability:hover,
.spotlight__aside:hover {
  transform: translateY(-3px);
  border-color: #d7dbe0;
  box-shadow: 0 14px 30px rgba(19, 39, 62, .08);
}

.why-card__rule,
.capability__rule {
  transition: width .4s cubic-bezier(.22, .61, .36, 1), background-color .4s ease;
}
.why-card:hover .why-card__rule    { width: 44px; background: var(--accent); }
.capability:hover .capability__rule { width: 52px; background: var(--accent); }

/* --------------------------------------------------------------------------
   6. Footer and inline links
   -------------------------------------------------------------------------- */
a.footer__link {
  transition: opacity .25s ease, transform .25s cubic-bezier(.22, .61, .36, 1);
}
a.footer__link:hover { transform: translateX(3px); }
.footer__cred a,
.contact-item__value a { transition: color .25s ease, opacity .25s ease; }

/* --------------------------------------------------------------------------
   7. Contact page
   -------------------------------------------------------------------------- */
.field input,
.field textarea {
  transition: border-color .25s ease, box-shadow .25s ease;
}
.field input:hover,
.field textarea:hover { border-color: #cfd4da; }
.field input:focus-visible,
.field textarea:focus-visible {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(47, 109, 163, .18);
}

.contact-item__icon {
  transition: transform .3s cubic-bezier(.22, .61, .36, 1), box-shadow .3s ease;
}
.contact-item:hover .contact-item__icon {
  transform: translateY(-2px) scale(1.06);
  box-shadow: 0 8px 18px rgba(47, 109, 163, .28);
}

@keyframes acbSuccessIn {
  from { opacity: 0; transform: translateY(-8px); }
}
.form-success:not([hidden]) {
  animation: acbSuccessIn .45s cubic-bezier(.22, .61, .36, 1);
}

/* --------------------------------------------------------------------------
   8. Home hero — the network diagram comes alive
   Each keyframe repeats the element's own translate(-50%, -50%) so its
   designed position is preserved for the whole cycle.
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: no-preference) {

  @keyframes acbGlow {
    0%, 100% { transform: translate(-50%, -50%) scale(1);    opacity: .88; }
    50%      { transform: translate(-50%, -50%) scale(1.07); opacity: 1; }
  }
  .hero-scene__glow { animation: acbGlow 9s ease-in-out infinite; }

  @keyframes acbHub {
    0%, 100% { transform: translate(-50%, -50%); }
    50%      { transform: translate(-50%, calc(-50% - 4px)); }
  }
  .hero-scene__hub { animation: acbHub 6.5s ease-in-out infinite; }

  @keyframes acbDrift {
    0%, 100% { transform: translate(-50%, -50%); }
    50%      { transform: translate(-50%, calc(-50% + 5px)); }
  }
  .hero-scene__card { animation: acbDrift 7.5s ease-in-out .4s infinite; }

  @keyframes acbSlot {
    0%, 100% { transform: translate(-50%, -50%); }
    50%      { transform: translate(-50%, calc(-50% - 3px)); }
  }
  .hero-scene__slot--a { animation: acbSlot 8s ease-in-out .2s infinite; }
  .hero-scene__slot--b { animation: acbSlot 7s ease-in-out .9s infinite; }
  .hero-scene__slot--c { animation: acbSlot 9s ease-in-out 1.4s infinite; }

  @keyframes acbBarPulse {
    0%, 100% { opacity: 1; }
    50%      { opacity: .72; }
  }
  .hero-scene__card-head { animation: acbBarPulse 4s ease-in-out infinite; }

  /* Signal travelling along each connector. The pulse inherits the
     connector's own low opacity, so it reads as a shimmer, not a light show. */
  .hero-scene__conn { overflow: hidden; }
  .hero-scene__conn::after {
    content: "";
    position: absolute;
    inset: 0 auto 0 0;
    width: 45%;
    height: 100%;
    background: linear-gradient(90deg, transparent, var(--accent), transparent);
    animation: acbFlowX 3.4s linear infinite;
  }
  @keyframes acbFlowX {
    from { transform: translateX(-110%); }
    to   { transform: translateX(230%); }
  }

  .hero-scene__conn--2::after { animation-delay: .8s; }
  .hero-scene__conn--4::after { animation-delay: 1.6s; }

  .hero-scene__conn--3::after {
    inset: 0 0 auto 0;
    width: 100%;
    height: 45%;
    background: linear-gradient(180deg, transparent, var(--accent), transparent);
    animation: acbFlowY 3.4s linear .6s infinite;
  }
  @keyframes acbFlowY {
    from { transform: translateY(-110%); }
    to   { transform: translateY(230%); }
  }

  @keyframes acbBlip {
    0%, 70%, 100% { transform: translate(-50%, -50%) scale(1);   opacity: .85; }
    35%           { transform: translate(-50%, -50%) scale(2.1); opacity: 1; }
  }
  .hero-scene__junction    { animation: acbBlip 3.4s ease-in-out infinite; }
  .hero-scene__junction--2 { animation-delay: .8s; }
  .hero-scene__junction--3 { animation-delay: .4s; }
  .hero-scene__junction--4 { animation-delay: 1.6s; }

  /* Feature-panel backlight breathes */
  @keyframes acbPanelGlow {
    0%, 100% { transform: rotate(115.48deg) scale(1); }
    50%      { transform: rotate(119.5deg) scale(1.06); }
  }
  .features__glow img { animation: acbPanelGlow 16s ease-in-out infinite; }
}

/* --------------------------------------------------------------------------
   9. About hero — the stack assembles top-down
   -------------------------------------------------------------------------- */
@keyframes acbPop {
  from { opacity: 0; transform: translateY(14px) scale(.94); }
  to   { opacity: 1; transform: none; }
}
@keyframes acbGrow {
  from { transform: scaleY(0); }
  to   { transform: scaleY(1); }
}

.js-anim .about-scene .about-scene__block,
.js-anim .about-scene .about-scene__badge,
.js-anim .about-scene .about-scene__card,
.js-anim .about-scene .about-scene__logo { opacity: 0; }

.js-anim .about-scene .about-scene__connector { transform: scaleY(0); transform-origin: top center; }

.js-anim .about-scene.is-in .about-scene__block { animation: acbPop .6s cubic-bezier(.22, .61, .36, 1) .25s both; }
.js-anim .about-scene.is-in .about-scene__logo  { animation: acbPop .6s cubic-bezier(.22, .61, .36, 1) .35s both; }
.js-anim .about-scene.is-in .about-scene__badge { animation: acbPop .6s cubic-bezier(.22, .61, .36, 1) .62s both; }
.js-anim .about-scene.is-in .about-scene__card  { animation: acbPop .6s cubic-bezier(.22, .61, .36, 1) .88s both; }
.js-anim .about-scene.is-in .about-scene__group:nth-of-type(1) .about-scene__connector {
  animation: acbGrow .35s cubic-bezier(.22, .61, .36, 1) .5s both;
}
.js-anim .about-scene.is-in .about-scene__group:nth-of-type(2) .about-scene__connector {
  animation: acbGrow .3s cubic-bezier(.22, .61, .36, 1) .78s both;
}

/* --------------------------------------------------------------------------
   10. Product showcase — side captures slide in, the handset rises then floats
   -------------------------------------------------------------------------- */
.js-anim .showcase .showcase__shot,
.js-anim .showcase .showcase__phone { opacity: 0; }

@keyframes acbShotLeft {
  from { opacity: 0; transform: translateX(-26px); }
  to   { opacity: 1; transform: none; }
}
@keyframes acbShotRight {
  from { opacity: 0; transform: translateX(26px); }
  to   { opacity: 1; transform: none; }
}
@keyframes acbPhoneIn {
  from { opacity: 0; transform: translate(-50%, -46%) scale(.94); }
  to   { opacity: 1; transform: translate(-50%, -50%) scale(1); }
}
@keyframes acbPhoneFloat {
  0%, 100% { transform: translate(-50%, -50%); }
  50%      { transform: translate(-50%, calc(-50% - 8px)); }
}

.js-anim .showcase.is-in .showcase__shot--left {
  animation: acbShotLeft .85s cubic-bezier(.22, .61, .36, 1) .12s both;
}
.js-anim .showcase.is-in .showcase__shot--right {
  animation: acbShotRight .85s cubic-bezier(.22, .61, .36, 1) .2s both;
}
.js-anim .showcase.is-in .showcase__phone {
  animation: acbPhoneIn .95s cubic-bezier(.22, .61, .36, 1) both,
             acbPhoneFloat 7.5s ease-in-out 1.25s infinite;
}

/* --------------------------------------------------------------------------
   11. Products hero handset
   -------------------------------------------------------------------------- */
@keyframes acbDeviceIn {
  from { opacity: 0; transform: scaleX(-1) translateY(26px); }
  to   { opacity: 1; transform: scaleX(-1) translateY(0); }
}
@keyframes acbDeviceFloat {
  0%, 100% { transform: scaleX(-1) translateY(0); }
  50%      { transform: scaleX(-1) translateY(-10px); }
}
.js-anim .device-scene .device { opacity: 0; }
.js-anim .device-scene.is-in .device {
  animation: acbDeviceIn .9s cubic-bezier(.22, .61, .36, 1) .15s both,
             acbDeviceFloat 8s ease-in-out 1.35s infinite;
}

/* --------------------------------------------------------------------------
   12. KeyRing feature panel — headline then a card ripple
   -------------------------------------------------------------------------- */
@keyframes acbFeatureIn {
  from { opacity: 0; transform: translateY(10px) scale(.96); }
  to   { opacity: 1; transform: none; }
}
@keyframes acbHeadIn {
  from { opacity: 0; transform: translateY(12px); }
  to   { opacity: 1; transform: none; }
}
.js-anim .features .features__head,
.js-anim .features .feature { opacity: 0; }

.js-anim .features.is-in .features__head {
  animation: acbHeadIn .7s cubic-bezier(.22, .61, .36, 1) .18s both;
}
.js-anim .features.is-in .feature {
  animation: acbFeatureIn .6s cubic-bezier(.22, .61, .36, 1) both;
}
.js-anim .features.is-in .feature:nth-child(1) { animation-delay: .30s; }
.js-anim .features.is-in .feature:nth-child(2) { animation-delay: .38s; }
.js-anim .features.is-in .feature:nth-child(3) { animation-delay: .46s; }
.js-anim .features.is-in .feature:nth-child(4) { animation-delay: .54s; }
.js-anim .features.is-in .feature:nth-child(5) { animation-delay: .62s; }
.js-anim .features.is-in .feature:nth-child(6) { animation-delay: .70s; }

/* Shadow only — the entrance animation owns `transform` on these cards. */
.feature { transition: box-shadow .3s ease; }
.feature:hover { box-shadow: 0 8px 20px rgba(0, 0, 0, .22); }

/* Launch marker on the home spotlight card */
@media (prefers-reduced-motion: no-preference) {
  @keyframes acbDot {
    0%, 100% { transform: scale(1);    opacity: 1; }
    50%      { transform: scale(1.22); opacity: .7; }
  }
  .spotlight__status img { animation: acbDot 2.4s ease-in-out infinite; }
}

/* --------------------------------------------------------------------------
   13. Catch-all — honour an explicit reduced-motion preference everywhere,
   including the transitions declared in style.css.
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
}
