/* ===== home.css ===== */
/* ═══════════════════════════════════════════════
   FLEETRABBIT AI — core (variables, base, shared utilities)
   Section styles live in their own files:
   header.css · hero.css · scene.css · logos.css ·
   integrations.css · features.css · why.css · reviews.css ·
   faq.css · cta.css · footer.css
   ═══════════════════════════════════════════════ */
/* Variables live on the homepage wrapper (not :root) so they can't override
   the site theme's global tokens; they still inherit to everything inside. */
#homepage-content {
  --ink: #1d1d1f;
  --ink-2: #6e6e73;
  --bg: #ffffff;
  --bg-alt: #f5f5f7;
  --dark: #0b0b0f;
  --accent: #0071e3;
  --accent-2: #2563eb;
  --green: #30d158;
  --amber: #ff9f0a;
  --radius: 22px;
  --ease: cubic-bezier(0.16, 1, 0.3, 1);
  --font: -apple-system, BlinkMacSystemFont, "SF Pro Display", "SF Pro Text", "Segoe UI", Inter, Roboto, sans-serif;
}

/* All base/element rules are scoped to the wrapper via :where() so they only
   affect the homepage — never the shared site elements. :where() adds the
   scope with ZERO specificity, so every .fx-* class rule still wins exactly
   as before (behaviour unchanged, only the global leak is removed). */
:where(#homepage-content) *,
:where(#homepage-content) *::before,
:where(#homepage-content) *::after { margin: 0; padding: 0; box-sizing: border-box; }
/* neutralise the site template's generic `section { padding: 110px 0 }` so it can't
   add stray space (and a grey band on the oneflow's grey bg) to the fx- sections.
   0,0,1 specificity + loaded after style.css beats the template; fx- section rules
   (0,1,0) still win and keep their own padding. */
:where(#homepage-content) section { padding-top: 0; padding-bottom: 0; }
/* the template sets body { word-break: break-word }, which is inherited and splits
   words mid-character (e.g. "FleetRabbit" -> "FleetRabb / it"). Restore normal wrapping. */
#homepage-content { word-break: normal; overflow-wrap: normal; }
/* The site theme (Reboot) sets element margins/paddings — h*{margin-bottom},
   p{margin-bottom}, ul/ol{padding-left,margin-bottom}. Those have element-level
   weight and would beat the universal reset above, so re-zero them at matching
   weight inside the homepage only. Still loses to every .fx-* class rule. */
:where(#homepage-content) :is(h1,h2,h3,h4,h5,h6,p,ul,ol,dl,dd,figure,blockquote,fieldset,hr,pre) { margin: 0; padding: 0; }
html { scroll-behavior: smooth; -webkit-text-size-adjust: 100%; }
/* kill sideways panning on phones — hidden on body alone isn't honored by
   mobile browsers, so clip at both levels (hidden = old-browser fallback) */
/* The homepage's own <body>: kill the default UA 8px margin and contain
   sideways overflow. Scoped to .fx-home so other site pages' <body> is
   never touched (on the live site the theme already resets body margin;
   this also makes the standalone homepage.html render edge-to-edge). */
body.fx-home { margin: 0; overflow-x: hidden; overflow-x: clip; }
#homepage-content { overflow-x: hidden; overflow-x: clip; max-width: 100%; }
#homepage-content {
  font-family: var(--font);
  color: var(--ink);
  background: var(--bg);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}
:where(#homepage-content) img, :where(#homepage-content) svg { max-width: 100%; display: block; }
:where(#homepage-content) a { text-decoration: none; color: inherit; }
:where(#homepage-content) ul { list-style: none; }

.fx-container { width: min(1180px, 92vw); margin: 0 auto; }
.fx-container.fx-narrow { width: min(820px, 92vw); }
.fx-center { text-align: center; }

:where(#homepage-content) h1, :where(#homepage-content) h2, :where(#homepage-content) h3 { letter-spacing: -0.022em; line-height: 1.08; font-weight: 700; }
:where(#homepage-content) h2 { font-size: clamp(2rem, 4.6vw, 3.5rem); }
/* headings paint as a soft ink → slate gradient instead of flat black;
   .fx-h2-grad / .fx-l2-style spans keep their own blue gradient (their class wins) */
:where(#homepage-content) h1, :where(#homepage-content) h2 {
  background-image: linear-gradient(100deg, #0f0f10 0%, #3d3d42 45%, #a9a9b0 100%);
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent;
}
/* headings that sit on dark / colored backgrounds keep their solid color */
.fx-hero-title, .fx-of-title, .fx-scene-text h2, .fx-sup-cta-card h2 {
  background-image: none;
  -webkit-text-fill-color: currentColor;
}
/* accent words inside gradient headings keep their own color */
.fx-bc-title em { -webkit-text-fill-color: var(--accent, #2563eb); }
.fx-lead { font-size: clamp(1.05rem, 1.5vw, 1.3rem); color: var(--ink-2); max-width: 46em; }
.fx-lead.fx-center { margin: 18px auto 0; }
.fx-kicker {
  font-size: 0.85rem; font-weight: 700; text-transform: uppercase;
  letter-spacing: 0.14em; color: var(--accent); margin-bottom: 14px;
}
/* gradient highlight for part of a heading */
.fx-h2-grad {
  background: linear-gradient(100deg, #1d4ed8 0%, #2f80ee 45%, #aacdf8 100%);
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent; color: transparent;
}

/* ───────── reveal-on-scroll ───────── */
.fx-reveal { opacity: 0; transform: translateY(18px); transition: opacity .55s var(--ease), transform .55s var(--ease); }
.fx-reveal.fx-in { opacity: 1; transform: none; }

/* ───────── buttons ───────── */
.fx-btn {
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 999px; font-weight: 600; white-space: nowrap;
  transition: transform .35s var(--ease), box-shadow .35s var(--ease), background .3s;
}
.fx-btn:hover { transform: translateY(-2px); }
.fx-btn:active { transform: scale(.97); }
.fx-btn-primary { background: var(--accent); color: #fff; box-shadow: 0 8px 24px rgba(0,113,227,.32); }
.fx-btn-primary:hover { background: #0a7dff; box-shadow: 0 12px 32px rgba(0,113,227,.42); }
.fx-btn-white { background: #fff; color: var(--dark); }
.fx-btn-outline {
  background: #fff; color: var(--accent);
  border: 1.5px solid var(--accent);
  box-shadow: 0 8px 24px rgba(0,113,227,.1);
}
.fx-btn-outline:hover { background: #f0f7ff; box-shadow: 0 12px 32px rgba(0,113,227,.16); }
.fx-btn-ghost { border: 1px solid rgba(255,255,255,.4); color: #fff; }
.fx-btn-ghost:hover { background: rgba(255,255,255,.1); }
.fx-btn-sm { padding: 9px 20px; font-size: .92rem; }
.fx-btn-lg { padding: 16px 36px; font-size: 1.08rem; }
@media (max-width: 640px) {
  .fx-btn-lg { padding: 11px 22px; font-size: 0.94rem; }
}
.fx-btn-link { color: var(--accent); font-weight: 600; font-size: 1.05rem; display: inline-flex; align-items: center; gap: 5px; }
.fx-btn-link:hover { text-decoration: underline; }
/* the site template sets a:hover{color:var(--base-color)} (a blue-purple) which
   overrides button text on hover — e.g. Sign Up's white text goes purple. Keep each
   button's own text colour on hover/focus. */
.fx-btn-primary:hover, .fx-btn-primary:focus,
.fx-btn-ghost:hover,   .fx-btn-ghost:focus   { color: #fff; }
.fx-btn-white:hover,   .fx-btn-white:focus   { color: var(--dark); }
.fx-btn-link:hover,    .fx-btn-link:focus,
.fx-pb-btn-outline:hover, .fx-pb-btn-outline:focus { color: var(--accent); }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .fx-reveal { opacity: 1; transform: none; transition: none; }
}

/* ===== hero.css ===== */
/* ═══════════ HERO ═══════════ */
.fx-hero {
  padding: 0;
  background: #fbfbfd;
}

/* ── APPLE-STYLE TAKEOVER ──
   The hero pins to the top of the viewport (sticky) while the next
   section slides up OVER it like a card. home.js dims the hero in
   place as it gets covered (no transform — scale exposed white side
   bands, drift read as the hero scrolling with the page) and scrubs
   --cover (0→1) on #vehicles-root. */
.fx-hero-takeover #hero-root {
  position: sticky;
  top: 0;
  z-index: 0;
}
.fx-hero-takeover #vehicles-root {
  position: relative;
  z-index: 1;
  border-radius: clamp(20px, 3vw, 32px) clamp(20px, 3vw, 32px) 0 0;
  box-shadow: 0 -18px 50px rgba(12, 28, 64, .18);
  /* the shadow is only for the hero edge above — clip it below so it
     never bleeds onto the white phone-tour section and draws a seam */
  clip-path: inset(-120px 0 0 0);
  /* card-landing entrance: rises in slightly narrowed over the dimmed
     hero, then docks edge-to-edge (home.js completes --cover by half
     the takeover). Defaults to 1 (no JS / reduced motion → no effect). */
  transform-origin: 50% 0;
  transform: scale(calc(1 - (1 - var(--cover, 1)) * 0.04));
  will-change: transform;
}
/* the hero card dims as it's covered (filter set by JS) */
.fx-hero-takeover .fx-hero-card {
  will-change: filter;
}
.fx-hero-card {
  position: relative; overflow: hidden;
  width: 100%;
  display: grid; grid-template-rows: auto 1fr; justify-items: center;
  min-height: min(880px, 100vh);
  background: linear-gradient(135deg, #b9cdf2 0%, #4a86ea 45%, #3d7ae5 100%);
}
.fx-hero-card::before {
  content: ""; position: absolute; inset: 0;
  background: url("../images/homepage-images/Hero bg.webp") center / cover no-repeat;
  z-index: 0;
}
/* soft fade into the next section's background — no hard edge */
.fx-hero-card::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0;
  height: clamp(120px, 22vh, 220px);
  background: linear-gradient(180deg, rgba(245,245,247,0) 0%, rgba(245,245,247,.55) 62%, var(--bg-alt) 100%);
  pointer-events: none; z-index: 2;
}
.fx-hero-copy, .fx-hero-visual { min-width: 0; }
.fx-hero-copy {
  position: relative; z-index: 1; align-self: start; text-align: center;
  padding: clamp(98px, 14vh, 140px) 24px 0;
}
.fx-hero-badge {
  display: inline-block; padding: 7px 18px; border-radius: 999px;
  background: rgba(255,255,255,.18); color: #fff;
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
  border: 1px solid rgba(255,255,255,.25);
  font-weight: 600; font-size: .9rem; margin-bottom: 26px;
}
.fx-hero-title {
  font-size: clamp(2.4rem, 4.2vw, 4rem); font-weight: 600; color: #fff;
  text-shadow: 0 2px 24px rgba(21, 58, 129, .25);
}
.fx-hero-sub { max-width: 46em; margin: 20px auto 0; font-size: clamp(1rem, 1.3vw, 1.18rem); color: rgba(255,255,255,.88); }

/* ═══ INTRO CHOREOGRAPHY (one-time, on load) ═══
   phone rises → title words appear → sub → buttons → trust →
   nav (see header.css) → watermark emerges with a glass shine.
   `backwards` fill keeps each element hidden through its delay
   without locking styles after the animation ends. */
@keyframes hero-rise {
  from { opacity: 0; transform: translateY(26px); filter: blur(10px); }
  to   { opacity: 1; transform: none;             filter: blur(0); }
}
@keyframes hero-phone-in {
  0%   { opacity: 0; transform: translateY(150px) scale(.94); }
  60%  { opacity: 1; }
  78%  { transform: translateY(-10px) scale(1.004); } /* soft overshoot, then settle */
  100% { opacity: 1; transform: translateY(0) scale(1); }
}
.fx-hero-visual { animation: hero-phone-in 1.7s cubic-bezier(.3, .9, .35, 1) .15s backwards; }

/* title appears word by word */
.fx-hero-title .fx-hw { display: inline-block; animation: hero-rise 1.15s var(--ease) backwards; }
.fx-hero-title .fx-hw:nth-child(1) { animation-delay: .75s; }
.fx-hero-title .fx-hw:nth-child(2) { animation-delay: .95s; }
.fx-hero-title .fx-hw:nth-child(3) { animation-delay: 1.15s; }
.fx-hero-title .fx-hw:nth-child(4) { animation-delay: 1.35s; }

.fx-hero-sub { animation: hero-rise 1.15s var(--ease) 1.6s backwards; }
.fx-hero-cta { animation: hero-rise 1.15s var(--ease) 1.9s backwards; }
.fx-hero-trust li { animation: hero-rise .95s var(--ease) backwards; }
.fx-hero-trust li:nth-child(1) { animation-delay: 2.15s; }
.fx-hero-trust li:nth-child(2) { animation-delay: 2.3s; }
.fx-hero-trust li:nth-child(3) { animation-delay: 2.45s; }
.fx-hero-cta { display: flex; gap: 16px; align-items: center; justify-content: center; margin-top: 38px; flex-wrap: wrap; }
.fx-btn-link.fx-light { color: #fff; }

/* ── hero buttons — glass pills that sit on the blue ── */
.fx-btn-hero {
  display: inline-flex; align-items: center; gap: 10px;
  padding: 15px 32px; border-radius: 999px;
  font-weight: 700; font-size: 1rem; letter-spacing: .01em;
  transition: transform .35s var(--ease), box-shadow .35s ease,
              background .35s ease, border-color .35s ease;
}
.fx-btn-hero:hover { transform: translateY(-2px); }
.fx-btn-hero:active { transform: scale(.97); }

/* primary — solid white, same language as the nav Signup over the hero */
.fx-btn-hero.fx-primary {
  background: #fff; color: #0b3ea8;
  box-shadow: 0 12px 30px rgba(10, 35, 90, .32);
}
.fx-btn-hero.fx-primary:hover { box-shadow: 0 16px 38px rgba(10, 35, 90, .42); }

/* secondary — frosted glass, matches the hero badge */
.fx-btn-hero.fx-glass {
  background: rgba(255, 255, 255, .14); color: #fff;
  border: 1.5px solid rgba(255, 255, 255, .32);
  -webkit-backdrop-filter: saturate(160%) blur(12px);
  backdrop-filter: saturate(160%) blur(12px);
  box-shadow: 0 8px 24px rgba(10, 35, 90, .18);
}
.fx-btn-hero.fx-glass:hover {
  background: rgba(255, 255, 255, .24);
  border-color: rgba(255, 255, 255, .6);
  box-shadow: 0 12px 30px rgba(10, 35, 90, .28);
}

/* ── giant glass wordmark behind the phone mockup ── */
.fx-hero-watermark {
  position: absolute; left: 5vw; right: 5vw; top: 51%;
  transform: translateY(-50%);
  z-index: 0; /* above the bg image, below .fx-hero-visual (z:1) */
  /* "Fleet" pins to the left edge, "Rabbit AI" to the right —
     symmetric at any viewport width, phone sits in the gap between them */
  display: flex; justify-content: space-between; align-items: baseline;
  white-space: nowrap;
  pointer-events: none; user-select: none;
  font-weight: 600; letter-spacing: .05em; line-height: 1;
  font-size: clamp(3.6rem, 9.5vw, 15rem);
  filter: blur(0) drop-shadow(0 14px 34px rgba(21, 58, 129, .22));
  animation: watermark-emerge 2.2s cubic-bezier(.22, 1, .36, 1) 2.7s backwards;
}
/* glass: translucent white gradient clipped to the glyphs + frosted edge.
   first layer is an oversized diagonal highlight that wm-shine sweeps
   across the glyphs once — the "reflection moving over glass" moment */
.fx-hero-watermark .fx-wm-word {
  position: relative;
  background:
    linear-gradient(105deg, transparent 42%, rgba(255,255,255,.7) 50%, transparent 58%),
    linear-gradient(180deg, rgba(255,255,255,.62) 0%, rgba(255,255,255,.26) 55%, rgba(255,255,255,.1) 100%);
  background-size: 240% 100%, 100% 100%;
  background-position: 180% 0, 0 0;
  -webkit-background-clip: text; background-clip: text;
  color: transparent;
  -webkit-text-stroke: 1px rgba(255,255,255,.48);
  animation: wm-shine 5.5s ease-in-out 5s; /* long, slow reflection glide */
}
/* "Fleet" nudged in toward the phone — sits closer to it than the left edge */
.fx-hero-watermark .fx-wm-word:first-child { margin-left: 9vw; }
/* bright white copy of each word, revealed through a soft circular mask
   that follows the cursor (--mx/--my set per word by initHero in hero.js) */
.fx-hero-watermark .fx-wm-word::after {
  content: attr(data-text);
  position: absolute; inset: 0;
  background: linear-gradient(180deg, #ffffff 0%, rgba(255,255,255,.75) 100%);
  -webkit-background-clip: text; background-clip: text;
  color: transparent;
  -webkit-text-stroke: 1px rgba(255,255,255,.85);
  filter: drop-shadow(0 0 28px rgba(255,255,255,.6));
  opacity: var(--spot, 0);
  transition: opacity .5s ease;
  -webkit-mask-image: radial-gradient(clamp(160px, 16vw, 300px) circle at var(--mx, 50%) var(--my, 50%),
                      #000 0%, rgba(0,0,0,.5) 48%, transparent 74%);
  mask-image: radial-gradient(clamp(160px, 16vw, 300px) circle at var(--mx, 50%) var(--my, 50%),
              #000 0%, rgba(0,0,0,.5) 48%, transparent 74%);
}
/* condenses out of the background: blurred mist → sharp glass */
@keyframes watermark-emerge {
  from {
    opacity: 0;
    transform: translateY(calc(-50% + 56px)) scale(1.05);
    filter: blur(18px) drop-shadow(0 14px 34px rgba(21, 58, 129, 0));
  }
  to {
    opacity: 1;
    transform: translateY(-50%) scale(1);
    filter: blur(0) drop-shadow(0 14px 34px rgba(21, 58, 129, .22));
  }
}
@keyframes wm-shine {
  from { background-position: 180% 0, 0 0; }
  to   { background-position: -80% 0, 0 0; }
}
@media (prefers-reduced-motion: reduce) {
  .fx-hero-watermark, .fx-hero-watermark .fx-wm-word, .fx-hero-visual, .fx-hero-title .fx-hw,
  .fx-hero-sub, .fx-hero-cta, .fx-hero-trust li { animation: none; }
}

.fx-hero-trust { display: flex; gap: 26px; justify-content: center; margin-top: 30px; flex-wrap: wrap; }
.fx-hero-trust li { display: flex; align-items: center; gap: 7px; font-size: .92rem; color: rgba(255,255,255,.9); font-weight: 500; }
.fx-hero-trust svg { width: 15px; height: 15px; color: #8effb1; }
.fx-hero-visual {
  position: relative; z-index: 1; align-self: end;
  display: flex; justify-content: center;
  padding: 56px 24px 0;
  /* the phone sits left of center inside the mockup image (hand extends right) — shift right to optically center it.
     `left` instead of transform: hero-phone-in animates transform */
  left: clamp(0px, 3vw, 50px);
}
.fx-hero-visual img {
  width: min(520px, 44vw); height: auto;
  filter: drop-shadow(0 34px 60px rgba(10, 35, 90, .45));
}

/* ── DESKTOP: the hero is exactly one screen tall ──
   Row 1 (copy) sizes to its content; row 2 (phone) gets whatever height
   is left and the mockup scales DOWN to fit it — so the whole phone,
   hand included, is always visible above the fold, and the arrangement
   (title → sub → CTAs → trust → phone over the watermark) is identical
   at every PC width, height and aspect ratio. Spacing scales with vh so
   short landscape screens tighten up instead of pushing the phone out. */
@media (min-width: 861px) {
  .fx-hero-card {
    height: 100vh; height: 100svh;
    min-height: 640px;
    grid-template-rows: auto minmax(0, 1fr);
  }
  /* shorter bottom fade so less of the hand is washed out */
  .fx-hero-card::after { height: clamp(90px, 15vh, 170px); }
  .fx-hero-copy  { padding-top: clamp(88px, 12vh, 140px); }
  .fx-hero-sub   { margin-top: clamp(12px, 2vh, 20px); }
  .fx-hero-cta   { margin-top: clamp(22px, 3.5vh, 38px); }
  .fx-hero-trust { margin-top: clamp(16px, 2.8vh, 30px); }
  .fx-hero-visual {
    align-self: stretch; min-height: 0;
    align-items: flex-end;
    padding: clamp(20px, 4vh, 56px) 24px 0;
  }
  .fx-hero-visual img {
    width: auto; height: auto;
    max-height: 100%;
    /* cap grows with viewport height so tall screens don't leave an
       empty band above the phone; width-capped on narrow windows */
    max-width: min(44vw, clamp(560px, 52vh, 720px));
  }
  /* sits behind the upper body of the phone — tracks the phone row,
     which starts lower on tall screens than on short ones */
  .fx-hero-watermark { top: 60%; }
}

@media (max-width: 860px) {
  .fx-hero { padding: 0; }
  .fx-hero-card { grid-template-columns: 1fr; min-height: min(780px, 100vh); text-align: center; }
  /* portrait sky gradient for phone screens — the landscape one crops badly at tall aspect ratios */
  .fx-hero-card::before { background-image: url("../images/homepage-images/HeroPhonebg.webp"); }
  .fx-hero-copy { padding: 130px clamp(22px, 6vw, 48px) 8px; }
  .fx-hero-title { font-size: clamp(1.9rem, 7.2vw, 3rem); }
  /* smaller, tighter subtitle on phones */
  .fx-hero-sub { margin: 12px auto 0; font-size: clamp(.82rem, 3.4vw, .95rem); max-width: 34em; }
  .fx-hero-cta, .fx-hero-trust { justify-content: center; }
  /* buttons share one row — small, simple, sized to their label */
  .fx-hero-cta { gap: 10px; margin-top: 20px; flex-wrap: nowrap; }
  .fx-btn-hero {
    flex: 0 1 auto; min-width: 0;
    justify-content: center; white-space: nowrap;
    padding: 10px 18px; font-size: clamp(.8rem, 3.4vw, .9rem);
  }
  /* trust badges hidden on phones — they crowd the hero */
  .fx-hero-trust { display: none; }
  .fx-hero-visual { padding-top: 28px; }
  .fx-hero-visual img { width: min(460px, 94vw); }
  /* sit behind the upper body of the phone mockup, clear of the trust badges */
  .fx-hero-watermark {
    top: 50%; font-size: clamp(2.2rem, 11vw, 4.4rem); letter-spacing: .03em;
    left: 0; right: 0; justify-content: center; gap: .35em;
    filter: drop-shadow(0 8px 20px rgba(21, 58, 129, .1));
  }
  /* much fainter on phones — barely-there glass */
  .fx-hero-watermark .fx-wm-word {
    background: linear-gradient(180deg, rgba(255,255,255,.22) 0%, rgba(255,255,255,.07) 55%, rgba(255,255,255,.02) 100%);
    -webkit-background-clip: text; background-clip: text;
    -webkit-text-stroke: 1px rgba(255,255,255,.14);
    animation: none;
  }
  /* centered on phones — no desktop nudge */
  .fx-hero-watermark .fx-wm-word:first-child { margin-left: 0; }
}

/* ===== duo.css ===== */
/* ═══════════════════════════════════════════════
   DUO — cinematic layered hero stage
   Layers (back → front):
     1 .fx-duo-photo   full photo (desk + people, white bg)
     2 .fx-duo-glow    blue screen-light + desk reflection
     3 .fx-duo-ui      live glass panels
     4 .fx-duo-cutout  people only (bg removed) — panels tuck BEHIND them
   The stage is full-bleed; 1em tracks viewport width so the
   UI scales with the photo. Panels sized in em, placed in %.
   Capsule tabs swap all three panels to the chosen module:
     .fx-duo-intro  (left)   heading + subtext
     .fx-duo-main   (middle) paragraph + portal/page buttons
     .fx-duo-side   (right)  one .fx-duo-card per module, unique mini-UI
   ═══════════════════════════════════════════════ */

.fx-duo {
  background: #fff;
  padding: clamp(70px, 8vw, 120px) 0 0;
  overflow: hidden;
}

/* ───────── heading (mirrors the hero copy) ───────── */
.fx-duo-head {
  width: min(1400px, 96vw);
  margin: 0 auto;
  text-align: center;
}
.fx-duo-title {
  /* vw-scaled so the full line always fits the viewport on one line */
  font-size: clamp(1.6rem, 3.55vw, 3.6rem);
  white-space: nowrap;
  letter-spacing: -0.03em; line-height: 1.08; font-weight: 700;
}
.fx-duo-nowrap { white-space: nowrap; }
.fx-duo-grad {
  background: linear-gradient(100deg, #1d4ed8 0%, #2f80ee 45%, #aacdf8 100%);
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent; color: transparent;
}
.fx-duo-sub {
  margin: 20px auto 0; max-width: 44em;
  font-size: clamp(1rem, 1.35vw, 1.25rem); color: var(--ink-2);
}
.fx-duo-trust {
  display: flex; justify-content: center; gap: 26px; flex-wrap: wrap;
  margin-top: 26px; padding: 0; list-style: none;
}
.fx-duo-trust li {
  display: inline-flex; align-items: center; gap: 7px;
  font-size: 0.9rem; font-weight: 500; color: var(--ink-2);
}
.fx-duo-trust svg { width: 14px; height: 14px; color: var(--green); }

/* ── feature capsules — swap the stage panels ── */
.fx-duo-tabs {
  display: flex; justify-content: center; flex-wrap: wrap; gap: 9px;
  margin-top: 28px;
}
.fx-duo-tab {
  appearance: none; cursor: pointer;
  padding: 9px 18px; border-radius: 999px;
  border: 1px solid rgba(0, 113, 227, 0.3);
  background: linear-gradient(180deg, #f3f9ff, #e6f1fd);
  color: #0a5bb5;
  box-shadow: 0 2px 8px -3px rgba(0, 113, 227, 0.3);
  font-family: inherit; font-size: 0.86rem; font-weight: 600; letter-spacing: -0.01em;
  transition: color .25s, border-color .25s, background .25s, box-shadow .25s, transform .25s;
}
.fx-duo-tab:hover {
  color: #084a94; border-color: rgba(0, 113, 227, 0.55);
  background: linear-gradient(180deg, #e9f3ff, #d8e9fc);
  box-shadow: 0 5px 14px -4px rgba(0, 113, 227, 0.4);
  transform: translateY(-1px);
}
.fx-duo-tab.fx-is-active {
  color: #fff; border-color: transparent;
  background: linear-gradient(135deg, #1d4ed8, #2f80ee);
  box-shadow: 0 8px 20px -6px rgba(29, 78, 216, 0.5);
}

/* dots under the capsules — phone-carousel position indicator
   (duo.js fills one <i> per module; only the ≤640px layout shows them) */
.fx-duo-dots {
  display: none; justify-content: center; align-items: center; gap: 6px;
  margin-top: 4px;
}
.fx-duo-dots i {
  width: 6px; height: 6px; border-radius: 999px;
  background: rgba(29, 29, 31, 0.18);
  transition: width .3s var(--ease), background .3s;
}
.fx-duo-dots i.fx-on {
  width: 18px;
  background: linear-gradient(90deg, #1d4ed8, #2f80ee);
}

/* heading entrance */
.fx-duo-head > * { opacity: 0; transform: translateY(22px); transition: opacity .7s var(--ease), transform .7s var(--ease); }
.fx-duo-head .fx-duo-sub { transition-delay: .08s; }
.fx-duo-head .fx-duo-trust { transition-delay: .16s; }
.fx-duo-head .fx-duo-tabs { transition-delay: .24s; }
.fx-duo-head .fx-duo-dots { transition-delay: .3s; }
.fx-duo.fx-duo-in .fx-duo-head > * { opacity: 1; transform: none; }

/* ───────── stage · full-bleed ───────── */
.fx-duo-stage {
  position: relative;
  width: 100%;
  margin-top: clamp(10px, 2.4vw, 34px);
  /* 1em ≈ 1.14% of viewport width → panels scale with the photo */
  font-size: clamp(5px, 1.14vw, 24px);
}
.fx-duo-photo, .fx-duo-cutout {
  width: 100%; height: auto; display: block;
  opacity: 0; transform: scale(1.02);
  transition: opacity 1s var(--ease), transform 1.4s var(--ease);
}
.fx-duo-photo { position: relative; z-index: 1; }
.fx-duo-cutout {
  position: absolute; inset: 0; z-index: 4; pointer-events: none;
}
.fx-duo.fx-duo-in .fx-duo-photo, .fx-duo.fx-duo-in .fx-duo-cutout { opacity: 1; transform: none; }

/* ── blue screen-light + reflection on the desk (depth) ── */
.fx-duo-glow {
  position: absolute; inset: 0; z-index: 2; pointer-events: none;
  background:
    /* light spilling in the void between them */
    radial-gradient(38% 34% at 44% 26%, rgba(37, 99, 235, 0.18), transparent 72%),
    radial-gradient(30% 28% at 62% 16%, rgba(56, 162, 255, 0.14), transparent 70%),
    radial-gradient(26% 24% at 28% 34%, rgba(103, 76, 255, 0.09), transparent 70%),
    /* reflection pooling on the desk */
    radial-gradient(30% 9% at 50% 84%, rgba(37, 99, 235, 0.16), transparent 75%);
  filter: blur(14px);
  opacity: 0; transition: opacity 1.6s ease .3s;
}
.fx-duo.fx-duo-in .fx-duo-glow { opacity: 1; }

/* ───────── glass panels ───────── */
.fx-duo-ui { position: absolute; inset: 0; z-index: 3; pointer-events: none; }

.fx-duo-panel {
  position: absolute;
  background: rgba(250, 252, 255, 0.74);
  -webkit-backdrop-filter: blur(24px) saturate(1.8);
  backdrop-filter: blur(24px) saturate(1.8);
  border: 1px solid rgba(255, 255, 255, 0.9);
  border-radius: 1.35em;
  box-shadow:
    0 2.6em 5em -1.6em rgba(17, 45, 120, 0.42),
    0 0.6em 1.6em rgba(17, 45, 120, 0.08),
    inset 0 1px 0 rgba(255, 255, 255, 0.95);
  color: var(--ink);
  opacity: 0;
}
.fx-duo.fx-duo-in .fx-duo-panel { animation: duoRise 1.1s var(--ease) both; }
.fx-duo.fx-duo-in .fx-duo-main  { animation-delay: .25s; }
.fx-duo.fx-duo-in .fx-duo-agent { animation-delay: .45s; }
.fx-duo.fx-duo-in .fx-duo-side  { animation-delay: .6s; }

/* final keyframe keeps the live parallax var + per-panel depth,
   so scroll drift keeps working after the entrance settles */
@keyframes duoRise {
  from {
    opacity: 0;
    transform: translate3d(0, calc(var(--py, 0) * 1px + 2.6em), 0) scale(calc(var(--sc, 1) * 0.92));
    filter: blur(14px);
  }
  to {
    opacity: var(--op, 1);
    transform: translate3d(0, calc(var(--py, 0) * 1px), 0) scale(var(--sc, 1));
    filter: blur(var(--rest-blur, 0px));
  }
}

/* ── middle · plain centered column: heading → story → actions ──
   no glass box — the panel chrome is stripped so the copy floats
   over the stage; only the buttons keep their pill styling */
.fx-duo-main {
  /* 23em column: 1.5em clear of both card inner edges (cards sit at ±12.5em) */
  left: calc(50% - 11.5em); top: 7%; width: 23em; z-index: 3;
  padding: 0; text-align: center;
  background: none; border: none; box-shadow: none;
  -webkit-backdrop-filter: none; backdrop-filter: none;
  --py-rate: -0.08;
}
.fx-duo-main-inner { transition: opacity .4s ease, transform .4s var(--ease); }
.fx-duo-main-inner.fx-swap-out { opacity: 0; transform: translateY(0.6em); }
.fx-duo-main-para {
  font-size: 0.98em; line-height: 1.6; color: #3a3a3e; font-weight: 500;
  max-width: 100%; margin: 0 auto 1.3em; min-height: 6.5em;
}
.fx-duo-main-btns { display: flex; justify-content: center; gap: 0.8em; }
.fx-duo-main-btn {
  display: flex; align-items: center; justify-content: center; gap: 0.5em;
  padding: 0.78em 1.3em; white-space: nowrap;
  border-radius: 0.8em; text-decoration: none;
  background: linear-gradient(135deg, #1d4ed8, #2b8fee);
  color: #fff; font-size: 0.78em; font-weight: 700; letter-spacing: -0.01em;
  box-shadow: 0 0.6em 1.6em -0.5em rgba(29, 78, 216, 0.55);
  pointer-events: auto;
  transition: transform .25s var(--ease), box-shadow .25s, background .25s;
}
.fx-duo-main-btn:hover {
  transform: translateY(-2px);
  box-shadow: 0 0.9em 2em -0.5em rgba(29, 78, 216, 0.65);
}
.fx-duo-main-btn svg { width: 1.15em; height: 1.15em; transition: transform .25s var(--ease); }
.fx-duo-main-btn:hover svg { transform: translateX(0.2em); }
.fx-duo-main-btn.fx-ghost {
  background: rgba(255, 255, 255, 0.85);
  color: var(--accent);
  border: 1.5px solid rgba(0, 113, 227, 0.45);
  box-shadow: none;
}
.fx-duo-main-btn.fx-ghost:hover {
  background: rgba(0, 113, 227, 0.07);
  box-shadow: none;
}

/* ── module heading · tops the centered column ── */
.fx-duo-intro { margin-bottom: 1em; }
.fx-duo-intro-inner { transition: opacity .4s ease, transform .4s var(--ease); }
.fx-duo-intro-inner.fx-swap-out { opacity: 0; transform: translateY(0.6em); }
.fx-duo-kicker {
  display: inline-block;
  font-size: 0.62em; font-weight: 800; letter-spacing: 0.14em; text-transform: uppercase;
  color: #0a5bb5; background: rgba(0, 113, 227, 0.12);
  padding: 0.45em 1.1em; border-radius: 999px;
}
.fx-duo-intro-title {
  font-size: 2.7em; font-weight: 700; letter-spacing: -0.025em; line-height: 1.1;
  margin: 0.35em 0 0;
}
/* the short one-liner is retired from view — the paragraph below
   carries the info now; the element stays in the DOM for duo.js */
.fx-duo-intro-sub { display: none; }

/* ── left · AI-agent action card (mirror of the right card) ── */
.fx-duo-agent {
  /* exact mirror of .fx-duo-side: inner edge at 50% − 12.5em, same top, same box */
  left: calc(50% - 30em); top: 21%; width: 17.5em; height: 17em; z-index: 2;
  padding: 1.7em 1.5em 1.6em;
  --py-rate: -0.16;
}

/* ── right · per-module mini-UI (crisp, same plane as the main card) ── */
.fx-duo-side {
  left: calc(50% + 12.5em); top: 21%; width: 17.5em; height: 17em; z-index: 2;
  padding: 1.7em 1.5em 1.6em;
  --py-rate: -0.16;
}
.fx-duo-card { display: none; position: relative; }
/* fill the fixed-height panel: header top, footer pinned to the bottom edge,
   so every module's card shares one silhouette */
.fx-duo-card.fx-on { display: flex; flex-direction: column; height: 100%; }

.fx-duo-side-head {
  display: flex; align-items: center; justify-content: space-between; gap: 0.6em;
  margin-bottom: 0.9em;
}
.fx-duo-side-head strong { font-size: 0.88em; letter-spacing: -0.01em; white-space: nowrap; }
.fx-duo-side-tag {
  font-size: 0.62em; font-weight: 700; text-transform: uppercase; letter-spacing: 0.08em;
  padding: 0.35em 0.9em; border-radius: 999px; white-space: nowrap;
}
.fx-duo-side-tag.fx-green { color: #1d8a44; background: rgba(48, 209, 88, 0.14); }
.fx-duo-side-tag.fx-blue { color: #0a5bb5; background: rgba(0, 113, 227, 0.12); }
.fx-duo-side-tag.fx-red { color: #b3261e; background: rgba(255, 59, 48, 0.12); }
.fx-duo-side-foot {
  display: flex; align-items: baseline; gap: 0.55em;
  margin-top: auto; padding-top: 1em;
  border-top: 1px solid rgba(29, 29, 31, 0.07);
}
.fx-duo-side-foot b { font-size: 1.05em; letter-spacing: -0.01em; font-variant-numeric: tabular-nums; }
.fx-duo-side-foot span { font-size: 0.68em; color: var(--ink-2); font-weight: 600; }

/* inspections · checklist */
.fx-duo-check { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.5em; }
.fx-duo-check li { display: flex; align-items: center; gap: 0.6em; font-size: 0.78em; font-weight: 600; }
.fx-duo-check li i {
  width: 1.5em; height: 1.5em; border-radius: 50%; flex: none;
  display: grid; place-items: center; font-style: normal;
  background: rgba(48, 209, 88, 0.15); color: #1d8a44;
}
.fx-duo-check li i::before { content: '✓'; font-size: 0.8em; font-weight: 800; }
.fx-duo-check li.fx-amber i { background: rgba(255, 159, 10, 0.16); color: #9a6200; }
.fx-duo-check li.fx-amber i::before { content: '!'; }
.fx-duo-prog {
  height: 0.55em; border-radius: 999px; overflow: hidden;
  background: rgba(29, 29, 31, 0.07); margin-top: 0.95em;
}
.fx-duo-prog i {
  display: block; height: 100%; width: var(--w, 0%);
  border-radius: inherit;
  background: linear-gradient(90deg, #5be08a, #1d8a44);
}

/* dvir + recalls + agent · report rows */
.fx-duo-rows { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.55em; }
.fx-duo-rows li {
  display: flex; justify-content: space-between; gap: 0.8em;
  font-size: 0.76em; padding: 0.6em 0.85em;
  background: rgba(255, 255, 255, 0.75);
  border: 1px solid rgba(29, 29, 31, 0.06);
  border-radius: 0.7em; white-space: nowrap;
}
.fx-duo-rows li span { color: var(--ink-2); font-weight: 600; }
.fx-duo-rows li b { font-weight: 700; }
.fx-duo-rows b.fx-ok { color: #1d8a44; }
.fx-duo-rows b.fx-warn { color: #b3261e; }
.fx-duo-stamp {
  position: absolute; right: 0.4em; bottom: 0.1em;
  padding: 0.25em 0.75em;
  border: 0.18em solid #1d8a44; border-radius: 0.5em;
  color: #1d8a44; background: rgba(255, 255, 255, 0.55);
  font-size: 0.92em; font-weight: 800; text-transform: uppercase; letter-spacing: 0.12em;
  transform: rotate(-8deg);
}

/* maintenance + parts · level meters */
.fx-duo-meter { margin-bottom: 0.7em; }
.fx-duo-meter:last-of-type { margin-bottom: 0; }
.fx-duo-meter-top {
  display: flex; justify-content: space-between; gap: 0.6em;
  font-size: 0.74em; font-weight: 600; margin-bottom: 0.35em;
}
.fx-duo-meter-top span { color: var(--ink-2); }
.fx-duo-meter-top b { font-weight: 700; font-variant-numeric: tabular-nums; }
.fx-duo-meter-bar { height: 0.5em; border-radius: 999px; overflow: hidden; background: rgba(29, 29, 31, 0.07); }
.fx-duo-meter-bar i {
  display: block; height: 100%; width: var(--w, 0%);
  border-radius: inherit;
  background: linear-gradient(90deg, #7cc0ff, #0071e3);
}
.fx-duo-meter.fx-amber .fx-duo-meter-bar i { background: linear-gradient(90deg, #ffd08a, #ff9f0a); }
.fx-duo-meter.fx-amber .fx-duo-meter-top b { color: #9a6200; }

/* compliance · score ring */
.fx-duo-ringwrap { display: flex; align-items: center; gap: 1.1em; }
.fx-duo-ringbox { position: relative; width: 6.2em; height: 6.2em; flex: none; }
.fx-duo-ring { width: 100%; height: 100%; transform: rotate(-90deg); }
.fx-duo-ring circle { fill: none; stroke-width: 8; }
.fx-duo-ring-bg { stroke: rgba(29, 29, 31, 0.07); }
.fx-duo-ring-val {
  stroke: #0071e3; stroke-linecap: round;
  stroke-dasharray: 213.6; stroke-dashoffset: 4.3;
}
.fx-duo-ring-num {
  position: absolute; inset: 0; display: grid; place-items: center;
  font-size: 1.15em; font-weight: 800; letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
}
.fx-duo-ring-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.5em; }
.fx-duo-ring-list li { display: flex; align-items: center; gap: 0.5em; font-size: 0.74em; font-weight: 600; }
.fx-duo-ring-list li::before {
  content: '✓';
  width: 1.4em; height: 1.4em; border-radius: 50%;
  display: grid; place-items: center;
  background: rgba(48, 209, 88, 0.15); color: #1d8a44;
  font-size: 0.8em; font-weight: 800;
}

/* hos · duty clock */
.fx-duo-hos-big { margin: 0.1em 0 0.85em; }
.fx-duo-hos-big b { display: block; font-size: 1.7em; letter-spacing: -0.02em; font-variant-numeric: tabular-nums; }
.fx-duo-hos-big span { font-size: 0.68em; color: var(--ink-2); font-weight: 600; }
.fx-duo-seg { display: flex; gap: 0.25em; height: 0.8em; }
.fx-duo-seg i { width: var(--w, 0%); border-radius: 999px; }
.fx-duo-seg .fx-drive { background: linear-gradient(90deg, #7cc0ff, #0071e3); }
.fx-duo-seg .fx-brk { background: #30d158; }
.fx-duo-seg .fx-rest { background: rgba(29, 29, 31, 0.1); }
.fx-duo-seg-key { list-style: none; margin: 0.6em 0 0; padding: 0; display: flex; gap: 1em; }
.fx-duo-seg-key li {
  display: flex; align-items: center; gap: 0.4em;
  font-size: 0.64em; font-weight: 600; color: var(--ink-2); white-space: nowrap;
}
.fx-duo-seg-key li::before { content: ''; width: 0.7em; height: 0.7em; border-radius: 50%; }
.fx-duo-seg-key .fx-drive::before { background: #0071e3; }
.fx-duo-seg-key .fx-brk::before { background: #30d158; }
.fx-duo-seg-key .fx-rest::before { background: rgba(29, 29, 31, 0.18); }

/* dispatch · live route map */
.fx-duo-route-map { width: 100%; height: 5.4em; display: block; margin-bottom: 0.85em; }
.fx-duo-route-shadow { stroke: rgba(37, 99, 235, 0.16); stroke-width: 5.5; stroke-linecap: round; }
.fx-duo-route-line {
  stroke: #0071e3; stroke-width: 2.4; stroke-linecap: round;
  stroke-dasharray: 5 4;
  animation: duoRouteFlow 1.6s linear infinite;
}
@keyframes duoRouteFlow { to { stroke-dashoffset: -18; } }
.fx-duo-route-a { fill: #a6a9b3; }
.fx-duo-route-b { fill: #0071e3; }
.fx-duo-route-dot { fill: #0071e3; stroke: #fff; stroke-width: 1.4; }
/* dispatch card has no footer — the meta row pins to the bottom instead */
.fx-duo-route-meta { display: flex; justify-content: space-between; gap: 0.6em; margin-top: auto; }
.fx-duo-route-meta div { text-align: center; flex: 1; }
.fx-duo-route-meta b {
  display: block; font-size: 1.25em; letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums; transition: color .3s;
}
.fx-duo-route-meta b.fx-tick { color: var(--accent); }
.fx-duo-route-meta span { display: block; font-size: 0.6em; color: var(--ink-2); font-weight: 600; margin-top: 0.1em; }

/* recalls · pulsing alert dot */
.fx-duo-alert {
  display: inline-block; width: 0.6em; height: 0.6em; border-radius: 50%;
  background: #ff3b30; margin-right: 0.45em; vertical-align: 0.05em;
  animation: duoPulseRed 1.6s ease-in-out infinite;
}
@keyframes duoPulseRed {
  0%, 100% { box-shadow: 0 0 0 0.2em rgba(255, 59, 48, 0.18); }
  50% { box-shadow: 0 0 0 0.55em rgba(255, 59, 48, 0.04); }
}

/* ── ghost graph · faded chrome-less chart in the void between the people ──
   No card, no glass — just soft data breathing behind the panels so the
   stage feels alive. One svg per module; the capsule tabs swap them
   (display none → block re-runs the entrance). Hidden on phone. */
.fx-duo-ghost {
  /* edge to edge — the ends tuck behind the people cutout (z-4) */
  position: absolute;
  left: 0; top: 56%;
  width: 100%; height: 9.9em;
  z-index: 1; pointer-events: none;
  opacity: 0; transition: opacity 1.4s ease .9s;
}
.fx-duo.fx-duo-in .fx-duo-ghost { opacity: 1; }
.fx-duo-ghost svg { position: absolute; inset: 0; width: 100%; height: 100%; }
.fx-duo-ghost svg[data-graph] { display: none; }
.fx-duo-ghost svg[data-graph].fx-on { display: block; }
.fx-duo.fx-duo-in .fx-duo-ghost svg[data-graph].fx-on { animation: duoGhostIn .9s var(--ease) both; }
@keyframes duoGhostIn { from { opacity: 0; transform: translateY(1.2em); } }

/* shared chart furniture — gridlines + weekday axis, always under the graph */
.fx-duo-ghost .fx-gh-base { stroke: rgba(29, 29, 31, 0.1); stroke-width: 1.5; }
.fx-duo-ghost .fx-gh-gridline {
  stroke: rgba(29, 29, 31, 0.055); stroke-width: 1;
  stroke-dasharray: 3 6;
}
.fx-duo-ghost .fx-gh-axis {
  fill: rgba(29, 29, 31, 0.28);
  font-family: inherit; font-size: 8px; font-weight: 700; letter-spacing: 0.12em;
  text-anchor: middle;
}

/* equalizer / column bars — slow staggered breathing */
.fx-duo-ghost .fx-gh-bar {
  fill: rgba(37, 99, 235, 0.2);
  transform-box: fill-box; transform-origin: 50% 100%;
  animation: duoGhostEq 3.8s ease-in-out calc(var(--i, 0) * -0.42s) infinite;
}
.fx-duo-ghost .fx-gh-bar.fx-alt { fill: rgba(56, 162, 255, 0.13); }
@keyframes duoGhostEq {
  0%, 100% { transform: scaleY(1); }
  50% { transform: scaleY(var(--q, 0.7)); }
}

/* dvir · drifting waves (paths carry one extra 176-unit period past the
   right edge; −176px loops seamlessly) */
.fx-duo-ghost .fx-gh-wave { animation: duoGhostDrift 10s linear infinite; }
.fx-duo-ghost .fx-gh-wave.fx-w1 { fill: rgba(47, 128, 238, 0.15); }
.fx-duo-ghost .fx-gh-wave.fx-w2 { fill: rgba(47, 128, 238, 0.09); animation-duration: 16s; animation-direction: reverse; }
@keyframes duoGhostDrift { to { transform: translateX(-176px); } }

/* trend + staircase lines — draw themselves in on each swap */
.fx-duo-ghost .fx-gh-line {
  fill: none; stroke: rgba(37, 99, 235, 0.32);
  stroke-width: 2.6; stroke-linecap: round; stroke-linejoin: round;
}
.fx-duo-ghost .fx-gh-area { fill: rgba(47, 128, 238, 0.1); }
.fx-duo.fx-duo-in .fx-duo-ghost svg.fx-on .fx-gh-draw {
  stroke-dasharray: 1; /* with pathLength="1" one dash covers the path */
  animation: duoGhostDraw 1.8s var(--ease) .15s both;
}
@keyframes duoGhostDraw { from { stroke-dashoffset: 1; } to { stroke-dashoffset: 0; } }

/* dots · data nodes, waypoints, travelers, radar ping */
.fx-duo-ghost .fx-gh-node {
  fill: rgba(250, 252, 255, 0.9);
  stroke: rgba(37, 99, 235, 0.45); stroke-width: 1.6;
  transform-box: fill-box; transform-origin: center;
  animation: duoGhostNode .5s cubic-bezier(.34, 1.56, .64, 1) both;
  animation-delay: calc(var(--i, 0) * 0.28s + .3s);
}
@keyframes duoGhostNode { from { transform: scale(0); } }
.fx-duo-ghost .fx-gh-stop { fill: rgba(37, 99, 235, 0.4); }
.fx-duo-ghost .fx-gh-mover { fill: rgba(37, 99, 235, 0.55); stroke: rgba(255, 255, 255, 0.85); stroke-width: 1.3; }
.fx-duo-ghost .fx-gh-ping {
  fill: rgba(37, 99, 235, 0.3);
  transform-box: fill-box; transform-origin: center;
  animation: duoGhostPing 2.2s ease-out infinite;
}
@keyframes duoGhostPing {
  from { transform: scale(0.4); opacity: 1; }
  to { transform: scale(2.4); opacity: 0; }
}

/* hos · duty bands — soft glow pulse, staggered per row */
.fx-duo-ghost .fx-gh-band { animation: duoGhostGlow 4.4s ease-in-out calc(var(--i, 0) * -1.3s) infinite; }
.fx-duo-ghost .fx-gh-band.fx-drive { fill: rgba(37, 99, 235, 0.22); }
.fx-duo-ghost .fx-gh-band.fx-brk { fill: rgba(48, 209, 88, 0.28); }
.fx-duo-ghost .fx-gh-band.fx-rest { fill: rgba(29, 29, 31, 0.07); }
@keyframes duoGhostGlow { 0%, 100% { opacity: 1; } 50% { opacity: 0.45; } }

/* dispatch · wide faded route */
.fx-duo-ghost .fx-gh-route-shadow { stroke: rgba(37, 99, 235, 0.1); stroke-width: 6; stroke-linecap: round; fill: none; }
.fx-duo-ghost .fx-gh-route {
  stroke: rgba(37, 99, 235, 0.34); stroke-width: 2.4; stroke-linecap: round; fill: none;
  stroke-dasharray: 6 5;
  animation: duoGhostFlow 1.8s linear infinite;
}
@keyframes duoGhostFlow { to { stroke-dashoffset: -22; } }

/* recalls · heartbeat trace (2-period path scrolls left forever) */
.fx-duo-ghost .fx-gh-ecg {
  fill: none; stroke: rgba(37, 99, 235, 0.32);
  stroke-width: 2.4; stroke-linecap: round; stroke-linejoin: round;
  animation: duoGhostDrift 7s linear infinite;
}

/* ── card entrance choreography — restarts on every tab switch
   (display:none → block re-runs the animations; --d staggers per element) ── */
@keyframes duoItem { from { opacity: 0; transform: translateY(0.6em); } }
@keyframes duoPop { from { transform: scale(0); } }
@keyframes duoGrow { from { width: 0; } }
@keyframes duoStampIn { from { opacity: 0; transform: rotate(-14deg) scale(1.7); } }
@keyframes duoRingIn { from { stroke-dashoffset: 213.6; } }

.fx-duo.fx-duo-in .fx-duo-card.fx-on .fx-duo-side-head,
.fx-duo.fx-duo-in .fx-duo-card.fx-on .fx-duo-check li,
.fx-duo.fx-duo-in .fx-duo-card.fx-on .fx-duo-rows li,
.fx-duo.fx-duo-in .fx-duo-card.fx-on .fx-duo-meter,
.fx-duo.fx-duo-in .fx-duo-card.fx-on .fx-duo-prog,
.fx-duo.fx-duo-in .fx-duo-card.fx-on .fx-duo-ringwrap,
.fx-duo.fx-duo-in .fx-duo-card.fx-on .fx-duo-hos-big,
.fx-duo.fx-duo-in .fx-duo-card.fx-on .fx-duo-seg,
.fx-duo.fx-duo-in .fx-duo-card.fx-on .fx-duo-seg-key,
.fx-duo.fx-duo-in .fx-duo-card.fx-on .fx-duo-route-map,
.fx-duo.fx-duo-in .fx-duo-card.fx-on .fx-duo-route-meta,
.fx-duo.fx-duo-in .fx-duo-card.fx-on .fx-duo-side-foot {
  animation: duoItem .5s var(--ease) both;
  animation-delay: var(--d, 0s);
}
.fx-duo.fx-duo-in .fx-duo-card.fx-on .fx-duo-check li i {
  animation: duoPop .45s cubic-bezier(.34, 1.56, .64, 1) both;
  animation-delay: calc(var(--d, 0s) + .18s);
}
.fx-duo.fx-duo-in .fx-duo-card.fx-on .fx-duo-prog i,
.fx-duo.fx-duo-in .fx-duo-card.fx-on .fx-duo-meter-bar i,
.fx-duo.fx-duo-in .fx-duo-card.fx-on .fx-duo-seg i {
  animation: duoGrow .9s var(--ease) both;
  animation-delay: calc(var(--d, 0s) + .25s);
}
.fx-duo.fx-duo-in .fx-duo-card.fx-on .fx-duo-stamp {
  animation: duoStampIn .55s cubic-bezier(.34, 1.56, .64, 1) both;
  animation-delay: .5s;
}
.fx-duo.fx-duo-in .fx-duo-card.fx-on .fx-duo-ring-val {
  animation: duoRingIn 1.2s var(--ease) both;
  animation-delay: .25s;
}

/* ───────── small screens: same arrangement as desktop ─────────
   All three panels stay, in their desktop positions, so the stage
   reads identically on phone — just scaled down with the photo.
   Lower size floor so the three-card row clears a 320px viewport. */
@media (max-width: 640px) {
  .fx-duo-stage { font-size: clamp(4px, 1.14vw, 24px); }
  /* phone: generous air above AND below so the section breathes —
     desktop keeps the full-bleed photo touching the next section,
     but at phone scale that read as one cramped strip */
  .fx-duo { padding: clamp(64px, 16vw, 96px) 0 clamp(56px, 15vw, 88px); }
  /* big two-line heading — wrap is allowed again, .fx-duo-nowrap keeps
     "Entire Fleet" together, taller line-height for the stacked lines */
  .fx-duo-title {
    white-space: normal;
    font-size: clamp(1.5rem, 7vw, 2.1rem);
    line-height: 1.16;
  }
  /* phone: drop the subtitle — title + trust row carry the message */
  .fx-duo-sub { display: none; }
  /* trust row: one small vw-scaled line — all three fit even at 320px */
  .fx-duo-trust {
    margin-top: 16px;
    flex-wrap: nowrap;
    gap: clamp(8px, 2.6vw, 14px);
  }
  .fx-duo-trust li {
    font-size: clamp(0.55rem, 2.7vw, 0.8rem);
    white-space: nowrap;
    gap: 4px;
  }
  .fx-duo-trust svg { width: 1.15em; height: 1.15em; }

  /* capsules → center-mode cover-flow strip: one snap-centered row,
     looped by duo.js clones so it scrolls left AND right from the start;
     faded edges + peeking neighbors + dots say "this scrolls" */
  .fx-duo-tabs {
    flex-wrap: nowrap; justify-content: flex-start; gap: 8px;
    overflow-x: auto; overscroll-behavior-x: contain;
    scroll-snap-type: x mandatory;
    /* vertical padding must fit the 1.12-scaled center pill AND its
       0 8px 20px shadow — the overflow clip slices anything past it */
    padding: 12px 50% 28px;
    scrollbar-width: none;
    -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 15%, #000 85%, transparent 100%);
    mask-image: linear-gradient(90deg, transparent 0, #000 15%, #000 85%, transparent 100%);
  }
  .fx-duo-tabs::-webkit-scrollbar { display: none; }
  .fx-duo-tab {
    flex: none; scroll-snap-align: center;
    padding: 7px 13px; font-size: 0.78rem;
    /* --cf / --cfo come from duo.js per scroll frame: the button nearest
       the middle rides at full size, neighbors shrink + dim (cover flow) */
    transform: scale(var(--cf, 1));
    opacity: var(--cfo, 1);
    transition: color .25s, border-color .25s, background .25s, box-shadow .25s;
  }
  .fx-duo-dots { display: flex; }

  /* rhythm: even, breathable gaps — heading → trust → capsules → stage */
  .fx-duo-trust { margin-top: 26px; }
  .fx-duo-tabs { margin-top: 20px; }
  /* negative margin swallows the strip's shadow-room padding so the
     visual gap to the dots stays the same as before */
  .fx-duo-dots { margin-top: -8px; }
  /* headroom for the info card, which floats up out of the photo —
     extra-tall so the photo rides lower and the people/hands clear
     the card's buttons (card lifts by the same amount, see .fx-duo-main) */
  .fx-duo-stage { margin-top: clamp(110px, 32vw, 190px); }

  /* ── stage · phone: the module story becomes a real glass card ──
     the two mini-cards are desktop garnish — at phone scale (stage em
     ≈ 4px) they're unreadable, so they step aside and the center info
     re-bases its em on the viewport and gets the panel chrome back,
     so it reads as a clean card over the photo instead of loose text */
  .fx-duo-agent, .fx-duo-side { display: none; }
  /* ghost graph stays on phone — it fills the void between the two
     people, under the floating card, so the stage doesn't feel empty */
  .fx-duo-ghost {
    left: 50%; transform: translateX(-50%);
    top: 52%;
    width: 74vw; height: 21vw;
  }
  .fx-duo-main {
    font-size: clamp(9px, 2.5vw, 14px);
    width: min(38em, 92vw);
    left: 0; right: 0; margin: 0 auto;
    /* lifted well off the photo's top edge — paired with the taller
       stage margin so the buttons sit in the void ABOVE the people's
       hands instead of being covered by the cutout */
    top: -26vw;
    padding: 1.7em 1.5em 1.9em;
    background: rgba(250, 252, 255, 0.78);
    -webkit-backdrop-filter: blur(14px) saturate(1.6);
    backdrop-filter: blur(14px) saturate(1.6);
    border: 1px solid rgba(255, 255, 255, 0.9);
    border-radius: 1.5em;
    box-shadow:
      0 1.8em 3.6em -1.4em rgba(17, 45, 120, 0.38),
      inset 0 1px 0 rgba(255, 255, 255, 0.95);
  }
  .fx-duo-main-para { max-width: 26em; margin: 0 auto 1.4em; }
  .fx-duo-intro { margin-bottom: 0.9em; }
  .fx-duo-intro-title { margin-top: 0.45em; }
  .fx-duo-main-btn { font-size: 0.88em; padding: 0.85em 1.5em; }
  .fx-duo-kicker { font-size: 0.7em; padding: 0.5em 1.2em; }
}

@media (prefers-reduced-motion: reduce) {
  .fx-duo-head > *, .fx-duo-photo, .fx-duo-cutout, .fx-duo-glow { opacity: 1; transform: none; transition: none; }
  .fx-duo-panel { opacity: var(--op, 1); transform: scale(var(--sc, 1)); filter: blur(var(--rest-blur, 0px)); }
  .fx-duo.fx-duo-in .fx-duo-panel { animation: none; }
  .fx-duo.fx-duo-in .fx-duo-card.fx-on *, .fx-duo-alert, .fx-duo-live i, .fx-duo-route-line { animation: none !important; }
  /* ghost graph: freeze every loop; gh-draw paths fall back to fully drawn
     (dashoffset's natural value is 0) and the svg entrance snaps to visible */
  .fx-duo-ghost, .fx-duo-ghost * { animation: none !important; transition: none !important; }
  .fx-duo.fx-duo-in .fx-duo-ghost { opacity: 1; }
}

/* ===== bookcall.css ===== */
/* ═══════════════════════════════════════════════
   BOOK A CALL — orange Calendly panel (after hero)
   ═══════════════════════════════════════════════ */
.fx-bookcall { padding: 0; }

.fx-bc-card {
  position: relative;
  width: 100%;
  border-radius: 0;
  overflow: hidden;
  background: #fff;
  isolation: isolate;
}

.fx-bc-stripes { display: none; }

/* ───────── content ───────── */
.fx-bc-inner {
  position: relative; z-index: 2;
  display: flex; flex-direction: column; align-items: center;
  text-align: center;
  padding: clamp(48px, 7vw, 84px) 6vw clamp(52px, 7vw, 88px);
}

.fx-bc-chip {
  display: inline-flex; align-items: center; gap: 9px;
  background: #fff; border: 1px solid #e6e9ef; border-radius: 999px;
  padding: 7px 16px 7px 8px;
  font-size: .92rem; font-weight: 600; color: var(--ink);
  box-shadow: 0 6px 18px rgba(15, 30, 60, .06);
}
.fx-bc-chip img {
  width: 26px; height: 26px; border-radius: 50%; object-fit: cover;
  background: #f5f5f7;
}

.fx-bc-title {
  margin-top: clamp(20px, 3vw, 32px);
  font-size: clamp(2rem, 5.4vw, 4.6rem);
  line-height: 1.02; letter-spacing: -0.03em;
  color: var(--ink, #0f1e3c);
}
.fx-bc-title em {
  font-style: normal;
  color: var(--accent, #2563eb);
}

.fx-bc-sub {
  margin-top: clamp(16px, 2.4vw, 26px);
  font-size: clamp(1rem, 1.5vw, 1.22rem);
  color: #5b6572;
  line-height: 1.55;
}
.fx-bc-sub strong { color: var(--ink, #0f1e3c); }

.fx-bc-btn {
  display: inline-flex; align-items: center; gap: 10px;
  margin-top: clamp(26px, 3.4vw, 40px);
  padding: 15px 34px;
  border-radius: 999px;
  background: var(--accent, #2563eb); color: #fff;
  font-weight: 700; font-size: 1.05rem; white-space: nowrap;
  box-shadow: 0 10px 26px rgba(37, 99, 235, .28);
  transition: transform .35s var(--ease), box-shadow .35s var(--ease);
}
.fx-bc-btn svg { width: 19px; height: 19px; }
.fx-bc-btn:hover { transform: translateY(-2px); box-shadow: 0 14px 34px rgba(37, 99, 235, .36); }
.fx-bc-btn:active { transform: scale(.97); }

@media (max-width: 720px) {
  .fx-bc-sub br { display: none; }
}

/* ===== logos.css ===== */
/* =========== TRUSTED BY - CHIP MARQUEE ===========
   Two opposing rows of white chip cards flowing over a blueprint-style
   blue line grid. Neutral ink at rest, accent blue blooms in on hover. */
/* start in the previous section's gray and dissolve into white — no hard seam. */
.fx-logos {
  position: relative;
  isolation: isolate;
  padding: 72px 0 76px;
  background: linear-gradient(180deg, var(--bg-alt) 0%, var(--bg) clamp(220px, 32vh, 320px), var(--bg) 100%);
}

/* ── person cutout: background image on the section's left side ──
   Bottom-anchored at the screen's left edge, painted BEHIND the
   marquee chips and text (z-index -1 in the section's stacking
   context). His right side is softly mask-faded so the chips
   scrolling past him blend instead of clashing. */
.fx-logos::before {
  content: "";
  position: absolute;
  z-index: -1;
  left: 0;
  bottom: 0;
  width: clamp(260px, 26vw, 430px);
  aspect-ratio: 902 / 1329;
  background: url("../images/homepage-images/personbg.webp") left bottom / contain no-repeat;
  -webkit-mask-image: linear-gradient(105deg, #000 55%, rgba(0, 0, 0, .4) 78%, transparent 96%);
  mask-image: linear-gradient(105deg, #000 55%, rgba(0, 0, 0, .4) 78%, transparent 96%);
  pointer-events: none;
}
.fx-logos-kicker { text-align: center; }
.fx-logos-title { text-align: center; font-size: clamp(1.5rem, 2.8vw, 2.2rem); max-width: 26em; margin: 0 auto; }
.fx-logos-sub { text-align: center; color: var(--ink-2); margin: 18px auto 0; }

.fx-logo-band {
  margin-top: 56px; padding: 48px 0;
  display: grid; gap: 22px;
  overflow: hidden; position: relative;
  /* blue line grid, fading into the page background top and bottom */
  background:
    linear-gradient(180deg, var(--bg), rgba(255, 255, 255, 0) 30%, rgba(255, 255, 255, 0) 70%, var(--bg)),
    linear-gradient(rgba(0, 113, 227, .08) 1px, transparent 1px) 0 0 / 44px 44px,
    linear-gradient(90deg, rgba(0, 113, 227, .08) 1px, transparent 1px) 0 0 / 44px 44px;
  /* fade the band edges, not each row, so both rows share one mask */
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
}

.fx-logo-row {
  display: flex; gap: 18px; width: max-content;
  animation: logo-scroll 38s linear infinite;
  will-change: transform;
}
.fx-logo-row.fx-reverse { animation-direction: reverse; animation-duration: 46s; }
/* pause both rows together so a chip can be read / hovered */
.fx-logo-band:hover .fx-logo-row { animation-play-state: paused; }
@keyframes logo-scroll { to { transform: translateX(-50%); } }

/* -- chip card -- */
/* each chip carries its brand hue in --c (set inline in the HTML) */
.fx-logo-chip {
  --c: var(--accent);
  display: inline-flex; align-items: center; gap: 12px;
  padding: 10px 24px 10px 10px; white-space: nowrap; cursor: default;
  background: #fff; border-radius: 999px;
  border: 1px solid rgba(15, 30, 60, .1);
  box-shadow: 0 1px 2px rgba(15, 30, 60, .05), 0 8px 20px -14px rgba(15, 30, 60, .18);
  transition: transform .4s var(--ease), box-shadow .4s var(--ease), border-color .35s ease, opacity .5s var(--ease);
}
.fx-logo-chip:hover {
  transform: translateY(-4px) scale(1.02);
  border-color: color-mix(in srgb, var(--c) 45%, #fff);
  box-shadow: 0 14px 30px -10px color-mix(in srgb, var(--c) 38%, transparent);
}

/* monogram badge — soft brand tint at rest, solid brand color on hover */
.fx-chip-mono {
  display: grid; place-items: center; flex: none;
  width: 38px; height: 38px; border-radius: 50%;
  font-size: .78rem; font-weight: 800; letter-spacing: .02em;
  color: var(--c);
  background: color-mix(in srgb, var(--c) 10%, #fff);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--c) 16%, transparent);
  transition: background .35s ease, color .35s ease, box-shadow .35s ease;
}
.fx-logo-chip:hover .fx-chip-mono {
  background: var(--c); color: #fff;
  box-shadow: 0 6px 14px -6px color-mix(in srgb, var(--c) 60%, transparent);
}

.fx-logo-chip strong {
  font-size: 1.02rem; font-weight: 700; letter-spacing: -0.015em;
  color: var(--ink); transition: color .35s ease;
}
.fx-logo-chip:hover strong { color: var(--c); }

/* -- credibility stats under the band -- */
.fx-logo-stats {
  margin-top: 34px;
  display: flex; flex-wrap: wrap; justify-content: center;
  gap: 20px clamp(36px, 7vw, 88px);
  text-align: center;
}
.fx-logo-stats .fx-stat {
  display: grid; gap: 3px;
  transition: transform .65s var(--ease), opacity .6s var(--ease);
}
.fx-logo-stats strong {
  font-size: clamp(1.55rem, 2.6vw, 2.15rem);
  font-weight: 700; letter-spacing: -.02em; line-height: 1.1;
}
.fx-logo-stats span { font-size: .92rem; font-weight: 500; color: var(--ink-2); }

/* ═══════════ SCROLL ENTRANCE (toggled by logos.js) ═══════════
   Until the band scrolls into view the chips sit low and faded and
   the stats are hidden. When .fx-logos-in lands the chips pop up one
   after another (the delay cycles every 8 chips, so both marquee rows
   and their duplicated halves stagger the same way) and the stats
   rise in left to right. .fx-logos-settled drops the delays afterwards
   so chip hover stays instant. Replays in both directions. */
.fx-logos:not(.fx-logos-in) .fx-logo-chip {
  opacity: 0;
  transform: translateY(22px) scale(.88);
}
.fx-logos:not(.fx-logos-in) .fx-logo-stats .fx-stat {
  opacity: 0;
  transform: translateY(26px);
}
.fx-logo-chip:nth-child(8n+1) { --chip-d: .04s; }
.fx-logo-chip:nth-child(8n+2) { --chip-d: .09s; }
.fx-logo-chip:nth-child(8n+3) { --chip-d: .14s; }
.fx-logo-chip:nth-child(8n+4) { --chip-d: .19s; }
.fx-logo-chip:nth-child(8n+5) { --chip-d: .24s; }
.fx-logo-chip:nth-child(8n+6) { --chip-d: .29s; }
.fx-logo-chip:nth-child(8n+7) { --chip-d: .34s; }
.fx-logo-chip:nth-child(8n+8) { --chip-d: .39s; }
.fx-logos.fx-logos-in:not(.fx-logos-settled) .fx-logo-chip {
  transition-duration: .55s;
  transition-delay: var(--chip-d, 0s);
}
/* the second (reverse) row trails the first by a beat */
.fx-logos.fx-logos-in:not(.fx-logos-settled) .fx-logo-row.fx-reverse .fx-logo-chip {
  transition-delay: calc(var(--chip-d, 0s) + .3s);
}
.fx-logos.fx-logos-in:not(.fx-logos-settled) .fx-logo-stats .fx-stat:nth-child(1) { transition-delay: .55s; }
.fx-logos.fx-logos-in:not(.fx-logos-settled) .fx-logo-stats .fx-stat:nth-child(2) { transition-delay: .67s; }
.fx-logos.fx-logos-in:not(.fx-logos-settled) .fx-logo-stats .fx-stat:nth-child(3) { transition-delay: .79s; }
.fx-logos.fx-logos-in:not(.fx-logos-settled) .fx-logo-stats .fx-stat:nth-child(4) { transition-delay: .91s; }

@media (max-width: 860px) {
  /* less dead gap above the section, more air inside it */
  .fx-logos { padding: 44px 0 64px; }
  .fx-logos::before { display: none; }
  .fx-logos-sub { margin-top: 14px; }
  .fx-logo-band { margin-top: 46px; padding: 40px 0; gap: 20px; background-size: auto, 36px 36px, 36px 36px; }
  .fx-logo-row { gap: 14px; }
  .fx-logo-chip { padding: 8px 18px 8px 8px; }
  .fx-chip-mono { width: 32px; height: 32px; font-size: .7rem; }
  .fx-logo-chip strong { font-size: .92rem; }
  /* stats as a tidy 2×2 grid */
  .fx-logo-stats { margin-top: 40px; display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 30px 16px; }
  .fx-logo-stats strong { font-size: 1.45rem; }
  .fx-logo-stats span { font-size: .8rem; }
}

@media (prefers-reduced-motion: reduce) {
  /* static, wrapped, centered list — no motion at all */
  .fx-logo-band { mask-image: none; -webkit-mask-image: none; }
  .fx-logo-row { animation: none; width: auto; flex-wrap: wrap; justify-content: center; row-gap: 14px; }
  .fx-logo-row.fx-reverse { display: none; }
  .fx-logo-chip:hover { transform: none; }
  .fx-logos:not(.fx-logos-in) .fx-logo-chip { opacity: 1; transform: none; }
  .fx-logos:not(.fx-logos-in) .fx-logo-stats .fx-stat { opacity: 1; transform: none; }
}

/* ===== dashcam.css ===== */
/* =========== DASHCAM AI — PRODUCT SPOTLIGHT ===========
   Ad-style hero card: big two-line headline, the transparent dashcam
   floating over a blue gradient pill, outlined ghost pills clipped at
   the screen edges, and a divider-separated feature strip below. */
.fx-dashcam {
  position: relative;
  padding: 84px 0 90px;
  /* dissolve out of the white logos section into a soft studio gray and back */
  background: linear-gradient(180deg, var(--bg) 0%, var(--bg-alt) 18%, var(--bg-alt) 84%, var(--bg) 100%);
  overflow: hidden; /* keep the ghost pills from widening the page */
}

.fx-dashcam-wrap { text-align: center; }

.fx-dashcam-title {
  font-size: clamp(2.2rem, 5.4vw, 4rem);
  line-height: 1.06;
  margin: 0 auto;
  position: relative;
  z-index: 1;
}

/* ── product stage ── */
.fx-dashcam-stage {
  position: relative;
  z-index: 2;
  /* sit fully below the headline so the camera never covers "AI Dashcam." */
  margin-top: clamp(12px, 2vw, 24px);
}

.fx-dashcam-img {
  position: relative;
  z-index: 2;
  width: min(560px, 78%);
  margin: 0 auto;
  filter: drop-shadow(0 34px 44px rgba(8, 28, 60, .38));
  transition: transform .8s var(--ease);
}
.fx-dashcam-stage:hover .fx-dashcam-img { transform: translateY(-8px) scale(1.015); }

/* blue gradient pill behind the camera — bright glow at top center,
   deepening toward the edges */
.fx-dashcam-card {
  position: absolute;
  z-index: 1;
  left: 50%;
  top: 46%;
  transform: translateX(-50%);
  width: min(700px, 96%);
  height: 46%;
  border-radius: clamp(26px, 4vw, 44px);
  background: radial-gradient(140% 190% at 50% -25%, #d7ebff 0%, #6fadf5 34%, #2478e6 68%, #115ac9 100%);
  box-shadow: 0 30px 60px -28px rgba(17, 90, 201, .55);
}

/* outlined ghost pills clipped by the section edges */
.fx-dashcam-ghost {
  position: absolute;
  z-index: 0;
  top: 46%;
  height: 46%;
  width: clamp(120px, 15vw, 220px);
  border: 1.5px solid rgba(0, 113, 227, .5);
  border-radius: clamp(26px, 4vw, 44px);
}
/* anchored past the viewport edge so only a sliver peeks in, like the ad */
.fx-ghost-left { left: calc(50% - 50vw - clamp(60px, 8vw, 130px)); }
.fx-ghost-right { right: calc(50% - 50vw - clamp(60px, 8vw, 130px)); }

/* ── feature strip ── */
.fx-dashcam-feats {
  margin-top: clamp(44px, 7vw, 72px);
  display: flex;
  justify-content: center;
  align-items: center;
}
.fx-dc-feat {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 6px clamp(24px, 4.5vw, 56px);
}
.fx-dc-feat + .fx-dc-feat { border-left: 1px solid rgba(15, 30, 60, .16); }
.fx-dc-feat strong {
  font-size: clamp(1rem, 1.4vw, 1.18rem);
  font-weight: 600;
  letter-spacing: -0.015em;
  color: var(--ink);
  white-space: nowrap;
}

.fx-dc-ico {
  flex: none;
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  color: var(--accent);
}
.fx-dc-ico svg { width: 24px; height: 24px; }
/* first icon: solid blue rounded square with a white spark */
.fx-dc-ico-solid {
  background: linear-gradient(160deg, #2f86ef, #0b63d8);
  border-radius: 10px;
  color: #fff;
  box-shadow: 0 8px 18px -8px rgba(0, 113, 227, .6);
}
.fx-dc-ico-solid svg { width: 18px; height: 18px; }
.fx-dc-ico-dark { color: #123c78; }

/* ── closing copy ── */
.fx-dashcam-note {
  margin-top: clamp(34px, 5vw, 52px);
  color: var(--ink-2);
  font-size: clamp(.95rem, 1.2vw, 1.05rem);
}
.fx-dashcam-url {
  margin-top: clamp(40px, 6vw, 64px);
  color: #9a9aa1;
  font-size: .95rem;
  letter-spacing: .01em;
}

@media (max-width: 860px) {
  .fx-dashcam { padding: 56px 0 64px; }
  .fx-dashcam-stage { margin-top: 10px; }
  .fx-dashcam-img { width: min(420px, 92%); }
  .fx-dashcam-card { width: 100%; }
  .fx-dashcam-ghost { display: none; }
  /* stack the features, dividers become soft horizontal rules */
  .fx-dashcam-feats { flex-direction: column; gap: 4px; }
  .fx-dc-feat { width: min(280px, 100%); justify-content: flex-start; padding: 12px 6px; }
  .fx-dc-feat + .fx-dc-feat { border-left: 0; border-top: 1px solid rgba(15, 30, 60, .12); }
  .fx-dashcam-note br { display: none; }
}

/* ── entrance choreography ──
   The shared reveal system toggles .fx-in on .fx-dashcam-stage (two-way, so it
   replays every time the section scrolls back in). The stage itself stays
   put; its layers come in one after another: the blue card pops up from
   the centre, the ghost pills slide in from the screen edges, and only
   then does the camera rise out of the card and settle. Standalone
   translate/scale are used so the hover `transform` on the image and the
   centring transform on the card are never fought. */
.fx-dashcam-stage.fx-reveal { opacity: 1; transform: none; transition: none; }

.fx-dashcam-card {
  opacity: 0; scale: .72;
  transition: opacity .6s var(--ease), scale .75s cubic-bezier(.22, 1, .36, 1);
}
.fx-dashcam-ghost {
  opacity: 0;
  transition: opacity .7s var(--ease), translate .9s cubic-bezier(.22, 1, .36, 1);
}
.fx-ghost-left  { translate: -70px 0; }
.fx-ghost-right { translate:  70px 0; }
.fx-dashcam-img {
  opacity: 0; translate: 0 90px; scale: .86;
  transition:
    opacity .7s var(--ease),
    translate 1s cubic-bezier(.22, 1, .36, 1),
    scale 1s cubic-bezier(.22, 1, .36, 1),
    transform .8s var(--ease); /* keeps the hover lift */
}

.fx-dashcam-stage.fx-in .fx-dashcam-card  { opacity: 1; scale: 1; transition-delay: .05s; }
.fx-dashcam-stage.fx-in .fx-dashcam-ghost { opacity: 1; translate: 0 0; transition-delay: .3s; }
.fx-dashcam-stage.fx-in .fx-dashcam-img   { opacity: 1; translate: 0 0; scale: 1; transition-delay: .5s; }
/* feature strip and copy follow the camera instead of racing it */
.fx-dashcam-feats.fx-reveal.fx-in { transition-delay: .9s; }
.fx-dashcam-note.fx-reveal.fx-in  { transition-delay: 1.05s; }

@media (prefers-reduced-motion: reduce) {
  .fx-dashcam-stage:hover .fx-dashcam-img { transform: none; }
  .fx-dashcam-card, .fx-dashcam-ghost, .fx-dashcam-img {
    opacity: 1; translate: none; scale: none; transition: none;
  }
  .fx-dashcam-feats.fx-reveal.fx-in, .fx-dashcam-note.fx-reveal.fx-in { transition-delay: 0s; }
}

/* ===== portal.css ===== */
/* ═══════════════════════════════════════════════
   AI PORTAL — hanging banner board section
   The board drops in from the top (like a sign being
   lowered on its wires) when the section scrolls into view.
   Uses the shared .fx-reveal / .fx-in observer from home.js.
   Sits flush between Spend and Why — no background of its
   own, and the artwork's empty bottom half is cropped away
   so the section blends into its neighbours.
   ═══════════════════════════════════════════════ */

.fx-portal-banner {
  padding: clamp(20px, 4vw, 44px) 24px 0;
  overflow: hidden;
}

.fx-pb-stage {
  max-width: 900px;
  margin: 0 auto;
  overflow: hidden;
  /* source art is 1672×941; the board + its shadow end at ≈y 780,
     the rest is empty white — crop only that off */
  aspect-ratio: 1672 / 790;
}

.fx-pb-art {
  width: 100%;
  height: auto;
  display: block;
  transform-origin: top center;
  /* melt the artwork's white background into the page */
  mix-blend-mode: multiply;
}

/* ── copy + actions under the board ── */
.fx-pb-copy {
  max-width: 720px;
  margin: clamp(28px, 4vw, 48px) auto clamp(60px, 8vw, 120px);
  text-align: center;
}

.fx-pb-para {
  font-size: 1.08rem;
  line-height: 1.65;
  color: #55606f;
}

.fx-pb-actions {
  margin-top: 30px;
  display: flex;
  justify-content: center;
  flex-wrap: wrap;
  gap: 14px;
}

.fx-pb-btn-outline {
  color: var(--accent);
  border: 1.5px solid var(--accent);
  background: #fff;
}
.fx-pb-btn-outline:hover { background: rgba(0, 113, 227, .06); }

/* drop-from-top: override the shared reveal's upward slide */
.fx-portal-banner .fx-pb-art.fx-reveal {
  opacity: 0;
  transform: translateY(-140px);
  transition:
    opacity .7s var(--ease),
    transform 1.1s cubic-bezier(.34, 1.45, .64, 1); /* slight overshoot = settle bounce */
}

.fx-portal-banner .fx-pb-art.fx-reveal.fx-in {
  opacity: 1;
  transform: translateY(0);
}

@media (prefers-reduced-motion: reduce) {
  .fx-portal-banner .fx-pb-art.fx-reveal {
    opacity: 1;
    transform: none;
    transition: none;
  }
}

/* ===== why.css ===== */
/* ═══════════ PORTAL MOCKUP · desktop only, above Why Choose ═══════════ */
.fx-why-portal { padding: 96px 0 0; background: var(--bg); }
.fx-portal-intro { margin-bottom: 56px; }
.fx-portal-intro h2 { font-size: clamp(1.9rem, 3.4vw, 2.7rem); }
.fx-portal-points {
  margin-top: 26px;
  display: flex; justify-content: center; flex-wrap: wrap;
  gap: 10px 12px;
}
.fx-portal-points span {
  padding: 9px 18px; border-radius: 999px;
  background: #fff; border: 1px solid rgba(15, 30, 60, .08);
  box-shadow: 0 1px 2px rgba(15, 30, 60, .04);
  font-size: .82rem; font-weight: 600; color: #3a4a63;
}
.fx-why-portal img {
  width: 100%; height: auto;
  border-radius: 24px;
  border: 1px solid rgba(15, 30, 60, .08);
  box-shadow:
    0 2px 6px rgba(15, 30, 60, .06),
    0 18px 36px -12px rgba(15, 30, 60, .14),
    0 44px 80px -24px rgba(15, 30, 60, .24);
}

/* ═══════════ WHY CHOOSE · image left / points right ═══════════ */
.fx-why { padding: 150px 0 110px; background: var(--bg); }

.fx-why-grid {
  display: grid;
  grid-template-columns: minmax(0, .92fr) minmax(0, 1.08fr);
  gap: clamp(36px, 6vw, 84px);
  align-items: center;
}

/* ── left · photo card: shows the full mockup photo uncropped;
       the card takes the image's natural aspect ratio ── */
.fx-why-visual {
  border-radius: 24px; overflow: hidden;
  border: 1px solid rgba(15, 30, 60, .08);
  box-shadow:
    0 2px 6px rgba(15, 30, 60, .06),
    0 18px 36px -12px rgba(15, 30, 60, .16),
    0 44px 80px -24px rgba(15, 30, 60, .28);
}
.fx-why-visual img {
  display: block;
  width: 100%; height: auto;
}
/* ── right · numbered points separated by hairlines ── */
.fx-why-copy h2 { font-size: clamp(1.9rem, 3.4vw, 2.7rem); max-width: 14em; }

.fx-why-rows { margin-top: 18px; display: grid; }
.fx-why-row {
  display: flex; align-items: baseline;
  gap: clamp(20px, 2.5vw, 32px);
  padding: 30px 0;
  border-bottom: 1px solid rgba(15, 30, 60, .07);
}
.fx-why-row:last-child { border-bottom: 0; padding-bottom: 0; }

/* minimal index — just a small blue figure, no box */
.fx-why-num {
  flex: 0 0 auto; min-width: 2em;
  font-size: .85rem; font-weight: 700; line-height: 1;
  letter-spacing: .08em;
  color: var(--accent-2);
  font-variant-numeric: tabular-nums;
}

.fx-why-row h3 { font-size: clamp(1.05rem, 1.5vw, 1.22rem); font-weight: 650; margin-bottom: 7px; }
.fx-why-row p { color: var(--ink-2); font-size: .93rem; line-height: 1.65; max-width: 44em; }

/* ── responsive · stack with the image on top ── */
@media (max-width: 900px) {
  /* portal mockup is desktop-only */
  .fx-why-portal { display: none; }
  .fx-why { padding: 64px 0 76px; }
  .fx-why-grid { grid-template-columns: 1fr; gap: 36px; }
  .fx-why-visual { max-width: 440px; margin: 0 auto; width: 100%; }
  /* centered layout on phones */
  .fx-why-copy { text-align: center; }
  .fx-why-copy h2 { max-width: none; }
  .fx-why-row {
    flex-direction: column; align-items: center;
    gap: 10px; padding: 26px 0;
  }
  .fx-why-num { min-width: 0; }
  .fx-why-row p { max-width: 36em; margin: 0 auto; }
}

/* ===== reviews.css ===== */
/* ═══════════ REVIEWS · 3-column vertical marquee ═══════════
   Columns drift continuously — outer two upward, middle one downward.
   Each track holds its card set twice; translating by half the track
   (plus half the gap) loops seamlessly. Hover pauses all three. */
/* start in the previous section's white and dissolve into gray — no hard seam */
.fx-reviews {
  padding: 110px 0; overflow: hidden;
  background: linear-gradient(180deg, var(--bg) 0%, var(--bg-alt) clamp(220px, 30vh, 320px), var(--bg-alt) 100%);
}

/* ── header · heading left, data right ── */
.fx-reviews-head {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: 40px; flex-wrap: wrap;
}
.fx-reviews-title h2 { font-size: clamp(1.9rem, 3.4vw, 2.7rem); max-width: 15em; }
.fx-review-stats { display: flex; gap: clamp(32px, 4.5vw, 72px); }
.fx-review-stats .fx-stat { display: grid; gap: 3px; text-align: center; }
.fx-review-stats strong {
  font-size: clamp(1.9rem, 3vw, 2.6rem); font-weight: 800;
  letter-spacing: -.02em; line-height: 1.1;
}
.fx-review-stats .fx-stars { font-size: .9rem; letter-spacing: 2px; color: var(--amber); }
.fx-review-stats .fx-stat > span:last-child { font-size: .88rem; font-weight: 500; color: var(--ink-2); }

/* ── marquee ── */
.fx-review-marquee {
  margin-top: 56px;
  display: grid; grid-template-columns: repeat(3, 1fr);
  gap: 20px;
  height: 620px;
  /* cards dissolve at the top and bottom edges */
  -webkit-mask-image: linear-gradient(180deg, transparent, #000 12%, #000 88%, transparent);
  mask-image: linear-gradient(180deg, transparent, #000 12%, #000 88%, transparent);
}
.fx-review-col { overflow: hidden; }
.fx-review-track {
  display: grid; gap: 20px;
  animation: reviewScroll 26s linear infinite;
  will-change: transform;
}
/* half the track + half the gap = exactly one card-set — seamless loop */
@keyframes reviewScroll { to { transform: translateY(calc(-50% - 10px)); } }
.fx-review-col.fx-down .fx-review-track { animation-direction: reverse; animation-duration: 32s; }
.fx-review-col:last-child .fx-review-track { animation-duration: 23s; }
.fx-review-marquee:hover .fx-review-track { animation-play-state: paused; }

/* ── card ── */
.fx-review-card {
  background: #fff; border-radius: 18px; padding: 24px;
  border: 1px solid rgba(15, 30, 60, .07);
  box-shadow: 0 1px 2px rgba(15, 30, 60, .03), 0 14px 34px -22px rgba(15, 30, 60, .12);
  display: flex; flex-direction: column; gap: 14px;
  margin: 0;
}
.fx-review-head { display: flex; align-items: center; gap: 12px; }
.fx-avatar {
  --c: var(--accent-2);
  width: 42px; height: 42px; border-radius: 50%; flex: 0 0 auto;
  display: grid; place-items: center;
  font-weight: 800; font-size: .82rem; letter-spacing: .02em;
  color: var(--c);
  background: color-mix(in srgb, var(--c) 10%, #fff);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--c) 18%, transparent);
}
.fx-review-head strong { display: block; font-size: .94rem; letter-spacing: -.01em; }
.fx-review-head span:not(.fx-avatar) { font-size: .78rem; color: var(--ink-2); }
.fx-review-card p { font-size: .92rem; line-height: 1.6; color: #3a4a63; flex: 1; }
.fx-review-foot { display: flex; align-items: center; justify-content: space-between; }
.fx-review-foot .fx-stars { font-size: .86rem; letter-spacing: 2px; color: var(--amber); }
.fx-review-foot time {
  font-size: .7rem; font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
  color: var(--ink-2); background: var(--bg-alt);
  padding: 5px 10px; border-radius: 999px;
}

/* ── responsive ── */
@media (max-width: 1024px) {
  .fx-review-marquee { grid-template-columns: 1fr 1fr; height: 560px; }
  .fx-review-col:last-child { display: none; }
}
@media (max-width: 640px) {
  .fx-reviews { padding: 72px 0; }
  .fx-reviews-head { justify-content: center; text-align: center; }
  .fx-reviews-title h2 { margin: 0 auto; }
  .fx-review-stats { width: 100%; justify-content: center; }
  .fx-review-marquee { grid-template-columns: 1fr; height: 520px; max-width: 460px; margin: 44px auto 0; }
  .fx-review-col.fx-down { display: none; }
}

/* ── accessibility · static list, duplicates hidden ── */
@media (prefers-reduced-motion: reduce) {
  .fx-review-track { animation: none !important; }
  .fx-review-card.fx-dup { display: none; }
  .fx-review-marquee { height: auto; mask-image: none; -webkit-mask-image: none; }
}

/* ===== faq.css ===== */
/* ═══════════ FAQ · rounded card accordion ═══════════ */
/* start in the reviews section's gray and dissolve into white — no hard seam */
.fx-faq {
  padding: 110px 0 120px;
  background: linear-gradient(180deg, var(--bg-alt) 0%, var(--bg) clamp(200px, 28vh, 300px), var(--bg) 100%);
}
.fx-faq h2 { font-size: clamp(1.9rem, 3.4vw, 2.7rem); }

.fx-faq-list { margin-top: 54px; display: grid; gap: 14px; }

/* ── item card · soft blue pill that grows when opened ── */
.fx-faq-item {
  border-radius: 18px;
  background: #f0f4fc;
  border: 1px solid rgba(37, 99, 235, .07);
  transition: background .35s ease, box-shadow .35s ease;
}
.fx-faq-item:hover { background: #ecf1fb; }
.fx-faq-item.fx-open {
  background: #f4f7fd;
  box-shadow: 0 1px 2px rgba(15, 30, 60, .03), 0 16px 36px -24px rgba(15, 30, 60, .16);
}

/* question row */
.fx-faq-q {
  all: unset; box-sizing: border-box;
  display: block; width: 100%; cursor: pointer;
  position: relative;
  padding: 21px 76px 21px 26px;
  font-family: inherit;
  font-size: clamp(1rem, 1.4vw, 1.13rem); font-weight: 600;
  color: var(--ink); letter-spacing: -.01em; line-height: 1.4;
  transition: color .25s ease;
}
.fx-faq-q:hover { color: var(--accent); }
.fx-faq-q:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; border-radius: 18px; }

/* white circle button · plus rotates into × on open */
.fx-faq-x {
  position: absolute; right: 16px; top: 50%;
  width: 36px; height: 36px; margin-top: -18px;
  border-radius: 50%; background: #fff;
  box-shadow: 0 2px 6px rgba(15, 30, 60, .08), 0 8px 18px -8px rgba(15, 30, 60, .14);
  transition: transform .45s var(--ease);
}
.fx-faq-x::before, .fx-faq-x::after {
  content: ""; position: absolute; background: var(--ink); border-radius: 2px;
  transition: background .3s ease;
}
.fx-faq-x::before { left: 11px; top: 17px; width: 14px; height: 2px; }
.fx-faq-x::after { left: 17px; top: 11px; width: 2px; height: 14px; }
.fx-faq-item.fx-open .fx-faq-x { transform: rotate(135deg); }
.fx-faq-item.fx-open .fx-faq-x::before, .fx-faq-item.fx-open .fx-faq-x::after { background: var(--accent); }

/* answer — 0fr → 1fr grid row animates height smoothly to any content size */
.fx-faq-a {
  display: grid; grid-template-rows: 0fr;
  transition: grid-template-rows .55s var(--ease);
}
.fx-faq-a-inner { overflow: hidden; min-height: 0; }
.fx-faq-a p {
  padding: 0 76px 24px 26px;
  color: var(--ink-2); font-size: .96rem; line-height: 1.65; max-width: 62em;
  opacity: 0; transform: translateY(-6px);
  transition: opacity .4s ease, transform .5s var(--ease);
}
.fx-faq-item.fx-open .fx-faq-a { grid-template-rows: 1fr; }
.fx-faq-item.fx-open .fx-faq-a p { opacity: 1; transform: none; transition-delay: .1s; }

@media (max-width: 640px) {
  .fx-faq { padding: 72px 0 84px; }
  .fx-faq-list { margin-top: 40px; gap: 12px; }
  .fx-faq-q { padding: 18px 62px 18px 20px; }
  .fx-faq-x { right: 12px; width: 32px; height: 32px; margin-top: -16px; }
  .fx-faq-x::before { left: 9px; top: 15px; }
  .fx-faq-x::after { left: 15px; top: 9px; }
  .fx-faq-a p { padding: 0 54px 20px 20px; }
}

@media (prefers-reduced-motion: reduce) {
  .fx-faq-a, .fx-faq-a p, .fx-faq-x, .fx-faq-x::before, .fx-faq-x::after { transition: none; }
}

/* ===== vehicles.css ===== */
/* =========== VEHICLES - WHAT WE SERVE ===========
   Replaces the old "solution" section (parked in assets/dead-code/).
   White section. Big heading + paragraph + glass arrows pinned on the
   left; a side-scroll rail of tall photo cards fills the rest of the
   width and bleeds off the right edge. The copy block sits ABOVE the
   rail with a soft fade on its right edge, so cards slide under it as
   the user scrolls. vehicles.js: arrows, mouse drag, exact --edge. */

#vehicles-root {
  background: #ffffff;
  overflow: hidden;
}
.fx-vehicles {
  --edge: max(16px, calc((100vw - min(1180px, 92vw)) / 2)); /* container inset */
  --copyw: clamp(340px, 37vw, 540px);                         /* left copy column */
  --fade: 140px;                                              /* copy → rail dissolve */
  --gap: 14px;
  --cw: clamp(200px, 17vw, 250px);                            /* card width */
  position: relative;
  padding: clamp(56px, 8vh, 88px) 0 clamp(44px, 6vh, 64px);
}
.fx-veh-body { position: relative; }

/* ── left: copy pinned over the rail ──
   The text sits on top of the cards. Behind the text, a long white
   veil runs from solid at the page edge to clear past the copy, so a
   card scrolling left slides under the words and dissolves smoothly
   instead of being cut off. */
.fx-veh-head {
  position: absolute;
  top: 0; bottom: 0; left: 0;
  z-index: 2;
  width: calc(var(--edge) + var(--copyw));
  padding-left: var(--edge);
  display: flex;
  flex-direction: column;
  justify-content: center;
  text-align: left;
  pointer-events: none;            /* let drags start on cards behind the copy */
}
.fx-veh-head > * { pointer-events: auto; }
.fx-veh-head::before {
  content: "";
  position: absolute;
  top: 0; bottom: 0; left: 0;
  right: calc(-1 * var(--fade));
  z-index: -1;
  background: linear-gradient(90deg,
    #fff 0%,
    #fff 30%,
    rgba(255, 255, 255, .94) 52%,
    rgba(255, 255, 255, .72) 74%,
    rgba(255, 255, 255, .35) 90%,
    rgba(255, 255, 255, 0) 100%);
  pointer-events: none;
}
.fx-vehicles h2 {
  font-size: clamp(2.6rem, 4.6vw, 4.4rem);
  line-height: 1.04;
  max-width: 9em;
}
.fx-vehicles .fx-lead {
  margin-top: 22px;
  font-size: clamp(1.05rem, 1.35vw, 1.3rem);
  max-width: 22em;
}
/* heading + lead rise and de-blur (overrides the generic .fx-reveal) */
.fx-vehicles h2.fx-reveal,
.fx-vehicles .fx-lead.fx-reveal {
  transform: translateY(24px);
  filter: blur(8px);
  transition: opacity .8s var(--ease), transform .8s var(--ease), filter .8s var(--ease);
}
.fx-vehicles .fx-lead.fx-reveal { transition-delay: .1s; }
.fx-vehicles h2.fx-reveal.fx-in,
.fx-vehicles .fx-lead.fx-reveal.fx-in { transform: none; filter: none; }

/* ── frosted-glass arrows, under the paragraph ── */
.fx-veh-nav {
  display: flex;
  gap: 10px;
  margin-top: 34px;
  transition-delay: .25s;
}
.fx-veh-btn {
  width: 50px; height: 50px;
  border-radius: 50%;
  border: 1px solid rgba(15, 30, 60, .1);
  background: rgba(245, 245, 247, .7);
  -webkit-backdrop-filter: blur(14px) saturate(160%);
  backdrop-filter: blur(14px) saturate(160%);
  color: var(--ink);
  display: inline-flex; align-items: center; justify-content: center;
  cursor: pointer;
  box-shadow:
    0 6px 16px -8px rgba(15, 30, 60, .25),
    inset 0 1px 0 rgba(255, 255, 255, .9);
  transition: background .3s, transform .35s var(--ease), box-shadow .35s var(--ease), opacity .3s;
}
.fx-veh-btn svg { width: 19px; height: 19px; }
.fx-veh-btn:hover {
  background: #fff;
  transform: translateY(-1px);
  box-shadow: 0 10px 22px -10px rgba(15, 30, 60, .3), inset 0 1px 0 #fff;
}
.fx-veh-btn:active { transform: scale(.94); }
.fx-veh-btn:disabled { opacity: .35; cursor: default; pointer-events: none; }
.fx-veh-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

/* ── right: the rail ──
   Starts under the copy column; first card sits just past the fade. */
.fx-veh-rail {
  display: flex;
  gap: var(--gap);
  padding: 12px var(--edge) 6px calc(var(--edge) + var(--copyw) + var(--fade));
  overflow-x: auto;
  overflow-y: hidden;
  scroll-snap-type: x mandatory;
  scroll-padding-left: calc(var(--edge) + var(--copyw) + var(--fade));
  overscroll-behavior-x: contain;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
  cursor: grab;
  /* the rail is the .fx-reveal trigger for the card cascade — it never
     hides itself, only its cards do */
  opacity: 1; transform: none; transition: none;
}
.fx-veh-rail::-webkit-scrollbar { display: none; }
.fx-veh-rail.fx-is-dragging { cursor: grabbing; scroll-snap-type: none; }
.fx-veh-rail.fx-is-dragging .fx-veh-link { pointer-events: none; }

.fx-veh-card {
  position: relative;
  flex: 0 0 var(--cw);
  scroll-snap-align: start;
  /* entrance: cards rise in order once the rail is on screen */
  opacity: 0;
  transform: translateY(30px);
  transition: opacity .35s var(--ease), transform .35s var(--ease);
}
.fx-veh-rail.fx-in .fx-veh-card {
  opacity: 1;
  transform: none;
  transition: opacity .7s var(--ease) var(--d, 0s), transform .7s cubic-bezier(.22, 1, .36, 1) var(--d, 0s);
}
.fx-veh-card:nth-child(1) { --d: .04s; }
.fx-veh-card:nth-child(2) { --d: .10s; }
.fx-veh-card:nth-child(3) { --d: .16s; }
.fx-veh-card:nth-child(4) { --d: .22s; }
.fx-veh-card:nth-child(5) { --d: .28s; }
.fx-veh-card:nth-child(6) { --d: .34s; }
.fx-veh-card:nth-child(7) { --d: .40s; }
.fx-veh-card:nth-child(8) { --d: .46s; }
.fx-veh-card:nth-child(9) { --d: .52s; }

.fx-veh-link { display: block; border-radius: 14px; }
.fx-veh-link:focus-visible { outline: 2px solid var(--accent); outline-offset: 4px; }

/* tall rounded photo */
.fx-veh-fig {
  position: relative;
  aspect-ratio: 1 / 1.62;
  border-radius: 14px;
  overflow: hidden;
  background: #e3e4e8;
  transform: translateZ(0);
  transition: transform .6s var(--ease), box-shadow .6s var(--ease);
}
.fx-veh-fig img {
  width: 100%; height: 100%;
  object-fit: cover;
  transform: scale(1.03);
  transition: transform 1s var(--ease);
}
/* soft top scrim so the numeral reads on bright skies */
.fx-veh-fig::after {
  content: "";
  position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(20, 28, 44, .34) 0%, rgba(20, 28, 44, 0) 42%);
  pointer-events: none;
}

/* thin white numeral in the card's top-left */
.fx-veh-num {
  position: absolute;
  z-index: 2;
  top: 6px;
  left: 12px;
  font-size: calc(var(--cw) * .32);
  font-weight: 300;
  letter-spacing: -.02em;
  line-height: 1;
  color: #fff;
  pointer-events: none;
  /* follows its card in, a beat later */
  opacity: 0;
  transform: translateY(10px);
  transition: opacity .6s var(--ease), transform .6s var(--ease);
}
.fx-veh-rail.fx-in .fx-veh-num {
  opacity: 1; transform: none;
  transition-delay: calc(var(--d, 0s) + .2s);
}

/* hover: gentle lift + photo zoom */
.fx-veh-link:hover .fx-veh-fig,
.fx-veh-link:focus-visible .fx-veh-fig {
  transform: translateY(-8px);
  box-shadow: 0 26px 44px -22px rgba(15, 30, 60, .4);
}
.fx-veh-link:hover .fx-veh-fig img,
.fx-veh-link:focus-visible .fx-veh-fig img { transform: scale(1.1); }

/* ── caption: UPPERCASE NAME, then  ── sub ──  ── */
.fx-veh-cap { margin-top: 18px; padding: 0 2px; text-align: center; }
.fx-veh-cap h3 {
  font-size: .8rem;
  font-weight: 600;
  letter-spacing: .09em;
  text-transform: uppercase;
  line-height: 1.35;
  color: var(--ink);
  transition: color .3s;
}
.fx-veh-cap p {
  display: flex; align-items: center; justify-content: center;
  gap: 7px;
  margin-top: 8px;
  font-size: .7rem;
  letter-spacing: .02em;
  color: var(--ink-2);
  white-space: nowrap;
}
.fx-veh-cap p::before,
.fx-veh-cap p::after {
  content: "";
  flex: 1 1 0;
  min-width: 12px;
  max-width: 24px;
  height: 1px;
  background: rgba(29, 29, 31, .32);
  transition: background .3s, max-width .45s var(--ease);
}
.fx-veh-link:hover .fx-veh-cap h3,
.fx-veh-link:focus-visible .fx-veh-cap h3 { color: var(--accent-2); }
.fx-veh-link:hover .fx-veh-cap p::before,
.fx-veh-link:hover .fx-veh-cap p::after,
.fx-veh-link:focus-visible .fx-veh-cap p::before,
.fx-veh-link:focus-visible .fx-veh-cap p::after { background: var(--accent); max-width: 32px; }

/* ── responsive ── */
@media (max-width: 1020px) {
  .fx-vehicles { --copyw: clamp(280px, 38vw, 400px); --cw: clamp(190px, 24vw, 230px); }
  .fx-vehicles h2 { font-size: clamp(2rem, 4.4vw, 3rem); }
  .fx-vehicles .fx-lead { font-size: clamp(.98rem, 1.5vw, 1.12rem); }
}

@media (max-width: 760px) {
  /* stack: copy on top (normal flow), rail below, nothing overlaps */
  .fx-vehicles {
    --cw: 62vw;
    --gap: 12px;
    /* extra air between the hero's rounded edge and the heading */
    padding: 80px 0 44px;
  }
  .fx-veh-head {
    position: static;
    width: auto;
    padding: 0 var(--edge);
  }
  .fx-veh-head::before { display: none; }
  .fx-vehicles h2 { max-width: none; font-size: clamp(2rem, 8.5vw, 2.6rem); }
  .fx-vehicles .fx-lead { max-width: 30em; font-size: 1rem; }
  .fx-veh-nav { margin-top: 20px; }
  .fx-veh-rail {
    margin-top: 28px;
    padding: 10px var(--edge) 6px var(--edge);
    scroll-padding-left: var(--edge);
  }
  .fx-veh-num { font-size: 2.4rem; }
  .fx-veh-cap h3 { font-size: .74rem; }
  .fx-veh-cap p { font-size: .66rem; }
}

@media (prefers-reduced-motion: reduce) {
  .fx-vehicles h2.fx-reveal,
  .fx-vehicles .fx-lead.fx-reveal,
  .fx-veh-card,
  .fx-veh-num {
    opacity: 1; transform: none; filter: none;
    transition: none;
  }
  .fx-veh-fig, .fx-veh-fig img, .fx-veh-btn { transition: none; }
  .fx-veh-link:hover .fx-veh-fig img { transform: scale(1.03); }
  .fx-veh-rail { scroll-behavior: auto; }
}

/* ===== phonetour.css ===== */
/* ═══════════════════════════════════════════════
   PHONE TOUR — Apple-style scroll-driven 3D app tour
   A CSS-built phone rotates through poses while the
   section is pinned; callouts fade in beside it.
   Driven by phonetour.js (lerp-smoothed rAF loop).
   ═══════════════════════════════════════════════ */

.fx-phonetour { background: var(--bg); }

.fx-pt-head { padding: 12vh 0 6vh; }

/* ───────── pinned stage ───────── */
.fx-pt-stage { height: 460vh; position: relative; }
.fx-pt-viewport {
  position: sticky; top: 0; height: 100vh;
  overflow: hidden;
  display: flex; align-items: center; justify-content: center;
  perspective: 1700px;
}
/* world map backdrop — sits behind the phone.
   Parallax: phonetour.js sets --map-shift from scroll progress;
   scaled up so the drifting edges never show. */
.fx-pt-viewport::before {
  content: ""; position: absolute; inset: 0; z-index: 0;
  background: url("../images/homepage-images/World-map.webp") center / contain no-repeat;
  opacity: .18; pointer-events: none;
  transform: translateY(var(--map-shift, 0px)) scale(1.18);
  will-change: transform;
}
.fx-pt-viewport > * { position: relative; }

.fx-pt-fit { transform: scale(1); transform-style: preserve-3d; }
@media (max-height: 740px) { .fx-pt-fit { transform: scale(.82); } }
@media (max-width: 700px)  {
  .fx-pt-fit { transform: scale(.6); }
  /* the scaled-down phone leaves dead space above it inside the
     centered 100vh viewport — close the gap between head and phone */
  .fx-pt-head { padding: 8vh 0 0; }
  .fx-pt-stage { margin-top: -21vh; }
}

/* ───────── the device ───────── */
.fx-pt-phone {
  position: relative;
  width: 300px; height: 610px;
  transform-style: preserve-3d;
  will-change: transform;
}
.fx-pt-layer {
  position: absolute; inset: 0;
  border-radius: 50px;
  background: linear-gradient(180deg, #c9c9ce 0%, #a9a9b0 18%, #bfbfc5 50%, #a2a2a9 84%, #c6c6cb 100%);
}
.fx-pt-face {
  position: absolute; inset: 0;
  border-radius: 50px;
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
}

/* front — FleetRabbit AI app on screen */
.fx-pt-front {
  background: #050506;
  padding: 11px;
  box-shadow: inset 0 0 0 1.5px rgba(255,255,255,.22);
}
.fx-pt-screen {
  position: relative; width: 100%; height: 100%;
  border-radius: 40px; overflow: hidden;
  background:
    radial-gradient(130% 55% at 50% -10%, #dde8ff 0%, rgba(221,232,255,0) 60%),
    #f4f6fb;
  display: flex; flex-direction: column;
}
.fx-pt-island {
  position: absolute; top: 10px; left: 50%; transform: translateX(-50%);
  width: 92px; height: 26px; border-radius: 18px; background: #000; z-index: 2;
}
.fx-pt-statusbar {
  display: flex; justify-content: space-between; align-items: center;
  padding: 14px 24px 0;
  font-size: 13px; font-weight: 700; color: var(--ink);
}
.fx-pt-status-icons { display: flex; align-items: center; gap: 6px; }
.fx-pt-sig { display: flex; gap: 2px; align-items: flex-end; }
.fx-pt-sig i { width: 3px; background: var(--ink); border-radius: 1px; display: block; }
.fx-pt-sig i:nth-child(1) { height: 4px; }
.fx-pt-sig i:nth-child(2) { height: 6px; }
.fx-pt-sig i:nth-child(3) { height: 8px; }
.fx-pt-sig i:nth-child(4) { height: 10px; }
.fx-pt-batt {
  width: 21px; height: 10.5px;
  border: 1.5px solid rgba(29,29,31,.5); border-radius: 3.5px;
  position: relative; display: block;
}
.fx-pt-batt i {
  position: absolute; inset: 1.5px; right: 5px;
  background: var(--ink); border-radius: 1.5px; display: block;
}
.fx-pt-batt::after {
  content: ""; position: absolute; top: 2.5px; right: -3.5px;
  width: 2px; height: 4px;
  background: rgba(29,29,31,.5); border-radius: 0 2px 2px 0;
}

/* stacked app screens — cross-faded by phonetour.js on scroll */
.fx-pt-apps { position: relative; flex: 1; min-height: 0; }
.fx-pt-app {
  position: absolute; inset: 0;
  display: flex; flex-direction: column;
  opacity: 0;
  will-change: opacity, transform;
}
.fx-pt-app:first-child { opacity: 1; }

.fx-pt-appbar {
  display: flex; align-items: center; gap: 8px;
  padding: 18px 18px 0;
  font-size: 15.5px; letter-spacing: -.01em; color: var(--ink);
}
.fx-pt-applogo { width: 24px; height: 24px; object-fit: contain; flex: none; }
.fx-pt-bell {
  margin-left: auto; position: relative;
  width: 30px; height: 30px; border-radius: 50%;
  background: #fff; color: var(--ink);
  display: grid; place-items: center;
  box-shadow: 0 1px 4px rgba(13,20,33,.08);
}
.fx-pt-bell svg { width: 15px; height: 15px; }
.fx-pt-bell::after {
  content: ""; position: absolute; top: 6px; right: 6px;
  width: 7px; height: 7px; border-radius: 50%;
  background: #ff453a; border: 1.5px solid #fff;
}

/* dark vehicle card */
.fx-pt-vehicle {
  margin: 14px 16px 0;
  padding: 15px 16px;
  border-radius: 18px;
  background:
    radial-gradient(120% 140% at 100% 0%, rgba(56,162,255,.28) 0%, transparent 55%),
    linear-gradient(135deg, #14264e 0%, #0b1730 70%);
  display: flex; align-items: center; justify-content: space-between;
  color: #fff;
  box-shadow: 0 12px 26px rgba(11, 23, 48, .28);
}
.fx-pt-veh-chip {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 9.5px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
  color: #7ee2a0; background: rgba(48, 209, 88, .14);
  border-radius: 999px; padding: 3px 9px;
}
.fx-pt-veh-chip::before {
  content: ""; width: 5px; height: 5px; border-radius: 50%;
  background: var(--green); box-shadow: 0 0 6px var(--green);
}
.fx-pt-veh-info h4 { font-size: 17px; font-weight: 700; letter-spacing: -.01em; margin-top: 7px; }
.fx-pt-veh-info p { font-size: 11px; font-weight: 600; color: rgba(255,255,255,.55); margin-top: 2px; }
.fx-pt-veh-ring {
  width: 56px; height: 56px; border-radius: 50%; flex: none;
  background: conic-gradient(#38a2ff 0deg 270deg, rgba(255,255,255,.14) 270deg 360deg);
  display: grid; place-items: center;
  position: relative;
}
.fx-pt-veh-ring::before {
  content: ""; position: absolute; inset: 5px;
  border-radius: 50%; background: #10203f;
}
.fx-pt-veh-ring span { position: relative; font-size: 12.5px; font-weight: 700; }

/* checklist */
.fx-pt-sec-label {
  display: flex; justify-content: space-between; align-items: baseline;
  padding: 16px 20px 8px;
}
.fx-pt-sec-label span {
  font-size: 11px; font-weight: 700; letter-spacing: .09em;
  text-transform: uppercase; color: var(--ink-2);
}
.fx-pt-sec-label b { font-size: 12px; font-weight: 700; color: var(--accent); }
.fx-pt-progress {
  margin: 0 20px; height: 6px; border-radius: 4px; background: #e2e5ec;
  overflow: hidden;
}
.fx-pt-progress i {
  display: block; width: 75%; height: 100%; border-radius: 4px;
  background: linear-gradient(90deg, var(--accent-2), #38a2ff);
  box-shadow: 0 0 8px rgba(0, 113, 227, .45);
}
.fx-pt-checks { padding: 12px 14px 0; display: flex; flex-direction: column; gap: 8px; }
.fx-pt-check {
  display: flex; align-items: center; gap: 10px;
  background: #fff; border-radius: 14px;
  border: 1px solid rgba(13, 20, 33, .05);
  padding: 9px 12px;
  color: var(--ink);
  box-shadow: 0 1px 3px rgba(13, 20, 33, .05);
}
.fx-pt-check > div { flex: 1; min-width: 0; }
.fx-pt-check b { display: block; font-size: 13px; font-weight: 700; letter-spacing: -.005em; }
.fx-pt-check small { display: block; font-size: 10.5px; font-weight: 600; color: var(--ink-2); margin-top: 1px; }
.fx-pt-check.fx-warn { background: #fffaf1; border-color: rgba(255, 159, 10, .28); }
.fx-pt-check.fx-warn small { color: #c77700; }
.fx-pt-ico {
  width: 30px; height: 30px; border-radius: 9px; flex: none;
  display: grid; place-items: center;
}
.fx-pt-ico svg { width: 16px; height: 16px; }
.fx-i-brakes  { background: #e7f0ff; color: #0071e3; }
.fx-i-tires   { background: #efeaff; color: #7c5cf0; }
.fx-i-lights  { background: #fff4df; color: #d98a00; }
.fx-i-coolant { background: #ffe9e3; color: #e8552f; }
.fx-pt-tick {
  width: 20px; height: 20px; border-radius: 50%; flex: none;
  position: relative;
}
.fx-pt-check.fx-ok .fx-pt-tick { background: var(--green); box-shadow: 0 2px 6px rgba(48,209,88,.4); }
.fx-pt-check.fx-warn .fx-pt-tick { background: var(--amber); box-shadow: 0 2px 6px rgba(255,159,10,.4); }
.fx-pt-check.fx-ok .fx-pt-tick::after {
  content: ""; position: absolute; left: 6.5px; top: 4px;
  width: 5px; height: 9px;
  border: solid #fff; border-width: 0 2.2px 2.2px 0;
  transform: rotate(42deg);
}
.fx-pt-check.fx-warn .fx-pt-tick::after {
  content: "!"; position: absolute; inset: 0;
  color: #fff; font-weight: 800; font-size: 13px;
  display: flex; align-items: center; justify-content: center;
}
.fx-pt-submit {
  margin: auto 16px 10px;
  display: flex; align-items: center; justify-content: center; gap: 8px;
  background: linear-gradient(135deg, var(--accent-2) 0%, #0a84ff 100%);
  color: #fff;
  border-radius: 999px;
  padding: 13px 0; font-size: 14.5px; font-weight: 700; letter-spacing: -.005em;
  box-shadow: 0 10px 22px rgba(0, 113, 227, .38), inset 0 1px 0 rgba(255,255,255,.25);
}
.fx-pt-submit svg { width: 14px; height: 14px; }
.fx-pt-homebar {
  width: 108px; height: 5px; border-radius: 3px;
  background: #c9cfd9;
  margin: 0 auto 9px;
  position: relative; z-index: 2;
}

/* ── screen 0 · welcome / start ── */
.fx-pt-welcome {
  flex: 1; min-height: 0;
  display: flex; flex-direction: column;
  align-items: center; justify-content: center;
  text-align: center;
  padding: 0 26px 20px;
}
.fx-pt-w-logo {
  width: 76px; height: 76px; border-radius: 23px;
  background: #fff;
  display: grid; place-items: center;
  box-shadow:
    0 16px 34px rgba(0, 113, 227, .28),
    0 0 0 12px rgba(0, 113, 227, .06),
    0 0 0 26px rgba(0, 113, 227, .03),
    inset 0 0 0 1px rgba(13, 20, 33, .05);
}
.fx-pt-w-logo img { width: 54px; height: 54px; object-fit: contain; }
.fx-pt-w-eyebrow {
  display: block; font-style: normal;
  font-size: 12px; font-weight: 700;
  letter-spacing: .12em; text-transform: uppercase;
  color: var(--accent);
  margin-top: 26px;
}
.fx-pt-w-name {
  display: block;
  font-size: 30px; font-weight: 700; letter-spacing: -.02em;
  color: var(--ink);
  margin-top: 6px;
}
.fx-pt-w-sub {
  display: block;
  font-size: 13px; font-weight: 600; line-height: 1.55;
  color: var(--ink-2);
  margin-top: 12px;
  max-width: 30ch;
}
.fx-pt-w-btn {
  margin-top: 28px;
  display: inline-flex; align-items: center; gap: 8px;
  background: linear-gradient(135deg, var(--accent-2) 0%, #0a84ff 100%);
  color: #fff;
  border-radius: 999px;
  padding: 13px 34px;
  font-size: 14.5px; font-weight: 700; letter-spacing: -.005em;
  box-shadow: 0 10px 22px rgba(0, 113, 227, .38), inset 0 1px 0 rgba(255,255,255,.25);
}
.fx-pt-w-btn svg { width: 14px; height: 14px; }
.fx-pt-w-dots { display: flex; gap: 7px; margin-top: 26px; }
.fx-pt-w-dots i {
  width: 6px; height: 6px; border-radius: 50%;
  background: rgba(29, 29, 31, .22); display: block;
}
.fx-pt-w-dots i:first-child { background: var(--accent); }

/* ── screen 2 · defect capture ── */
.fx-pt-bar2 {
  display: flex; align-items: center; gap: 10px;
  padding: 18px 18px 0;
  font-size: 15.5px; letter-spacing: -.01em; color: var(--ink);
}
.fx-pt-back { width: 16px; height: 16px; color: var(--ink-2); flex: none; }
.fx-pt-step {
  margin-left: auto;
  font-size: 11px; font-weight: 700; color: var(--ink-2);
  background: #e9edf4; border-radius: 999px; padding: 3px 9px;
}
.fx-pt-finder {
  position: relative;
  margin: 14px 16px 0;
  flex: 1; min-height: 0;
  border-radius: 18px; overflow: hidden;
  background:
    radial-gradient(120% 90% at 50% 0%, #232b3d 0%, #10151f 70%);
  display: grid; place-items: center;
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.06);
}
.fx-pt-finder .fx-c {
  position: absolute; width: 22px; height: 22px;
  border: 2.5px solid rgba(255,255,255,.75);
}
.fx-pt-finder .fx-c.fx-tl { top: 12px; left: 12px; border-right: 0; border-bottom: 0; border-radius: 6px 0 0 0; }
.fx-pt-finder .fx-c.fx-tr { top: 12px; right: 12px; border-left: 0; border-bottom: 0; border-radius: 0 6px 0 0; }
.fx-pt-finder .fx-c.fx-bl { bottom: 12px; left: 12px; border-right: 0; border-top: 0; border-radius: 0 0 0 6px; }
.fx-pt-finder .fx-c.fx-br { bottom: 12px; right: 12px; border-left: 0; border-top: 0; border-radius: 0 0 6px 0; }
.fx-pt-tire { width: 62%; max-height: 78%; }
.fx-pt-tag-defect {
  position: absolute; top: 16px; left: 50%; transform: translateX(-50%);
  white-space: nowrap;
  font-size: 10.5px; font-weight: 700; color: #ffb4ad;
  background: rgba(255, 69, 58, .16);
  border: 1px solid rgba(255, 69, 58, .35);
  border-radius: 999px; padding: 4px 11px;
}
.fx-pt-tag-geo {
  position: absolute; bottom: 14px; left: 50%; transform: translateX(-50%);
  display: inline-flex; align-items: center; gap: 5px;
  white-space: nowrap;
  font-size: 10px; font-weight: 700; color: rgba(255,255,255,.8);
  background: rgba(255,255,255,.12);
  -webkit-backdrop-filter: blur(4px); backdrop-filter: blur(4px);
  border-radius: 999px; padding: 4px 10px;
}
.fx-pt-tag-geo svg { width: 11px; height: 11px; }
.fx-pt-thumbs { display: flex; gap: 8px; padding: 12px 16px 0; }
.fx-pt-thumb {
  width: 40px; height: 40px; border-radius: 10px; flex: none;
  box-shadow: 0 1px 4px rgba(13,20,33,.14);
}
.fx-pt-thumb.fx-t1 { background: linear-gradient(140deg, #3a4356, #1a2130); }
.fx-pt-thumb.fx-t2 { background: linear-gradient(140deg, #4a3f33, #221a12); }
.fx-pt-thumb.fx-add {
  display: grid; place-items: center;
  background: #e9edf4; color: var(--ink-2);
  font-size: 18px; font-weight: 700;
  box-shadow: none;
}
.fx-pt-shutter-row {
  display: flex; align-items: center; justify-content: space-between;
  padding: 10px 40px 14px;
}
.fx-pt-gal {
  width: 26px; height: 26px; border-radius: 8px;
  background: linear-gradient(140deg, #38a2ff, #2563eb);
}
.fx-pt-shutter {
  width: 54px; height: 54px; border-radius: 50%;
  border: 3.5px solid var(--ink);
  display: grid; place-items: center;
}
.fx-pt-shutter i {
  width: 40px; height: 40px; border-radius: 50%;
  background: var(--accent); display: block;
  box-shadow: 0 4px 12px rgba(0,113,227,.4);
}
.fx-pt-flip {
  width: 30px; height: 30px; border-radius: 50%;
  background: #e9edf4; color: var(--ink);
  display: grid; place-items: center;
}
.fx-pt-flip svg { width: 15px; height: 15px; }

/* ── screen 3 · compliance ── */
.fx-pt-bar2-title { flex: 1; }
.fx-pt-chip-ready {
  font-size: 10px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
  color: #1d9d4e; background: rgba(48, 209, 88, .14);
  border-radius: 999px; padding: 4px 10px;
}
.fx-pt-shield-card {
  margin: 14px 16px 0;
  padding: 14px 16px;
  border-radius: 18px;
  display: flex; align-items: center; gap: 12px;
  background:
    radial-gradient(120% 140% at 100% 0%, rgba(48,209,88,.25) 0%, transparent 55%),
    linear-gradient(135deg, #0f2e1c 0%, #0b1f14 70%);
  color: #fff;
  box-shadow: 0 12px 26px rgba(10, 30, 18, .28);
}
.fx-pt-shield {
  width: 40px; height: 40px; border-radius: 12px; flex: none;
  background: rgba(48, 209, 88, .16); color: #6ee39a;
  display: grid; place-items: center;
}
.fx-pt-shield svg { width: 22px; height: 22px; }
.fx-pt-shield-card b { display: block; font-size: 15px; letter-spacing: -.01em; }
.fx-pt-shield-card small { display: block; font-size: 11px; font-weight: 600; color: rgba(255,255,255,.55); margin-top: 2px; }
.fx-pt-shield-card div { flex: 1; }
.fx-pt-shield-card em {
  font-style: normal; font-size: 15px; font-weight: 800; color: #6ee39a;
  font-variant-numeric: tabular-nums;
}
.fx-pt-docs { padding: 4px 14px 0; display: flex; flex-direction: column; gap: 8px; }
.fx-pt-doc {
  display: flex; align-items: center; gap: 10px;
  background: #fff; border-radius: 14px;
  border: 1px solid rgba(13, 20, 33, .05);
  padding: 10px 12px;
  box-shadow: 0 1px 3px rgba(13, 20, 33, .05);
}
.fx-pt-doc > div { flex: 1; min-width: 0; }
.fx-pt-doc b { display: block; font-size: 12.5px; font-weight: 700; letter-spacing: -.005em; color: var(--ink); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.fx-pt-doc small { display: block; font-size: 10.5px; font-weight: 600; color: var(--ink-2); margin-top: 1px; }
.fx-i-doc1 { background: #e7f0ff; color: #0071e3; }
.fx-i-doc2 { background: #e6f8ec; color: #1d9d4e; }
.fx-i-doc3 { background: #fff4df; color: #d98a00; }
.fx-pt-pill {
  flex: none; font-size: 9.5px; font-weight: 800; letter-spacing: .05em; text-transform: uppercase;
  border-radius: 999px; padding: 4px 9px;
}
.fx-pt-pill.fx-ok { color: #1d9d4e; background: rgba(48, 209, 88, .14); }
.fx-pt-pill.fx-soon { color: #c77700; background: rgba(255, 159, 10, .16); }

/* ── screen 4 · sync ── */
.fx-pt-sync-hero {
  padding: 34px 20px 0;
  text-align: center;
}
.fx-pt-cloud {
  width: 86px; height: 86px; border-radius: 50%;
  margin: 0 auto;
  display: grid; place-items: center;
  color: #fff;
  background: linear-gradient(135deg, var(--accent-2), #0a84ff);
  box-shadow:
    0 14px 30px rgba(0, 113, 227, .35),
    0 0 0 12px rgba(0, 113, 227, .07),
    0 0 0 26px rgba(0, 113, 227, .04);
}
.fx-pt-cloud svg { width: 44px; height: 44px; }
.fx-pt-sync-hero b { display: block; font-size: 20px; font-weight: 700; letter-spacing: -.015em; color: var(--ink); margin-top: 18px; }
.fx-pt-sync-hero small { display: block; font-size: 12px; font-weight: 600; color: var(--ink-2); margin-top: 4px; }
.fx-pt-sync-list { padding: 20px 16px 0; display: flex; flex-direction: column; gap: 8px; }
.fx-pt-sync-row {
  display: flex; align-items: center; gap: 10px;
  background: #fff; border-radius: 13px;
  border: 1px solid rgba(13, 20, 33, .05);
  padding: 10px 13px;
  box-shadow: 0 1px 3px rgba(13, 20, 33, .05);
}
.fx-pt-sync-row b { flex: 1; font-size: 12.5px; font-weight: 700; color: var(--ink); }
.fx-pt-sync-row small { font-size: 10.5px; font-weight: 700; color: var(--ink-2); font-variant-numeric: tabular-nums; }
.fx-pt-mini-tick {
  width: 17px; height: 17px; border-radius: 50%; flex: none;
  background: var(--green); position: relative;
}
.fx-pt-mini-tick::after {
  content: ""; position: absolute; left: 5.5px; top: 3.5px;
  width: 4px; height: 7.5px;
  border: solid #fff; border-width: 0 2px 2px 0;
  transform: rotate(42deg);
}
.fx-pt-offline-note {
  margin: auto 16px 14px;
  display: flex; align-items: center; justify-content: center; gap: 7px;
  font-size: 11px; font-weight: 700; color: var(--ink-2);
  background: #e9edf4; border-radius: 999px; padding: 9px 0;
}
.fx-pt-offline-note svg { width: 13px; height: 13px; }

/* back — camera */
.fx-pt-back {
  transform: rotateY(180deg) translateZ(26px);
  background:
    radial-gradient(140% 90% at 30% 0%, rgba(255,255,255,.5) 0%, transparent 40%),
    linear-gradient(160deg, #e9e9ee 0%, #d4d4da 45%, #dfdfe4 100%);
  box-shadow: inset 0 0 0 1.5px rgba(255,255,255,.65), inset 0 0 24px rgba(0,0,0,.06);
}
.fx-pt-cam {
  position: absolute; top: 20px; left: 20px;
  width: 128px; height: 128px; border-radius: 36px;
  background: linear-gradient(150deg, #d3d3d9, #bcbcc3);
  box-shadow: inset 0 1px 2px rgba(255,255,255,.8), 0 6px 16px rgba(0,0,0,.16);
}
.fx-pt-lens {
  position: absolute;
  width: 48px; height: 48px; border-radius: 50%;
  background:
    radial-gradient(circle at 34% 30%, rgba(120,170,255,.55) 0%, transparent 26%),
    radial-gradient(circle at 50% 50%, #1a2030 0%, #05070c 62%, #23252c 78%, #4c4e57 100%);
  box-shadow: 0 2px 6px rgba(0,0,0,.4), inset 0 0 0 3px rgba(255,255,255,.14);
}
.fx-pt-lens.fx-l1 { top: 12px; left: 12px; }
.fx-pt-lens.fx-l2 { top: 12px; right: 12px; }
.fx-pt-lens.fx-l3 { bottom: 12px; left: 12px; }
.fx-pt-flash {
  position: absolute; bottom: 24px; right: 24px;
  width: 18px; height: 18px; border-radius: 50%;
  background: radial-gradient(circle at 40% 35%, #fff8dd, #e8c86a 70%, #b9963d);
}
.fx-pt-backmark {
  position: absolute; top: 50%; left: 50%;
  width: 52px; height: 52px;
  transform: translate(-50%, -30%);
  border-radius: 50%;
  border: 3px solid rgba(120,120,128,.5);
}
.fx-pt-backmark::after {
  content: ""; position: absolute; inset: 12px;
  border-radius: 50%; background: rgba(120,120,128,.5);
}

.fx-pt-shadow {
  position: absolute; left: 50%; bottom: 8vh;
  width: 340px; height: 44px;
  transform: translateX(-50%);
  background: radial-gradient(50% 50% at 50% 50%, rgba(0,0,0,.28), transparent 70%);
  filter: blur(6px);
  will-change: transform, opacity;
  pointer-events: none;
  opacity: 0;
}

/* ───────── callouts — Apple-style plain text ───────── */
.fx-pt-callout {
  position: absolute; top: 50%;
  width: min(310px, 32vw);
  transform: translateY(-50%) translateX(var(--slide, 0px));
  opacity: 0;
  will-change: transform, opacity;
  pointer-events: none;
}
.fx-pt-callout.fx-left  { left: max(24px, 7.5vw); }
.fx-pt-callout.fx-right { right: max(24px, 7.5vw); }

/* per-topic accent for the second half of the heading */
.fx-pt-callout.fx-co-blue  { --co-a: #0071e3; }
.fx-pt-callout.fx-co-red   { --co-a: #e8552f; }
.fx-pt-callout.fx-co-green { --co-a: #1d9d4e; }
.fx-pt-callout.fx-co-sky   { --co-a: #0a84ff; }

.fx-pt-callout h3 {
  font-size: 23px; font-weight: 700; letter-spacing: -.015em;
  line-height: 1.22;
  margin-bottom: 10px; color: var(--ink);
  text-wrap: balance;
}
.fx-pt-callout h3 span { color: var(--co-a); }
.fx-pt-callout p {
  font-size: 16px; line-height: 1.55;
  color: var(--ink-2); font-weight: 600;
}

/* connector: hairline + dot at the phone end, Apple-style */
.fx-pt-tether {
  position: absolute; top: 14px; width: 130px; height: 1px;
  background: rgba(29, 29, 31, .28);
  transform: scaleX(0);
}
.fx-pt-callout.fx-left  .fx-pt-tether { left: 100%; margin-left: 16px; transform-origin: left; }
.fx-pt-callout.fx-right .fx-pt-tether { right: 100%; margin-right: 16px; transform-origin: right; }
.fx-pt-tether::after {
  content: ""; position: absolute; top: -3px; width: 7px; height: 7px;
  border-radius: 50%; background: rgba(29, 29, 31, .45);
}
.fx-pt-callout.fx-left  .fx-pt-tether::after { right: -3.5px; }
.fx-pt-callout.fx-right .fx-pt-tether::after { left: -3.5px; }

@media (max-width: 700px) {
  .fx-pt-callout, .fx-pt-callout.fx-left, .fx-pt-callout.fx-right {
    left: 50%; right: auto; top: auto; bottom: 4vh;
    width: min(430px, 88vw);
    transform: translate(-50%, 0) translateX(var(--slide, 0px));
    text-align: center;
    background: rgba(255, 255, 255, .8);
    -webkit-backdrop-filter: blur(14px);
    backdrop-filter: blur(14px);
    border-radius: 20px;
    padding: 16px 20px;
    box-shadow: 0 10px 34px rgba(13, 20, 33, .1);
  }
  .fx-pt-callout h3 { font-size: 19px; }
  .fx-pt-callout p { font-size: 14px; }
  .fx-pt-tether { display: none; }
}

/* ═══════════ live screens: entrance + ambient motion ═══════════
   phonetour.js adds .fx-live to a .fx-pt-app as it fades in (and removes
   it when it fully fades out, so the sequence replays on return).
   Everything here is gated on no-preference so reduced-motion
   users get the static, fully-visible screens. */
@property --ring { syntax: "<angle>"; initial-value: 0deg; inherits: false; }

@media (prefers-reduced-motion: no-preference) {

  /* entrance staging: children rise in, staggered */
  .fx-pt-app .fx-pt-appbar, .fx-pt-app .fx-pt-bar2,
  .fx-pt-app .fx-pt-vehicle, .fx-pt-app .fx-pt-sec-label, .fx-pt-app .fx-pt-progress,
  .fx-pt-app .fx-pt-check, .fx-pt-app .fx-pt-submit,
  .fx-pt-app .fx-pt-finder, .fx-pt-app .fx-pt-thumbs, .fx-pt-app .fx-pt-shutter-row,
  .fx-pt-app .fx-pt-shield-card, .fx-pt-app .fx-pt-doc,
  .fx-pt-app .fx-pt-sync-hero, .fx-pt-app .fx-pt-sync-row, .fx-pt-app .fx-pt-offline-note {
    opacity: 0; transform: translateY(14px);
    transition: opacity .5s var(--ease), transform .5s var(--ease);
  }
  .fx-pt-app.fx-live .fx-pt-appbar, .fx-pt-app.fx-live .fx-pt-bar2,
  .fx-pt-app.fx-live .fx-pt-vehicle, .fx-pt-app.fx-live .fx-pt-sec-label, .fx-pt-app.fx-live .fx-pt-progress,
  .fx-pt-app.fx-live .fx-pt-check, .fx-pt-app.fx-live .fx-pt-submit,
  .fx-pt-app.fx-live .fx-pt-finder, .fx-pt-app.fx-live .fx-pt-thumbs, .fx-pt-app.fx-live .fx-pt-shutter-row,
  .fx-pt-app.fx-live .fx-pt-shield-card, .fx-pt-app.fx-live .fx-pt-doc,
  .fx-pt-app.fx-live .fx-pt-sync-hero, .fx-pt-app.fx-live .fx-pt-sync-row, .fx-pt-app.fx-live .fx-pt-offline-note {
    opacity: 1; transform: none;
  }
  .fx-pt-app.fx-live .fx-pt-appbar, .fx-pt-app.fx-live .fx-pt-bar2 { transition-delay: .05s; }
  .fx-pt-app.fx-live .fx-pt-vehicle, .fx-pt-app.fx-live .fx-pt-finder,
  .fx-pt-app.fx-live .fx-pt-shield-card, .fx-pt-app.fx-live .fx-pt-sync-hero { transition-delay: .14s; }
  .fx-pt-app.fx-live .fx-pt-sec-label { transition-delay: .22s; }
  .fx-pt-app.fx-live .fx-pt-progress { transition-delay: .26s; }
  .fx-pt-app.fx-live .fx-pt-check:nth-child(1), .fx-pt-app.fx-live .fx-pt-doc:nth-child(1),
  .fx-pt-app.fx-live .fx-pt-sync-row:nth-child(1), .fx-pt-app.fx-live .fx-pt-thumbs { transition-delay: .32s; }
  .fx-pt-app.fx-live .fx-pt-check:nth-child(2), .fx-pt-app.fx-live .fx-pt-doc:nth-child(2),
  .fx-pt-app.fx-live .fx-pt-sync-row:nth-child(2) { transition-delay: .42s; }
  .fx-pt-app.fx-live .fx-pt-check:nth-child(3), .fx-pt-app.fx-live .fx-pt-doc:nth-child(3),
  .fx-pt-app.fx-live .fx-pt-sync-row:nth-child(3), .fx-pt-app.fx-live .fx-pt-shutter-row { transition-delay: .52s; }
  .fx-pt-app.fx-live .fx-pt-check:nth-child(4) { transition-delay: .62s; }
  .fx-pt-app.fx-live .fx-pt-submit, .fx-pt-app.fx-live .fx-pt-offline-note { transition-delay: .74s; }

  /* checkmarks pop in with a spring, after their row lands */
  .fx-pt-app .fx-pt-tick, .fx-pt-app .fx-pt-mini-tick {
    transform: scale(0);
    transition: transform .5s cubic-bezier(.34, 1.56, .64, 1);
  }
  .fx-pt-app.fx-live .fx-pt-check:nth-child(1) .fx-pt-tick,
  .fx-pt-app.fx-live .fx-pt-sync-row:nth-child(1) .fx-pt-mini-tick { transform: scale(1); transition-delay: .62s; }
  .fx-pt-app.fx-live .fx-pt-check:nth-child(2) .fx-pt-tick,
  .fx-pt-app.fx-live .fx-pt-sync-row:nth-child(2) .fx-pt-mini-tick { transform: scale(1); transition-delay: .74s; }
  .fx-pt-app.fx-live .fx-pt-check:nth-child(3) .fx-pt-tick,
  .fx-pt-app.fx-live .fx-pt-sync-row:nth-child(3) .fx-pt-mini-tick { transform: scale(1); transition-delay: .86s; }
  .fx-pt-app.fx-live .fx-pt-check:nth-child(4) .fx-pt-tick { transform: scale(1); transition-delay: .98s; }

  /* progress bar fills once the screen lands */
  .fx-pt-app .fx-pt-progress i { width: 0; transition: width 1.1s cubic-bezier(.22, .8, .26, 1); }
  .fx-pt-app.fx-live .fx-pt-progress i { width: 75%; transition-delay: .5s; }

  /* vehicle ring draws itself (falls back to an instant fill
     where @property isn't supported) */
  .fx-pt-app .fx-pt-veh-ring {
    --ring: 0deg;
    background: conic-gradient(#38a2ff 0deg var(--ring), rgba(255,255,255,.14) var(--ring) 360deg);
    transition: --ring 1.3s var(--ease);
  }
  .fx-pt-app.fx-live .fx-pt-veh-ring { --ring: 270deg; transition-delay: .5s; }

  /* welcome screen: logo pops, text rises, dots step */
  .fx-pt-app .fx-pt-w-logo {
    opacity: 0; transform: scale(.5);
    transition: opacity .55s var(--ease), transform .55s cubic-bezier(.34, 1.56, .64, 1);
  }
  .fx-pt-app .fx-pt-w-eyebrow, .fx-pt-app .fx-pt-w-name, .fx-pt-app .fx-pt-w-sub,
  .fx-pt-app .fx-pt-w-btn, .fx-pt-app .fx-pt-w-dots {
    opacity: 0; transform: translateY(14px);
    transition: opacity .5s var(--ease), transform .5s var(--ease);
  }
  .fx-pt-app.fx-live .fx-pt-w-logo { opacity: 1; transform: scale(1); transition-delay: .1s; }
  .fx-pt-app.fx-live .fx-pt-w-eyebrow, .fx-pt-app.fx-live .fx-pt-w-name, .fx-pt-app.fx-live .fx-pt-w-sub,
  .fx-pt-app.fx-live .fx-pt-w-btn, .fx-pt-app.fx-live .fx-pt-w-dots { opacity: 1; transform: none; }
  .fx-pt-app.fx-live .fx-pt-w-eyebrow { transition-delay: .28s; }
  .fx-pt-app.fx-live .fx-pt-w-name    { transition-delay: .36s; }
  .fx-pt-app.fx-live .fx-pt-w-sub     { transition-delay: .46s; }
  .fx-pt-app.fx-live .fx-pt-w-btn     { transition-delay: .58s; }
  .fx-pt-app.fx-live .fx-pt-w-dots    { transition-delay: .7s; }

  /* ── ambient motion while a screen is live ── */

  /* welcome: logo breathes, loading dots step through */
  .fx-pt-app.fx-live .fx-pt-w-logo { animation: pt-w-glow 3s ease-in-out infinite 1.2s; }
  .fx-pt-app.fx-live .fx-pt-w-dots i           { animation: pt-w-dot 1.8s ease-in-out infinite 1s; }
  .fx-pt-app.fx-live .fx-pt-w-dots i:nth-child(2) { animation-delay: 1.3s; }
  .fx-pt-app.fx-live .fx-pt-w-dots i:nth-child(3) { animation-delay: 1.6s; }

  /* notification badge pulse */
  .fx-pt-app.fx-live .fx-pt-bell::after { animation: pt-badge 2.2s ease-in-out infinite 1s; }

  /* warning row glow */
  .fx-pt-app.fx-live .fx-pt-check.fx-warn .fx-pt-tick { animation: pt-warn 2.4s ease-in-out infinite 1.4s; }

  /* camera: scanning line sweeps the viewfinder */
  .fx-pt-scan {
    position: absolute; left: 10%; right: 10%; top: 12%; height: 2px;
    background: linear-gradient(90deg, transparent, rgba(56,162,255,.95), transparent);
    box-shadow: 0 0 14px rgba(56,162,255,.8);
    opacity: 0;
  }
  .fx-pt-app.fx-live .fx-pt-scan { opacity: 1; animation: pt-scan 2.8s ease-in-out infinite .6s; }

  /* camera: defect ring breathes, shutter throbs */
  .fx-pt-defect { transform-box: fill-box; transform-origin: center; }
  .fx-pt-app.fx-live .fx-pt-defect { animation: pt-pulse 2s ease-in-out infinite .8s; }
  .fx-pt-app.fx-live .fx-pt-shutter i { animation: pt-shutter 3.2s ease-in-out infinite 1.2s; }

  /* compliance: shield glints */
  .fx-pt-app.fx-live .fx-pt-shield { animation: pt-glint 3s ease-in-out infinite 1.2s; }

  /* sync: ripples radiate from the cloud */
  .fx-pt-cloud { position: relative; }
  .fx-pt-cloud::before, .fx-pt-cloud::after {
    content: ""; position: absolute; inset: 0;
    border-radius: 50%;
    border: 2px solid rgba(10, 132, 255, .4);
    opacity: 0;
  }
  .fx-pt-app.fx-live .fx-pt-cloud::before { animation: pt-ripple 2.6s ease-out infinite .8s; }
  .fx-pt-app.fx-live .fx-pt-cloud::after  { animation: pt-ripple 2.6s ease-out infinite 2.1s; }

  @keyframes pt-w-glow  { 0%, 100% { box-shadow: 0 16px 34px rgba(0,113,227,.28), 0 0 0 12px rgba(0,113,227,.06), 0 0 0 26px rgba(0,113,227,.03), inset 0 0 0 1px rgba(13,20,33,.05); }
                          50%      { box-shadow: 0 16px 40px rgba(0,113,227,.42), 0 0 0 16px rgba(0,113,227,.09), 0 0 0 34px rgba(0,113,227,.05), inset 0 0 0 1px rgba(13,20,33,.05); } }
  @keyframes pt-w-dot   { 0%, 100% { transform: translateY(0);    opacity: .55; }
                          30%      { transform: translateY(-5px); opacity: 1; } }
  @keyframes pt-badge   { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.35); } }
  @keyframes pt-warn    { 0%, 100% { box-shadow: 0 2px 6px rgba(255,159,10,.4); }
                          50%      { box-shadow: 0 2px 14px rgba(255,159,10,.85); } }
  @keyframes pt-scan    { 0%, 100% { top: 12%; } 50% { top: 84%; } }
  @keyframes pt-pulse   { 0%, 100% { opacity: .55; transform: scale(1); }
                          50%      { opacity: 1;  transform: scale(1.1); } }
  @keyframes pt-shutter { 0%, 100% { transform: scale(1); }
                          5%       { transform: scale(.82); }
                          11%      { transform: scale(1); } }
  @keyframes pt-glint   { 0%, 100% { box-shadow: 0 0 0 rgba(110,227,154,0); }
                          50%      { box-shadow: 0 0 18px rgba(110,227,154,.55); } }
  @keyframes pt-ripple  { 0%  { transform: scale(1);   opacity: .8; }
                          100% { transform: scale(1.9); opacity: 0; } }
}

/* ───────── reduced motion: static fallback ───────── */
@media (prefers-reduced-motion: reduce) {
  .fx-pt-stage { height: auto; padding: 6vh 0; }
  .fx-pt-viewport {
    position: static; height: auto; min-height: 0;
    flex-direction: column; gap: 40px; padding: 40px 0;
  }
  .fx-pt-phone { transform: rotateY(-24deg) rotateX(4deg) !important; }
  .fx-pt-callout, .fx-pt-callout.fx-left, .fx-pt-callout.fx-right {
    position: static; opacity: 1 !important; transform: none !important;
    width: min(460px, 88vw); text-align: center; margin: 0 auto;
  }
  .fx-pt-tether, .fx-pt-shadow { display: none; }
}

/* ===== integrations.css ===== */
/* =========== ONEFLOW INTEGRATION - OPERATIONAL PIPELINE ===========
   Left-to-right flow diagram: signal list → data sources →
   FleetRabbit operational data layer → AI analysis → actions →
   ERP systems, closed by a "One Connected Flow" summary bar.
   (The old partner-ecosystem hub lives in assets/dead-code/.)

   Animation model: the .fx-ofi-flow wrapper carries .fx-reveal, so the
   shared observer toggles .fx-in both ways — the whole entrance
   choreography (each card wipes into existence, its contents build,
   its arrow pops and "creates" the next card, strictly one layer at
   a time) replays on every scroll-through. Ambient loops (arrow
   nudges, marching dashes, hub glow, AI rings, wave dots) run
   continuously and are sequenced with delays so data appears to
   travel down the pipeline. */

/* full-bleed blend: pick up the grey the oneflow stage above fades
   into, hold a cool blue-grey plate behind the white cards, ease
   back into --bg-alt for the section below */
#integrations-root {
  background: linear-gradient(180deg,
    var(--bg-alt) 0%,
    #f2f6fb 16%,
    #f2f6fb 84%,
    var(--bg-alt) 100%);
}
.fx-ofi {
  width: min(1440px, 94vw);
  margin: 0 auto;
  padding: clamp(64px, 9vh, 120px) 0;
}

/* ── header: big duo-tone heading left, paragraph right ── */
.fx-ofi-head {
  display: grid;
  grid-template-columns: 1.15fr .85fr;
  gap: clamp(28px, 4vw, 72px);
  /* paragraph floats centred beside the big heading */
  align-items: center;
  margin-bottom: clamp(36px, 5.5vh, 64px);
}
.fx-ofi-head h2 { font-size: clamp(2.1rem, 4.2vw, 3.6rem); max-width: 12em; }
.fx-ofi-head .fx-lead {
  font-size: clamp(.95rem, 1.15vw, 1.12rem);
  max-width: 36em;
}
@media (max-width: 900px) {
  .fx-ofi-head { grid-template-columns: 1fr; align-items: start; gap: 16px; }
}

/* ══════════ pipeline grid ══════════ */
.fx-ofi-flow {
  display: grid;
  grid-template-columns: 1.5fr 1fr auto 1.1fr auto 1.05fr auto 1.15fr auto 1fr;
  gap: clamp(8px, 1.1vw, 16px);
  align-items: stretch;
}

/* shared white card
   z-index lifts every card above the connector SVGs so the shine
   line's overhanging ends disappear BEHIND the card edges — the
   wire looks like it plugs into the cards, not floats between them */
.fx-ofi-card {
  position: relative;
  z-index: 1;
  background: #fff;
  border: 1px solid rgba(21, 44, 84, .05);
  border-radius: 22px;
  box-shadow: 0 18px 40px -26px rgba(15, 30, 60, .22);
  padding: clamp(14px, 1.6vw, 22px);
  display: flex;
  flex-direction: column;
  min-width: 0;
}
.fx-ofi-card h3 {
  font-size: clamp(.6rem, .8vw, .72rem);
  font-weight: 700;
  letter-spacing: .13em;
  text-transform: uppercase;
  color: #8496af;
  text-align: center;
  margin-bottom: clamp(10px, 1.4vh, 16px);
}

/* ── 1 · signal list ── */
.fx-ofi-signals { padding-top: clamp(8px, 1vw, 12px); padding-bottom: clamp(8px, 1vw, 12px); justify-content: center; }
.fx-ofi-signals li {
  display: flex; align-items: center;
  gap: clamp(8px, .9vw, 12px);
  padding: clamp(6px, .95vh, 10px) 4px;
  font-size: clamp(.72rem, .95vw, .9rem);
  font-weight: 600;
  color: #33415c;
  white-space: nowrap;
}
.fx-ofi-signals li + li { border-top: 1px solid #eef2f8; }
.fx-sg-ic {
  display: grid; place-items: center; flex: none;
  width: clamp(24px, 2.2vw, 32px); height: clamp(24px, 2.2vw, 32px);
  border-radius: 9px;
  background: #ecf3fd;
  color: var(--accent);
}
.fx-sg-ic svg, .fx-ac-ic svg, .fx-src-node svg, .fx-bar-ic svg, .fx-ai-core svg {
  fill: none; stroke: currentColor;
  stroke-linecap: round; stroke-linejoin: round;
}
.fx-sg-ic svg, .fx-ac-ic svg { width: 62%; height: 62%; stroke-width: 1.8; }

/* ── 2 · data sources: node column, dashed wires merging right ── */
.fx-src-map { position: relative; flex: 1; min-height: 280px; }
.fx-src-node {
  position: absolute; left: 30%;
  transform: translate(-50%, -50%);
  display: grid; place-items: center;
  width: clamp(34px, 3.2vw, 46px); height: clamp(34px, 3.2vw, 46px);
  border-radius: 50%;
  background: #fff;
  border: 1px solid #e2ebf7;
  box-shadow: 0 10px 22px -12px rgba(15, 30, 60, .3);
  color: var(--accent);
  animation: ofi-node 3.6s ease-in-out infinite;
}
.fx-src-node svg { width: 50%; height: 50%; stroke-width: 1.7; }
.fx-n-1 { top: 10%; animation-delay: 0s; }
.fx-n-2 { top: 30%; animation-delay: .35s; }
.fx-n-3 { top: 50%; animation-delay: .7s; }
.fx-n-4 { top: 70%; animation-delay: 1.05s; }
.fx-n-5 { top: 90%; animation-delay: 1.4s; }
@keyframes ofi-node {
  0%, 100% { box-shadow: 0 10px 22px -12px rgba(15, 30, 60, .3); border-color: #e2ebf7; }
  50%      { box-shadow: 0 10px 24px -10px rgba(0, 113, 227, .45); border-color: #bcd7f5; }
}
.fx-src-wires { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
.fx-src-wires path {
  fill: none;
  stroke: #a9c6e8; stroke-width: 1.6;
  vector-effect: non-scaling-stroke;
  stroke-linecap: round;
  stroke-dasharray: 5 6;
  animation: ofi-march 1.5s linear infinite;
}
/* dashes crawl toward the merge point — data draining rightward */
@keyframes ofi-march { to { stroke-dashoffset: -11; } }

/* ── connector links: organic curved wires between cards ──
   n8n-style: two S-curves (green + blue) merge into the next card,
   wobbling gently as if alive, while colored data dots ride the
   curves left→right (SMIL animateMotion, one per wire). */
.fx-ofi-link {
  align-self: center; flex: none;
  width: clamp(38px, 3.4vw, 58px);
  height: clamp(96px, 13vh, 140px);
  overflow: visible;
}
.fx-lk {
  fill: none;
  stroke-width: 2;
  stroke-linecap: round;
  vector-effect: non-scaling-stroke;
  animation: lk-wiggle 2.4s ease-in-out infinite;
}
.fx-lk-g { stroke: #34c759; }
.fx-lk-b { stroke: #2f80ee; animation-delay: -1.2s; }
/* the "shake": each wire breathes up and down, out of phase */
@keyframes lk-wiggle {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(2.6px); }
}
.fx-lk-head {
  fill: none;
  stroke: var(--accent);
  stroke-width: 2.2;
  stroke-linecap: round; stroke-linejoin: round;
}
.fx-lk-dot.fx-dg { fill: #34c759; filter: drop-shadow(0 0 3px rgba(52, 199, 89, .65)); }
.fx-lk-dot.fx-db { fill: #2f80ee; filter: drop-shadow(0 0 3px rgba(47, 128, 238, .65)); }

/* ── interconnect shine line ──
   A straight rail across the whole gap whose ends overhang the
   viewBox (-30 → 90) and tuck under the neighbouring cards
   (cards carry z-index: 1), so the wire emerges from behind one
   card and plugs into the next. A bright glowing dash window
   sweeps along it on a loop — staggered per gap so the "shine"
   relays left→right down the pipeline. */
.fx-lk-base {
  fill: none;
  stroke: #b9d4f1;
  stroke-width: 1.8;
  stroke-linecap: round;
  vector-effect: non-scaling-stroke;
}
.fx-lk-shine {
  fill: none;
  stroke: #9ecaff;
  stroke-width: 3;
  stroke-linecap: round;
  vector-effect: non-scaling-stroke;
  /* pathLength=1: a .22-long bright window on a 1-long rail */
  stroke-dasharray: .22 1;
  stroke-dashoffset: .22;
  filter: drop-shadow(0 0 5px rgba(64, 140, 247, .95));
  animation: lk-shine 2.6s linear infinite;
}
/* window sweeps offscreen-left → offscreen-right, then repeats */
@keyframes lk-shine { to { stroke-dashoffset: -1; } }
/* relay: each gap shines a beat after the previous one */
.fx-l-1 .fx-lk-shine { animation-delay: 0s; }
.fx-l-2 .fx-lk-shine { animation-delay: .55s; }
.fx-l-3 .fx-lk-shine { animation-delay: 1.1s; }
.fx-l-4 .fx-lk-shine { animation-delay: 1.65s; }

/* ── 3 · FleetRabbit hub card ── */
.fx-ofi-hub {
  position: relative;
  z-index: 1; /* above the shine rails, like the white cards */
  overflow: hidden;
  border-radius: 26px;
  background: linear-gradient(178deg, #3a72e6 0%, #2050c8 48%, #16368f 100%);
  color: #fff;
  display: flex; flex-direction: column;
  align-items: center; justify-content: center;
  text-align: center;
  gap: clamp(8px, 1.2vh, 14px);
  padding: clamp(18px, 2vw, 28px);
  min-width: 0;
  box-shadow: 0 26px 54px -22px rgba(22, 54, 143, .55);
  animation: ofi-hub-glow 5s ease-in-out infinite;
}
@keyframes ofi-hub-glow {
  0%, 100% { box-shadow: 0 26px 54px -22px rgba(22, 54, 143, .55); }
  50%      { box-shadow: 0 26px 60px -18px rgba(0, 113, 227, .65); }
}
/* the FleetRabbit app icon, framed like an app tile on the blue glass */
.fx-hub-mark {
  width: clamp(52px, 4.6vw, 72px);
  border-radius: 24%;
  box-shadow: 0 0 0 2px rgba(255, 255, 255, .55),
              0 10px 22px rgba(0, 20, 80, .45);
  filter: drop-shadow(0 8px 16px rgba(0, 20, 80, .4));
  animation: ofi-mark 5s ease-in-out infinite;
}
@keyframes ofi-mark {
  0%, 100% { scale: 1; }
  50%      { scale: 1.06; }
}
.fx-ofi-hub b {
  font-size: clamp(1.05rem, 1.5vw, 1.4rem);
  font-weight: 800;
  letter-spacing: -.01em;
}
.fx-ofi-hub i {
  font-style: normal;
  font-size: clamp(.8rem, 1vw, .98rem);
  font-weight: 500;
  line-height: 1.4;
  color: rgba(255, 255, 255, .78);
}
/* soft specular streak gliding over the glass every few seconds */
.fx-hub-sheen {
  position: absolute; top: -30%; bottom: -30%;
  left: 0; width: 55%;
  background: linear-gradient(100deg,
    rgba(255, 255, 255, 0),
    rgba(255, 255, 255, .16) 50%,
    rgba(255, 255, 255, 0));
  transform: translateX(-160%) skewX(-14deg);
  animation: ofi-sheen 7s ease-in-out infinite;
  pointer-events: none;
}
@keyframes ofi-sheen {
  0%, 55%   { transform: translateX(-160%) skewX(-14deg); }
  90%, 100% { transform: translateX(340%) skewX(-14deg); }
}

/* ── 4 · AI analysis ── */
.fx-ofi-ai { align-items: center; }
.fx-ai-orb {
  position: relative; flex: none;
  width: clamp(86px, 8.5vw, 122px); height: clamp(86px, 8.5vw, 122px);
  margin: auto 0;
  display: grid; place-items: center;
}
.fx-ai-core {
  display: grid; place-items: center;
  width: 74%; height: 74%;
  border-radius: 50%;
  background: radial-gradient(circle at 38% 30%, #f2f8ff, #dcebfc 70%, #cfe3fa);
  border: 1px solid #d3e4f8;
  box-shadow: 0 0 0 clamp(6px, .8vw, 10px) rgba(0, 113, 227, .07),
              0 14px 28px -14px rgba(0, 113, 227, .4);
  color: var(--accent);
  z-index: 1;
}
.fx-ai-core svg { width: 56%; height: 56%; stroke-width: 1.5; }
/* expanding "thinking" rings */
.fx-ai-ring {
  position: absolute; inset: 0;
  border-radius: 50%;
  border: 1.5px solid rgba(0, 113, 227, .4);
  animation: ofi-ring 3.2s ease-out infinite;
}
.fx-ai-ring.fx-r2 { animation-delay: 1.6s; }
@keyframes ofi-ring {
  0%   { transform: scale(.66); opacity: 0; }
  25%  { opacity: .8; }
  100% { transform: scale(1.12); opacity: 0; }
}
.fx-ofi-ai ul { margin-top: auto; align-self: flex-start; width: 100%; }
.fx-ofi-ai li {
  position: relative;
  padding: clamp(3px, .5vh, 5px) 0 clamp(3px, .5vh, 5px) 15px;
  font-size: clamp(.72rem, .85vw, .84rem);
  font-weight: 600;
  color: #43536e;
  white-space: nowrap;
}
.fx-ofi-ai li::before {
  content: '';
  position: absolute; left: 2px; top: 50%;
  width: 5px; height: 5px; border-radius: 50%;
  transform: translateY(-50%);
  background: var(--accent);
  opacity: .75;
}

/* ── 5 · action list ── */
.fx-ofi-action ul {
  flex: 1;
  display: flex; flex-direction: column;
  justify-content: space-evenly;
  gap: clamp(4px, .8vh, 10px);
}
.fx-ofi-action li {
  display: flex; align-items: center;
  gap: clamp(8px, .9vw, 12px);
  font-size: clamp(.72rem, .9vw, .86rem);
  font-weight: 600;
  color: #33415c;
}
.fx-ac-ic {
  display: grid; place-items: center; flex: none;
  width: clamp(26px, 2.4vw, 36px); height: clamp(26px, 2.4vw, 36px);
  border-radius: 10px;
  background: #ecf3fd;
  color: var(--accent);
}

/* ── 6 · ERP logos ── */
.fx-erp-logos {
  flex: 1;
  display: flex; flex-direction: column;
  align-items: center; justify-content: space-evenly;
  gap: clamp(10px, 1.6vh, 18px);
  padding: clamp(6px, 1vh, 12px) 0;
}
.fx-erp-sap {
  font-size: clamp(1.1rem, 1.4vw, 1.45rem);
  font-weight: 800; font-style: italic;
  letter-spacing: .02em;
  color: #fff;
  background: linear-gradient(180deg, #3f9fda 0%, #0b6cb4 100%);
  padding: .18em .9em .18em .55em;
  clip-path: polygon(0 0, 100% 0, 76% 100%, 0 100%);
}
.fx-erp-oracle {
  font-size: clamp(.9rem, 1.1vw, 1.15rem);
  font-weight: 800;
  letter-spacing: .06em;
  color: #C74634;
}
.fx-erp-msd {
  display: flex; align-items: center;
  gap: 8px;
  color: #0f4fa8;
}
.fx-erp-msd svg { width: clamp(20px, 2vw, 28px); height: clamp(20px, 2vw, 28px); flex: none; }
.fx-erp-msd > span {
  font-size: clamp(.66rem, .8vw, .8rem);
  font-weight: 600;
  line-height: 1.25;
  color: #4c5d78;
  text-align: left;
}
.fx-erp-more {
  font-size: clamp(.76rem, .9vw, .9rem);
  font-weight: 700;
  color: var(--accent);
}

/* ══════════ one connected flow bar ══════════ */
.fx-ofi-bar {
  margin-top: clamp(16px, 2.4vh, 26px);
  background: #fff;
  border: 1px solid rgba(21, 44, 84, .05);
  border-radius: 20px;
  box-shadow: 0 18px 40px -26px rgba(15, 30, 60, .22);
  display: flex; align-items: center;
  gap: clamp(14px, 1.8vw, 24px);
  padding: clamp(14px, 1.8vw, 22px) clamp(16px, 2.2vw, 30px);
}
.fx-bar-ic {
  display: grid; place-items: center; flex: none;
  width: clamp(40px, 3.6vw, 52px); height: clamp(40px, 3.6vw, 52px);
  border-radius: 14px;
  background: #ecf3fd;
  color: var(--accent);
}
.fx-bar-ic svg { width: 58%; height: 58%; stroke-width: 1.7; }
.fx-bar-copy b {
  display: block;
  font-size: clamp(.9rem, 1.1vw, 1.02rem);
  font-weight: 700;
  color: #1d2b45;
  margin-bottom: 2px;
}
.fx-bar-copy p {
  font-size: clamp(.78rem, .95vw, .88rem);
  color: #64748b;
  max-width: 36em;
}
.fx-bar-wave { flex: 1; min-width: 120px; height: clamp(38px, 4vw, 56px); margin-left: auto; overflow: visible; }
.fx-bar-wave path {
  fill: none;
  stroke: #c3d4ea; stroke-width: 1.6;
  vector-effect: non-scaling-stroke;
  stroke-linecap: round;
  stroke-dasharray: .004 .009;
  animation: ofi-wave 2.6s linear infinite;
}
@keyframes ofi-wave { to { stroke-dashoffset: -.026; } }
.fx-bar-wave .fx-wd {
  fill: #2f80ee; stroke: none;
  transform-box: fill-box; transform-origin: center;
  animation: ofi-wd 2.8s ease-in-out infinite;
}
.fx-bar-wave .fx-d-1 { animation-delay: 0s; }
.fx-bar-wave .fx-d-2 { animation-delay: .45s; }
.fx-bar-wave .fx-d-3 { animation-delay: .9s; }
.fx-bar-wave .fx-d-4 { animation-delay: 1.35s; }
.fx-bar-wave .fx-d-5 { animation-delay: 1.8s; }
@keyframes ofi-wd {
  0%, 100% { opacity: .3; transform: scale(.65); }
  50%      { opacity: 1; transform: scale(1.1); }
}

/* ══════════ entrance choreography ══════════
   Strictly sequential "assembly line": each card materialises with a
   left→right clip wipe (blur clearing as it lands), then its arrow
   pops out of it and "creates" the next card down the pipeline.
   Hidden states use the standalone translate/scale properties so
   they never fight the rotate() the arrows get on mobile.
   NOTE: the revealed clip-path keeps a large negative inset so the
   cards' drop shadows are never clipped once the wipe completes. */
.fx-ofi-flow .fx-ofi-col {
  opacity: 0; translate: -30px 14px; scale: .95;
  clip-path: inset(-70px 105% -70px -70px);
  filter: blur(7px);
  transition:
    opacity   .5s var(--ease),
    translate .7s cubic-bezier(.22, 1.1, .36, 1),
    scale     .7s cubic-bezier(.22, 1.1, .36, 1),
    clip-path .7s cubic-bezier(.6, .05, .3, 1),
    filter    .55s ease;
}
.fx-ofi-flow.fx-in .fx-ofi-col {
  opacity: 1; translate: 0 0; scale: 1;
  clip-path: inset(-70px -70px -70px -70px);
  filter: blur(0);
}
/* connector wires grow out of the finished card toward the next one
   (pathLength=1 stroke draw); arrowhead + data dots light up once
   the wire has reached the other side */
.fx-lk {
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
  transition: stroke-dashoffset .5s cubic-bezier(.5, .1, .3, 1);
}
.fx-ofi-flow.fx-in .fx-lk { stroke-dashoffset: 0; }
/* the shine rail slides out from behind the finished card too */
.fx-lk-base {
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
  transition: stroke-dashoffset .55s cubic-bezier(.5, .1, .3, 1);
}
.fx-ofi-flow.fx-in .fx-lk-base { stroke-dashoffset: 0; }
.fx-lk-head, .fx-lk-dot, .fx-lk-shine { opacity: 0; transition: opacity .4s ease; }
.fx-ofi-flow.fx-in .fx-lk-head, .fx-ofi-flow.fx-in .fx-lk-dot, .fx-ofi-flow.fx-in .fx-lk-shine { opacity: 1; }

/* one element at a time: card → its contents → wire → next card */
.fx-ofi-flow.fx-in .fx-ofi-signals { transition-delay: .05s; }
.fx-ofi-flow.fx-in .fx-ofi-sources { transition-delay: .5s; }
.fx-ofi-flow.fx-in .fx-l-1 .fx-lk, .fx-ofi-flow.fx-in .fx-l-1 .fx-lk-base { transition-delay: 1.1s; }
.fx-ofi-flow.fx-in .fx-l-1 .fx-lk-head, .fx-ofi-flow.fx-in .fx-l-1 .fx-lk-dot, .fx-ofi-flow.fx-in .fx-l-1 .fx-lk-shine { transition-delay: 1.55s; }
.fx-ofi-flow.fx-in .fx-ofi-hub      { transition-delay: 1.3s; }
.fx-ofi-flow.fx-in .fx-l-2 .fx-lk, .fx-ofi-flow.fx-in .fx-l-2 .fx-lk-base { transition-delay: 1.95s; }
.fx-ofi-flow.fx-in .fx-l-2 .fx-lk-head, .fx-ofi-flow.fx-in .fx-l-2 .fx-lk-dot, .fx-ofi-flow.fx-in .fx-l-2 .fx-lk-shine { transition-delay: 2.4s; }
.fx-ofi-flow.fx-in .fx-ofi-ai       { transition-delay: 2.15s; }
.fx-ofi-flow.fx-in .fx-l-3 .fx-lk, .fx-ofi-flow.fx-in .fx-l-3 .fx-lk-base { transition-delay: 2.8s; }
.fx-ofi-flow.fx-in .fx-l-3 .fx-lk-head, .fx-ofi-flow.fx-in .fx-l-3 .fx-lk-dot, .fx-ofi-flow.fx-in .fx-l-3 .fx-lk-shine { transition-delay: 3.25s; }
.fx-ofi-flow.fx-in .fx-ofi-action   { transition-delay: 3s; }
.fx-ofi-flow.fx-in .fx-l-4 .fx-lk, .fx-ofi-flow.fx-in .fx-l-4 .fx-lk-base { transition-delay: 3.65s; }
.fx-ofi-flow.fx-in .fx-l-4 .fx-lk-head, .fx-ofi-flow.fx-in .fx-l-4 .fx-lk-dot, .fx-ofi-flow.fx-in .fx-l-4 .fx-lk-shine { transition-delay: 4.1s; }
.fx-ofi-flow.fx-in .fx-ofi-erp      { transition-delay: 3.85s; }

/* signal rows type themselves in while the card wipe passes over */
.fx-ofi-signals li { opacity: 0; translate: -12px 0; transition: opacity .55s var(--ease), translate .55s var(--ease); }
.fx-ofi-flow.fx-in .fx-ofi-signals li { opacity: 1; translate: 0 0; }
.fx-ofi-flow.fx-in .fx-ofi-signals li:nth-child(1)  { transition-delay: .3s; }
.fx-ofi-flow.fx-in .fx-ofi-signals li:nth-child(2)  { transition-delay: .36s; }
.fx-ofi-flow.fx-in .fx-ofi-signals li:nth-child(3)  { transition-delay: .42s; }
.fx-ofi-flow.fx-in .fx-ofi-signals li:nth-child(4)  { transition-delay: .48s; }
.fx-ofi-flow.fx-in .fx-ofi-signals li:nth-child(5)  { transition-delay: .54s; }
.fx-ofi-flow.fx-in .fx-ofi-signals li:nth-child(6)  { transition-delay: .6s; }
.fx-ofi-flow.fx-in .fx-ofi-signals li:nth-child(7)  { transition-delay: .66s; }
.fx-ofi-flow.fx-in .fx-ofi-signals li:nth-child(8)  { transition-delay: .72s; }
.fx-ofi-flow.fx-in .fx-ofi-signals li:nth-child(9)  { transition-delay: .78s; }
.fx-ofi-flow.fx-in .fx-ofi-signals li:nth-child(10) { transition-delay: .84s; }

/* source nodes pop one by one, wires fade in behind them */
.fx-src-node { opacity: 0; scale: .4; transition: opacity .45s var(--ease), scale .5s cubic-bezier(.34, 1.6, .5, 1); }
.fx-ofi-flow.fx-in .fx-src-node { opacity: 1; scale: 1; }
.fx-ofi-flow.fx-in .fx-n-1 { transition-delay: .8s; }
.fx-ofi-flow.fx-in .fx-n-2 { transition-delay: .88s; }
.fx-ofi-flow.fx-in .fx-n-3 { transition-delay: .96s; }
.fx-ofi-flow.fx-in .fx-n-4 { transition-delay: 1.04s; }
.fx-ofi-flow.fx-in .fx-n-5 { transition-delay: 1.12s; }
.fx-src-wires { opacity: 0; transition: opacity .8s ease; }
.fx-ofi-flow.fx-in .fx-src-wires { opacity: 1; transition-delay: 1s; }

/* hub contents assemble after the blue shell wipes in */
.fx-hub-mark, .fx-ofi-hub b, .fx-ofi-hub i {
  opacity: 0; translate: 0 12px;
  transition: opacity .5s var(--ease), translate .5s var(--ease);
}
.fx-ofi-flow.fx-in .fx-hub-mark, .fx-ofi-flow.fx-in .fx-ofi-hub b, .fx-ofi-flow.fx-in .fx-ofi-hub i { opacity: 1; translate: 0 0; }
.fx-ofi-flow.fx-in .fx-hub-mark  { transition-delay: 1.6s; }
.fx-ofi-flow.fx-in .fx-ofi-hub b { transition-delay: 1.72s; }
.fx-ofi-flow.fx-in .fx-ofi-hub i { transition-delay: 1.82s; }

/* AI orb blooms, bullets tick in beneath it */
.fx-ai-orb { opacity: 0; scale: .5; transition: opacity .5s var(--ease), scale .6s cubic-bezier(.34, 1.5, .5, 1); }
.fx-ofi-flow.fx-in .fx-ai-orb { opacity: 1; scale: 1; transition-delay: 2.45s; }
.fx-ofi-ai li, .fx-ofi-action li, .fx-erp-logos > span {
  opacity: 0; translate: 0 10px;
  transition: opacity .55s var(--ease), translate .55s var(--ease);
}
.fx-ofi-flow.fx-in .fx-ofi-ai li, .fx-ofi-flow.fx-in .fx-ofi-action li, .fx-ofi-flow.fx-in .fx-erp-logos > span { opacity: 1; translate: 0 0; }
.fx-ofi-flow.fx-in .fx-ofi-ai li:nth-child(1) { transition-delay: 2.65s; }
.fx-ofi-flow.fx-in .fx-ofi-ai li:nth-child(2) { transition-delay: 2.73s; }
.fx-ofi-flow.fx-in .fx-ofi-ai li:nth-child(3) { transition-delay: 2.81s; }
.fx-ofi-flow.fx-in .fx-ofi-ai li:nth-child(4) { transition-delay: 2.89s; }

/* action rows stamp in one after another */
.fx-ofi-flow.fx-in .fx-ofi-action li:nth-child(1) { transition-delay: 3.35s; }
.fx-ofi-flow.fx-in .fx-ofi-action li:nth-child(2) { transition-delay: 3.43s; }
.fx-ofi-flow.fx-in .fx-ofi-action li:nth-child(3) { transition-delay: 3.51s; }
.fx-ofi-flow.fx-in .fx-ofi-action li:nth-child(4) { transition-delay: 3.59s; }
.fx-ofi-flow.fx-in .fx-ofi-action li:nth-child(5) { transition-delay: 3.67s; }

/* ERP logos land last, closing the build */
.fx-ofi-flow.fx-in .fx-erp-logos > span:nth-child(1) { transition-delay: 4.2s; }
.fx-ofi-flow.fx-in .fx-erp-logos > span:nth-child(2) { transition-delay: 4.3s; }
.fx-ofi-flow.fx-in .fx-erp-logos > span:nth-child(3) { transition-delay: 4.4s; }
.fx-ofi-flow.fx-in .fx-erp-logos > span:nth-child(4) { transition-delay: 4.5s; }

/* wave dots wait for the bar's own reveal */
.fx-ofi-bar .fx-bar-wave { opacity: 0; transition: opacity .9s ease .3s; }
.fx-ofi-bar.fx-in .fx-bar-wave { opacity: 1; }

/* ══════════ responsive ══════════ */
/* strip wrapper: the nav arrows anchor to it; they only exist on
   the narrow snap-strip layout below */
.fx-ofi-strip { position: relative; }
.fx-ofi-nav { display: none; }

@media (max-width: 1060px) {
  /* the pipeline stays side-by-side: a swipeable horizontal strip of
     desktop-style cards. Every card snaps dead-centre; the end padding
     lets the first and last cards reach the centre too. integrations.js
     drives the floating prev/next arrows that hint at hidden cards. */
  .fx-ofi-flow {
    display: flex;
    overflow-x: auto;
    gap: clamp(10px, 2vw, 16px);
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
    scroll-snap-type: x mandatory;
    /* 50% resolves against the parent, not the scrollport, so the
       +16px keeps the first/last cards' snap centres safely inside
       the scroll range — snap-align centres them exactly anyway */
    padding-inline: calc(50% - min(39vw, 160px) + 16px);
  }
  .fx-ofi-flow::-webkit-scrollbar { display: none; }
  /* one uniform width so every card sits identically centred */
  .fx-ofi-col { flex: none; width: min(78vw, 320px); scroll-snap-align: center; }
  .fx-ofi-link { flex: none; width: 44px; height: 112px; }
  .fx-src-map { min-height: 250px; }
  .fx-ofi-ai li, .fx-ofi-action li, .fx-ofi-signals li { white-space: normal; }

  /* ── floating strip arrows ──
     .fx-can-right / .fx-can-left on .fx-ofi-strip (set by integrations.js from
     scrollLeft) decide which side is visible: the right arrow shows
     while more cards hide off-screen, the left one appears once the
     user has scrolled away from the start. Both nudge sideways so
     they read as "more this way". */
  .fx-ofi-nav {
    position: absolute; z-index: 3;
    top: 50%; translate: 0 -50%; scale: .6;
    display: grid; place-items: center;
    width: 42px; height: 42px; padding: 0;
    border-radius: 50%;
    border: 1px solid #d7e5f7;
    background: #fff;
    color: var(--accent);
    box-shadow: 0 12px 26px -10px rgba(15, 30, 60, .4);
    cursor: pointer;
    opacity: 0; pointer-events: none;
    transition: opacity .3s var(--ease), scale .35s cubic-bezier(.34, 1.5, .5, 1);
  }
  .fx-ofi-nav svg {
    width: 20px; height: 20px;
    fill: none; stroke: currentColor; stroke-width: 2.2;
    stroke-linecap: round; stroke-linejoin: round;
  }
  .fx-ofi-prev { left: 4px; }
  .fx-ofi-next { right: 4px; }
  .fx-ofi-strip.fx-can-left  .fx-ofi-prev,
  .fx-ofi-strip.fx-can-right .fx-ofi-next { opacity: 1; pointer-events: auto; scale: 1; }
  .fx-ofi-strip.fx-can-right .fx-ofi-next { animation: ofi-nudge-r 1.6s ease-in-out infinite; }
  .fx-ofi-strip.fx-can-left  .fx-ofi-prev { animation: ofi-nudge-l 1.6s ease-in-out infinite; }
}
@keyframes ofi-nudge-r { 0%, 100% { transform: translateX(0); } 50% { transform: translateX(4px); } }
@keyframes ofi-nudge-l { 0%, 100% { transform: translateX(0); } 50% { transform: translateX(-4px); } }

@media (max-width: 640px) {
  .fx-ofi-head .fx-lead { font-size: .88rem; line-height: 1.55; }
  .fx-ofi-signals li { font-size: .82rem; }
  .fx-ofi-bar { flex-wrap: wrap; }
  .fx-bar-wave { flex-basis: 100%; margin-left: 0; }
}

/* ══════════ reduced motion ══════════ */
@media (prefers-reduced-motion: reduce) {
  .fx-src-node, .fx-src-wires path, .fx-lk, .fx-lk-shine, .fx-ofi-hub, .fx-hub-mark,
  .fx-hub-sheen, .fx-ai-ring, .fx-bar-wave path, .fx-bar-wave .fx-wd, .fx-ofi-nav { animation: none; }
  .fx-hub-sheen, .fx-ai-ring, .fx-lk-dot, .fx-lk-shine { display: none; }
  .fx-lk, .fx-lk-base { stroke-dashoffset: 0; }
  .fx-lk-head { opacity: 1; }
  .fx-ofi-flow .fx-ofi-col,
  .fx-ofi-signals li, .fx-src-node, .fx-src-wires,
  .fx-hub-mark, .fx-ofi-hub b, .fx-ofi-hub i, .fx-ai-orb,
  .fx-ofi-ai li, .fx-ofi-action li, .fx-erp-logos > span, .fx-ofi-bar .fx-bar-wave {
    opacity: 1; translate: 0 0; scale: 1;
    clip-path: none; filter: none; transition: none;
  }
}

/* ===== telematics.css ===== */
/* =========== TELEMATICS INTEGRATION — LIVE DATA SHOWCASE ===========
   Ad-style stage modeled on a banking-app poster: rounded blue gradient
   panel, a giant ghost word across the top, a CSS-built phone rising from
   the bottom edge, frosted-glass telematics cards floating on both sides,
   and small corner labels. Copy above uses the shared kicker/h2/lead. */
.fx-telematics {
  position: relative;
  padding: 90px 0 96px;
  background: var(--bg);
  overflow: hidden;
}

.fx-tm-title {
  position: relative; z-index: 1;
  /* sized so the whole line fits on one row on desktop */
  font-size: clamp(1.45rem, 3.4vw, 2.95rem);
}
@media (min-width: 900px) { .fx-tm-title { white-space: nowrap; } }
.fx-tm-lead { margin: 18px auto 0; }

/* ───────── the stage panel ───────── */
.fx-tm-stage {
  position: relative;
  /* break out of the 1180px container to a near full-bleed banner */
  width: min(1560px, 96vw);
  left: 50%;
  margin-left: calc(min(1560px, 96vw) / -2);
  margin-top: clamp(34px, 5vw, 56px);
  border-radius: clamp(22px, 3vw, 34px);
  min-height: clamp(500px, 44vw, 680px);
  overflow: hidden;
  /* bright glow upper-left, deepening toward the right edge */
  background:
    radial-gradient(120% 150% at 12% -20%, rgba(214, 234, 255, .55) 0%, rgba(214, 234, 255, 0) 46%),
    linear-gradient(112deg, #4f8ff2 0%, #2f74e8 38%, #1d5bd4 72%, #1547b6 100%);
  box-shadow: 0 40px 80px -36px rgba(17, 74, 182, .55);
}

/* giant ghost word across the top, fading downward like watermark type */
.fx-tm-ghost {
  position: absolute;
  top: clamp(4px, 1.4vw, 18px);
  left: 0; right: 0;
  text-align: center;
  font-weight: 800;
  font-size: clamp(2.6rem, 11.6vw, 11.4rem);
  letter-spacing: .015em;
  line-height: 1;
  white-space: nowrap;
  user-select: none;
  background: linear-gradient(180deg, rgba(255, 255, 255, .30) 0%, rgba(255, 255, 255, .05) 92%);
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent; color: transparent;
}

/* ───────── phone ───────── */
.fx-tm-phone-wrap {
  position: absolute;
  left: 50%;
  bottom: clamp(-160px, -13vw, -110px); /* cropped by the panel edge, like a held phone */
  transform: translateX(-50%);
  z-index: 3;
  filter: drop-shadow(0 40px 54px rgba(6, 26, 70, .5));
}
.fx-tm-phone {
  width: 288px; height: 600px;
  border-radius: 46px;
  background: #050506;
  padding: 10px;
  box-shadow:
    inset 0 0 0 1.5px rgba(255, 255, 255, .28),
    0 0 0 5px #101116;
}
.fx-tm-screen {
  position: relative;
  width: 100%; height: 100%;
  border-radius: 37px;
  overflow: hidden;
  background:
    radial-gradient(130% 45% at 50% -8%, #dbe8ff 0%, rgba(219, 232, 255, 0) 60%),
    #f2f5fb;
  display: flex; flex-direction: column;
}
.fx-tm-island {
  position: absolute; top: 9px; left: 50%; transform: translateX(-50%);
  width: 86px; height: 24px; border-radius: 16px; background: #000; z-index: 2;
}

/* greeting bar */
.fx-tm-greet {
  display: flex; align-items: center; gap: 9px;
  padding: 44px 16px 0;
}
.fx-tm-avatar {
  width: 34px; height: 34px; border-radius: 50%;
  background: #e3edff; overflow: hidden;
  display: grid; place-items: center; flex: none;
}
.fx-tm-avatar img { width: 24px; height: 24px; }
.fx-tm-greet-txt { display: flex; flex-direction: column; line-height: 1.25; }
.fx-tm-greet-txt small { font-size: 10px; color: #7a8296; font-weight: 600; }
.fx-tm-greet-txt b { font-size: 12.5px; color: var(--ink); letter-spacing: -.01em; }
.fx-tm-greet-btns { margin-left: auto; display: flex; gap: 6px; }
.fx-tm-greet-btns i {
  width: 26px; height: 26px; border-radius: 50%;
  background: #fff; border: 1px solid #e4e8f2; display: block;
}

/* odometer hero number */
.fx-tm-odo { padding: 12px 16px 0; line-height: 1.1; }
.fx-tm-odo small {
  display: block; font-size: 10.5px; font-weight: 700;
  color: var(--accent); text-transform: uppercase; letter-spacing: .08em;
}
.fx-tm-odo b {
  font-size: 30px; font-weight: 800; letter-spacing: -.03em; color: var(--ink);
}
.fx-tm-odo em { font-style: normal; font-size: 16px; font-weight: 700; color: #7a8296; }

/* mini card row */
.fx-tm-cardrow {
  display: flex; gap: 7px;
  padding: 12px 16px 0;
}
.fx-tm-add {
  flex: none; width: 40px; border-radius: 13px;
  background: #fff; border: 1px solid #e4e8f2;
  display: grid; place-items: center;
  font-size: 18px; font-weight: 600; color: var(--accent);
}
.fx-tm-minicard {
  flex: 1;
  background: #fff; border: 1px solid #e4e8f2; border-radius: 13px;
  padding: 9px 11px;
  display: flex; flex-direction: column; gap: 1px;
}
.fx-tm-mc-ico {
  width: 20px; height: 20px; border-radius: 6px;
  display: grid; place-items: center; margin-bottom: 5px;
  color: #fff;
}
.fx-tm-mc-ico svg { width: 13px; height: 13px; }
.fx-tm-mc-ico.fx-blue { background: linear-gradient(160deg, #2f86ef, #0b63d8); }
.fx-tm-mc-ico.fx-dark { background: #1d1d1f; }
.fx-tm-minicard small { font-size: 9.5px; color: #7a8296; font-weight: 600; }
.fx-tm-minicard b { font-size: 13px; color: var(--ink); letter-spacing: -.01em; }

/* section label */
.fx-tm-sec { padding: 14px 16px 6px; }
.fx-tm-sec span { font-size: 12px; font-weight: 700; color: var(--ink); letter-spacing: -.01em; }

/* vehicle-health rows */
.fx-tm-rows { display: flex; flex-direction: column; gap: 6px; padding: 0 16px; }
.fx-tm-row {
  display: flex; align-items: center; gap: 9px;
  background: #fff; border: 1px solid #e4e8f2; border-radius: 12px;
  padding: 8px 10px;
}
.fx-tm-r-ico {
  flex: none; width: 26px; height: 26px; border-radius: 8px;
  background: #ecf3ff; color: var(--accent);
  display: grid; place-items: center;
}
.fx-tm-r-ico svg { width: 15px; height: 15px; }
.fx-tm-r-txt { display: flex; flex-direction: column; line-height: 1.3; min-width: 0; }
.fx-tm-r-txt b { font-size: 11.5px; color: var(--ink); letter-spacing: -.01em; }
.fx-tm-r-txt small { font-size: 9.5px; color: #7a8296; }
.fx-tm-row em {
  margin-left: auto; font-style: normal;
  font-size: 10px; font-weight: 700;
}
.fx-tm-row em.fx-ok { color: #1fa04b; }

/* bottom tabs + nav (partially cropped by the panel edge) */
.fx-tm-tabs { display: flex; gap: 7px; padding: 10px 16px 0; }
.fx-tm-tabs span {
  flex: 1; background: #fff; border: 1px solid #e4e8f2; border-radius: 12px;
  padding: 10px 12px; font-size: 11.5px; font-weight: 700; color: var(--ink);
}
.fx-tm-nav {
  margin-top: auto;
  display: flex; align-items: center; justify-content: space-around;
  padding: 10px 22px 18px;
}
.fx-tm-nav i { width: 18px; height: 18px; border-radius: 5px; background: #d3d9e6; display: block; }
.fx-tm-nav-core {
  width: 42px; height: 42px; border-radius: 50%;
  background: linear-gradient(160deg, #2f86ef, #0b63d8);
  color: #fff; display: grid; place-items: center;
  box-shadow: 0 8px 18px -6px rgba(11, 99, 216, .7);
  margin-top: -14px;
}
.fx-tm-nav-core svg { width: 20px; height: 20px; }

/* ───────── floating glass cards ───────── */
.fx-tm-float {
  position: absolute; z-index: 2;
  border-radius: 16px;
  padding: 14px 16px;
  color: #fff;
  background: rgba(255, 255, 255, .13);
  border: 1px solid rgba(255, 255, 255, .28);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  box-shadow: 0 22px 44px -18px rgba(8, 34, 96, .5);
  width: clamp(150px, 17.5vw, 232px);
}

/* on the full-bleed banner the phone grows with the panel */
@media (min-width: 1200px) {
  .fx-tm-phone-wrap { scale: 1.12; transform-origin: 50% 100%; bottom: -150px; }
}

/* upper-left · GPS / speed (the "bank card") */
.fx-tm-gps { left: 8%; top: 26%; }
.fx-tm-gps-top {
  display: flex; align-items: baseline; justify-content: space-between;
  margin-bottom: clamp(18px, 3vw, 34px);
}
.fx-tm-gps-top b { font-size: .95rem; letter-spacing: .05em; }
.fx-tm-gps-top span { font-size: .68rem; font-weight: 700; letter-spacing: .1em; opacity: .85; }
.fx-tm-gps small { display: block; font-size: .72rem; opacity: .82; }
.fx-tm-gps-val { font-size: 1.25rem; font-weight: 700; letter-spacing: -.01em; }

/* lower-left · utilization with progress bar */
.fx-tm-util { left: 5%; bottom: 14%; }
.fx-tm-f-head { display: flex; align-items: flex-start; justify-content: space-between; }
.fx-tm-f-txt { display: flex; flex-direction: column; line-height: 1.3; font-size: .82rem; font-weight: 600; }
.fx-tm-f-txt small { font-size: .68rem; font-weight: 500; opacity: .78; }
.fx-tm-f-ico {
  flex: none; width: 26px; height: 26px; border-radius: 8px;
  background: rgba(255, 255, 255, .22);
  display: grid; place-items: center; color: #fff;
}
.fx-tm-f-ico svg { width: 15px; height: 15px; }
.fx-tm-f-val { display: block; font-size: 1.35rem; font-weight: 700; margin-top: 10px; letter-spacing: -.01em; }
.fx-tm-bar {
  display: block; height: 5px; border-radius: 3px;
  background: rgba(255, 255, 255, .25); margin-top: 9px; overflow: hidden;
}
.fx-tm-bar i { display: block; height: 100%; width: 82%; border-radius: 3px; background: #fff; }

/* center-right · glowing signal button */
.fx-tm-pulse {
  position: absolute; z-index: 2;
  right: 13%; top: 34%;
  width: 76px; height: 76px;
}
.fx-tm-core {
  position: absolute; inset: 0;
  border-radius: 50%;
  background: radial-gradient(120% 120% at 30% 20%, #6fb2ff 0%, #2e7ceb 55%, #1b5fd6 100%);
  border: 1px solid rgba(255, 255, 255, .45);
  color: #fff; display: grid; place-items: center;
  box-shadow: 0 14px 34px -10px rgba(9, 40, 110, .65);
}
.fx-tm-core svg { width: 30px; height: 30px; }
.fx-tm-ring {
  /* margin-centred (not transform-centred) so the ping `scale` animation
     expands around the ring's own centre */
  position: absolute; left: 50%; top: 50%;
  border-radius: 50%;
  border: 1px solid rgba(255, 255, 255, .35);
}
.fx-tm-ring.fx-r1 { width: 112px; height: 112px; margin: -56px 0 0 -56px; }
.fx-tm-ring.fx-r2 { width: 148px; height: 148px; margin: -74px 0 0 -74px; border-color: rgba(255, 255, 255, .18); }

/* lower-right · fault codes */
.fx-tm-fault { right: 7%; bottom: 15%; }
.fx-tm-f-sub { display: block; font-size: .68rem; opacity: .8; margin-top: 5px; line-height: 1.35; }

/* corner labels */
.fx-tm-label {
  position: absolute; z-index: 2; bottom: clamp(16px, 2.6vw, 30px);
  color: #fff; font-weight: 600;
  font-size: clamp(.82rem, 1.2vw, 1rem);
  letter-spacing: -.01em;
}
.fx-tm-label-l { left: clamp(18px, 3vw, 38px); }
.fx-tm-label-r { right: clamp(18px, 3vw, 38px); }

/* closing copy */
.fx-tm-note {
  margin-top: clamp(34px, 5vw, 52px);
  text-align: center;
  color: var(--ink-2);
  font-size: clamp(.95rem, 1.2vw, 1.05rem);
}

/* portal + page buttons under the note (mirrors .fx-aiau-actions) */
.fx-tm-actions {
  display: flex; justify-content: center; flex-wrap: wrap;
  gap: 14px;
  margin-top: clamp(20px, 2.5vw, 30px);
}
.fx-tm-btn { padding: 12px 26px; font-size: 0.95rem; }

/* ───────── responsive ───────── */
@media (max-width: 980px) {
  .fx-tm-pulse { display: none; } /* frees the right side for the fault card */
  .fx-tm-gps { top: 22%; }
}
@media (max-width: 760px) {
  .fx-telematics { padding: 60px 0 66px; }
  .fx-tm-stage { min-height: 470px; }
  .fx-tm-phone-wrap { bottom: -170px; transform: translateX(-50%) scale(.86); transform-origin: bottom center; }
  .fx-tm-float { width: 148px; padding: 11px 13px; }
  .fx-tm-util { display: none; }
  .fx-tm-gps { left: 4%; top: 20%; }
  .fx-tm-fault { right: 4%; bottom: 12%; }
  .fx-tm-label { display: none; }
  .fx-tm-note br { display: none; }
}
@media (max-width: 520px) {
  .fx-tm-stage { min-height: 440px; }
  .fx-tm-phone-wrap { transform: translateX(-50%) scale(.78); bottom: -200px; }
  /* not enough room beside the phone — keep just the GPS card (it sits on
     blue; the fault card would wash out over the white phone screen) */
  .fx-tm-float { width: 122px; padding: 10px 12px; z-index: 4; }
  .fx-tm-gps { left: 3%; top: 20%; }
  .fx-tm-gps-top { margin-bottom: 14px; }
  .fx-tm-fault { display: none; }
}

/* ───────── entrance choreography ─────────
   The shared reveal system toggles .fx-in on .fx-tm-stage. The panel settles
   first, then the ghost word fades through, the phone rises out of the
   bottom edge, and the glass cards pop in one after another. Standalone
   translate/scale so the centring transform on the phone is never fought. */
.fx-tm-stage.fx-reveal {
  opacity: 0; transform: translateY(26px);
  transition: opacity .65s var(--ease), transform .65s var(--ease);
}
.fx-tm-stage.fx-reveal.fx-in { opacity: 1; transform: none; }

.fx-tm-ghost { opacity: 0; transition: opacity .8s var(--ease); }
.fx-tm-phone-wrap {
  translate: 0 110px; opacity: 0;
  transition: opacity .7s var(--ease), translate 1s cubic-bezier(.22, 1, .36, 1);
}
.fx-tm-float, .fx-tm-pulse {
  opacity: 0; scale: .8;
  transition: opacity .55s var(--ease), scale .65s cubic-bezier(.22, 1, .36, 1);
}
.fx-tm-label { opacity: 0; transition: opacity .6s var(--ease); }

.fx-tm-stage.fx-in .fx-tm-ghost { opacity: 1; transition-delay: .15s; }
.fx-tm-stage.fx-in .fx-tm-phone-wrap { opacity: 1; translate: 0 0; transition-delay: .3s; }
.fx-tm-stage.fx-in .fx-tm-gps   { opacity: 1; scale: 1; transition-delay: .55s; }
.fx-tm-stage.fx-in .fx-tm-util  { opacity: 1; scale: 1; transition-delay: .68s; }
.fx-tm-stage.fx-in .fx-tm-pulse { opacity: 1; scale: 1; transition-delay: .8s; }
.fx-tm-stage.fx-in .fx-tm-fault { opacity: 1; scale: 1; transition-delay: .92s; }
.fx-tm-stage.fx-in .fx-tm-label { opacity: 1; transition-delay: 1.05s; }
.fx-tm-note.fx-reveal.fx-in { transition-delay: 1.1s; }

/* ───────── living data (loops that run after the entrance) ─────────
   Everything rests at its final state, so a paused frame still looks
   finished; the loops only start once .fx-in lands on the stage. */
@keyframes tm-bob   { 0%, 100% { translate: 0 0; } 50% { translate: 0 -9px; } }
@keyframes tm-ping  { 0% { scale: .55; opacity: .9; } 75% { opacity: 0; } 100% { scale: 1.85; opacity: 0; } }
@keyframes tm-glow  {
  0%, 100% { box-shadow: 0 14px 34px -10px rgba(9, 40, 110, .65); }
  50%      { box-shadow: 0 10px 46px -4px rgba(126, 182, 255, .9); }
}
@keyframes tm-fill  { 0%, 100% { width: 82%; } 50% { width: 74%; } }
@keyframes tm-blink { 0%, 100% { opacity: .9; } 50% { opacity: .35; } }
@keyframes tm-blip  { 0% { scale: 1; } 35% { scale: 1.14; } 100% { scale: 1; } }

/* glass cards drift gently, out of phase with each other */
.fx-tm-stage.fx-in .fx-tm-gps   { animation: tm-bob 6.5s ease-in-out 1.6s infinite; }
.fx-tm-stage.fx-in .fx-tm-util  { animation: tm-bob 7.5s ease-in-out 2.1s infinite; }
.fx-tm-stage.fx-in .fx-tm-fault { animation: tm-bob 7s ease-in-out 2.5s infinite; }

/* signal button: radar pings + breathing glow */
.fx-tm-stage.fx-in .fx-tm-ring.fx-r1 { animation: tm-ping 2.8s cubic-bezier(.2, .6, .4, 1) 1.6s infinite; }
.fx-tm-stage.fx-in .fx-tm-ring.fx-r2 { animation: tm-ping 2.8s cubic-bezier(.2, .6, .4, 1) 3s infinite; }
.fx-tm-stage.fx-in .fx-tm-core    { animation: tm-glow 3.4s ease-in-out 1.6s infinite; }
.fx-tm-stage.fx-in .fx-tm-nav-core { animation: tm-glow 3.4s ease-in-out 2.2s infinite; }

/* utilization bar breathes, LIVE tag blinks */
.fx-tm-stage.fx-in .fx-tm-bar i { animation: tm-fill 5.5s ease-in-out 2.2s infinite; }
.fx-tm-stage.fx-in .fx-tm-gps-top span { animation: tm-blink 1.9s ease-in-out 1.6s infinite; }

/* data-tick pop — telematics.js swaps a value then re-adds this class */
.fx-tm-gps-val, .fx-tm-odo-num, .fx-tm-live-coolant, .fx-tm-live-batt, .fx-tm-live-tire {
  display: inline-block; transform-origin: left center;
}
.fx-tm-blip { animation: tm-blip .5s var(--ease); }

/* ───────── scroll parallax ─────────
   telematics.js writes --tm-par on .fx-tm-stage (-1 stage entering below →
   +1 scrolled past); each layer multiplies it at its own depth via
   `transform`. The reveal choreography owns `translate`/`scale` and
   tm-bob animates `translate`, so driving parallax through the separate
   `transform` property composes with both instead of fighting them.
   Positive depth = background (lags the scroll), negative = foreground. */
.fx-tm-stage { --tm-amp: 1; }
.fx-tm-ghost      { transform: translateY(calc(var(--tm-par, 0) * var(--tm-amp) * 60px)); will-change: transform; }
.fx-tm-pulse      { transform: translateY(calc(var(--tm-par, 0) * var(--tm-amp) * 24px)); }
.fx-tm-phone      { transform: translateY(calc(var(--tm-par, 0) * var(--tm-amp) * -46px)); will-change: transform; }
.fx-tm-gps        { transform: translateY(calc(var(--tm-par, 0) * var(--tm-amp) * -26px)); }
.fx-tm-util       { transform: translateY(calc(var(--tm-par, 0) * var(--tm-amp) * -48px)); }
.fx-tm-fault      { transform: translateY(calc(var(--tm-par, 0) * var(--tm-amp) * -36px)); }
@media (max-width: 640px) { .fx-tm-stage { --tm-amp: .45; } }

@media (prefers-reduced-motion: reduce) {
  .fx-tm-stage.fx-reveal, .fx-tm-ghost, .fx-tm-phone-wrap, .fx-tm-float, .fx-tm-pulse, .fx-tm-label {
    opacity: 1; translate: none; scale: none; transform: none; transition: none;
  }
  .fx-tm-phone-wrap { transform: translateX(-50%); }
  .fx-tm-note.fx-reveal.fx-in { transition-delay: 0s; }
  .fx-telematics * { animation: none !important; }
}

/* ===== sap.css ===== */
/* ═══════════════════════════════════════════════
   SAP INTEGRATION — parallax showcase (sap.html)
   Layer model inside .fx-sapi-stage:
     .fx-sapi-photo  z1  full photo card
     .fx-sapi-title  z2  giant headline
     .fx-sapi-cutout z3  subject cutout (same framing as the photo)
   The section carries data-parallax="0.3"; home.js writes --para (px)
   and each layer multiplies it: title .55× (fastest), photo + cutout
   .22× (identical, so they stay pixel-registered). Scrolling makes
   the headline glide behind the woman and tablet. (The interim glass
   composite lives in assets/dead-code/sap-glass-composite.html.)
   .fx-sapi-media must NOT create a stacking context (no transform /
   z-index) or the title could no longer slot between its children.
   ═══════════════════════════════════════════════ */

.fx-sapi {
  padding: clamp(64px, 9vh, 120px) 0 clamp(56px, 7vh, 96px);
  background: var(--bg);
  overflow: clip; /* parallax overshoot stays inside the section */
}

.fx-sapi-stage {
  position: relative;
  width: min(1240px, 92vw);
  margin: 0 auto;
  display: flex;
  align-items: stretch; /* both columns end on the same baseline */
  gap: clamp(24px, 4vw, 56px);
}

/* ── giant sandwiched headline ── */
.fx-sapi-title {
  position: absolute;
  left: 0; right: 0;
  top: clamp(18px, 7vw, 86px);
  z-index: 2;
  line-height: 1;
  white-space: nowrap;
  pointer-events: none;
  /* damped travel: enough drift to slide behind the tablet, but the
     headline never sinks low enough to look cut off mid-scroll */
  transform: translate3d(0, calc(var(--para, 0px) * .55), 0);
  will-change: transform;
  /* the global h2 ink gradient would tint the span, kill it here */
  background-image: none;
  -webkit-text-fill-color: currentColor;
}
.fx-sapi-title span {
  display: inline-block;
  font-size: clamp(2.7rem, 10.2vw, 8rem);
  font-weight: 700;
  letter-spacing: -0.035em;
  word-spacing: 0.22em;
  /* blue over the white page, fading to white where it crosses the photo
     (photo left edge sits at ~66% of the text run on desktop) */
  background-image: linear-gradient(94deg, #1652d8 0%, #2563eb 42%, #2f80ee 56%, #ffffff 68%);
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent; color: transparent;
}

/* ── left copy column ── */
.fx-sapi-copy {
  position: relative;
  z-index: 4; /* sync card floats above the photo if they ever overlap */
  width: 44%;
  flex: none;
  display: flex; flex-direction: column; /* lets the sync card grow to the
                                            right column's bottom edge */
  padding-top: clamp(115px, 18vw, 225px); /* clears the absolute headline */
}
/* duo-tone sub-heading, same recipe as the site's h2s:
   ink→slate gradient with a blue .fx-h2-grad span inside */
.fx-sapi-copy h3 {
  font-size: clamp(1.35rem, 2vw, 1.8rem);
  max-width: 15em;
  background-image: linear-gradient(100deg, #0f0f10 0%, #3d3d42 45%, #a9a9b0 100%);
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent;
}
.fx-sapi-copy .fx-lead {
  margin-top: 14px;
  font-size: clamp(.95rem, 1.15vw, 1.1rem);
  max-width: 34em;
}

/* ── SAP sync dashboard card — full-column, Apple-style ──
   Deliberately outside the parallax (no --para transform): the card stays
   registered with the right column, its bottom edge landing on the same
   baseline as the graph card via the stretched flex column. */
.fx-sapi-sync {
  margin-top: clamp(34px, 4.5vh, 48px);
  background: #fff;
  border: 1px solid #eef2f9;
  border-radius: var(--radius);
  box-shadow: 0 2px 8px rgba(15, 30, 60, .06), 0 24px 48px -30px rgba(15, 30, 60, .28);
  padding: clamp(16px, 1.7vw, 22px) clamp(16px, 1.8vw, 24px);
  max-width: 520px;
  /* fill the column down to the stage's bottom edge; internals spread */
  flex: 1 1 auto;
  width: 100%;
  display: flex; flex-direction: column;
}

.fx-sync-head { display: flex; align-items: center; gap: 10px; }
.fx-sync-sap {
  flex: none;
  font-size: .82rem;
  font-weight: 800; font-style: italic;
  letter-spacing: .02em;
  color: #fff;
  background: linear-gradient(180deg, #3f9fda 0%, #0b6cb4 100%);
  padding: .2em .8em .2em .5em;
  clip-path: polygon(0 0, 100% 0, calc(100% - .75em) 100%, 0 100%);
  border-radius: 4px 0 0 4px;
}
.fx-sync-head b { font-size: .92rem; letter-spacing: -.01em; }
.fx-sync-live {
  margin-left: auto;
  display: inline-flex; align-items: center; gap: 6px;
  font-size: .72rem; font-weight: 700;
  color: #1f9d4d;
}
.fx-sync-live i {
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--green);
  box-shadow: 0 0 0 0 rgba(48, 209, 88, .5);
  animation: sapi-pulse 2.2s ease-out infinite;
}
@keyframes sapi-pulse {
  0%   { box-shadow: 0 0 0 0 rgba(48, 209, 88, .5); }
  70%  { box-shadow: 0 0 0 9px rgba(48, 209, 88, 0); }
  100% { box-shadow: 0 0 0 0 rgba(48, 209, 88, 0); }
}

.fx-sync-stats {
  margin-top: 12px;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px 10px;
}
.fx-sync-stats li {
  background: var(--bg-alt);
  border-radius: 14px;
  padding: 10px 13px;
  display: flex; flex-direction: column; gap: 1px;
}
.fx-sync-stats i {
  font-style: normal;
  font-size: .62rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: .08em;
  color: #8496af;
}
.fx-sync-stats b { font-size: .95rem; letter-spacing: -.01em; color: #1c2b45; }
.fx-sync-stats .fx-v-amber { color: #c77700; }
.fx-sync-stats .fx-v-ok { color: #1f9d4d; }

/* ── recent transfers feed ── */
.fx-sync-sub {
  margin-top: 16px;
  padding-top: 14px;
  border-top: 1px solid #eef2f9;
  display: flex; align-items: center; justify-content: space-between;
}
.fx-sync-sub span {
  font-size: .64rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: .08em;
  color: #8496af;
}
.fx-sync-sub em {
  font-style: normal;
  font-size: .68rem; font-weight: 700;
  color: #2563eb;
  background: #e8f0fe;
  padding: 3px 10px;
  border-radius: 999px;
}
.fx-sync-feed {
  margin-top: 10px;
  display: flex; flex-direction: column;
  justify-content: space-evenly; /* spare card height spreads between rows */
  flex: 1;
  gap: 8px;
}
.fx-sync-feed li {
  display: flex; align-items: center; gap: 10px;
  background: var(--bg-alt);
  border-radius: 14px;
  padding: 10px 12px;
}
.fx-sf-ico {
  flex: none;
  width: 32px; height: 32px;
  border-radius: 10px;
  display: grid; place-items: center;
  background: #e8f0fe;
  color: #2563eb;
}
.fx-sf-ico svg {
  width: 16px; height: 16px;
  fill: none; stroke: currentColor; stroke-width: 1.5;
  stroke-linecap: round; stroke-linejoin: round;
}
.fx-sync-feed li > div { min-width: 0; }
.fx-sync-feed b, .fx-sync-feed small {
  display: block;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.fx-sync-feed b { font-size: .78rem; letter-spacing: -.01em; color: #1c2b45; }
.fx-sync-feed small { font-size: .66rem; color: #8496af; }
.fx-sync-feed .fx-pill { margin-left: auto; }

/* ── next auto-sync footer — anchored to the card's bottom edge ── */
.fx-sync-next {
  margin-top: 14px;
  display: flex; align-items: center; gap: 12px;
}
.fx-sync-track {
  flex: 1;
  height: 5px;
  border-radius: 999px;
  background: #edf1f8;
  overflow: hidden;
}
.fx-sync-track i {
  display: block;
  width: 38%; height: 100%;
  border-radius: 999px;
  background: linear-gradient(90deg, #3a72e6, #1d4ed8);
  animation: sapi-fill 6s ease-in-out infinite;
}
@keyframes sapi-fill {
  0%   { width: 26%; }
  55%  { width: 62%; }
  100% { width: 26%; }
}
.fx-sync-eta { flex: none; font-size: .7rem; font-weight: 600; color: #64748b; }
.fx-sync-eta b { color: #1c2b45; }

/* portal + page buttons — centered row under the whole stage */
.fx-sapi-actions {
  display: flex; flex-wrap: wrap; justify-content: center;
  gap: 14px;
  width: min(1240px, 92vw);
  margin: clamp(30px, 4vw, 46px) auto 0;
}
.fx-sapi-btn { padding: 12px 26px; font-size: 0.95rem; }

/* status pills (shared with the flow strip legend) — scoped to .fx-sapi so
   they never fight the generic .fx-pill in features.css */
.fx-sapi .fx-pill {
  flex: none;
  font-style: normal;
  font-size: .68rem; font-weight: 700;
  letter-spacing: .02em;
  padding: 3px 10px;
  border-radius: 999px;
}
.fx-sapi .fx-p-ok   { color: #157a3c; background: #e5f7ec; }
.fx-sapi .fx-p-wait { color: #a36a00; background: #fdf3e0; animation: sapi-wait 1.6s ease-in-out infinite; }
.fx-sapi .fx-p-fail { color: #c22e2e; background: #fdeaea; }
@keyframes sapi-wait { 50% { opacity: .55; } }

/* ── right column: photo + flow strip beneath it ──
   Plain wrapper — no transform / z-index, so it never becomes a
   stacking context and the title keeps slotting between photo layers. */
.fx-sapi-right {
  flex: 1;
  min-width: 0;
  display: flex; flex-direction: column;
  gap: clamp(14px, 1.8vh, 20px);
}

/* ── photo composite ── */
.fx-sapi-media {
  position: relative;
  width: 100%;
  aspect-ratio: 1271 / 1236;
  border-radius: clamp(20px, 2.4vw, 34px);
  overflow: hidden;
  isolation: auto;
}

.fx-sapi-photo, .fx-sapi-cutout {
  position: absolute;
  inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  /* both share the same multiplier + bleed scale — never de-register */
  transform: translate3d(0, calc(var(--para, 0px) * .22), 0) scale(1.14);
  will-change: transform;
}
.fx-sapi-photo  { z-index: 1; }
.fx-sapi-cutout { z-index: 3; }
/* opacity-only reveal — translate would fight the parallax transform
   (.fx-reveal.fx-in sets transform: none, so both states restate their own) */
.fx-sapi-photo.fx-reveal, .fx-sapi-photo.fx-reveal.fx-in,
.fx-sapi-cutout.fx-reveal, .fx-sapi-cutout.fx-reveal.fx-in {
  transform: translate3d(0, calc(var(--para, 0px) * .22), 0) scale(1.14);
  transition: opacity .7s var(--ease);
}

/* ── event flow strip (sits under the photo, revealed on scroll) ── */
.fx-sapi-flow {
  background: #fff;
  border: 1px solid #eef2f9;
  border-radius: var(--radius);
  box-shadow: 0 2px 8px rgba(15, 30, 60, .06), 0 18px 40px -28px rgba(15, 30, 60, .24);
  padding: clamp(12px, 1.4vh, 16px) clamp(14px, 1.5vw, 20px);
  display: flex; flex-direction: column;
  gap: 10px;
}
.fx-fl-chain {
  display: flex; align-items: center;
  justify-content: space-between; /* chain spans the full card width */
  gap: clamp(3px, .45vw, 7px);
  flex-wrap: wrap;
}
.fx-fl-node {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: clamp(.62rem, .74vw, .72rem); font-weight: 700;
  color: #33415c;
  background: #fff;
  border: 1px solid #e6ecf5;
  box-shadow: 0 1px 3px rgba(15, 30, 60, .05);
  border-radius: 999px;
  padding: 6px 11px;
  white-space: nowrap;
}
.fx-fl-node svg {
  flex: none; width: 15px; height: 15px;
  fill: none; stroke: currentColor; stroke-width: 1.8;
  stroke-linecap: round; stroke-linejoin: round;
}
.fx-fl-bad { color: #c22e2e; background: #fdeeee; border-color: #f8dcdc; }
.fx-fl-fr  { color: #fff; background: linear-gradient(135deg, #3a72e6, #1d4ed8); border: none; }
.fx-fl-sap { border: none; }
.fx-fl-fr img { width: 15px; height: 15px; border-radius: 4px; }
.fx-fl-sap {
  color: #fff; font-style: italic; font-weight: 800;
  background: linear-gradient(180deg, #3f9fda 0%, #0b6cb4 100%);
  border-radius: 7px;
  padding: 7px 18px 7px 11px;
  clip-path: polygon(0 0, 100% 0, calc(100% - .8em) 100%, 0 100%);
}
.fx-fl-arrow { flex: none; width: clamp(16px, 1.5vw, 22px); height: 24px; overflow: visible; }
.fx-fl-arrow path {
  fill: none; stroke: #b9c8dd; stroke-width: 2;
  stroke-linecap: round; stroke-linejoin: round;
}
.fx-fl-arrow .fx-fa-line { stroke-dasharray: 5 7; animation: sapi-march 1.1s linear infinite; }
@keyframes sapi-march { to { stroke-dashoffset: -12; } }

.fx-fl-foot {
  display: flex; align-items: center; justify-content: space-between;
  gap: 8px 14px;
  padding-top: 10px;
  border-top: 1px solid #eef2f9;
  flex-wrap: wrap;
}
.fx-fl-note { font-size: .72rem; font-weight: 600; color: #64748b; }
.fx-fl-states { display: flex; gap: 6px; }

/* ── sync volume graph card (fills the space under the flow strip) ── */
.fx-sapi-graph {
  background: #fff;
  border: 1px solid #eef2f9;
  border-radius: var(--radius);
  box-shadow: 0 2px 8px rgba(15, 30, 60, .06), 0 18px 40px -28px rgba(15, 30, 60, .24);
  padding: clamp(14px, 1.6vh, 18px) clamp(14px, 1.6vw, 20px) clamp(12px, 1.4vh, 16px);
}
.fx-gr-head {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: 10px;
}
.fx-gr-titles b { display: block; font-size: .92rem; letter-spacing: -.01em; color: #1c2b45; }
.fx-gr-titles small { display: block; margin-top: 2px; font-size: .68rem; font-weight: 600; color: #8496af; }
.fx-gr-delta {
  flex: none;
  display: inline-flex; align-items: center; gap: 4px;
  font-size: .68rem; font-weight: 700;
  color: #2563eb;
  background: #e8f0fe;
  padding: 4px 10px;
  border-radius: 999px;
}
.fx-gr-delta svg {
  width: 11px; height: 11px;
  fill: none; stroke: currentColor; stroke-width: 1.8;
  stroke-linecap: round; stroke-linejoin: round;
}
.fx-gr-plot {
  position: relative;
  margin-top: 14px;
  height: clamp(120px, 13vw, 170px);
}
.fx-gr-plot > svg { position: absolute; inset: 0; width: 100%; height: 100%; }
.fx-gr-grid path { stroke: #edf1f8; stroke-width: 1; }
.fx-gr-line { stroke-width: 2.5; stroke-linecap: round; }
/* endpoint dot + value chip live in HTML so the stretched SVG can't distort
   them; percentages mirror the path's last point (554/560, 30/200) */
.fx-gr-dot {
  position: absolute;
  left: 98.9%; top: 15%;
  width: 10px; height: 10px;
  translate: -50% -50%;
  border-radius: 50%;
  background: #1d4ed8;
  border: 2px solid #fff;
  box-shadow: 0 0 0 4px rgba(37, 99, 235, .16);
}
.fx-gr-val {
  position: absolute;
  left: 98.9%; top: 15%;
  translate: calc(-100% - 14px) -50%;
  font-size: .72rem; font-weight: 700;
  color: #fff;
  background: #1c2b45;
  padding: 3px 9px;
  border-radius: 8px;
}
.fx-gr-x {
  margin-top: 8px;
  display: flex; justify-content: space-between;
  font-size: .64rem; font-weight: 600;
  color: #8496af;
}
/* line draws itself once the card reveals; area and endpoint fade after */
.fx-gr-line { stroke-dasharray: 1; stroke-dashoffset: 1; transition: stroke-dashoffset 1.3s var(--ease) .25s; }
.fx-sapi-graph.fx-in .fx-gr-line { stroke-dashoffset: 0; }
.fx-gr-area, .fx-gr-dot, .fx-gr-val {
  opacity: 0;
  transition: opacity .7s var(--ease) .95s;
}
.fx-sapi-graph.fx-in .fx-gr-area,
.fx-sapi-graph.fx-in .fx-gr-dot,
.fx-sapi-graph.fx-in .fx-gr-val { opacity: 1; }

/* ── entrance choreography ──
   Cards fade up via the shared .fx-reveal; their contents stagger in. */
.fx-sync-stats li,
.fx-sync-feed li,
.fx-fl-chain > * {
  opacity: 0; translate: 0 10px;
  transition: opacity .5s var(--ease), translate .5s var(--ease);
}
.fx-sapi-sync.fx-in .fx-sync-stats li,
.fx-sapi-sync.fx-in .fx-sync-feed li,
.fx-sapi-flow.fx-in .fx-fl-chain > * { opacity: 1; translate: 0 0; }
.fx-sapi-sync.fx-in .fx-sync-stats li:nth-child(1) { transition-delay: .15s; }
.fx-sapi-sync.fx-in .fx-sync-stats li:nth-child(2) { transition-delay: .23s; }
.fx-sapi-sync.fx-in .fx-sync-stats li:nth-child(3) { transition-delay: .31s; }
.fx-sapi-sync.fx-in .fx-sync-stats li:nth-child(4) { transition-delay: .39s; }
.fx-sapi-sync.fx-in .fx-sync-feed li:nth-child(1) { transition-delay: .47s; }
.fx-sapi-sync.fx-in .fx-sync-feed li:nth-child(2) { transition-delay: .55s; }
.fx-sapi-sync.fx-in .fx-sync-feed li:nth-child(3) { transition-delay: .63s; }
.fx-sapi-flow.fx-in .fx-fl-chain > :nth-child(1) { transition-delay: .1s; }
.fx-sapi-flow.fx-in .fx-fl-chain > :nth-child(2) { transition-delay: .25s; }
.fx-sapi-flow.fx-in .fx-fl-chain > :nth-child(3) { transition-delay: .4s; }
.fx-sapi-flow.fx-in .fx-fl-chain > :nth-child(4) { transition-delay: .55s; }
.fx-sapi-flow.fx-in .fx-fl-chain > :nth-child(5) { transition-delay: .7s; }
.fx-sapi-flow.fx-in .fx-fl-chain > :nth-child(6) { transition-delay: .85s; }
.fx-sapi-flow.fx-in .fx-fl-chain > :nth-child(7) { transition-delay: 1s; }

/* ═══════════ responsive ═══════════ */
@media (max-width: 900px) {
  .fx-sapi { padding-top: clamp(36px, 5vh, 56px); }
  .fx-sapi-stage { flex-direction: column; }
  /* phone: simple stacked layout — the headline sits in normal flow above
     the photo (the desktop z-sandwich/parallax breaks in in-app webviews:
     clipped title, white half invisible on the white page) */
  .fx-sapi-title {
    position: static;
    order: 0;
    white-space: normal;
    line-height: 1.05;
    margin-bottom: clamp(14px, 4vw, 22px);
    transform: none;
    will-change: auto;
  }
  .fx-sapi-title span {
    font-size: clamp(2.2rem, 11.5vw, 4rem);
    /* fully blue — no white fade, the heading no longer crosses the photo */
    background-image: linear-gradient(94deg, #1652d8 0%, #2563eb 55%, #2f80ee 100%);
  }
  .fx-sapi-right { order: 1; width: 100%; flex: none; }
  .fx-sapi-media {
    width: 100vw;
    margin-left: calc(50% - 50vw);
    border-radius: 0;
  }
  /* photo layers: no parallax drift / bleed scale on phone — the headline
     is out of the sandwich, so the layers just sit still and registered
     (selectors mirror the desktop reveal restatements so they all win) */
  .fx-sapi-photo, .fx-sapi-cutout,
  .fx-sapi-photo.fx-reveal, .fx-sapi-photo.fx-reveal.fx-in,
  .fx-sapi-cutout.fx-reveal, .fx-sapi-cutout.fx-reveal.fx-in {
    transform: none;
  }
  .fx-sapi-copy { order: 2; width: 100%; padding-top: 8px; }
  .fx-sapi-sync { max-width: none; }
  .fx-fl-states { margin-left: 0; width: 100%; }
}

@media (prefers-reduced-motion: reduce) {
  .fx-sync-live i, .fx-sapi .fx-p-wait, .fx-fa-line, .fx-sync-track i { animation: none; }
  .fx-sync-stats li, .fx-sync-feed li, .fx-fl-chain > * { opacity: 1; translate: 0 0; transition: none; }
  .fx-gr-line { stroke-dashoffset: 0; transition: none; }
  .fx-gr-area, .fx-gr-dot, .fx-gr-val { opacity: 1; transition: none; }
}

/* ===== aiaudit.css ===== */
/* ═══════════════════════════════════════════════
   AI AUDITOR — copy + photo + audit flow (below SAP)
   Left: big gradient heading, the paragraph info, then the tablet photo
   (./homepage-images/ai-auditor-tablet.webp). Right: audit workflow card —
   step → AI findings → recommended action → approve bar. Findings stagger
   in off the shared .fx-reveal on the aside. (The v3 animated graph is parked
   in dead-code/aiaudit-graph.*)
   ═══════════════════════════════════════════════ */
.fx-aiau { background: var(--bg); overflow: hidden; padding: clamp(96px, 14vw, 210px) 0 clamp(64px, 8vw, 110px); }

.fx-aiau-wrap {
  display: grid;
  grid-template-columns: 1.05fr 0.95fr;
  column-gap: clamp(40px, 5vw, 84px);
  align-items: start; /* card top aligns with the heading */
}

/* ───────── left: heading + copy + photo ───────── */
.fx-aiau-title {
  font-size: clamp(3.4rem, 8vw, 6rem);
  background-image: linear-gradient(100deg, #1d4ed8 0%, #2f80ee 55%, #6faef5 100%);
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent;
}
.fx-aiau-sub {
  margin-top: clamp(18px, 2.2vw, 26px);
  font-size: clamp(1.15rem, 1.8vw, 1.45rem);
  font-weight: 600; color: var(--ink);
  letter-spacing: -0.014em; line-height: 1.3;
}
.fx-aiau-desc {
  margin-top: 14px;
  font-size: clamp(0.98rem, 1.3vw, 1.1rem);
  color: var(--ink-2); max-width: 34em;
}

/* ───────── tablet photo ───────── */
.fx-aiau-photo {
  margin: clamp(28px, 3.5vw, 44px) 0 0;
  width: min(520px, 100%);
}
.fx-aiau-photo img {
  width: 100%;
  border-radius: 20px;
  border: 1px solid rgba(29, 29, 31, 0.06);
  box-shadow: 0 24px 52px rgba(29, 78, 216, 0.13);
  transition: transform .45s var(--ease), box-shadow .45s var(--ease);
}
.fx-aiau-photo img:hover { transform: translateY(-4px) scale(1.012); box-shadow: 0 30px 62px rgba(29, 78, 216, 0.18); }

/* ───────── right: audit workflow ───────── */
.fx-aiau-flow {
  background: var(--bg-alt);
  border: 1px solid rgba(29, 29, 31, 0.05);
  border-radius: 22px;
  padding: clamp(18px, 2.4vw, 28px);
}

.fx-af-card {
  background: #fff;
  border: 1px solid rgba(29, 29, 31, 0.06);
  border-radius: 16px;
  box-shadow: 0 10px 26px rgba(29, 78, 216, 0.07);
  transition: transform .35s var(--ease), box-shadow .35s var(--ease);
}
.fx-af-card:hover { transform: translateY(-3px); box-shadow: 0 16px 34px rgba(29, 78, 216, 0.13); }
.fx-af-step {
  display: flex; align-items: center; gap: 12px;
  padding: 13px 16px;
  width: fit-content; min-width: 62%;
}
.fx-af-step b { font-size: 0.95rem; }

.fx-af-ico {
  display: grid; place-items: center; flex: none;
  width: 36px; aspect-ratio: 1; border-radius: 10px;
}
.fx-af-ico svg { width: 20px; height: 20px; }
.fx-af-ico-green { background: #e5f8ec; color: #23a04c; }
.fx-af-ico-blue  { background: #e8f0fd; color: var(--accent-2); }
.fx-af-ico-ai    { background: linear-gradient(135deg, #2f80ee, #1d4ed8); color: #fff; }

/* dotted connector */
.fx-af-link { display: flex; justify-content: center; padding: 2px 0; }
.fx-af-link i {
  display: block; width: 2px; height: 26px;
  background-image: linear-gradient(#93b8f2 55%, transparent 55%);
  background-size: 2px 7px;
}

/* AI findings card */
.fx-af-main { padding: 16px 18px 8px; }
.fx-af-main-head { display: flex; align-items: center; gap: 12px; padding-bottom: 6px; }
.fx-af-main-head b { font-size: 1.02rem; }
.fx-af-list li {
  display: flex; align-items: center; gap: 10px;
  padding: 9px 8px; margin: 0 -8px;
  border-radius: 9px;
  font-size: 0.9rem; color: #3c3c43;
  border-top: 1px solid rgba(29, 29, 31, 0.05);
}
.fx-af-list li:hover { background: #f2f7ff; border-top-color: transparent; }
.fx-af-list li:hover + li { border-top-color: transparent; }
.fx-af-list li:hover svg { transform: scale(1.18); }
.fx-af-list svg { transition: transform .3s var(--ease); }
.fx-af-list li:first-child { border-top: 0; }
.fx-af-list svg { width: 17px; height: 17px; flex: none; }
.fx-af-list .fx-ok svg   { color: #23a04c; }
.fx-af-list .fx-warn svg { color: var(--amber); }

/* staggered entrance for findings (driven by the aside's .fx-reveal → .fx-in) */
.fx-aiau-flow .fx-af-list li { opacity: 0; transform: translateY(10px); transition: opacity .5s var(--ease), transform .5s var(--ease); }
.fx-aiau-flow.fx-in .fx-af-list li { opacity: 1; transform: none; }
.fx-aiau-flow.fx-in .fx-af-list li:nth-child(1) { transition-delay: .25s; }
.fx-aiau-flow.fx-in .fx-af-list li:nth-child(2) { transition-delay: .4s; }
.fx-aiau-flow.fx-in .fx-af-list li:nth-child(3) { transition-delay: .55s; }
.fx-aiau-flow.fx-in .fx-af-list li:nth-child(4) { transition-delay: .7s; }
.fx-aiau-flow.fx-in .fx-af-list li:nth-child(5) { transition-delay: .85s; }

/* recommended action */
.fx-af-action {
  display: flex; align-items: center; gap: 12px;
  padding: 13px 16px;
  background: linear-gradient(100deg, #eef4ff, #f7faff);
  transition: transform .35s var(--ease), box-shadow .35s var(--ease);
}
.fx-af-action:hover { transform: translateY(-2px); box-shadow: 0 14px 32px rgba(29, 78, 216, 0.12); }
.fx-af-action-txt { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.fx-af-action-txt small { font-size: 0.72rem; color: var(--ink-2); }
.fx-af-action-txt b { font-size: 0.95rem; color: var(--ink); }
.fx-af-chev { width: 8px; color: var(--accent-2); flex: none; }

/* approve bar → result line after a choice (aiaudit.js) */
.fx-af-approve { margin-top: clamp(14px, 1.8vw, 20px); }
.fx-af-ask {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  flex-wrap: wrap;
}
.fx-af-ask > span:first-child { font-size: 0.85rem; color: var(--ink-2); }
.fx-af-ask[hidden] { display: none; }
.fx-af-result {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  border-radius: 12px; padding: 11px 14px;
  font-size: 0.88rem; font-weight: 600;
  animation: af-result-in .45s var(--ease);
}
.fx-af-result[hidden] { display: none; }
@keyframes af-result-in { from { opacity: 0; transform: translateY(8px); } }
.fx-af-approve.fx-is-ok .fx-af-result { background: #e5f8ec; color: #1d7a3c; }
.fx-af-approve.fx-is-no .fx-af-result { background: #eceef2; color: #55555c; }
.fx-af-approve.fx-is-ok .fx-af-result-txt::before { content: "✓  "; }
.fx-af-undo {
  border: 0; background: none; padding: 0; cursor: pointer;
  font-family: var(--font); font-size: 0.84rem; font-weight: 600;
  color: var(--accent-2); text-decoration: underline; flex: none;
}
.fx-af-btns { display: flex; gap: 10px; }
.fx-af-btns button {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 9px 18px; border-radius: 10px;
  font-family: var(--font); font-size: 0.88rem; font-weight: 600;
  cursor: pointer;
  transition: transform .3s var(--ease), box-shadow .3s var(--ease), background .3s;
}
.fx-af-btns svg { width: 11px; height: 11px; }
.fx-af-reject { background: #fff; color: var(--ink); border: 1px solid rgba(29, 29, 31, 0.14); }
.fx-af-reject:hover { background: #f5f5f7; }
.fx-af-ok { background: var(--accent-2); color: #fff; border: 0; box-shadow: 0 8px 20px rgba(37, 99, 235, 0.3); }
.fx-af-ok:hover { background: #1d4ed8; transform: translateY(-1px); }

/* portal + page buttons under the workflow card */
.fx-aiau-actions {
  display: flex; justify-content: center; flex-wrap: wrap;
  gap: 14px;
  margin-top: clamp(20px, 2.5vw, 30px);
}
.fx-aiau-btn { padding: 12px 26px; font-size: 0.95rem; }

/* ───────── responsive ───────── */
@media (max-width: 900px) {
  .fx-aiau-wrap { grid-template-columns: 1fr; gap: 42px; }
  .fx-aiau-photo { margin-inline: auto; }
  .fx-aiau-right { max-width: 480px; margin: 0 auto; width: 100%; }
}

@media (prefers-reduced-motion: reduce) {
  .fx-aiau-photo img { transition: none; }
  .fx-aiau-flow .fx-af-list li { opacity: 1; transform: none; transition: none; }
}

/* ===== oneflow.css ===== */
/* ═══════════ ONEFLOW AI · glass-grid showcase ═══════════
   Full-viewport stage (same footprint as the hero): a warehouse photo,
   graded into the site's blue, under a grid of solid tiles. On entry
   (oneflow.js toggles .fx-in) each tile turns to frosted glass in a diagonal
   wave with a little random scatter — the reveal is a keyframe animation
   with a per-cell delay (--d), so the cells' normal transitions stay free
   for hover. A handful of cells stay a brighter glass, like a storyboard
   frame. The grid lights up under the cursor: the hovered pane brightens
   and lifts, and a soft spotlight (--mx/--my from the script) follows the
   pointer. Everything replays when the section leaves and re-enters.
   Grid geometry (--cols / --rows) is set by the script so cells stay square. */
.fx-oneflow {
  position: relative;
  background: var(--bg-alt);
  overflow: hidden;
  margin-bottom: -1px;             /* overlap the next section by a hair — no seam */
  line-height: 1.5;                /* restored here, see the root rules below */
  font-size: 1rem;
}
/* Dev servers (Live Server, browser-sync…) inject markup into every HTML
   file they serve — including fetched components. In a root container that
   shows up as a stray inline/text node and paints a body-white line box
   (~24px) between this section and the next. Collapse anything that isn't
   the section itself. */
#oneflow-root { font-size: 0; line-height: 0; }
/* breathing room between the phone-tour section above and the stage —
   white, so it reads as a clean gap the stage's top fade melts into */
#oneflow-root { padding-top: clamp(64px, 10vh, 140px); background: var(--bg); }
#oneflow-root > :not(.fx-oneflow) { display: none !important; }

/* ── the stage · full-bleed, full-height picture ── */
.fx-of-stage {
  --cols: 12;
  --rows: 8;
  --mx: 50%;
  --my: 50%;
  position: relative;
  min-height: min(740px, 100vh);
  min-height: min(740px, 100svh);
  display: grid;
  align-items: start;
  overflow: hidden;
  background: #eaf4ff; /* shows for a beat before the gradient paints */
}
/* blend: the grey of the sections above and below dissolves into the
   picture instead of meeting it at a hard edge (same trick as the hero).
   Real elements, not pseudo-elements, so nothing odd can happen at the
   grid container's edges. */
.fx-of-fade {
  position: absolute; left: 0; right: 0; z-index: 3;
  pointer-events: none;
}
.fx-of-fade-top {
  /* white, not grey — the phone-tour section above ends on --bg */
  top: 0; height: clamp(140px, 22vh, 220px);
  background: linear-gradient(180deg,
    #ffffff 0%, rgba(255,255,255,.86) 18%, rgba(255,255,255,.55) 42%,
    rgba(255,255,255,.22) 68%, rgba(255,255,255,.06) 88%, rgba(255,255,255,0) 100%);
}
.fx-of-fade-bottom {
  /* tighter than the top fade — the rich blue base should hold almost to
     the edge, then dissolve quickly into the grey of the next section */
  bottom: 0; height: clamp(100px, 15vh, 160px);
  background: linear-gradient(0deg,
    #ffffff 0%, #ffffff 3%, rgba(255,255,255,.88) 18%, rgba(255,255,255,.55) 42%,
    rgba(255,255,255,.24) 66%, rgba(255,255,255,.08) 86%, rgba(255,255,255,0) 100%);
}

/* the backdrop: a slow-drifting blue gradient + the blue grade so the
   white copy stays crisp */
.fx-of-picture {
  position: absolute; inset: 0; z-index: 0;
  overflow: hidden;
  /* the ramp lives in the lower half: white holds through the brand area,
     then blue builds smoothly and lands on a deep, rich base at the bottom.
     NB the backdrop is 130% tall, so only ~0–77% of these stops are on
     screen — the deep base sits at ~70%, not 100%, to actually be visible. */
  background: linear-gradient(180deg,
    #ffffff 0%, #fbfdff 16%, #eef6ff 28%, #cfe4fc 40%, #9dcaf9 51%,
    #5ba5f3 60%, #2b89ec 68%, #1a73e2 76%, #135fd2 88%, #0e55c4 100%);
  background-size: 130% 130%;
  animation: of-drift 22s ease-in-out infinite;
}
/* gentle breathe — small range so the white top and blue base never leave place */
@keyframes of-drift {
  0%, 100% { background-position: 50% 0%; }
  50%      { background-position: 50% 30%; }
}
.fx-of-picture::after {
  content: ""; position: absolute; inset: 0;
  /* faint top-left light source, plus a soft glow low in the blue so the
     bottom half reads as the lit part of the stage */
  background:
    radial-gradient(70% 80% at 18% 8%, rgba(255, 255, 255, .55) 0%, rgba(255, 255, 255, 0) 60%),
    radial-gradient(90% 55% at 50% 100%, rgba(140, 200, 255, .28) 0%, rgba(140, 200, 255, 0) 70%);
}

/* ── giant display word · sits on the picture, under the glass grid, and
      runs off the bottom edge like a poster title ── */
.fx-of-word {
  display: none;                   /* retired with the light redesign — delete to bring back */
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 1;
  text-align: center;
  font-size: 14.2vw;                                  /* 9 letters ≈ 88vw at any width */
  font-weight: 800; line-height: .8;
  letter-spacing: -.03em; text-transform: uppercase;
  white-space: nowrap;
  color: transparent;
  background: linear-gradient(180deg, rgba(255,255,255,.42) 0%, rgba(255,255,255,.3) 50%, rgba(255,255,255,.16) 80%, rgba(255,255,255,.06) 100%);
  -webkit-background-clip: text; background-clip: text;
  pointer-events: none; user-select: none;
  padding-bottom: .04em;
  transform: translateY(.12em);
  opacity: 0;
  transition: opacity 1.4s var(--ease) 1.1s, transform 1.6s var(--ease) 1.1s;
}
.fx-of-stage.fx-in .fx-of-word { opacity: 1; transform: none; }

/* ── the glass grid · retired — the picture now shows clean. The markup
      and script stay (the stage's IntersectionObserver still drives the
      copy/word reveal); delete this display:none to bring the grid back. ── */
.fx-of-grid {
  position: absolute; inset: 0 -1px -1px 0; z-index: 2;
  display: grid;
  grid-template-columns: repeat(var(--cols), 1fr);
  grid-template-rows: repeat(var(--rows), 1fr);
  display: none;
}
/* spotlight that trails the cursor across the panes */
.fx-of-grid::after {
  content: ""; position: absolute; inset: 0; z-index: 2;
  pointer-events: none;
  background: radial-gradient(300px circle at var(--mx) var(--my),
    rgba(255,255,255,.16) 0%, rgba(255,255,255,.06) 40%, transparent 70%);
  opacity: 0;
  transition: opacity .6s ease;
}
.fx-of-stage.fx-in.fx-lit .fx-of-grid::after { opacity: 1; }

.fx-of-cell {
  /* cover colours — slight variation so the cover reads as a mosaic */
  --solid: #e6f0ff;
  --glass: rgba(255, 255, 255, .03);
  --line: rgba(255, 255, 255, .2);
  --edge: none;
  position: relative;
  background: var(--solid);
  /* one hairline per pane (right + bottom) -> single crisp lines, never doubled */
  border-right: 1px solid rgba(255, 255, 255, .7);
  border-bottom: 1px solid rgba(255, 255, 255, .7);
  box-shadow: none;
  /* hover eases in fast and fades out slowly, leaving a trail */
  transition:
    background .9s ease,
    border-color .9s ease,
    box-shadow .9s ease,
    transform .9s var(--ease),
    -webkit-backdrop-filter .9s ease,
    backdrop-filter .9s ease;
}
.fx-of-cell:nth-child(3n) { --solid: #dbe8ff; }
.fx-of-cell:nth-child(5n) { --solid: #eaf2ff; }
.fx-of-cell:nth-child(7n) { --solid: #d3e3ff; }

/* revealed: every pane is clear glass, a few stay frosted brighter */
.fx-of-stage.fx-in .fx-of-cell {
  background: var(--glass);
  border-color: var(--line);
  box-shadow: var(--edge);
  animation: of-peel .9s cubic-bezier(.4, 0, .2, 1) var(--d, 0s) backwards;
}
.fx-of-stage.fx-in .fx-of-cell.fx-keep {
  --glass: rgba(214, 232, 255, .3);
  --edge: inset 0 0 0 1px rgba(255, 255, 255, .55), inset 0 0 30px rgba(255, 255, 255, .08);
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
  /* after the peel, drift up and down slowly like floating glass;
     the negative delay reuses each pane's stagger (--d) so they bob out of phase */
  animation:
    of-peel .9s cubic-bezier(.4, 0, .2, 1) var(--d, 0s) backwards,
    of-float 7s ease-in-out calc(var(--d, 0s) * -8) infinite;
}
.fx-of-stage.fx-in .fx-of-cell.fx-keep.fx-soft  { --glass: rgba(214, 232, 255, .16); animation-duration: .9s, 9s; }
.fx-of-stage.fx-in .fx-of-cell.fx-keep.fx-frame {
  --glass: rgba(214, 232, 255, .06);
  --edge: inset 0 0 0 2px rgba(255, 255, 255, .85);
  animation-duration: .9s, 8s;
}
@keyframes of-peel {
  0%   { background: var(--solid); border-color: rgba(255,255,255,.7); transform: scale(1); }
  55%  { background: rgba(255,255,255,.22); transform: scale(.9); }
  100% { background: var(--glass); border-color: var(--line); transform: scale(1); }
}
@keyframes of-float {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-9px); }
}
/* when the cover comes back (scrolling away) it lands quickly, not staggered */
.fx-of-stage:not(.fx-in) .fx-of-cell { transition-duration: .35s; }

/* hover · the pane under the cursor brightens, frosts and lifts */
@media (hover: hover) {
  .fx-of-stage.fx-in .fx-of-cell:hover {
    background: rgba(255, 255, 255, .2);
    border-color: rgba(255, 255, 255, .85);
    box-shadow:
      inset 0 0 0 1px rgba(255, 255, 255, .85),
      inset 0 0 40px rgba(255, 255, 255, .12),
      0 18px 46px -18px rgba(0, 10, 40, .5);
    -webkit-backdrop-filter: blur(8px) saturate(1.3); backdrop-filter: blur(8px) saturate(1.3);
    transform: scale(1.04);
    z-index: 3;
    transition-duration: .25s;
  }
}

/* ── copy · info left, giant brand mark right ── */
.fx-of-content {
  position: relative; z-index: 4;
  width: min(1180px, 92vw);
  margin: 0 auto;
  padding: clamp(36px, 5vh, 64px) 0 clamp(72px, 10vh, 120px);
  display: flex; flex-direction: column;
  align-items: center;
  gap: clamp(56px, 11vh, 130px);   /* brand sits in the white, info in the blue */
  text-align: center;
}
.fx-of-brand {
  display: flex; flex-direction: column; align-items: center;
  gap: clamp(22px, 2.6vw, 36px);
  justify-self: center;
}
.fx-of-brand-logo {
  width: clamp(110px, 12vw, 168px); height: auto;
  filter: drop-shadow(0 16px 34px rgba(30, 111, 242, .28));
}
.fx-of-brand-wordmark {
  width: clamp(220px, 22vw, 310px); height: auto;
}

/* ── the glass slab · frosted card that carries the info ── */
.fx-of-slab {
  position: relative; overflow: hidden;
  border-radius: 28px;
  padding: clamp(32px, 4vw, 56px);
  background: rgba(255, 255, 255, .38);
  border: 1px solid rgba(255, 255, 255, .7);
  box-shadow:
    0 30px 70px -30px rgba(20, 60, 140, .35),
    inset 0 1px 0 rgba(255, 255, 255, .85);
  -webkit-backdrop-filter: blur(18px) saturate(1.35);
  backdrop-filter: blur(18px) saturate(1.35);
}
/* giant ghosted mark inside the slab, clipped by its corners */
.fx-of-slab-mark {
  position: absolute; right: -14%; bottom: -20%;
  width: 64%; height: auto;
  opacity: .14;
  pointer-events: none; user-select: none;
}
.fx-of-slab > :not(.fx-of-slab-mark) { position: relative; z-index: 1; }
.fx-of-kicker {
  display: inline-flex; align-items: center; gap: 10px;
  padding: 7px 16px; border-radius: 999px;
  background: rgba(255,255,255,.16); color: #fff;
  border: 1px solid rgba(255,255,255,.28);
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
  font-size: .78rem; font-weight: 700; letter-spacing: .12em; text-transform: uppercase;
  margin-bottom: 24px;
}
.fx-of-kicker::before {
  content: ""; width: 7px; height: 7px; border-radius: 50%;
  background: #7ee0a3; box-shadow: 0 0 0 4px rgba(126, 224, 163, .25);
}
.fx-of-title {
  color: #fff;
  font-size: clamp(1.7rem, 2.4vw, 2.4rem);   /* one-line heading on the blue */
  font-weight: 700; line-height: 1.16; letter-spacing: -.02em;
  text-shadow: 0 2px 20px rgba(10, 50, 120, .35);
}
.fx-of-title .fx-ow { display: inline-block; }
.fx-of-br { display: none; }  /* phone-only line break — shown ≤480px */
.fx-of-accent {
  /* plain white, same as the rest of the title (its text-shadow inherits) */
  color: #fff;
}
.fx-of-lead {
  margin: 16px auto 0;
  font-size: clamp(1rem, 1.3vw, 1.18rem);
  line-height: 1.6; color: rgba(255, 255, 255, .94);
  max-width: 34em;
  text-shadow: 0 1px 12px rgba(10, 50, 120, .3);
}
/* demo CTA · frosted glass pill on the blue lower half */
.fx-of-cta { margin-top: 30px; display: flex; justify-content: center; }
.fx-of-btn {
  display: inline-flex; align-items: center;
  padding: 14px 34px; border-radius: 999px;
  background: rgba(255, 255, 255, .16); color: #fff;
  border: 1px solid rgba(255, 255, 255, .45);
  font-weight: 700; font-size: 1rem; letter-spacing: .01em;
  -webkit-backdrop-filter: blur(14px) saturate(1.3);
  backdrop-filter: blur(14px) saturate(1.3);
  box-shadow:
    0 12px 30px rgba(10, 35, 90, .22),
    inset 0 1px 0 rgba(255, 255, 255, .55);
  transition:
    background .4s ease, border-color .4s ease,
    transform .4s var(--ease), box-shadow .4s ease;
}
.fx-of-btn:hover {
  background: rgba(255, 255, 255, .3);
  border-color: rgba(255, 255, 255, .8);
  transform: translateY(-2px);
  box-shadow:
    0 18px 40px rgba(10, 35, 90, .32),
    inset 0 1px 0 rgba(255, 255, 255, .7),
    inset 0 0 24px rgba(255, 255, 255, .12);
}
.fx-of-btn:active { transform: scale(.97); }

/* ── entrance choreography · plays ONCE, the first time the stage
      scrolls in (.fx-in from oneflow.js, which unobserves after adding it).
      Sequence: the flower mark dives in from in front of the screen —
      huge, blurred and spinning, as if flying past the viewer through a
      portal — lands and stops; then the ONEFLOW AI wordmark fades in;
      then title, lead and CTA follow. ── */
.fx-of-brand-logo { opacity: 0; }
.fx-of-stage.fx-in .fx-of-brand-logo {
  animation: of-portal 2.8s cubic-bezier(.3, .65, .25, 1) .1s forwards;
}
/* starts lower inside the stage (translateY) so the scaled-up mark never
   pokes past the stage's overflow:hidden top edge and gets cut by the
   section above; it glides up into its slot while the spin winds down */
@keyframes of-portal {
  0% {
    opacity: 0;
    transform: translateY(24vh) scale(2.6) rotate(-360deg);
    filter: blur(14px) drop-shadow(0 16px 34px rgba(30, 111, 242, 0));
  }
  30% { opacity: 1; }
  85% {
    transform: translateY(0) scale(.97) rotate(7deg);
    filter: blur(0) drop-shadow(0 16px 34px rgba(30, 111, 242, .28));
  }
  100% {
    opacity: 1;
    transform: translateY(0) scale(1) rotate(0deg);
    filter: blur(0) drop-shadow(0 16px 34px rgba(30, 111, 242, .28));
  }
}
.fx-of-brand-wordmark, .fx-of-title, .fx-of-lead, .fx-of-cta {
  opacity: 0; transform: translateY(26px);
}
.fx-of-stage.fx-in :is(.fx-of-brand-wordmark, .fx-of-title, .fx-of-lead, .fx-of-cta) {
  opacity: 1; transform: none;
  transition: opacity .9s var(--ease), transform .9s var(--ease);
}
/* wordmark waits for the mark to land (~2.7s), the copy follows */
.fx-of-stage.fx-in .fx-of-brand-wordmark { transition-delay: 2.55s; }
.fx-of-stage.fx-in .fx-of-title          { transition-delay: 2.95s; }
.fx-of-stage.fx-in .fx-of-lead           { transition-delay: 3.12s; }
.fx-of-stage.fx-in .fx-of-cta            { transition-delay: 3.3s; }

/* ── responsive ── */
@media (max-width: 820px) {
  .fx-of-stage { min-height: min(760px, 100vh); min-height: min(760px, 100svh); }
  .fx-of-content { padding: 64px 0 72px; }
  .fx-of-title { white-space: normal; font-size: clamp(2rem, 5.6vw, 3rem); }
  .fx-of-word { font-size: 14.2vw; }
}
@media (max-width: 480px) {
  /* smaller, and the .fx-of-br break lands it on exactly two lines:
     "AI-Powered Operations," / "From Gate to ERP" */
  .fx-of-title { font-size: clamp(1.35rem, 7vw, 1.85rem); }
  .fx-of-br { display: inline; }
  .fx-of-kicker { font-size: .7rem; padding: 6px 13px; }
}

@media (prefers-reduced-motion: reduce) {
  .fx-of-cell, .fx-of-stage.fx-in .fx-of-cell,
  .fx-of-stage.fx-in .fx-of-cell.fx-keep { animation: none; transition: none; }
  .fx-of-picture { animation: none; }
  .fx-of-word { opacity: 1; transform: none; transition: none; }
  .fx-of-grid::after { transition: none; }
  .fx-of-brand-logo, .fx-of-brand-wordmark, .fx-of-title, .fx-of-lead, .fx-of-cta {
    opacity: 1; transform: none; transition: none; animation: none;
  }
}
