/* =================================================================
   Reachly ROI calculator - visual layer, dual theme
   Paste inside a <style> tag in the page's custom code (head).
   Overrides the Webflow classes already on the page.

   Every colour is a token on .content-roi. The dark palette swaps the
   token values only, so there is one set of rules for both themes.
   Theme is set by data-roi-theme="light|dark" on .content-roi (JS).

   Radius system, applied everywhere with no exceptions:
     panel 28px | cards 16px | inputs + bars 12px | pills and thumbs 999px
   ================================================================= */

/* `.rly-pagehead` is listed here so the title lifted OUT of the panel still
   resolves the type ramp and the palette. It deliberately does NOT appear on
   the `[data-roi-theme="dark"]` block below, so it keeps the light values in
   both themes: the page around the card stays lavender when the card goes
   dark, and near-white type on lavender would be unreadable. */
.content-roi,
.rly-pagehead {
  /* ---- type ramp -------------------------------------------------
     Fixed rem scale anchored at 1rem = 16px. Four roles carry the
     whole widget; hierarchy below body comes from weight and colour,
     not from more sizes. Type is Poppins throughout, numerals included:
     figures get weight 700 and tabular-nums rather than a second family. */
  --roi-text-caption: 0.8125rem;     /* 13px   - labels, hints, legend   */
  --roi-text-body: 1rem;             /* 16px   - labels, values, inputs  */
  --roi-text-lead: 1.125rem;         /* 18px   - lead paragraph          */
  --roi-text-stat: 1.625rem;         /* 26px   - secondary stat figures  */
  --roi-text-display: clamp(2.5rem, 5vw, 3.5rem);   /* 40-56px hero ROI  */
  --roi-text-title: clamp(2.25rem, 4.5vw, 3.25rem); /* 36-52px page H1   */

  /* ---- spacing scale ---------------------------------------------
     4px base. Structural spacing (card padding, group and column gaps,
     row rhythm) comes from here; anything below 4px, and the 6-7px inline
     gaps inside pills and legends, stay as optical detail rather than
     layout. Before this the panel painted 25 distinct spacing values,
     nearly every integer from 1 to 20. */
  --roi-space-1: 4px;
  --roi-space-2: 8px;
  --roi-space-3: 12px;
  --roi-space-4: 16px;
  --roi-space-5: 20px;
  --roi-space-6: 24px;
  --roi-space-7: 28px;
  --roi-space-8: 32px;

  --roi-leading-tight: 1.1;
  --roi-leading-body: 1.55;

  --roi-sans: Poppins, system-ui, -apple-system, sans-serif;

  /* ---- volume-ramp series ----------------------------------------
     Two stacked purples, the same pair the proposal deck's forecast
     slide uses. Email is the deep stop, LinkedIn the light one. */
  --roi-vol-em-a: #8B63F0;
  --roi-vol-em-b: #5A32B8;
  --roi-vol-li-a: #D6C4FF;
  --roi-vol-li-b: #A587FF;

  /* Hero fill, tokenised so the dark theme can lift it. Was three raw
     hexes in a rule, which is why it used to be the one region of the
     widget that could not re-theme. */
  /* The light stop sets the worst case for every piece of type on the card.
     #8F63EC left the supporting line at 4.39:1, which looked fine and was
     not, so the stop is capped where that line clears 4.5:1. */
  /* One flat brand purple, not a three-stop ramp. A gradient between three
     shades of the same hue carries no information; it is the single most
     recognisable generated-UI tell, and the brand is one purple. */
  --roi-hero-fill: #7B4DE0;
  --roi-hero-fill-neg: #2E2A38;
  --roi-hero-ink: #FFFFFF;
  --roi-hero-ink-2: #F7F4FE;

  /* ---- radius ---------------------------------------------------- */
  --roi-r-panel: 28px;
  --roi-r-card: 16px;
  --roi-r-input: 12px;

  /* ---- motion ---------------------------------------------------- */
  --roi-ease: cubic-bezier(0.2, 0, 0, 1);
  --roi-dur: 180ms;

  /* ---- light palette (default) ----------------------------------- */
  --roi-panel: #FFFFFF;
  --roi-panel-tint: transparent;
  --roi-surface: #FFFFFF;
  --roi-field: #FFFFFF;
  --roi-hairline: rgba(34, 31, 46, 0.08);
  --roi-hairline-strong: rgba(34, 31, 46, 0.16);
  --roi-ink: #221F2E;
  --roi-ink-2: #45414F;
  --roi-ink-3: #5E5A6B;
  --roi-accent: #7B4DE0;
  --roi-accent-2: #9B74EE;
  --roi-accent-text: #6A3ACF;
  --roi-accent-wash: #EBE6FD;
  --roi-accent-veil: rgba(123, 77, 224, 0.12);
  --roi-negative: #B3261E;
  --roi-pill: #7B4DE0;

  --roi-shadow-panel:
    0 1px 2px rgba(34, 31, 46, 0.04),
    0 24px 60px -24px rgba(34, 31, 46, 0.18);
  /* One elevation, not two. This carried a 1px hairline ring AND a wide
     soft lift, which is the ghost card: the edge and the shadow each claim
     to be the thing separating the card from the panel. The lift is the
     honest one here (these cards float on a panel, they are not inset), so
     the ring goes and the lift darkens slightly to hold the edge alone. */
  --roi-shadow-card:
    0 1px 2px rgba(34, 31, 46, 0.05),
    0 6px 16px -6px rgba(34, 31, 46, 0.14);
  --roi-shadow-field:
    0 0 0 1px rgba(34, 31, 46, 0.08),
    0 1px 2px rgba(34, 31, 46, 0.04);
  --roi-shadow-field-hover:
    0 0 0 1px rgba(34, 31, 46, 0.16),
    0 1px 2px rgba(34, 31, 46, 0.05),
    0 4px 10px rgba(34, 31, 46, 0.05);
  /* The thumb already has a real 3px ring border. A purple halo under it
     made three edge treatments on one 20px control. */
  --roi-shadow-thumb:
    0 2px 6px rgba(34, 31, 46, 0.22);
  --roi-thumb-ring: #FFFFFF;

  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  font-kerning: normal;
}

/* ---- dark palette ------------------------------------------------
   Off-black with a purple cast, never pure #000. The brand purple
   stays the fill colour; text-on-dark uses a lifted tint of it so
   figures clear WCAG AA against the card surface. */
.content-roi[data-roi-theme="dark"] {
  --roi-panel: #14111E;
  --roi-panel-tint: rgba(123, 77, 224, 0.10);
  --roi-surface: #1B1728;
  --roi-field: #221D31;
  --roi-hairline: rgba(255, 255, 255, 0.09);
  --roi-hairline-strong: rgba(255, 255, 255, 0.20);
  --roi-ink: #F3F1F9;
  --roi-ink-2: #C4BFD4;
  --roi-ink-3: #9B94AE;
  --roi-accent: #8B5CF0;
  --roi-accent-2: #B79AF5;
  --roi-accent-text: #BEA2F7;
  --roi-accent-wash: rgba(139, 92, 240, 0.20);
  --roi-accent-veil: rgba(139, 92, 240, 0.16);
  --roi-negative: #FF9B8F;
  /* The accent is the pill fill, and white on it is 4.30:1 at 11px. Small
     white-on-purple gets a deeper token of its own. */
  --roi-pill: #5E33C4;

  --roi-shadow-panel:
    0 1px 0 rgba(255, 255, 255, 0.04) inset,
    0 30px 80px -30px rgba(8, 6, 14, 0.9);
  /* Dark keeps a hairline instead of the lift: on a near-black panel a drop
     shadow has nothing to darken, so the edge IS the elevation here. Still
     one declaration, just the opposite one from light. */
  --roi-shadow-card:
    0 0 0 1px rgba(255, 255, 255, 0.08),
    0 1px 2px rgba(0, 0, 0, 0.3);
  --roi-shadow-field:
    0 0 0 1px rgba(255, 255, 255, 0.09),
    0 1px 2px rgba(0, 0, 0, 0.25);
  --roi-shadow-field-hover:
    0 0 0 1px rgba(255, 255, 255, 0.20),
    0 1px 2px rgba(0, 0, 0, 0.3),
    0 4px 10px rgba(0, 0, 0, 0.3);
  --roi-shadow-thumb:
    0 2px 8px rgba(0, 0, 0, 0.6);
  --roi-thumb-ring: #14111E;

  --roi-vol-em-a: #9B74EE;
  --roi-vol-em-b: #6438C6;
  --roi-vol-li-a: #E2D4FF;
  --roi-vol-li-b: #B294FA;

  /* Deeper than the light fill, and deeper than it first looks like it needs
     to be. The dark panel runs 6:1 to 16.6:1 everywhere else, so a mid-purple
     made the hero the LOWEST-contrast region on the page while being its most
     important element: white read 6.73 and the supporting ink 5.49, under even
     the quietest label elsewhere. At #4C2596 those become 10.44 and 8.51, and
     the block still separates from the panel at 1.78. */
  --roi-hero-fill: #4C2596;
  --roi-hero-fill-neg: #24202D;
  --roi-hero-ink: #FFFFFF;
  --roi-hero-ink-2: #EDE4FE;
}

/* Webflow puts overflow:hidden on .section, which makes that element a
   scroll container that never scrolls. Every position:sticky inside it is
   therefore stuck to a box that does not move, so the desktop hero never
   travelled and the running total never pinned. Clip on x only, which keeps
   the original intent of stopping decorative horizontal overflow, and leave
   y visible so sticky resolves against the viewport. Scoped with :has so no
   other section on the site is touched. */
.section:has(.content-roi) {
  overflow-x: clip;
  overflow-y: visible;
}

/* ================================================================
   the panel
   ================================================================ */

/* The widget is a panel in both themes, so only the palette changes
   between them. Webflow already sets flex-column + 40px side padding. */
.content-roi {
  isolation: isolate;
  border-radius: var(--roi-r-panel);
  background: var(--roi-panel);
  box-shadow: var(--roi-shadow-panel);
  padding: var(--roi-space-5) var(--roi-space-8) var(--roi-space-8) !important;
  color: var(--roi-ink);
  font-family: var(--roi-sans);
  transition: background-color 260ms var(--roi-ease),
              box-shadow 260ms var(--roi-ease);
}

/* Grid and glow so the dark panel is not a dead flat rectangle.
   Both are painted from the panel tint, so light mode gets nothing. */
.content-roi::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: inherit;
  background-image:
    radial-gradient(80% 60% at 88% -6%, var(--roi-panel-tint) 0%, transparent 70%),
    linear-gradient(var(--roi-hairline) 1px, transparent 1px),
    linear-gradient(90deg, var(--roi-hairline) 1px, transparent 1px);
  background-size: auto, 44px 44px, 44px 44px;
  mask-image: radial-gradient(90% 70% at 84% 0%, #000 0%, transparent 76%);
  -webkit-mask-image: radial-gradient(90% 70% at 84% 0%, #000 0%, transparent 76%);
  opacity: 0;
  transition: opacity 260ms var(--roi-ease);
  pointer-events: none;
}

.content-roi[data-roi-theme="dark"]::before { opacity: 1; }

.content-roi .roi-form-calculator { width: 100%; }

/* ---- page head (outside the panel) -------------------------------- */

/* The title and standfirst sit on the page, above the card. They are OUTSIDE
   the theme scope on purpose: `.content-roi[data-roi-theme]` repaints the card
   only, so the ground out here is the light lavender page in both themes and
   these colours are fixed rather than tokenised. */
.rly-pagehead {
  width: 100%;
  margin: 0 auto 22px;
  text-align: center;
}

.rly-pagehead h1,
.rly-pagehead .heading-style-h2,
.rly-pagehead .heading-style-h2.white {
  margin: 0;
  font-family: var(--roi-sans);
  font-size: var(--roi-text-title);
  font-weight: 800;
  line-height: var(--roi-leading-tight);
  letter-spacing: -0.03em;
  /* .white is a Webflow class hard-setting #fff, which was only ever legible
     against the old page background. Drive it from the token, which out here
     never flips to the dark palette. */
  color: var(--roi-ink) !important;
  text-align: center;
  text-wrap: balance;
}

.rly-pagehead .paragraph,
.rly-pagehead p {
  max-width: 58ch;
  margin: 10px auto 0;
  font-family: var(--roi-sans);
  font-size: var(--roi-text-lead);
  font-weight: 300;
  line-height: 1.5;
  color: var(--roi-ink-2);
  text-align: center;
  text-wrap: pretty;
}

/* ---- header (what is left inside the panel) ----------------------- */

/* Only `.rly-controls` lives here now, so it stops being a stacked header
   block and becomes a chrome row sitting to the right of the panel's top
   edge, out of the way of the first input. */
.content-roi .content-header-wrap {
  width: 100%;
  padding: 0 0 var(--roi-space-3) !important;
}

.content-roi .content-header-wrap .rly-controls {
  justify-content: flex-end;
}

/* .white on the h1 is a Webflow class hard-setting #fff, which only
   worked against the old page background. Drive it from the token. */
.content-roi h1,
.content-roi .heading-style-h2,
.content-roi .heading-style-h2.white {
  font-family: var(--roi-sans);
  font-size: var(--roi-text-title);
  font-weight: 800;
  line-height: var(--roi-leading-tight);
  letter-spacing: -0.03em;
  color: var(--roi-ink);
  text-wrap: balance;
}

.content-roi h2 { text-wrap: balance; color: var(--roi-ink); }

.content-roi .paragraph.center {
  font-family: var(--roi-sans);
  font-size: var(--roi-text-lead);
  font-weight: 300;
  line-height: 1.5;
  color: var(--roi-ink-2);
  max-width: 58ch;
  margin-left: auto;
  margin-right: auto;
  text-wrap: pretty;
}

/* The control row holds the help toggle and the theme switch. JS moves
   the existing .toggle-wrapper in here so the two sit on one line. */
.rly-controls {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: var(--roi-space-2) var(--roi-space-5);
  width: 100%;
}

.rly-controls .toggle-wrapper {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  min-height: 44px;
  padding: 0 4px;
  cursor: pointer;
  float: none;
  /* Webflow ships this with `margin-left: auto` as its float-right stand-in.
     Inside a flex row that auto margin eats the free space, so the item pins
     to the right edge and `justify-content` on the parent has nothing left to
     centre -- visible as soon as the row wraps on a phone. */
  margin: 0;
}

/* w-clearfix adds ::before and ::after table boxes. Inside a flex wrapper
   they become flex items and push the label off centre. */
.rly-controls .toggle-wrapper::before,
.rly-controls .toggle-wrapper::after { content: none; }

/* ---- theme switch ------------------------------------------------ */

.rly-theme {
  position: relative;
  display: inline-flex;
  align-items: center;
  padding: 3px;
  border-radius: 999px;
  background: var(--roi-accent-veil);
  box-shadow: 0 0 0 1px var(--roi-hairline);
}

/* The travelling pill. Two options, so 50% wide, 100% of travel. */
.rly-theme::before {
  content: "";
  position: absolute;
  top: 3px;
  bottom: 3px;
  left: 3px;
  width: calc(50% - 3px);
  border-radius: 999px;
  background: var(--roi-surface);
  box-shadow: var(--roi-shadow-field);
  transform: translateX(calc(var(--rly-theme-i, 0) * 100%));
  transition: transform 260ms var(--roi-ease);
}

.rly-theme-btn {
  position: relative;
  z-index: 1;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-width: 84px;
  min-height: 44px;
  justify-content: center;
  padding: 7px 14px;
  border: 0;
  border-radius: 999px;
  background: transparent;
  font-family: var(--roi-sans);
  font-size: var(--roi-text-caption);
  font-weight: 500;
  color: var(--roi-ink-3);
  cursor: pointer;
  transition: color var(--roi-dur) var(--roi-ease);
}

.rly-theme-btn[aria-checked="true"] { color: var(--roi-ink); font-weight: 600; }
.rly-theme-btn:hover { color: var(--roi-ink-2); }
.rly-theme-btn svg { width: 14px; height: 14px; flex: none; }

.rly-theme-btn:focus-visible {
  outline: 2px solid var(--roi-accent);
  outline-offset: 2px;
}

/* ================================================================
   left column: inputs
   ================================================================ */

/* ================================================================
   left column: the form
   ================================================================
   One row is label / control / hint, on a two-column grid so every
   label sits on the same axis as the control it names. Each label
   points at its own input, which the source markup did not.  */

.rly-form {
  display: flex;
  flex-direction: column;
  /* Group separation. The heading must read as belonging to what follows,
     so the space above it beats the space below: 28 + the previous row's 8
     is 36 above, against 8 + 4 + 8 = 20 below. */
  gap: var(--roi-space-7);
  font-family: var(--roi-sans);
}

.rly-group {
  display: flex;
  flex-direction: column;
}

/* Named groups. The source separated these with unlabelled hairlines,
   so the visitor could see there was structure and could not read it. */
.rly-group-t {
  margin: 0 0 var(--roi-space-1);
  padding-bottom: var(--roi-space-2);
  border-bottom: 1px solid var(--roi-hairline);
  font-family: var(--roi-sans);
  font-size: 0.8125rem;
  font-weight: 600;
  line-height: 1.3;
  letter-spacing: 0.02em;
  color: var(--roi-ink-3);
}

/* A FIXED label column, not a share of the row. A fractional split parked
   short labels at the far left of a 313px cell with the control at the far
   right of the next, and that gap is what read as dead space. 14.75rem is the
   longest label ("Connection acceptance rate", 228px) plus a little, so every
   row aligns, nothing wraps, and the control sits as close as the widest label
   allows. Anything narrower needs the copy to get shorter first. */
.rly-in {
  display: grid;
  grid-template-columns: 14.75rem minmax(0, 1fr);
  align-items: center;
  column-gap: var(--roi-space-5);
  padding: var(--roi-space-2) 0;
}

.rly-in-l {
  grid-column: 1;
  font-size: var(--roi-text-body);
  font-weight: 500;
  line-height: var(--roi-leading-body);
  letter-spacing: -0.01em;
  color: var(--roi-ink);
  cursor: pointer;
}

.rly-in-c {
  grid-column: 2;
  display: flex;
  align-items: center;
  gap: 12px;
  min-width: 0;
}

/* Hints and cap notes live under the control, and collapse to nothing
   with help off. Grid rows rather than a max-height, so a long hint can
   never be clipped by a magic number. */
.rly-in-h,
.rly-cap {
  grid-column: 2;
  display: grid;
  grid-template-rows: 0fr;
  margin: 0;
  font-size: var(--roi-text-caption);
  font-weight: 300;
  line-height: var(--roi-leading-body);
  color: var(--roi-ink-3);
  max-width: 62ch;
  text-wrap: pretty;
  opacity: 0;
  /* grid-template-rows and opacity only. Animating padding-top as well made
     every one of these an animated layout property for no visible gain. */
  transition: grid-template-rows 260ms var(--roi-ease),
              opacity 200ms var(--roi-ease);
}

.rly-in-h > *,
.rly-cap > * { overflow: hidden; }

.content-roi.is-help .rly-in-h,
.content-roi.is-help .rly-cap {
  grid-template-rows: 1fr;
  padding-top: 7px;
  opacity: 1;
}

/* A capped rate is an operating fact, so it reads in the accent rather
   than as an error. */
.rly-cap { color: var(--roi-accent-text); font-weight: 400; }

/* The slider and its typed value are one control sharing one cell.
   44px tall so the whole row is the hit area on a phone. */
.rly-slider {
  flex: 1 1 0;
  min-width: 60px;
  display: flex;
  align-items: center;
  height: 44px;
}

/* ---- the derived read-out -----------------------------------------
   LinkedIn DM volume is a consequence of the three fields above it, so
   it is rendered as a result and never as something to type into. */
.rly-derived {
  display: grid;
  grid-template-columns: 14.75rem minmax(0, 1fr);
  align-items: center;
  column-gap: var(--roi-space-5);
  /* Sits in the row stack, so it keeps the row stack's rhythm: the 6/2 it
     used to carry was the only pair in the column that was not symmetric. */
  margin: var(--roi-space-1) 0;
  padding: var(--roi-space-3) var(--roi-space-4);
  border-radius: var(--roi-r-input);
  background: var(--roi-accent-wash);
}

.rly-derived-l {
  grid-column: 1;
  font-size: 0.9375rem;
  font-weight: 600;
  line-height: 1.35;
  color: var(--roi-accent-text);
}

.rly-derived-v {
  grid-column: 2;
  font-size: 1.125rem;
  font-weight: 700;
  color: var(--roi-accent-text);
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
}

.rly-derived-h {
  grid-column: 1 / -1;
  display: grid;
  grid-template-rows: 0fr;
  /* Same measure cap as .rly-help. Without it this one ran to 98 characters
     at desktop, well past the ~80ch the eye can track back from. */
  max-width: 62ch;
  font-size: var(--roi-text-caption);
  font-weight: 300;
  line-height: var(--roi-leading-body);
  color: var(--roi-accent-text);
  opacity: 0;
  /* grid-template-rows and opacity only. Animating padding-top as well made
     every one of these an animated layout property for no visible gain. */
  transition: grid-template-rows 260ms var(--roi-ease),
              opacity 200ms var(--roi-ease);
}

.rly-derived-h > * { overflow: hidden; }

.content-roi.is-help .rly-derived-h {
  grid-template-rows: 1fr;
  padding-top: 6px;
  opacity: 1;
}

/* ---- text and percent fields ------------------------------------ */

.text-field-roi.w-input,
.text-field-roi {
  height: 44px;
  border: 0 !important;
  border-radius: var(--roi-r-input) !important;
  background: var(--roi-field);
  box-shadow: var(--roi-shadow-field);
  font-family: var(--roi-sans);
  font-size: 0.9375rem;
  font-weight: 500;
  color: var(--roi-ink);
  font-variant-numeric: tabular-nums;
  padding: 0 14px;
  transition: box-shadow var(--roi-dur) var(--roi-ease),
              background-color 260ms var(--roi-ease),
              color 260ms var(--roi-ease);
}

.text-field-roi::placeholder {
  font-family: var(--roi-sans);
  font-weight: 400;
  color: var(--roi-ink-3);
  opacity: 1;
}

.text-field-roi:hover { box-shadow: var(--roi-shadow-field-hover); }

.text-field-roi:focus {
  outline: none;
  box-shadow:
    0 0 0 1px var(--roi-accent),
    0 0 0 4px var(--roi-accent-veil);
}

.text-field-roi.input-percent {
  flex: 0 0 auto;
  width: 104px;
  min-width: 92px;
  text-align: center;
  font-weight: 600;
  padding-left: 6px;
  padding-right: 6px;
}

/* ---- sliders ----------------------------------------------------
   The element itself is the hit area and paints nothing; the visible
   6px track is drawn by the track pseudo-element. --rly-p is the fill
   percentage, set in JS. 44px tall so a thumb is reachable on a phone. */

.content-roi input[type="range"] {
  -webkit-appearance: none;
  appearance: none;
  display: block;
  width: 100%;
  /* One height declaration, and it is the tap target. */
  height: 44px;
  background: transparent !important;
  border: 0 !important;
  border-radius: 0 !important;
  padding: 0 !important;
  margin: 0 !important;
  min-height: 0;
  cursor: pointer;
  outline: none;
  box-shadow: none !important;
}

.content-roi input[type="range"]::-webkit-slider-runnable-track {
  height: 6px;
  border-radius: 999px;
  background: linear-gradient(
    to right,
    var(--roi-accent) var(--rly-p, 0%),
    var(--roi-accent-wash) var(--rly-p, 0%)
  );
}

.content-roi input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  height: 20px;
  width: 20px;
  /* centre the 20px thumb on the 6px track */
  margin-top: -7px;
  border-radius: 50%;
  background: var(--roi-accent);
  border: 3px solid var(--roi-thumb-ring);
  box-shadow: var(--roi-shadow-thumb);
  transition: transform var(--roi-dur) var(--roi-ease),
              box-shadow var(--roi-dur) var(--roi-ease);
}

.content-roi input[type="range"]::-moz-range-track {
  height: 6px;
  border-radius: 999px;
  background: var(--roi-accent-wash);
}

.content-roi input[type="range"]::-moz-range-progress {
  height: 6px;
  border-radius: 999px;
  background: var(--roi-accent);
}

.content-roi input[type="range"]::-moz-range-thumb {
  height: 14px;
  width: 14px;
  border-radius: 50%;
  background: var(--roi-accent);
  border: 3px solid var(--roi-thumb-ring);
  box-shadow: var(--roi-shadow-thumb);
}

.content-roi input[type="range"]:hover::-webkit-slider-thumb { transform: scale(1.1); }

.content-roi input[type="range"]:active::-webkit-slider-thumb {
  transform: scale(0.96);
  box-shadow:
    0 0 0 1px var(--roi-accent),
    0 0 0 8px var(--roi-accent-veil);
}

.content-roi input[type="range"]:focus-visible::-webkit-slider-thumb {
  box-shadow:
    0 0 0 2px var(--roi-thumb-ring),
    0 0 0 5px var(--roi-accent);
}

.content-roi input[type="range"]:focus-visible::-moz-range-thumb {
  box-shadow:
    0 0 0 2px var(--roi-thumb-ring),
    0 0 0 5px var(--roi-accent);
}

/* Firefox draws no track height of its own once the host is 44px. */
.content-roi input[type="range"]::-moz-range-thumb { height: 18px; width: 18px; }

/* ---- duration: discrete stops ----------------------------------- */

.rly-duration-out {
  font-family: var(--roi-sans);
  font-size: 0.9375rem;
  font-weight: 600;
  color: var(--roi-ink);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  min-width: 88px;
  text-align: right;
}

/* The duration cell stacks the track over its tick marks, with the month
   readout parked to the right. The hint no longer crosses the track,
   because the row is a grid we own rather than a Webflow layout cell. */
.rly-slider.is-duration {
  flex-direction: column;
  align-items: stretch;
  justify-content: center;
  height: auto;
  padding: 3px 0 2px;
}

/* Six stops, so the slider reads as a set of months rather than a
   continuous dial. Marks sit under the track and light up as passed. */
.rly-ticks {
  display: flex;
  justify-content: space-between;
  margin: -6px 10px 0;
}

.rly-tick {
  width: 2px;
  height: 6px;
  border-radius: 999px;
  background: var(--roi-accent-wash);
  transition: background-color var(--roi-dur) var(--roi-ease);
}

.rly-tick.is-on { background: var(--roi-accent); }

/* ================================================================
   right column: results
   ================================================================ */

.rly-results {
  display: flex;
  flex-direction: column;
  gap: var(--roi-space-3);
  font-family: var(--roi-sans);
  -webkit-font-smoothing: antialiased;
}

/* Card heads and stat labels share one style. Sentence case, not a
   fifth uppercase micro-label stacked down the column. */
.rly-card-title {
  font-size: var(--roi-text-caption);
  font-weight: 600;
  line-height: 1.3;
  letter-spacing: -0.005em;
  color: var(--roi-ink-3);
}

/* --- hero: the one number that matters ---
   Sticky on desktop so the figure stays in view while the sliders
   further down the form are being dragged. */

.rly-hero {
  position: relative;
  overflow: hidden;
  border-radius: var(--roi-r-card);
  padding: var(--roi-space-6) var(--roi-space-5);
  background: var(--roi-hero-fill);
  /* Ink-tinted elevation, one step above the cards beside it, in the same
     language as they use. The old shadow was a 50%-alpha violet bloom plus a
     glassy inset top edge: a glow and a highlight, neither of which is depth. */
  box-shadow:
    0 1px 2px rgba(34, 31, 46, 0.06),
    0 10px 24px -8px rgba(34, 31, 46, 0.20);
  color: var(--roi-hero-ink);
  transition: background 300ms var(--roi-ease), box-shadow 300ms var(--roi-ease);
}

/* A campaign that loses money should not be congratulated in full purple.
   The fill drains to the panel's own ink and the figure turns. */
.rly-hero.is-negative {
  background: var(--roi-hero-fill-neg);
}

/* The grid that used to live here was commented "keeps the flat purple from
   looking dead", which is decoration hired to cover a composition problem: the
   figure painted 151px wide on a 450px line and left 299px of empty fill. The
   fix is to give that line something to say, not something to look at, so the
   figure now carries a label on its baseline and the grid is gone. */

.rly-hero > * { position: relative; }

/* Figure and its unit share a baseline, so the headline reads as one phrase
   and fills the line it sits on. */
.rly-hero-head {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 0 var(--roi-space-3);
}

.rly-hero-unit {
  font-family: var(--roi-sans);
  font-size: var(--roi-text-lead);
  font-weight: 400;
  letter-spacing: -0.01em;
  color: var(--roi-hero-ink-2);
}

.rly-hero-value {
  font-family: var(--roi-sans);
  font-size: var(--roi-text-display);
  line-height: var(--roi-leading-tight);
  font-weight: 800;
  /* Poppins ExtraBold needs less negative tracking than the mono face did. */
  letter-spacing: -0.03em;
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
}

/* The sentence that says what the multiple means. This used to be hidden
   behind the help toggle, which is where the least believable number on
   the page kept its own explanation. */
.rly-hero-sub {
  margin: 10px 0 0;
  max-width: 44ch;
  font-size: 0.9375rem;
  font-weight: 300;
  line-height: var(--roi-leading-body);
  color: var(--roi-hero-ink-2);
  text-wrap: pretty;
}

.rly-hero-sub b {
  font-weight: 700;
  color: var(--roi-hero-ink);
  font-variant-numeric: tabular-nums;
}

.rly-hero-sub b#rlyMonths { font-weight: 600; }

/* --- two secondary stats --- */

.rly-split {
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-template-rows: auto auto auto;
  /* row-gap 0 on purpose. `gap` on a row grid gaps the ROWS too, and the
     subgrid below inherits those tracks, so a plain `gap: 12px` silently
     added 24px of air inside each card between label, figure and hint. */
  column-gap: 12px;
  row-gap: 0;
}

/* Label / figure / hint are three shared rows, so a label that wraps at a
   narrow width lifts BOTH figures together and neither card pads itself. */
.rly-split > .rly-stat {
  grid-row: span 3;
  display: grid;
  grid-template-rows: subgrid;
  align-content: start;
}

.rly-stat {
  border-radius: var(--roi-r-card);
  padding: var(--roi-space-4) var(--roi-space-5);
  background: var(--roi-surface);
  box-shadow: var(--roi-shadow-card);
  transition: background-color 260ms var(--roi-ease),
              box-shadow 260ms var(--roi-ease);
}

.rly-stat-l {
  display: block;
  font-size: var(--roi-text-caption);
  font-weight: 600;
  color: var(--roi-ink-3);
  /* The two figures share a baseline because the cards share row tracks via
     subgrid, not because the label reserves a second line. The old
     `min-height: 2.6em` fired even when both labels fit on one line, which is
     every desktop width, so each card carried a blank line it never used. */
  line-height: 1.3;
  text-wrap: balance;
}

.rly-stat-v {
  display: block;
  margin-top: 6px;
  font-family: var(--roi-sans);
  font-size: var(--roi-text-stat);
  font-weight: 600;
  line-height: var(--roi-leading-tight);
  letter-spacing: -0.03em;
  color: var(--roi-ink);
  font-variant-numeric: tabular-nums;
}

.rly-stat-v.is-negative { color: var(--roi-negative); }

/* ================================================================
   revenue against spend
   ================================================================ */

/* The time series sits on its own row under both columns, so it gets the
   full width of the panel instead of the narrow results column. The volume
   ramp stays in the results column above the funnel, where it reads as the
   cause of the numbers under it. */
/* Webflow's own stylesheet splits this grid 1.75fr/1fr, which was wrong in
   both directions: it left a ~155px canyon between every label and its
   control, and it squeezed the volume ramp and the funnel into the narrower
   column. Pulling width across closes the canyon and gives the charts room.

   MUST stay inside a min-width query. Webflow collapses this grid to a single
   column at max-width 767px, and an unconditional `!important` here overrides
   that, leaving two ~150px columns on a phone with the month ticks colliding
   and the hero copy breaking one word per line. */
@media screen and (min-width: 768px) {
  .content-roi .roi-form {
    grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr) !important;
    /* Webflow ships 30px here; the scale step is 32. */
    gap: var(--roi-space-8);
  }
}

.roi-form .rly-chart-row { grid-column: 1 / -1; }

.rly-chart {
  border-radius: var(--roi-r-card);
  padding: var(--roi-space-4) var(--roi-space-5);
  background: var(--roi-surface);
  box-shadow: var(--roi-shadow-card);
  transition: background-color 260ms var(--roi-ease),
              box-shadow 260ms var(--roi-ease);
}

.rly-chart-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  margin-bottom: 14px;
}

.rly-legend {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  font-size: 0.75rem;
  font-weight: 500;
  color: var(--roi-ink-3);
  white-space: nowrap;
}

.rly-legend-i { display: inline-flex; align-items: center; gap: 5px; }

.rly-legend-i::before {
  content: "";
  width: 14px;
  height: 2px;
  border-radius: 999px;
  background: var(--roi-accent);
}

/* The volume series are two stops of the one accent, stacked, so the chart
   still runs on a single hue. */
.rly-legend-i.is-email::before {
  width: 11px;
  height: 11px;
  border-radius: 3.5px;
  background: var(--roi-vol-em-b);
}

.rly-legend-i.is-li::before {
  width: 11px;
  height: 11px;
  border-radius: 3.5px;
  background: var(--roi-vol-li-b);
}

/* Spend is the neutral series. One accent on the page, so the second
   line is a dashed hairline rather than a second colour. */
.rly-legend-i.is-spend::before {
  background: repeating-linear-gradient(
    90deg, var(--roi-ink-3) 0 4px, transparent 4px 7px);
}

/* Plot area. The y labels hang in the left gutter, so the canvas keeps
   the full width for the series. */
.rly-plot { padding-left: 46px; }

.rly-canvas {
  position: relative;
  height: 224px;
}

.rly-y { position: absolute; inset: 0; }

.rly-y-line {
  position: absolute;
  left: 0;
  right: 0;
  height: 0;
  border-top: 1px solid var(--roi-hairline);
}

.rly-y-line:last-child { border-top-color: var(--roi-hairline-strong); }

.rly-y-lab {
  position: absolute;
  right: calc(100% + 10px);
  top: -0.62em;
  font-family: var(--roi-sans);
  font-size: 0.75rem;
  font-weight: 400;
  color: var(--roi-ink-3);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.rly-svg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
}

.rly-area { fill: var(--roi-accent-veil); stroke: none; }

.rly-rev {
  fill: none;
  stroke: var(--roi-accent);
  stroke-width: 2.5;
  stroke-linejoin: round;
  stroke-linecap: round;
  vector-effect: non-scaling-stroke;
}

.rly-spend {
  fill: none;
  stroke: var(--roi-ink-3);
  stroke-width: 1.5;
  stroke-dasharray: 4 4;
  stroke-linecap: round;
  vector-effect: non-scaling-stroke;
}

/* Break-even marker: a hairline where the series cross, plus a label.
   Absolutely positioned HTML so the type never scales with the svg. */
.rly-be {
  position: absolute;
  top: -4px;
  bottom: 0;
  width: 1px;
  background: var(--roi-hairline-strong);
  transition: left 260ms var(--roi-ease), opacity 200ms var(--roi-ease);
}

.rly-be-lab {
  position: absolute;
  top: -9px;
  left: 6px;
  padding: 3px 8px;
  border-radius: 999px;
  background: var(--roi-pill);
  color: #fff;
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: -0.005em;
  white-space: nowrap;
}

/* Flip the label inside the plot once the marker is past the midpoint. */
.rly-be.is-late .rly-be-lab { left: auto; right: 6px; }
.rly-be.is-off { opacity: 0; visibility: hidden; }

.rly-head-dot {
  position: absolute;
  width: 9px;
  height: 9px;
  margin: -4.5px 0 0 -4.5px;
  border-radius: 50%;
  background: var(--roi-accent);
  /* The surface ring is a knockout so the dot reads clear of the series
     line underneath. The accent halo that sat on top of it was decoration. */
  box-shadow: 0 0 0 3px var(--roi-surface);
  transition: top 260ms var(--roi-ease), background-color 260ms var(--roi-ease);
}

.rly-x {
  position: relative;
  height: 20px;
  margin-top: 6px;
}

.rly-x span {
  position: absolute;
  transform: translateX(-50%);
  font-family: var(--roi-sans);
  font-size: 0.75rem;
  font-weight: 400;
  color: var(--roi-ink-3);
  font-variant-numeric: tabular-nums;
}

.rly-x span:last-child { transform: translateX(-100%); }

/* The empty state, before a cost or a deal value exists. */
.rly-chart.is-empty .rly-canvas { opacity: 0.4; }

.rly-chart-empty {
  display: none;
  font-size: var(--roi-text-caption);
  font-weight: 400;
  color: var(--roi-ink-3);
  padding: 4px 0 2px;
}

.rly-chart.is-empty .rly-chart-empty { display: block; }

/* ================================================================
   volume ramp
   ================================================================
   Stacked sends per month, in the form the proposal deck's forecast
   slide uses: one column per month, LinkedIn above email, the figure
   above the bar and the month under it. The first column is a quarter
   of the rest, which is the whole point of drawing it. */

.rly-vol {
  border-radius: var(--roi-r-card);
  padding: var(--roi-space-4) var(--roi-space-5);
  background: var(--roi-surface);
  box-shadow: var(--roi-shadow-card);
  transition: background-color 260ms var(--roi-ease),
              box-shadow 260ms var(--roi-ease);
}

/* The three send totals. The page used to report replies, meetings and
   deals and never once report how many messages it assumed were sent. */
.rly-vol-sums {
  display: flex;
  flex-wrap: wrap;
  gap: 10px 28px;
  padding-bottom: 16px;
  margin-bottom: 4px;
  border-bottom: 1px solid var(--roi-hairline);
}

.rly-vol-sum {
  display: flex;
  flex-direction: column;
  gap: 1px;
}

.rly-vol-sum-l {
  font-size: 0.75rem;
  font-weight: 400;
  line-height: 1.3;
  color: var(--roi-ink-3);
}

.rly-vol-sum-v {
  font-size: 1.0625rem;
  font-weight: 700;
  line-height: 1.25;
  letter-spacing: -0.02em;
  color: var(--roi-ink);
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
}

.rly-vol-plot {
  display: flex;
  align-items: flex-end;
  gap: 10px;
  height: 206px;
  padding: 26px 0 30px;
}

.rly-vol-col {
  flex: 1 1 0;
  min-width: 0;
  height: 100%;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  position: relative;
}

.rly-vol-col b {
  position: absolute;
  bottom: -26px;
  left: 0;
  right: 0;
  text-align: center;
  font-size: 0.75rem;
  font-weight: 400;
  color: var(--roi-ink-3);
}

.rly-vol-b {
  position: relative;
  display: block;
  width: 66%;
  max-width: 58px;
  height: 0;
  min-height: 2px;
}

.rly-vol-fill {
  position: absolute;
  inset: 0;
  border-radius: 10px 10px 2px 2px;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
}

.rly-vol-fill i { display: block; width: 100%; }

/* Solid, not gradient. A vertical ramp inside a stacked bar encodes nothing,
   and it softened the one edge that carries meaning: where email stops and
   LinkedIn starts. These are the exact two values the legend paints, so the
   key and the marks are the same colour rather than merely similar. */
.rly-vol-fill i.is-li {
  background: var(--roi-vol-li-b);
}

.rly-vol-fill i.is-email {
  background: var(--roi-vol-em-b);
}

.rly-vol-lab {
  position: absolute;
  bottom: 100%;
  left: 50%;
  transform: translateX(-50%);
  margin-bottom: 7px;
  font-size: 0.75rem;
  font-style: normal;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--roi-ink-2);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* Always visible: the ramp is the one assumption that most moves the
   answer, so it does not sit behind the help toggle. */
.rly-vol-note {
  margin: 4px 0 0;
  /* Same measure cap as the hints. In the single-column band this note gets
     the full panel width and ran to 81 characters. */
  max-width: 62ch;
  font-size: var(--roi-text-caption);
  font-weight: 300;
  line-height: var(--roi-leading-body);
  color: var(--roi-ink-3);
  text-wrap: pretty;
}

/* ================================================================
   funnel
   ================================================================ */

.rly-funnel {
  border-radius: var(--roi-r-card);
  padding: var(--roi-space-4) var(--roi-space-5);
  background: var(--roi-surface);
  box-shadow: var(--roi-shadow-card);
  transition: background-color 260ms var(--roi-ease),
              box-shadow 260ms var(--roi-ease);
}

.rly-funnel-head { padding: 0 0 8px; }

.rly-row {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: baseline;
  column-gap: var(--roi-space-3);
  row-gap: 0;
  padding: var(--roi-space-2) 0;
}

.rly-row + .rly-row { border-top: 1px solid var(--roi-hairline); }

.rly-row-l {
  font-size: 0.9375rem;
  font-weight: 400;
  line-height: var(--roi-leading-body);
  color: var(--roi-ink-2);
}

.rly-row-v {
  font-family: var(--roi-sans);
  font-size: 0.9375rem;
  font-weight: 600;
  line-height: var(--roi-leading-body);
  color: var(--roi-ink);
  font-variant-numeric: tabular-nums;
}

/* Proportional bar under the row. It spans BOTH columns on purpose: in a
   `1fr auto` grid, column 1 is whatever the value leaves behind, so a track
   confined to it ended at a different x on every row (measured 314.6 to
   323.4px) and the lengths could not be compared against each other. */
.rly-bar {
  grid-column: 1 / -1;
  height: 4px;
  border-radius: 999px;
  background: var(--roi-accent-veil);
  overflow: hidden;
  margin-top: 4px;
}

.rly-bar-fill {
  display: block;
  height: 100%;
  border-radius: 999px;
  background: linear-gradient(90deg, var(--roi-accent), var(--roi-accent-2));
  transform-origin: left center;
  /* scaleX rather than width, so the bar composites instead of relaying out.
     The fill is a plain gradient, so the horizontal scale is invisible. */
  width: 100% !important;
  transform: scaleX(var(--rly-w, 0));
  transition: transform 260ms var(--roi-ease);
}

.rly-row.is-cost { padding-top: 12px; }
.rly-row.is-cost .rly-row-l { color: var(--roi-ink-3); }

/* ================================================================
   help toggle and glossary
   ================================================================ */

.content-roi .hero-toggle-text {
  font-family: var(--roi-sans);
  font-size: var(--roi-text-caption);
  font-weight: 500;
  color: var(--roi-ink-2);
  padding-top: 0;
}

.content-roi .hero-toggle {
  float: none;
  flex: none;
  background-color: var(--roi-accent-veil);
  box-shadow: 0 0 0 1px var(--roi-hairline);
  transition: background-color 200ms var(--roi-ease),
              box-shadow 200ms var(--roi-ease);
}

.content-roi .hero-toggle-dot {
  background-color: var(--roi-surface);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25);
  transition: transform 220ms var(--roi-ease),
              background-color 260ms var(--roi-ease);
  will-change: transform;
}

.content-roi .toggle-wrapper:active .hero-toggle-dot { transform: scale(0.96); }
.content-roi.is-help .hero-toggle { background-color: var(--roi-accent); }
/* 36px track - 4px padding - 13px dot = 15px of travel */
.content-roi.is-help .hero-toggle-dot { transform: translateX(15px); }
.content-roi.is-help .toggle-wrapper:active .hero-toggle-dot { transform: translateX(15px) scale(0.96); }
.content-roi.is-help .hero-toggle-text { color: var(--roi-ink); }

.content-roi .toggle-wrapper:focus-visible {
  outline: 2px solid var(--roi-accent);
  outline-offset: 4px;
  border-radius: 999px;
}

/* Field hints already occupy their space, so revealing them shifts nothing. */
.content-roi .lable-roi-desc {
  opacity: 0;
  transition: opacity 200ms var(--roi-ease);
}

.content-roi.is-help .lable-roi-desc { opacity: 1; }

/* Results-side glossary. Collapsed to zero height until the toggle is on. */
/* Grid rows rather than a max-height, so a hint that runs long can never
   be clipped by a magic number. */
.rly-help {
  grid-column: 1 / -1;
  display: grid;
  grid-template-rows: 0fr;
  opacity: 0;
  font-size: var(--roi-text-caption);
  font-weight: 300;
  line-height: var(--roi-leading-body);
  max-width: 62ch;
  color: var(--roi-ink-3);
  text-wrap: pretty;
  transition: grid-template-rows 240ms var(--roi-ease),
              opacity 240ms var(--roi-ease),
              margin-top 240ms var(--roi-ease);
}

.rly-help > * { overflow: hidden; }

.content-roi.is-help .rly-help {
  grid-template-rows: 1fr;
  opacity: 1;
  margin-top: 5px;
}

/* ================================================================
   running total
   ================================================================
   Only on screens too narrow to keep the hero in view. Sticky to the
   bottom of the viewport rather than fixed, so it belongs to the panel
   and disappears with it instead of following the visitor down the page. */

.rly-mini { display: none; }

@media screen and (max-width: 991px) {
  .rly-mini {
    position: sticky;
    bottom: 10px;
    z-index: 5;
    display: flex;
    align-items: baseline;
    justify-content: center;
    gap: 7px;
    width: fit-content;
    max-width: 100%;
    margin: 0 auto;
    padding: var(--roi-space-2) var(--roi-space-5);
    border-radius: 999px;
    /* The same fill as the hero, not --roi-accent. This pill IS the hero on a
       phone, and on --roi-accent its dark-mode label sat at 3.51 against the
       4.5 it needs -- a real AA failure that desktop audits never see, because
       the pill is display:none above 991px. */
    background: var(--roi-hero-fill);
    /* Ink-tinted, same language as every other elevated thing here. This used
       to ride on --roi-hero-glow, which no longer exists. */
    box-shadow:
      0 2px 6px rgba(34, 31, 46, 0.18),
      0 12px 30px -10px rgba(34, 31, 46, 0.28);
    font-family: var(--roi-sans);
    /* Lifts clear of the last card without adding height to the panel. */
    margin-top: -46px;
  }

  .rly-mini-v {
    font-size: 1.0625rem;
    font-weight: 700;
    letter-spacing: -0.02em;
    color: var(--roi-hero-ink);
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum" 1;
  }

  .rly-mini-v.is-2 { font-weight: 600; }

  .rly-mini-l {
    font-size: 0.75rem;
    font-weight: 400;
    color: var(--roi-hero-ink-2);
  }

  .rly-mini-sep {
    width: 1px;
    height: 12px;
    margin: 0 3px;
    background: rgba(255, 255, 255, 0.34);
  }
}

/* ================================================================
   responsive
   ================================================================ */

/* The hero used to be `position: sticky; top: 20px` above 992px, to keep the
   figure in view while the lower sliders were dragged. Removed: its containing
   block is the whole results column, so it travelled the full height of that
   column and slid over the stat cards, the volume ramp and the funnel, and at
   the top of the range it collided with the site's own fixed nav. A number that
   covers the chart explaining it is worse than a number you scroll back to. */

@media screen and (max-width: 991px) {
  .content-roi { padding: 28px 24px 34px !important; }

  /* Webflow puts a 120px top margin on the panel below this breakpoint. That
     read as ordinary section spacing while the title lived inside the card;
     now that the title sits above it, the same margin opens a gulf between
     the two. The page head carries the spacing instead. */
  .content-roi { margin-top: 0 !important; }

  .rly-pagehead { margin-bottom: 18px; }

  /* The row wraps onto two lines at this width, and right-aligning a wrapped
     row leaves both lines hanging off the same edge. Centre it. */
  .content-roi .content-header-wrap .rly-controls {
    justify-content: center;
  }

  /* Label over control from here down. The 768-991 band was the one nobody
     had rendered, and it is where the percent boxes clipped their own value. */
  .rly-in,
  .rly-derived {
    grid-template-columns: minmax(0, 1fr);
    row-gap: 8px;
  }
  .rly-in-l,
  .rly-in-c,
  .rly-in-h,
  .rly-cap,
  .rly-derived-l,
  .rly-derived-v,
  .rly-derived-h { grid-column: 1; }

  .rly-derived {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: 4px 16px;
  }
}

@media screen and (max-width: 767px) {
  .content-roi {
    padding: 22px 18px 28px !important;
    border-radius: 22px;
  }
  .content-roi .content-header-wrap { padding-bottom: 24px !important; }
  .rly-split { grid-template-columns: 1fr; }
  .text-field-roi.input-percent { max-width: none; }
  .rly-plot { padding-left: 42px; }
  .rly-canvas { height: 172px; }

}

@media (prefers-reduced-motion: reduce) {
  .content-roi,
  .content-roi *,
  .content-roi *::before,
  .content-roi *::after,
  .reachly-cta-wrap,
  .reachly-cta-wrap *,
  .reachly-cta-wrap *::before,
  .reachly-cta-wrap *::after {
    transition-duration: 1ms !important;
    animation-duration: 1ms !important;
    animation-iteration-count: 1 !important;
  }
}

/* ---- CTA spacing ------------------------------------------------ */

.rly-cta-mount { margin-top: 72px; }

@media screen and (max-width: 767px) {
  .rly-cta-mount { margin-top: 48px; }
}


@import url("https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700;800&display=swap");

  .reachly-cta-wrap,
  .reachly-cta-wrap *,
  .reachly-cta-wrap *::before,
  .reachly-cta-wrap *::after {
    box-sizing: border-box;
  }

  .reachly-cta-wrap {
    --reachly-purple: #7B4DE0;
    --reachly-purple-dark: #5B33C9;
    --reachly-text: #1A1A2E;

    max-width: 1280px;
    margin: 40px auto;
    padding: 0 24px;
    font-family: "Poppins", system-ui, -apple-system, sans-serif;
    color: var(--reachly-text);
  }

  .reachly-cta {
    position: relative;
    padding: 72px 56px;
    border-radius: 32px;
    overflow: hidden;
    background:
      radial-gradient(70% 60% at 8% 10%, rgba(255, 255, 255, 0.95) 0%, rgba(255, 255, 255, 0) 60%),
      radial-gradient(55% 55% at 12% 95%, rgba(235, 230, 253, 0.95) 0%, rgba(235, 230, 253, 0) 65%),
      radial-gradient(60% 70% at 95% 50%, rgba(214, 196, 255, 0.7) 0%, rgba(214, 196, 255, 0) 70%),
      linear-gradient(135deg, #F8F2FF 0%, #EDE2FF 55%, #E5D6FF 100%);
  }

  .reachly-cta::before,
  .reachly-cta::after {
    content: "";
    position: absolute;
    border-radius: 50%;
    pointer-events: none;
  }
  .reachly-cta::before {
    width: 480px; height: 480px;
    top: -180px; left: -120px;
    background: radial-gradient(circle, rgba(255, 255, 255, 0.85) 0%, rgba(255, 255, 255, 0) 70%);
    filter: blur(40px);
  }
  .reachly-cta::after {
    width: 420px; height: 420px;
    bottom: -160px; right: -120px;
    background: radial-gradient(circle, rgba(213, 200, 245, 0.7) 0%, rgba(213, 200, 245, 0) 70%);
    filter: blur(50px);
  }

  .reachly-cta__inner {
    position: relative;
    z-index: 1;
    display: grid;
    grid-template-columns: 1fr 1.15fr;
    align-items: center;
    gap: 56px;
  }

  .reachly-cta__title {
    font-family: "Poppins", system-ui, sans-serif;
    font-size: clamp(30px, 3.6vw, 46px);
    line-height: 1.15;
    font-weight: 700;
    letter-spacing: -0.02em;
    margin: 0 0 20px;
    color: #1A1A2E;
  }
  .reachly-cta__title em {
    color: var(--reachly-purple);
    font-style: normal;
  }

  .reachly-cta__subtitle {
    font-family: "Poppins", system-ui, sans-serif;
    font-size: 17px;
    font-weight: 400;
    line-height: 1.55;
    color: #4A4A66;
    margin: 0 0 32px;
    max-width: 480px;
  }

  .reachly-cta__button {
    font-family: "Poppins", system-ui, sans-serif;
    display: inline-flex;
    align-items: center;
    gap: 10px;
    padding: 14px 26px;
    font-size: 15px;
    font-weight: 600;
    color: #fff;
    background: var(--reachly-purple);
    border: none;
    border-radius: 10px;
    text-decoration: none;
    box-shadow: 0 8px 22px rgba(123, 77, 224, 0.32);
    transition: transform 0.18s ease, box-shadow 0.18s ease, background 0.18s ease;
  }
  .reachly-cta__button:hover {
    background: var(--reachly-purple-dark);
    transform: translateY(-2px);
    box-shadow: 0 12px 28px rgba(123, 77, 224, 0.4);
    color: #fff;
    text-decoration: none;
  }
  .reachly-cta__button:active { transform: translateY(0); }

  /* The page's only conversion element used to offer a keyboard user nothing
     but the browser default ring. */
  .reachly-cta__button:focus-visible {
    outline: 3px solid var(--reachly-text);
    outline-offset: 3px;
    box-shadow:
      0 0 0 3px #FFFFFF,
      0 8px 22px rgba(123, 77, 224, 0.32);
  }
  .reachly-cta__button svg { transition: transform 0.18s ease; }
  .reachly-cta__button:hover svg { transform: translateX(4px); }

  .reachly-cta__visual {
    position: relative;
    width: 100%;
    aspect-ratio: 985 / 569;
    border-radius: 16px;
    overflow: hidden;
    box-shadow: 0 28px 60px rgba(80, 50, 180, 0.22),
                0 6px 18px rgba(80, 50, 180, 0.08);
    transform: rotate(-1deg);
    container-type: inline-size;
    /* The mock is wider than the frame on purpose, so the cut edge fades
       instead of ending in a hard vertical line mid-label. The fade must reach
       FULL transparency, and late: stopping at 0.04 alpha at 97% left about a
       quarter of the width as legible-but-washed ghost type ("Pipeline funn",
       "Contacted", "Emails s"), which reads as a broken render rather than as
       framing. Held opaque to 80%, gone by the edge. */
    mask-image: linear-gradient(90deg, #000 0 80%, rgba(0, 0, 0, 0) 100%);
    -webkit-mask-image: linear-gradient(90deg, #000 0 80%, rgba(0, 0, 0, 0) 100%);
  }
  /* Deliberately no :hover transform. Un-rotating or lifting a product shot
     under the cursor is decoration on an element that is not interactive;
     the only thing to click here is the button. */

  /* The inner is a 1280px dashboard. It used to be scaled by 100cqw/985px,
     so it painted at 130% of its own clipping box: 23% of the mock, an entire
     KPI card and the whole funnel value column, were rendered and thrown away
     at every single viewport, and what remained was painted at 0.578x, which
     is 6px type. Scaled to stay legible and cropped on purpose instead, with
     a fade on the cut edge so the crop reads as framing. */
  .reachly-cta__visual-inner {
    position: absolute;
    top: 0;
    left: 0;
    width: 1280px;
    transform-origin: top left;
    transform: scale(clamp(0.62, 100cqw / 1050px, 0.86));
  }



  .reachly-cta__visual::before {
    content: "";
    position: absolute;
    inset: auto 0 0 0;
    height: 70px;
    z-index: 2;
    pointer-events: none;
    background: linear-gradient(to bottom, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.55) 100%);
  }

  .reachly-cta__visual::after {
    content: "";
    position: absolute;
    inset: 0;
    pointer-events: none;
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.6);
    border-radius: 16px;
  }

  /* RESPONSIVE */
  @media (max-width: 1180px) {
    .reachly-cta { padding: 64px 44px; }
  }

  @media (max-width: 920px) {
    .reachly-cta-wrap { margin: 24px auto; padding: 0 16px; }
    .reachly-cta { padding: 48px 32px; border-radius: 28px; }
    .reachly-cta__inner {
      grid-template-columns: 1fr;
      gap: 36px;
      text-align: center;
    }
    .reachly-cta__title { font-size: clamp(28px, 4.6vw, 40px); margin-bottom: 16px; }
    .reachly-cta__subtitle { margin-left: auto; margin-right: auto; max-width: 540px; font-size: 16px; }
    .reachly-cta__visual { transform: none; }
  }

  @media (max-width: 600px) {
    .reachly-cta-wrap { margin: 16px auto; padding: 0 12px; }
    .reachly-cta { padding: 36px 22px; border-radius: 22px; }
    .reachly-cta::before { width: 220px; height: 220px; top: -70px; left: -70px; }
    .reachly-cta::after  { width: 240px; height: 240px; bottom: -90px; right: -80px; }
    .reachly-cta__inner { gap: 28px; }
    .reachly-cta__title { font-size: clamp(24px, 6.4vw, 30px); line-height: 1.18; margin-bottom: 14px; }
    .reachly-cta__subtitle { font-size: 15px; line-height: 1.5; margin-bottom: 24px; }
    .reachly-cta__button {
      padding: 14px 22px;
      font-size: 15px;
      width: 100%;
      max-width: 320px;
      justify-content: center;
      margin: 0 auto;
    }
    .reachly-cta__visual { border-radius: 12px; }
  }

  @media (max-width: 480px) {
    .reachly-cta { padding: 32px 18px; }
  }

  @media (max-width: 380px) {
    .reachly-cta__title { font-size: 24px; }
    .reachly-cta__subtitle { font-size: 14px; }
  }

  /* DASHBOARD STYLES (scoped to .r-app inside .reachly-cta-wrap) */
  .reachly-cta-wrap .r-app, .reachly-cta-wrap .r-app * {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
    font-family: "Poppins", system-ui, sans-serif;
  }
  .reachly-cta-wrap .r-app {
    --rp: #7B4DE0;
    --rp-rgb: 123, 77, 224;
    --rp-deep: #5B33C9;
    --rp-tint: #F5EEFF;
    /* Was amber #F7AC3F and emerald #10B981. Amber survives only inside
       the logo mark and emerald is not in the palette at all, so the mock
       runs on two stops of the accent instead. */
    --or: #B79AF5;
    --gn: #6438C6;
    --ink: #221F2E;
    /* Was #4B5563 / #6B7280, which is what put twelve labels in this block
       under 4.5:1. Tinted from the brand ink instead of grey. */
    --ink-soft: #3A3547;
    --muted: #504A61;
    --bg: #FFFFFF;
    --bg-soft: #FBFAFD;
    --bg-pin: #F5F0FF;
    --border: rgba(var(--rp-rgb), 0.08);
    --border-mid: rgba(var(--rp-rgb), 0.14);
    --border-strong: rgba(var(--rp-rgb), 0.22);

    width: 1280px;
    display: grid;
    grid-template-columns: 180px 1fr;
    background: var(--bg);
    border: 1px solid var(--border-mid);
    border-radius: 20px;
    box-shadow: 0 1px 0 rgba(var(--rp-rgb), 0.04), 0 32px 80px rgba(var(--rp-rgb), 0.14);
    overflow: hidden;
    color: var(--ink);
    font-size: 13px;
    line-height: 1.4;
  }

  .reachly-cta-wrap .r-sb {
    border-right: 1px solid var(--border);
    background: var(--bg-soft);
    padding: 20px 14px;
    opacity: 0;
    animation: r-in-left 0.5s ease 0.05s forwards;
  }
  .reachly-cta-wrap .r-sb-brand { display: flex; align-items: center; gap: 8px; padding: 0 6px 22px; font-size: 16px; font-weight: 800; letter-spacing: -0.01em; }
  .reachly-cta-wrap .r-sb-mark { width: 24px; height: 24px; background: linear-gradient(135deg, var(--rp) 0%, var(--rp-deep) 100%); border-radius: 7px; display: flex; align-items: center; justify-content: center; color: #fff; font-size: 12px; font-weight: 800; }
  .reachly-cta-wrap .r-sb-section { font-size: 11px; font-weight: 700; letter-spacing: 0.08em; color: var(--muted); text-transform: uppercase; padding: 0 6px 8px; }
  .reachly-cta-wrap .r-sb-item { display: flex; align-items: center; gap: 10px; padding: 9px 10px; border-radius: 9px; font-size: 13px; font-weight: 600; color: var(--ink-soft); margin-bottom: 4px; }
  .reachly-cta-wrap .r-sb-item.is-active { background: var(--rp-tint); color: var(--rp); font-weight: 700; }
  .reachly-cta-wrap .r-sb-item-icon { width: 16px; height: 16px; flex-shrink: 0; color: currentColor; }

  .reachly-cta-wrap .r-main { display: flex; flex-direction: column; min-width: 0; }
  .reachly-cta-wrap .r-top { display: flex; align-items: center; justify-content: space-between; padding: 16px 24px; border-bottom: 1px solid var(--border); background: linear-gradient(180deg, #FFFFFF 0%, var(--bg-soft) 100%); opacity: 0; animation: r-in-down 0.5s ease 0.15s forwards; }
  .reachly-cta-wrap .r-top-l { display: flex; align-items: center; gap: 16px; min-width: 0; }
  .reachly-cta-wrap .r-ws { display: flex; align-items: center; gap: 8px; padding: 6px 12px 6px 6px; background: var(--bg); border: 1px solid var(--border-mid); border-radius: 999px; font-size: 12px; font-weight: 700; }
  .reachly-cta-wrap .r-ws-mark { width: 22px; height: 22px; background: linear-gradient(135deg, #6438C6 0%, #4B22A8 100%); border-radius: 6px; display: flex; align-items: center; justify-content: center; color: #fff; font-size: 10px; font-weight: 800; }
  .reachly-cta-wrap .r-ws-caret { color: var(--muted); }
  .reachly-cta-wrap .r-greet { display: flex; align-items: baseline; gap: 8px; font-size: 18px; font-weight: 800; letter-spacing: -0.01em; }
  .reachly-cta-wrap .r-greet em { font-style: normal; }
  .reachly-cta-wrap .r-greet-meta { font-size: 12px; font-weight: 500; color: var(--muted); }
  .reachly-cta-wrap .r-top-r { display: flex; align-items: center; gap: 8px; }
  .reachly-cta-wrap .r-pill { display: inline-flex; align-items: center; gap: 6px; padding: 7px 12px; background: var(--bg); border: 1px solid var(--border-mid); border-radius: 9px; font-size: 12px; font-weight: 600; color: var(--ink-soft); }
  .reachly-cta-wrap .r-pill.is-icon { padding: 7px 9px; }
  .reachly-cta-wrap .r-pulse { position: relative; width: 8px; height: 8px; background: var(--gn); border-radius: 50%; }
  /* No pulse. This mock is a still image of a dashboard; a ring throbbing
     forever behind a static "Last 30 days" pill dresses fixed numbers up as
     a live feed. The dot alone already reads as a status. */
  .reachly-cta-wrap .r-pulse::before { content: ""; position: absolute; inset: -3px; border-radius: 50%; background: var(--gn); opacity: 0.18; }

  .reachly-cta-wrap .r-kpis { display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; padding: 18px 24px 0; }
  .reachly-cta-wrap .r-kpi { background: var(--bg); border: 1px solid var(--border-mid); border-radius: 12px; padding: 14px 16px; opacity: 0; animation: r-in-up 0.5s ease forwards; }
  .reachly-cta-wrap .r-kpi:nth-of-type(1) { animation-delay: 0.25s; }
  .reachly-cta-wrap .r-kpi:nth-of-type(2) { animation-delay: 0.32s; }
  .reachly-cta-wrap .r-kpi:nth-of-type(3) { animation-delay: 0.39s; }
  .reachly-cta-wrap .r-kpi:nth-of-type(4) { animation-delay: 0.46s; }
  .reachly-cta-wrap .r-kpi.is-active { background: linear-gradient(135deg, #FAF6FF 0%, #F1E9FF 100%); border-color: var(--border-strong); }
  .reachly-cta-wrap .r-kpi-head { display: flex; align-items: center; justify-content: space-between; }
  .reachly-cta-wrap .r-kpi-label { font-size: 11px; font-weight: 700; letter-spacing: 0.06em; color: var(--muted); text-transform: uppercase; }
  .reachly-cta-wrap .r-kpi-delta { display: inline-flex; align-items: center; gap: 3px; font-size: 11px; font-weight: 700; color: var(--gn); }
  .reachly-cta-wrap .r-kpi-row { display: flex; align-items: baseline; gap: 4px; margin-top: 8px; }
  .reachly-cta-wrap .r-kpi-value { font-size: 26px; font-weight: 800; letter-spacing: -0.02em; line-height: 1; }
  .reachly-cta-wrap .r-kpi-unit { font-size: 14px; font-weight: 700; color: var(--muted); }
  .reachly-cta-wrap .r-kpi-sub { margin-top: 6px; font-size: 11px; font-weight: 500; color: var(--muted); }

  .reachly-cta-wrap .r-mid { display: grid; grid-template-columns: 1fr 320px; gap: 12px; padding: 12px 24px 0; }
  .reachly-cta-wrap .r-card { background: var(--bg); border: 1px solid var(--border-mid); border-radius: 12px; padding: 18px 20px; opacity: 0; animation: r-in-up 0.5s ease 0.55s forwards; }
  .reachly-cta-wrap .r-card-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px; }
  .reachly-cta-wrap .r-card-title { font-size: 14px; font-weight: 800; letter-spacing: -0.01em; }
  .reachly-cta-wrap .r-card-sub { font-size: 11px; font-weight: 500; color: var(--muted); margin-bottom: 16px; }
  .reachly-cta-wrap .r-legend { display: flex; align-items: center; gap: 12px; font-size: 11px; font-weight: 600; color: var(--muted); }
  .reachly-cta-wrap .r-leg-dot { display: inline-block; width: 10px; height: 10px; border-radius: 3px; margin-right: 5px; vertical-align: middle; }
  .reachly-cta-wrap .r-leg-line { display: inline-block; width: 14px; height: 2px; margin-right: 5px; vertical-align: middle; }

  .reachly-cta-wrap .r-chart { position: relative; height: 220px; margin: 0 4px 8px; }
  .reachly-cta-wrap .r-chart-grid { position: absolute; inset: 0 0 18px 24px; display: flex; flex-direction: column; justify-content: space-between; pointer-events: none; }
  .reachly-cta-wrap .r-chart-grid-line { position: relative; height: 1px; background: var(--border); }
  .reachly-cta-wrap .r-chart-grid-label { position: absolute; left: -28px; top: -7px; font-size: 11px; font-weight: 600; color: var(--muted); }
  .reachly-cta-wrap .r-chart-bars { position: absolute; inset: 0 0 18px 24px; display: flex; align-items: flex-end; gap: 4px; }
  .reachly-cta-wrap .r-bar { flex: 1; border-radius: 3px 3px 0 0; background: linear-gradient(to bottom, var(--or) 0, var(--or) calc(var(--li, 0) * 1%), var(--rp) calc(var(--li, 0) * 1%), var(--rp) 100%); height: calc((var(--em, 0) + var(--li, 0)) * 1%); transform: scaleY(0); transform-origin: bottom; opacity: 0.95; animation: r-grow 0.6s cubic-bezier(0.22, 1, 0.36, 1) forwards; }
  .reachly-cta-wrap .r-chart-lines { position: absolute; inset: 0 0 18px 24px; width: calc(100% - 24px); height: calc(100% - 18px); pointer-events: none; }
  .reachly-cta-wrap .r-line { fill: none; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; stroke-dasharray: 2000; stroke-dashoffset: 2000; animation: r-draw 1.6s ease 1.5s forwards; }
  .reachly-cta-wrap .r-line.is-replies { stroke: var(--gn); stroke-dasharray: 5 5; animation: r-draw-dashed 1.6s ease 1.5s forwards; }
  .reachly-cta-wrap .r-line.is-positive { stroke: #4B22A8; }
  .reachly-cta-wrap .r-line-dot { fill: var(--gn); stroke: #fff; stroke-width: 2; opacity: 0; animation: r-fade 0.4s ease 3.0s forwards; }
  .reachly-cta-wrap .r-chart-x { position: absolute; inset: auto 0 0 24px; display: flex; justify-content: space-between; font-size: 11px; font-weight: 600; color: var(--muted); }

  .reachly-cta-wrap .r-funnel-list { padding: 4px 0 0; }
  .reachly-cta-wrap .r-funnel-row { display: flex; align-items: center; justify-content: space-between; padding: 10px 0; border-bottom: 1px dashed var(--border); opacity: 0; animation: r-in-up 0.4s ease forwards; }
  .reachly-cta-wrap .r-funnel-row:last-child { border-bottom: none; }
  .reachly-cta-wrap .r-funnel-row:nth-child(1) { animation-delay: 1.7s; }
  .reachly-cta-wrap .r-funnel-row:nth-child(2) { animation-delay: 1.78s; }
  .reachly-cta-wrap .r-funnel-row:nth-child(3) { animation-delay: 1.86s; }
  .reachly-cta-wrap .r-funnel-row:nth-child(4) { animation-delay: 1.94s; }
  .reachly-cta-wrap .r-funnel-row:nth-child(5) { animation-delay: 2.02s; }
  .reachly-cta-wrap .r-funnel-label { font-size: 13px; font-weight: 600; color: var(--ink-soft); }
  .reachly-cta-wrap .r-funnel-value { font-size: 16px; font-weight: 800; letter-spacing: -0.01em; }
  .reachly-cta-wrap .r-funnel-note { margin-top: 12px; padding: 10px 12px; background: var(--rp-tint); border-radius: 8px; font-size: 11px; color: var(--rp-deep); line-height: 1.5; }
  .reachly-cta-wrap .r-funnel-note b { font-weight: 700; }

  @keyframes r-in-left { from { opacity: 0; transform: translateX(-12px); } to { opacity: 1; transform: translateX(0); } }
  @keyframes r-in-down { from { opacity: 0; transform: translateY(-8px); } to { opacity: 1; transform: translateY(0); } }
  @keyframes r-in-up   { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } }
  @keyframes r-fade    { to { opacity: 1; } }
  @keyframes r-grow    { to { transform: scaleY(1); } }
  @keyframes r-draw    { to { stroke-dashoffset: 0; } }
  @keyframes r-draw-dashed { from { stroke-dashoffset: 2000; } to { stroke-dashoffset: 0; } }
  @keyframes r-tick    { 0% { transform: scale(1); } 30% { transform: scale(1.18); } 100% { transform: scale(1); } }
  .reachly-cta-wrap .r-tick { animation: r-tick 0.45s ease; transform-origin: left bottom; display: inline-block; }

  /* This file has its own animations and the guard in roi.css is scoped to
     .content-roi *, which stops at the calculator's edge. */
  @media (prefers-reduced-motion: reduce) {
    .reachly-cta-wrap *,
    .reachly-cta-wrap *::before,
    .reachly-cta-wrap *::after {
      /* Collapse the duration, never `animation: none`. Ten rules in this file
         start at opacity 0 and get their final opacity from an animation's
         `forwards` fill; clearing animation-name leaves them invisible, which
         rendered the whole dashboard mock as a blank rectangle. */
      animation-duration: 1ms !important;
      animation-delay: 0ms !important;
      animation-iteration-count: 1 !important;
      transition-duration: 1ms !important;
      transition-delay: 0ms !important;
    }
  }

