/* ============================================================
   ForgeX site styles.

   Deliberately plain. The previous sheet leaned on a fog canvas,
   glass panels, blur and glow, which pulled attention to the
   background instead of the offer. Everything here is flat:
   one typeface, a warm paper background, dark navy text, hairline
   rules, and a single accent used only where we want a click.

   Contrast and whitespace do the work. Nothing decorative.
   ============================================================ */

.fxs-site {
  /* Paper, not pure white: easier on the eye and warmer than a
     screen-white page, which reads as unfinished. */
  --paper:  #FBFAF8;
  --white:  #FFFFFF;
  --sand:   #F4F1EC;
  /* The wash behind the three journal panels, and nowhere else. Declared here
     so there is one place to change it. */
  --fxs-journal-band: transparent;   /* Funded Run palette experiment: was #93CFDF */
  /* And the wash behind the community block. */
  --fxs-community-band: transparent; /* Funded Run palette experiment: was #FCE7C9 */
  --ink:    #0E1B2A;
  --body:   #46586B;
  --muted:  #7B8A99;
  --line:   #E7E3DC;
  --line-2: #D8D3CA;

  --accent:     #0B4FD4;
  --accent-ink: #0840AC;
  --navy:       #0E1B2A;
  --up:         #12855A;
  --down:       #C0453B;

  --wrap: 1120px;
  --r: 10px;

  font-family: Manrope, ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  background: var(--paper);
  color: var(--body);
  font-size: 17px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

.fxs-site *, .fxs-site *::before, .fxs-site *::after { box-sizing: border-box; }
.fxs-site img { max-width: 100%; display: block; }

.fxs-site h1, .fxs-site h2, .fxs-site h3, .fxs-site h4 {
  color: var(--ink);
  font-weight: 800;
  line-height: 1.12;
  letter-spacing: -0.02em;
  margin: 0;
}
.fxs-site p { margin: 0; }
.fxs-site a { color: inherit; text-decoration: none; }

/* ── layout ─────────────────────────────────────────────── */
.fxs-site .fxs-wrap { width: 100%; max-width: var(--wrap); margin: 0 auto; padding: 0 24px; }

/* Sections breathe. Crowding is what made the old page feel busy. */
.fxs-site .fxs-sec { padding: 96px 0; }
.fxs-site .fxs-sec--tight { padding: 64px 0; }
.fxs-site .fxs-sec--white { background: var(--white); border-block: 1px solid var(--line); }
.fxs-site .fxs-sec--sand { background: var(--sand); border-block: 1px solid var(--line); }
.fxs-site .fxs-sec--navy { background: var(--navy); border-block: 1px solid var(--navy); }
.fxs-site .fxs-sec--navy h2, .fxs-site .fxs-sec--navy h3 { color: #fff; }
.fxs-site .fxs-sec--navy p { color: #A9BACB; }

.fxs-site .fxs-head { max-width: 700px; margin: 0 auto 52px; text-align: center; }
.fxs-site .fxs-head--mid { margin-inline: auto; text-align: center; }
.fxs-site .fxs-eyebrow {
  font-size: 12px; font-weight: 800; letter-spacing: 0.12em;
  text-transform: uppercase; color: var(--muted); margin-bottom: 14px;
}
.fxs-site .fxs-h2 { font-size: clamp(30px, 4vw, 42px); }
.fxs-site .fxs-lede { margin-top: 16px; font-size: 18px; color: var(--body); }

/* ── buttons ────────────────────────────────────────────── */
/* Every rule here is prefixed with .fxs-site on purpose. The app ships global
   `a` and `button` styles, and a bare `.fxs-btn--primary` loses to `.fxs-site a`
   on specificity, which silently reverted button text to the inherited colour. */
.fxs-site .fxs-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  padding: 14px 24px; border-radius: var(--r);
  font-size: 16px; font-weight: 700; cursor: pointer; font-family: inherit;
  border: 1px solid transparent; transition: background .15s, border-color .15s, color .15s;
  white-space: nowrap; text-decoration: none;
}
.fxs-site .fxs-btn--primary { background: var(--accent); color: #fff; }
.fxs-site .fxs-btn--primary:hover { background: var(--accent-ink); color: #fff; }

/* Glowing-beam button (.fx-beambtn) — a bright beam sweeps around the border and
   a soft glow pulses just outside it. Ported here from the app's glow-beam.css so
   the static pages get the same black Start-free CTA as the landing, which loads
   the same rules through the React bundle. Pure CSS, no script. */
@property --fx-angle { syntax: "<angle>"; initial-value: 0deg; inherits: false; }
@keyframes fx-beam-spin { to { --fx-angle: 360deg; } }
@keyframes fx-beam-pulse { 0%, 100% { opacity: 0.34; } 50% { opacity: 0.62; } }
.fxs-site .fx-beambtn { position: relative; isolation: isolate; --beam: #4f9dff; }
.fxs-site .fx-beambtn::before {
  content: ""; position: absolute; inset: 0; border-radius: inherit;
  padding: 2px; z-index: -1; pointer-events: none;
  background: conic-gradient(from var(--fx-angle),
    transparent 0deg 198deg,
    color-mix(in srgb, var(--beam) 35%, transparent) 248deg,
    var(--beam) 296deg, #ffffff 312deg, var(--beam) 328deg, transparent 360deg);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
          mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor; mask-composite: exclude;
  animation: fx-beam-spin 3.2s linear infinite;
}
.fxs-site .fx-beambtn::after {
  content: ""; position: absolute; inset: 0; border-radius: inherit;
  z-index: -2; pointer-events: none;
  box-shadow: 0 0 18px 1px color-mix(in srgb, var(--beam) 55%, transparent);
  animation: fx-beam-pulse 3.2s ease-in-out infinite;
}
.fxs-site .fx-beambtn--black { background: #0a0a0c !important; color: #ffffff !important; border-color: transparent !important; }
.fxs-site .fx-beambtn--black:hover { background: #16161c !important; color: #ffffff !important; }
@media (prefers-reduced-motion: reduce) {
  .fxs-site .fx-beambtn::before { animation: none; }
  .fxs-site .fx-beambtn::after { animation: none; opacity: 0.45; }
}
.fxs-site .fxs-btn--ghost { background: transparent; color: var(--ink); border-color: var(--line-2); }
.fxs-site .fxs-btn--ghost:hover { border-color: var(--ink); color: var(--ink); }
.fxs-site .fxs-btn--onnavy { background: #fff; color: var(--navy); }
.fxs-site .fxs-btn--onnavy:hover { background: #E9EEF4; color: var(--navy); }
.fxs-site .fxs-btn--sm { padding: 9px 16px; font-size: 14px; }

/* ── "Start free" nav CTA: a shiny border that travels around the button and,
   on hover, stops and floods the whole face (owner's spec).
   - The travelling comet is a conic gradient whose start angle is animated with
     @property --fx-angle (a plain custom property can't tween an <angle>); it is
     masked to just the border ring.
   - ::after is the flood that fades in on hover; on hover the comet also pauses
     and becomes a full bright ring, so the border reads as covering the button.
   - Both pseudos sit at negative z-index: above the button's own fill but under
     the label, which holds whether the label is bare text or the slide-wrapped
     spans landingMotion adds. The label flips to accent so it stays readable on
     the near-white flood. */
@property --fx-angle { syntax: "<angle>"; initial-value: 0deg; inherits: false; }
@keyframes fx-glow-spin { to { --fx-angle: 360deg; } }
.fxs-site .fx-glowbtn { position: relative; isolation: isolate; overflow: hidden; }
.fxs-site .fx-glowbtn::before,
.fxs-site .fx-glowbtn::after {
  content: ""; position: absolute; inset: 0; border-radius: inherit;
  z-index: -1; pointer-events: none;
}
.fxs-site .fx-glowbtn::before {
  padding: 1.5px;
  background: conic-gradient(from var(--fx-angle),
    transparent 0deg 205deg, #7fd8ff 262deg, #ffffff 292deg, #7fd8ff 322deg, transparent 360deg);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
          mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor; mask-composite: exclude;
  animation: fx-glow-spin 2.6s linear infinite;
}
.fxs-site .fx-glowbtn::after {
  background: linear-gradient(120deg, #eaf6ff, #ffffff 46%, #d6ecff);
  opacity: 0; transition: opacity 220ms ease;
}
.fxs-site .fx-glowbtn:hover { color: var(--accent); background: var(--accent); }
.fxs-site .fx-glowbtn:hover::before {
  animation-play-state: paused; padding: 2px;
  background: linear-gradient(#c4e7ff, #c4e7ff);
}
.fxs-site .fx-glowbtn:hover::after { opacity: 1; }
@media (prefers-reduced-motion: reduce) {
  .fxs-site .fx-glowbtn::before { animation: none; }
}

/* ── nav ────────────────────────────────────────────────── */
.fxs-site .fxs-nav {
  position: sticky; top: 0; z-index: 50;
  /* No white bar — the nav is a floating ISLAND. The header is transparent and
     only its three pieces (logo, island pill, buttons) carry a surface, so the
     empty gaps between them let clicks fall through to the page. */
  background: transparent; border-bottom: 0;
  padding: 14px 0;
  pointer-events: none;
}
/* On phones the floating-island nav has no gaps to spare, so scrolling content
   bleeds through the transparent header behind the logo. Give it a real,
   blurred bar there instead so it reads cleanly. */
@media (max-width: 760px) {
  .fxs-site .fxs-nav {
    /* Fully opaque rather than a translucent bar with a blur: a backdrop-filter
       on a sticky header re-blurs the page under it on every scrolled frame,
       which is one of the heavier things a weak phone can be asked to do while
       scrolling. A solid bar reads just as cleanly for free. */
    background: var(--paper);
    border-bottom: 1px solid var(--line);
    pointer-events: auto;
  }
}
.fxs-site .fxs-nav__logo,
.fxs-site .fxs-nav__links,
.fxs-site .fxs-nav__right { pointer-events: auto; }
/* Wider than the 1120 content wrap so the logo sits further left and the buttons
   further right, leaving the middle for a bigger island. min() keeps it inside
   any laptop width. */
.fxs-site .fxs-nav__in { display: flex; align-items: center; gap: 32px; min-height: 60px; position: relative; max-width: min(1360px, 100%); }
.fxs-site .fxs-nav__logo { display: flex; align-items: center; gap: 9px; font-weight: 800; color: var(--ink); font-size: 18px; letter-spacing: -0.01em; }
.fxs-site .fxs-nav__logo img { height: 26px; width: auto; }
/* The island: a floating rounded pill holding the nav items. */
.fxs-site .fxs-nav__links {
  display: flex; align-items: center; gap: 24px;
  position: absolute; left: 50%; transform: translateX(-50%);
  background: rgba(255, 255, 255, 0.9);
  border: 1px solid var(--line); border-radius: 999px;
  padding: 12px 28px;
  box-shadow: 0 12px 36px -16px rgba(14, 27, 42, 0.26);
  backdrop-filter: saturate(1.4) blur(8px);
}
.fxs-site .fxs-nav__links a { font-size: 15px; font-weight: 600; color: var(--body); }
.fxs-site .fxs-nav__links a:hover { color: var(--ink); }
.fxs-site .fxs-nav__right { margin-left: auto; display: flex; align-items: center; gap: 14px; position: relative; z-index: 1; }

/* ── Reading progress bar (right edge) ───────────────────────────────────────
   A thin fixed bar whose fill grows with scroll progress, so the end of the page
   is always in sight. The fill height is set each frame by LandingPage.jsx. */
.fxs-site .fxs-scrollbar {
  position: fixed; top: 0; left: 0; bottom: 0; width: 4px;
  z-index: 60; pointer-events: none;
  background: rgba(20, 30, 45, 0.07);
}
.fxs-site .fxs-scrollbar__fill {
  position: absolute; top: 0; left: 0; width: 100%; height: 0;
  background: var(--accent);
}

/* ── Preloader ───────────────────────────────────────────────────────────────
   A black screen with the logo. The logo settles, holds, then ZOOMS in as the
   black fades, revealing the landing. Pure CSS so it runs without any script;
   it ends visibility:hidden so it never captures clicks afterwards. */
.fxs-site .fxs-preloader {
  position: fixed; inset: 0; z-index: 200; background: #000;
  display: grid; place-items: center;
  animation: fxs-preload 2.2s cubic-bezier(.7, 0, .3, 1) forwards;
}
.fxs-site .fxs-preloader__logo {
  width: min(260px, 44vw); height: auto; will-change: transform, opacity;
  /* The visible mark sits low-and-left inside its own transparent canvas — the
     opaque content's centre is at ~43% / 59%, not 50/50 — so a plain
     centre-origin zoom slid the logo off to the left. Zoom FROM that real visual
     centre, and nudge it onto the screen centre first, so it grows straight out
     of the middle. (translate is a % of the logo box, so it holds at any size.) */
  transform-origin: 43.2% 59.2%;
  transform: translate(6.8%, -9.2%);
  animation: fxs-preload-logo 2.2s cubic-bezier(.7, 0, .3, 1) forwards;
}
@keyframes fxs-preload {
  0%, 58% { opacity: 1; }
  100%    { opacity: 0; visibility: hidden; }
}
@keyframes fxs-preload-logo {
  0%   { transform: translate(6.8%, -9.2%) scale(.7); opacity: 0; }
  24%  { transform: translate(6.8%, -9.2%) scale(1);  opacity: 1; }
  58%  { transform: translate(6.8%, -9.2%) scale(1);  opacity: 1; }
  100% { transform: translate(6.8%, -9.2%) scale(9);  opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .fxs-site .fxs-preloader { animation: fxs-preload-quick .4s ease .3s forwards; }
  .fxs-site .fxs-preloader__logo { animation: none; }
}
@keyframes fxs-preload-quick { to { opacity: 0; visibility: hidden; } }

/* ── Before/after comparison slider (Funded Run) ─────────────────────────────
   Two panes stacked; the "before" pane is clipped to --split and revealed by the
   draggable grip. --split is updated by LandingPage.jsx. Drop an
   <img class="fxs-compare__img"> into each pane for the real screenshots. */
.fxs-site .fxs-compare {
  position: relative; width: min(500px, 100%); margin: 2.6rem auto 0;
  aspect-ratio: 3 / 4; border-radius: 16px; overflow: hidden;
  border: 1px solid var(--line); box-shadow: 0 24px 60px -38px rgba(14, 27, 42, 0.42);
  user-select: none; touch-action: pan-y; background: #0b1017;
}
.fxs-site .fxs-compare__pane { position: absolute; inset: 0; display: grid; place-items: center; overflow: hidden; }
.fxs-site .fxs-compare__pane--after  { background: #0b1017; }
.fxs-site .fxs-compare__pane--before { background: #0b1017; clip-path: inset(0 calc(100% - var(--split, 50%)) 0 0); }
/* Background-image, not <img>, so a missing file degrades to the pane colour
   (no broken-image icon). The "before" is dimmed with a CSS filter to match the
   brighter "after" without touching the file. */
/* cover fills the width at natural scale (no zoom) and, anchored to the top,
   trims the excess off the BOTTOM. The frame's aspect-ratio decides how far down
   it reaches — tune it if the cut isn't exactly below 139.512. */
.fxs-site .fxs-compare__img { position: absolute; inset: 0; background-size: cover; background-repeat: no-repeat; background-position: top center; }
.fxs-site .fxs-compare__img--before { background-image: url("/media/FundedRunBeforeImage.jpeg"); filter: brightness(.88); }
.fxs-site .fxs-compare__img--after  { background-image: url("/media/FundedRunAfterImage.jpeg"); }
.fxs-site .fxs-compare__tag {
  position: absolute; top: 14px; z-index: 2;
  font-size: 12px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase;
  padding: 6px 12px; border-radius: 999px; color: #fff; background: rgba(0, 0, 0, .45);
}
.fxs-site .fxs-compare__tag--before { left: 14px; }
.fxs-site .fxs-compare__tag--after  { right: 14px; }
.fxs-site .fxs-compare__bar {
  position: absolute; top: 0; bottom: 0; left: var(--split, 50%); width: 2px;
  background: #fff; transform: translateX(-50%); z-index: 3; pointer-events: none;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, .15);
}
.fxs-site .fxs-compare__grip {
  position: absolute; top: 50%; left: var(--split, 50%); transform: translate(-50%, -50%);
  z-index: 4; width: 44px; height: 44px; border-radius: 50%;
  background: #fff; color: #0d1b2a; border: 0; cursor: ew-resize;
  display: grid; place-items: center; box-shadow: 0 6px 18px -4px rgba(0, 0, 0, .45);
  touch-action: none;
}
.fxs-site .fxs-compare__grip:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

/* Funded Run showcase video — replaces the old before/after slider. Sized to
   match the Trader Journey video (~960px on desktop, same 16px rounded corners)
   and centred in the 1000px .fr-promo column with margin-inline:auto, so it is
   centred for every viewer on every width (not tied to any scrollbar or layout
   quirk). The frame carries the recording's own ratio (1280 x 734) so
   object-fit: cover fills it with no letterbox and no visible crop; height is
   derived from the width by aspect-ratio, so there is nothing to tune per
   breakpoint and it collapses to the full column width on tablets and phones. */
.fxs-site .fr-promo__video {
  position: relative; width: min(960px, 100%); margin: 2.4rem auto 0;
  aspect-ratio: 1280 / 734; border-radius: 16px; overflow: hidden;
  border: 1px solid var(--line); box-shadow: 0 24px 60px -38px rgba(14, 27, 42, 0.42);
  background: #0b1017;
}
.fxs-site .fr-promo__video > video {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; display: block; background: #0b1017;
}

/* Features menu. Plain white card, one hairline, no glass. */
.fxs-site .fxs-navdrop { position: relative; display: flex; align-items: center; }
.fxs-site .fxs-navdrop__btn { display: inline-flex; align-items: center; gap: 6px; font-size: 15px; font-weight: 600; color: var(--body); background: none; border: 0; box-shadow: none; cursor: pointer; font-family: inherit; padding: 0; }
.fxs-site .fxs-navdrop__btn:hover { color: var(--ink); }
.fxs-site .fxs-navdrop__panel {
  position: absolute; top: calc(100% + 16px); left: -20px; min-width: 264px;
  background: var(--white); border: 1px solid var(--line); border-radius: 12px;
  padding: 8px;
  /* Always rendered so it can animate — hidden until data-open, then it drops in
     smoothly (opacity + a small rise/scale) instead of appearing instantly. */
  opacity: 0; visibility: hidden; pointer-events: none;
  transform: translateY(-8px) scale(.98); transform-origin: top left;
  transition: opacity .2s ease, transform .28s cubic-bezier(.22, 1, .36, 1), visibility .28s;
}
/* Bridges the 16px between the button and the panel. That strip belonged to
   neither element, so moving the pointer down toward the menu left both and the
   menu shut before you could reach it. The bridge is part of the panel, and the
   panel is inside the menu, so crossing it never counts as leaving. */
.fxs-site .fxs-navdrop__panel::before {
  content: "";
  position: absolute;
  /* A little taller than the 16px gap so it meets the button rather than
     leaving a hairline of dead space between them. */
  left: 0; right: 0; top: -22px; height: 22px;
}
.fxs-site .fxs-navdrop[data-open="true"] .fxs-navdrop__panel {
  opacity: 1; visibility: visible; pointer-events: auto;
  transform: translateY(0) scale(1);
}
.fxs-site .fxs-navdrop__panel a { display: block; padding: 10px 12px; border-radius: 8px; font-size: 15px; font-weight: 600; color: var(--ink); }
.fxs-site .fxs-navdrop__panel a:hover { background: var(--sand); }
.fxs-site .fxs-navdrop__panel span { display: block; font-size: 13px; font-weight: 500; color: var(--muted); margin-top: 2px; }

/* ── Liquid nav: icon-only until hover ────────────────────────────────────────
   Each top-level item shows only its line icon; its text label (and a dropdown's
   chevron) reveal on hover, on keyboard focus, or while the menu is open, by
   growing from 0 width. The label stays in the DOM the whole time, so screen
   readers and keyboard users always have the name. */
.fxs-site .fxs-nav__links > a,
.fxs-site .fxs-navdrop__btn { gap: 0; overflow: hidden; }
.fxs-site .fxs-nav__links > a { display: inline-flex; align-items: center; }
.fxs-site .fxs-nav__ico { flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center; width: 20px; height: 20px; }
.fxs-site .fxs-nav__ico svg { width: 100%; height: 100%; display: block; }
.fxs-site .fxs-nav__label {
  display: inline-block; max-width: 0; opacity: 0; margin-left: 0;
  overflow: hidden; white-space: nowrap;
  transition: max-width .42s cubic-bezier(.22, 1, .36, 1), opacity .3s ease, margin-left .42s cubic-bezier(.22, 1, .36, 1);
}
.fxs-site .fxs-navdrop__btn > svg { /* the dropdown chevron */
  max-width: 0; opacity: 0; margin-left: 0; overflow: hidden;
  transition: max-width .42s cubic-bezier(.22, 1, .36, 1), opacity .3s ease, margin-left .42s cubic-bezier(.22, 1, .36, 1);
}
.fxs-site .fxs-nav__links > a:hover .fxs-nav__label,
.fxs-site .fxs-nav__links > a:focus-visible .fxs-nav__label,
.fxs-site .fxs-navdrop:hover .fxs-nav__label,
.fxs-site .fxs-navdrop:focus-within .fxs-nav__label,
.fxs-site .fxs-navdrop[data-open="true"] .fxs-nav__label {
  max-width: 12em; opacity: 1; margin-left: 8px;
}
.fxs-site .fxs-navdrop:hover .fxs-navdrop__btn > svg,
.fxs-site .fxs-navdrop:focus-within .fxs-navdrop__btn > svg,
.fxs-site .fxs-navdrop[data-open="true"] .fxs-navdrop__btn > svg {
  max-width: 1em; opacity: .65; margin-left: 6px;
}
@media (prefers-reduced-motion: reduce) {
  .fxs-site .fxs-nav__label, .fxs-site .fxs-navdrop__btn > svg, .fxs-site .fxs-navdrop__panel { transition: none; }
}

/* ── hero ───────────────────────────────────────────────── */
.fxs-site .fxs-hero { padding: 88px 0 72px; text-align: center; }

/* The live count above the headline. A box rather than a line of text, so it
   reads as a status rather than as the first sentence of the page.

   The gap belongs between the dot and the sentence and nowhere else. The
   sentence is one span for that reason: as bare text nodes, "Join", the number
   and "other traders..." were three separate flex items, so the 9px gap landed
   between each of them on top of the spaces already there, and the number sat in
   the line with a hole either side of it. */
.fxs-site .fxs-live {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  /* Reserved but invisible until the live figure arrives, so revealing it does
     not push the hero down (that shift was most of the page's layout-shift score).
     JS adds .is-shown once there is a true number to display. */
  visibility: hidden;
  margin: 0 auto 26px;
  padding: 7px 15px 7px 12px;
  border-radius: 4px;
  background: var(--white);
  border: 1px solid var(--line);
  box-shadow: 0 8px 22px -16px rgba(14, 27, 42, 0.35);
  font-size: 14px;
  font-weight: 600;
  color: var(--body);
  white-space: nowrap;
}
.fxs-site .fxs-live.is-shown { visibility: visible; }
.fxs-site .fxs-live b { font-weight: 800; color: var(--ink); font-variant-numeric: tabular-nums; }

/* The dot breathes rather than blinks. A hard on/off reads as a warning light;
   this is meant to sit there being green. The ring is a separate shadow so the
   dot itself never changes size and cannot nudge the text beside it. */
.fxs-site .fxs-live__dot {
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--up);
  flex: 0 0 8px;
  animation: fxs-live-pulse 2.4s ease-out infinite;
}
@keyframes fxs-live-pulse {
  0%   { box-shadow: 0 0 0 0 color-mix(in srgb, var(--up) 55%, transparent); }
  70%  { box-shadow: 0 0 0 7px color-mix(in srgb, var(--up) 0%, transparent); }
  100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--up) 0%, transparent); }
}
@media (prefers-reduced-motion: reduce) {
  .fxs-site .fxs-live__dot { animation: none; }
}

/* The line is long and the pill does not wrap by default, so on a narrow phone
   it ran past the right edge: 354px of pill in a 375px window. Smaller type and
   tighter padding get it inside, and wrapping is allowed as the backstop so a
   still narrower screen gives it two lines instead of cutting it off. */
@media (max-width: 560px) {
  .fxs-site .fxs-live {
    font-size: 12.5px;
    padding: 6px 13px 6px 10px;
    gap: 7px;
    max-width: 100%;
    white-space: normal;
    text-align: left;
  }
}
/* The rotating line IS the headline now. The word sits on its own line so a
   longer one cannot reflow the line above it mid animation, and it keeps the
   accent colour so the eye lands on the part that moves. */
.fxs-site .fxs-hero__h1 {
  font-size: clamp(40px, 7vw, 76px);
  display: flex; flex-direction: column; align-items: center; gap: 0.04em;
  margin: 0 auto; max-width: 16ch;
}
.fxs-site .fxs-hero__h1 em {
  font-style: normal; color: var(--accent);
  display: inline-block; min-height: 1.12em;
  /* Room for the descender on words like "guesswork", and for the small
     travel of the swap animation, so neither can touch the paragraph. */
  padding-bottom: 0.1em;
}
.fxs-site .fxs-hero__sub { margin: 34px auto 0; max-width: 60ch; font-size: 19px; color: var(--body); }
.fxs-site .fxs-hero__cta { margin-top: 34px; display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; }

/* Trustpilot "Write a review" collector, centred under the hero CTAs. The widget
   itself fills the container width (data-style-width="100%"), so the container is
   what constrains it to a tidy size. */
.fxs-site .fxs-hero__review { margin: 20px auto 0; max-width: 320px; display: flex; flex-direction: column; align-items: center; gap: 6px; }
.fxs-site .fxs-hero__review-label { font-size: 14px; font-weight: 700; color: var(--muted); }
.fxs-site .fxs-hero__review .trustpilot-widget { width: 100%; }
/* Tradervue-style Social Proof: Overlapping avatars, Trustpilot stars, community proof */
.fxs-site .fxs-social-proof {
  margin: 36px auto 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  text-align: center;
  max-width: 580px;
}
.fxs-site .fxs-social-proof__avatars {
  display: flex;
  align-items: center;
  justify-content: center;
}
.fxs-site .fxs-social-proof__avatar {
  width: 44px;
  height: 44px;
  border-radius: 50%;
  object-fit: cover;
  border: 2.5px solid var(--paper, #f7f9fc);
  margin-left: -12px;
  box-shadow: 0 4px 10px rgba(0, 0, 0, 0.12);
  position: relative;
  transition: transform 0.2s ease, z-index 0.2s ease;
}
.fxs-site .fxs-social-proof__avatar:first-child {
  margin-left: 0;
}
.fxs-site .fxs-social-proof__avatar:hover {
  transform: translateY(-3px) scale(1.08);
  z-index: 10;
}
.fxs-site .fxs-social-proof__rating {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  background: rgba(0, 182, 122, 0.08);
  border: 1px solid rgba(0, 182, 122, 0.28);
  border-radius: 9999px;
  padding: 5px 14px 5px 10px;
  text-decoration: none;
  cursor: pointer;
  transition: transform 0.18s ease, background 0.18s ease, border-color 0.18s ease;
}
.fxs-site .fxs-social-proof__rating:hover {
  background: rgba(0, 182, 122, 0.15);
  border-color: rgba(0, 182, 122, 0.45);
  transform: translateY(-1px);
}
.fxs-site .fxs-social-proof__stars {
  display: flex;
  align-items: center;
  gap: 2px;
}
.fxs-site .fxs-social-proof__stars svg {
  width: 17px;
  height: 17px;
}
.fxs-site .fxs-social-proof__score {
  font-size: 13.5px;
  font-weight: 700;
  color: var(--ink, #0e1b2a);
  letter-spacing: -0.01em;
}

/* Trustpilot "Review us on Trustpilot" collector button under the hero CTAs */
.fxs-site .fxs-hero__review {
  margin: 6px auto 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
}
.fxs-site .fxs-hero__review-label {
  font-size: 13.5px;
  font-weight: 600;
  color: var(--muted);
}
.fxs-site .fxs-hero__review .trustpilot-widget {
  display: flex;
  justify-content: center;
  width: 100%;
  min-height: 48px;
}
.fxs-site .fxs-tp-btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 9px 22px;
  border-radius: 9999px;
  background: #ffffff;
  border: 1px solid rgba(0, 182, 122, 0.35);
  color: #0e1b2a;
  font-size: 14px;
  font-weight: 700;
  text-decoration: none;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
  transition: transform 0.18s ease, border-color 0.18s ease, box-shadow 0.18s ease;
}
.fxs-site .fxs-tp-btn:hover {
  transform: translateY(-1px);
  border-color: #00b67a;
  box-shadow: 0 4px 14px rgba(0, 182, 122, 0.2);
  color: #0e1b2a;
  text-decoration: none;
}

/* Social proof directly under the buttons, the way Tradervue does it. */
.fxs-site .fxs-proof { margin-top: 36px; display: flex; flex-direction: column; align-items: center; gap: 10px; }

/* The hero facts row, which replaced the five invented avatars. Three real
   numbers about the data set, side by side, with the figure carrying the
   weight and the label kept quiet under it. */
.fxs-site .fxs-proof__facts {
  display: flex; flex-wrap: wrap; justify-content: center;
  gap: 10px 28px;
}
.fxs-site .fxs-proof__facts span {
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  font-size: 13px; color: var(--muted); text-align: center;
  letter-spacing: 0.01em;
}
.fxs-site .fxs-proof__facts b {
  font-size: 22px; font-weight: 800; color: var(--ink);
  font-variant-numeric: tabular-nums; line-height: 1.1;
}

/* ── testimonials ───────────────────────────────────────── */
.fxs-site .fxs-quotes { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; }
.fxs-site .fxs-quote { background: var(--white); border: 1px solid var(--line); border-radius: 12px; padding: 24px; }
.fxs-site .fxs-quote p { font-size: 15px; color: var(--body); margin-top: 12px; }
.fxs-site .fxs-quote__who { display: flex; align-items: center; gap: 10px; margin-top: 18px; font-size: 14px; }
.fxs-site .fxs-quote__who b { color: var(--ink); font-weight: 700; }
.fxs-site .fxs-quote__av { width: 32px; height: 32px; border-radius: 50%; background: var(--sand); display: grid; place-items: center; font-size: 12px; font-weight: 800; color: var(--body); }

/* ── feature rows ───────────────────────────────────────── */
/* Centred rather than split left/right. A two column row reads as two things
   competing; one column down the middle reads as one thing. */
.fxs-site .fxs-feat { max-width: 760px; margin: 0 auto; text-align: center; padding: 64px 0; border-top: 1px solid var(--line); }
.fxs-site .fxs-feat:first-of-type { border-top: 0; padding-top: 8px; }
.fxs-site .fxs-feat h3 { font-size: clamp(24px, 3vw, 32px); }
.fxs-site .fxs-feat p { margin: 14px auto 0; font-size: 17px; max-width: 58ch; }
.fxs-site .fxs-feat__more { display: inline-flex; align-items: center; gap: 7px; margin-top: 20px; font-weight: 700; color: var(--accent); font-size: 16px; }
.fxs-site .fxs-feat__more:hover { color: var(--accent-ink); }

/* A calm placeholder for the video that will sit here. */
.fxs-site .fxs-feat__media { margin-top: 28px; aspect-ratio: 16 / 9; background: var(--white); border: 1px solid var(--line); border-radius: 12px; display: grid; place-items: center; color: var(--muted); font-size: 14px; font-weight: 600; }

/* ── steps ──────────────────────────────────────────────── */
.fxs-site .fxs-steps { display: grid; grid-template-columns: repeat(3, 1fr); gap: 40px; text-align: center; }
.fxs-site .fxs-step__n { font-size: 13px; font-weight: 800; color: var(--accent); letter-spacing: 0.08em; }
.fxs-site .fxs-step h3 { font-size: 21px; margin-top: 10px; }
.fxs-site .fxs-step p { margin-top: 8px; font-size: 16px; }

/* ── closing band ───────────────────────────────────────── */
.fxs-site .fxs-close { text-align: center; }
.fxs-site .fxs-close h2 { font-size: clamp(28px, 4vw, 40px); color: #fff; }
.fxs-site .fxs-close p { margin: 16px auto 0; max-width: 52ch; }
.fxs-site .fxs-close .fxs-hero__cta { margin-top: 30px; }

/* ── footer ─────────────────────────────────────────────── */
.fxs-site .fxs-foot { background: var(--white); border-top: 1px solid var(--line); padding: 56px 0 40px; }
.fxs-site .fxs-foot__grid { display: grid; grid-template-columns: 1.6fr repeat(3, 1fr); gap: 40px; text-align: left; }
.fxs-site .fxs-foot h4 { font-size: 13px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--muted); font-weight: 800; }
.fxs-site .fxs-foot ul { list-style: none; margin: 14px 0 0; padding: 0; display: grid; gap: 10px; }
.fxs-site .fxs-foot a { font-size: 15px; color: var(--body); }
.fxs-site .fxs-foot a:hover { color: var(--ink); }
.fxs-site .fxs-foot__social { display: flex; gap: 10px; margin-top: 18px; }
.fxs-site .fxs-foot__social a { display: inline-flex; align-items: center; justify-content: center; width: 38px; height: 38px; border-radius: 10px; border: 1px solid var(--line); color: var(--muted); transition: color .15s ease, border-color .15s ease, background .15s ease; }
.fxs-site .fxs-foot__social a:hover { color: var(--ink); border-color: var(--ink); background: var(--sand); }
.fxs-site .fxs-foot__bar { margin-top: 44px; padding-top: 22px; border-top: 1px solid var(--line); font-size: 14px; color: var(--muted); display: flex; justify-content: space-between; gap: 16px; flex-wrap: wrap; }

/* ── subpage hero ───────────────────────────────────────── */
.fxs-site .fxs-sub { padding: 72px 0 56px; text-align: center; border-bottom: 1px solid var(--line); }
.fxs-site .fxs-sub h1 { font-size: clamp(32px, 5vw, 50px); max-width: 18ch; margin: 0 auto; }
.fxs-site .fxs-sub p { margin: 20px auto 0; max-width: 58ch; font-size: 18px; }
.fxs-site .fxs-sub .fxs-hero__cta { margin-top: 30px; }
.fxs-site .fxs-back { display: inline-flex; align-items: center; gap: 7px; font-size: 14px; font-weight: 700; color: var(--muted); margin-bottom: 26px; }
.fxs-site .fxs-back:hover { color: var(--ink); }

.fxs-site .fxs-points { display: grid; grid-template-columns: repeat(2, 1fr); gap: 28px 48px; }
.fxs-site .fxs-point h3 { font-size: 19px; }
.fxs-site .fxs-point p { margin-top: 7px; font-size: 16px; }

/* "The rest of the platform" holds five links, not four. In a two column grid
   that left the fifth alone on the left of the last row, and each card sat at
   the far edge of a 512px column, so the whole block read as left aligned under
   a centred heading. Fixed width cards in a centred row put three above two,
   both rows on the same centre line as the title above them. */
.fxs-site .fxs-points--rest {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 40px 48px;
}
.fxs-site .fxs-points--rest .fxs-point { flex: 0 1 264px; text-align: center; }
.fxs-site .fxs-points--rest .fxs-feat__more { margin-top: 14px; }

/* ── education: strategy cards + video embed ─────────────── */
/* Squarish cards on /strategies: title at the top, a short rule under it, and the
   creator credit pinned to the bottom of the panel. auto-fill (not auto-fit) keeps
   a lone card from stretching across the whole row. */
.fxs-site .fxs-strat-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
  gap: 20px;
}
.fxs-site .fxs-strat {
  display: flex;
  flex-direction: column;
  aspect-ratio: 1 / 1;
  min-height: 190px;
  padding: 22px;
  background: var(--white);
  border: 1px solid var(--line);
  border-radius: 16px;
  color: var(--ink);
  transition: border-color .18s ease, transform .18s ease, box-shadow .18s ease;
}
.fxs-site .fxs-strat:hover {
  border-color: var(--accent);
  transform: translateY(-3px);
  box-shadow: 0 16px 34px rgba(14, 27, 42, 0.10);
}
.fxs-site .fxs-strat__title { margin: 0; font-size: 20px; font-weight: 700; line-height: 1.25; color: var(--ink); }
.fxs-site .fxs-strat__hook { margin: 12px 0 0; font-size: 14px; line-height: 1.45; color: var(--body); }
.fxs-site .fxs-strat__foot { margin-top: auto; }
.fxs-site .fxs-strat__line { display: block; width: 34px; height: 3px; margin: 0 0 12px; border-radius: 3px; background: var(--accent); }
.fxs-site .fxs-strat__by { margin: 0; font-size: 15px; color: var(--muted); }
.fxs-site .fxs-strat__by i { font-style: italic; font-weight: 600; color: var(--ink); }

/* Small, centred footer-style disclaimer under the hub. */
.fxs-site .fxs-strat-note { padding: 28px 0 46px; }
.fxs-site .fxs-strat-note p { max-width: 80ch; margin: 0 auto; text-align: center; font-size: 12.5px; line-height: 1.65; color: var(--muted); }

/* Responsive 16:9 YouTube embed on a strategy page. */
.fxs-site .fxs-embed {
  position: relative;
  aspect-ratio: 16 / 9;
  margin: 6px 0 12px;
  border-radius: 14px;
  overflow: hidden;
  background: #000;
  border: 1px solid var(--line);
}
.fxs-site .fxs-embed iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }
.fxs-site .fxs-embed__credit { margin: 0 0 1.6rem; font-size: 14px; color: var(--muted); }
.fxs-site .fxs-embed__credit a { color: var(--accent); }
.fxs-site .fxs-strat-cta { margin: 2.4rem 0 0.5rem; }

/* ── responsive ─────────────────────────────────────────── */
@media (max-width: 900px) {
.fxs-site .fxs-feat, .fxs-site .fxs-quotes, .fxs-site .fxs-steps, .fxs-site .fxs-points { grid-template-columns: 1fr; gap: 32px; }
.fxs-site .fxs-feat { padding: 48px 0; }
.fxs-site .fxs-feat--flip .fxs-feat__media { order: 0; }
.fxs-site .fxs-foot__grid { grid-template-columns: 1fr 1fr; }
.fxs-site .fxs-nav__links { display: none; }
.fxs-site .fxs-sec { padding: 64px 0; }
}
@media (max-width: 560px) {
.fxs-site .fxs-foot__grid { grid-template-columns: 1fr; }
.fxs-site .fxs-hero { padding: 56px 0 48px; }
.fxs-site .fxs-btn { width: 100%; }
.fxs-site .fxs-hero__cta { flex-direction: column; }
/* Phone type scale: the desktop hero sizes (40px floor heading, 19px lede) are too
   big on a narrow screen. Scale them down so the hero reads as phone-sized. */
.fxs-site .fxs-hero__h1 { font-size: clamp(29px, 8.4vw, 40px); max-width: 18ch; }
.fxs-site .fxs-hero__sub { font-size: 16px; margin-top: 22px; line-height: 1.55; }
.fxs-site .fxs-lede { font-size: 15px; }
}

/* ============================================================
   Additions: background texture, scroll reveal, review marquee,
   pricing, and the logo lockup.
   ============================================================ */

/* ── logo lockup ────────────────────────────────────────────
   The supplied logo is a raster with a baked-in near-black field and
   roughly half its pixels near white, so on a light page it either
   shows as a dark rectangle or half disappears. Sitting the cut-out
   mark in a small navy tile keeps the real logo, reads at any size,
   and looks deliberate instead of pasted on. */
.fxs-site .fxs-nav__logo img,
.fxs-site .fxs-foot .fxs-nav__logo img {
  height: 30px; width: auto; object-fit: contain;
}

/* ── very subtle background ─────────────────────────────────
   One faint wordmark, sized to the section and clipped, at an opacity
   where you notice the page has depth without noticing why. Nothing
   moves, nothing is coloured. */
/* A giant wordmark behind the hero was the first thing tried and it was wrong:
   the headline is the whole point of this section, and a second piece of type
   behind it competes no matter how faint. What is left is a soft warm wash that
   lifts the middle of the page off the edges. You should not be able to say what
   it is, only that the page has some depth. */
.fxs-site .fxs-hero { position: relative; overflow: hidden; }
.fxs-site .fxs-hero::before {
  content: ""; position: absolute; inset: -20% -10% auto; height: 150%;
  background:
    radial-gradient(ellipse 60% 50% at 50% 30%, rgba(11, 79, 212, 0.045), transparent 70%),
    radial-gradient(ellipse 50% 40% at 50% 75%, rgba(14, 27, 42, 0.03), transparent 70%);
  pointer-events: none; z-index: 0;
}
.fxs-site .fxs-hero > .fxs-wrap { position: relative; z-index: 1; }

/* A hairline grid, barely there, to stop large flat areas feeling empty. */
.fxs-site .fxs-sec--sand { position: relative; }
.fxs-site .fxs-sec--sand::before {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background-image:
    linear-gradient(to right, rgba(14,27,42,0.022) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(14,27,42,0.022) 1px, transparent 1px);
  background-size: 64px 64px;
  mask-image: radial-gradient(ellipse 70% 60% at 50% 50%, #000 40%, transparent 100%);
}
.fxs-site .fxs-sec--sand > .fxs-wrap { position: relative; z-index: 1; }

/* ── scroll reveal ──────────────────────────────────────────
   Sections are immediately crisp and readable without scroll-fade lag. */
.fxs-site [data-reveal] {
  opacity: 1 !important;
  transform: none !important;
  transition: none !important;
}
.fxs-site [data-reveal].is-in { opacity: 1 !important; transform: none !important; }
.fxs-site [data-reveal][data-reveal-x] { transform: none !important; }
/* Clip only the sections holding a side-slide, so the off-screen start position
   never adds a horizontal scrollbar. clip (not hidden) keeps the nav sticky. */
.fxs-site .fxs-sec:has([data-reveal-x]) { overflow-x: clip; }
@media (prefers-reduced-motion: reduce) {
.fxs-site [data-reveal] { opacity: 1; transform: none; transition: none; }
.fxs-site [data-reveal][data-reveal-x] { transform: none; }
}

/* ── review marquee ─────────────────────────────────────────
   A continuous track duplicated once, translated by exactly half its
   width, so the loop has no visible seam. Pauses on hover so a quote
   can actually be read. */
.fxs-site .fxs-marquee { position: relative; overflow: hidden; }
.fxs-site .fxs-marquee::before, .fxs-site .fxs-marquee::after {
  content: ""; position: absolute; top: 0; bottom: 0; width: 90px; z-index: 2; pointer-events: none;
}
.fxs-site .fxs-marquee::before { left: 0;  background: linear-gradient(to right, var(--white), transparent); }
.fxs-site .fxs-marquee::after { right: 0; background: linear-gradient(to left,  var(--white), transparent); }
.fxs-site .fxs-marquee__track { display: flex; gap: 20px; width: max-content; animation: fxs-scroll 64s linear infinite; will-change: transform; transform: translateZ(0); }
.fxs-site .fxs-marquee:hover .fxs-marquee__track { animation-play-state: paused; }
@keyframes fxs-scroll { from { transform: translateX(0); } to { transform: translateX(-50%); } }
@media (prefers-reduced-motion: reduce) {
.fxs-site .fxs-marquee__track { animation: none; }
.fxs-site .fxs-marquee { overflow-x: auto; }
}
.fxs-site .fxs-marquee .fxs-quote { width: 340px; flex: 0 0 340px; text-align: left; }
/* The guides strip curves (see .fxs-guide), so give it room top and bottom for
   the arc's tilt and drop without the marquee's overflow clipping the cards, and
   narrow its edge fades so the most-curved cards near the edges stay visible
   (the default 90px fade hid them, which made the arc read as flat). */
.fxs-site .fxs-marquee:has(.fxs-guide) { padding: 16px 0 52px; }
.fxs-site .fxs-marquee:has(.fxs-guide)::before,
.fxs-site .fxs-marquee:has(.fxs-guide)::after { width: 44px; }

/* ── the guides strip ─────────────────────────────────────────────────────
   Same footprint as the quote cards it replaced, so the marquee geometry is
   unchanged. These are links, so they get a hover and a focus ring that the
   quote cards never needed. */
/* Dark-blue cards, white text (owner). Each card also sits on a shallow arc:
   startGuidesArc in LandingPage.jsx writes --fx-arc (a per-card
   perspective/rotateY/translateY/translateZ) from the card's live position in
   the strip, so the row bows and the cards turn as the marquee flows past. The
   transform is NOT transitioned — the frame loop is what moves it; a transition
   would smear it. With the JS off or reduced-motion, --fx-arc is unset so the
   cards fall back to a flat row. */
.fxs-site .fxs-guide {
  width: 340px; flex: 0 0 340px;
  display: flex; flex-direction: column; gap: 8px;
  background: #0d1b2e; border: 1px solid rgba(255, 255, 255, 0.10);
  border-radius: 14px; padding: 22px 24px;
  text-align: left; text-decoration: none;
  transform: var(--fx-arc, none); transform-origin: center center;
  transition: border-color 140ms ease, box-shadow 200ms ease;
}
.fxs-site .fxs-guide:hover {
  border-color: var(--accent);
  transform: translateY(-4px) var(--fx-arc, none);
  box-shadow: 0 24px 54px -30px rgba(4, 10, 20, 0.85);
}
.fxs-site .fxs-guide:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.fxs-site .fxs-guide__k {
  font-size: 11px; font-weight: 800; letter-spacing: 0.1em;
  text-transform: uppercase; color: #7fa8d9;
}
.fxs-site .fxs-guide__t {
  font-size: 15px; font-weight: 700; line-height: 1.35; color: #fff;
}
.fxs-site .fxs-guide__d {
  font-size: 14px; line-height: 1.55; color: rgba(255, 255, 255, 0.72);
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical;
  overflow: hidden;
}
.fxs-site .fxs-guides__eyebrow {
  margin: 0 0 18px;
  font-size: 12px; font-weight: 800; letter-spacing: 0.12em;
  text-transform: uppercase; color: var(--muted);
}
@media (prefers-reduced-motion: reduce) {
  .fxs-site .fxs-guide { transition: none; }
  .fxs-site .fxs-guide:hover { transform: none; }
}

/* ── pricing ────────────────────────────────────────────────*/
.fxs-site .fxs-switch { display: inline-flex; gap: 4px; padding: 4px; background: var(--sand); border: 1px solid var(--line); border-radius: 999px; margin: 0 auto 40px; }
.fxs-site .fxs-switch button {
  border: 0; background: none; font-family: inherit; font-size: 14px; font-weight: 700;
  color: var(--body); padding: 8px 18px; border-radius: 999px; cursor: pointer;
}
.fxs-site .fxs-switch button[aria-pressed="true"] { background: var(--white); color: var(--ink); border: 1px solid var(--line); }

.fxs-site .fxs-plans { display: grid; grid-template-columns: repeat(4, 1fr); gap: 20px; text-align: left; }
@media (max-width: 1040px) { .fxs-site .fxs-plans { grid-template-columns: repeat(2, 1fr); } }
/* The Community plan is earned, not bought — give it a quiet accent so it reads as
   the odd one out in a good way. */
.fxs-site .fxs-plan--community { border-color: color-mix(in srgb, var(--accent) 40%, var(--line)); background: color-mix(in srgb, var(--accent) 4%, var(--white)); }
.fxs-site .fxs-plan { background: var(--white); border: 1px solid var(--line); border-radius: 14px; padding: 28px; display: flex; flex-direction: column;
  /* opacity keeps the scroll-reveal fade; the rest drives the hover reaction —
     all non-layout properties, so the card's size never changes. */
  transition: opacity .5s ease, transform .3s cubic-bezier(.22, 1, .36, 1), box-shadow .3s ease, border-color .3s ease;
}
/* Hover reaction: the card lifts, its border turns to the accent and it casts a
   tinted shadow. Size, padding and content are untouched. */
.fxs-site .fxs-plan:hover {
  transform: translateY(-6px);
  border-color: var(--accent);
  box-shadow: 0 24px 52px -26px rgba(11, 79, 212, 0.38);
}
/* The middle card stands on a podium.
   It used to sit higher while its text sat lower, which read as a mistake
   rather than a hierarchy. The cause was the "Most popular" tag: only this card
   has one, and in the flow it pushed the heading, the price and everything
   under it down by its own height plus its margin, so the card rose and the
   contents dropped.
   The tag comes out of the flow now. The card is pulled up by 28px and given
   that much back as padding plus room for the tag, so the card and everything
   inside it rise together. */
.fxs-site .fxs-plan--best {
  border-color: var(--accent);
  position: relative;
  margin-top: -28px;
  padding-top: 46px;
  box-shadow: 0 22px 50px -30px rgba(11, 79, 212, 0.45);
}
.fxs-site .fxs-plan__tag { display: inline-block; font-size: 11px; font-weight: 800; letter-spacing: 0.1em; text-transform: uppercase; color: var(--accent); margin-bottom: 10px; }
/* Absolute, so it labels the card without shifting anything below it. */
.fxs-site .fxs-plan--best .fxs-plan__tag {
  position: absolute;
  top: 20px;
  left: 28px;
  margin-bottom: 0;
}
.fxs-site .fxs-plan h3 { font-size: 22px; }
.fxs-site .fxs-plan__note { font-size: 15px; color: var(--muted); margin-top: 4px; }
.fxs-site .fxs-plan__price { margin-top: 18px; font-size: 38px; font-weight: 800; color: var(--ink); letter-spacing: -0.02em; }
.fxs-site .fxs-plan__price span { font-size: 15px; font-weight: 600; color: var(--muted); letter-spacing: 0; }
.fxs-site .fxs-plan__alt { font-size: 14px; color: var(--muted); margin-top: 6px; min-height: 20px; }
/* The Community plan's pitch, sat under its button so the button lines up with the
   other cards rather than being pushed down by the longer copy. */
.fxs-site .fxs-plan__blurb { font-size: 14px; line-height: 1.55; color: var(--muted); margin: 14px 0 0; }
.fxs-site .fxs-plan .fxs-btn { margin-top: 20px; width: 100%; }
.fxs-site .fxs-plan ul { list-style: none; margin: 22px 0 0; padding: 0; display: grid; gap: 11px; }
.fxs-site .fxs-plan li { display: flex; gap: 10px; font-size: 15px; color: var(--body); }
.fxs-site .fxs-plan li svg { flex: 0 0 auto; margin-top: 3px; }

/* ── comparison table ───────────────────────────────────────*/
.fxs-site .fxs-tablewrap { margin-top: 56px; overflow-x: auto; border: 1px solid var(--line); border-radius: 14px; background: var(--white); }
.fxs-site .fxs-table { width: 100%; border-collapse: collapse; font-size: 15px; min-width: 720px; }
.fxs-site .fxs-table th, .fxs-site .fxs-table td { padding: 13px 18px; text-align: left; border-bottom: 1px solid var(--line); }
.fxs-site .fxs-table thead th { font-size: 13px; letter-spacing: 0.06em; text-transform: uppercase; color: var(--muted); font-weight: 800; background: var(--sand); }
.fxs-site .fxs-table td:not(:first-child), .fxs-site .fxs-table th:not(:first-child) { text-align: center; }
.fxs-site .fxs-table tbody th { font-weight: 700; color: var(--ink); }
.fxs-site .fxs-table__group td { background: var(--sand); font-weight: 800; color: var(--ink); font-size: 13px; letter-spacing: 0.06em; text-transform: uppercase; }
.fxs-site .fxs-yes { color: var(--up); } .fxs-no { color: var(--muted); opacity: .55; }
.fxs-site .fxs-table tr:last-child td, .fxs-site .fxs-table tr:last-child th { border-bottom: 0; }

@media (max-width: 900px) {
.fxs-site .fxs-plans { grid-template-columns: 1fr; }
.fxs-site .fxs-marquee .fxs-quote { width: 280px; flex-basis: 280px; }
.fxs-site .fxs-guide { width: 280px; flex-basis: 280px; }
}

/* Empty stars on the partial ratings. Without this a three star review renders
   five gold stars, which quietly turns mixed feedback back into a wall of
   five star praise. */
.fxs-site .fxs-star--off { color: var(--line-2); }

/* ============================================================
   Background texture and the feature call to action.
   ============================================================ */

/* The page read as too empty once the decoration came off. This is the least
   that fixes it: a hairline grid over the whole page, faded out at the edges so
   it never draws a hard line, plus a soft warm bloom. You should register that
   the surface has a texture without being able to describe it. */
.fxs-site { position: relative; }
.fxs-site::before {
  content: ""; position: fixed; inset: 0; z-index: 0; pointer-events: none;
  background-image:
    linear-gradient(to right,  rgba(14,27,42,0.030) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(14,27,42,0.030) 1px, transparent 1px);
  background-size: 72px 72px;
  mask-image: radial-gradient(ellipse 90% 70% at 50% 30%, #000 20%, transparent 78%);
  -webkit-mask-image: radial-gradient(ellipse 90% 70% at 50% 30%, #000 20%, transparent 78%);
}
@media (max-width: 900px) {
  .fxs-site::before {
    position: absolute;
    height: 100vh;
    mask-image: none;
    -webkit-mask-image: none;
    opacity: 0.45;
  }
}
.fxs-site > * { position: relative; z-index: 1; }

/* Sections that carry their own background need to sit over the grid. */
.fxs-site .fxs-sec--white, .fxs-site .fxs-sec--navy, .fxs-site .fxs-foot { position: relative; z-index: 1; }

/* ── feature call to action ─────────────────────────────────
   Replaces the video placeholder on the front page. A short line, a question,
   and one button, rather than an empty grey box promising something later. */
.fxs-site .fxs-featcta {
  margin-top: 26px; padding-top: 24px; border-top: 1px solid var(--line);
  display: flex; flex-direction: column; align-items: center; gap: 14px;
}
.fxs-site .fxs-featcta p { font-size: 16px; color: var(--ink); font-weight: 700; margin: 0; }
/* Filled, not outlined. One class carries the call to action on all six feature
   blocks, so this is every one of them at once. */
.fxs-site .fxs-btn--feature {
  background: var(--ink); color: #fff; border-color: var(--ink);
  padding: 12px 22px; font-size: 15px;
}
.fxs-site .fxs-btn--feature:hover { background: #1B2E45; border-color: #1B2E45; color: #fff; }
.fxs-site .fxs-btn--feature svg { transition: transform .15s; }
.fxs-site .fxs-btn--feature:hover svg { transform: translateX(3px); }

/* ============================================================
   Auth pages.

   Login and signup were built on the app's dark design language, so
   arriving from a light marketing site dropped you onto a dark card
   that looked like a different product. Rather than rewrite the
   markup, this rethemes those classes inside .fxs-auth and adds the
   split layout: form on the left, proof on the right, which is what
   makes a sign in page feel like part of the site rather than a
   modal that lost its page.
   ============================================================ */
.fxs-auth {
  --paper:#FBFAF8; --white:#fff; --sand:#F4F1EC; --ink:#0E1B2A; --body:#46586B;
  --muted:#7B8A99; --line:#E7E3DC; --line-2:#D8D3CA; --accent:#0B4FD4; --accent-ink:#0840AC;
  background: var(--paper) !important;
  color: var(--body);
  font-family: Manrope, ui-sans-serif, system-ui, sans-serif;
  min-height: 100vh;
  display: grid; place-items: center; padding: 40px 24px;
}
.fxs-auth__grid {
  width: 100%; max-width: 1040px;
  display: grid; grid-template-columns: minmax(0,420px) minmax(0,1fr);
  gap: 56px; align-items: center;
}

/* Rethemed app classes, scoped so the dark app is untouched. */
.fxs-auth .fx-card, .fxs-auth .fx-auth__card {
  background: transparent !important; border: 0 !important; box-shadow: none !important;
  padding: 0 !important; max-width: none !important; width: 100% !important;
  display: flex; flex-direction: column; gap: 18px;
}
.fxs-auth .fx-title, .fxs-auth .fx-title--card {
  color: var(--ink) !important; font-weight: 800 !important;
  font-size: 32px !important; letter-spacing: -0.02em !important; line-height: 1.12 !important;
}
.fxs-auth .fx-eyebrow {
  color: var(--muted) !important; font-weight: 600 !important; font-size: 13px !important;
  letter-spacing: 0.01em !important; text-transform: none !important;
}
.fxs-auth .fx-meta { color: var(--muted) !important; font-size: 15px !important; }
.fxs-auth .fx-rule { border: 0; border-top: 1px solid var(--line); margin: 4px 0; }
.fxs-auth .fx-input {
  background: var(--white) !important; border: 1px solid var(--line-2) !important;
  color: var(--ink) !important; border-radius: 10px !important;
  min-height: 46px !important; padding: 11px 14px !important; font-size: 15px !important;
  font-family: inherit !important; width: 100%;
}
.fxs-auth .fx-input::placeholder { color: #A9B3BD !important; }
.fxs-auth .fx-input:focus { border-color: var(--accent) !important; outline: none !important; }
.fxs-auth .fx-field, .fxs-auth .fx-auth__form { display: flex; flex-direction: column; gap: 6px; }
.fxs-auth .fx-auth__form { gap: 16px; }
.fxs-auth .fx-auth__labelrow { display: flex; justify-content: space-between; align-items: baseline; gap: 12px; }
.fxs-auth label, .fxs-auth .fx-field > span:first-child {
  font-size: 12px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; color: var(--muted);
}
.fxs-auth .fx-btn, .fxs-auth .fx-btn-primary, .fxs-auth .fx-btn--block, .fxs-auth .fx-btn--tall {
  border-radius: 10px !important; font-family: inherit !important; font-weight: 700 !important;
  font-size: 16px !important; min-height: 48px !important; cursor: pointer;
}
.fxs-auth .fx-btn-primary {
  background: var(--accent) !important; border: 1px solid var(--accent) !important; color: #fff !important;
}
.fxs-auth .fx-btn-primary:hover { background: var(--accent-ink) !important; }
.fxs-auth .fx-btn-ghost {
  background: var(--white) !important; border: 1px solid var(--line-2) !important; color: var(--ink) !important;
}
.fxs-auth .fx-link { color: var(--accent) !important; font-weight: 700 !important; }
.fxs-auth .fx-notice {
  border-radius: 10px !important; font-size: 14px !important; padding: 12px 14px !important;
  box-shadow: none !important;
}
.fxs-auth .fx-notice--error { background: rgba(192,69,59,0.06) !important; border: 1px solid rgba(192,69,59,0.28) !important; color: #C0453B !important; }
.fxs-auth .fx-notice--accent { background: rgba(11,79,212,0.05) !important; border: 1px solid rgba(11,79,212,0.24) !important; color: #0840AC !important; }
.fxs-auth .fx-auth__brand { background: none !important; border: 0 !important; padding: 0 !important; display: inline-flex; align-items: center; gap: 9px; cursor: pointer; }
.fxs-auth .fx-auth__brandmark { color: var(--ink) !important; font-weight: 800; font-size: 18px; letter-spacing: -0.01em; text-transform: none; }
.fxs-auth .fx-auth__brand img { background: none !important; padding: 0 !important; border-radius: 0 !important; height: 28px !important; width: auto !important; }
.fxs-auth .fx-auth__foot { color: var(--muted) !important; font-size: 15px; }

/* Right hand panel. Same proof that is on the landing page, so the two read
   as one site. */
.fxs-auth__aside { background: var(--white); border: 1px solid var(--line); border-radius: 16px; padding: 34px; }
.fxs-auth__aside h2 { font-size: 26px; font-weight: 800; color: var(--ink); letter-spacing: -0.02em; line-height: 1.15; margin: 0; }
.fxs-auth__aside > p { margin: 12px 0 0; font-size: 16px; color: var(--body); }
.fxs-auth__quotes { display: grid; gap: 12px; margin-top: 24px; }
.fxs-auth__q { background: var(--sand); border: 1px solid var(--line); border-radius: 11px; padding: 15px 16px; }
.fxs-auth__q p { margin: 8px 0 0; font-size: 14px; color: var(--body); line-height: 1.5; }
.fxs-auth__q b { display: block; margin-top: 9px; font-size: 13px; color: var(--ink); }
.fxs-auth__stars { color: #E3A008; font-size: 13px; letter-spacing: 1px; }
.fxs-auth__stars i { color: var(--line-2); font-style: normal; }

@media (max-width: 900px) {
  .fxs-auth__grid { grid-template-columns: 1fr; gap: 32px; max-width: 460px; }
  .fxs-auth__aside { display: none; }
}

/* ── auth inside the site frame ─────────────────────────────*/
.fxs-site .fxs-authpage { background: var(--paper); min-height: 100vh; }
.fxs-site .fxs-auth__grid { align-items: start; gap: 64px; }
.fxs-site .fxs-auth__form { padding-top: 8px; }

/* Right hand panel: a real chart rather than a block of praise, so the page
   shows the product instead of talking about it. */
.fxs-site .fxs-auth__aside { padding: 30px; }
.fxs-site .fxs-auth__chart {
  margin-top: 22px; height: 300px; width: 100%;
  border: 1px solid var(--line); border-radius: 11px; overflow: hidden;
}
.fxs-site .fxs-auth__note { margin-top: 10px; font-size: 13px; color: var(--muted); }

@media (max-width: 900px) {
  /* The chart is the first thing to go: it is decoration next to a form
     somebody is trying to fill in on a phone. */
  .fxs-site .fxs-auth__aside { display: none; }
}

/* The login screen's own root carries the app's .fx-ground and .fx-scope, which
   paint the dark app surface and claim a full viewport. Inside the shell the
   page already provides both, so they have to be neutralised or the form sits
   in a dark slab on a light page. */
.fxs-site .fxs-auth__form .fx-ground,
.fxs-site .fxs-auth__form .fx-scope {
  background: transparent !important;
  background-image: none !important;
  min-height: 0 !important;
  height: auto !important;
  padding: 0 !important;
  display: block !important;
  place-items: initial !important;
  color: var(--body) !important;
}

/* ── auth alignment and the review strip ────────────────────*/
/* Both columns start at the same line. The form and the panel are similar
   heights, so top alignment reads as deliberate where centring each one
   independently just looks like they missed each other. */
.fxs-site .fxs-auth__grid { align-items: start; }
.fxs-site .fxs-auth__form { padding-top: 0; }
.fxs-site .fxs-auth__form > * { max-width: 460px; }

.fxs-site .fxs-auth__reviews {
  width: 100%; max-width: 1120px; margin: 64px auto 0;
  padding-top: 40px; border-top: 1px solid var(--line);
}
/* The strip sits on the paper background here, not on white, so the edge fades
   have to match or they show as two grey smudges. */
.fxs-site .fxs-auth__reviews .fxs-marquee::before { background: linear-gradient(to right, var(--paper), transparent); }
.fxs-site .fxs-auth__reviews .fxs-marquee::after  { background: linear-gradient(to left,  var(--paper), transparent); }

/* The facts row on the auth screens, which replaced the testimonial marquee.
   A quiet grid rather than a scroller: there is nothing to loop through and a
   signup page does not want a moving thing next to the form. */
.fxs-site .fxs-auth__proof {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: 18px 26px; margin-top: 34px;
  padding-top: 26px; border-top: 1px solid var(--line);
}
.fxs-site .fxs-authfact { display: flex; flex-direction: column; gap: 3px; }
.fxs-site .fxs-authfact b {
  font-size: 21px; font-weight: 800; color: var(--ink);
  font-variant-numeric: tabular-nums; line-height: 1.1;
}
.fxs-site .fxs-authfact__l {
  font-size: 12px; font-weight: 800; letter-spacing: 0.09em;
  text-transform: uppercase; color: var(--muted);
}
.fxs-site .fxs-authfact__n { font-size: 13px; line-height: 1.5; color: var(--body); }

/* Phone: the two-column auth layout (form + sample chart) was squeezing the form
   and pushing it off-centre / past the right edge. Collapse to a single centred
   column and drop the decorative chart so the form owns the full width. */
@media (max-width: 760px) {
  .fxs-site .fxs-auth { padding: 28px 16px; place-items: start center; }
  .fxs-site .fxs-auth__grid {
    /* minmax(0,1fr), not 1fr: a plain 1fr track won't shrink below the form card's
       420px min-content, so it overflowed a narrow phone. The 0 minimum lets the
       column shrink to the viewport and the card (maxWidth:100%) follows. */
    grid-template-columns: minmax(0, 1fr);
    gap: 0;
    max-width: 460px;
    width: 100%;
    justify-items: stretch;
  }
  .fxs-site .fxs-auth__aside { display: none; }
  .fxs-site .fxs-auth__form { width: 100%; min-width: 0; }
  .fxs-site .fxs-auth__form > * { max-width: none; width: 100%; }
}

/* ── video placeholder ──────────────────────────────────────
   Deliberately the brightest thing on the page. Everything else here is flat
   and quiet, so a soft halo and a play mark are enough to make this the thing
   the eye lands on, without adding a colour the palette does not have. */
.fxs-site .fxs-video {
  position: relative;
  margin: 34px auto 0;
  aspect-ratio: 16 / 9;
  width: 100%;
  background: var(--white);
  border: 1px solid var(--line);
  border-radius: 14px;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 10px;
  /* The glow, from the inside out: a white bloom hugging the border that reads
     against the faint grid behind it, a hairline to keep the bloom from just
     looking like a blurry edge, then a wide neutral halo lifting the whole card
     off the paper. All neutral, no colour the palette does not already have. */
  box-shadow:
    0 0 0 1px rgba(255, 255, 255, 0.95) inset,
    0 0 0 10px rgba(255, 255, 255, 0.8),
    0 0 0 11px rgba(14, 27, 42, 0.05),
    0 24px 60px -26px rgba(14, 27, 42, 0.30),
    0 0 90px -10px rgba(14, 27, 42, 0.14);
  transition: box-shadow .25s ease, transform .25s ease;
}
.fxs-site .fxs-video:hover {
  transform: translateY(-2px);
  box-shadow:
    0 0 0 1px rgba(255, 255, 255, 1) inset,
    0 0 0 12px rgba(255, 255, 255, 0.9),
    0 0 0 13px rgba(14, 27, 42, 0.07),
    0 28px 70px -26px rgba(14, 27, 42, 0.34),
    0 0 110px -10px rgba(14, 27, 42, 0.18);
}
.fxs-site .fxs-video__play {
  width: 62px; height: 62px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--white); color: var(--ink);
  border: 1px solid var(--line);
  box-shadow: 0 6px 22px -8px rgba(14, 27, 42, 0.30);
}
.fxs-site .fxs-video__label { font-size: 16px; font-weight: 700; color: var(--ink); }
.fxs-site .fxs-video__note { font-size: 13px; color: var(--muted); }

/* A real recording, rather than the "coming soon" placeholder: the video fills
   the same framed card (16:9), cropped to cover so no letterboxing shows. */
.fxs-site .fxs-video--real { overflow: hidden; padding: 0; background: #0b1a2b; }
.fxs-site .fxs-video__media {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover; display: block;
  border-radius: inherit;
}

/* Secondary button on the navy band. */
.fxs-site .fxs-btn--onnavyghost {
  background: transparent; color: #fff; border-color: rgba(255,255,255,0.34);
}
.fxs-site .fxs-btn--onnavyghost:hover { border-color: #fff; color: #fff; background: rgba(255,255,255,0.06); }

/* ── feature page body ───────────────────────────────────────────────────────
   The walkthrough leads, the writing sits under it. The prose is ranged left
   rather than centred: centred paragraphs give every line a different starting
   point, so the eye has to hunt for the start of each one. */
.fxs-site .fxs-featbody {
  max-width: 760px;
  margin: 0 auto;
}
.fxs-site .fxs-featbody .fxs-video { margin-top: 0; }
.fxs-site .fxs-prose { margin-top: 34px; }
.fxs-site .fxs-prose p {
  text-align: left;
  margin: 0 0 16px;
  font-size: 17px;
  line-height: 1.65;
  color: var(--body);
}
.fxs-site .fxs-prose p:last-child { margin-bottom: 0; }

/* ── feature blocks ─────────────────────────────────────────────────────────
   Five shapes rather than one row repeated six times. Alternating left/right is
   still a pattern, and a page made of it reads as a list however good the
   individual row is. Each feature gets the shape that suits it. */
.fxs-site .fxs-show { padding: 72px 0; border-top: 1px solid var(--line); }
.fxs-site .fxs-show:first-of-type { border-top: 0; padding-top: 8px; }
.fxs-site .fxs-show h3 {
  margin: 8px 0 14px;
  font-size: 30px; line-height: 1.14; letter-spacing: -0.022em; color: var(--ink);
}
.fxs-site .fxs-show p {
  margin: 0 0 16px; font-size: 16.5px; line-height: 1.65; color: var(--body);
}
/* The eyebrow is a <p>, so the rule above was outranking .fxs-eyebrow on
   specificity, 0-2-1 against 0-2-0, and every eyebrow inside a feature block was
   coming out at 16.5px against the 12px it asks for. The ones in a section
   heading, which are not inside a .fxs-show, were the right size all along, so
   the same label was two sizes on one page. */
.fxs-site .fxs-show p.fxs-eyebrow { font-size: 12px; letter-spacing: 0.12em; }
.fxs-site .fxs-show__copy, .fxs-site .fxs-show__head { text-align: left; }
.fxs-site .fxs-show__head { max-width: 720px; margin-bottom: 34px; }
.fxs-site .fxs-show__head--narrow { max-width: 560px; }

/* hero: the recording and the copy side by side, the recording leading. It ran
   the full width before and dominated the page; beside the copy it is about
   three fifths of that, which is the size the two of them fit together at. */
/* Proportioned the way Gumloop does it: the copy sits in a narrow column, the
   panel takes the rest. Measured off their page the copy runs about 26% of the
   row against 60% for the panel, with a wide gutter between.

   Ours pushes past that because the recording is the thing worth looking at: the
   panel takes 71% and the copy 24%, and the gutter is 56px rather than their
   105. The row is capped at the page's 1120px wrap, which every other block
   lines up to, so width for the video has to come out of the gutter and the
   copy; widening the row itself would leave this block hanging past the divider
   under it. */
.fxs-site .fxs-show--hero {
  display: grid;
  grid-template-columns: minmax(0, 3fr) minmax(0, 1fr);
  gap: 56px;
  align-items: center;
}
.fxs-site .fxs-show--hero .fxs-show__head { max-width: none; margin-bottom: 0; }
/* Smaller type, again theirs: the heading holds its size but the prose steps
   down, which is most of why their copy reads as the quieter half of the row. */
.fxs-site .fxs-show--hero h3 { font-size: clamp(22px, 1.9vw, 27px); max-width: none; }
/* Excluding the eyebrow by name, because it is a <p> too and this rule ties with
   the one that pins it to 12px, which put it back to prose size in this block
   only while every other eyebrow on the page stayed 12. */
.fxs-site .fxs-show--hero .fxs-show__head p:not(.fxs-eyebrow) { font-size: 15px; line-height: 1.6; }

/* What is shown is a window onto the recording, not the whole frame.

   The frame is 16:9 and the panel wants to be taller than that without getting
   wider, so the crop takes height from the full 1080 and width from wherever it
   can be spared: 1358 by 1045 out of 1920 by 1080, which is 1.30 rather than
   1.75. What goes is the drawing toolbar and old candles down the left, and the
   price axis down the right, cut in the blank gutter between the plot and the
   axis so no label is sliced in half. The replay controls along the top, which
   are the point of the clip, sit at x 860 to 1797 and stay whole.

   It also gets rid of the corner problem. Cap records onto a coloured ground and
   the window's rounded corners let it show through, which is why this used to
   need a 120px radius to hide the wedges. Cropping inside the window means there
   is no ground left to hide, so the corners can be as square as they look.

   The bounds are measured across the whole clip, not one frame, because the
   recording pans: the ground reaches furthest in around the six second mark, and
   the safe edges over thirteen sampled frames are x >= 89 on the left and
   x <= 1813 on the right. This crop sits inside both.

   Positioned rather than object-fitted, because a crop needs an offset and
   object-fit cannot say which part to keep. The percentages are the ratios:
   1920/1358 across, 1080/1045 down, shifted back by 451 and 30. */
.fxs-site .fxs-art--video { padding: 10px; }
.fxs-site .fxs-vidwin {
  position: relative;
  overflow: hidden;
  width: 100%;
  aspect-ratio: 1358 / 1045;
  /* Square enough to read as a screen rather than a pill. Concentric with the
     card: 8 inside its 10px padding sits under the card's own 16px corner. */
  border-radius: 8px;
  background: #0b1a2b;
}
.fxs-site .fxs-vid {
  position: absolute;
  display: block;
  width: 141.384%;
  height: 103.349%;
  left: -33.211%;
  top: -2.871%;
  max-width: none;
}

.fxs-site .fxs-grid line { stroke: var(--line); stroke-width: 1; }

/* split: copy beside a deck of cards that shuffles itself */
.fxs-site .fxs-show--split {
  display: grid; grid-template-columns: minmax(0, 0.78fr) minmax(0, 1.22fr);
  gap: 56px; align-items: center;
}
.fxs-site .fxs-deck { position: relative; height: 430px; }
/* Every card is the same size and sits on the same centre line. They used to be
   scaled down as they moved back, which made the two behind read as smaller,
   thinner cards rather than the same card further away, and they hung from the
   top of the stage instead of lining up with the copy beside them. The offsets
   are in pixels now, not percentages, so nothing changes shape as it moves. */
.fxs-site .fxs-deck__c {
  position: absolute;
  top: 50%;
  left: 0; right: 0;
  margin: 0 auto;
  width: 100%;
  animation: fxs-shuffle 4.2s cubic-bezier(0.45, 0, 0.25, 1) infinite;
}
.fxs-site .fxs-deck__c--front { animation-delay: 0s; }
.fxs-site .fxs-deck__c--mid   { animation-delay: -1.4s; }
.fxs-site .fxs-deck__c--back  { animation-delay: -2.8s; }
/* Resting on the deck freezes every card exactly where it is, mid travel and
   all, because pausing the play state holds the computed frame rather than
   restarting or snapping to the nearest position. Whatever card is in front
   when the pointer arrives is the card that stays in front. */
.fxs-site .fxs-deck:hover .fxs-deck__c,
.fxs-site .fxs-deck:focus-within .fxs-deck__c { animation-play-state: paused; }

@keyframes fxs-shuffle {
  /* front and centre */
  0%   { transform: translate(0, -50%) rotate(0deg);                      opacity: 1;    z-index: 3; box-shadow: 0 34px 70px -30px rgba(14, 27, 42, 0.42); }
  26%  { transform: translate(0, -50%) rotate(0deg);                      opacity: 1;    z-index: 3; box-shadow: 0 34px 70px -30px rgba(14, 27, 42, 0.42); }
  /* slides back and to the right */
  37%  { transform: translate(38px, calc(-50% - 30px)) rotate(2.2deg);    opacity: 0.85; z-index: 2; box-shadow: 0 22px 48px -32px rgba(14, 27, 42, 0.30); }
  59%  { transform: translate(38px, calc(-50% - 30px)) rotate(2.2deg);    opacity: 0.85; z-index: 2; box-shadow: 0 22px 48px -32px rgba(14, 27, 42, 0.30); }
  /* furthest back */
  70%  { transform: translate(-34px, calc(-50% - 60px)) rotate(-2.6deg);  opacity: 0.6;  z-index: 1; box-shadow: none; }
  92%  { transform: translate(-34px, calc(-50% - 60px)) rotate(-2.6deg);  opacity: 0.6;  z-index: 1; box-shadow: none; }
  /* and round to the front again */
  100% { transform: translate(0, -50%) rotate(0deg);                      opacity: 1;    z-index: 3; box-shadow: 0 34px 70px -30px rgba(14, 27, 42, 0.42); }
}

/* duo: two ideas on one line, but no longer half and half. The prop firm side
   carries a recording and the edge side a drawing, and a recording needs the
   room: an even split left it 524px wide, which is not enough to read a dialog
   in. */
.fxs-site .fxs-duo {
  display: grid; grid-template-columns: minmax(0, 1.45fr) minmax(0, 0.85fr); gap: 40px;
  padding: 72px 0; border-top: 1px solid var(--line);
}
.fxs-site .fxs-duo .fxs-show { padding: 0; border-top: 0; }
.fxs-site .fxs-duo h3 { font-size: 23px; margin-top: 6px; }
.fxs-site .fxs-duo p { font-size: 15.5px; }
.fxs-site .fxs-duo .fxs-art { margin-bottom: 22px; }

/* The prop firm recording, shown whole rather than cropped, because the ground
   Cap put it on is part of it: a grey to white ramp running left to right,
   #404040 at one end and #f4f6f4 at the other. It sits on the page without a
   card, so that gradient is its frame.

   No fade on the pale end. It was there to hide a seam between that #f4f6f4 and
   the page's #FBFAF8, but those are seven to eleven levels apart per channel, and
   they only ever meet at the start and the end of the clip: from about four
   seconds to twenty four the window fills the frame edge to edge, so that edge is
   dark UI and there is no pale seam to hide. The fade was solving something
   invisible at the cost of a dissolve that was not. */
.fxs-site .fxs-vidwide {
  position: relative;
  width: 100%;
  /* Per recording: the prop firm clip is 1892x1080, the creators one 1876x1080,
     and a frame that does not match its own file letterboxes or crops it. */
  aspect-ratio: 1892 / 1080;
  overflow: hidden;
  border-radius: 12px;
  margin-bottom: 22px;
}
.fxs-site .fxs-vidfull {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Creators: the recording takes the whole column and the copy sits above it.

   It is the payout dashboard, a modal of small type, and the drawn figure it
   replaces was about 490px wide in a side by side row. Nothing in a screen
   recording of a dialog survives being shown that small, so this one runs the
   full 1072px the page allows, which is more than twice the area and the largest
   thing on the landing page. */
.fxs-site .fxs-show--wide { display: block; }
.fxs-site .fxs-show--wide .fxs-show__head { margin-bottom: 34px; }
.fxs-site .fxs-vidwide--creators { aspect-ratio: 1876 / 1080; margin-bottom: 0; }

/* ── Prop firm + Vektor AI: card DECK ────────────────────────────────────────
   The two cards sit one behind the other in the same spot — Prop firm in front,
   Vektor AI just behind with its top edge peeking, like a stacked deck. The stage
   pins (sticky), and the driver in LandingPage.jsx maps scroll progress to each
   card's scale / lift / depth: the front card zooms out and recedes while the one
   behind zooms in and comes forward; reversible. Works under Lenis via the
   html.lenis body sticky override. The default (no-JS) state below already shows
   the deck, so it never renders as two flat overlapping cards. */
.fxs-site .fxs-deck { position: relative; height: 230vh; }
.fxs-site .fxs-deck__stage {
  position: sticky; top: 88px; height: min(80vh, 740px);
}
.fxs-site .fxs-deck__card {
  position: absolute; inset: 0; margin: auto;
  width: min(1000px, 92%); height: fit-content; max-height: 100%;
  background: var(--white); border: 1px solid var(--line); border-radius: 22px;
  box-shadow: 0 44px 100px -60px rgba(14, 27, 42, 0.55);
  padding: 18px; overflow: hidden;
  transform-origin: center center; will-change: transform, opacity;
  backface-visibility: hidden;
}
/* Default deck (JS off / first paint): Prop firm front, Vektor behind + peeking. */
.fxs-site .fxs-deck__card:nth-child(1) { z-index: 3; }
.fxs-site .fxs-deck__card:nth-child(2) { z-index: 1; transform: translateY(-50px) scale(0.84); opacity: 0.55; }
.fxs-site .fxs-deck__media {
  width: 100%; border-radius: 14px; overflow: hidden; margin: 0 0 14px;
  aspect-ratio: 1892 / 1080; max-height: min(46vh, 460px);
}
.fxs-site .fxs-vidwide.fxs-deck__media { background: #0b1017; }
.fxs-site .fxs-art--bars.fxs-deck__media {
  aspect-ratio: 1892 / 1080; max-height: min(46vh, 460px);
  background: linear-gradient(180deg, #f7f9fc, #eaf0f8);
  padding: 24px 28px; display: flex; flex-direction: column; justify-content: flex-end;
}
.fxs-site .fxs-art--bars.fxs-deck__media .fxs-bars { height: 64%; }
.fxs-site .fxs-deck__body { padding: 0 6px; }
.fxs-site .fxs-deck__body .fxs-eyebrow { margin-bottom: 8px; }
.fxs-site .fxs-deck__body h3 { font-size: 25px; margin: 4px 0 9px; }
.fxs-site .fxs-deck__body p { font-size: 15.5px; margin-bottom: 14px; }
@media (max-width: 900px), (pointer: coarse) {
  /* On phones the scroll-driven card stack collides with the next section and
     the JS timing is jittery, so drop the pinning entirely and let the two
     cards flow one under the other (same as the reduced-motion fallback). This
     matches exactly when LandingPage gates the deck's rAF loop off (liteMotion:
     a coarse pointer or a narrow screen), so the deck is never pinned-by-CSS
     while its driving script is switched off. */
  .fxs-site .fxs-deck { height: auto; }
  .fxs-site .fxs-deck__stage { position: static; height: auto; }
  .fxs-site .fxs-deck__card {
    position: static; inset: auto; margin: 0 auto 22px; padding: 13px;
    width: 100%; max-height: none;
    transform: none !important; opacity: 1 !important;
  }
  .fxs-site .fxs-deck__media, .fxs-site .fxs-art--bars.fxs-deck__media { max-height: none; }
}
/* Reduced motion: no deck/scroll effect — the two cards just stack in flow. */
@media (prefers-reduced-motion: reduce) {
  .fxs-site .fxs-deck { height: auto; }
  .fxs-site .fxs-deck__stage { position: static; height: auto; }
  .fxs-site .fxs-deck__card { position: static; inset: auto; margin: 0 auto 30px; transform: none !important; opacity: 1 !important; max-height: none; }
}

/* strip: full width, endless, and centred whatever the window */
.fxs-site .fxs-strip {
  overflow: hidden;
  /* Centred by the page's own wrap rather than by a 100vw full-bleed. 100vw
     counts the scrollbar and the viewport's content box does not, so the
     full-bleed version sat a few pixels left of centre, and by a different
     amount depending on whether the machine draws an overlay scrollbar. This
     cannot drift: it is as wide as the column everything else is centred in. */
  width: 100%;
  padding: 6px 0;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
          mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
}
.fxs-site .fxs-strip__row { display: flex; width: max-content; }
/* Two identical halves, and the track slides exactly one half before resetting.
   At the moment it snaps back the second half is sitting where the first was, so
   there is no seam and no end to reach. */
.fxs-site .fxs-strip__track {
  display: flex; gap: 14px; padding-right: 14px;
  animation: fxs-drift 42s linear infinite;
}
.fxs-site .fxs-strip:hover .fxs-strip__track { animation-play-state: paused; }
@keyframes fxs-drift { from { transform: translateX(0); } to { transform: translateX(-100%); } }
.fxs-site .fxs-chip {
  display: flex; align-items: center; gap: 11px; flex: 0 0 auto;
  padding: 13px 18px; border-radius: 14px;
  background: var(--white); border: 1px solid var(--line);
  box-shadow: 0 14px 34px -26px rgba(14, 27, 42, 0.34);
}
.fxs-site .fxs-chip b { font-size: 13.5px; color: var(--ink); display: block; }
.fxs-site .fxs-chip > b:last-child { margin-left: 14px; }

/* offset: tall figure, short column */

@media (prefers-reduced-motion: reduce) {
  .fxs-site .fxs-strip__track,
  .fxs-site .fxs-deck__c { animation: none; }
  .fxs-site .fxs-deck__c--front { transform: translate(0, -50%); z-index: 3; opacity: 1; }
  .fxs-site .fxs-deck__c--mid   { transform: translate(38px, calc(-50% - 30px)) rotate(2.2deg); z-index: 2; opacity: 0.85; }
  .fxs-site .fxs-deck__c--back  { transform: translate(-34px, calc(-50% - 60px)) rotate(-2.6deg); z-index: 1; opacity: 0.6; }
}

@media (max-width: 900px) {
  .fxs-site .fxs-show--hero,
  .fxs-site .fxs-show--split { grid-template-columns: 1fr; gap: 30px; }
  .fxs-site .fxs-show { padding: 44px 0; }
  .fxs-site .fxs-duo { grid-template-columns: 1fr; gap: 34px; padding: 44px 0; }
  /* Un-pinned on phones (cards stacked in flow), so the deck must grow to fit
     both cards; a fixed 340px clipped the second card into the next section. */
  .fxs-site .fxs-deck { height: auto; }
}

/* ── the drawn panels ─────────────────────────────────────────────────────── */
.fxs-site .fxs-art {
  background: var(--white);
  border: 1px solid var(--line);
  border-radius: 16px;
  padding: 14px;
  box-shadow: 0 24px 60px -34px rgba(14, 27, 42, 0.30);
}
.fxs-site .fxs-art__bar {
  display: flex; align-items: center; gap: 7px;
  padding-bottom: 11px; margin-bottom: 12px;
  border-bottom: 1px solid var(--line);
  font-size: 12.5px; color: var(--muted);
}
.fxs-site .fxs-art__bar em { font-style: normal; }
.fxs-site .fxs-art__bar b { margin-left: auto; color: var(--ink); font-size: 12.5px; }
.fxs-site .fxs-art__dot { width: 8px; height: 8px; border-radius: 50%; background: var(--line); }
.fxs-site .fxs-art__foot {
  margin-top: 12px; padding-top: 11px;
  border-top: 1px solid var(--line);
  font-size: 12.5px; color: var(--muted);
  display: flex; align-items: center; gap: 8px;
}
.fxs-site .fxs-art .up { color: #157a4a; }
.fxs-site .fxs-art .dn { color: #c0453b; }

/* replay */
.fxs-site .fxs-art--chart svg { display: block; width: 100%; height: 168px; }
.fxs-site .fxs-candles line { stroke: #157a4a; stroke-width: 1.6; }
.fxs-site .fxs-candles rect { fill: #157a4a; }
.fxs-site .fxs-candles g.dn line { stroke: #c0453b; }
.fxs-site .fxs-candles g.dn rect { fill: #c0453b; }
.fxs-site .fxs-playhead { stroke: var(--accent); stroke-width: 1.4; stroke-dasharray: 4 4; }
.fxs-site .fxs-art__play {
  width: 0; height: 0; border-left: 9px solid var(--accent);
  border-top: 6px solid transparent; border-bottom: 6px solid transparent;
}

/* journal, payouts */
.fxs-site .fxs-jrow {
  display: flex; align-items: center; gap: 10px;
  padding: 11px 4px; font-size: 13.5px; color: var(--body);
  border-bottom: 1px solid var(--line);
}
.fxs-site .fxs-jrow:last-of-type { border-bottom: 0; }
.fxs-site .fxs-jrow b { margin-left: auto; color: var(--ink); }
.fxs-site .fxs-tag {
  font-size: 11.5px; font-weight: 700; letter-spacing: 0.02em;
  padding: 3px 8px; border-radius: 6px;
  background: var(--sand); color: var(--ink);
}
.fxs-site .fxs-payout {
  font-size: 38px; font-weight: 800; letter-spacing: -0.02em;
  color: var(--ink); padding: 6px 4px 12px;
}

/* prop firm meters */
.fxs-site .fxs-meter { display: flex; align-items: center; gap: 10px; padding: 9px 4px; }
.fxs-site .fxs-meter__label { font-size: 13px; color: var(--body); width: 96px; }
.fxs-site .fxs-meter__val { font-size: 12.5px; color: var(--muted); width: 34px; text-align: right; }
.fxs-site .fxs-meter__track { flex: 1; height: 8px; border-radius: 99px; background: var(--sand); overflow: hidden; }
.fxs-site .fxs-meter__track i { display: block; height: 100%; background: #157a4a; border-radius: 99px; }
.fxs-site .fxs-meter__track.is-warn i { background: #e0a12a; }

/* edge bars */
.fxs-site .fxs-bars { display: flex; align-items: flex-end; gap: 8px; height: 132px; padding: 6px 4px 0; }
.fxs-site .fxs-bars i { flex: 1; background: var(--sand); border-radius: 5px 5px 0 0; }
.fxs-site .fxs-bars i.best { background: #157a4a; }
.fxs-site .fxs-bars i.worst { background: #c0453b; }
.fxs-site .fxs-grade {
  background: var(--sand); border-radius: 99px; padding: 3px 10px; font-size: 11.5px;
}

/* community */
.fxs-site .fxs-post {
  display: flex; align-items: center; gap: 11px;
  padding: 11px 4px; border-bottom: 1px solid var(--line);
}
.fxs-site .fxs-post:last-of-type { border-bottom: 0; }
.fxs-site .fxs-post b { font-size: 13.5px; color: var(--ink); display: block; }
.fxs-site .fxs-post > b:last-child { margin-left: auto; }
.fxs-site .fxs-avatar {
  width: 30px; height: 30px; border-radius: 50%; flex-shrink: 0;
  display: grid; place-items: center;
  background: var(--accent); color: #fff; font-size: 11px; font-weight: 700;
}
.fxs-site .fxs-verified { font-size: 11.5px; color: var(--accent); }



/* ── the dark band ───────────────────────────────────────────────────────── */
.fxs-site .fxs-sec--ink {
  background: #0B1220;
  color: #E7ECF4;
}
.fxs-site .fxs-sec--ink .fxs-h2 { color: #FFFFFF; }
.fxs-site .fxs-sec--ink .fxs-eyebrow { color: #7FB0FF; }
.fxs-site .fxs-sec--ink .fxs-sub {
  color: rgba(231, 236, 244, 0.72);
  /* The light-theme rule gives this a pale rule underneath, which on the dark
     ground read as a stray line floating between the copy and the figures. */
  border-bottom: 0;
  padding-bottom: 0;
}

.fxs-site .fxs-stats {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 20px;
  margin: 44px 0 52px;
}
.fxs-site .fxs-stats div { text-align: left; }
.fxs-site .fxs-stats b {
  display: block;
  font-size: clamp(30px, 4vw, 46px);
  font-weight: 800; letter-spacing: -0.03em; color: #fff;
}
.fxs-site .fxs-stats span { font-size: 13.5px; color: rgba(231, 236, 244, 0.66); }

.fxs-site .fxs-inkgrid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 18px;
}
.fxs-site .fxs-inkcard {
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid rgba(255, 255, 255, 0.10);
  border-radius: 16px;
  padding: 24px;
  text-align: left;
}
.fxs-site .fxs-inkcard h3 { margin: 0 0 10px; font-size: 18px; color: #fff; letter-spacing: -0.01em; }
.fxs-site .fxs-inkcard p { margin: 0; font-size: 15px; line-height: 1.6; color: rgba(231, 236, 244, 0.72); }

@media (max-width: 900px) {
  .fxs-site .fxs-row { grid-template-columns: 1fr; gap: 30px; padding: 44px 0; }
  .fxs-site .fxs-row--artleft .fxs-row__art { order: 0; }
  .fxs-site .fxs-stats { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .fxs-site .fxs-inkgrid { grid-template-columns: 1fr; }
}

/* ── learn section on the landing page ───────────────────────
   The library needs a place on the front page or nobody finds it.
   Two rows: the three clusters as a wide choice, then six actual
   guides underneath, because a category name persuades nobody and
   an article title does.
   ============================================================ */
.fxs-site .fxs-learn__groups {
  display: grid; gap: 1rem; margin-bottom: 1.6rem;
  /* Four topics, fixed columns rather than auto-fit. Auto-fit fitted three on a
     mid width screen and orphaned the fourth into its own row with a wide gap to
     its right. Four across, then a clean two by two, then stacked, so the row is
     always full and there is never a hole in the middle. */
  grid-template-columns: repeat(4, minmax(0, 1fr));
}
@media (max-width: 1040px) { .fxs-site .fxs-learn__groups { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 560px)  { .fxs-site .fxs-learn__groups { grid-template-columns: 1fr; } }
.fxs-site .fxs-learn__group {
  display: flex; flex-direction: column; gap: 0.35rem;
  padding: 1.3rem 1.4rem; text-decoration: none;
  background: var(--navy); border-radius: var(--r);
  transition: transform 140ms ease;
}
.fxs-site .fxs-learn__group:hover { transform: translateY(-2px); }
.fxs-site .fxs-learn__gt { font-size: 1.08rem; font-weight: 800; color: #fff; letter-spacing: -0.01em; }
.fxs-site .fxs-learn__gd { font-size: 0.9rem; line-height: 1.5; color: rgba(255,255,255,0.72); }
.fxs-site .fxs-learn__gn {
  margin-top: 0.35rem; font-size: 0.74rem; font-weight: 800;
  letter-spacing: 0.1em; text-transform: uppercase; color: rgba(255,255,255,0.5);
}

.fxs-site .fxs-learn__list {
  display: grid; gap: 1rem;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
}
.fxs-site .fxs-learn__item {
  display: flex; flex-direction: column; gap: 0.35rem;
  padding: 1.2rem 1.3rem; text-decoration: none;
  background: var(--white); border: 1px solid var(--line);
  border-radius: var(--r);
  transition: border-color 140ms ease, transform 140ms ease;
}
.fxs-site .fxs-learn__item:hover { border-color: var(--accent); transform: translateY(-2px); }
.fxs-site .fxs-learn__t {
  font-size: 1rem; font-weight: 700; line-height: 1.35;
  color: var(--ink); letter-spacing: -0.008em;
}
.fxs-site .fxs-learn__d { font-size: 0.88rem; line-height: 1.55; color: var(--body); }
.fxs-site .fxs-learn__m {
  margin-top: 0.2rem; font-size: 0.73rem; font-weight: 800;
  letter-spacing: 0.09em; text-transform: uppercase; color: var(--muted);
}
.fxs-site .fxs-learn__more { margin: 1.8rem 0 0; text-align: center; }

@media (prefers-reduced-motion: reduce) {
  .fxs-site .fxs-learn__group,
  .fxs-site .fxs-learn__item { transition: none; }
  .fxs-site .fxs-learn__group:hover,
  .fxs-site .fxs-learn__item:hover { transform: none; }
}

/* ── the journal, three ways ─────────────────────────────────────────────────
   A column of tall media on the left and a rail on the right that pins while
   they scroll past. Whichever panel is in view lights up its entry in the list.

   The rail is position: sticky, not a scroll handler moving things around, so
   the browser does the work and the page still scrolls at its own speed. */
/* The band of colour sits behind these three panels and stops with them.

   It is a pseudo element rather than a background on a section because the
   journal block has siblings above and below it inside the same wrap, so
   colouring any real ancestor would colour them too. This paints only the
   height of the journal block and full viewport width, and the colour ends
   exactly where the third panel does. */
.fxs-site .fxs-jsync::before {
  content: "";
  position: absolute;
  top: 0; bottom: 0; left: 50%;
  width: 100vw;
  transform: translateX(-50%);
  background: var(--fxs-journal-band);
  z-index: -1;
}

.fxs-site .fxs-jsync {
  position: relative;
  padding: 72px 0;

  /* Wider than the 1120 wrap it sits in. At full height a panel held to the
     normal column comes out portrait, and a landscape recording dropped into a
     portrait box either letterboxes or gets cropped.

     Done with margins rather than a transform on purpose: a transformed
     ancestor becomes the containing block for its descendants, which stops
     position: sticky on the rail from behaving the way it should. */
  /* Equal negative margins on both sides. The wrap this sits in is already
     centred, so pulling the same amount off each edge keeps it centred without
     any arithmetic that has to be exactly right. That matters because 100vw
     includes the scrollbar and the content box does not, so a width worked out
     from vw lands a few pixels off centre. Here vw only decides how far to
     break out, and being slightly out there is invisible. */
  margin-inline: calc(-1 * clamp(0px, (100vw - 1120px) / 2 - 20px, 260px));

  display: grid;
  /* The media column takes the larger share because a near full height panel
     that is also narrow ends up portrait, and anything anyone drops into it
     will be a landscape recording. The rail only needs room for a heading, a
     short list and a button. */
  grid-template-columns: minmax(0, 1.85fr) minmax(0, 0.7fr);
  gap: 40px;
  align-items: start;
  margin-top: 72px;
}
.fxs-site .fxs-jsync__media { display: flex; flex-direction: column; gap: 36px; }

/* Each panel is a touch shorter than the viewport so one is always the clear
   candidate for "in view", which is what keeps the rail from flickering
   between two entries at the boundary. */
.fxs-site .fxs-jsync__panel { margin: 0; }
/* Each panel is close to a screenful, so scrolling through one takes about the
   same effort as reading a page. That is the whole effect: three screens that
   happen to share a rail.

   Sized off the viewport rather than a fixed number, and clamped at both ends.
   The lower bound keeps it usable on a short laptop screen; the upper bound
   stops it turning into an enormous empty box on a tall monitor. The 132px
   taken off is the sticky nav plus a little air, so a panel never sits under
   the header or runs past the fold. dvh first, because mobile browsers change
   the visible height as the address bar hides and vh does not follow it. */
.fxs-site .fxs-jsync__frame {
  /* The frame carries the shape of the recordings, 1280x736, so the video
     fills it corner to corner with nothing cropped and no bars. Height follows
     from the column width rather than being set, which is what keeps the whole
     recording visible: the earlier fixed height made the box far squarer than
     the footage and would have cut the sides off.

     max-height is only a backstop for a very short window, where the ratio
     gives way rather than letting a panel run past the fold. object-fit is
     contain underneath, so even then nothing is lost. */
  width: 100%;
  aspect-ratio: 1280 / 736;
  max-height: calc(100vh - 132px);
  max-height: calc(100dvh - 132px);
  border-radius: 16px;
  overflow: hidden;
  background: var(--white);
  border: 1px solid var(--line);
  box-shadow: 0 24px 60px -38px rgba(14, 27, 42, 0.42);
  display: grid; place-items: center;
}
/* contain, not cover. These are full screen recordings and cover would crop
   the edges off to fill the box. Any leftover space is white, which is the
   colour the recordings sit on anyway, so it does not read as a letterbox. */
.fxs-site .fxs-jsync__frame > video,
.fxs-site .fxs-jsync__frame > img {
  width: 100%; height: 100%; object-fit: contain; display: block;
  background: var(--white);
}
/* Each recording wipes into view (bottom-up) the first time its panel scrolls
   in — the jsync driver in LandingPage.jsx adds/removes .is-clip. The round
   keeps the frame's 16px corners during the wipe. JS off / reduced motion → the
   video is simply shown. */
.fxs-site .fxs-jsync__frame {
  clip-path: inset(0 0 0 0 round 16px);
  transition: clip-path 760ms cubic-bezier(.22, 1, .36, 1), opacity 520ms ease;
}
.fxs-site .fxs-jsync__frame.is-clip { clip-path: inset(100% 0 0 0 round 16px); opacity: 0; }
@media (prefers-reduced-motion: reduce) {
  .fxs-site .fxs-jsync__frame { transition: none; }
  .fxs-site .fxs-jsync__frame.is-clip { clip-path: inset(0 0 0 0 round 16px); opacity: 1; }
}

/* ── Journal: pinned sticky-scroll (desktop) ─────────────────────────────────
   The driver in LandingPage.jsx adds .is-pinned on wide screens; without it (JS
   off, or a narrow screen) the stage is transparent to layout and the panels
   stay stacked. Pinned: the media column is a tall scroll TRACK, the stage
   sticks in place, and the three recordings overlap inside it so scrolling
   cycles them without the media moving. Tune the 300vh (total pin length) and
   the 96px top (where it locks) if the timing needs it. */
.fxs-site .fxs-jsync__stage { display: contents; }
.fxs-site .fxs-jsync.is-pinned .fxs-jsync__media { display: block; position: relative; height: 300vh; }
.fxs-site .fxs-jsync.is-pinned .fxs-jsync__stage {
  display: grid; place-items: center;
  position: sticky; top: 96px; height: calc(100dvh - 128px);
}
.fxs-site .fxs-jsync.is-pinned .fxs-jsync__panel {
  position: absolute; inset: 0; margin: 0;
  display: grid; place-items: center;
  opacity: 0; z-index: 1;
  transition: opacity .55s ease;
}
.fxs-site .fxs-jsync.is-pinned .fxs-jsync__panel.is-active { opacity: 1; z-index: 2; }
.fxs-site .fxs-jsync.is-pinned .fxs-jsync__rail { top: 96px; }

/* On phones the two-column split (wide media + narrow rail) crushes the rail so
   its text clips. Stack it: the recording on top, the heading/list/button in a
   full-width column beneath, with the rail no longer sticky. */
@media (max-width: 900px) {
  .fxs-site .fxs-jsync {
    /* minmax(0, 1fr), not 1fr: a bare 1fr track cannot shrink below the media's
       intrinsic width, so the whole column blew out to ~875px and the rail text
       clipped off the right. minmax(0,...) lets it shrink to the viewport. */
    grid-template-columns: minmax(0, 1fr);
    margin-inline: 0;
    gap: 26px; margin-top: 40px; padding: 48px 0;
  }
  /* min-width:0 down the whole chain. A flex/grid item that contains a 1280px
     video gets min-width:auto = the video's intrinsic width, so the panel blew
     out to ~875px, the frame's ratio box followed it, and the recording sat in a
     tall white letterbox. Forcing min-width:0 (and width:100%) lets every level
     shrink to the phone width. Community band panels get the same treatment. */
  .fxs-site .fxs-jsync__media,
  .fxs-site .fxs-jsync__rail,
  .fxs-site .fxs-jsync__panel,
  .fxs-site .fxs-cband__panel,
  .fxs-site .fxs-cframe,
  .fxs-site .fxs-jsync__frame { min-width: 0; max-width: 100%; }
  .fxs-site .fxs-jsync__media > *,
  .fxs-site .fxs-jsync__panel { width: 100%; }
  .fxs-site .fxs-jsync__rail {
    position: static; height: auto; display: block;
  }
  /* The frame becomes a clean 16:9-ish ratio box (padding-bottom 736/1280 = 57.5%
     of its own now-correct width) with the video pinned to COVER it on a dark
     ground — no white bezel top or bottom. Shared by the community band. */
  .fxs-site .fxs-jsync__frame {
    display: block; position: relative; width: 100%;
    /* height:auto (not 0) with padding-bottom: this is a border-box element and
       the video child is absolute, so the box height = the 57.5% padding alone. */
    height: auto; padding-bottom: 57.5%;
    aspect-ratio: auto; min-height: 0; max-height: none;
    background: #0b1017;
  }
  .fxs-site .fxs-jsync__frame > video,
  .fxs-site .fxs-jsync__frame > img {
    position: absolute; inset: 0;
    width: 100%; height: 100%;
    object-fit: cover; background: #0b1017;
  }
}

/* The placeholder. Deliberately plain, and it says what belongs there so an
   empty slot never looks like a broken image. */
/* Fills the frame rather than sitting in the middle of it, so the slot reads
   as the whole area a video will occupy. */
.fxs-site .fxs-jsync__ph {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 6px;
  width: calc(100% - 36px); height: calc(100% - 36px);
  font-size: 15px; font-weight: 700; color: var(--muted);
  border: 1px dashed var(--line-2); border-radius: 12px;
  text-align: center;
}
.fxs-site .fxs-jsync__ph em {
  font-style: normal; font-size: 12.5px; font-weight: 600;
  letter-spacing: 0.06em; text-transform: uppercase; opacity: 0.72;
}

.fxs-site .fxs-jsync__rail {
  position: sticky; top: 0;
  height: 100vh; height: 100dvh;
  display: flex; align-items: center;
}
.fxs-site .fxs-jsync__railin { width: 100%; }
.fxs-site .fxs-jsync__rail h3 { margin: 0 0 26px; }

.fxs-site .fxs-jsync__list {
  list-style: none; margin: 0 0 28px; padding: 0;
  display: flex; flex-direction: column; gap: 6px;
}
.fxs-site .fxs-jsync__list li {
  padding: 16px 18px; border-radius: 12px;
  background: transparent; border: 1px solid transparent;
  transition: background 200ms ease, border-color 200ms ease;
}
.fxs-site .fxs-jsync__list b {
  display: block; font-size: 16.5px; font-weight: 700; color: var(--muted);
  transition: color 200ms ease;
}
/* The description only exists for the active one. Collapsing the height rather
   than hiding it keeps the rail from jumping as the active entry changes. */
.fxs-site .fxs-jsync__list span {
  display: block; overflow: hidden;
  max-height: 0; opacity: 0;
  font-size: 14.5px; line-height: 1.6; color: var(--body);
  transition: max-height 260ms ease, opacity 200ms ease, margin-top 260ms ease;
}
.fxs-site .fxs-jsync__list li.is-on {
  background: var(--sand); border-color: var(--line);
}
.fxs-site .fxs-jsync__list li.is-on b { color: var(--ink); }
.fxs-site .fxs-jsync__list li.is-on span {
  max-height: 120px; opacity: 1; margin-top: 6px;
}

@media (max-width: 900px) {
  /* No room for two columns, so the rail goes on top and stops pinning. Each
     description is shown, because with nothing to sync to there is no active
     one and a list of three bare labels says nothing. */
  .fxs-site .fxs-jsync { grid-template-columns: 1fr; gap: 32px; margin-top: 48px;
    margin-inline: 0; }
  .fxs-site .fxs-jsync__rail { position: static; order: -1; height: auto; display: block; }
  /* The frame follows the recording's own 16:9-ish shape (padding-bottom ratio
     box) instead of a fixed tall height, so a landscape clip fills it with no
     white letterbox. The absolute/cover video comes from the block above. */
  .fxs-site .fxs-jsync__frame { height: auto; padding-bottom: 57.5%; max-height: none; min-height: 0; aspect-ratio: auto; }
  .fxs-site .fxs-jsync__media { gap: 28px; }
  .fxs-site .fxs-jsync__list li { background: var(--sand); border-color: var(--line); }
  .fxs-site .fxs-jsync__list b { color: var(--ink); }
  /* li in the selector so this outranks the .is-on rule above rather than
     merely coming after it. Same specificity relying on source order was not
     winning here, and on a stacked layout there is no active entry to sync to,
     so every description has to be readable. */
  .fxs-site .fxs-jsync__list li span,
  .fxs-site .fxs-jsync__list li.is-on span { max-height: 200px; opacity: 1; margin-top: 6px; }
}
@media (prefers-reduced-motion: reduce) {
  .fxs-site .fxs-jsync__list li,
  .fxs-site .fxs-jsync__list b,
  .fxs-site .fxs-jsync__list span { transition: none; }
}

/* The band above is 100vw wide. Where the scrollbar is not an overlay, 100vw is
   wider than the content box and would add a sideways scrollbar. clip stops
   that. It has to be clip and not hidden: hidden makes a scroll container and
   would stop the rail inside from sticking, whereas clip does not. */
/* Both bands are 100vw wide, and #features holds them both. */
.fxs-site .fxs-sec#features {overflow-x: clip; }

/* ── community ───────────────────────────────────────────────────────────────
   Same treatment as the journal band: a full width wash that starts and stops
   with this block, done as a pseudo element because the block has siblings
   inside the same wrap and colouring a real ancestor would colour them too.

   The frame borrows .fxs-jsync__frame for its shape and shadow, so a recording
   exported at the same size as the journal ones drops in without another rule
   being written. Everything below is only what differs: this one is a single
   centred panel rather than a column of three. */
.fxs-site .fxs-cband {
  position: relative;
  padding: 96px 0;
  margin-inline: calc(-1 * clamp(0px, (100vw - 1120px) / 2 - 20px, 260px));
}
.fxs-site .fxs-cband::before {
  content: "";
  position: absolute;
  top: 0; bottom: 0; left: 50%;
  width: 100vw;
  transform: translateX(-50%);
  background: var(--fxs-community-band);
  z-index: -1;
}

/* The copy sits above the frame and stays on the narrow measure the rest of
   the page uses, so the band gets wider without the sentences getting longer. */
.fxs-site .fxs-cband__head {
  max-width: 620px;
  margin: 0 auto 44px;
  text-align: center;
}
.fxs-site .fxs-cband__head h3 { margin: 8px 0 14px; }
.fxs-site .fxs-cband__head p { margin: 0 auto 22px; max-width: 56ch; }

.fxs-site .fxs-cband__panel { margin: 0; }
/* Wider than the journal panels because there is no rail beside it, capped so
   it does not sprawl on a very large screen. */
.fxs-site .fxs-cframe {
  max-width: 1180px;
  margin: 0 auto;
}

@media (max-width: 900px) {
  .fxs-site .fxs-cband { padding: 56px 0; margin-inline: 0; }
  .fxs-site .fxs-cband__head { margin-bottom: 28px; }
}

@media (max-width: 900px) {
  /* Stacked, there is no row for the middle card to stand above, so the podium
     comes off and the tag goes back into the flow. */
  .fxs-site .fxs-plan--best { margin-top: 0; padding-top: 28px; }
  .fxs-site .fxs-plan--best .fxs-plan__tag { position: static; margin-bottom: 10px; }
}

/* ── Funded Run palette experiment ──────────────────────────────────────────
   Blends the white hero into a deepening blue band across the feature panels,
   down to the darkest at the data section. The journal/community band vars are
   set transparent (see :root) so this gradient shows through them, giving one
   continuous blend with no hard edges between panels. Revert by restoring the
   two band vars above and deleting this block. */
.fxs-site .fxs-sec#features {background: linear-gradient(180deg, #ffffff 0%, #eaf1f8 12%, #88a5c2 100%); }
.fxs-site .fxs-sec#data { background: linear-gradient(180deg, #88a5c2 0%, #6b8aac 100%); }

/* ── Funded Run palette: recolour the below-gradient accents to match ────────
   The section backgrounds themselves are left alone. Only the accents change:
   the beige comparison-table cells become the lightest blue; the dark "learn"
   topic cards become plain white like the guide cards below them; and the
   landing's closing band (#closecta only, so feature pages keep their navy)
   becomes the second-lightest blue with dark text. Revert with this block. */
.fxs-site .fxs-table thead th { background: #eaf1f8; }
.fxs-site .fxs-table__group td { background: #eaf1f8; }

.fxs-site .fxs-learn__group { background: var(--white); border: 1px solid var(--line); }
.fxs-site .fxs-learn__group:hover { border-color: var(--accent); }
.fxs-site .fxs-learn__gt { color: var(--ink); }
.fxs-site .fxs-learn__gd { color: var(--body); }
.fxs-site .fxs-learn__gn { color: var(--muted); }

.fxs-site .fxs-sec#closecta { background: #cfdfec; border-block-color: #b9cee0; }
.fxs-site .fxs-sec#closecta h2 { color: var(--ink); }
.fxs-site .fxs-sec#closecta p { color: var(--body); }
.fxs-site .fxs-sec#closecta .fxs-btn--onnavy { background: var(--ink); color: #fff; }
.fxs-site .fxs-sec#closecta .fxs-btn--onnavy:hover { background: #0a1420; color: #fff; }

/* ── Button hover states — stable, crisp text without fading away ──────────── */
.fxs-site .fxs-btn, .fxs-site .fr-promo__btn { overflow: hidden; }
.fxs-site .fxs-slide { position: relative; display: inline-flex; align-items: center; }
.fxs-site .fxs-slide__a { display: inline-flex; align-items: center; gap: .45em; white-space: nowrap; }
.fxs-site .fxs-slide__b { display: none !important; }

/* ── Static page reveals — immediately visible without scroll-fade lag ─────── */
.fxs-site .fx-rvl { opacity: 1 !important; transform: none !important; transition: none !important; }
.fxs-site .fx-rvl--in { opacity: 1 !important; transform: none !important; }

/* The blinds/curtain scroll-transition covers were removed — the landing keeps
   only text effects (hero SplitText, per-word ScrambleText on the first two
   panels) and the button animations. See landingShutter.js. */

/* ── custom painted cursor: DISABLED ─────────────────────────────────────────
   The static pages used to hide the native cursor and paint a dot-and-ring in
   its place (driven by /forgex-site/js/cursor.js). That is turned off now:
   every page shows the visitor's own default cursor. cursor.js is a no-op and
   never adds the `fx-jscursor` class, so the native cursor is never hidden. The
   rule that set `cursor: none` has been removed; the painted .fxc-ring/.fxc-dot
   elements below are no longer created and the styles are kept only as dead
   code. The React app's FxCursor is likewise disabled (see main.jsx). */

.fxc-ring, .fxc-dot {
  position: fixed;
  top: 0;
  left: 0;
  pointer-events: none;
  z-index: 2147483000;
  mix-blend-mode: difference;
  will-change: transform;
  opacity: 0;
  transition: opacity 0.05s ease;
}
.fxc-dot svg { display: block; transition: transform 0.1s ease; transform-origin: center; }
.fxc-ring.is-down svg, .fxc-dot.is-down svg { transform: scale(0.7); }
.fxc-ring {
  box-sizing: border-box;
  transition: opacity 0.05s ease, width 0.1s cubic-bezier(.25, .25, .42, 1), height 0.1s cubic-bezier(.25, .25, .42, 1), border-radius 0.1s cubic-bezier(.25, .25, .42, 1);
}
.fxc-ring::after {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  border-radius: inherit;
  border: 1.5px solid #f7f8fa;
  box-sizing: border-box;
  transition: transform 0.1s ease;
}
.fxc-ring.is-down::after {
  transform: scale(0.9);
}

/* ── Trader Journey carousel ───────────────────────────────────────────────
   Five slides on the landing page, the second of which is the walkthrough
   video. Built as a horizontal scroll-snap strip so it works with no JS;
   journeyCarousel.js adds the arrows, dots, keyboard and video play/pause.
   Light theme, same tokens as the rest of the public site. */
/* ── Trader Journey (plain video + text) ──────────────────────────────────
   Replaces the old .fxj carousel. A static two-column grid that mirrors the
   journal section's shape: a large recording on the left in a 16px rounded
   frame (its own aspect ratio, object-fit: contain so nothing is ever cropped)
   and a short explanation + button on the right. No sticky scroll, no JS.
   Stacks to one column on phones with the text above the video. */
.fxs-site .fxjv {
  display: grid;
  grid-template-columns: minmax(0, 1.85fr) minmax(0, 0.8fr);
  gap: 40px;
  align-items: center;
  margin: 72px 0;
  /* Break out wider than the 1120 wrap, exactly like .fxs-jsync, so the
     landscape recording has room and never comes out squashed. */
  margin-inline: calc(-1 * clamp(0px, (100vw - 1120px) / 2 - 20px, 260px));
}
.fxs-site .fxjv__media { min-width: 0; }
.fxs-site .fxjv__frame {
  width: 100%;
  aspect-ratio: 1872 / 1080;            /* the recording's own ratio — no letterbox */
  max-height: calc(100vh - 132px);
  max-height: calc(100dvh - 132px);
  border-radius: 16px;
  overflow: hidden;
  background: var(--white);
  border: 1px solid var(--line);
  box-shadow: 0 24px 60px -38px rgba(14, 27, 42, 0.42);
  display: grid; place-items: center;
}
.fxs-site .fxjv__frame > video {
  width: 100%; height: 100%; object-fit: contain; display: block; background: var(--white);
}
.fxs-site .fxjv__rail { min-width: 0; }
.fxs-site .fxjv__rail h3 { margin: 10px 0 14px; }
.fxs-site .fxjv__rail > p {
  margin: 0 0 24px; font-size: 16px; line-height: 1.6; color: var(--body); max-width: 420px;
}
@media (max-width: 900px) {
  .fxs-site .fxjv {
    grid-template-columns: 1fr;
    gap: 26px;
    margin: 48px 0;
    margin-inline: 0;                   /* no break-out on phones */
  }
  .fxs-site .fxjv__rail { order: -1; }  /* text sits above the video on phones */
  .fxs-site .fxjv__frame {
    aspect-ratio: 1872 / 1080;
    max-height: none;
  }
  .fxs-site .fxjv__rail > p { max-width: none; }
}

.fxs-site .fxj { padding: 8px 0 4px; }
.fxs-site .fxj__head { max-width: 720px; margin: 0 0 26px; text-align: left; }
.fxs-site .fxj__head h3 {
  margin: 8px 0 12px;
  font-size: clamp(24px, 2.4vw, 32px); line-height: 1.12;
  letter-spacing: -0.022em; color: var(--ink);
}
.fxs-site .fxj__head p { margin: 0; font-size: 16px; line-height: 1.6; color: var(--body); max-width: 640px; }

/* The scrolling strip. scroll-snap keeps each slide aligned; the gradient masks
   hint that more slides sit off each edge. */
.fxs-site .fxj__viewport {
  overflow-x: auto;
  overflow-y: hidden;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;             /* the dots are the indicator */
  outline: none;
  border-radius: 16px;
}
.fxs-site .fxj__viewport::-webkit-scrollbar { display: none; }
.fxs-site .fxj__viewport:focus-visible { box-shadow: 0 0 0 3px rgba(11, 79, 212, 0.35); }

.fxs-site .fxj__track {
  display: flex;
  gap: 20px;
  list-style: none;
  margin: 0;
  padding: 6px 2px 10px;
}
.fxs-site .fxj__slide {
  scroll-snap-align: start;
  flex: 0 0 100%;
  min-width: 0;
}

/* Each non-video slide is a card: copy on the left, a big step number + line
   icon on the right, on paper with the same soft lift as .fxs-video. */
.fxs-site .fxj__card {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr);
  gap: 28px;
  align-items: center;
  min-height: 300px;
  padding: 36px 40px;
  background: var(--white);
  border: 1px solid var(--line);
  border-radius: 16px;
  box-shadow:
    0 1px 0 rgba(255, 255, 255, 0.9) inset,
    0 18px 50px -28px rgba(14, 27, 42, 0.26),
    0 0 70px -20px rgba(14, 27, 42, 0.10);
}
.fxs-site .fxj__kicker {
  display: inline-block;
  font-size: 12px; font-weight: 800; letter-spacing: 0.12em;
  text-transform: uppercase; color: var(--accent); margin-bottom: 12px;
}
.fxs-site .fxj__copy h4 {
  margin: 0 0 12px;
  font-size: clamp(21px, 2vw, 27px); line-height: 1.14;
  letter-spacing: -0.02em; color: var(--ink);
}
.fxs-site .fxj__copy p { margin: 0; font-size: 16px; line-height: 1.62; color: var(--body); }

.fxs-site .fxj__art {
  position: relative;
  align-self: stretch;
  display: grid; place-items: center;
  border-radius: 12px;
  background:
    radial-gradient(120% 120% at 70% 20%, rgba(11, 79, 212, 0.08), transparent 60%),
    var(--sand);
  color: var(--accent);
  overflow: hidden;
}
.fxs-site .fxj__art svg { width: 78px; height: 78px; opacity: 0.9; }
.fxs-site .fxj__num {
  position: absolute; top: 14px; right: 18px;
  font-size: 58px; font-weight: 800; letter-spacing: -0.03em;
  color: rgba(14, 27, 42, 0.07); line-height: 1;
}

/* The video slide. Dark window like .fxs-vidwin, 16:9, with a placeholder that
   covers it until the file actually loads. */
.fxs-site .fxj__card--video { padding: 14px; grid-template-columns: 1fr; }
.fxs-site .fxj__videowrap {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;
  border-radius: 10px;
  overflow: hidden;
  background: #0b1a2b;
}
.fxs-site .fxj__video {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  display: block;
  opacity: 0;
  transition: opacity .3s ease;
}
.fxs-site .fxj.is-video-ready .fxj__video { opacity: 1; }
.fxs-site .fxj__videoph {
  position: absolute; inset: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 10px;
  text-align: center; padding: 20px;
  color: #cdd8e6;
  background:
    radial-gradient(90% 90% at 50% 40%, rgba(11, 79, 212, 0.18), transparent 70%),
    #0b1a2b;
  transition: opacity .3s ease;
}
.fxs-site .fxj.is-video-ready .fxj__videoph { opacity: 0; pointer-events: none; }
.fxs-site .fxj__videoph-play {
  width: 60px; height: 60px; border-radius: 50%;
  display: grid; place-items: center;
  background: #fff; color: var(--ink);
  box-shadow: 0 6px 22px -8px rgba(0, 0, 0, 0.5);
}
.fxs-site .fxj__videoph-label { font-size: 16px; font-weight: 700; color: #fff; }
.fxs-site .fxj__videoph-note { font-size: 13px; color: #94a6bb; }

/* Controls: arrows flank a row of dots. */
.fxs-site .fxj__controls {
  display: flex; align-items: center; justify-content: center; gap: 18px;
  margin-top: 22px;
}
.fxs-site .fxj__arrow {
  width: 44px; height: 44px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--white); color: var(--ink);
  border: 1px solid var(--line-2);
  cursor: pointer;
  transition: background .15s, border-color .15s, transform .15s, opacity .15s;
}
.fxs-site .fxj__arrow:hover:not(:disabled) { background: var(--ink); color: #fff; border-color: var(--ink); }
.fxs-site .fxj__arrow:disabled { opacity: 0.35; cursor: default; }
.fxs-site .fxj__dots { display: flex; align-items: center; gap: 10px; }
.fxs-site .fxj__dot {
  width: 9px; height: 9px; padding: 0; border-radius: 50%;
  background: var(--line-2); border: 0; cursor: pointer;
  transition: background .15s, transform .15s, width .15s;
}
.fxs-site .fxj__dot:hover { background: var(--muted); }
.fxs-site .fxj__dot.is-on { background: var(--accent); width: 24px; border-radius: 6px; }
.fxs-site .fxj__cta { margin-top: 24px; }

@media (max-width: 760px) {
  .fxs-site .fxj__card { grid-template-columns: 1fr; gap: 20px; padding: 26px 22px; min-height: 0; }
  .fxs-site .fxj__art { min-height: 150px; }
  .fxs-site .fxj__num { font-size: 44px; }
}

/* ============================================================
   Mobile & Tablet Performance, Smoothness & Ergonomics Overhaul
   ============================================================ */

/* 1. Rendering Optimization: content-visibility on below-the-fold sections */
@media (max-width: 1024px) {
  .fxs-site .fxs-sec:not(.fxs-hero),
  .fxs-site .fr-promo-band,
  .fxs-site .fxjv,
  .fxs-site .fxs-jsync,
  .fxs-site .fxs-deck,
  .fxs-site .fxs-cband,
  .fxs-site .fxs-show,
  .fxs-site .fxs-foot {
    content-visibility: auto;
    contain-intrinsic-size: 1px 700px;
  }
  .fxs-site .fxs-hero {
    content-visibility: visible;
  }
}

/* 2. Touch Ergonomics & Scalable Typography (Phones & Small Tablets) */
@media (max-width: 768px) {
  /* Minimum 44x44px touch targets */
  .fxs-site .fxs-btn {
    min-height: 48px;
    padding: 12px 24px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }
  .fxs-site .fxs-btn--sm {
    min-height: 44px;
    padding: 10px 18px;
    font-size: 15px;
  }
  .fxs-site .fr-promo__btn {
    min-height: 48px;
    padding: 12px 28px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }
  .fxs-site .fxs-nav__right .fxs-btn {
    min-height: 40px;
    padding: 8px 16px;
  }

  /* Full-width thumb-friendly hero CTAs */
  .fxs-site .fxs-hero__cta {
    display: flex;
    flex-direction: column;
    gap: 12px;
    width: 100%;
    max-width: 360px;
    margin: 28px auto 0;
  }
  .fxs-site .fxs-hero__cta .fxs-btn {
    width: 100%;
    justify-content: center;
  }

  /* Scalable typography with comfortable line height */
  .fxs-site {
    font-size: 16px;
    line-height: 1.55;
  }
  .fxs-site .fxs-hero__sub,
  .fxs-site .fxs-sub,
  .fxs-site .fxs-lede,
  .fxs-site p {
    font-size: 16px;
    line-height: 1.55;
  }
  .fxs-site .fxs-hero__h1 {
    font-size: clamp(2.4rem, 9vw, 3.4rem);
    line-height: 1.06;
  }

  /* Simplify heavy multi-layer box shadows to reduce mobile GPU composite overhead */
  .fxs-site .fxs-plan,
  .fxs-site .fxs-card,
  .fxs-site .fxs-deck__card,
  .fxs-site .fxs-inkcard {
    box-shadow: 0 4px 16px rgba(14, 27, 42, 0.08) !important;
  }
  .fxs-site .fr-promo__btn {
    box-shadow: 0 4px 16px rgba(10, 14, 20, 0.22) !important;
  }

  /* Graceful single-column reflow for data and step sections */
  .fxs-site .fxs-stats {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 16px;
  }
  .fxs-site .fxs-inkgrid {
    display: grid;
    grid-template-columns: 1fr;
    gap: 16px;
  }
  .fxs-site .fxs-steps {
    display: grid;
    grid-template-columns: 1fr;
    gap: 20px;
  }

  /* Feature table responsive scrolling */
  .fxs-site .fxs-tablewrap {
    -webkit-overflow-scrolling: touch;
    overscroll-behavior-x: contain;
  }

  /* Video frames padding and borders */
  .fxs-site .fr-promo__video,
  .fxs-site .fxjv__frame,
  .fxs-site .fxs-jsync__frame,
  .fxs-site .fxs-cframe {
    border-radius: 10px;
    overflow: hidden;
  }
}

