/* ─────────────────────────────────────────────────────────
 * animations.css — i-Comply Motion Engine v3
 *
 * A fully choreographed motion system:
 *  · Editorial word-cascade headlines (split by JS)
 *  · Self-drawing SVG line-art (services / about / headers)
 *  · Self-assembling app mockup (solutions)
 *  · 3D tilt + glare cards (team), cursor spotlight elsewhere
 *  · Choreographed form entrance + drawn success check (contact)
 *  · Scroll progress, magnetic CTAs, counters, page transitions
 *
 * Every hidden state is gated behind `html.js` (added by JS on
 * load) AND prefers-reduced-motion: no-preference. If JS fails
 * or the user prefers reduced motion, all content stays visible.
 * ───────────────────────────────────────────────────────── */

:root {
  --ease-out:        cubic-bezier(0.16, 1, 0.3, 1);
  --ease-out-strong: cubic-bezier(0.19, 1, 0.22, 1);
  --ease-in-out:     cubic-bezier(0.65, 0, 0.35, 1);
  --ease-spring:     cubic-bezier(0.34, 1.56, 0.64, 1);
  --transition-interactive: 180ms cubic-bezier(0.16, 1, 0.3, 1);
  --reveal-dur: 0.75s;
}

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

/* ─────────────────────────────────────────────────────────
 * CROSS-DOCUMENT PAGE TRANSITIONS
 * ───────────────────────────────────────────────────────── */
@media (prefers-reduced-motion: no-preference) {
  @view-transition { navigation: auto; }
  ::view-transition-old(root) { animation: vt-out 0.22s var(--ease-in-out) both; }
  ::view-transition-new(root) { animation: vt-in  0.45s var(--ease-out)    both; }
}
@keyframes vt-out { to   { opacity: 0; transform: translateY(-8px); } }
@keyframes vt-in  { from { opacity: 0; transform: translateY(10px); } }

/* ─────────────────────────────────────────────────────────
 * SCROLL PROGRESS BAR (injected by JS)
 * ───────────────────────────────────────────────────────── */
.scroll-progress {
  position: fixed;
  inset: 0 0 auto 0;
  height: 3px;
  z-index: 200;
  transform-origin: left center;
  transform: scaleX(0);
  background: linear-gradient(90deg, var(--color-primary), var(--color-secondary));
  box-shadow: 0 0 12px oklch(from var(--color-primary) l c h / 0.45);
  pointer-events: none;
  will-change: transform;
}

/* ─────────────────────────────────────────────────────────
 * NAV — entrance, scroll state, link underline sweep
 * ───────────────────────────────────────────────────────── */
@media (prefers-reduced-motion: no-preference) {
  html.js .nav { animation: nav-drop 0.65s var(--ease-out) both; }
}
@keyframes nav-drop {
  from { opacity: 0; transform: translateY(-14px); }
  to   { opacity: 1; transform: none; }
}

.nav {
  transition: background var(--transition-interactive),
              box-shadow 0.3s var(--ease-out);
}
.nav--scrolled { box-shadow: var(--shadow-sm); }

.nav__links a { position: relative; }
.nav__links a::after {
  content: '';
  position: absolute;
  left: 0; bottom: -3px;
  width: 100%; height: 2px;
  background: var(--color-primary);
  border-radius: 2px;
  transform: scaleX(0);
  transform-origin: right center;
  transition: transform 0.32s var(--ease-out);
}
.nav__links a:hover::after,
.nav__links a.active::after {
  transform: scaleX(1);
  transform-origin: left center;
}

/* ─────────────────────────────────────────────────────────
 * SPLIT HEADLINES — word cascade (spans injected by JS)
 * ───────────────────────────────────────────────────────── */

/* animations.js runs at the END of <body>, so without this the browser paints
 * the finished headline first and only then splits it into words — which snaps
 * it into the `backwards` from-frame. The result is the headline flashing at
 * full opacity for one frame before it animates in.
 *
 * Hold it back from first paint and drop the guard the instant the word spans
 * exist (splitWords sets data-split). `visibility` rather than opacity/display
 * so the text still occupies its box: no reflow when the words appear, and no
 * layout shift for the subtitle and buttons beneath it.
 *
 * Deliberately NOT wrapped in prefers-reduced-motion. The guard has to lift on
 * every path, so initHeadlines sets data-split even when it skips the animation
 * — otherwise a reader who switches reduced-motion off mid-session would find
 * the guard newly active on an already-split headline that can never re-mark
 * itself. If JS is absent or throws, the head script strips `js` and the whole
 * rule stops matching.
 */
html.js .page-header__title:not([data-split]),
html.js .hero__heading:not([data-split]) { visibility: hidden; }

.split-word {
  display: inline-block;
  overflow: clip;
  vertical-align: bottom;
  padding-bottom: 0.12em;
  margin-bottom: -0.12em;
}
.split-word__inner { display: inline-block; transform-origin: 0 100%; }

@media (prefers-reduced-motion: no-preference) {
  /* `backwards` holds the hidden from-frame through the delay, then
   * reverts to natural style so :hover and JS transforms keep working. */
  html.js .split-word__inner {
    animation: word-rise 0.85s var(--ease-out-strong) backwards;
    animation-delay: calc(var(--wi, 0) * 55ms + var(--split-base, 0.1s));
  }
}
@keyframes word-rise {
  from { opacity: 0; transform: translateY(112%) rotate(2deg); }
}

/* Intro pieces around the headline (badge, subtitle, CTAs) */
@media (prefers-reduced-motion: no-preference) {
  html.js .intro-pop {
    animation: intro-pop 0.7s var(--ease-spring) backwards;
    animation-delay: var(--d, 0ms);
  }
  html.js .intro-rise {
    animation: intro-rise 0.8s var(--ease-out) backwards;
    animation-delay: var(--d, 0ms);
  }
}
@keyframes intro-pop {
  from { opacity: 0; transform: scale(0.82) translateY(8px); filter: blur(4px); }
  to   { opacity: 1; transform: none;                        filter: blur(0); }
}
@keyframes intro-rise {
  from { opacity: 0; transform: translateY(20px); filter: blur(6px); }
  to   { opacity: 1; transform: none;             filter: blur(0); }
}

/* ─────────────────────────────────────────────────────────
 * SCROLL REVEAL ENGINE
 * Keyframe-based so :hover transforms keep working after the
 * entrance. `backwards` holds the from-frame through the delay.
 * ───────────────────────────────────────────────────────── */
@media (prefers-reduced-motion: no-preference) {

  html.js :is(.fade-in, .reveal-up, .reveal-left, .reveal-right,
              .stagger-child, [data-reveal]):not(.is-visible) {
    opacity: 0;
  }

  html.js :is(.fade-in, .reveal-up, .stagger-child, [data-reveal]).is-visible {
    animation: reveal-rise var(--reveal-dur) var(--ease-out) backwards;
    animation-delay: calc(var(--i, 0) * 70ms);
  }
  html.js .reveal-left.is-visible {
    animation: reveal-left var(--reveal-dur) var(--ease-out) backwards;
    animation-delay: calc(var(--i, 0) * 70ms);
  }
  html.js .reveal-right.is-visible {
    animation: reveal-right var(--reveal-dur) var(--ease-out) backwards;
    animation-delay: calc(var(--i, 0) * 70ms);
  }

  /* Cards rise with a touch of scale */
  html.js :is(.team-card, .capability-card, .service-card,
              .value-card, .flow-card, .audience-card).is-visible {
    animation-name: reveal-card;
  }
}
@keyframes reveal-rise {
  from { opacity: 0; transform: translate3d(0, 24px, 0); filter: blur(6px); }
  to   { opacity: 1; transform: none;                    filter: blur(0); }
}
@keyframes reveal-card {
  from { opacity: 0; transform: translate3d(0, 28px, 0) scale(0.96); filter: blur(5px); }
  to   { opacity: 1; transform: none;                                filter: blur(0); }
}
@keyframes reveal-left {
  from { opacity: 0; transform: translate3d(-32px, 0, 0); filter: blur(6px); }
  to   { opacity: 1; transform: none;                     filter: blur(0); }
}
@keyframes reveal-right {
  from { opacity: 0; transform: translate3d(32px, 0, 0); filter: blur(6px); }
  to   { opacity: 1; transform: none;                    filter: blur(0); }
}

/* Team card photos settle from a deeper zoom as the card reveals */
@media (prefers-reduced-motion: no-preference) {
  html.js .team-card.is-visible .team-card__avatar img {
    animation: img-settle 1.2s var(--ease-out) backwards;
    animation-delay: calc(var(--i, 0) * 70ms);
  }
}
@keyframes img-settle {
  from { transform: scale(1.16); }
  to   { transform: scale(1); }
}

/* ─────────────────────────────────────────────────────────
 * SERVICE DETAIL CHOREOGRAPHY (services page)
 * JS tags content children `.sd-item` with --i; the visual gets
 * a scale entrance and its SVG draws itself (JS-driven strokes).
 * ───────────────────────────────────────────────────────── */
@media (prefers-reduced-motion: no-preference) {
  html.js .service-detail:not(.is-visible) .sd-item,
  html.js .service-detail:not(.is-visible) .service-detail__visual {
    opacity: 0;
  }
  html.js .service-detail.is-visible .sd-item {
    animation: sd-in 0.7s var(--ease-out) backwards;
    animation-delay: calc(var(--i, 0) * 60ms);
  }
  html.js .service-detail--reverse.is-visible .sd-item {
    animation-name: sd-in-r;
  }
  html.js .service-detail.is-visible .service-detail__visual {
    animation: sd-visual 1s var(--ease-out) 0.12s backwards;
  }
}
@keyframes sd-in {
  from { opacity: 0; transform: translate3d(-26px, 0, 0); }
  to   { opacity: 1; transform: none; }
}
@keyframes sd-in-r {
  from { opacity: 0; transform: translate3d(26px, 0, 0); }
  to   { opacity: 1; transform: none; }
}
@keyframes sd-visual {
  from { opacity: 0; transform: translateY(18px) scale(0.95); }
  to   { opacity: 1; transform: none; }
}

/* ─────────────────────────────────────────────────────────
 * APP MOCKUP SELF-ASSEMBLY (solutions page)
 * JS tags each SVG child `.mock-piece` with --i and flips
 * `.is-built` on the wrapper when it scrolls into view.
 * ───────────────────────────────────────────────────────── */
@media (prefers-reduced-motion: no-preference) {
  html.js .app-mockup:not(.is-built) .mock-piece { opacity: 0; }
  html.js .app-mockup.is-built .mock-piece {
    transform-box: fill-box;
    animation: mock-in 0.55s var(--ease-out) backwards;
    animation-delay: calc(var(--i, 0) * 32ms + 0.15s);
  }
}
@keyframes mock-in {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: none; }
}

/* Watch-demo button: idle pulse ring + spring icon */
.watch-demo__icon { position: relative; }
@media (prefers-reduced-motion: no-preference) {
  .watch-demo__icon::after {
    content: '';
    position: absolute;
    inset: 0;
    border-radius: inherit;
    animation: pulse-ring 2.6s var(--ease-out) infinite;
    pointer-events: none;
  }
}
@keyframes pulse-ring {
  0%   { box-shadow: 0 0 0 0 oklch(from var(--color-primary) l c h / 0.45); }
  70%  { box-shadow: 0 0 0 20px oklch(from var(--color-primary) l c h / 0); }
  100% { box-shadow: 0 0 0 0 oklch(from var(--color-primary) l c h / 0); }
}

/* Flow arrow nudges forward; accent card glows once revealed */
@media (prefers-reduced-motion: no-preference) {
  .flow-arrow svg { animation: arrow-nudge 1.9s ease-in-out infinite; }
  .tcf-dpp-flow .flow-card--accent.is-visible {
    animation: reveal-card var(--reveal-dur) var(--ease-out) backwards,
               accent-glow 3.2s ease-in-out 1.2s 3;
    animation-delay: calc(var(--i, 0) * 70ms), 1.2s;
  }
}
@keyframes arrow-nudge {
  0%, 100% { transform: translateX(0); }
  50%      { transform: translateX(7px); }
}
@keyframes accent-glow {
  0%, 100% { box-shadow: 0 0 0 0 oklch(from var(--color-primary) l c h / 0); }
  50%      { box-shadow: 0 14px 44px -14px oklch(from var(--color-primary) l c h / 0.55); }
}

/* ─────────────────────────────────────────────────────────
 * 3D TILT + GLARE  (.tilt added by JS — team cards, app mockup)
 * Transform itself is set inline by JS; CSS supplies the glare.
 * ───────────────────────────────────────────────────────── */
@media (hover: hover) and (pointer: fine) and (prefers-reduced-motion: no-preference) {
  html.js .tilt { position: relative; will-change: transform; }
  html.js .tilt::after {
    content: '';
    position: absolute;
    inset: 0;
    border-radius: inherit;
    background: radial-gradient(
      460px circle at var(--gx, 50%) var(--gy, 50%),
      rgba(255, 255, 255, 0.14),
      transparent 62%
    );
    opacity: 0;
    transition: opacity 0.35s var(--ease-out);
    pointer-events: none;
    z-index: 2;
  }
  html.js .tilt:hover::after { opacity: 1; }
}

/* ─────────────────────────────────────────────────────────
 * CURSOR SPOTLIGHT  (.spotlight added by JS to flat cards)
 * ───────────────────────────────────────────────────────── */
@media (prefers-reduced-motion: no-preference) {
  html.js .spotlight { position: relative; isolation: isolate; }
  html.js .spotlight::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -1;
    border-radius: inherit;
    background: radial-gradient(
      260px circle at var(--mx, 50%) var(--my, 50%),
      var(--color-primary-subtle),
      transparent 64%
    );
    opacity: 0;
    transition: opacity 0.4s var(--ease-out);
    pointer-events: none;
  }
  html.js .spotlight:hover::before { opacity: 1; }
}

/* ─────────────────────────────────────────────────────────
 * BUTTONS — lift, press, shine sweep (magnetic offset via JS)
 * ───────────────────────────────────────────────────────── */
.btn {
  position: relative;
  overflow: hidden;
  transition: background var(--transition-interactive),
              color var(--transition-interactive),
              border-color var(--transition-interactive),
              box-shadow var(--transition-interactive),
              transform 0.25s var(--ease-out);
}
.btn:hover  { transform: translateY(-2px); box-shadow: var(--shadow-md); }
.btn:active { transform: translateY(0);    box-shadow: none; }

.btn--primary::after,
.btn--white::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(105deg,
    transparent 38%, rgba(255, 255, 255, 0.28) 50%, transparent 62%);
  transform: translateX(-130%);
  pointer-events: none;
}
@media (prefers-reduced-motion: no-preference) {
  .btn--primary:hover::after,
  .btn--white:hover::after {
    animation: btn-shine 0.7s var(--ease-out) forwards;
  }
}
@keyframes btn-shine { to { transform: translateX(130%); } }

/* ─────────────────────────────────────────────────────────
 * CARD HOVERS — service / value / region / faq / capability /
 * trust / flow / audience
 * ───────────────────────────────────────────────────────── */
.service-card, .value-card, .region-card, .faq-item,
.capability-card, .audience-card, .flow-card {
  transition: box-shadow 0.32s var(--ease-out),
              transform 0.32s var(--ease-out),
              border-color 0.32s var(--ease-out);
}
.service-card:hover, .value-card:hover, .region-card:hover,
.audience-card:hover {
  transform: translateY(-4px);
  box-shadow: var(--shadow-lg);
  border-color: var(--color-primary);
}
.faq-item:hover {
  border-color: var(--color-primary);
  box-shadow: var(--shadow-md);
}

.service-card__icon, .value-card__icon, .capability-card__icon {
  transition: background 0.3s var(--ease-out),
              color 0.3s var(--ease-out),
              transform 0.45s var(--ease-spring);
}
.service-card:hover .service-card__icon,
.value-card:hover .value-card__icon,
.capability-card:hover .capability-card__icon {
  background: var(--color-primary-subtle);
  transform: scale(1.12) rotate(-6deg);
}
.service-card__link svg {
  display: inline-block;
  transition: transform var(--transition-interactive);
}
.service-card:hover .service-card__link svg { transform: translateX(5px); }

/* Trust items — scale pop */
.trust-item {
  transition: box-shadow 0.32s var(--ease-out),
              transform 0.32s var(--ease-out),
              border-color 0.32s var(--ease-out);
}
.trust-item:hover {
  transform: translateY(-3px) scale(1.02);
  box-shadow: var(--shadow-md);
  border-color: var(--color-primary);
}
.trust-item__number {
  font-variant-numeric: tabular-nums;
  transition: color 0.3s var(--ease-out), transform 0.4s var(--ease-spring);
}
.trust-item:hover .trust-item__number {
  color: var(--color-primary);
  transform: scale(1.08);
}
.stat-item__value { font-variant-numeric: tabular-nums; }

/* ─────────────────────────────────────────────────────────
 * TEAM CARDS — tilt handled by JS; photo + name treatments here
 * ───────────────────────────────────────────────────────── */
.team-card {
  position: relative;
  transition: box-shadow 0.35s var(--ease-out),
              transform 0.35s var(--ease-out),
              border-color 0.35s var(--ease-out);
}
.team-card:hover {
  box-shadow: var(--shadow-lg);
  border-color: var(--color-primary);
}
.team-card__avatar { position: relative; overflow: hidden; }
.team-card__avatar img {
  transition: transform 0.65s var(--ease-out), filter 0.5s ease;
  filter: saturate(0.92);
  will-change: transform;
}
.team-card:hover .team-card__avatar img {
  transform: scale(1.06);
  filter: saturate(1.05);
}
/* Brand tint that lifts away on hover */
.team-card__avatar::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(to top,
    oklch(from var(--color-primary) l c h / 0.16), transparent 55%);
  transition: opacity 0.45s var(--ease-out);
  pointer-events: none;
}
.team-card:hover .team-card__avatar::after { opacity: 0; }

/* Name underline sweep */
.team-card__name {
  position: relative;
  align-self: flex-start;
  padding-bottom: 2px;
}
.team-card__name::after {
  content: '';
  position: absolute;
  left: 0; bottom: 0;
  width: 100%; height: 2px;
  background: var(--color-primary);
  border-radius: 2px;
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 0.4s var(--ease-out) 0.05s;
}
.team-card:hover .team-card__name::after { transform: scaleX(1); }

/* ─────────────────────────────────────────────────────────
 * PROCESS STEPS — progressive highlight (classes from JS)
 * ───────────────────────────────────────────────────────── */
.process-step {
  transition: background 0.4s var(--ease-out), border-color 0.4s var(--ease-out);
}
.process-step__num { transition: color 0.3s var(--ease-out); }
.process-step.step-active                    { background: var(--color-primary-subtle); }
.process-step.step-active .process-step__num { color: var(--color-primary); }

/* ─────────────────────────────────────────────────────────
 * FOOTER LINKS
 * ───────────────────────────────────────────────────────── */
.footer__links a {
  display: inline-block;
  transition: color var(--transition-interactive), transform var(--transition-interactive);
}
.footer__links a:hover { color: var(--color-primary); transform: translateX(3px); }

/* ─────────────────────────────────────────────────────────
 * CLIENT LOGOS / MARQUEE
 * ───────────────────────────────────────────────────────── */
.client-logo-item {
  transition: opacity 0.25s var(--ease-out),
              transform 0.25s var(--ease-spring),
              filter 0.25s var(--ease-out);
}
.client-logo-item:hover {
  opacity: 1 !important;
  transform: scale(1.07);
  filter: grayscale(0%) !important;
}
.marquee-item {
  transition: border-color var(--transition-interactive),
              color var(--transition-interactive);
}
.marquee-item:hover {
  border-color: var(--color-primary);
  color: var(--color-text);
}

/* ─────────────────────────────────────────────────────────
 * TESTIMONIAL — oversized quote mark scales in
 * ───────────────────────────────────────────────────────── */
.testimonial { position: relative; }
.testimonial::before {
  content: '\201C';
  position: absolute;
  top: -0.1em; left: 0.2em;
  font-size: 8rem;
  font-family: var(--font-display);
  line-height: 1;
  color: var(--color-primary);
  opacity: 0.08;
  pointer-events: none;
  user-select: none;
}
@media (prefers-reduced-motion: no-preference) {
  html.js .testimonial.is-visible::before {
    animation: quote-pop 0.9s var(--ease-spring) 0.3s backwards;
  }
}
@keyframes quote-pop {
  from { opacity: 0; transform: scale(0.4) rotate(-8deg); }
  to   { opacity: 0.08; transform: none; }
}

/* ─────────────────────────────────────────────────────────
 * CTA BANNER — decorative path draw-in + pulsing orbs
 * ───────────────────────────────────────────────────────── */
.cta-banner .cta-banner__decoration path,
.cta-banner .cta-banner__decoration rect {
  stroke-dasharray: 500;
  stroke-dashoffset: 500;
  transition: stroke-dashoffset 1.3s var(--ease-out);
}
.cta-banner--animated .cta-banner__decoration path,
.cta-banner--animated .cta-banner__decoration rect { stroke-dashoffset: 0; }
.cta-banner--animated .cta-banner__decoration rect:nth-of-type(2) { transition-delay: 0.25s; }
.cta-banner--animated .cta-banner__decoration rect:nth-of-type(3) { transition-delay: 0.45s; }

@keyframes orb-pulse {
  0%, 100% { r: 3; opacity: 0.4; }
  50%      { r: 5; opacity: 0.9; }
}
@keyframes orb-pulse2 {
  0%, 100% { r: 2; opacity: 0.3; }
  50%      { r: 4; opacity: 0.7; }
}

/* ─────────────────────────────────────────────────────────
 * GLOBE — fade-and-settle (index + about)
 * ───────────────────────────────────────────────────────── */
@media (prefers-reduced-motion: no-preference) {
  html.js .globe-wrapper {
    opacity: 0;
    transform: scale(0.95);
    transition: opacity 1s var(--ease-out), transform 1s var(--ease-out);
  }
  html.js .globe-wrapper.globe--visible { opacity: 1; transform: scale(1); }
}

/* ─────────────────────────────────────────────────────────
 * FORMS — focus ring, label tint, option pop, success check
 * ───────────────────────────────────────────────────────── */
.form-input, .form-textarea, .form-select {
  transition: border-color 0.25s var(--ease-out), box-shadow 0.25s var(--ease-out);
}
.form-input:focus, .form-textarea:focus, .form-select:focus {
  border-color: var(--color-primary);
  box-shadow: 0 0 0 3px oklch(from var(--color-primary) l c h / 0.18);
}
.form-label { transition: color 0.25s var(--ease-out); }
.form-group:focus-within .form-label { color: var(--color-primary); }

@media (prefers-reduced-motion: no-preference) {
  .service-option:has(input:checked) { animation: option-pop 0.35s var(--ease-spring); }
}
@keyframes option-pop {
  50% { transform: scale(1.035); }
}

/* Success state: icon springs in, check draws itself */
@media (prefers-reduced-motion: no-preference) {
  .form-success__icon { animation: intro-pop 0.6s var(--ease-spring) both; }
  .form-success__icon svg path,
  .form-success__icon svg polyline {
    stroke-dasharray: 80;
    stroke-dashoffset: 80;
    animation: draw-check 0.9s var(--ease-out) 0.25s forwards;
  }
  .form-success__icon svg polyline { animation-delay: 0.55s; }
  .form-success__title { animation: intro-rise 0.7s var(--ease-out) 0.35s both; }
  .form-success__body  { animation: intro-rise 0.7s var(--ease-out) 0.5s  both; }
}
@keyframes draw-check { to { stroke-dashoffset: 0; } }

/* Contact methods — slide + icon spring */
.contact-method {
  transition: box-shadow var(--transition-interactive),
              transform var(--transition-interactive),
              border-color var(--transition-interactive);
}
a.contact-method:hover {
  box-shadow: var(--shadow-md);
  transform: translateX(4px);
  border-color: var(--color-primary);
}
.contact-method__icon {
  transition: transform 0.45s var(--ease-spring), background 0.3s var(--ease-out);
}
a.contact-method:hover .contact-method__icon {
  transform: scale(1.15) rotate(-6deg);
  background: var(--color-primary-highlight);
}

/* Promise box: lightning icon pulse */
@media (prefers-reduced-motion: no-preference) {
  .promise-box__icon { animation: badge-float 3.2s ease-in-out infinite; }
}

/* ─────────────────────────────────────────────────────────
 * TIMELINE (about)
 * ───────────────────────────────────────────────────────── */
.timeline { position: relative; }
.timeline::before {
  content: '';
  position: absolute;
  left: 20px; top: 0; bottom: 0;
  width: 2px;
  background: linear-gradient(to bottom, var(--color-primary) 0%, var(--color-divider) 100%);
}
.timeline-item.is-visible .timeline-item__dot {
  animation: dot-pulse 1.5s var(--ease-spring) both;
}
@keyframes dot-pulse {
  0%   { transform: scale(0.5);  opacity: 0; }
  60%  { transform: scale(1.15); opacity: 1; }
  100% { transform: scale(1);    opacity: 1; }
}

/* ─────────────────────────────────────────────────────────
 * MISC ACCENTS
 * ───────────────────────────────────────────────────────── */
.region-card__dot { transition: transform 0.4s var(--ease-spring); }
.region-card:hover .region-card__dot { transform: scale(1.5); }

.service-detail__visual {
  transition: box-shadow 0.35s var(--ease-out);
}
.service-detail__visual:hover { box-shadow: var(--shadow-lg); }

.about-intro__visual {
  transition: box-shadow 0.4s var(--ease-out), transform 0.4s var(--ease-out);
}
.about-intro__visual:hover { box-shadow: var(--shadow-lg); transform: scale(1.02); }

@keyframes badge-float {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-4px); }
}
@keyframes flow-dash { to { stroke-dashoffset: -40; } }

@keyframes badge-shimmer {
  0%   { background-position: -200% center; }
  100% { background-position:  200% center; }
}
.badge--blue { background-size: 200% auto; }
@media (prefers-reduced-motion: no-preference) {
  .badge--blue { animation: badge-shimmer 5s linear infinite; }
}

/* ─────────────────────────────────────────────────────────
 * REDUCED MOTION — neutralise everything that moves
 * ───────────────────────────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
  .scroll-progress { display: none; }
  .btn:hover, .service-card:hover, .value-card:hover, .trust-item:hover,
  .team-card:hover, .region-card:hover, .capability-card:hover,
  .audience-card:hover, .about-intro__visual:hover, a.contact-method:hover,
  .team-card:hover .team-card__avatar img {
    transform: none !important;
  }
  .badge--blue, .flow-arrow svg, .promise-box__icon,
  .watch-demo__icon::after { animation: none !important; }
  .spotlight::before, .tilt::after { display: none; }
  .cta-banner .cta-banner__decoration path,
  .cta-banner .cta-banner__decoration rect {
    stroke-dasharray: none;
    stroke-dashoffset: 0;
    transition: none;
  }
}
