/* ============================================================
   Free reports page (/free)
   Scoped to `.free-page`. Uses design tokens — no hardcoded
   colors, radii or shadows. Brand-tinted backgrounds derive
   from token colors via color-mix() so the brand palette is
   the single source of truth.
   ============================================================ */

.free-page {
  /* Page-local derived tints (single source per tint). */
  --free-tint-coral:    color-mix(in srgb, var(--purple)   8%, transparent);
  --free-tint-border:   color-mix(in srgb, var(--pink) 20%, transparent);
  --free-tint-teal:     color-mix(in srgb, var(--purple)    10%, transparent);
  --free-tint-sage:     color-mix(in srgb, var(--cyan)    10%, transparent);
  --free-tint-teal-bd:  color-mix(in srgb, var(--purple)    22%, transparent);
  --free-tint-amber:    color-mix(in srgb, var(--yellow)   14%, transparent);
  --free-tint-amber-bd: color-mix(in srgb, var(--yellow)   30%, transparent);
  --free-tint-pink:     color-mix(in srgb, var(--cyan)    10%, transparent);
  --free-tint-coral-soft: color-mix(in srgb, var(--purple) 12%, transparent);

  /* Soft hairline color — visible at 0.75px against white but lighter
     than --gray-mid. Used by the section top, row dividers, and preview
     pane bottom border. */
  --free-hairline: color-mix(in srgb, var(--gray-mid) 40%, transparent);

  /* Sticky offsets — search bar pins below the navbar; the
     list/preview columns pin below the search bar. */
  --free-sticky-search: calc(var(--navbar-height) - 35px);
  /* Tabs row (gray bar) pins directly below the search pill so list rows
     scroll under it, not under the search bar. ~75px ≈ search pill 68px
     + breathing room. */
  --free-sticky-tabs:   calc(var(--free-sticky-search) + var(--space-5));
  /* Sticky preview pane pins just below the navbar's visible bottom
     edge, reusing the same offset the search bar previously used (the
     search bar's stickiness was removed earlier; the offset itself is
     still the canonical "just below navbar" pin point on /free). */
  --free-sticky-cols:   var(--free-sticky-search);
  --free-cols-max-h:    calc(100vh - var(--navbar-height) - 150px);
}

/* Solid white page surface outside the gradient hero. */
body:has(.mw-page.free-page) { background: var(--white) !important; }

/* ---------- Listing-page hero (Explore + Free) ----------------
   Self-contained band that frames the floating navbar at the top
   of the page. Title and tagline live in `.page-title-block`
   directly below — see further down. Owns its own width breakout,
   background, radius, and height; no dependency on `.landing-hero*`
   in home.css, so changes here cannot affect the home page and
   vice versa. Background is exposed via the `--listing-hero-bg`
   CSS variable so swapping the visual is a one-line edit.

   ⚠️ MUST-MATCH WITH work.css L289-313 (`.mw-page .listing-hero`
   + `.mw-page .listing-hero-panel`). The two copies exist (rather
   than a shared selector) so each page can carry its own scoped
   overrides without entangling the other consumer — but the BASE
   rules below MUST read identically. /free, /explore, and /work
   all share the same flush-heading layout (no 100px top push).

   PARITY rules (must stay identical between work.css + free.css):
     • .listing-hero — z-index, width-breakout (margin-left/right
       calc + width: 100vw), padding, overflow.
     • .listing-hero-panel — --listing-hero-bg, margin, border-radius,
       background, padding, overflow.
     • mobile @media — margin, border-radius, padding.
   --------------------------------------------------------------- */
.free-page .listing-hero {
  position: relative;
  /* z-index: 7 lifts the gradient band above the sticky search bar's
     white `::before` cap (z-index: 6) so the heading inside the hero
     can never be covered by the cap. The navbar (z-index: 1000) still
     paints above the hero as expected. When the user scrolls, the
     hero scrolls out of view and the cap continues to cover the area
     behind the navbar — no regression. */
  z-index: 7;
  /* Break out of `.mw-page` (max-width 1390px) so the panel spans
     the full viewport width like the home page hero. */
  margin-left: calc(50% - 50vw);
  margin-right: calc(50% - 50vw);
  width: 100vw;
  padding: 0;
  overflow: visible;
}

.free-page .listing-hero-panel {
  /* Background removed (26 Apr 2026) — panel is transparent so the
     white page surface shows through. Swap the value below to bring
     back a gradient, image, or solid color. */
  --listing-hero-bg: transparent;
  position: relative;
  /* No top margin — heading sits flush below the navbar pill, just
     like /work. Padding-top is --topbar-height MINUS --space-4 so the
     heading sits ~16px below the navbar bottom edge instead of ~48px
     (the additive +space-4 variant we used before created a gap
     Christine described as "giant"). Mirrors work.css L335 — both
     pages must stay in lock-step. Updated 4 May 2026. */
  margin: 0 var(--space-10);
  border-radius: 0;
  background: var(--listing-hero-bg);
  padding: var(--listing-hero-pad-top) var(--space-8) var(--space-7);
  overflow: hidden;
}

@media (max-width: 768px) {
  .free-page .listing-hero-panel {
    margin: var(--space-3) var(--space-3) 0;
    border-radius: 28px;
    padding: var(--listing-hero-pad-top-mobile) var(--space-5) var(--space-5);
  }
}

/* Full-bleed gradient hero (used on the simpler /free hero variant). */
.free-page .free-hero {
  background: var(--gradient);
  padding: calc(var(--topbar-height) + var(--space-6)) var(--space-4) var(--space-8);
  margin-left: calc(50% - 50vw);
  margin-right: calc(50% - 50vw);
  width: 100vw;
  position: relative;
  overflow: visible;
}
.free-page .free-hero-inner {
  max-width: 920px;
  margin: 0 auto;
  text-align: center;
  color: var(--white);
}
.free-page .free-hero-title {
  font-size: clamp(36px, 5.5vw, 64px);
  font-weight: var(--font-bold, 700);
  letter-spacing: var(--letter-spacing-tight, -0.02em);
  color: var(--white);
  margin: 0 0 10px;
  line-height: 1.05;
}
.free-page .free-hero-sub {
  font-size: clamp(15px, 1.4vw, 18px);
  color: rgb(255 255 255 / 0.92);
  margin: 0 0 var(--space-5);
}
/* Form carries the spacing rhythm directly so /free + /explore match
   /work's `.mw-search-form` (work.css L411-425) one-for-one:
   4px above the pill, 8px below, and a token-based side inset that
   keeps the pill flush with `.listing-hero-panel`'s outer edge
   (panel margin = --space-10). No outer wrapper margins/padding —
   the section + inner wrappers are pure structural shells now.
   Top margin reduced from 24px → 4px on 4 May 2026 per Christine
   ("gap before the search bar is quite large, reduce 20px").
   Side padding uses the --page-gutter-x token (defined in
   tokens/spacing.css) so the pill sits flush with the title TEXT
   inside .listing-hero-panel — the panel's outer margin + inner
   padding folded into one named value. Mobile override (further
   down in this file, inside @media max-width: 768px) swaps to
   --page-gutter-x-mobile so phones can use a tighter inset
   independently of desktop. */
.free-page .free-hero-search {
  margin: var(--space-1) auto var(--space-2);
  width: 100%;
  max-width: 1342px;
  padding-left: var(--page-gutter-x);
  padding-right: var(--page-gutter-x);
  box-sizing: border-box;
}

/* ---------- Search bar — scrolls with the page (not sticky) ---
   The pill sits just below the hero and scrolls away naturally.
   The `.page-search-bar` padding from home.css L433-435 (10/0/8)
   is overridden here so the form margins are the single source of
   truth for rhythm above and below the pill (matches /work). */
.free-page .page-search-bar {
  position: relative;
  top: auto;
  z-index: 6;
  background: transparent;
  margin: 0;
  padding: 0;
}
.free-page .page-search-bar::before {
  content: none;
}
/* Solutions mode renders no collapse machinery (the magnifier +
   hamburger toggles and inline-search input only exist in the
   products branch of explore.html), so free.js initSearchToggle()
   bails before binding the scroll listener — .is-scrolled is never
   added and the sticky bar can never collapse, pinning it forever.
   On /solutions, render the bar in normal flow so it scrolls away
   with the page like the rest of the content. */
.free-page .page-search-bar--no-collapse {
  position: relative;
  top: auto;
}
.free-page .page-search-bar-inner { max-width: 1342px; padding: 0; }

/* ---------- Search pill — mirrors /work's
   `.activity-search-bar.home-search-bar.home-search-bar--hero`
   (home-search.css L63-71 + L549-559, work.css L433-437) so the
   pill on /free + /explore is visually identical to the one on
   /work: 68px tall, fully-rounded, hairline border, light shadow,
   no harder drop-shadow. */
.free-page .free-search-pill {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  width: 100% !important;
  max-width: none !important;
  margin: 0;
  height: 68px;
  padding: 0 var(--space-4-5) 0 var(--space-6);
  background: var(--white);
  border: 0.5px solid #cccccc;
  border-radius: var(--radius-full) !important;
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
  transition: border-color 150ms ease, box-shadow 150ms ease;
}
.free-page .free-search-pill:focus-within {
  /* Black focus ring (was the pink accent, swapped 4 May 2026 per Christine). */
  border-color: var(--navy);
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.10);
}
/* Leading magnifying glass icon — same class + sizing as /work
   (work.css L551-560). Scoped here so the rule only reaches the
   /free + /explore pill and doesn't leak into /work's own form. */
.free-page .free-search-pill .mw-search-icon {
  display: flex;
  align-items: center;
  color: var(--gray-mid);
  flex-shrink: 0;
  padding-right: var(--space-1);
}
.free-page .free-search-pill .mw-search-icon svg {
  width: 19px;
  height: 19px;
}
.free-page .free-search-filters {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
}
.free-page .free-filter { display: inline-flex; }
.free-page .free-filter-sep,
.free-page .free-search-sep {
  display: inline-block;
  width: 1px;
  height: 18px;
  background: var(--gray-light);
  margin: 0 var(--space-1);
  flex: 0 0 auto;
}
/* Input mirrors /work's `.activity-search-input` inside the hero
   pill (home-search.css L73-81): ~19px input text, 16px #CCCCCC
   placeholder. The pill's own `padding: 0 18px 0 24px` carries
   the inset, so the input itself has no padding. */
.free-page .free-search-input {
  flex: 1 1 auto;
  border: none; outline: none; background: transparent;
  font-size: calc(var(--text-base) * 1.2);
  font-weight: 400;
  color: var(--text-primary);
  padding: 0;
  min-width: 0;
}
.free-page .free-search-input::placeholder {
  color: var(--gray-mid);
  font-size: 16px;
  font-weight: 400;
}

.free-page .free-search-clear {
  flex: 0 0 auto;
  appearance: none;
  background: var(--gray-mid);
  border: none;
  width: 18px; height: 18px;
  border-radius: var(--radius-full);
  display: inline-flex; align-items: center; justify-content: center;
  color: #ffffff;
  cursor: pointer;
  margin-right: var(--space-1);
  transition: background 0.15s ease, color 0.15s ease;
}
.free-page .free-search-clear svg { width: 8px; height: 8px; stroke-width: 4; }
.free-page .free-search-clear:hover {
  background: var(--gray-mid);
  color: var(--text-primary);
}

/* ---------- Tabs row (category labels + region/lang filters) -- */
.free-page .free-tabs-row {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--space-6);
  margin: var(--space-5) 0 var(--space-1);
  background: transparent;
  /* TEMP (2026-05-02): stickiness removed at Christine's request while
     finalising the tabs row look. Position/top/z-index plus the two
     companion white-buffer pseudo-elements (::after below + ::before
     above-when-scrolled) all suppressed together — they only existed
     to mask scrolled content sliding behind the sticky row. Restore
     this block as a unit when re-enabling stickiness. */
}
.free-page .free-tabs-row::after,
.free-page.search-collapsible.is-scrolled .free-tabs-row::before {
  content: none;
}
.free-page .free-tabs-row .free-tabs {
  margin: 0;
  border-bottom: none;
  flex: 1 1 auto;
  min-width: 0;
}
.free-page .free-tabs-filters {
  display: flex;
  align-items: center;
  /* Center the filter group vertically inside the row instead of
     bottom-aligning with the tabs underline. */
  align-self: center;
  gap: var(--space-3);
  flex: 0 0 auto;
}
.free-page .free-filter-pop {
  position: relative;
  display: inline-block;
}
.free-page .free-filter-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  border: 0;
  opacity: 0;
  pointer-events: none;
}
.free-page .free-filter-btn {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  background: var(--white);
  border: 1px solid var(--gray-light);
  border-radius: var(--radius-md);
  padding: var(--space-2) var(--space-3);
  font: inherit;
  font-size: var(--text-sm);
  color: var(--text-primary);
  cursor: pointer;
  transition: border-color 120ms ease, background 120ms ease;
}
.free-page .free-filter-btn:hover {
  background: var(--bg-hover);
}
.free-page .free-filter-pop.open .free-filter-btn,
.free-page .free-filter-btn:focus-visible {
  border-color: var(--text-primary);
  outline: none;
}
.free-page .free-filter-chev {
  width: 14px;
  height: 14px;
  flex-shrink: 0;
}
.free-page .free-filter-pop .mw-menu-dropdown {
  right: auto;
  left: 0;
  min-width: 200px;
  max-height: 320px;
  overflow-y: auto;
  /* Sit above the sticky tabs row (z:5) and the preview pane on the
     right so Region/Language popovers never tuck behind either. */
  z-index: 50;
}
.free-page .free-filter-pop { position: relative; z-index: 50; }
.free-page .free-tabs {
  display: flex; flex-wrap: wrap;
  align-items: center;
  gap: 14px;
  margin: var(--space-5) 0 var(--space-1);
  border-bottom: 1px solid var(--gray-light);
  /* Align "ALL" with the product row text below. The .home-cards-container
     adds 40px of horizontal padding to the list column, which is exactly
     the inset needed here — the .activity-item's 16px left margin is
     visually absorbed by the .free-tab button's own optical bearing, so
     56px overshot the row text by ~16px in screenshot measurement.
     Pinned at 40px (matching the cards container padding) instead. */
  padding-left: var(--space-10);
}
.free-page .free-tab {
  appearance: none;
  background: transparent;
  color: var(--ink-2);
  border: none;
  padding: 10px 0;
  margin-bottom: -1px;
  font-size: 0.875rem; /* 14px — one step up from --caption (13px) */
  /* Inactive tabs sit at medium weight so the bold active tab below
     reads as the clear "you are here" — colour + underline alone
     wasn't enough hierarchy at this size. Active state lifts back to
     700 in the .is-active rule. */
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  cursor: pointer;
  transition: color 0.15s ease, box-shadow 0.15s ease, font-weight 0.15s ease;
}
.free-page .free-tab { display: inline-flex; align-items: center; gap: var(--space-3); }
.free-page .free-tab .free-tab-icon {
  width: 14px; height: 14px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
}
.free-page .free-tab.is-active .free-tab-icon { fill: currentColor; }
.free-page .free-tab:hover { color: var(--text-primary); }
.free-page .free-tab.is-active {
  color: var(--text-primary);
  box-shadow: inset 0 -2px 0 var(--text-primary);
  /* Lift the active tab back to bold (base rule sets inactive to 500). */
  font-weight: 700;
}
.free-page .free-tab-fav {
  display: inline-flex; align-items: center;
  /* Hang the star into the 40px padding-left gutter so "ALL" lines up
     with the product row text below (40px = .home-cards-container's
     horizontal padding). Star is 22px + 14px tabs-gap = 36px pulled
     left, leaving a 4px breathing edge. */
  margin-left: calc(-1 * var(--space-9));
}

/* /solutions tab strip — same .free-tabs base as /explore, with a
   "More" dropdown holding the personas that don't fit inline. The
   strip sits flush with the row-text gutter; the fav star hangs
   into it just like /explore. Christine 25 May 2026. */
.free-page .solutions-tabs {
  flex: 1 1 auto;
  min-width: 0;
}
.free-page .solutions-tabs .solutions-more-pop {
  position: relative;
}
.free-page .solutions-tabs .solutions-more-btn {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  cursor: pointer;
}
.free-page .solutions-tabs .solutions-more-btn .free-filter-chev {
  width: 14px;
  height: 14px;
}

/* ---------- Collapsed search-bar + tabs hamburger --------------
   On page load the page-search-bar is fully visible (legacy look).
   Once the user scrolls past the threshold, free.js adds .is-scrolled
   to the page and the bar collapses to a magnifier icon in the tabs
   row. Clicking the icon expands an INLINE search input inside the
   tabs row (not above it), folding the tab strip into a hamburger
   so search + filters share one horizontal line. Returning to the
   top of the page automatically resets everything. */
.free-page.search-collapsible.is-scrolled .page-search-bar { display: none; }

/* Search-toggle button — sits LEFT of the favourites star (or at the
   start of the strip on /explore). Hidden until .is-scrolled. */
.free-page .free-search-toggle {
  appearance: none;
  background: transparent;
  border: none;
  padding: var(--space-2) var(--space-1);
  margin-bottom: -1px;
  cursor: pointer;
  color: var(--ink-2);
  display: none;
  align-items: center;
  transition: color 0.15s ease;
}
.free-page.search-collapsible.is-scrolled .free-search-toggle { display: inline-flex; }
.free-page .free-search-toggle:hover { color: var(--text-primary); }
.free-page .free-search-toggle svg {
  width: 18px; height: 18px;
  fill: none; stroke: currentColor; stroke-width: 2;
}

/* Hamburger toggle (now a direct child of .free-tabs-row, not nested
   inside .free-tabs). Hidden by default; revealed when the inline
   search bar is open so the user can still reach categories. */
.free-page .free-tabs-menu-wrap { position: relative; display: none; align-items: center; }
.free-page .free-tabs-menu-toggle {
  appearance: none;
  background: transparent;
  border: none;
  padding: var(--space-2) var(--space-1);
  cursor: pointer;
  color: var(--ink-2);
  display: inline-flex;
  align-items: center;
  transition: color 0.15s ease;
}
.free-page .free-tabs-menu-toggle:hover { color: var(--text-primary); }
.free-page .free-tabs-menu-toggle svg {
  width: 22px; height: 22px;
  fill: none; stroke: currentColor; stroke-width: 2;
}

/* When search is expanded (only meaningful with .is-scrolled):
   - Hide the tab strip entirely (the magnifier sits inside it and
     hides naturally with its parent).
   - Reveal the hamburger wrapper so categories remain reachable.
   - Reveal the inline search input so it occupies the freed space. */
.free-page.search-collapsible.is-scrolled.search-expanded .free-tabs { display: none; }
.free-page.search-collapsible.is-scrolled.search-expanded .free-tabs-menu-wrap { display: inline-flex; }
.free-page.search-collapsible.is-scrolled.search-expanded .free-search-inline-wrap { display: flex; }
/* When the inline search bar is open, vertically center the row so
   the search bar lines up with the region / language dropdowns.
   (Default flex-end keeps tab underlines pinned to the bottom; we
   only swap to center while expanded.) */
.free-page.search-collapsible.is-scrolled.search-expanded .free-tabs-row { align-items: center; }

/* Inline search input — only ever visible inside the tabs row when
   search is expanded. Sits between the hamburger and the filters. */
.free-page .free-search-inline-wrap {
  display: none;
  align-items: center;
  flex: 1 1 auto;
  min-width: 0;
  gap: var(--space-2);
  padding: 0 14px;
  /* Match the height of the region/language filter buttons. */
  height: 40.39px;
  box-sizing: border-box;
  background: var(--white);
  border: 1px solid var(--gray-light);
  border-radius: var(--radius-full);
}
.free-page .free-search-inline-icon {
  width: 18px; height: 18px;
  flex: 0 0 auto;
  color: var(--ink-2);
}
.free-page .free-search-inline {
  appearance: none;
  background: transparent;
  border: none;
  outline: none;
  flex: 1 1 auto;
  min-width: 0;
  font-size: var(--text-sm);
  color: var(--text-primary);
}
.free-page .free-search-inline::placeholder { color: var(--gray-mid); }
.free-page .free-search-inline-clear {
  appearance: none;
  background: transparent;
  border: none;
  flex: 0 0 auto;
  cursor: pointer;
  font-size: var(--text-lg);
  line-height: 1;
  color: var(--ink-2);
  padding: var(--space-1) var(--space-1-5);
}
.free-page .free-search-inline-clear:hover { color: var(--text-primary); }

/* Hamburger dropdown — vertical category list. Same visual idiom as
   the existing region/language popovers (.mw-menu-dropdown) so it
   feels native, not grafted on. */
.free-page .free-tabs-menu-dropdown {
  position: absolute;
  top: 100%;
  left: 0;
  margin-top: var(--space-1);
  min-width: 200px;
  background: var(--white);
  border: 1px solid var(--gray-light);
  border-radius: var(--radius-lg);
  padding: var(--space-1-5) 0;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.10);
  z-index: 70;
  display: none;
}
.free-page .free-tabs-menu-dropdown.is-open { display: block; }
.free-page .free-tabs-menu-dropdown-item {
  display: block;
  width: 100%;
  background: transparent;
  border: none;
  padding: var(--space-2) var(--space-4);
  font-size: var(--caption);
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-2);
  text-align: left;
  cursor: pointer;
  transition: background 0.12s ease, color 0.12s ease;
}
.free-page .free-tabs-menu-dropdown-item:hover {
  background: var(--bg-hover);
  color: var(--text-primary);
}
.free-page .free-tabs-menu-dropdown-item.is-active { color: var(--text-primary); }

/* Mobile (≤768px) hides .free-tabs-row entirely (rule below at L1083),
   which would also hide our new magnifier toggle and leave search
   inaccessible. So on mobile we opt back into the legacy behaviour:
   keep the page-search-bar always visible (override the collapse
   default) and hide the desktop-only toggles defensively. */
@media (max-width: 768px) {
  /* Match the .is-scrolled selector's specificity so this win even
     after free.js adds the .is-scrolled class on scroll — otherwise
     the desktop collapse rule would hide the bar on mobile too. */
  .free-page.search-collapsible .page-search-bar,
  .free-page.search-collapsible.is-scrolled .page-search-bar,
  .free-page.search-collapsible.is-scrolled.search-expanded .page-search-bar { display: block; }
  .free-page .free-search-toggle,
  .free-page .free-tabs-menu-toggle,
  .free-page .free-tabs-menu-wrap,
  .free-page .free-search-inline-wrap { display: none; }
}
.free-page .free-fav-count {
  display: inline-block;
  margin-left: var(--space-1-5);
  min-width: 18px;
  padding: 0 var(--space-1-5);
  font-size: 11px;
  font-weight: 700;
  line-height: 16px;
  text-align: center;
  color: var(--ink-2);
  background: var(--bg-hover);
  border-radius: var(--radius-full);
}
.free-page .free-tab-fav.is-active .free-fav-count {
  color: var(--white);
  background: var(--text-primary);
}
.free-page .free-fav-empty {
  padding: 28px var(--space-4);
  text-align: center;
  color: var(--ink-2);
  font-size: var(--text-sm);
  line-height: 1.5;
}
.free-page .free-fav-empty .free-fav-empty-icon {
  display: block; margin: 0 auto var(--space-2); opacity: 0.5;
}

/* Search results meta inline in the tabs row. */
.free-page .free-tabs-results {
  display: inline-flex; align-items: center; gap: var(--space-2);
  margin-left: var(--space-2);
  align-self: center;
  padding: 10px 0;
  white-space: nowrap;
  line-height: 1.5;
}
.free-page .free-tabs-results .free-results-title {
  font-size: var(--caption);
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-primary);
  margin-bottom: -1px;
}
.free-page .free-tabs-results .free-results-meta {
  font-size: var(--caption);
  font-weight: 500;
  color: var(--ink-2);
}

/* ---------- Sticky list + preview columns --------------------- */
.free-page .home-cards-container {
  border-top: none;
  padding-top: 0 !important;
}
/* Left list scrolls naturally with the page; the sticky search bar +
   tabs row above it (opaque white background, z-index 6/60) clip its
   content visually so rows never bleed under the navbar. */
.free-page .home-list-col {
  position: static !important;
  align-self: start;
  max-height: none !important;
  overflow: visible !important;
}
/* Re-apply the fluid grid track from home-search.css with higher
   specificity at desktop widths.

   Why: work.css defines
     @media (min-width: 1025px) {
       .mw-page .home-activity-page .activity-columns {
         grid-template-columns: minmax(0, 1fr) 524px;
       }
     }
   That rule has higher specificity than the base
   `.home-activity-page .activity-columns` rule, and both /free and
   /explore carry the .mw-page class — so the work.css override wins
   and locks the right column at 524px. The visible symptom is that
   the right column appears to scale (because the left 1fr track
   absorbs all container shrinkage) while the left column appears
   "fixed" relative to the right.

   Adding `.free-page` to the selector raises the specificity above
   the .mw-page rule (.mw-page.free-page beats .mw-page) so the
   percentage-based right-column track from home-search.css applies
   on /free and /explore. /work and other .mw-page-but-not-free-page
   pages are unaffected and keep the 524px right column. */
@media (min-width: 768px) {
  /* Selector must include #explorePage to beat the ID-bearing :has()
     rule in work.css L1407 (`.mw-page:has(... > #mw-tab-content > .listing-hero)
     .home-activity-page .activity-columns`), which would otherwise win
     on specificity and pin the right pane at 35%. */
  .mw-page.free-page#explorePage .home-activity-page .activity-columns,
  .mw-page.free-page .home-activity-page .activity-columns {
    grid-template-columns: minmax(0, 1fr) minmax(360px, 45%);
    /* Column-gap removed at Christine's request — list and preview now
       sit flush. Side effect: the preview panel's left-side soft
       drop-shadow is painted over by the list rows next to it. The
       shadow above/below/right of the panel still reads normally. */
    column-gap: 0;
    /* Top spacing was previously padding-top: 32px on this container,
       which extended the columns track upward visually. Moved onto the
       two direct children below so both the list and the preview panel
       move down 32px while the columns container itself starts flush
       with the tabs row above. */
  }
  .mw-page.free-page .home-activity-page .activity-columns > .home-list-col,
  .mw-page.free-page .home-activity-page .activity-columns > .home-right-col {
    margin-top: var(--space-8);
  }
}
/* .activity-columns must have no fill of its own on /free — the page
   background (white) shows through, and any per-row / per-panel fills
   are owned by the children themselves. */
.free-page .activity-columns {
  background: transparent !important;
}
/* The grid override above is necessary but NOT sufficient on its own
   for /free and /explore. work.css line 829 also locks the wrapper:
     @media (min-width: 769px) {
       .mw-page .home-search-section {
         width: 1310px;
         max-width: 1310px;
       }
     }
   That means the section that contains the column grid is rendered
   at exactly 1310px on every laptop viewport — even at 1100px, the
   page overflows horizontally and the inner grid never sees a
   narrower parent to scale into. Symptom: both columns appear
   "fixed" because the parent never shrinks.
   Fix: undo the 1310px lock on /free and /explore so the section
   fills its parent and the inner .home-cards-container (which has
   its own max-width: 1425px; margin: 0 auto) takes over as the
   centering/capping element. /work and other .mw-page-only pages
   keep the 1310px lock unchanged. */
@media (min-width: 769px) {
  .mw-page.free-page .home-search-section {
    width: auto;
    max-width: none;
  }
}
/* Strip the 24px top padding inherited from home-search.css L335
   (`padding: var(--space-6) 0 var(--space-8)`). Scoped to /free only
   per Christine's request — other pages keep their default top spacing. */
.mw-page.free-page .home-search-section {
  padding-top: 0;
}
/* Preview pane pins directly below the sticky search-bar + tabs stack
   so it stays in view while the left list scrolls. The pane scrolls
   internally if its own content exceeds the viewport height. */
/* Override the universal 32px margin-top on .home-right-row1 (set in
   home-search.css) for /free only. On /free the panel must align flush
   with the top of the left list — Christine's explicit ask. The
   trade-off is that the top edge of the soft drop-shadow now extends
   above the panel into the sticky-tabs area and may be partly covered
   there. The left/right/bottom shadow edges remain fully visible. */
.free-page .home-right-row1 {
  margin-top: 0;
}
.free-page .home-right-col {
  /* Background was previously --off-white (#FAFAFA), but that masked
     the panel's soft 6%-alpha drop-shadow (which renders correctly
     against white on the home page cards). Removed so the shadow is
     visible against the .home-cards-container's white background —
     matching the home page card shadow look exactly. */
  /* min-height removed per Christine — column sizes to its content
     along with the panel inside it. */
  border-top: none;
  position: sticky !important;
  top: var(--free-sticky-cols);
  align-self: start;
  max-height: var(--free-cols-max-h) !important;
  /* overflow MUST be visible — `overflow-y: auto` clips the panel's
     drop-shadow on left/right/bottom (the browser establishes a
     clipping context on both axes once either is non-visible). The
     panel sizes to its content so no scroll is needed. */
  overflow: visible !important;
  z-index: 4;
}
/* /explore reuses the .free-page styles but wants the preview pane to
   fit its own content height — no fixed cap, no internal scroll. The
   pane is still sticky so it stays in view as the left list scrolls. */
.free-page#explorePage .home-right-col {
  min-height: 0;
  max-height: none !important;
  height: auto !important;
  overflow-y: visible !important;
}
.free-page#explorePage .home-right-col .activity-preview-panel,
.free-page#explorePage.mw-page .home-right-col .activity-preview-panel,
.free-page#explorePage .activity-preview-section,
.free-page#explorePage .preview-holding-ad,
.free-page#explorePage .preview-holding-ad.preview-holding-ad-rotator {
  /* /explore preview pane (and its holding-ad rotator) fit their own
     content height — no fixed 600px cap. Overrides:
       - the 500px on .activity-page .activity-preview-section in
         explore-work.css
       - the 600px min-height on .home-right-col, the panel, and the
         active holding-ad card from earlier in this file
     Other pages (/work, /home, /free) keep their original heights
     because this block is scoped to #explorePage. */
  height: auto !important;
  min-height: 0 !important;
  max-height: none !important;
  overflow: visible !important;
}
/* Short-viewport rescue: the preview pane is sticky-pinned below the
   search bar, so when a kit's content is taller than the available
   viewport the bottom of the pane is unreachable. Cap the pane's
   height to the visible space below the sticky bar (with a small
   bottom gutter) and let it scroll internally. The cap only kicks in
   when content actually exceeds the viewport, so taller screens
   continue to render the pane at its natural height. Scoped to the
   panel itself so the inner sections don't establish their own scroll
   contexts. */
@media (max-height: 900px) {
  .free-page#explorePage .home-right-col .activity-preview-panel,
  .free-page#explorePage.mw-page .home-right-col .activity-preview-panel {
    max-height: calc(100vh - var(--free-sticky-cols) - var(--space-6)) !important;
    overflow-y: auto !important;
  }
}
/* Preview pane on /explore is always the canonical white surface —
   no hover/idle/empty state may flip it. The panel itself is the
   only painted surface; inner wrappers stay transparent so the
   panel's white + soft-shadow frame is visible all the way around. */
.free-page#explorePage .home-right-col,
.free-page#explorePage .home-right-col .activity-preview-panel,
.free-page#explorePage .home-right-col .activity-preview-section {
  background: var(--white) !important;
}
/* Slug (left) and time (right) sit on the same line above the title.
   Scoped to /explore so the shared .activity-preview-tag rules on
   /free, /home and /work keep their original block layout. */
.free-page#explorePage .activity-preview-combined .activity-preview-tag {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  margin-bottom: 5px;
}
/* /free preview title — font-size 16px → 18px, line-height 1.3 → 1.5
   per Christine. Scoped to /free only — /explore keeps its 17px/1.45.
   min-height bumped to match (2 lines * 1.5em) so the 2-line clamp
   reserves enough vertical space.
   `position: relative` anchors the ::after gradient divider below. */
.free-page:not(#explorePage) .activity-preview-combined .activity-preview-title {
  font-size: 18px;
  line-height: 1.5;
  position: relative;
  /* The 2-line height reservation (preventing CTA jumps between
     short and long titles) lives on the parent `.ep-title-block`
     wrapper now, NOT on the title itself. The title sizes to its
     actual content (1 or 2 lines) so the gradient divider below it
     sits 12px from the visible text on every report. */
  min-height: 0;
  /* No bottom margin on the title — the gap between the title and
     the gradient divider is controlled by `.ep-title-divider`'s
     `margin-top: 12px` so the spacing is defined in one place. */
  margin-bottom: 0;
}
/* Fixed-height wrapper around the title + gradient divider. Reserves
   space for the worst case (a 2-line title + 12px gap + 3px divider)
   so the description / CTA below never shifts between rows. Inside
   this fixed box the title flows from the top — short titles take
   one line, the divider sits right below, and the leftover space
   appears as invisible padding at the bottom of the block. */
.free-page:not(#explorePage) .activity-preview-combined .ep-title-block {
  min-height: unset;
}
/* The divider under the title — Christine (28 May v9): swapped from
   the 50×3 brand gradient to a quiet 64×1 grey hairline so /free reads
   in lockstep with /work (see static/css/work.css L3086 — same width,
   height, margin, and --ink-4 token). The title-block min-height
   reservation stays at 69px; the 2px shorter divider falls inside the
   existing bottom slack so nothing below it shifts. */
.free-page:not(#explorePage) .ep-title-divider {
  width: 59px;
  height: 5px;
  margin-top: var(--space-3);
  background:
    linear-gradient(var(--kicker-t10), var(--kicker-t10))  0px 0 / 5px 5px no-repeat,
    linear-gradient(var(--kicker-t09), var(--kicker-t09))  6px 0 / 5px 5px no-repeat,
    linear-gradient(var(--kicker-t08), var(--kicker-t08)) 12px 0 / 5px 5px no-repeat,
    linear-gradient(var(--kicker-t07), var(--kicker-t07)) 18px 0 / 5px 5px no-repeat,
    linear-gradient(var(--kicker-t06), var(--kicker-t06)) 24px 0 / 5px 5px no-repeat,
    linear-gradient(var(--kicker-t05), var(--kicker-t05)) 30px 0 / 5px 5px no-repeat,
    linear-gradient(var(--kicker-t04), var(--kicker-t04)) 36px 0 / 5px 5px no-repeat,
    linear-gradient(var(--kicker-t03), var(--kicker-t03)) 42px 0 / 5px 5px no-repeat,
    linear-gradient(var(--kicker-t02), var(--kicker-t02)) 48px 0 / 5px 5px no-repeat,
    linear-gradient(var(--kicker-t01), var(--kicker-t01)) 54px 0 / 5px 5px no-repeat;
}
/* Brand-gradient horizontal divider + meta line directly under the
   preview title. Implemented as a single ::before pseudo on BOTH
   #ep-snippets and #ep-description (JS toggles between them via the
   `.hidden` class depending on whether the report has key_headlines
   or an exec paragraph; the hidden one's ::before doesn't render).
   The 50px × 3px gradient line is painted as a background-image at
   top-left of the pseudo; padding-top reserves space for it; the
   text content "Sourced research · 38 languages · 69 countries"
   sits below the line. Single pseudo handles both because ::before
   only allows one element per parent. */
/* Replace numeric "1./2./3." prefixes on the key-findings list with
   colored bullets — pink / coral / amber by row. Scoped to /free.
   Hides the existing .ep-snippet-num span and adds a circular ::before
   bullet on each .ep-snippet-item, colored by nth-child. */
.free-page:not(#explorePage) #ep-snippets .ep-snippet-num {
  display: none;
}
/* Override the baseline alignment from explore-work.css so the bullet
   aligns with the first text line (not the baseline of all lines). */
/* Christine (28 May v8): bullet discs swapped to the brand arrow.svg
   (cyan dashed-tail + filled triangle), matching the /work LIVE PREVIEW
   marker and /explore .ep-bullets above. Same SVG, same 26×14 dimensions,
   same left-aligned background + -2px right-margin pull-in. The previous
   per-row colour variation (cyan / purple / amber by nth-child) collapses
   to a single cyan arrow — the SVG is authored in #3bc0ff and isn't
   recolourable without a per-row filter or per-row asset. */
.free-page:not(#explorePage) #ep-snippets .ep-snippet-item {
  align-items: flex-start;
  /* Zero the flex gap so the -2px right-margin on ::before pulls the
     snippet body 5px closer to the arrow (same treatment as /work). */
  gap: 0;
}
.free-page:not(#explorePage) #ep-snippets .ep-snippet-item::before {
  content: "";
  display: inline-block;
  flex-shrink: 0;
  width: 26px;
  height: 14px;
  background: url("/static/images/icons/arrow.svg") no-repeat left center / contain;
  /* Optically baseline the arrow against the first line of body copy.
     Text 14px × line-height 1.65 ≈ 23px line box; arrow 14px tall;
     centred = (23 − 14) / 2 ≈ 4.5 → round to 5px. */
  margin-top: 5px;
  margin-right: -2px;
}
/* Report meta grid — Report ID / Product / Region.
   Three equal columns matching the My Work preview panel style. */
.free-page:not(#explorePage) .activity-preview-combined #ep-meta {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  column-gap: var(--space-5);
  padding-top: 10px;
  margin-bottom: 20px;
}
.ep-mg-field {
  display: flex;
  flex-direction: column;
  gap: 1px;
  min-width: 0;
}
.ep-mg-label {
  font-size: 11px;
  font-weight: 500;
  line-height: 1.2;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: #8a8a8a;
  white-space: nowrap;
}
.ep-mg-value {
  font-size: 13px;
  font-weight: 500;
  line-height: 1.2;
  color: var(--navy);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* /free preview eyebrow tag styling — scoped to /free only:
   - bottom margin: 2px → 8px (more breathing room above the title)
   - color: gray-dark → black (stronger eyebrow presence)
   - letter-spacing: 0.04em → 0.14em (per Christine's "+0.1" request) */
.free-page:not(#explorePage) .activity-preview-combined .activity-preview-tag {
  margin-bottom: var(--space-2);
  color: var(--navy);
  letter-spacing: 0.14em;
}
/* Title-block wrapper on /explore — same pattern as /free, recalculated
   for the /explore title size (17px × 1.45 line-height = ~24.6px per line;
   2 lines ≈ 49.3px + 12px gap + 3px divider ≈ 65px). Reserves space for
   the worst-case 2-line title so the meta line / CTA / description below
   never shifts between rows of different title length. */
.free-page#explorePage .activity-preview-combined .ep-title-block {
  min-height: unset;
}
/* Divider — Christine (28 May v9): swapped from the 50×3 brand gradient
   to a 64×1 grey hairline so /explore stays in lockstep with /free and
   /work above. Same --ink-4 token used across all three surfaces. */
.free-page#explorePage .ep-title-divider {
  width: 59px;
  height: 5px;
  margin-top: var(--space-3);
  background:
    linear-gradient(var(--kicker-t10), var(--kicker-t10))  0px 0 / 5px 5px no-repeat,
    linear-gradient(var(--kicker-t09), var(--kicker-t09))  6px 0 / 5px 5px no-repeat,
    linear-gradient(var(--kicker-t08), var(--kicker-t08)) 12px 0 / 5px 5px no-repeat,
    linear-gradient(var(--kicker-t07), var(--kicker-t07)) 18px 0 / 5px 5px no-repeat,
    linear-gradient(var(--kicker-t06), var(--kicker-t06)) 24px 0 / 5px 5px no-repeat,
    linear-gradient(var(--kicker-t05), var(--kicker-t05)) 30px 0 / 5px 5px no-repeat,
    linear-gradient(var(--kicker-t04), var(--kicker-t04)) 36px 0 / 5px 5px no-repeat,
    linear-gradient(var(--kicker-t03), var(--kicker-t03)) 42px 0 / 5px 5px no-repeat,
    linear-gradient(var(--kicker-t02), var(--kicker-t02)) 48px 0 / 5px 5px no-repeat,
    linear-gradient(var(--kicker-t01), var(--kicker-t01)) 54px 0 / 5px 5px no-repeat;
}
/* Meta line directly under the divider — clock icon + time + middle dot
   + deliverables. Single-line strip in --gray-mid; the clock and the
   middle-dot separator both flow inline with the text. */
.free-page#explorePage .ep-meta-line {
  display: flex;
  align-items: center;
  gap: var(--space-1-5);
  margin-top: var(--space-3);
  margin-bottom: var(--space-4);
  font-size: var(--text-xs);
  font-weight: var(--font-weight-normal);
  line-height: 1.4;
  color: var(--ink-2);
}
.free-page#explorePage .ep-meta-line.hidden { display: none; }
.free-page#explorePage .ep-meta-line .ep-meta-clock {
  width: 12px;
  height: 12px;
  flex: 0 0 auto;
  color: currentColor;
}
.free-page#explorePage .ep-meta-line .ep-meta-sep {
  opacity: 0.6;
}
/* Bullet list under the description — "Who this is for" + "How it works"
   rows. List reset; label in bold; em-dash flows inline between label
   and value. Christine (28 May v8): marker swapped from native pink/purple
   discs to the brand arrow.svg (cyan dashed-tail + filled triangle) to
   match /work's LIVE PREVIEW snippet marker. Same SVG, same 26×14
   dimensions, same left-aligned background + -2px right-margin pull-in
   used in static/css/work.css L2956+. */
.free-page#explorePage .ep-bullets {
  list-style: none;
  margin: var(--space-4) 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  font-size: var(--ew-preview-desc-size);
  line-height: var(--ew-preview-desc-lh);
  color: var(--navy);
}
.free-page#explorePage .ep-bullets.hidden { display: none; }
.free-page#explorePage .ep-bullets li {
  margin: 0;
  padding: 0;
  display: flex;
  align-items: flex-start;
  gap: 0;
}
.free-page#explorePage .ep-bullets li::before {
  content: "";
  display: inline-block;
  flex-shrink: 0;
  width: 26px;
  /* Christine (28 May v11): arrow now vertical-centres against the
     label line. Box height = label line-box (font-size × label
     line-height 1.3 set below), and the 26×14 arrow PNG is centred
     inside that box via background-position. This replaces the
     hand-tuned margin-top: 6px that used to baseline the arrow's
     triangle against the cap-line of the OLD inline label+value
     layout — the new stacked-heading layout has a different first
     line (heading-weight, tighter line-height) so the centring needs
     to follow it directly. */
  height: calc(var(--ew-preview-desc-size, var(--text-sm, 14px)) * 1.3);
  background: url("/static/images/icons/arrow.svg") no-repeat left center;
  background-size: 26px 14px;
  margin-top: 0;
  margin-right: -2px;
}
/* Christine (28 May v9): row body is a flex column so the label
   ("Who this is for" / "How it works") renders as a heading on its
   own line above the value paragraph, instead of flowing inline
   with an em-dash separator. Stops the label from wrapping into a
   narrow ragged column when the value text is long. */
.free-page#explorePage .ep-bullets li .ep-bullets-body {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  min-width: 0; /* lets long values wrap inside the flex item */
  flex: 1 1 auto;
  /* Christine (28 May v15): nudge the heading + body 10px right of
     the arrow so the text doesn't crowd the arrow's triangle tip.
     padding (not margin) so the gap sits inside the flex item and
     long values still wrap against the row's right edge cleanly. */
  padding-left: 10px;
}
.free-page#explorePage .ep-bullets li .ep-bullets-label {
  display: block;
  font-weight: var(--font-weight-semibold);
  /* Slightly tighter line-height than body so the heading reads as
     a label, not a first paragraph line. */
  line-height: 1.3;
}
.free-page#explorePage .ep-bullets li .ep-bullets-value {
  display: block;
  /* Christine (28 May v22): inspector showed this computing to
     pure #000000 — pin to brand black so the /explore + /solutions
     preview-pane bullet values match the brand navy used everywhere
     else in the preview. */
  color: var(--navy);
}
/* Back-compat: any remaining inline-em-dash row (kit "Output" or
   future additions that still use the old <strong>label</strong>
   markup without the wrapper) keeps the bold label treatment. */
.free-page#explorePage .ep-bullets li strong {
  font-weight: var(--font-weight-semibold);
}
/* Kit contents block — sits at the bottom of the preview pane on
   kit rows. Body copy, markers, and spacing all reuse the same
   tokens as the .ep-bullets list above so the section reads as
   visually identical body copy with the same alternating brand
   discs (pink / coral) under the "Kit contents" label. */
.free-page#explorePage .ep-kit-contents {
  margin-top: var(--space-4);
  font-size: var(--ew-preview-desc-size);
  line-height: var(--ew-preview-desc-lh);
  font-weight: var(--font-weight-normal);
  color: var(--navy);
}
.free-page#explorePage .ep-kit-contents.hidden { display: none; }
.free-page#explorePage .ep-kit-contents-label {
  font-weight: var(--font-weight-semibold);
  margin-bottom: var(--space-2);
}
.free-page#explorePage .ep-kit-contents-list {
  list-style: disc outside;
  margin: 0;
  padding: 0 0 0 var(--space-4-5);
  /* No flex gap between items — they should stack with the same
     vertical rhythm as the surrounding body copy (driven purely by
     the inherited line-height), not the wider --space-4 gap used
     between the labeled rows of .ep-bullets. */
}
.free-page#explorePage .ep-kit-contents-list li {
  margin: 0;
  padding: 0;
}
.free-page#explorePage .ep-kit-contents-list li:nth-child(odd)::marker {
  color: var(--cyan);
}
.free-page#explorePage .ep-kit-contents-list li:nth-child(even)::marker {
  color: var(--purple);
}
/* CTA row on /explore is 1-, 2-, or 3-pill depending on auth state
   (Start chat + optional Add-to-Project + optional Subscribe). Pills
   auto-share the row width: 2 pills → 2 columns ~50/50, 3 pills →
   3 columns ~33/33/33. Centred so a lone Start chat pill doesn't
   stretch edge-to-edge. */
.free-page#explorePage .cta-pill-row {
  justify-content: center;
}
.free-page#explorePage .cta-pill-row > * {
  /* Christine (28 May v10): /explore pills are content-width like
     /free — was flex:1 1 0 which stretched each to fill its slot.
     v14: inherits the shared --cta-pill-min-w 150px floor from the
     .free-page .cta-pill-row > * rule above; no override needed. */
  flex: 0 0 auto;
}
/* Inline label + price on the same row inside each pill (Christine
   7 May 2026). Overrides the shared column layout from
   `.free-page .cta-pill` so the dollar amount sits beside the
   action label instead of stacked beneath it. /free keeps the
   stacked layout — it's only flipped on /explore. nowrap keeps
   "Subscribe $20" on a single line — pills grow to fit. */
.free-page#explorePage .cta-pill {
  flex-direction: row;
  flex-wrap: nowrap;
  gap: var(--space-1);
  white-space: nowrap;
}
.free-page#explorePage .cta-pill__sub {
  opacity: 1;
  font-size: var(--text-sm);
  font-weight: 500;
}
/* When the Subscribe pill is hidden (signed-in / subscriber / enterprise)
   the JS adds `cta-pill-row--single` to the row so the lone Start chat
   pill flips to the solid black treatment from the dummy. Width capped
   at 50% per Christine 7 May 2026 so the lone pill doesn't stretch
   edge-to-edge of the preview pane. flex-grow:0 disables the
   row > * { flex:1 1 0 } stretch above; align is handled by the row's
   justify-content:center. */
.free-page#explorePage .cta-pill-row--single {
  /* Christine (28 May v23): row stays left-aligned so the pill
     sits in line with the rest of the CTA family above. The text
     inside the pill is centred via text-align below — the two
     concerns are independent. */
  justify-content: flex-start;
}
.free-page#explorePage .cta-pill-row--single .cta-pill#ep-cta-start {
  background: var(--navy) !important;
  color: var(--white) !important;
  border-color: var(--navy) !important;
  text-align: center !important;
  /* Christine (28 May v10): lone Start chat pill is content-width
     like the rest of the CTA family — was capped at 50% which made
     it visually inconsistent with the multi-pill rows. */
}
/* Christine (28 May v24): the "Start chat" label was rendering
   hard-left inside the pill. Root cause: the row's
   `> * { flex: 1 1 0 }` rule stretches the button wider than its
   content, but the inner `.cta-pill__label` is a display:block
   element so it fills the pill width — and `align-items:center`
   on the flex parent doesn't centre text inside a block-width
   child. Pinning the label to `text-align:center` (and giving
   it explicit `width:100%` so text-align has a box to centre
   against) puts "Start chat" dead-centre of the pill regardless
   of how wide the row flex stretches it. */
.free-page#explorePage .cta-pill-row--single .cta-pill#ep-cta-start .cta-pill__label,
.free-page#explorePage .cta-pill-row--single .cta-pill#ep-cta-start .cta-pill__sub {
  width: 100%;
  text-align: center !important;
}
.free-page#explorePage .cta-pill-row--single .cta-pill#ep-cta-start:hover {
  /* Christine (28 May v23): flip to brand pink on hover so the lone
     Start chat pill matches the rest of the app's CTA hover
     treatment (see .free-page .cta-pill:hover at L1804+ and the
     home-hero New Chat pill in work.css L458+). Was inverting to
     white/black which read as a bug, not a hover state. */
  background: var(--pink) !important;
  color: var(--white) !important;
  border-color: var(--pink) !important;
}
/* Hide the legacy #ep-credits container on /explore — replaced by the
   .cta-pill-row above. Kept in the DOM so existing by-id lookups don't
   error, but visually retired. */
.free-page#explorePage #ep-credits {
  display: none !important;
}
/* Bump the preview heading by one step and open up the line height.
   Hard-cap at 2 lines so a long product title can't push the rest of
   the preview pane content downward. -webkit-box + line-clamp gives
   the truncation; max-height provides a non-webkit fallback. */
.free-page#explorePage .activity-preview-combined .activity-preview-title {
  font-size: 17px;
  line-height: 1.45;
  width: 90%;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  overflow: hidden;
  max-height: calc(1.45em * 2);
}
/* Hairline divider rendered 100px from the bottom of the preview pane
   on both /free and /explore. The pane sizes to its content, so the
   divider always sits 100px above whatever the bottom edge happens to
   be — giving the pricing block a consistent ~100px zone underneath.
   Scoped to #explorePreviewCards so it only renders when a product is
   being previewed (the holding-ad rotator is a separate sibling). */
.free-page #explorePreviewCards .activity-preview-section {
  position: relative;
}
/* Bottom padding on .activity-preview-combined removed on the
   preview pane (the global rule in home-search.css applies
   `padding: 30px` to all four sides; here we zero out the bottom so
   the preview content sits flush with the section edge). Applies to
   /explore (`.free-page#explorePage`) and /free (`.free-page` alone,
   no id) so both panes share the same fixed-height behaviour. */
.free-page #explorePreviewCards .activity-preview-combined {
  /* Padding: 15px top / 30px sides / 30px bottom. Top reduced from
     27px → 15px per Christine. Overrides the global `padding: 30px`
     from home-search.css. */
  padding: 15px var(--space-7-5) var(--space-7-5);
  /* Height removed per Christine — block sizes to its content.
     Absolutely-positioned children (.ep-bottom-stats, ::before
     divider, Show-more popover) still anchor to this block via the
     position: relative below; their bottom-edge offsets now follow
     the content's actual bottom. */
  /* Establish positioning context for the absolutely-positioned
     Show-more popover and bottom-stats so they're anchored to the
     combined block (not the viewport or some distant ancestor). */
  position: relative;
}
.free-page #explorePreviewCards .activity-preview-section::before {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: 100px;
  /* Thick white separator above the pricing strip. The pane sits on
     off-white (#FAFAFA), so a solid white band reads as a clean
     visual gap — heavier and brighter than the previous 0.75px
     gray hairline. Rendered as a filled bar (no border) so the full
     6px height shows. */
  height: 6px;
  background: var(--white);
  pointer-events: none;
}
/* On /explore only, pin the pricing block inside that reserved 100px
   zone, edge-to-edge, so it always sits at the bottom of the pane
   regardless of content height above. /free keeps its existing static
   flow (overridden further down) — only the divider is re-added there.

   Inverted-strip treatment: solid black band, white text, larger
   price values, generous interior padding — turns the pricing row
   into a clear visual stop at the bottom of the pane. */
.free-page#explorePage #explorePreviewCards #ep-credits {
  position: absolute !important;
  /* !important on inset values is required because an earlier rule sets
     `inset: auto !important` on this same element to keep /free's
     pricing in static flow. Without !important here, that wins and the
     pricing sits at top:auto/bottom:auto and disappears behind content. */
  left: 0 !important;
  right: 0 !important;
  bottom: 0 !important;
  top: auto !important;
  padding: 18px var(--ew-preview-card-padding-x);
  margin-top: 0 !important;
  background: var(--off-white) !important;
  color: var(--navy) !important;
}
/* Hide the hairline top border that .ep-credits draws in the shared
   stylesheet — the off-white band already provides its own visual stop. */
.free-page#explorePage #explorePreviewCards #ep-credits::before {
  display: none !important;
}
/* Black price values + muted-black labels inside the off-white band.
   The dollar amount (column value) is bumped to 16px / 600 weight so
   it reads as the primary call to action; the "X credits" label stays
   small underneath in a softer black. */
.free-page#explorePage #explorePreviewCards #ep-credits .ep-credit-col-value {
  color: var(--navy) !important;
  font-size: var(--text-base) !important;
  font-weight: var(--font-weight-semibold) !important;
  line-height: 1.2;
}
.free-page#explorePage #explorePreviewCards #ep-credits .ep-credit-col-label {
  color: rgba(0, 0, 0, 0.6) !important;
  font-size: var(--text-2xs) !important;
  margin-top: 2px;
}
/* When a column carries only a label (no separate $value) — e.g. the
   "Buy $10" line, which arrives as label-only because it doesn't have
   an "N credits" suffix — promote that label to the same weight and
   colour as the priced columns so it reads as a real call to action
   instead of secondary microcopy. */
.free-page#explorePage #explorePreviewCards #ep-credits .ep-credit-col:not(:has(.ep-credit-col-value)) .ep-credit-col-label {
  color: var(--navy) !important;
  font-size: var(--text-base) !important;
  font-weight: var(--font-weight-semibold) !important;
  margin-top: 0 !important;
}
/* Hide the hairline divider above the pricing block — it sat 100px
   from the bottom and was a soft separator for a light pricing strip.
   With the black band it's redundant and creates visual noise. */
.free-page#explorePage #explorePreviewCards .activity-preview-section::before {
  display: none !important;
}
/* The legacy `#ep-meta-audience-row` / `#ep-meta-howitworks-row`
   blocks have been replaced on /explore by the `<ul class="ep-bullets">`
   list (Suitable for + How it works rendered as `<li>` rows with bold
   label and em-dash value). Styling for the new structure lives near
   the new `.ep-bullets` rule above. */
.free-page#explorePage #ep-description {
  display: block;
  overflow: visible;
}
/* Force-display preview content slots so no inherited rule can hide them.
   #ep-credits intentionally excluded — on /free the legacy credit block
   is replaced by the .cta-pill-row above and hidden via display: none. */
.free-page #explorePreviewCards #ep-snippets:not(.hidden),
.free-page #explorePreviewCards #ep-bottom-stats:not(.hidden),
.free-page #explorePreviewCards #ep-ad:not(.hidden) {
  display: block !important;
  visibility: visible !important;
  opacity: 1 !important;
  height: auto !important;
  max-height: none !important;
  overflow: visible !important;
}

/* Kill the shared hover/active gray tint — on /free the preview pane
   stays white regardless of which list row is hovered or selected. */
.free-page .home-cards-container:has(.home-popular-list .activity-item:hover) .home-right-col,
.free-page .home-cards-container:has(.home-popular-list .activity-item.hover-active) .home-right-col,
.free-page .home-cards-container:has(.home-popular-list .activity-item:hover) .home-right-col .activity-preview-panel,
.free-page .home-cards-container:has(.home-popular-list .activity-item.hover-active) .home-right-col .activity-preview-panel {
  /* Mirror the panel fill on hover/active so it doesn't shift when a
     row in the list is highlighted. */
  background: var(--white);
}
.free-page.mw-page .home-right-col .activity-preview-panel,
.free-page .activity-preview-panel {
  /* /free-specific sizing + layout only. The panel's visual identity
     (white background, no border, rounded corners) lives ONCE in
     home-search.css on the shared `.activity-preview-panel` rule.
     The drop-shadow lives on the parent `.home-right-row1` wrapper
     (also in home-search.css) via `filter: drop-shadow()`. */
  box-sizing: border-box;
  margin-top: 0;
  /* Height removed per Christine — panel sizes to its content. */
  height: auto;
  min-height: 0;
  max-height: none;
  /* `overflow: hidden` clips inner content (live-preview cards,
     holding-ad surfaces) to the panel's rounded shape so the corners
     read as rounded in every state. Was `visible` previously, which
     let flat-cornered live-preview content bleed past the radius,
     making the panel look square when hovering a row. Drop-shadow
     lives on the parent `.home-right-row1` wrapper via
     `filter: drop-shadow()`, so it is NOT clipped by this. */
  overflow: hidden;
  position: relative;
  /* Match the holding-ad card radius (--radius-lg = 12px) so the
     panel and the ad surface inside it share identical corner
     rounding. */
  border-radius: var(--radius-lg) !important;
}
/* Strip backgrounds off every wrapper INSIDE the panel so only the
   panel's own off-white fill paints, and the panel's border stays
   visible all the way around. The colored ad-cards retain their own
   fills (handled by .preview-holding-ad-card--<variant> rules). */
.free-page .activity-preview-panel .preview-holding-ad,
.free-page.mw-page .activity-preview-panel .preview-holding-ad,
.free-page .activity-preview-panel .activity-preview-section,
.free-page.mw-page .activity-preview-panel .activity-preview-section,
.free-page .activity-preview-panel .activity-preview-section:hover,
.free-page.mw-page .activity-preview-panel .activity-preview-section:hover,
.free-page .activity-preview-panel .activity-preview-combined,
.free-page.mw-page .activity-preview-panel .activity-preview-combined {
  background: transparent !important;
}
/* Live-preview block (only visible when hovering a report) gets a
   small top inset so its content doesn't sit flush at the top of
   the panel. Holding-ad rotator stays flush as designed. */
.free-page #explorePreviewCards {
  margin-top: 9px;
}
.free-page .home-activity-page .activity-preview-section {
  height: auto;
  overflow: visible !important;
  border-top: none !important;
}
/* /free preview pane is solid white at all times — neither the panel
   nor its inner .activity-preview-section ever shifts colour. The
   shared work.css rule paints .activity-preview-section #fafafa
   permanently (rest + hover) to match the legacy Free/Explore look;
   override it back to white here so the preview surface is one flat
   white slab regardless of cursor position. */
.free-page .activity-preview-section,
.free-page .activity-preview-section:hover,
.free-page .home-right-col .activity-preview-section,
.free-page .home-right-col .activity-preview-section:hover {
  background: var(--white) !important;
}
.free-page .activity-preview-panel,
.free-page .activity-preview-panel:hover {
  background: var(--white) !important;
}

/* /explore subcategory headings (mirror navbar mega-menu groupings).
   Reuses .home-mega-group-heading typography; this rule only handles
   placement inside the vertical list flow.
   Box height was 100px (matching a card row) — reduced to 60px per
   Christine 7 May 2026 (originally tightened to 40px on 5 May, then
   loosened back up by 20px to give the pink label more breathing room).
   Padding is zeroed and the heading text is anchored to the bottom of
   the box via flexbox so it sits flush with the bottom edge — directly
   above the first card of the new section. margin-left = card
   margin-left (16px) + card inner padding-left (24px) = 40px, so the
   pink label starts on the same x-axis as the row title beneath it
   without using padding. */
.free-page .home-list-col .explore-section-heading,
.mw-page .home-list-col .explore-section-heading {
  height: 60px;
  padding: 0;
  margin-top: 0;
  margin-left: var(--space-10);
  display: flex;
  align-items: flex-end;
  color: var(--cyan);
  text-transform: uppercase;
  font-weight: 700;
  font-size: 16px;
  text-decoration: none;
}
.free-page .home-list-col .explore-section-heading:not(.all-reports-heading),
.mw-page .home-list-col .explore-section-heading:not(.all-reports-heading) {
  color: var(--cyan);
  font-weight: 400;
  text-transform: none;
  text-decoration: underline;
}
.free-page .home-list-col .explore-section-heading::before,
.free-page .home-list-col .explore-section-heading::after,
.mw-page .home-list-col .explore-section-heading::before,
.mw-page .home-list-col .explore-section-heading::after {
  content: none !important;
}
.free-page .home-list-col .all-reports-heading,
.free-page#explorePage .home-list-col .all-reports-heading,
.mw-page .home-list-col .all-reports-heading {
  cursor: default;
  pointer-events: none;
}
.all-reports-btn {
  background: none;
  border: none;
  padding: 0;
  margin: 0;
  font: inherit;
  color: inherit;
  text-transform: inherit;
  font-weight: inherit;
  font-size: inherit;
  text-decoration: inherit;
  text-decoration-thickness: inherit;
  text-underline-offset: inherit;
  text-decoration-skip-ink: inherit;
  letter-spacing: inherit;
  cursor: pointer;
  appearance: none;
  display: block;
  width: 100%;
  text-align: left;
}

/* No top hairline on the cards container — the first list row is now
   borderless on top. The right preview pane keeps its own border-top
   via .home-right-col, so the right column is unaffected. */
.free-page .home-cards-container {
  border-top: none;
}

/* Override the global home-search.css rule that applies
   `padding: 0 30px; margin: 0 -30px;` to .home-popular-list — that
   negative right margin pushes the list 30px into the right preview
   column. On /free we keep the list strictly inside its own column. */
.free-page .home-list-col .home-popular-list,
.free-page .home-list-col #freeFileList {
  padding-right: 0 !important;
  margin-right: 0 !important;
}

/* Rows: 100px tall, no perimeter borders, single visible bottom hairline.
   We override the canonical .mw-page ::before hairline (which uses the
   too-pale --gray-light token) by drawing our own border-bottom in the
   darker --gray-mid so 0.75px actually reads against the white surface. */
.free-page .home-list-col .activity-item,
.free-page .home-list-col .activity-item.mw-frow,
.free-page .home-list-col .activity-item.explore-item {
  border: none !important;
  border-bottom: 0.75px solid var(--free-hairline) !important;
  box-shadow: none !important;
  border-radius: 0 !important;
  height: 100px !important;
  min-height: 100px !important;
  max-height: 100px !important;
  /* 16px LEFT gutter only on desktop — right margin removed at
     Christine's request so rows run flush against the right column
     edge (and the preview pane next to it). The mobile breakpoint
     at ~line 944 resets margin-left back to 0 so phones stay flush. */
  margin-left: var(--space-4) !important;
  margin-right: 0 !important;
  /* Override the canonical white fill from home-search.css so /free
     inactive cards inherit the page surface instead of stamping a solid
     #FFFFFF rectangle inside the row. The selected/hover states still
     paint their own backgrounds further down. */
  background: transparent !important;
  position: relative;
}
/* Hover/active state: white fill + deeper big soft drop-shadow so the
   row reads as a clean elevated card. The border-bottom hairline is
   suppressed on the hovered card (the shadow does the visual work
   instead — borderless silhouette with the elevation read solely from
   the shadow). Resting rows keep their border-bottom as the list
   separator. position:relative + high z-index lift the row above
   (a) its flush-stacked sibling rows AND (b) the right preview column
   (z-index:4 on .home-right-col), so the shadow doesn't get clipped
   on the right where it would otherwise paint behind the preview. */
.free-page .home-list-col .activity-item:hover,
.free-page .home-list-col .activity-item.hover-active,
.free-page .home-list-col .activity-item.hover-active:hover {
  background: var(--white) !important;
  box-shadow: var(--shadow-xl) !important;
  border-bottom-color: transparent !important;
  position: relative;
  z-index: 10;
  /* Clip the shadow on the RIGHT edge only so the hovered card meets
     the preview pane seamlessly (no double-shadow at the joining
     edge). Negative insets on top/bottom/left let the shadow extend
     ~50px outward on those sides; right inset of 0 clips at the
     element's right edge. The card itself isn't visually clipped —
     negative insets mean "extend", not "trim". */
  clip-path: inset(-50px 0 -50px -50px);
}
/* When the dot-menu dropdown inside a row is open, lift the whole row
   above its siblings so the menu (which overflows the row downward)
   doesn't get covered by the next row in source order. The hovered/
   active row above sits at z-index:10; this beats it and any
   non-hovered sibling that would otherwise paint last. */
/* Selector targets the actual DOM: the `.open` class is toggled on the
   wrap (.explore-card-menu-wrap), and the dropdown itself is
   .mw-menu-dropdown — NOT .explore-card-menu-dropdown (that's the
   /explore-page variant). The previous selector never matched, which
   is why the row stayed clipped and the dropdown's lower items were
   cut off when more than two were present. */
.free-page .home-list-col .activity-item:has(.explore-card-menu-wrap.open) {
  position: relative;
  z-index: 60;
  /* When the dot-menu is open, drop the hover clip-path so the dropdown
     can paint outside the row's box. The hover rule above clips at
     bottom: -50px, which is shorter than the dropdown can grow once it
     has 2+ items, causing the menu to look cut off horizontally. */
  clip-path: none !important;
  /* And drop the row's height clamp so the dropdown can paint outside
     the 100px row box. The clamp is what was visually cropping the
     third menu item. */
  overflow: visible !important;
}
/* Lift the dropdown itself well above the right preview column and any
   sibling row stacking. Base rule sets z-index:100; on /free the preview
   column + hovered-card shadows live in the same paint layer, so we
   raise this one further so the menu always wins. */
.free-page .home-list-col .explore-card-menu-wrap.open .mw-menu-dropdown {
  z-index: 1000;
}

/* Share channel-picker popover (WhatsApp/Email/LinkedIn/X/Copy link),
   spawned by the row dot-menu Share for enterprise viewers. The shared
   styles live in explore-work.css which /free doesn't load — so the
   minimum rules needed to make the popover visible are duplicated
   here. Kept in sync with explore-work.css L881–L954. */
.free-page .work-share-modal.delete-confirm-modal {
  background: var(--white);
  border: 1px solid var(--gray-light);
  border-radius: 10px;
  padding: var(--space-5) var(--space-6);
  box-shadow: 0 8px 30px rgba(0,0,0,0.12);
  z-index: 9999;
  min-width: 220px;
  max-width: 280px;
}
.free-page .work-share-modal .delete-confirm-title {
  font-size: var(--text-base);
  font-weight: var(--font-weight-semibold);
  color: var(--navy);
  margin: 0 0 var(--space-1-5);
}
.free-page .work-share-modal .work-share-channels {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  margin: var(--space-2) 0 0;
}
.free-page .work-share-modal .work-share-ch {
  display: flex;
  align-items: center;
  gap: 10px;
  background: none;
  border: none;
  padding: var(--space-2) var(--space-1-5);
  font-size: 13px;
  font-weight: var(--font-weight-medium);
  color: var(--navy);
  border-radius: 6px;
  cursor: pointer;
  font-family: inherit;
  transition: background 0.12s;
  text-align: left;
  width: 100%;
}
.free-page .work-share-modal .work-share-ch:hover { background: var(--gray-white); }
.free-page .work-share-modal .work-share-ch svg { flex-shrink: 0; }
/* Suppress the canonical ::before / first-row ::after pseudo hairlines
   from work.css so we only ever render the one border-bottom above. */
.free-page .home-list-col .activity-item::before,
.free-page .home-list-col .activity-item:first-child::after {
  content: none !important;
  display: none !important;
}

/* Drop the heavy pink left border from anything inside the preview pane
   (the preview replicates row markup, so the country-intelligence rule
   would otherwise apply there too). */
.free-page .home-right-col [data-report-type="country-intelligence"],
.free-page .activity-preview-panel [data-report-type="country-intelligence"],
.free-page .activity-preview-panel .activity-item {
  border-left: none !important;
  padding-left: 0 !important;
}

.free-page .activity-preview-combined { border-top: none !important; }
.free-page .activity-preview-combined::before {
  content: none !important;
  border: none !important;
}

/* Ren ad inside the preview pane — pinned to 100px tall. */
.free-page #explorePreviewCards #ep-ad,
.free-page #explorePreviewCards .ep-ad,
.free-page #explorePreviewCards #ep-ad img,
.free-page #explorePreviewCards .ep-ad img { height: 100px !important; }

/* On /free the preview is shorter than on /work: restore stat
   cards / pricing / ad to normal flow (explore-work.css absolutely
   positions them at the bottom of the combined preview). */
.free-page #explorePreviewCards .ep-bottom-stats,
.free-page #explorePreviewCards .ep-credits,
.free-page #explorePreviewCards #ep-credits,
.free-page #explorePreviewCards .ep-ad,
.free-page #explorePreviewCards #ep-ad {
  position: static !important;
  inset: auto !important;
  height: auto !important;
}
/* No wrapper card — stat tiles each carry their own white fill below,
   so they sit as floating white tiles on the panel's off-white fill.

   Absolute-positioned to the bottom of .activity-preview-combined
   (which is 500px tall + position:relative on /free), so the stats
   are anchored exactly 30px from the bottom edge of the preview pane
   regardless of how many bullets render above them. left/right match
   the 30px horizontal padding of the combined block so the tiles
   align with the rest of the preview content. */
.free-page #explorePreviewCards .ep-bottom-stats:not(.hidden) {
  background: transparent;
  border: none;
  padding: 0;
  margin: 0;
  position: absolute;
  left: var(--space-7-5);
  right: var(--space-7-5);
  bottom: var(--space-7-5);
}
/* Kill the 30px white gutter from explore-work.css so the stat tiles
   align with the rest of the preview content instead of floating in
   a wide gutter. */
.free-page #explorePreviewCards .ep-bottom-stats .ep-key-stats-wrap {
  padding: 0 !important;
}
/* Centre the stats grid horizontally + vertically. justify-content
   centres the 2-col grid as a whole; align-items handles rows of
   uneven height; justify-content on .ep-key-stat centres label/value
   inside each tile. */
.free-page #explorePreviewCards .ep-bottom-stats .ep-key-stats {
  justify-content: center;
  align-items: center;
  margin-top: var(--space-7-5);
}
.free-page #explorePreviewCards .ep-bottom-stats .ep-key-stat {
  justify-content: center;
  background: color-mix(in srgb, var(--cyan) 10%, transparent);
  border: none;
}
.free-page:not(#explorePage) #explorePreviewCards .ep-bottom-stats .ep-key-stat {
  background: color-mix(in srgb, var(--cyan) 10%, transparent);
  border: none;
}
/* Christine (28 May v21): force every text element in the /free
   preview pane onto brand black (--brand-black = #0f1e41, the
   deep-navy "brand black" from Brand Guidelines V3.0). Without
   this block the cascade was landing on pure #000000 (browser
   fallback) for #ep-title / #ep-meta / .ep-snippet-text and on
   #444 (--ew-preview-desc-color, a hard-coded literal in
   tokens/explore-work.css L48) for .ep-key-stat-label — two
   different blacks, neither on brand. Pinning to --brand-black
   directly at higher specificity guarantees brand consistency
   regardless of what tokens upstream stylesheets define. */
.free-page:not(#explorePage) #explorePreviewCards #ep-title,
.free-page:not(#explorePage) #explorePreviewCards .activity-preview-title,
.free-page:not(#explorePage) #explorePreviewCards #ep-meta,
.free-page:not(#explorePage) #explorePreviewCards .ep-snippet-text,
.free-page:not(#explorePage) #explorePreviewCards .ep-snippet-item,
.free-page:not(#explorePage) #explorePreviewCards .ep-snippet-num,
.free-page:not(#explorePage) #explorePreviewCards .ep-key-stat-label,
.free-page:not(#explorePage) #explorePreviewCards .activity-preview-tag,
.free-page:not(#explorePage) #explorePreviewCards .ep-live-preview-heading,
.free-page:not(#explorePage) #explorePreviewCards #ep-description {
  color: var(--navy);
}
.free-page:not(#explorePage) #explorePreviewCards .ep-bottom-stats .ep-key-stat-value {
  color: var(--navy);
}
.free-page #explorePreviewCards .ep-credits,
.free-page #explorePreviewCards #ep-credits { margin-top: 0 !important; }

/* ----------------------------------------------------------------
   .cta-pill-row — three-pill action row (Download / Build / Customise)
   Brand-new isolated class names so nothing else in the cascade can
   touch them. Replaces the previous attempt to coerce #ep-credits +
   .ep-credits-grid into a 3-up flex row, which lost to higher-
   specificity rules in explore-work.css and home-search.css.
   The legacy #ep-credits container is hidden on /free below; this
   row is the single source of truth for the action pills.
   ---------------------------------------------------------------- */
.free-page .cta-pill-row {
  display: flex;
  flex-wrap: nowrap;
  gap: var(--space-2);
  align-items: stretch;
  /* Christine (28 May v9): added a fine grey hairline under the CTA
     row — same --ink-4 token as the /work card rows and the new
     preview-title divider above. padding-bottom sits the line
     var(--space-4) below the pills; the existing var(--space-6)
     margin-bottom then breathes between the line and the snippets
     list that follows, so the divider reads as section punctuation
     rather than a pill border. */
  margin: 0 0 var(--space-6);
  padding-bottom: 20px;
  border-bottom: 1px solid var(--ink-4, #d8d8d8);
}
/* "LIVE PREVIEW" eyebrow above the snippets list — Christine
   (28 May v9): mirrors the /work heading in static/css/work.css L2930
   (same uppercase tracked spec) so /free reads as a peer of /work.
   Scoped to .free-page:not(#explorePage) per Christine — /explore is
   intentionally excluded; the heading markup only ships in
   templates/pages/public/free.html so /explore wouldn't render it
   anyway, but the scoped selector keeps it that way if /explore ever
   gains the same DOM. JS toggles display in lockstep with #ep-snippets
   so the heading only renders when there are snippets below it. */
.free-page:not(#explorePage) .ep-live-preview-heading {
  margin: 0 0 var(--space-3);
  padding: 0;
  color: var(--navy);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  line-height: 1.45;
}
/* Christine (28 May v10): every pill in every preview now sits at a
   shared 56px height and shrinks to its content width — no more
   1/3-row fixed slots, no more flex:1 stretch. Single height token
   used across /free + /explore + visitor preview-card pills so they
   all read as a single CTA family regardless of which row they sit in.
   56px = padding (8 top + 8 bottom) + stacked label (17px @ 1.2 lh)
        + gap (4) + sub (14px @ 1.2 lh) + border (3) ≈ 54px → round to 56
   so single-line label-only pills (and the inline-layout /explore
   variant) still feel comfortable inside the same box. */
:root {
  /* Christine (28 May v14): 56 → 52, min-width floor 150px. Every
     preview-pane pill on /free + /explore shares both tokens so
     short-label pills ("Customise", "Download") stay legible at the
     same minimum tap area as longer-label pills ("Subscribe $20"). */
  --cta-pill-h: 52px;
  --cta-pill-min-w: 150px;
}
.free-page .cta-pill-row > * {
  /* Auto-width above the 150px floor — each pill is as wide as its
     content + horizontal padding, but never narrower than the shared
     --cta-pill-min-w. Hidden pills (.hidden) take no space; visible
     pills don't try to fill empty siblings' slots. */
  flex: 0 0 auto;
  min-width: var(--cta-pill-min-w);
}
.free-page .cta-pill {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-1);
  /* Pill border — matches the visitor .ep-price-cta pill: 1.5px
     hairline in --true-black with a fully-rounded radius. */
  border: 1.5px solid var(--navy);
  border-radius: var(--radius-full);
  padding: var(--space-2) var(--space-4);
  /* Shared CTA height — see :root --cta-pill-h above. */
  height: var(--cta-pill-h);
  background: var(--white);
  color: var(--navy);
  font-family: inherit;
  font-size: var(--text-sm);
  font-weight: 500;
  line-height: 1.2;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  transition: background 120ms ease, color 120ms ease;
}
.free-page .cta-pill:hover {
  /* Christine (28 May v9): pill hover flips to brand pink (same
     hover treatment as the home-hero "New Chat" pill in work.css
     L458+). White text stays for contrast against the pink fill;
     border picks up the pink so the 1.5px outline doesn't read
     as a black halo on the new fill. */
  background: var(--pink);
  color: var(--white);
  border-color: var(--pink);
}
.free-page .cta-pill:focus-visible {
  outline: 2px solid var(--navy);
  outline-offset: 2px;
}
.free-page .cta-pill__label {
  display: block;
  font-size: var(--text-sm);
  font-weight: 500;
  line-height: 1.2;
}
.free-page .cta-pill__sub {
  display: block;
  font-size: var(--text-xs);
  font-weight: 400;
  line-height: 1.2;
  opacity: 0.75;
}
/* Empty subtext span collapses so enterprise pills don't carry
   blank vertical space. */
.free-page .cta-pill__sub:empty {
  display: none;
}
/* Subscriber Download pill: when the subtext is empty BUT the
   row still has other pills carrying a subtext (i.e. the multi-pill
   subscriber row, not the solo enterprise row), pin the label to
   the top of the pill instead of vertical-centering it. Keeps the
   "Download" word optically aligned with the "Customise" label on
   its sibling pill. Christine 5 May 2026. */
.free-page .cta-pill-row:not(.cta-pill-row--solo) .cta-pill:has(.cta-pill__sub:empty) {
  justify-content: flex-start;
}
/* Solo variant — when only the Download pill is visible (enterprise),
   the row collapses to a single ~1/3-width solid black pill, matching
   the lone-CTA look used on the other pages. */
.free-page .cta-pill-row.cta-pill-row--solo {
  justify-content: flex-start;
}
.free-page .cta-pill-row.cta-pill-row--solo > .cta-pill:not(.hidden) {
  /* Christine (28 May v10): solo enterprise Download pill is now
     content-width like the rest of the CTA family — was pinned
     to a 1/3-row slot. Height still inherits the shared --cta-pill-h
     from .free-page .cta-pill above. */
  background: var(--navy);
  color: var(--white);
  border-color: var(--navy);
}
.free-page .cta-pill-row.cta-pill-row--solo > .cta-pill:not(.hidden):hover {
  /* Christine (28 May v9): solo pill hover now matches the multi-pill
     hover (pink fill + white text + pink border) instead of the old
     white-flip, so all pill variants share one hover identity. */
  background: var(--pink);
  color: var(--white);
  border-color: var(--pink);
}

/* Solid (primary) variant — used by the Subscribe pill in .cta-pill-row.
   Matches the visitor .ep-price-cta--solid look (black bg, white text).
   !important on bg + color so nothing in the cascade can flip it back. */
.free-page .cta-pill.cta-pill--solid {
  background: var(--navy) !important;
  color: var(--white) !important;
  border-color: var(--navy) !important;
}
.free-page .cta-pill.cta-pill--solid:hover {
  /* Christine (28 May v9): solid pill hover now matches the outline +
     solo variants (pink fill, white text, pink border) so every CTA
     in the preview row has the same single pink-hover identity. */
  background: var(--pink) !important;
  color: var(--white) !important;
  border-color: var(--pink) !important;
}
/* Hide the legacy #ep-customise chip on /free — its function is now
   covered by the Build your own pill in .cta-pill-row. Kept in DOM
   only so free.js's by-id lookups (~L608) don't error. */
.free-page #ep-customise {
  display: none !important;
}
/* Hide the legacy #ep-credits container on /free. Kept in DOM only
   so free.js's grid-injection logic doesn't error. */
.free-page #explorePreviewCards #ep-credits {
  display: none !important;
}

/* ---------- Visitor / freemium inline prompt ----------
   The download-prompt modal, inlined under the live preview so
   visitors + freemium see the price + framing without a click.
   Title + body + three CTAs (Buy / Build / Subscribe). Subscribe
   is the solid primary; Buy and Build are ghost pills. */
/* The buy/build/subscribe slot lives at the TOP of the preview
   content (above the bullets) so it's always reachable on laptop
   viewports where the sticky preview pane would clip the bottom.
   One row of three pills, no card frame, no shadow. */
.free-page #explorePreviewCards #ep-prompt {
  margin: 0 0 var(--space-4, 16px) 0;
}
.free-page #explorePreviewCards #ep-prompt.hidden {
  display: none;
}
/* When the prompt is visible, collapse the gap above it: the title
   has a 20px bottom margin + a 2-line min-height reserved for layout
   stability, and an empty <p id="ep-description"> sits between them.
   Together that's ~70px of dead space. Override only when the prompt
   is in play so subscribers (no prompt) keep the original layout. */
/* Keep the 2-line min-height (so 1-line and 2-line titles reserve
   the same height across reports — no layout shift between rows).
   Just kill the extra 20px bottom margin so the buttons sit close. */
.free-page #explorePreviewCards #previewCollapsible:has(#ep-prompt:not(.hidden)) .activity-preview-title {
  margin-bottom: var(--space-2) !important;
}
/* Hard-cap every preview title at 2 lines (ellipsis on overflow)
   so very long titles don't push the buttons down — matches the
   2-line min-height already reserved above. */
.free-page #explorePreviewCards .activity-preview-title {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  overflow: hidden;
  text-overflow: ellipsis;
  word-break: break-word;
}
.free-page #explorePreviewCards #previewCollapsible:has(#ep-prompt:not(.hidden)) #ep-description:empty {
  display: none !important;
}
.free-page #explorePreviewCards #previewCollapsible:has(#ep-prompt:not(.hidden)) #ep-description {
  margin: 0 !important;
}
.free-page #explorePreviewCards .ep-price-ctas {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}
.free-page #explorePreviewCards .ep-price-cta {
  appearance: none;
  border: 1.5px solid var(--navy);
  border-radius: var(--radius-full);
  /* Christine (28 May v10): visitor preview-card pills share the same
     56px CTA height token as the subscriber-row pills so the whole
     CTA family reads as one. Horizontal padding kept at var(--space-4)
     to match .cta-pill above; vertical padding is implicit since
     height is fixed. */
  padding: 0 var(--space-4);
  height: var(--cta-pill-h);
  font-size: var(--caption);
  font-weight: 600;
  line-height: 1;
  cursor: pointer;
  transition: background-color 120ms ease, color 120ms ease,
              transform 80ms ease;
  font-family: inherit;
  letter-spacing: 0;
  white-space: nowrap;
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  /* Content-width — was flex:1 1 0 which stretched each pill to fill
     an equal share of the row. v14: 150px min-width floor matches
     the shared --cta-pill-min-w so visitor preview-card pills sit
     at the same minimum as the subscriber row above. */
  flex: 0 0 auto;
  min-width: var(--cta-pill-min-w);
}
.free-page #explorePreviewCards .ep-price-cta--ghost {
  background: var(--white);
  color: var(--navy);
}
.free-page #explorePreviewCards .ep-price-cta--ghost:hover {
  /* Christine (28 May v9): /free visitor preview-card pills (ghost +
     solid) share the same pink-hover identity as the subscriber-row
     .cta-pill above. Border picks up the pink so the 1.5px outline
     on the ghost variant doesn't leave a black ring on the new fill. */
  background: var(--pink);
  color: var(--white);
  border-color: var(--pink);
}
.free-page #explorePreviewCards .ep-price-cta--solid {
  background: var(--navy);
  color: var(--white);
}
.free-page #explorePreviewCards .ep-price-cta--solid:hover {
  background: var(--pink);
  color: var(--white);
  border-color: var(--pink);
}
.free-page #explorePreviewCards .ep-price-cta:active {
  transform: translateY(1px);
}
.free-page #explorePreviewCards .ep-price-cta:focus-visible {
  outline: 2px solid var(--navy);
  outline-offset: 2px;
}
.free-page #explorePreviewCards .ep-ad,
.free-page #explorePreviewCards #ep-ad { margin-top: var(--space-3) !important; }

/* (Promo breaker styles — .free-list-break, .flb-card, .flb-icon,
   .flb-text, .flb-headline, .flb-sub, .flb-cta, and all six
   [data-break-kind="..."] colour overrides — removed 26 May 2026
   when the breaker feature itself was retired. The companion
   responsive overrides in the @media (max-width: 720px) block below
   were dropped in the same change.) */

/* Preview-pane card stack (replaces inline flex/gap styles). */
.free-page #explorePreviewCards {
  flex-direction: column;
  gap: var(--space-4);
}

/* ---------- Infinite-scroll sentinel + status ----------------- */
.free-sentinel { height: 1px; }
.free-list-status {
  padding: var(--space-4);
  text-align: center;
  color: var(--ink-2);
  font-size: 0.875rem;
}
.free-list-status.is-loading::after { content: 'Loading more…'; }
.free-list-status.is-end::after     { content: ''; }

/* Visually hidden (a11y). */
.sr-only {
  position: absolute !important;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0,0,0,0);
  white-space: nowrap;
  border: 0;
}

/* Misc page-meta line in the title row. */
.mw-page-meta {
  color: var(--ink-2);
  font-size: 0.9rem;
  margin-left: 0.75rem;
}

/* ---------- Responsive --------------------------------------- */
/* (Mobile breaker overrides — full-bleed wrapper + hairline edge
   extension — removed 26 May 2026 with the breakers themselves.) */

/* Mobile-only filter icon inside the search pill (right side).
   Hidden on desktop; opens a sheet with category + region + language
   on phones. */
.search-filter-btn { display: none; }

/* Mobile-only fragments inside the page-title-desc are hidden by
   default; the @media (max-width: 768px) block immediately below
   flips them on for phones (and hides the matching .hide-on-mobile
   fragments). MUST sit before the @media block so the cascade lets
   the mobile rule win at small widths — when this rule was placed
   later in the file the default-deny clobbered the mobile reveal. */
.free-page .page-title-desc .show-on-mobile { display: none; }

/* Tighten the page tagline on phones — the desktop size (~16px)
   feels heavy under the smaller mobile section title. */
@media (max-width: 768px) {
  .free-page .page-title { font-size: 1.6875rem !important; } /* 27px */
  .free-page .page-title-desc { font-size: var(--text-sm) !important; }
  .free-page .page-title-desc .hide-on-mobile { display: none; }
  .free-page .page-title-desc .show-on-mobile { display: inline; }
  /* Hide the desktop tabs row on phones — category, region and
     language all live in the filter sheet instead. */
  .free-page .free-tabs-row { display: none; }
  .free-page .home-list-col .all-reports-heading,
  .free-page#explorePage .home-list-col .all-reports-heading {
    display: flex !important;
    align-items: center;
    pointer-events: auto;
    cursor: pointer;
  }
  .free-page .home-list-col .explore-section-heading,
  .mw-page .home-list-col .explore-section-heading {
    margin-left: 0;
    height: 40px;
    font-size: 14px;
  }
  .free-page .home-list-col .all-reports-heading .all-reports-btn::after,
  .free-page#explorePage .home-list-col .all-reports-heading .all-reports-btn::after {
    content: none;
  }
  /* Show the filter icon, sitting flush to the right inside the
     search pill (next to the clear button). */
  .search-filter-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    order: 3;
    width: 32px;
    height: 32px;
    margin-left: var(--space-1);
    padding: 0;
    background: transparent;
    border: none;
    color: #ff2cd7;
    cursor: pointer;
    appearance: none;
  }
  .free-search-clear { order: 2; }
  .search-filter-btn svg { width: 20px; height: 20px; color: #ff2cd7; }
  .search-filter-btn:hover { color: #ff2cd7; }

  /* Push the filter icon hard to the right edge of the pill on /explore.
     /free puts the input directly inside .free-search-pill so it expands
     naturally, but /explore wraps the input in .free-search-input-wrap
     which collapses to its content width — leaving the filter button
     bunched up next to the input. Forcing the wrap to flex:1 makes the
     wrap eat the remaining pill width and parks the filter icon flush
     right where it belongs. */
  .free-page#explorePage .free-search-input-wrap {
    flex: 1 1 auto !important;
    display: flex !important;
    align-items: center;
    min-width: 0;
    width: 100%;
  }
  .free-page#explorePage .free-search-input-wrap .free-search-input {
    flex: 1 1 auto;
    width: 100%;
    min-width: 0;
  }
  /* Belt-and-braces: also pin the filter button to the right by
     letting the wrap before it claim every spare pixel via auto
     left margin. Works even if a future flex tweak resets things. */
  .free-page#explorePage .free-search-pill .search-filter-btn {
    margin-left: auto;
    flex: 0 0 auto;
  }

  /* Hide favourite stars on mobile across /free product rows. The sort
     menu still respects favourites set on desktop — only the per-row
     star icon is hidden, not the underlying data or sort behaviour. */
  .free-page .mw-frow-star { display: none !important; }

  /* ----- Mobile filter sheet (opened by .search-filter-btn) ----- */
  .filter-sheet {
    position: fixed;
    inset: 0;
    z-index: 1100;
    display: flex;
    align-items: flex-end;
    justify-content: center;
  }
  .filter-sheet[hidden] { display: none; }
  .filter-sheet__backdrop {
    position: absolute;
    inset: 0;
    background: rgba(0, 0, 0, 0.45);
    animation: filter-sheet-fade 160ms ease;
  }
  .filter-sheet__panel {
    position: relative;
    width: 100%;
    max-height: 60vh;
    background: var(--white);
    border-radius: 16px 16px 0 0;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    animation: filter-sheet-slide 220ms cubic-bezier(0.2, 0.7, 0.2, 1);
    padding-bottom: env(safe-area-inset-bottom, 0);
  }
  .filter-sheet__header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 10px var(--space-4);
    border-bottom: 1px solid var(--gray-light);
  }
  .filter-sheet__title {
    margin: 0;
    font-size: var(--text-base);
    font-weight: var(--font-weight-semibold, 600);
    color: var(--navy);
  }
  .filter-sheet__close {
    width: 32px;
    height: 32px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: transparent;
    border: none;
    color: var(--ink-2);
    cursor: pointer;
  }
  .filter-sheet__body {
    flex: 1 1 auto;
    overflow-y: auto;
    padding: var(--space-1) 0 var(--space-2);
    -webkit-overflow-scrolling: touch;
  }
  .filter-sheet__section {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-3) var(--space-4);
  }
  .filter-sheet__section-title { display: none; }
  .filter-sheet__item {
    display: inline-flex;
    align-items: center;
    width: auto;
    padding: 7px 14px;
    background: rgba(0, 195, 255, 0.05);
    border: 1px solid var(--cyan);
    border-radius: var(--radius-full);
    text-align: left;
    font-size: var(--text-sm);
    color: var(--navy);
    cursor: pointer;
    appearance: none;
    white-space: nowrap;
  }
  .filter-sheet__check { display: none; }
  .filter-sheet__item.is-active {
    font-weight: var(--font-weight-semibold, 600);
    background: var(--cyan);
    color: var(--white);
  }

  @keyframes filter-sheet-fade {
    from { opacity: 0; }
    to   { opacity: 1; }
  }
  @keyframes filter-sheet-slide {
    from { transform: translateY(100%); }
    to   { transform: translateY(0); }
  }
  /* Mobile search bar respects the `.mw-page` 24px gutter (no
     negative margins) so the pill aligns with the rest of the
     page content rather than overlapping the side padding. The
     form's desktop --page-gutter-x is swapped for the mobile
     companion token --page-gutter-x-mobile (currently 0) so the
     .mw-page gutter is the only horizontal inset on phones —
     desktop and mobile insets can now be tuned independently
     from tokens/spacing.css. */
  .free-page .page-search-bar {
    margin-left: 0;
    margin-right: 0;
  }
  .free-page .free-hero-search {
    padding-left: var(--page-gutter-x-mobile);
    padding-right: var(--page-gutter-x-mobile);
  }
  /* Pill fills the available width within the gutter. !important
     is needed to beat the desktop rule (lines 144-148) which
     itself uses !important. Height locked to 44px on phones (down
     from the 68px desktop pill) per Christine's request. */
  .free-page .free-search-pill {
    width: 100% !important;
    max-width: 100% !important;
    border-radius: 16px !important;
    border-color: var(--gray-light) !important;
    height: 44px !important;
    min-height: 44px;
    padding: var(--space-1) 10px;
  }
  /* Breathing room between the search bar and the report list on
     mobile, matching the desktop rhythm. */
  .free-page .free-hero-search,
  .free-page .page-search-bar { margin-bottom: var(--space-5); }
}

@media (max-width: 640px) {
  .free-page .free-search-pill {
    border-radius: 16px;
    padding: var(--space-2) 10px;
  }
  .free-page .free-search-sep { display: none; }
  .free-page .free-tabs-filters .filter-select { flex: 1 1 0; }
}

/* On phones the row should sit flush to the page gutter — drop the
   16px L/R margin baked into the canonical row rule above and the
   18/24px L/R padding inherited from .home-popular-list .activity-item. */
@media (max-width: 768px) {
  .free-page .home-list-col .activity-item,
  .free-page .home-list-col .activity-item.mw-frow,
  .free-page .home-list-col .activity-item.explore-item {
    margin-left: 0 !important;
    margin-right: 0 !important;
    padding: var(--space-3) 0 !important;
    height: 72px !important;
    min-height: 72px !important;
    max-height: 72px !important;
  }
  .free-page .free-tab-fav { display: none; }
  .mw-menu-dropdown .mw-menu-item[data-row-action="star"] { display: none; }
  .free-page .home-list-col .activity-item { gap: 4px; }
  .free-page .home-list-col .activity-item-actions {
    padding-right: 0;
    min-width: 0;
    width: 30px;
    flex-direction: row;
    align-items: center;
    align-self: flex-start;
  }
  .free-page .home-list-col .explore-card-menu-trigger { padding-right: 0; margin-top: 5px; }
}

/* Hard single-line ellipsis on the title and subtitle so long
   report names can't bleed into the star/menu icons on the right.
   Applies at every viewport — the breakpoint-only version was
   getting overridden by the wider canonical row rule on tablet. */
.free-page .home-list-col .activity-item-title,
.free-page .home-list-col .activity-item-product-label {
  display: block !important;
  white-space: nowrap !important;
  overflow: hidden !important;
  text-overflow: ellipsis !important;
  max-width: 100% !important;
  min-width: 0;
}
.free-page .home-list-col .activity-item-content {
  min-width: 0;
  overflow: hidden;
}
/* iPad (768px+): work.css sets flex-direction:column-reverse on
   .activity-item-actions at ≤1440px (designed for desktop-only star
   rows). On /free the star + three-dot menu must sit side-by-side on
   all viewports. Reset to row and narrow the content area by 20px so
   both icons always have room. */
@media (min-width: 768px) and (max-width: 1440px) {
  .free-page .home-list-col .activity-item-actions {
    flex-direction: row !important;
    align-items: center;
    gap: var(--space-2);
  }
  .free-page .home-list-col .activity-item-content {
    max-width: calc(100% - 20px);
  }
}

/* ──────────────────────────────────────────────────────────────
   Page title block (Explore + Free, 26 Apr 2026)
   Sits directly below the shrunken hero panel; the title and tagline
   used to live INSIDE .landing-hero-panel but have been pulled out so
   the panel collapses to navbar-frame height. Kept inside .mw-page so
   the text aligns with the search/tabs/cards below.
   ────────────────────────────────────────────────────────────── */
.free-page .page-title-block {
  /* Lives inside `.listing-hero-panel` — the panel provides the
     outer padding, so this block just centers the text and caps
     the width so the tagline doesn't span the full panel on wide
     monitors. */
  margin: 0 auto;
  padding: 0;
  text-align: center;
  max-width: 1200px;
}

.free-page .page-title {
  text-align: center;
  margin: 0;
  color: var(--navy);
  font-size: var(--section-heading);
}

.free-page .page-title-desc {
  text-align: center;
  font-size: var(--text-base);
  color: var(--navy);
  margin: 0 auto;
  max-width: 720px;
  line-height: 1.55;
}

/* (The default `.show-on-mobile { display: none }` rule lives ABOVE
   the @media (max-width: 768px) block earlier in this file. A stale
   duplicate used to live here and won by source order, blanking the
   mobile subheading — removed.) */

.free-page .page-title-desc strong {
  color: var(--navy);
  font-weight: var(--font-weight-semibold, 600);
}

/* ─────────────────────────────────────────────────────────────────
   Holding ad — fills the right-column live-preview pane on
   /explore and /free until the user hovers their first row. The
   hover handlers in explore.html and static/js/free.js add the
   `.hidden` class to `#previewHoldingAd` the first time a preview
   is rendered; from that point on the live preview owns the slot.

   The old text-only empty state (`#mwPreviewEmpty`) is hidden on
   these pages because the holding ad replaces its role entirely
   — keeping both around would create two competing empty states.
   ───────────────────────────────────────────────────────────── */

.free-page #mwPreviewEmpty { display: none; }

.free-page .preview-holding-ad {
  position: relative;
  height: 100%;
  min-height: 460px;
  border-radius: var(--radius-lg, 18px);
  overflow: hidden;
  background: var(--gradient);
  color: var(--white);
  padding: var(--space-7) var(--space-6);
  display: flex;
  align-items: center;
  justify-content: center;
}

.free-page .preview-holding-ad.hidden { display: none; }

/* ─────────────────────────────────────────────────────────────────
   /solutions persona ad. Lives in the same slot as the /explore
   holding-ad rotator (same #previewHoldingAd id so the hover
   handler in explore.html toggles `.hidden` on it identically).
   Layout: full-bleed background image, eyebrow pill top-left,
   headline + body stacked above. Background image sits behind a
   left-to-right white-fading gradient so copy stays legible no
   matter how the photo is composed.
   ───────────────────────────────────────────────────────────── */
.free-page .persona-ad {
  position: relative;
  width: 100%;
  min-height: 600px;
  border-radius: var(--radius-lg, 18px);
  overflow: hidden;
  background: var(--white);
  padding: var(--space-8) var(--space-8);
  display: flex;
  align-items: flex-start;
  justify-content: flex-start;
}
.free-page .persona-ad.hidden { display: none; }
.free-page .persona-ad-bg {
  position: absolute;
  inset: 0;
  background-repeat: no-repeat;
  background-position: right bottom;
  background-size: contain;
  z-index: 0;
}
.free-page .persona-ad-inner {
  position: relative;
  z-index: 1;
  max-width: calc(58% + 50px);
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}
.free-page .persona-ad-eyebrow {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  align-self: flex-start;
  padding: 6px 16px 5px;
  border-radius: 999px;
  font-size: 12px;
  line-height: 1;
  font-weight: 700;
  letter-spacing: 0.08em;
  color: var(--white);
  text-transform: uppercase;
}
.free-page .persona-ad-headline {
  margin: 38px 0 0;
  font-size: 30px;
  line-height: 1.18;
  font-weight: 800;
  color: var(--black, #111);
  letter-spacing: -0.01em;
}
.free-page .persona-ad-body {
  margin: 25px 0 0;
  /* Per Christine 2026-05-25: body copy sits 50px narrower than the
     inner column so it breaks earlier and lands above the photo
     instead of overlapping the subject's face. */
  max-width: calc(100% - 50px);
  padding-right: 40px;
  font-size: 14px;
  line-height: 1.55;
  color: var(--black, #222);
}
.free-page .persona-ad--mirror .persona-ad-body {
  /* Mirror variant text is right-aligned, so shrink from the LEFT
     edge by pushing the body in 30px instead of trimming from the
     right (which would create a gap against the right edge). */
  margin-left: 50px;
  max-width: calc(100% - 50px);
}
.free-page .persona-ad-body--tail { margin-top: var(--space-3); font-weight: 600; }
/* Per-line white background behind body text so it stays legible
   over the founder photo (notably the dark shirt) when the preview
   scales narrow enough that the photo creeps under the copy.
   box-decoration-break: clone makes each wrapped line carry its
   own background + padding instead of one box around the whole
   paragraph. -webkit- prefix required for Safari/iOS. */
.free-page .persona-ad-body-text {
  /* 30% transparent (70% opaque white) so the photo shows through
     softly behind the copy. Christine 2026-05-25. */
  background: rgba(255, 255, 255, 0.7);
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
  padding: 2px 8px;
  margin-left: -8px;
  border-radius: 6px;
}

/* Mirror variant — used by personas whose hero photo sits on the LEFT
   and copy on the RIGHT (e.g. /solutions?persona=leaders). Flips the
   background-image anchor, right-aligns the inner column, and right-
   aligns the eyebrow + text. Founders ad keeps the default layout. */
.free-page .persona-ad--mirror .persona-ad-bg {
  background-position: left bottom;
}
.free-page .persona-ad--mirror {
  justify-content: flex-end;
}
.free-page .persona-ad--mirror .persona-ad-inner {
  align-items: flex-end;
  text-align: right;
}
.free-page .persona-ad--mirror .persona-ad-eyebrow {
  align-self: flex-end;
}

@media (max-width: 900px) {
  .free-page .persona-ad { min-height: 480px; }
  .free-page .persona-ad-inner { max-width: 100%; }
  .free-page .persona-ad-bg {
    background-position: right bottom;
    background-size: 60% auto;
    opacity: 0.4;
  }
  .free-page .persona-ad--mirror .persona-ad-bg {
    background-position: left bottom;
  }
  .free-page .persona-ad-headline { font-size: 22px; }
}

/* ─────────────────────────────────────────────────────────────────
   Holding-ad rotator (/free only). The wrapper still carries
   `.preview-holding-ad` so the `.hidden` toggle in showPanel()
   keeps working, but in rotator mode it strips the gradient bg /
   centering — each card paints its own full-bleed colored surface.
   /explore's holding ad doesn't get `.preview-holding-ad-rotator`
   so its gradient styling is unaffected.
   ───────────────────────────────────────────────────────────── */
.free-page .preview-holding-ad.preview-holding-ad-rotator {
  background: none;
  color: inherit;
  padding: 0;
  display: block;
}
.free-page .preview-holding-ad-card { display: none; }
.free-page .preview-holding-ad-card.is-active {
  display: flex;
  flex-direction: column;
  /* Fixed card height — eyebrow at top, CTA + copy anchored at bottom. */
  min-height: 500px;
  /* Generous interior padding so eyebrow / pill aren't jammed against
     the top-left edge and the CTA has room to breathe at the bottom. */
  padding: var(--space-10) var(--space-10);
  border-radius: var(--radius-lg, 18px);
  position: relative;
}
.free-page#explorePage .preview-holding-ad-card.is-active {
  min-height: 0;
  height: auto;
}
.free-page .preview-holding-ad-card--yellow { background: var(--yellow); }
.free-page .preview-holding-ad-card--purple { background: var(--purple); }
/* Startup-launch-kit ad: full-bleed vivid photo, copy sits on a
   solid white panel anchored at the bottom so the image doesn't
   need to be washed out. */
.free-page .preview-holding-ad-card.is-active[data-ad-key="startup-launch-kit"] {
  background-color: var(--white);
  background-image: url('/static/images/ads/startup.jpg');
  background-repeat: no-repeat;
  background-size: 100% auto;
  background-position: bottom right;
  overflow: hidden;
  min-height: 560px;
  padding-top: 20px;
}
.free-page .preview-holding-ad-card[data-ad-key="startup-launch-kit"] .phac-eyebrow {
  align-self: flex-start;
  padding: 6px 12px 6px 0;
  background: var(--white);
  color: var(--navy);
  opacity: 1;
  border-radius: 999px;
  margin-bottom: 0;
}
.free-page .preview-holding-ad-card[data-ad-key="startup-launch-kit"] .phac-bottom {
  background: transparent;
  padding: 0;
  align-self: stretch;
  max-width: 420px;
}
.free-page .preview-holding-ad-card[data-ad-key="startup-launch-kit"] .phac-headline {
  margin-bottom: var(--space-2);
  color: var(--navy);
}
.free-page .preview-holding-ad-card[data-ad-key="startup-launch-kit"] .phac-body {
  font-size: var(--text-sm);
  font-weight: 400;
  line-height: 1.4;
  margin-bottom: var(--space-4);
  padding-right: 20px;
  color: var(--navy);
}
.free-page .preview-holding-ad-card[data-ad-key="startup-launch-kit"] .phac-sub {
  color: var(--navy);
}
.free-page .preview-holding-ad-card[data-ad-key="startup-launch-kit"] .phac-cta {
  background: var(--navy);
  color: var(--white);
}

/* Competitive-landscape ad: same image-led layout as startup-launch-kit,
   using competitive.jpg anchored bottom-right at full width. */
.free-page .preview-holding-ad-card.is-active[data-ad-key="competitive-landscape"] {
  background-color: var(--white);
  background-image: url('/static/images/ads/competitive.jpg');
  background-repeat: no-repeat;
  background-size: 100% auto;
  background-position: bottom right;
  overflow: hidden;
  min-height: 560px;
  padding-top: 20px;
}
.free-page .preview-holding-ad-card[data-ad-key="competitive-landscape"] .phac-eyebrow {
  align-self: flex-start;
  padding: 6px 12px 6px 0;
  background: var(--white);
  color: var(--navy);
  opacity: 1;
  border-radius: 999px;
  margin-bottom: 0;
}
.free-page .preview-holding-ad-card[data-ad-key="competitive-landscape"] .phac-bottom {
  background: transparent;
  padding: 0;
  align-self: stretch;
  max-width: 420px;
}
.free-page .preview-holding-ad-card[data-ad-key="competitive-landscape"] .phac-headline {
  margin-bottom: var(--space-2);
  color: var(--navy);
}
.free-page .preview-holding-ad-card[data-ad-key="competitive-landscape"] .phac-body {
  font-size: var(--text-sm);
  font-weight: 400;
  line-height: 1.4;
  margin-bottom: var(--space-4);
  padding-right: 20px;
  color: var(--navy);
}
.free-page .preview-holding-ad-card[data-ad-key="competitive-landscape"] .phac-sub {
  color: var(--navy);
}
.free-page .preview-holding-ad-card[data-ad-key="competitive-landscape"] .phac-cta {
  background: var(--navy);
  color: var(--white);
}

/* Free-reports ad: same image-led layout, using report.jpg
   anchored bottom-right at full width. */
.free-page .preview-holding-ad-card.is-active[data-ad-key="free-reports"] {
  background-color: var(--white);
  background-image: url('/static/images/ads/report.jpg');
  background-repeat: no-repeat;
  background-size: 100% auto;
  background-position: bottom right;
  overflow: hidden;
  min-height: 560px;
  padding-top: 20px;
}
.free-page .preview-holding-ad-card[data-ad-key="free-reports"] .phac-eyebrow {
  align-self: flex-start;
  padding: 6px 12px 6px 0;
  background: var(--white);
  color: var(--navy);
  opacity: 1;
  border-radius: 999px;
  margin-bottom: 0;
}
.free-page .preview-holding-ad-card[data-ad-key="free-reports"] .phac-bottom {
  background: transparent;
  padding: 0;
  align-self: stretch;
  max-width: 420px;
}
.free-page .preview-holding-ad-card[data-ad-key="free-reports"] .phac-headline {
  margin-bottom: var(--space-2);
  color: var(--navy);
}
.free-page .preview-holding-ad-card[data-ad-key="free-reports"] .phac-body {
  font-size: var(--text-sm);
  font-weight: 400;
  line-height: 1.4;
  margin-bottom: var(--space-4);
  padding-right: 20px;
  color: var(--navy);
}
.free-page .preview-holding-ad-card[data-ad-key="free-reports"] .phac-sub {
  color: var(--navy);
}
.free-page .preview-holding-ad-card[data-ad-key="free-reports"] .phac-cta {
  background: var(--navy);
  color: var(--white);
}

/* Customer-discovery-simulation ad: same image-led layout, using
   discovery.jpg anchored bottom-right at full width. */
.free-page .preview-holding-ad-card.is-active[data-ad-key="customer-discovery-simulation"] {
  background-color: var(--white);
  background-image: url('/static/images/ads/discovery.jpg');
  background-repeat: no-repeat;
  background-size: 100% auto;
  background-position: bottom right;
  overflow: hidden;
  min-height: 560px;
  padding-top: 20px;
}
.free-page .preview-holding-ad-card[data-ad-key="customer-discovery-simulation"] .phac-eyebrow {
  align-self: flex-start;
  padding: 6px 12px 6px 0;
  background: var(--white);
  color: var(--navy);
  opacity: 1;
  border-radius: 999px;
  margin-bottom: 0;
}
.free-page .preview-holding-ad-card[data-ad-key="customer-discovery-simulation"] .phac-bottom {
  background: transparent;
  padding: 0;
  align-self: stretch;
  max-width: 420px;
}
.free-page .preview-holding-ad-card[data-ad-key="customer-discovery-simulation"] .phac-headline {
  margin-bottom: var(--space-2);
  color: var(--navy);
}
.free-page .preview-holding-ad-card[data-ad-key="customer-discovery-simulation"] .phac-body {
  font-size: var(--text-sm);
  font-weight: 400;
  line-height: 1.4;
  margin-bottom: var(--space-4);
  padding-right: 20px;
  color: var(--navy);
}
.free-page .preview-holding-ad-card[data-ad-key="customer-discovery-simulation"] .phac-sub {
  color: var(--navy);
}
.free-page .preview-holding-ad-card[data-ad-key="customer-discovery-simulation"] .phac-cta {
  background: var(--navy);
  color: var(--white);
}

/* Public-safety-simulation ad: same image-led layout as the
   startup-launch-kit card, using the train.jpg asset. */
.free-page .preview-holding-ad-card.is-active[data-ad-key="child-safety-simulation"] {
  background-color: var(--white);
  background-image: url('/static/images/ads/train.jpg');
  background-repeat: no-repeat;
  background-size: 75% auto;
  background-position: bottom center;
  overflow: hidden;
  min-height: 460px;
  padding-top: 20px;
  padding-bottom: 150px;
}
.free-page .preview-holding-ad-card[data-ad-key="child-safety-simulation"] .phac-eyebrow {
  align-self: flex-start;
  padding: 6px 12px 6px 0;
  background: var(--white);
  color: var(--navy);
  opacity: 1;
  border-radius: 999px;
  margin-bottom: 0;
}
.free-page .preview-holding-ad-card[data-ad-key="child-safety-simulation"] .phac-bottom {
  background: transparent;
  padding: 0;
  align-self: stretch;
  max-width: none;
}
.free-page .preview-holding-ad-card[data-ad-key="child-safety-simulation"] .phac-headline {
  max-width: 90%;
}
.free-page .preview-holding-ad-card[data-ad-key="child-safety-simulation"] .phac-body {
  max-width: none;
}
.free-page .preview-holding-ad-card[data-ad-key="child-safety-simulation"] .phac-headline {
  margin-bottom: var(--space-2);
  color: var(--navy);
}
.free-page .preview-holding-ad-card[data-ad-key="child-safety-simulation"] .phac-body {
  font-size: var(--text-sm);
  font-weight: 400;
  line-height: 1.4;
  margin-bottom: var(--space-4);
  padding-right: 20px;
  color: var(--navy);
}
.free-page .preview-holding-ad-card[data-ad-key="child-safety-simulation"] .phac-sub {
  color: var(--navy);
}
.free-page .preview-holding-ad-card[data-ad-key="child-safety-simulation"] .phac-cta {
  background: var(--navy);
  color: var(--white);
}
.free-page .preview-holding-ad-card--cyan  { background: var(--cyan); }
/* Three additional gradient-sampled colors for ad-card variety. They
   don't replace the brand tokens (--cyan/--purple/--yellow); they sit
   between them on the same gradient line so the rotator feels like
   one family. Hex values are inlined here because they're only used
   by these three cards — promoting them to brand tokens would
   suggest broader use. */
.free-page .preview-holding-ad-card--fuchsia { background: var(--navy); }
.free-page .preview-holding-ad-card--peach   { background: #FFAB94; }
.free-page .preview-holding-ad-card--honey   { background: #FFC890; }
.free-page .preview-holding-ad-card--methodology { background: var(--white); }

/* Methodology card — content flows top-to-bottom (overrides the bottom-
   anchored layout used by the amber/coral/pink ad cards). All values
   reference brand tokens. */
.free-page .preview-holding-ad-card--methodology {
  justify-content: flex-start;
  gap: var(--space-3);
}
.free-page .preview-holding-ad-card--methodology .phac-eyebrow {
  color: var(--gray-500);
}
.free-page .preview-holding-ad-card--methodology .phac-method-headline {
  color: var(--navy);
  margin: 0 0 var(--space-6);
}
.free-page .phac-method-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
}
.free-page .phac-method-item {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
}
.free-page .phac-method-tick {
  flex: 0 0 auto;
  width: var(--space-5);
  height: var(--space-5);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--gray-500);
  margin-top: var(--space-1);
}
.free-page .phac-method-body { flex: 1 1 auto; min-width: 0; }
.free-page .phac-method-title {
  font-size: var(--text-sm);
  font-weight: var(--font-weight-bold);
  color: var(--navy);
  margin-bottom: var(--space-1);
  line-height: 1.35;
}
.free-page .phac-method-desc {
  font-size: var(--text-sm);
  line-height: 1.5;
  color: var(--gray-500);
  margin: 0;
}

.free-page .phac-eyebrow {
  font-size: var(--text-2xs);
  letter-spacing: var(--letter-spacing-eyebrow);
  font-weight: var(--font-bold);
  text-transform: uppercase;
  color: var(--navy);
  opacity: 0.72;
  margin-bottom: var(--space-4);
}
.free-page .phac-pill {
  display: inline-flex;
  align-items: center;
  align-self: flex-start;
  padding: var(--space-1-5) 14px;
  border: 1.5px solid var(--navy);
  border-radius: var(--radius-full);
  font-size: var(--text-2xs);
  letter-spacing: var(--letter-spacing-eyebrow);
  font-weight: var(--font-bold);
  text-transform: uppercase;
  color: var(--navy);
  margin-bottom: var(--space-4);
}
/* Bottom block — wrapper around headline+body+sub+cta. `margin-top:auto`
   pushes the entire block to the bottom of the card so the eyebrow
   anchors the top and the messaging anchors the bottom (matches the
   reference layout). The arrow lives below this block, centered. */
.free-page .phac-bottom {
  margin-top: auto;
  display: flex;
  flex-direction: column;
}
.free-page .phac-headline {
  font-size: clamp(28px, 2.6vw, 36px);
  font-weight: var(--font-bold);
  line-height: 1.15;
  letter-spacing: -0.01em;
  color: var(--navy);
  margin: 0 0 var(--space-4);
  max-width: 520px;
}
.free-page .phac-body {
  font-size: var(--text-base);
  font-weight: var(--font-semibold);
  line-height: 1.4;
  color: var(--navy);
  margin: 0 0 var(--space-2);
  max-width: 520px;
}
.free-page .phac-sub {
  font-size: var(--text-sm);
  line-height: 1.45;
  color: var(--navy);
  opacity: 0.65;
  margin: 0 0 var(--space-5);
  max-width: 520px;
}
.free-page .phac-cta {
  align-self: flex-start;
  appearance: none;
  border: none;
  background: var(--navy);
  color: var(--white);
  text-decoration: none;
  font-size: var(--text-sm);
  font-weight: var(--font-semibold);
  padding: var(--space-3) var(--space-5);
  margin-top: 5px;
  border-radius: var(--radius-full);
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  cursor: pointer;
  transition: transform 0.15s ease;
}
.free-page .phac-cta:hover { transform: translateY(-1px); }

/* Coral / Pink / Fuchsia cards — white text on saturated brand
   surfaces (matches the platform-wide convention used in admin
   dashboards, kit purchase, explore CTAs). Amber, peach and honey
   stay on the default dark text because their backgrounds are
   light enough that white would wash out. */
.free-page .preview-holding-ad-card--purple .phac-eyebrow,
.free-page .preview-holding-ad-card--purple .phac-headline,
.free-page .preview-holding-ad-card--purple .phac-body,
.free-page .preview-holding-ad-card--purple .phac-sub,
.free-page .preview-holding-ad-card--cyan  .phac-headline,
.free-page .preview-holding-ad-card--cyan  .phac-body,
.free-page .preview-holding-ad-card--cyan  .phac-sub,
.free-page .preview-holding-ad-card--fuchsia .phac-eyebrow,
.free-page .preview-holding-ad-card--fuchsia .phac-headline,
.free-page .preview-holding-ad-card--fuchsia .phac-body,
.free-page .preview-holding-ad-card--fuchsia .phac-sub {
  color: var(--white);
}
.free-page .preview-holding-ad-card--cyan .phac-pill {
  border-color: var(--white);
  color: var(--white);
}

/* Coral card CTA: pure black instead of the default `--black`
   (which is a slightly desaturated charcoal). The photo background
   needs the extra punch to keep the button reading as a button. */
.free-page .preview-holding-ad-card--purple .phac-cta {
  background: var(--navy);
}

.free-page .preview-holding-ad-inner {
  width: 100%;
  max-width: 480px;
}

.free-page .preview-holding-ad-label {
  font-size: var(--text-2xs);
  letter-spacing: var(--letter-spacing-eyebrow);
  font-weight: var(--font-semibold);
  text-transform: uppercase;
  color: rgb(255 255 255 / 0.78);
  margin-bottom: var(--space-3);
}

.free-page .preview-holding-ad-headline {
  font-size: clamp(20px, 1.6vw, 24px);
  font-weight: var(--font-weight-semibold, 600);
  line-height: 1.25;
  color: var(--white);
  margin: 0 0 var(--space-5);
}

.free-page .preview-holding-ad-pillars {
  list-style: none;
  margin: 0 0 var(--space-5);
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.free-page .preview-holding-ad-pillars li {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding-left: var(--space-3);
  border-left: 2px solid rgb(255 255 255 / 0.35);
}

.free-page .pha-pillar-title {
  font-size: var(--caption);
  font-weight: var(--font-semibold);
  color: var(--white);
}

.free-page .pha-pillar-body {
  font-size: 12.5px;
  line-height: 1.45;
  color: rgb(255 255 255 / 0.80);
}

.free-page .preview-holding-ad-hint {
  font-size: var(--text-xs);
  color: rgb(255 255 255 / 0.65);
  text-align: center;
  border-top: 1px solid rgb(255 255 255 / 0.15);
  padding-top: var(--space-3);
  margin-top: var(--space-3);
}

/* ----------------------------------------------------------------
   Mobile click-to-expand inline preview (.row-inline-preview).
   Injected by free.js below a tapped row on /free + /explore at
   <=767px. Hidden everywhere else so desktop right-col preview
   keeps working untouched. Three classes the JS uses:
     .row-inline-preview        — wrapper (display none until .open)
     .rip-headline / .rip-desc  — body content
     .rip-cta-wrap / .rip-cta   — "View report" CTA
   ---------------------------------------------------------------- */
.row-inline-preview { display: none; }

@media (max-width: 767px) {
  .row-inline-preview.open {
    display: block;
    padding: 0 var(--space-4) var(--space-4);
    background: var(--off-white);
  }
  .free-page .row-inline-preview.open,
  #explorePage .row-inline-preview.open {
    padding-top: 0;
    border-top: 1px solid var(--gray-light);
    border-bottom: 1px solid var(--gray-light);
    animation: ripFadeIn 140ms ease-out;
  }
  .row-inline-preview .ep-title-divider {
    margin-top: 0 !important;
    margin-bottom: 10px;
  }
  .row-inline-preview .rip-loading {
    font-size: 13px;
    color: #888;
    padding: var(--space-1) 0;
  }
  .row-inline-preview .rip-headline {
    font-size: 13.5px;
    line-height: 1.45;
    color: #1a1a1a;
    padding: var(--space-1) 0;
    display: flex;
    gap: var(--space-1-5);
  }
  .row-inline-preview .rip-headline-num {
    font-weight: 600;
    color: #555;
    flex: 0 0 auto;
  }
  .row-inline-preview .rip-desc {
    font-size: 13.5px;
    line-height: 1.5;
    color: #1a1a1a;
    padding: 2px 0 var(--space-1);
  }
  .row-inline-preview .rip-show-more {
    background: none;
    border: none;
    padding: 4px 0 0;
    font-size: 13px;
    font-weight: 600;
    color: var(--pink);
    cursor: pointer;
    letter-spacing: 0.01em;
  }
  .row-inline-preview .rip-extra { margin-top: 10px; }
  .row-inline-preview .rip-kicker-strip {
    width: 59px;
    height: 5px;
    margin: 12px 0 10px;
    background:
      linear-gradient(var(--kicker-t10), var(--kicker-t10))  0px 0 / 5px 5px no-repeat,
      linear-gradient(var(--kicker-t09), var(--kicker-t09))  6px 0 / 5px 5px no-repeat,
      linear-gradient(var(--kicker-t08), var(--kicker-t08)) 12px 0 / 5px 5px no-repeat,
      linear-gradient(var(--kicker-t07), var(--kicker-t07)) 18px 0 / 5px 5px no-repeat,
      linear-gradient(var(--kicker-t06), var(--kicker-t06)) 24px 0 / 5px 5px no-repeat,
      linear-gradient(var(--kicker-t05), var(--kicker-t05)) 30px 0 / 5px 5px no-repeat,
      linear-gradient(var(--kicker-t04), var(--kicker-t04)) 36px 0 / 5px 5px no-repeat,
      linear-gradient(var(--kicker-t03), var(--kicker-t03)) 42px 0 / 5px 5px no-repeat,
      linear-gradient(var(--kicker-t02), var(--kicker-t02)) 48px 0 / 5px 5px no-repeat,
      linear-gradient(var(--kicker-t01), var(--kicker-t01)) 54px 0 / 5px 5px no-repeat;
  }
  .row-inline-preview .rip-meta-cols {
    display: grid;
    grid-template-columns: max-content 1fr 1fr;
    gap: 8px;
    margin-bottom: 12px;
  }
  .free-page .row-inline-preview .rip-meta-cols,
  #explorePage .row-inline-preview .rip-meta-cols {
    grid-template-columns: max-content 1fr 1fr;
  }
  .row-inline-preview .rip-meta-col {
    display: flex;
    flex-direction: column;
    gap: 0;
    min-width: 0;
  }
  .free-page .row-inline-preview .rip-meta-col,
  #explorePage .row-inline-preview .rip-meta-col {
    gap: 0;
  }
  .row-inline-preview .rip-meta-stack { display: flex; flex-direction: column; gap: 8px; }
  .row-inline-preview .rip-meta-row {
    display: flex;
    flex-direction: column;
    gap: 2px;
  }
  .row-inline-preview .rip-meta-label {
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: #888;
  }
  .row-inline-preview .rip-meta-val {
    font-size: 13px;
    color: #1a1a1a;
    line-height: 1.45;
  }
  .row-inline-preview .rip-meta-row--pricing {
    margin-top: 8px;
    padding-bottom: 4px;
  }
  .row-inline-preview .rip-meta-row--pricing .rip-meta-val {
    font-weight: 300;
    color: var(--navy);
  }
  .row-inline-preview .rip-price-amount {
    font-weight: 600;
    color: var(--cyan);
  }
  .row-inline-preview .rip-price-medium {
    font-weight: 500;
  }
  .row-inline-preview .rip-cta-wrap {
    margin-top: var(--space-3);
  }
  .row-inline-preview .rip-cta {
    display: block;
    width: 100%;
    box-sizing: border-box;
    text-align: center;
    padding: 11px var(--space-4);
  }

  /* Dark overlay behind the selected card */
  .free-page.has-rip-open::before {
    content: '';
    position: fixed;
    inset: 0;
    background: rgba(15, 30, 65, 0.35);
    z-index: 9;
    pointer-events: none;
  }
  /* Selected row: override desktop clip (right) → mobile clip (bottom) + rounded top */
  .free-page .home-list-col .activity-item.hover-active,
  .free-page .home-list-col .activity-item.hover-active:hover,
  #exploreList .activity-item.hover-active,
  #exploreList .activity-item.hover-active:hover {
    border-radius: var(--radius-lg) var(--radius-lg) 0 0 !important;
    border-bottom: none !important;
    box-shadow: 0 0 0 7px var(--white), var(--shadow-xl) !important;
    clip-path: inset(-50px -50px 0 -50px) !important;
  }
  /* Slab: rounded bottom corners + matching shadow bleed */
  .row-inline-preview.open {
    position: relative;
    z-index: 10;
    box-shadow: 0 0 0 7px var(--white);
    clip-path: inset(0 -50px -50px -50px);
    border-radius: 0 0 var(--radius-lg) var(--radius-lg);
    margin: 0;
    border-top: 1px solid var(--gray-light);
  }
}

@keyframes ripFadeIn {
  from { opacity: 0; transform: translateY(-2px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* Mobile vertical-rhythm tweaks: tighten the gaps between the
   page title, search bar, and product list. Each `margin-top`
   value matches the per-section "move up" amount the user asked
   for, applied to the outermost element of each section. */
@media (max-width: 768px) {
  .free-page .page-title-block { margin-top: -20px; }
  /* Mobile rhythm: spacing now lives on the form (desktop default
     `24px auto 8px`) so the section's old `-5px` nudge moves onto
     the form instead. Net visual gap above the pill stays close
     to the previous mobile look (~5px). */
  .free-page .free-hero-search { margin-top: 5px; }
  .free-page .home-search-section { margin-top: -20px; }
}
