/* ==========================================================================
   Grid & visual clean-up overrides
   The mirrored site keeps its original CSS untouched; these rules fix:
     1. Nav alignment to the same 50px/12px column grid as the page body
     2. Doubled borders (icon-25 bottom + nav_line, outer section borders)
     3. Outer left/right borders on full-width sections (buttons, footer,
        gridded content blocks, default-container variants, image_full)
     4. h1 right-alignment on tablet/mobile caused by align-items:flex-end
        surviving the grid→flex-column switch
     5. Button hover z-index so hovered card sits above its siblings
   ========================================================================== */


/* ── 1. NAV GRID ALIGNMENT (≥480px) ─────────────────────────────────────── */
/* Nav shares the body's 50px gutters and left-aligned flex layout. Threshold
   matches the native stylesheet's own tablet/mobile split (rules live in a
   max-width:991px block, with a separate max-width:479px block below that) --
   NOT an arbitrary 768px. Below 768 but at/above 480, this rule used to not
   apply at all, leaving the native max-width:991 rules unchallenged: logo-2
   becomes width:100% there with no matching justify-content override, so it
   renders shifted right of the true left edge instead of pinned to it (menu
   itself is legitimately display:none in this whole range — replaced by the
   hamburger's full-screen overlay — so hiding it isn't the bug, only the
   logo's own position was). */
@media screen and (min-width: 480px) {
  .section-2.is--nav {
    justify-content: flex-start;
    padding-left: 50px;
    padding-right: 50px;
  }

  /* Logo occupies exactly the first grid column (25% of inner width).
     Right divider lands on the first column line = same as hero-line-block 2. */
  .logo-2,
  .logo-2.w--current {
    width: 25%;
    justify-content: flex-start;
    padding-left: 0;
  }

  /* Hamburger sits in the right gutter. Width matches the gutter so its
     left divider lands on the last column line. */
  .section-2.is--nav .icon-25 {
    width: 50px;
  }
}

/* Menu fills the remaining three columns -- but only at genuine desktop
   widths (≥992px) where .top's horizontal links are actually visible
   (native CSS hides .top below that). Below 992px, .menu is also .full's
   containing block for the mobile overlay (.full is position:relative
   there, not a fixed full-viewport layer), so constraining it to 75% width
   left the overlay's grey backdrop covering only three-quarters of the
   screen with page content showing through the rest. */
@media screen and (min-width: 992px) {
  .section-2.is--nav .menu {
    width: 75%;
  }
}

/* ── 1b. /TOOLS "✦ /tools" BANNER ALIGNMENT (≥768px) ────────────────────── */
/* .support-banner-tools sits in a full-bleed nav (no 50px gutters, unlike
   .section-2.is--nav above) as a flex child alongside .menu, centred as a
   pair via justify-content:center. Its RIGHT edge should land on the same
   column line as the main nav logo's right border: 50px gutter + 25% of the
   remaining width. A margin-left can't reach that position without first
   pushing the pair's combined width past the container and wrapping the
   banner onto its own centred line (confirmed live: anywhere past ~165px
   margin at 1440px width, the banner snaps to a wrapped, wrongly-centred
   position). Pull it out of the flex flow instead — .support-nav.navtool
   is already position:fixed, so an absolutely-positioned child here is
   positioned purely by inset properties, independent of .menu's width.
   Anchor with `right` (not `left`) so the banner's right edge lands on
   the line regardless of the banner's own width: right offset = container
   width minus the target x-position = 100% - (50px + 25% of (100% - 100px))
   = 75% - 25px. */
@media screen and (min-width: 768px) {
  .support-banner-tools {
    position: absolute;
    margin-left: 0;
    left: auto;
    right: calc(75% - 25px);
  }
}

/* Match the "Tools" nav pill's brand gradient (app's --grad-sidebar) and
   flip the "✦ /tools" label to white so it reads against the darker
   blue/lime end of the gradient. */
.support-banner-tools {
  background-image: linear-gradient(168deg, #f8c0ff 0%, #cdebf4 52%, #eaffa8 110%);
}
.support-banner-tools .medium-uppercase-m {
  color: #000;
}


/* ── 1c. NAV VERTICAL LINES (≥768px) ─────────────────────────────────────
 * JS injects .rp-nav-lines-grid as the first child of .section-2.is--nav,
 * laid out on the same 4-column/50px-padding grid as the native
 * .hero-lines-grid so its lines land on the same x positions as the
 * homepage hero's. Only the outer edges (first-block's left, fourth-block's
 * right) get a border here — the middle column line at the 25% mark isn't
 * needed from this grid because the logo's own border-right (see NAV GRID
 * ALIGNMENT above) already draws it. Deliberately NOT drawing the 50%/75%
 * lines per feedback: only three vertical lines should show in the nav. */
@media screen and (min-width: 768px) {
  .rp-nav-lines-grid {
    z-index: 0;
    display: grid;
    grid-template-columns: 1fr 1fr 1fr 1fr;
    position: absolute;
    inset: 0;
    padding-left: 50px;
    padding-right: 50px;
    pointer-events: none;
  }
  .rp-nav-line-block.first-block {
    border-left: 0.5px solid var(--black);
  }
  .rp-nav-line-block.fourth-block {
    border-right: 0.5px solid var(--black);
  }
}


/* ── 2. REMOVE DOUBLED BORDER ON ICON-25 ────────────────────────────────── */
/* .nav_line already provides a full-width 0.5px bottom border for the nav.
   icon-25's own border-bottom creates a double 1px line at the nav foot
   between x=1390–1440. Remove it. The left border is correct and kept.
   z-index: 101 keeps icon-25 above .full (z-index:100) so the ✕ button
   remains clickable while the nav overlay is open. */
.icon-25 {
  border-bottom: none;
  z-index: 101;
}


/* ── 3. REMOVE OUTER LEFT/RIGHT BORDERS ON FULL-WIDTH SECTIONS ──────────── */
/* The buttons grid has border:0.5px on all 4 sides, meaning left/right
   borders land at x=0 and x=1440 (screen edges, outside the 50px gutters).
   The individual button-tops already carry the correct in-grid left/right
   borders at x≈50 and x≈1390. Remove the container's outer borders only. */
.three-big-buttons-grid {
  border-left-width: 0;
  border-right-width: 0;
}

/* hero-content has an erroneous border-right:0.5px solid at the screen edge
   when the hero is full-width (homepage and interior pages). In the halfed
   layout (tools page), hero-content only fills the left half (≈x=0–745) so
   its border-right is the correct column divider — leave it intact.
   Use :not(.halfed) to target only the full-width case. */
.hero-content-wrapper:not(.halfed) .hero-content {
  border-right-width: 0;
}

/* footer-block spans full width and has left/right borders at screen edges.
   The footer-lines-grid inside is correctly inset 50px on both sides. */
.footer-block {
  border-left-width: 0;
  border-right-width: 0;
}

/* .gridded-content and .gridded-content-left are full-width section grids
   (width:100%, padding-left/right:50px) used on about, services, and all
   4 project pages. The CSS sets border-style:solid; border-width:.5px which
   puts border-left at x=0 and border-right at the viewport right edge — both
   outside the 50px content gutters. The inner grid columns already carry the
   correct separators. Remove the outer left/right borders only. */
.gridded-content,
.gridded-content-left {
  border-left-width: 0;
  border-right-width: 0;
}

/* .image_full is the right-half image panel in the tools page hero. It sits
   inside hero-content-wrapper.halfed as a flex sibling to hero-content.
   Its border-left at x≈745 would double with hero-content's border-right —
   remove it. Its border-right lands at x=1440 (screen edge) — remove that
   too. The left gutter line (x=50) and column divider (x≈745) are provided
   by the hero-lines-grid and hero-content respectively. */
.image_full {
  border-left-width: 0;
  border-right-width: 0;
}

/* Hide the tools-page hero image panel on tablet and below */
@media screen and (max-width: 991px) {
  .image_full {
    display: none !important;
  }
}


/* ── 4. FIX h1 ALIGNMENT IN FLEX-COLUMN MODE (≤991px) ───────────────────── */
/* At ≥992px the hero-text-grid is a 4-column CSS grid; align-items:flex-end
   means "anchor cells to the bottom of the row", which is correct.
   Below 992px Webflow switches it to display:flex; flex-flow:column.
   In flex-column layout the cross-axis is horizontal, so align-items:flex-end
   right-aligns the children — pushing the h1 container 61px from the left
   instead of flush to the 50px gutter. Override to left-align. */
@media screen and (max-width: 991px) {
  /* Target .home specifically — it has higher specificity (0,2,0) than the
     base .hero-text-grid rule and sets align-items:flex-end at all sizes.
     In column-flex mode that right-aligns children; override to left-align. */
  .hero-text-grid.home {
    align-items: flex-start;
  }
}


/* ── 5. FOUR-BUTTON-GRID ON TOOLS PAGE ──────────────────────────────────── */
/* Same outer-border issue as three-big-buttons-grid: the grid container spans
   the full viewport and has border-left/right at screen edges. */
.four-button-grid {
  border-left-width: 0;
  border-right-width: 0;
}

/* Interior seams: each button-top has both border-left and border-right, so
   adjacent pairs share a seam where two 0.5px lines stack to 1px. Remove the
   left border from buttons 2-4 to keep every seam at exactly 0.5px. */
.four-button-grid .btn:not(:first-child) .button-top {
  border-left-width: 0;
}


/* ── 6. BUTTON HOVER Z-INDEX ─────────────────────────────────────────────── */
/* .btn elements are position:static, so z-index has no effect and the
   Webflow IX2 right+up animation renders behind later siblings (DOM order).
   Give each button a stacking context via position:relative; z-index is
   managed by overrides.js mouseenter/mouseleave to guarantee the hovered
   button always paints above all siblings regardless of DOM position. */
.btn {
  position: relative;
}


/* ── 7. DOT-GRID CURSOR REVEAL ──────────────────────────────────────────── */
/* Implemented entirely via the #rp-dot-reveal overlay created in overrides.js.
   The overlay carries the brand gradient as its background and is revealed only
   through the intersection of two CSS masks:
     (a) a 240px radial circle following the cursor
     (b) a repeating 1.5px dot grid (20px pitch)
   Outside the cursor radius: overlay is fully transparent — no visual change.
   Inside the radius but between dots: also transparent.
   Inside radius AND inside a dot: gradient colour shows through.
   Net: tiny brand-coloured dots appear around the cursor; everywhere else
   the overlay is invisible and page content is unaffected.                  */


/* ── 8. TYPOGRAPHY ──────────────────────────────────────────────────────── */
/* Body text (.regular-s) inherits the body's 14px / 120% lh — too small and
   too tight for a marketing site. Lift to 16px / 1.6 lh. .regular-m already
   has 16px in Webflow CSS but an identical tight line-height; loosen it.
   .regular-l at 20px / 112% lh is also tight for paragraph use.
   h2 line-height 104% causes visible collisions when a headline wraps. */
.regular-s { font-size: 16px; line-height: 1.6; }
.regular-m { line-height: 1.6; }
.regular-l { line-height: 1.45; }
h2          { line-height: 1.15; }
p           { line-height: 1.6; }


/* ── 9. PIXEL-ART BULLET PLACEHOLDER ────────────────────────────────────── */
/* .big-button-heading-shape.dark is a 6×6 solid black square used as a
   section-heading bullet. overrides.js replaces it with a pixel-art SVG
   chevron. Hide the square as a fallback until JS executes. */
.big-button-heading-shape.dark {
  background-color: transparent;
}


/* ── 10. FEATURED CLIENTS — LOGO HOVER ──────────────────────────────────── */
/* Keyboard-key "press" illusion without moving the container — the container
   stays in its grid cell (no overlap with the row below). Instead the LOGO
   IMAGE sinks down, and inset shadows on the container simulate the key frame
   walls and depth. Left + right black bars mimic the exposed key-slot sides.
   Cycling brand colours (yellow→mint→green→pink) are set via JS inline style,
   which overrides the :hover rule below. */
.logo-block {
  transition:
    background-color 0.15s cubic-bezier(.6, -.28, .735, .045),
    box-shadow       0.12s ease;
}
.logo-block-image {
  transition: transform 0.12s ease, opacity 0.15s ease;
}
.logo-block:hover {
  background-color: var(--white); /* JS inline style overrides this */
  box-shadow:
    inset -5px 0   0 #000,                /* right bar  */
    inset 0    6px 0 rgba(0, 0, 0, 0.45); /* top border */
}
.logo-block:hover .logo-block-image {
  transform: translate(-4px, 5px);
  opacity: 0.8;
}


/* ── 11. ENTRANCE ANIMATIONS ─────────────────────────────────────────────── */
/* 1. Hero:   chip slides up on load → h1 words stagger in → subheading fades.
   2. Reveal: project cards + section headings fade-up as they enter viewport.
   3. Counter: [fb-count-target] numbers count up when the Highlights section
               scrolls into view (Webflow's counter plugin is inactive in mirror).
   4. Footer:  .footer-line-block shapes rise up from below, staggered. */

@keyframes rp-slide-up {
  from { opacity: 0; transform: translateY(28px); }
  to   { opacity: 1; transform: translateY(0); }
}
@keyframes rp-fade-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}

/* Hero chip */
.rp-hero-chip {
  opacity: 0;
  animation: rp-slide-up 0.55s cubic-bezier(0.22, 1, 0.36, 1) 0.05s forwards;
}
/* Hero h1 — each word wrapped in a span.rp-word by JS */
.rp-word {
  display: inline-block;
  opacity: 0;
  animation: rp-slide-up 0.65s cubic-bezier(0.22, 1, 0.36, 1) forwards;
}
/* Hero subheading */
.rp-hero-sub {
  opacity: 0;
  animation: rp-fade-in 0.7s ease forwards;
}

/* Scroll-reveal base + triggered state */
.rp-reveal {
  opacity: 0;
  transform: translateY(36px);
  transition: opacity 0.75s cubic-bezier(0.22, 1, 0.36, 1),
              transform 0.75s cubic-bezier(0.22, 1, 0.36, 1);
}
.rp-reveal.rp-in {
  opacity: 1;
  transform: translateY(0);
}
.rp-reveal.rp-delay-1 { transition-delay: 0.15s; }
.rp-reveal.rp-delay-2 { transition-delay: 0.30s; }

/* Footer shapes — clipped then rise on .rp-footer-revealed */
.footer-lines-grid { overflow: hidden; }
.footer-line-block {
  transition: transform 0.9s cubic-bezier(0.22, 1, 0.36, 1),
              opacity   0.9s ease;
}
.footer-lines-grid:not(.rp-footer-revealed) .footer-line-block {
  transform: translateY(110%);
  opacity: 0;
}
.footer-lines-grid.rp-footer-revealed .footer-line-block.first-block  { transition-delay: 0s;    }
.footer-lines-grid.rp-footer-revealed .footer-line-block.second-block { transition-delay: 0.12s; }
.footer-lines-grid.rp-footer-revealed .footer-line-block.third-block  { transition-delay: 0.24s; }
.footer-lines-grid.rp-footer-revealed .footer-line-block.fourth-block { transition-delay: 0.36s; }


/* ── 12. NO-WEBFLOW-RUNTIME REPLACEMENTS ─────────────────────────────────── */
/* Button hover — replaces IX2 xValue:10 yValue:-10 transform.
   Transition is on the base state so it eases both in and out. */
.button-top {
  transition: transform 0.25s cubic-bezier(0.25, 0.46, 0.45, 0.94);
}
.btn:hover .button-top {
  transform: translate(10px, -10px);
}

/* CSS hamburger — replaces the Lottie icon_lottie element.
   Three .bar spans animate into an ✕ when .icon-25.is-open is set by JS. */
.icon_lottie {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  width: 22px;
  height: 15px;
}
.icon_lottie .bar {
  display: block;
  width: 100%;
  height: 2px;
  background-color: #132C5F;
  border-radius: 1px;
  transform-origin: center;
  transition: transform 0.3s cubic-bezier(0.25, 0.46, 0.45, 0.94),
              opacity   0.2s ease;
}
.icon-25.is-open .icon_lottie .bar:nth-child(1) { transform: translateY(6.5px) rotate(45deg);  }
.icon-25.is-open .icon_lottie .bar:nth-child(2) { opacity: 0; transform: scaleX(0);            }
.icon-25.is-open .icon_lottie .bar:nth-child(3) { transform: translateY(-6.5px) rotate(-45deg); }

/* Ensure background video fills its container without Webflow's JS
   setting object-fit via data-object-fit attribute. */
.w-background-video video {
  object-fit: cover;
}


/* ── 13. NAV ENHANCEMENTS ────────────────────────────────────────────────── */

/* 1 — desktop link hover underline */
.top_link p:not(.pill) {
  background-image: linear-gradient(currentColor, currentColor);
  background-size: 0% 1px;
  background-position: 0 100%;
  background-repeat: no-repeat;
  transition: background-size 0.25s cubic-bezier(0.22, 1, 0.36, 1);
}
.top_link:hover p:not(.pill) {
  background-size: 100% 1px;
}

/* 2 — hamburger middle bar: rotate while collapsing */
.icon-25.is-open .icon_lottie .bar:nth-child(2) {
  opacity: 0;
  transform: scaleX(0) rotate(90deg);
}

/* 3 — MOBILE MENU OVERLAY ──────────────────────────────────────────────── */

/* .full_contain (the overlay's actual content box) is deliberately
   background-color:var(--brand-pink) in the native stylesheet's base
   rule — but a max-width:991px override turns it transparent, so the
   overlay showed solid brand pink on wide viewports and, below 991px,
   whatever's behind .full/.menu instead (page content or <body>'s
   dot-grid pattern, depending on breakpoint) — inconsistent, and at some
   widths unreadable. Forcing the same pink at every width instead, on
   .full_contain itself (the element the colour was already meant for),
   which is reliably full-width/full-height at every breakpoint. */
.full_contain {
  background-color: var(--brand-pink) !important;
}

/* overrides.js sets .menu's display to make it (and .full inside it)
   visible below 991px, where .menu is display:none by default. That also
   reveals .menu's other children (.top, .side — the desktop horizontal nav
   links), which would otherwise render on top of our overlay. Hide them
   specifically while the overlay is open. */
.menu:has(> .full.rp-menu-open) .top,
.menu:has(> .full.rp-menu-open) .side,
.menu:has(> .full.rp-menu-closing) .top,
.menu:has(> .full.rp-menu-closing) .side {
  display: none !important;
}
.full {
  height: 100dvh !important;
}
/* .menu's native mobile rule (max-width:991px) ships with
   padding-top:8.7em/padding-bottom:6.6em — leftover from whatever Webflow
   originally used this element for, never reset at any breakpoint we
   actually render it at. .full is a flex child of .menu with flex-shrink:1,
   so it shrinks to fit inside that padding instead of filling .menu's full
   height — exposing .menu's own background (mint) as a band above AND
   below .full's pink overlay, i.e. what looks like "two menus" stacked.
   Desktop is unaffected: the padding only ever applied inside that same
   max-width:991px rule, and .menu renders as a normal inline nav there. */
.menu {
  padding: 0 !important;
  /* Kill .menu's own background outright rather than just relying on .full
     covering it exactly — any future gap (animation edge case, rounding)
     exposes "transparent" instead of mint. .full/.full_contain already
     supply the visible pink; .menu itself has no reason to show a colour
     of its own on mobile. */
  background: transparent !important;
}

/* Container: padded, flex column, everything centred; address+BRN still
   pinned to bottom via margin-top:auto regardless. */
.full_contain {
  padding: 80px 50px 44px !important; /* 50px matches site gutter */
  height: 100%;
  box-sizing: border-box;
  display: flex !important;
  flex-direction: column !important;
  align-items: center !important;
  justify-content: center !important;
  text-align: center;
  gap: 0 !important;
}

/* Hide desktop-only clutter (JS removes them from the DOM; this is a CSS fallback) */
.full_contain .hidemobile { display: none !important; }
/* Address + BRN paragraphs are deliberately kept visible */
.full_contain p.rp-menu-address,
.full_contain p.rp-menu-brn { display: block !important; }

/* Main nav links (injected): large, bold, ordered first */
.full_contain .rp-menu-injected {
  order: 1;
  display: block !important;
  padding: 11px 0;
  text-decoration: none;
}
/* Extra top gap before the second section (Our Services follows sub-links in DOM) */
.full_contain .rp-menu-sub + .rp-menu-injected {
  padding-top: 22px;
}
.full_contain .rp-menu-injected .full_link-text {
  font-family: 'Space Grotesk', sans-serif;
  font-size: clamp(2rem, 9vw, 2.8rem);
  font-weight: 700;
  line-height: 1.1;
  letter-spacing: -0.03em;
  color: #132C5F !important;
  margin: 0 !important;
  -webkit-font-smoothing: antialiased;
}

/* Project sub-links: smaller, indented, below Our Projects */
.full_contain .rp-menu-sub {
  order: 1;
  display: block !important;
  padding: 4px 0 4px 1.2rem;
  text-decoration: none;
}
.full_contain .rp-menu-sub .full_link-text {
  font-family: 'Space Grotesk', sans-serif;
  font-size: 0.85rem;
  font-weight: 500;
  letter-spacing: 0.01em;
  color: rgba(19, 44, 95, 0.55) !important;
  margin: 0 !important;
}
.full_contain .rp-menu-sub:hover .full_link-text {
  color: rgba(19, 44, 95, 0.85) !important;
}

/* Address: pinned above login, tiny */
.full_contain p.rp-menu-address,
.full_contain p.rp-menu-brn {
  order: 3;
  margin: 0 !important;
  font-family: 'Space Grotesk', sans-serif;
  font-size: 0.62rem;
  font-weight: 400;
  line-height: 1.6;
  color: rgba(19, 44, 95, 0.35) !important;
}
.full_contain p.rp-menu-address {
  margin-top: auto !important; /* push bottom block down */
}

/* Login link: sits between main links and address/BRN */
.full_contain > a:not(.rp-menu-injected):not(.rp-menu-sub) {
  order: 2;
  display: block !important;
  padding: 18px 0 14px;
  text-decoration: none;
}
.full_contain > a:not(.rp-menu-injected):not(.rp-menu-sub) .full_link-text {
  font-family: 'Space Grotesk', sans-serif;
  font-size: 0.7rem;
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: rgba(19, 44, 95, 0.4) !important;
  margin: 0 !important;
}

/* 4 — entrance stagger: items slide in from left */
.full .full_contain > * {
  opacity: 0;
  transform: translateX(-24px);
  transition:
    opacity   0.38s cubic-bezier(0.22, 1, 0.36, 1),
    transform 0.38s cubic-bezier(0.22, 1, 0.36, 1);
}
.full.rp-menu-open .full_contain > * {
  opacity: 1;
  transform: translateX(0);
}
.full.rp-menu-open .full_contain > *:nth-child(1)  { transition-delay: 0.18s; }
.full.rp-menu-open .full_contain > *:nth-child(2)  { transition-delay: 0.23s; }
.full.rp-menu-open .full_contain > *:nth-child(3)  { transition-delay: 0.27s; }
.full.rp-menu-open .full_contain > *:nth-child(4)  { transition-delay: 0.31s; }
.full.rp-menu-open .full_contain > *:nth-child(5)  { transition-delay: 0.34s; }
.full.rp-menu-open .full_contain > *:nth-child(6)  { transition-delay: 0.37s; }
.full.rp-menu-open .full_contain > *:nth-child(7)  { transition-delay: 0.40s; }
.full.rp-menu-open .full_contain > *:nth-child(8)  { transition-delay: 0.43s; }
.full.rp-menu-open .full_contain > *:nth-child(9)  { transition-delay: 0.46s; }
.full.rp-menu-open .full_contain > *:nth-child(10) { transition-delay: 0.49s; }

/* 5 — exit stagger: reverse order, slide to right */
.full.rp-menu-closing .full_contain > * {
  opacity: 0;
  transform: translateX(18px);
  transition:
    opacity   0.18s ease,
    transform 0.18s cubic-bezier(0.55, 0, 1, 0.45);
}
.full.rp-menu-closing .full_contain > *:nth-child(10) { transition-delay: 0s;    }
.full.rp-menu-closing .full_contain > *:nth-child(9)  { transition-delay: 0.03s; }
.full.rp-menu-closing .full_contain > *:nth-child(8)  { transition-delay: 0.06s; }
.full.rp-menu-closing .full_contain > *:nth-child(7)  { transition-delay: 0.08s; }
.full.rp-menu-closing .full_contain > *:nth-child(6)  { transition-delay: 0.10s; }
.full.rp-menu-closing .full_contain > *:nth-child(5)  { transition-delay: 0.12s; }
.full.rp-menu-closing .full_contain > *:nth-child(4)  { transition-delay: 0.14s; }
.full.rp-menu-closing .full_contain > *:nth-child(3)  { transition-delay: 0.16s; }
.full.rp-menu-closing .full_contain > *:nth-child(2)  { transition-delay: 0.18s; }
.full.rp-menu-closing .full_contain > *:nth-child(1)  { transition-delay: 0.20s; }

/* 6 — hover: fade slightly */
.full_contain .rp-menu-injected:hover .full_link-text {
  opacity: 0.5;
}
.full_contain > a:not(.rp-menu-injected):hover .full_link-text {
  color: rgba(19, 44, 95, 0.65) !important;
}


/* ── 14. MARQUEE CLIENT LOGOS ────────────────────────────────────────────────
 * overrides.js (before the logo-hover IIFE) moves all .logo-block elements
 * into a .rp-marquee-track, duplicates them for seamless looping, then adds
 * .rp-marquee to .logos-grid. The track animates -50% (= one full set width).
 * Hovering pauses so users can interact with individual logos.
 * Logo colour cycling + keyboard-press effect both still fire on hover.
 *
 * Hide the grid in its original Webflow position until JS adds .rp-marquee —
 * prevents a flash of logos at their un-moved location on initial paint.     */
.logos-grid:not(.rp-marquee):not(.rp-logos-visible) {
  visibility: hidden !important;
}
.logos-grid.rp-marquee {
  display: block !important; /* override Webflow grid */
  overflow: hidden;
  /* Full-bleed: break out of the container's horizontal padding to reach the
     viewport left edge. Works as long as no ancestor has overflow:hidden.   */
  width: 100vw !important;
  position: relative;
  left: 50%;
  transform: translateX(-50%);
  /* Strip Webflow borders + padding */
  border: none !important;
  padding: 0 !important;
  margin: 0 !important;
}
.rp-marquee-track {
  display: flex;
  width: max-content;

  /* SHIFT DISTANCE — must be a LENGTH, never a percentage. See the keyframes
     below for why. One full set is 10 logos x 180px (.logo-block flex-basis)
     = 1800px; the track holds that set twice, so scrolling 1800px lands the
     clone exactly where the original started and the loop is seamless.
     overrides.js overwrites this with the measured half-width before the
     track is inserted, so it stays correct if the logo count or block width
     ever changes — this value is the fallback. */
  --rp-marquee-shift: -1800px;

  /* Static -8s negative delay: starts mid-loop so the strip is already in
     motion on its first painted frame rather than easing off a standing
     edge. Deliberately a fixed value well inside the 28s period — an earlier
     attempt computed this dynamically as -(8s + elapsed page time) and
     mutated it on the already-running animation, which Blink tolerated and
     WebKit did not. Don't reintroduce that. */
  animation: rp-marquee-scroll 28s linear -8s infinite;
}
/* NO pause-on-hover. There used to be a
     .logos-grid.rp-marquee:hover .rp-marquee-track { animation-play-state: paused }
   rule here, on the reasoning that pausing let users interact with individual
   logos. It was removed because it caused a "marquee frozen on first load" bug
   and bought nothing in return:
     - The marquee is a FULL-WIDTH 80px band injected into the middle of the
       hero. If the pointer happens to be resting anywhere in that band when the
       page loads — likely, since it's mid-screen and spans the whole width —
       the strip is paused from the first frame and stays frozen until the user
       moves the mouse. It then "fixes itself", which is what made it look like
       a first-load-only glitch.
     - There is nothing to interact with anyway: the marquee's .logo-block
       elements are all <a href="#"> with no destination, and the brand-colour
       hover cycling is explicitly skipped for marquee logos (see the
       `if (el.closest('.rp-marquee')) return;` guard in overrides.js).
   If real per-logo links or hover behaviour are ever added back, don't restore
   a bare :hover pause — gate it behind a "user has actually moved the pointer"
   flag, or it will reintroduce the same freeze. */
/* Two deliberate choices here, both for WebKit/Safari:
 *
 * 1. A LENGTH, not translateX(-50%). A percentage transform resolves against
 *    the element's own width, and this track is width:max-content. WebKit
 *    resolves that percentage unreliably against an intrinsic width — it can
 *    come out as ~0, so the strip barely moves and reads as completely frozen.
 *    Chrome resolves it fine, which is why this only ever showed up in Safari.
 *    A plain px distance sidesteps intrinsic-width resolution entirely.
 *
 *    This was the real cause of the "marquee frozen on load" report. The old
 *    pause-on-hover rule was accidentally MASKING it: toggling
 *    animation-play-state forced WebKit to recompute the transform, which is
 *    why mousing over and off appeared to kick the strip into life. Removing
 *    that rule (correct in itself — see the note above) left the underlying
 *    bug exposed and the strip stuck for good.
 *
 * 2. translate3d, not translateX. Forces the animation onto the GPU in WebKit,
 *    which also stops it going stale behind first-load image decoding. Doubles
 *    as the compositor promotion a will-change: transform was doing before, so
 *    that's no longer needed.
 */
@keyframes rp-marquee-scroll {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(var(--rp-marquee-shift, -1800px), 0, 0); }
}
.rp-marquee-track .logo-block {
  flex: 0 0 180px; /* fixed width replaces grid-column sizing */
  height: 80px;
}
/* Marquee logos: disable the keyboard-press box-shadow and colour-cycle hover.
   Higher specificity (two classes) beats the §10 single-class rule without !important. */
.logos-grid.rp-marquee {
  background: transparent !important; /* Webflow sets black here — clear it */
}
.rp-marquee .logo-block {
  transition: none;
  background: transparent !important;
  border: none !important;
  box-shadow: none !important;
}
.rp-marquee .logo-block-image {
  /* Logos are white/light (designed for dark bg) — invert to black for grey bg */
  filter: brightness(0) !important;
  opacity: 0.75 !important;
}
.rp-marquee .logo-block:hover {
  background-color: transparent !important;
  box-shadow: none !important;
  transform: none !important;
}
.rp-marquee .logo-block:hover .logo-block-image {
  transform: none;
  filter: brightness(0) !important;
  opacity: 1 !important;
}


/* ── 15. PROJECT IMAGE BLOCK ─────────────────────────────────────────────────
 * position:relative is used by the flagship full-bleed card layout (§18).   */
.project-image-block {
  position: relative;
}


/* Custom cursor CSS removed per feedback — native cursor is used site-wide. */


/* ── 15. PROJECT IMAGE ZOOM ──────────────────────────────────────────────────
 * .project-image-block already has overflow:hidden. The image scales within
 * that clip so no overflow or layout shift occurs.                           */
.project-image {
  transition: transform 0.65s cubic-bezier(0.22, 1, 0.36, 1),
              filter     0.5s ease;
}
/* Desaturate the photo on hover so the mix-blend-mode:color overlay
   creates a clean duotone — brand hue on near-greyscale base.        */
.project-item:hover .project-image {
  transform: scale(1.05);
  filter: saturate(0.15);
}
/* Homepage flagship card (.rp-flagship, added by JS to the first
   .project-item) keeps a static image — no zoom/desaturate on hover. */
.project-item.rp-flagship:hover .project-image {
  transform: none;
  filter: none;
}


/* ── 16. ACTIVE PAGE NAV LINK ────────────────────────────────────────────────
 * JS matches window.location.pathname to each .top_link href and adds
 * .rp-nav-active. The underline is shown permanently (not just on hover)
 * to indicate "you are here". Same gradient trick as the hover underline. */
.top_link.rp-nav-active p:not(.pill) {
  background-size: 100% 1px;
}


/* ── 17. TOOLS PILL BREATHE ──────────────────────────────────────────────────
 * Very slow scale breathe (3s period, 1.05× peak) draws the eye to the CTA
 * without feeling animated. display:inline-block required for transform on
 * a <span>.                                                                  */
@keyframes rp-pill-breathe {
  0%, 100% { transform: scale(1);    }
  50%       { transform: scale(1.05); }
}
.pinkpill.gradient {
  display: inline-block;
  background-image: none;
  background-color: var(--brand-pink);
  animation: rp-pill-breathe 3s ease-in-out infinite;
}


/* ── 21. FULL-HEIGHT LINES (home page only) ──────────────────────────────────
 * Problem: hero-section has min-height:520px but its block children only
 * grow to content height (~440px), so the absolutely-positioned lines grid
 * stops short of the hero bottom.
 *
 * Fix: flex chain. hero-section becomes a flex column; each descendent in the
 * chain gets flex:1 so hero-content fills the full 520px. The absolutely-
 * positioned hero-lines-grid then uses height:100% and covers everything.
 * margin-top:auto on the marquee pins it to the bottom of hero-content,
 * flush with the three-buttons section.                                      */
main.hero-section {
  position: relative;
  min-height: 520px;
  display: flex;
  flex-direction: column;
}
main.hero-section > .wide-container {
  flex: 1;
  display: flex;
  flex-direction: column;
}
main.hero-section > .wide-container > .hero {
  flex: 1;
}
main.hero-section > .wide-container > .hero > .hero-content-wrapper {
  flex: 1;
}
main.hero-section > .wide-container > .hero > .hero-content-wrapper > .hero-content {
  flex: 1;
  padding-bottom: 0; /* marquee goes flush to hero bottom */
}
/* Pin marquee to bottom of hero-content, just above the buttons */
main.hero-section .hero-content > .logos-grid.rp-marquee {
  margin-top: auto !important;
}
/* Lines grid now inherits the full hero-content height */
main.hero-section .hero-lines-grid {
  height: 100%;
}


/* ── 18. FLAGSHIP PROJECT CARD (home page only) ──────────────────────────────
 * JS adds .rp-flagship to the first .project-item. The info card floats left
 * with a light-to-transparent gradient so the photo bleeds through on the right.
 * background !important overrides the dot-grid inline backgroundImage set by
 * the cursor-reveal IIFE before .rp-flagship is added by the home-page IIFE. */
.project-item.rp-flagship {
  position: relative !important;
  display: block !important;
  min-height: 640px;
  overflow: hidden;
}
.project-item.rp-flagship .project-image-block {
  position: absolute !important;
  inset: 0 !important;
  width: 100% !important;
  height: 100% !important;
}
.project-item.rp-flagship .project-image-block img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 20%;
}
/* Info card: page-grey left → transparent right */
.project-item.rp-flagship .project-info-card {
  position: relative;
  z-index: 3;
  width: 52%;
  min-height: 640px;
  padding: 3rem 2.5rem;
  background: linear-gradient(
    to right,
    #f2f2f2 0%,
    #f2f2f2 30%,
    rgba(242, 242, 242, 0.6) 50%,
    rgba(242, 242, 242, 0) 65%
  ) !important;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 1.5rem;
  box-sizing: border-box;
  box-shadow: none;
}
/* Label/value rows: keep them close together instead of space-between */
.project-item.rp-flagship .project-info-block {
  justify-content: flex-start !important;
  gap: 6px !important;
}
/* All content dark for contrast on the light gradient */
.project-item.rp-flagship .project-info-card .h3,
.project-item.rp-flagship .project-info-card h3 { color: #0a0a0a; }
.project-item.rp-flagship .project-info-card .regular-s { color: rgba(10,10,10,0.8); }
.project-item.rp-flagship .project-info-card .medium-uppercase-xs { color: rgba(10,10,10,0.55); }
.project-item.rp-flagship .project-info-card .color-black-opacity-70 { color: rgba(10,10,10,0.55) !important; }
/* Chips: dark outline */
.project-item.rp-flagship .descriptive-chips { border-color: rgba(10,10,10,0.2); }
.project-item.rp-flagship .chips-shape { background: rgba(10,10,10,0.07); }
.project-item.rp-flagship .descriptive-chips * { color: rgba(10,10,10,0.7); }
/* Button: transparent fill, dark outline + text */
.project-item.rp-flagship .btn .button-top {
  background: transparent !important;
  background-image: none !important;
  border: 1.5px solid #0a0a0a !important;
  color: #0a0a0a !important;
  box-shadow: none !important;
}
.project-item.rp-flagship .btn .button-top * {
  color: #0a0a0a !important;
}
.project-item.rp-flagship .btn .button-bottom {
  background: transparent !important;
}
/* Flagship "Learn more" must NOT lift/shift on hover (it sits on the photo,
   so the global diagonal translate reads as a glitch). Hold it still and use
   a fill inversion as the hover cue instead. */
.project-item.rp-flagship .btn .button-top {
  transition: background-color 0.28s ease, color 0.28s ease !important;
}
.project-item.rp-flagship .btn:hover .button-top {
  transform: none !important;
  background: #0a0a0a !important;
}
.project-item.rp-flagship .btn:hover .button-top * {
  color: #f2f2f2 !important;
}


/* ── 19. NAVY HERO (home page only) ─────────────────────────────────────────
 * JS adds .rp-navy-hero to <main class="hero-section">.
 * .hero-content has 50px left/right padding; we use a gradient that keeps
 * those padded gutter areas in the page's grey (#f2f2f2) while filling the
 * content band with navy.                                                    */
main.rp-navy-hero {
  background: linear-gradient(
    to right,
    #f2f2f2 50px,
    #132C5F 50px,
    #132C5F calc(100% - 50px),
    #f2f2f2 calc(100% - 50px)
  );
}

/* All text → off-white (needs !important — Webflow locks h1/p colours tightly) */
main.rp-navy-hero h1,
main.rp-navy-hero h2,
main.rp-navy-hero p,
main.rp-navy-hero .medium-uppercase-xs,
main.rp-navy-hero .medium-uppercase-s,
main.rp-navy-hero .medium-uppercase-m,
main.rp-navy-hero .regular-s,
main.rp-navy-hero .hero-description { color: #f2f2f2 !important; }

/* Swapping word + cursor → yellow (only the one word, not all .rp-word spans
   which the entrance animation uses for every word in the h1).              */
main.rp-navy-hero .rp-swap-target { color: #F1FB6D !important; }

/* .hero-content-wrapper gets a grey dot-grid background-image from the cursor
   reveal IIFE (runs before rp-navy-hero is added). Both properties need
   !important to override the JS-set inline style and Webflow's bg-color.     */
main.rp-navy-hero .hero-content-wrapper {
  background-color: transparent !important;
  background-image: none !important;
}

/* All structural borders → faint white rule lines */
main.rp-navy-hero .hero-content,
main.rp-navy-hero .hero-content-wrapper,
main.rp-navy-hero .hero-text-grid,
main.rp-navy-hero .hero-lines-grid,
main.rp-navy-hero .hero-line-block { border-color: rgba(242,242,242,0.12) !important; }

/* Chip (THE MARKETING AGENCY YOU CAN TRUST) */
main.rp-navy-hero .chips { border-color: rgba(242,242,242,0.3); }
main.rp-navy-hero .chips-shape { background: rgba(242,242,242,0.3); }



/* ── 20. FEATURED CLIENTS → SPACER ──────────────────────────────────────────
 * The logos are now in the hero marquee. Hide the heading + description that
 * remain in section.section-top-padding and let the section act as a spacer. */
body.rp-home section.section-top-padding:has(.space-bottom-60) {
  display: none;
}


/* ── 20b. HERO H1 FOUC FIX ───────────────────────────────────────────────────
 * Before the entrance-animation IIFE wraps words in .rp-word spans, the h1
 * is painted in Webflow's default navy. Hiding the h1 until JS runs prevents
 * the flash; the .rp-word spans override visibility and animate in normally. */
.hero-section h1 {
  visibility: hidden;
}
.hero-section h1 .rp-word {
  visibility: visible;
}


/* ── 21. BUTTONS SECTION (home page only) ───────────────────────────────────
 * JS moves .three-big-buttons-grid out of main.rp-navy-hero into a sibling
 * div.rp-buttons-section, giving it its own non-navy stacking context.      */
.rp-buttons-section {
  background: var(--white, #f2f2f2);
}


/* ══════════════════════════════════════════════════════════════════════════
   DESIGN-PASS 1 — HOME-PAGE POLISH
   Refinements layered on the existing overrides. All home-page-scoped where
   the effect is homepage-specific; motion is collapsed under reduced-motion.
   ══════════════════════════════════════════════════════════════════════════ */

/* ── 22. MARQUEE EDGE FADE ───────────────────────────────────────────────────
 * Dissolve the client logos into the background at both container edges so the
 * loop reads as continuous rather than hard-cropping at the gutters.          */
.logos-grid.rp-marquee {
  -webkit-mask-image: linear-gradient(
    90deg, transparent 0%, #000 7%, #000 93%, transparent 100%);
          mask-image: linear-gradient(
    90deg, transparent 0%, #000 7%, #000 93%, transparent 100%);
}


/* ── 23. HERO ORBS — STATIC ───────────────────────────────────────────────────
 * Previously had a slow vertical float (rp-orb-float); removed per feedback
 * so the hero asset sits still. */


/* ── 23b. HERO VALUE POINTS ───────────────────────────────────────────────────
 * Three points under the hero subheading, flowing left to right, each a navy
 * circle with a pixelarticons "check" SVG (currentColor, white) — matches the
 * icon style already used for the "■ OUR PROJECTS" section bullets — plus a
 * label. Wraps to its own line per item on narrow viewports. */
.rp-hero-points {
  display: flex;
  flex-wrap: wrap;
  gap: 20px 28px;
  margin-top: 20px; /* matches the h1 -> subheading gap above */
}
.rp-hero-point {
  display: flex;
  align-items: center;
  gap: 10px;
}
.rp-hero-point-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background-color: var(--primary);
  color: var(--white);
}
.rp-hero-point-icon svg {
  display: block;
  width: 9px;
  height: 9px;
}
.rp-hero-point .medium-uppercase-xs {
  color: var(--primary);
}


/* ── 24. BIG-BUTTON HOVER POLISH (home page + /tools hero/stats) ─────────────
 * The global .btn:hover rule shifts .button-top by translate(10px,-10px) — a
 * Webflow-era diagonal jump. For the home page's three flagship buttons, the
 * /tools hero's Try now/Login buttons, and the /tools stat cards
 * (.four-button-grid), replace it with a clean straight lift + a shadow
 * tinted toward the button's own colour, and (where the markup has the
 * chevron in its own span) nudge it to signal direction. Scoped so smaller
 * buttons elsewhere keep the original layered-reveal interaction.             */
.rp-buttons-section .btn .button-top,
.stacked-right-btns .btn .button-top,
.four-button-grid .btn .button-top {
  transition: transform 0.32s cubic-bezier(0.22, 1, 0.36, 1),
              box-shadow 0.32s cubic-bezier(0.22, 1, 0.36, 1);
  box-shadow: 0 0 0 rgba(19, 44, 95, 0);
}
.rp-buttons-section .btn:hover .button-top,
.stacked-right-btns .btn:hover .button-top,
.four-button-grid .btn:hover .button-top {
  transform: translateY(-6px);
  box-shadow: 0 18px 34px -14px rgba(19, 44, 95, 0.35);
}
.rp-buttons-section .btn:active .button-top,
.stacked-right-btns .btn:active .button-top,
.four-button-grid .btn:active .button-top {
  transform: translateY(-2px);
  transition-duration: 0.12s;
}
/* Chevron (injected svg span) glides right on hover */
.rp-buttons-section .big-button-heading span {
  transition: transform 0.32s cubic-bezier(0.22, 1, 0.36, 1);
}
.rp-buttons-section .btn:hover .big-button-heading span {
  transform: translateX(4px);
}


/* ── 24b. /TOOLS HERO — SPACE ABOVE BUTTONS ──────────────────────────────────
 * .stacked-right-btns sits flush against the h1 with no margin of its own. */
.stacked-right-btns {
  margin-top: 28px;
}


/* ── 25. REDUCED-MOTION GUARD (mandatory) ────────────────────────────────────
 * Every looping / entrance animation added by these overrides collapses to a
 * static, fully-visible end state when the user requests reduced motion.
 * The custom cursor is removed and the native pointer restored.               */
@media (prefers-reduced-motion: reduce) {
  .rp-marquee-track,
  .pinkpill.gradient {
    animation: none !important;
  }
  .rp-word,
  .rp-hero-chip,
  .rp-hero-sub {
    animation: none !important;
    opacity: 1 !important;
    transform: none !important;
  }
  .rp-reveal {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
  }
  .footer-lines-grid:not(.rp-footer-revealed) .footer-line-block,
  .footer-line-block {
    transform: none !important;
    opacity: 1 !important;
    transition: none !important;
  }
  .rp-buttons-section .btn .button-top,
  .rp-buttons-section .big-button-heading span {
    transition: none !important;
  }
}


/* ── 26. FOOTER LINK HOVER UNDERLINE ─────────────────────────────────────────
 * Same grow-from-left underline as the desktop nav links (§13), applied to the
 * footer menu + legal links so the whole site shares one hover language. Bare
 * <a> elements here, so the gradient underline sits on the anchor itself.     */
.footer-menu-item,
.footer-link {
  background-image: linear-gradient(currentColor, currentColor);
  background-size: 0% 1px;
  background-position: 0 100%;
  background-repeat: no-repeat;
  text-decoration: none;
  transition: background-size 0.28s cubic-bezier(0.22, 1, 0.36, 1),
              color 0.2s ease;
}
.footer-menu-item:hover,
.footer-link:hover {
  background-size: 100% 1px;
}
@media (prefers-reduced-motion: reduce) {
  .footer-menu-item,
  .footer-link { transition: background-size 0s, color 0.2s ease; }
}


/* ══════════════════════════════════════════════════════════════════════════
   27. TOOLS HERO — FLOATING 3D PRODUCT CARD (/tools only)
   JS strips the Webflow swipe-in interaction from the hero screenshot and wraps
   it as .rp-tools-card (outer, floats) > .rp-tools-card-inner (tilts in 3D) > img.
   Background is untouched — the card floats on the existing mint panel.
   ══════════════════════════════════════════════════════════════════════════ */
main.hero-section .image_full {
  overflow: visible !important;   /* was clipped — let the card + shadow breathe */
  perspective: 1700px;
  display: flex;
  /* .image_full's native flex-flow is column, so align-items (not
     justify-content) is the horizontal/cross axis — flex-start left-anchors
     the card instead of centring it, so a card wider than the panel bleeds
     out the right edge only, rather than growing symmetrically into the
     hero-content column on the left. justify-content still centres it
     vertically (the main axis). */
  align-items: flex-start;
  justify-content: center;
  padding: 12px 0 12px 26px !important;   /* override .padded-top-5em; drop the right gutter so the card can run flush to (and past) the panel's right edge */
}
/* Ancestor up the chain from .image_full that still clips: .hero-content-wrapper
   has overflow:hidden natively (needed elsewhere so nothing else escapes its
   box). Scoped via :has() to only the wrapper that actually contains this
   card, so it doesn't loosen clipping on every other page's hero. */
.hero-content-wrapper:has(.rp-tools-card) {
  overflow: visible;
}
/* Bleeding the card off the viewport edge (below) would otherwise create a
   genuine horizontal scrollbar/pannable page — overflow:visible on an
   ancestor doesn't itself add scroll room, but a normal-flow box simply
   rendering wider than its container does. This is the standard safety net
   for any full-bleed element on the site, not just this one. */
html, body {
  overflow-x: hidden;
}
.rp-tools-card {
  position: relative;
  /* Deliberately wider than .image_full's own content box (695px at 1440,
     776px at 1600, ~936px at 1920+) so it bleeds a constant ~120px past the
     panel — and off the browser viewport's right edge, since the panel
     itself runs flush to the viewport at these widths. Scales with the
     panel automatically instead of needing a per-breakpoint max-width. */
  width: calc(100% + 120px);
  transform-style: preserve-3d;
  animation: rp-card-float 6s ease-in-out infinite;
  will-change: transform;
}
.rp-tools-card-inner {
  position: relative;
  /* Near-square box so the card reads big + upright. The 4:3 source is still
     cover-cropped on the right (object-position:left top keeps the sidebar +
     title) but only ~6% of it — 1:1 was cropping a full 25% off the right
     edge, cutting into the stat cards; 5:4 keeps the tall silhouette while
     showing nearly the whole screenshot. */
  aspect-ratio: 5 / 4;
  border-radius: 16px;
  overflow: hidden;
  background: #fff;
  transform-style: preserve-3d;
  transform: rotateX(var(--rx, 4deg)) rotateY(var(--ry, -9deg));
  transition: transform 0.25s cubic-bezier(0.22, 1, 0.36, 1);
  border: 1px solid rgba(19, 44, 95, 0.12);
  box-shadow:
    0 2px 6px rgba(19, 44, 95, 0.06),
    0 18px 34px -12px rgba(19, 44, 95, 0.22),
    0 46px 82px -28px rgba(19, 44, 95, 0.42);
}
.rp-tools-card-img {
  display: block;
  /* Webflow's .image-2 is position:absolute with top:70px/left:20px. `static`
     puts it back in flow AND drops those offsets so the shot sits flush. */
  position: static;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: left top;   /* keep the sidebar + title when a wide shot crops */
  border-radius: inherit;
}
/* diagonal glass sheen to sell the 3D surface */
.rp-tools-card-inner::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: linear-gradient(118deg,
              rgba(255, 255, 255, 0.30) 0%,
              rgba(255, 255, 255, 0) 38%,
              rgba(255, 255, 255, 0) 72%,
              rgba(255, 255, 255, 0.14) 100%);
  pointer-events: none;
}
@keyframes rp-card-float {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-14px); }
}
@media (prefers-reduced-motion: reduce) {
  .rp-tools-card { animation: none !important; }
  .rp-tools-card-inner {
    transition: none !important;
    transform: rotateX(4deg) rotateY(-9deg) !important;
  }
}

/* ── 27. ABOUT-BLOCKS FIXED HEIGHT GAP (768-991px) ───────────────────────────
 * The native stylesheet forces .blocks-section.about-blocks to a fixed
 * height:800px only within the 768-991px range (auto above and below it).
 * That height assumes the background video is visible and fills the section
 * (.about-video-block height:100%), but the video is hidden at this same
 * breakpoint (display:none) leaving only the shorter static image + text
 * column — so the section renders ~175px taller than its own content,
 * showing as a dead gap before the next section. height:auto here matches
 * the (already-correct) behaviour on every other breakpoint. */
.blocks-section.about-blocks {
  height: auto;
  min-height: 0;
}


/* ── 28. /TOOLS DOCS (generated pages under /tools/docs/) ────────────────────
 * Styles for the docs library. Markup is generated by build_docs.mjs —
 * edit docs-src/ + rerun `pnpm docs:build`; never hand-edit tools/docs/. */

.rp-docs { background: #fff; }
.rp-docs .rp-docs-main { padding: 140px 0 80px; }

.rp-docs-shell {
  /* mirror .section-2.is--nav geometry (max-width 1928, centred, 50px side
     padding) so the sidebar divider lines up with the nav logo's right border */
  max-width: 1928px; margin: 0 auto; padding: 0 50px;
  display: grid; grid-template-columns: 25% minmax(0, 1fr); gap: 0;
  align-items: stretch;
}

/* right-hand content frame — .side (the fixed, full-height strip holding the
   scroll-progress bar + social icons, ≥992px) already sits exactly at the
   nav's 50px gutter, i.e. the same x as icon-25's own border. Its own native
   CSS clearly intends a matching border-left there ("border-left:1px
   #241c15") but the vendor stylesheet is missing the style keyword, so it
   defaults to none and never renders, on ANY page. Fix it, scoped to docs
   pages only (marketing pages weren't part of what was asked for). Since
   .side is nested inside the nav (z-index:1000), this divider is naturally
   always on top of scrolled content — no extra stacking work needed. */
.rp-docs .side {
  border-left-style: solid;
}

/* sidebar — solid divider between it and the content, continuing the line of
   the nav logo box's right border (§1 sets .logo-2 to 25% of the nav's inner
   width; same .5px solid black as the nav/footer frame).
   The divider must reach the nav's own bottom line (.nav_line, ~73px) rather
   than start at .rp-docs-main's 140px content offset, so it runs unbroken
   from the nav down. Pull the box up by the 67px difference with a negative
   margin, then cancel that with matching padding-top so the sidebar's own
   content (search box, home link, first group) still lands at its original
   140px position — only the border's start point moves.
   Same trick at the bottom: .rp-docs-main's 80px bottom padding otherwise
   leaves a gap of dead space between the end of the sidebar/article and the
   footer, where the divider just stops. Extend the box down by that 80px
   (margin-bottom) and cancel it with matching padding-bottom, so the line
   runs unbroken all the way to the footer's top edge. */
.rp-docs-sidebar {
  padding-right: 32px; border-right: .5px solid #000;
  margin-top: -67px; padding-top: 67px;
  margin-bottom: -80px; padding-bottom: 80px;
  /* Bleed the grey into the page's standard 50px left gutter, which would
     otherwise show through as a white strip (the sidebar box itself starts
     at the gutter's right edge, not the viewport edge). */
  margin-left: -50px; padding-left: 50px;
  background-color: #f2f2f2;
}
.rp-docs-side-inner { position: sticky; top: 110px; }
.rp-docs-side-toggle { display: none; }
.rp-docs-side-home {
  display: block; font: 600 13px/1 "Space Grotesk", sans-serif; letter-spacing: .06em;
  text-transform: uppercase; color: #132C5F; text-decoration: none; margin: 18px 0 10px;
}
.rp-docs-side-group { border-top: 1px solid rgba(19,44,95,.12); padding: 12px 0; }
.rp-docs-side-channel {
  display: block; font: 600 14px/1.3 "Space Grotesk", sans-serif; color: #132C5F;
  text-decoration: none; padding: 4px 0;
}
/* Sections (themes, e.g. "Disapprovals & policy") within a channel — hidden
   entirely unless the channel itself is open; each section then toggles
   its own article list independently, so a large channel doesn't dump one
   giant flat list on the reader. */
.rp-docs-side-section { display: none; margin-top: 4px; }
.rp-docs-side-group-open .rp-docs-side-section { display: block; }
.rp-docs-side-section-title {
  display: block; width: 100%; text-align: left; background: none; border: 0; cursor: pointer;
  font: 600 12px/1.3 "Space Grotesk", sans-serif; letter-spacing: .03em; text-transform: uppercase;
  color: rgba(19,44,95,.55); padding: 6px 0;
}
.rp-docs-side-section-title:hover { color: #132C5F; }
.rp-docs-side-section-title::before { content: "+ "; }
.rp-docs-side-section-open > .rp-docs-side-section-title::before { content: "− "; }
.rp-docs-side-list { list-style: none; margin: 2px 0 0; padding: 0 0 0 12px; display: none; }
.rp-docs-side-section-open .rp-docs-side-list { display: block; }
.rp-docs-side-link {
  display: block; font: 400 13px/1.45 "Space Grotesk", sans-serif; color: rgba(19,44,95,.72);
  text-decoration: none; padding: 5px 0 5px 10px; border-left: 2px solid transparent;
}
.rp-docs-side-link:hover { color: #132C5F; border-left-color: rgba(19,44,95,.3); }
.rp-docs-side-link-current { color: #132C5F; font-weight: 600; border-left-color: #132C5F; }

/* search */
.rp-docs-search { position: relative; margin-bottom: 8px; }
.rp-docs-search-input {
  width: 100%; box-sizing: border-box; padding: 10px 14px;
  font: 400 14px/1.2 "Space Grotesk", sans-serif; color: #132C5F;
  background: #fff; border: 1px solid rgba(19,44,95,.25); border-radius: 0;
  outline: none;
}
.rp-docs-search-input:focus { border-color: #132C5F; }
.rp-docs-search-results {
  position: absolute; z-index: 60; top: calc(100% + 4px); left: 0; right: 0;
  background: #fff; border: 1px solid #132C5F; max-height: 340px; overflow: auto;
  box-shadow: 0 14px 34px rgba(19,44,95,.16);
}
.rp-docs-search-hit { display: block; padding: 10px 14px; text-decoration: none; border-bottom: 1px solid rgba(19,44,95,.08); }
.rp-docs-search-hit:hover, .rp-docs-search-hit.is-active { background: #B9F0E7; }
.rp-docs-search-hit-title { font: 600 14px/1.3 "Space Grotesk", sans-serif; color: #132C5F; display: block; }
.rp-docs-search-hit-meta { font: 400 12px/1.4 "Space Grotesk", sans-serif; color: rgba(19,44,95,.6); display: block; }
.rp-docs-search-empty { padding: 12px 14px; font: 400 13px/1.4 "Space Grotesk", sans-serif; color: rgba(19,44,95,.6); }
.rp-docs-search-hero { max-width: 480px; margin: 28px 0 0; }
.rp-docs-search-hero .rp-docs-search-input { padding: 14px 18px; font-size: 16px; }

/* breadcrumbs */
.rp-docs-breadcrumbs { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin-bottom: 26px; }
.rp-docs-crumb {
  font: 500 12px/1 "Space Grotesk", sans-serif; letter-spacing: .05em; text-transform: uppercase;
  color: rgba(19,44,95,.62); text-decoration: none;
}
a.rp-docs-crumb:hover { color: #132C5F; text-decoration: underline; }
.rp-docs-crumb-current { color: #132C5F; }
.rp-docs-crumb-sep { color: rgba(19,44,95,.35); font-size: 12px; }

/* article header */
.rp-docs-article { min-width: 0; max-width: 780px; padding-left: 40px; }
.rp-docs-article-head { margin-bottom: 26px; }
.rp-docs-h1 {
  font: 600 clamp(30px, 4.4vw, 46px)/1.08 "Space Grotesk", sans-serif;
  letter-spacing: -0.02em; color: #132C5F; margin: 14px 0 14px;
}
.rp-docs-lede { font: 400 17px/1.55 "Space Grotesk", sans-serif; color: rgba(19,44,95,.75); margin: 0; max-width: 640px; }
.rp-docs-updated { font: 500 11px/1 "Space Grotesk", sans-serif; letter-spacing: .06em; text-transform: uppercase; color: rgba(19,44,95,.5); margin-left: 10px; }

.rp-docs-chip {
  display: inline-block; padding: 5px 10px 4px; font: 600 11px/1 "Space Grotesk", sans-serif;
  letter-spacing: .08em; text-transform: uppercase; color: #132C5F; background: #B9F0E7;
}
.rp-docs-chip-reference { background: #F1FB6D; }
.rp-docs-chip-howto { background: #9EE89B; }
.rp-docs-chip-faq { background: #F8C0FF; }

/* plain-English summary box */
.rp-docs-summary {
  background: #132C5F; color: #fff; padding: 26px 30px; margin: 0 0 34px;
}
.rp-docs-summary-label {
  font: 600 11px/1 "Space Grotesk", sans-serif; letter-spacing: .1em; text-transform: uppercase;
  color: #B9F0E7; margin-bottom: 12px;
}
.rp-docs-summary p { font: 400 16px/1.6 "Space Grotesk", sans-serif; margin: 0; color: #fff; }

/* prose */
.rp-docs-prose { font: 400 16px/1.65 "Space Grotesk", sans-serif; color: #1d2b4d; }
.rp-docs-prose h2 {
  font: 600 24px/1.2 "Space Grotesk", sans-serif; letter-spacing: -0.01em; color: #132C5F;
  margin: 44px 0 14px; padding-top: 18px; border-top: 1px solid rgba(19,44,95,.12);
}
.rp-docs-prose h3 { font: 600 18px/1.3 "Space Grotesk", sans-serif; color: #132C5F; margin: 30px 0 10px; }
.rp-docs-prose p { margin: 0 0 16px; }
.rp-docs-prose a { color: #132C5F; text-decoration: underline; text-decoration-color: rgba(19,44,95,.4); text-underline-offset: 2px; }
.rp-docs-prose a:hover { text-decoration-color: #132C5F; }
.rp-docs-prose ul, .rp-docs-prose ol { margin: 0 0 18px; padding-left: 22px; }
.rp-docs-prose li { margin-bottom: 8px; }
.rp-docs-prose code {
  font: 500 0.88em/1 "SF Mono", "Menlo", monospace; background: rgba(19,44,95,.08);
  padding: 2px 6px; color: #132C5F;
}
.rp-docs-prose table { width: 100%; border-collapse: collapse; margin: 20px 0 26px; font-size: 14px; }
.rp-docs-prose th {
  text-align: left; font: 600 12px/1.3 "Space Grotesk", sans-serif; letter-spacing: .05em;
  text-transform: uppercase; color: #132C5F; background: #B9F0E7; padding: 10px 12px;
}
.rp-docs-prose td { padding: 10px 12px; border-bottom: 1px solid rgba(19,44,95,.12); vertical-align: top; }
.rp-docs-prose blockquote { margin: 0 0 18px; padding: 4px 0 4px 18px; border-left: 3px solid #9EE89B; color: rgba(19,44,95,.8); }

/* table scroll on small screens */
@media (max-width: 767px) {
  .rp-docs-prose table { display: block; overflow-x: auto; }
}

/* deep dive */
.rp-docs-deep { margin: 8px 0 26px; border: 1px solid rgba(19,44,95,.2); background: #fff; }
.rp-docs-deep > summary {
  cursor: pointer; list-style: none; padding: 14px 18px;
  font: 600 15px/1.3 "Space Grotesk", sans-serif; color: #132C5F;
  display: flex; align-items: center; gap: 10px;
}
.rp-docs-deep > summary::-webkit-details-marker { display: none; }
.rp-docs-deep > summary::after { content: "−"; margin-left: auto; font-size: 18px; color: rgba(19,44,95,.5); }
.rp-docs-deep:not([open]) > summary::after { content: "+"; }
.rp-docs-deep-tag {
  flex: none; padding: 4px 8px 3px; font: 600 10px/1 "Space Grotesk", sans-serif;
  letter-spacing: .08em; text-transform: uppercase; background: #F1FB6D; color: #132C5F;
}
.rp-docs-deep-body { padding: 2px 18px 8px; border-top: 1px solid rgba(19,44,95,.12); }

/* steps / faq / related */
.rp-docs-steps h2, .rp-docs-faq h2, .rp-docs-related h2 {
  font: 600 24px/1.2 "Space Grotesk", sans-serif; color: #132C5F; margin: 44px 0 16px;
  padding-top: 18px; border-top: 1px solid rgba(19,44,95,.12);
}
.rp-docs-steps ol { counter-reset: step; list-style: none; margin: 0; padding: 0; }
.rp-docs-steps li {
  counter-increment: step; position: relative; padding: 0 0 18px 52px; margin: 0;
  font: 400 15px/1.6 "Space Grotesk", sans-serif; color: #1d2b4d;
}
.rp-docs-steps li::before {
  content: counter(step); position: absolute; left: 0; top: 0;
  width: 34px; height: 34px; display: grid; place-items: center;
  background: #9EE89B; color: #132C5F; font: 600 15px/1 "Space Grotesk", sans-serif;
}
.rp-docs-faq-item { border-bottom: 1px solid rgba(19,44,95,.12); }
.rp-docs-faq-item summary {
  cursor: pointer; list-style: none; padding: 14px 0;
  font: 600 15px/1.4 "Space Grotesk", sans-serif; color: #132C5F;
  display: flex; justify-content: space-between; gap: 16px;
}
.rp-docs-faq-item summary::-webkit-details-marker { display: none; }
.rp-docs-faq-item summary::after { content: "+"; color: rgba(19,44,95,.5); flex: none; }
.rp-docs-faq-item[open] summary::after { content: "−"; }
.rp-docs-faq-item p { font: 400 15px/1.6 "Space Grotesk", sans-serif; color: #1d2b4d; margin: 0 0 16px; max-width: 640px; }
.rp-docs-related ul { list-style: none; margin: 0; padding: 0; }
.rp-docs-related li { padding: 12px 0; border-bottom: 1px solid rgba(19,44,95,.12); }
.rp-docs-related a { font: 600 15px/1.4 "Space Grotesk", sans-serif; color: #132C5F; text-decoration: none; }
.rp-docs-related a:hover { text-decoration: underline; }
.rp-docs-related-desc { display: block; font: 400 13px/1.5 "Space Grotesk", sans-serif; color: rgba(19,44,95,.65); margin-top: 3px; }

/* prev/next */
.rp-docs-prevnext { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; margin: 44px 0 0; }
.rp-docs-pn {
  display: block; padding: 16px 18px; border: 1px solid rgba(19,44,95,.2); background: #fff;
  font: 600 15px/1.35 "Space Grotesk", sans-serif; color: #132C5F; text-decoration: none;
}
.rp-docs-pn:hover { background: #B9F0E7; }
.rp-docs-pn-next { text-align: right; }
.rp-docs-pn-label { display: block; font: 500 11px/1 "Space Grotesk", sans-serif; letter-spacing: .07em; text-transform: uppercase; color: rgba(19,44,95,.55); margin-bottom: 6px; }

/* CTA */
.rp-docs-cta {
  margin: 44px 0 0; padding: 26px 30px; background: #F1FB6D;
  display: flex; align-items: center; justify-content: space-between; gap: 24px; flex-wrap: wrap;
}
.rp-docs-cta-text { font: 400 15px/1.55 "Space Grotesk", sans-serif; color: #132C5F; max-width: 480px; }
.rp-docs-cta-btn {
  flex: none; padding: 14px 22px; background: #132C5F; color: #fff; text-decoration: none;
  font: 600 13px/1 "Space Grotesk", sans-serif; letter-spacing: .06em; text-transform: uppercase;
}
.rp-docs-cta-btn:hover { background: #0d1f45; }

/* channel + home pages */
.rp-docs-kicker { display: inline-block; padding: 6px 12px 5px; font: 600 12px/1 "Space Grotesk", sans-serif; letter-spacing: .08em; text-transform: uppercase; color: #132C5F; }
.rp-docs-accent-mint { background: #B9F0E7; }
.rp-docs-accent-green { background: #9EE89B; }
.rp-docs-accent-yellow { background: #F1FB6D; }
.rp-docs-accent-pink { background: #F8C0FF; }
.rp-docs-section-title { font: 600 22px/1.25 "Space Grotesk", sans-serif; color: #132C5F; margin: 40px 0 18px; }
.rp-docs-cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 16px; }
.rp-docs-card {
  display: flex; flex-direction: column; gap: 10px; padding: 22px; background: #fff;
  border: 1px solid rgba(19,44,95,.18); text-decoration: none; transition: transform .16s ease, box-shadow .16s ease;
}
.rp-docs-card:hover { transform: translateY(-3px); box-shadow: 0 12px 28px rgba(19,44,95,.12); }
.rp-docs-card h3 { font: 600 17px/1.3 "Space Grotesk", sans-serif; color: #132C5F; margin: 0; }
.rp-docs-card p { font: 400 13px/1.55 "Space Grotesk", sans-serif; color: rgba(19,44,95,.7); margin: 0; }
.rp-docs-card .rp-docs-chip { align-self: flex-start; }
.rp-docs-card-arrow { margin-top: auto; font: 600 13px/1 "Space Grotesk", sans-serif; color: #132C5F; }

.rp-docs-home { max-width: 1280px; margin: 0 auto; padding: 0 40px; }
.rp-docs-home-head { max-width: 720px; margin-bottom: 48px; }
/* .chips is display:flex, which as a plain block box stretches to its
   parent's width by default; on marketing pages it only looks pill-sized
   because it sits inside a flex column with align-items:flex-start.
   rp-docs-home-head has no such flex context, so pin the chip's width to
   its content directly. */
.rp-docs-home-head .chips { width: fit-content; }
.rp-docs-home-h1 { margin-top: 22px; }
.rp-docs-channelgrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 18px; }
.rp-docs-channelcard {
  position: relative; overflow: hidden; display: flex; flex-direction: column; gap: 12px;
  padding: 30px 26px 26px; text-decoration: none; border: 1px solid rgba(19,44,95,.18);
  transition: transform .16s ease, box-shadow .16s ease; min-height: 190px;
}
.rp-docs-channelcard:hover { transform: translateY(-3px); box-shadow: 0 14px 30px rgba(19,44,95,.14); }
.rp-docs-channelcard h2 { font: 600 21px/1.2 "Space Grotesk", sans-serif; color: #132C5F; margin: 0; }
.rp-docs-channelcard p { font: 400 13px/1.55 "Space Grotesk", sans-serif; color: rgba(19,44,95,.75); margin: 0; }
.rp-docs-channelcard-shape { position: absolute; top: -30px; right: -30px; width: 90px; height: 90px; background: rgba(255,255,255,.5); transform: rotate(45deg); }
.rp-docs-start { margin: 56px 0 0; }
.rp-docs-startlinks { display: flex; flex-direction: column; }
.rp-docs-startlink {
  padding: 16px 0; border-bottom: 1px solid rgba(19,44,95,.15); text-decoration: none;
  font: 600 17px/1.3 "Space Grotesk", sans-serif; color: #132C5F;
}
.rp-docs-startlink:hover { padding-left: 8px; }

/* responsive */
@media (max-width: 991px) {
  .rp-docs-shell { grid-template-columns: 1fr; gap: 24px; padding: 0 24px; }
  .rp-docs-home { padding: 0 24px; }
  .rp-docs-sidebar { position: static; border-right: 0; padding-right: 0; margin-top: 0; padding-top: 0; margin-bottom: 0; padding-bottom: 0; }
  .rp-docs-side-inner { position: static; }
  .rp-docs-article { padding-left: 0; }
  .rp-docs-side-toggle {
    display: block; width: 100%; padding: 12px 16px; background: #fff;
    border: 1px solid rgba(19,44,95,.25); font: 600 13px/1 "Space Grotesk", sans-serif;
    letter-spacing: .06em; text-transform: uppercase; color: #132C5F; text-align: left; cursor: pointer;
  }
  .rp-docs-side-toggle::after { content: " +"; }
  .rp-docs-side-toggle[aria-expanded="true"]::after { content: " −"; }
  .rp-docs-side-inner { display: none; padding: 16px; background: #fff; border: 1px solid rgba(19,44,95,.25); border-top: 0; }
  .rp-docs-sidebar.is-open .rp-docs-side-inner { display: block; }
  .rp-docs .rp-docs-main { padding-top: 120px; }
  .rp-docs-prevnext { grid-template-columns: 1fr; }
}

@media (prefers-reduced-motion: reduce) {
  .rp-docs-card, .rp-docs-channelcard, .rp-docs-startlink { transition: none; }
  .rp-docs-card:hover, .rp-docs-channelcard:hover { transform: none; }
}


/* ══════════════════════════════════════════════════════════════════════════
   32. WEBFLOW CDN INDEPENDENCE
   Every Webflow-hosted asset has been downloaded to images/wf/ and every
   reference rewritten to a root-absolute /images/wf/... path, so the site no
   longer depends on Webflow's asset CDN. Root-absolute (not relative) because
   pages sit at four different depths and the site always serves from the
   domain root. (Hostname deliberately not spelled out here, so a grep for it
   across the repo stays a clean signal.)

   Three url() references remain inside css/rp-ltd.webflow.min.css, which is
   off-limits by project rule (never hand-edit the Webflow export). Two of them
   (.comparison-positive / .comparison-negative) point at a different Webflow
   site entirely and those classes appear nowhere in our markup, so they never
   fetch — left alone deliberately rather than adding dead CSS for dead
   classes. The third IS live: it's the dropdown chevron on <select>, used by
   the contact form's Inquiry Type field. Re-point it at the local copy here.
   ══════════════════════════════════════════════════════════════════════════ */
.input.select {
  background-image: url(/images/wf/67272f9741f0c324a9189910_67272f9741f0c324a91899ca_Chevron-Down.svg);
}
