/**
 * @file
 * css/components/save-pay-file.css
 *
 * Light "Save / Pay / File" sticky scroll sequence.
 *
 * Mobile-first LINEAR by default: every step reflows into a vertical list
 * (eyebrow, heading, description, button, then the media). The sticky-scrub
 * engine only activates at >=992px with prefers-reduced-motion: no-preference
 * AND when JS has set data-spf-engine="on" on the runway — so mobile, no-JS and
 * reduced-motion all share the same safe linear fallback.
 *
 * Brand tokens are locked (navy / green / inks / light wash). The primary CTA is
 * navy with white text (~11.6:1) because white on the brand green (#3CB944) only
 * reaches ~2.2:1 and would fail WCAG AA. Green is used for accents and the
 * :focus-visible ring.
 */

@font-face {
  font-family: 'Manrope';
  src: url('../../fonts/Manrope-VariableFont_wght.woff2?v=2') format('woff2-variations');
  font-weight: 200 800;
  font-style: normal;
  font-display: swap;
}

/* ============================================================
   THEME STICKY UNLOCK (critical)

   Scoped by delivery: this stylesheet only loads via attach_library on pages
   that actually render the section, so the override below never touches other
   pages.

   The techprosolutions base theme clips the entire page with
   `.boxed_wrapper { overflow: hidden !important }` (css/style.css:117, reinforced
   by css/responsive.css). `.boxed_wrapper` is the outermost page wrapper, and any
   ancestor whose overflow is not `visible`/`clip` becomes a scroll container that
   silently disables `position: sticky` for everything inside it — which is why the
   stage never pinned.

   Restore sticky WITHOUT re-introducing horizontal page scroll: switch the clip
   axis to `overflow-x: clip` — it clips like `hidden` but, unlike `hidden`, does
   NOT establish a scroll container, so sticky keeps working — and free the block
   axis with `overflow-y: visible`. Because `clip` is neither `scroll` nor `auto`,
   the paired `visible` is not coerced to `auto` (CSS Overflow 3).

   `html body .boxed_wrapper` (specificity 0,1,2) + !important beats the base
   `.boxed_wrapper` (0,1,0 !important) regardless of stylesheet load order. The
   inner wrappers carry no overflow today and are included only as a safety net.
   ============================================================ */
html body .boxed_wrapper,
html body #main-wrapper,
html body .site-wrapper-reveal,
html body .layout-content {
  overflow-x: clip !important;
  overflow-y: visible !important;
}

.save-pay-file {
  --spf-navy: #1c3557;
  --spf-navy-hover: #142844;
  --spf-green: #3cb944;
  --spf-green-2: #167a5b;
  --spf-ink: #0a0a0a;
  --spf-body: #45464f;
  --spf-muted: #5b6470;
  --spf-wash: #e8f5e9;
  --spf-white: #ffffff;
  --spf-hairline: rgba(28, 53, 87, 0.10);
  --spf-frame-border: rgba(60, 185, 68, 0.18);
  --spf-radius-lg: 16px;
  --spf-radius-sm: 12px;
  --spf-pill: 9999px;
  --spf-shadow: 0 20px 40px rgba(28, 53, 87, 0.08);
  --spf-ease: cubic-bezier(0.16, 1, 0.3, 1);
  /* If a PERSISTENT fixed header is added later, set this to its height. The
     site's smart-header auto-hides on scroll-down (the scrub direction), so 0
     is correct today. */
  --spf-header-offset: 0px;

  position: relative;
  background-color: var(--spf-white);
  color: var(--spf-body);
  font-family: 'Manrope', -apple-system, 'Segoe UI', Roboto, sans-serif;
  /* This section carries no visible heading (the pinned stage centres its own
     content), so the shared 80–160px rhythm would leave a dead band at the top.
     Trim the section-local rhythm to a tighter 48px block — still on the 4px grid,
     and matches the mobile rhythm. */
  --et-section-pad-y: 3rem; /* 48px — section-local override of the global token */
  /* The features section directly above owns the upper boundary gap via its own
     bottom rhythm (--et-section-pad-y), so this section only needs a small top
     inset; a full 48px here would stack into a double gap now that the awards
     marquee (which used to fill that space) is gone. Bottom keeps the 48px rhythm
     into the testimonials section. Loaded only where this section renders. */
  padding: 1rem 0 var(--et-section-pad-y); /* 16px top / 48px bottom */
}

.save-pay-file *,
.save-pay-file *::before,
.save-pay-file *::after {
  box-sizing: border-box;
}

.spf-visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* ============================================================
   Section heading (optional; scrolls away before the stage pins)
   ============================================================ */
.spf-head {
  max-width: 1200px;
  margin: 0 auto;
  padding: 0 clamp(1.25rem, 5vw, 2rem);
}

/* Unified H2 token — identical to every other section title. */
.spf-section-title {
  margin: 0 0 var(--et-title-gap, 3rem);
  max-width: 22ch;
  font-family: 'Manrope', sans-serif; /* beats the base theme's h1-h6 Roboto rule */
  color: var(--et-heading-color, #0a0a0a);
  font-size: var(--et-h2-size);
  font-weight: var(--et-h2-weight, 800);
  line-height: var(--et-h2-lh, 1.15);
  letter-spacing: var(--et-h2-track, -0.02em);
}

/* ============================================================
   Macro layout — mobile-first LINEAR (no pinning)
   ============================================================ */
.spf-runway {
  position: relative;
}

.spf-stage {
  position: relative;
}

.spf-stage__inner {
  max-width: 1200px;
  margin: 0 auto;
  padding: 0 clamp(1.25rem, 5vw, 2rem);
}

/* Tabs are inert without the engine, so they stay hidden until it turns on. */
.spf-tabs {
  display: none;
  gap: clamp(1rem, 3vw, 1.75rem);
  margin-bottom: clamp(1.5rem, 4vw, 2.25rem);
  border-bottom: 1px solid var(--spf-hairline);
}

.spf-tab {
  position: relative;
  appearance: none;
  background: none;
  border: 0;
  padding: 0 0 0.75rem; /* 12px — 4px grid (was 0.65rem) */
  font-family: inherit;
  font-size: var(--et-body-size, 1rem); /* unified UI label (was 1.05rem) */
  font-weight: 700;
  line-height: 1;
  color: var(--spf-muted);
  cursor: pointer;
  min-height: 44px;
  transition: color 0.25s var(--spf-ease);
}

.spf-tab::after {
  content: '';
  position: absolute;
  left: 0;
  bottom: -1px;
  width: 100%;
  height: 2px;
  background-color: var(--spf-green);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 0.3s var(--spf-ease);
}

.spf-tab:hover {
  color: var(--spf-navy);
}

.spf-tab.is-active {
  color: var(--spf-navy);
}

.spf-tab.is-active::after {
  transform: scaleX(1);
}

/* ----- Panes (linear: a vertical stack of steps) ----- */
.spf-panes {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: clamp(2.5rem, 7vw, 3.5rem);
}

.spf-pane {
  display: flex;
  flex-direction: column;
  gap: clamp(1.25rem, 4vw, 1.75rem);
}

.spf-pane__text {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  min-width: 0;
}

.spf-eyebrow {
  margin: 0 0 0.75rem;
  font-size: var(--et-overline-size, 0.8125rem);
  font-weight: var(--et-overline-weight, 700);
  letter-spacing: var(--et-overline-track, 0.08em);
  text-transform: uppercase;
  color: var(--spf-green-2);
}

/* Pane headings ("Sign up & pick your year" …) read as section titles on the
   pinned full-screen panes, so they carry the SAME unified H2 scale (the tag
   stays <h3> for document outline; only the visual scale is unified). */
.spf-heading {
  margin: 0 0 1rem;
  font-family: 'Manrope', sans-serif; /* beats the base theme's h1-h6 Roboto rule */
  color: var(--et-heading-color, #0a0a0a);
  font-size: var(--et-h2-size);
  font-weight: var(--et-h2-weight, 800);
  line-height: var(--et-h2-lh, 1.15);
  letter-spacing: var(--et-h2-track, -0.02em);
}

.spf-desc {
  margin: 0 0 1.75rem;
  max-width: 46ch;
  color: var(--spf-body);
  font-size: var(--et-lead-size, 1.125rem);
  line-height: var(--et-body-lh, 1.6);
}

.spf-desc p {
  margin: 0 0 0.75rem;
}

.spf-desc p:last-child {
  margin-bottom: 0;
}

.spf-button {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  min-height: 44px;
  padding: 0.75rem 1.5rem; /* 12px 24px — 4px grid (was 0.85/1.6) */
  border-radius: var(--spf-pill);
  background-color: var(--spf-navy);
  color: var(--spf-white);
  font-weight: 700;
  font-size: 1rem;
  letter-spacing: var(--et-btn-track, 0.02em); /* bold button tracking law */
  line-height: 1;
  text-decoration: none;
  transition: background-color 0.25s var(--spf-ease), transform 0.25s var(--spf-ease);
}

.spf-button:hover {
  background-color: var(--spf-navy-hover);
}

.spf-button__arrow {
  flex: none;
  transition: transform 0.25s var(--spf-ease);
}

.spf-button:hover .spf-button__arrow {
  transform: translateX(4px); /* 4px grid (was 3px) */
}

/* Steps with no media upload render text-only (keeps the live section tidy
   while GIFs are still being produced). */
.spf-pane--no-media .spf-pane__text {
  max-width: 60ch;
}

/* ----- Media frame (the GIF/image stage) ----- */
.spf-pane__media {
  min-width: 0;
}

.spf-media-frame {
  position: relative;
  width: 100%;
  /* Match the authored media aspect (= the locked desktop 493x500 ratio) so the
     edge-to-edge `cover` fill below never crops meaningfully on mobile. */
  aspect-ratio: 493 / 500;
  display: block;
  /* No padding: the GIF fills the frame edge-to-edge (no white letterbox). */
  padding: 0;
  /* Fallback only — hidden under an opaque GIF; shows through transparency. */
  background: linear-gradient(135deg, var(--spf-wash) 0%, var(--spf-white) 72%);
  border-radius: var(--spf-radius-lg);
  box-shadow: var(--spf-shadow);
  overflow: hidden;
}

.spf-media-frame__img {
  width: 100%;
  height: 100%;
  /* Fill the box completely; crop slightly if the GIF aspect differs. */
  object-fit: cover;
  display: block;
  border-radius: inherit;
}

/* ----- Dual-layer media: Lottie background + transparent foreground image -----
   When a step carries a Lottie JSON (field_lottie_animation_json) it renders as
   the MOVING BACKGROUND layer; the static (transparent PNG) image stacks ON TOP
   of it as the foreground. Steps without a Lottie keep the single-image `cover`
   behaviour above — .spf-media-fg-image is only added alongside a Lottie. */

/* Layer 1: the Lottie background. */
.spf-media-lottie-bg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 1;
  pointer-events: none;
}

/* Layer 2: the transparent foreground image. */
.spf-media-frame__img.spf-media-fg-image {
  position: absolute;
  inset: 0;
  /* Contain (not cover): the foreground is a floating UI card whose transparent
     framing must stay intact — cropping it would clip the card edges. */
  object-fit: contain;
  z-index: 2;
  pointer-events: none;
}

/* ============================================================
   Focus visibility — locked brand ring on every interactive element
   ============================================================ */
.save-pay-file a:focus-visible,
.save-pay-file button:focus-visible {
  outline: 2px solid var(--spf-green);
  outline-offset: 2px;
  border-radius: 4px;
}

/* ============================================================
   DESKTOP + MOTION ENGINE
   Pins the stage and crossfades panes. Gated on JS (data-spf-engine="on") so the
   no-JS / mobile / reduced-motion fallback is the linear list above.
   ============================================================ */
@media (min-width: 992px) and (prefers-reduced-motion: no-preference) {
  /* The runway is the SCROLL RUNWAY for the pin: its height beyond the pinned
     stage is exactly the scroll distance over which the 3 steps cross-fade. It
     used to be `steps * 100vh`, which (a) made the section absurdly tall and (b)
     paired with a full-screen stage. We now hug the content, so the runway only
     needs a modest band per step. --spf-step-scroll is that band (kept in sync
     with the JS, which maps progress over `runwayHeight - stageHeight`). */
  .spf-runway[data-spf-engine='on'] {
    --spf-step-scroll: 62vh;
    min-height: calc(var(--spf-steps, 3) * var(--spf-step-scroll));
  }

  .spf-runway[data-spf-engine='on'] .spf-stage {
    position: sticky;
    top: var(--spf-header-offset, 0px);
    /* HUG THE CONTENT — no forced `height: 100vh`. A full-screen stage on desktop
       left a huge dead band above AND below the ~600px of content (centring only
       split it in two). The stage is now only as tall as its tallest step plus a
       small breathing block, so the pinned panel wraps its content tightly and
       the next section follows right after the (now much shorter) pin. */
    display: flex;
    flex-direction: column;
    justify-content: center;
    padding-block: clamp(1.5rem, 5vh, 3rem);
    overflow: hidden;
  }

  .spf-runway[data-spf-engine='on'] .spf-stage__inner {
    width: 100%;
  }

  .spf-runway[data-spf-engine='on'] .spf-tabs {
    display: flex;
  }

  /* The eyebrow is the mobile stand-in for the tabs; hide it on the engine. */
  .spf-runway[data-spf-engine='on'] .spf-eyebrow {
    display: none;
  }

  .spf-runway[data-spf-engine='on'] .spf-panes {
    display: block;
    min-height: clamp(380px, 60vh, 540px);
  }

  /* ------------------------------------------------------------------
     3-STATE SPATIAL ANIMATION ENGINE
     Each pane carries exactly one of is-upcoming / is-active / is-past
     (set per frame by setStep in js/components/save-pay-file.js). The
     symmetrical +40px / 0 / -40px translateY on the locked bezier makes
     the stack behave like a physical vertical carousel: scroll down and
     panes rise up through centre; scroll up and they drop back down.
     Text + media share the one pane, so they move together as intended.
     ------------------------------------------------------------------ */
  .spf-runway[data-spf-engine='on'] .spf-pane {
    position: absolute;
    inset: 0;
    display: grid;
    /* Left column flexes; right column is the locked 493px media stage. */
    grid-template-columns: minmax(0, 1fr) 493px;
    gap: clamp(2rem, 5vw, 4rem);
    align-items: center;
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transition:
      opacity 0.7s var(--spf-ease),
      transform 0.7s var(--spf-ease),
      visibility 0.7s var(--spf-ease);
  }

  /* 1. UPCOMING — waiting 40px below, scaled down, not reached yet. */
  .spf-runway[data-spf-engine='on'] .spf-pane.is-upcoming {
    opacity: 0;
    visibility: hidden;
    transform: translateY(40px) scale(0.96);
    pointer-events: none;
    z-index: 1;
  }

  /* 2. ACTIVE — centred, full size, interactive. */
  .spf-runway[data-spf-engine='on'] .spf-pane.is-active {
    opacity: 1;
    visibility: visible;
    transform: translateY(0) scale(1);
    pointer-events: auto;
    z-index: 2;
  }

  /* 3. PAST — exited 40px upward, scaled down, scrolled beyond. */
  .spf-runway[data-spf-engine='on'] .spf-pane.is-past {
    opacity: 0;
    visibility: hidden;
    transform: translateY(-40px) scale(0.96);
    pointer-events: none;
    z-index: 1;
  }

  /* Text-only step: single centred column instead of the split grid. */
  .spf-runway[data-spf-engine='on'] .spf-pane--no-media {
    grid-template-columns: minmax(0, 760px);
    justify-content: center;
  }

  /* Locked media stage: exactly 493 x 500. The grid reserves a 493px column, so
     width:100% resolves to 493px; height is fixed at 500px. Engine runs only at
     >=992px, where this fits inside the 1200px container with room to spare, so
     it never forces horizontal scroll. Mobile keeps the responsive aspect-ratio
     frame above. */
  .spf-runway[data-spf-engine='on'] .spf-media-frame {
    aspect-ratio: auto;
    width: 100%;
    max-width: 493px;
    height: 500px;
    margin-inline: auto;
  }
}

/* ============================================================
   Reduced motion — belt-and-braces (the engine never starts, but make sure no
   crossfade/transition motion survives if these rules are reached).
   ============================================================ */
@media (prefers-reduced-motion: reduce) {
  .spf-tab,
  .spf-tab::after,
  .spf-button,
  .spf-button__arrow,
  .spf-pane {
    transition: none;
  }
}
