/**
 * Component Styles
 *
 * This file contains component-level CSS that requires proper cascade order
 * (loading AFTER Tailwind). For theme variables, see themes.css.
 */

/* ==========================================================================
   AUDIENCE CONTENT — DISSOLVE TRANSITIONS & HEIGHT RESERVATION
   Prevents layout jumping and adds graceful dissolves when switching
   Business/Individual audience.
   ========================================================================== */

/**
 * audience-height-reserve: Stacks both audience variants in the same grid
 * cell so the taller one drives container height — no layout jump on switch.
 * Overrides Stimulus hidden (display:none) with visibility:hidden to keep
 * the element in flow for height measurement.
 */
.audience-height-reserve {
  display: grid;
}

.audience-height-reserve > * {
  grid-column: 1;
  grid-row: 1;
  /* Prevent scroll anchoring from shifting the viewport when opacity changes
     on audience-switched panels during segment toggling. */
  overflow-anchor: none;
}

.audience-height-reserve > .hidden {
  display: block !important;
  visibility: hidden;
  pointer-events: none;
}

/**
 * audience-dissolve: Marker class for GSAP-driven crossfade transitions.
 *
 * On controller connect, JS converts the hidden class on inactive elements
 * to opacity:0 (keeping them in DOM flow). On audience switch, GSAP
 * crossfades active/inactive (duration set via dissolveDurationValue). togglePanelVisibility() skips
 * dissolve elements so the hidden class never interrupts the transition.
 *
 * No CSS transition rules here — GSAP handles all opacity animation.
 */

/* ==========================================================================
   RESEARCH LOGOS — Opacity-only de-emphasis for light/dark mode
   SVG fills handle all color; CSS controls visibility only.
   ========================================================================== */

.research-logo {
  opacity: 0.7;
  transition: opacity 0.3s ease;
}

.dark .research-logo {
  opacity: 0.85;
}

/* Research page: source links — no decoration at rest, underline + bg tint on hover */
.research-content .research-source-link {
  text-decoration: none;
}

/* a11y (#778): inside <blockquote> attribution lines, the surrounding text uses
   --color-foreground-secondary which has insufficient contrast with
   --color-accent-primary (1.17:1 light, 1.03:1 dark — both fail axe-core's
   link-in-text-block 3:1 threshold). Restore the underline at rest so the
   non-color distinguishing feature satisfies the rule. Body-text source links
   on --color-foreground-primary still rely on the no-underline aesthetic. */
.research-content blockquote .research-source-link {
  text-decoration: underline;
}

/* External link arrow in [View ↗] — scaled down to sit proportionally next to text */
.research-source-link .external-arrow {
  font-size: 0.65em;
  vertical-align: baseline;
}

/* Inline academic citations — smaller font, bg tint + underline on hover only */
.research-content .cite-link {
  color: var(--color-accent);
  text-decoration: none;
  font-size: 0.9em;
  border-radius: 2px;
  transition: background 0.2s ease;
}

.research-content .cite-link:hover {
  background: color-mix(in srgb, var(--color-accent) 8%, transparent);
  text-decoration: underline;
}

/* ==========================================================================
   ARTICLE / RESEARCH TOC — Fixed sidebar Table of Contents with scrollspy
   Visible only on viewports >= 1440px where the left margin has space for a
   comfortable gap between the TOC right edge and the article body text
   (#895 raised the breakpoint from 1280px — at 1280px the gap was ~12px,
   which read as the TOC crowding the reading column. At 1440px the gap is
   comfortable). Two class families share these rules:
     - .research-toc*  hand-authored on /research/business + /research/individual
     - .article-toc*   auto-generated on /blog/<slug> (#847)
   The toc-scrollspy Stimulus controller works against both via class-family
   detection in activateLink().
   ========================================================================== */

.research-toc,
.article-toc {
  position: fixed;
  /* `top` is read from a CSS custom property so the toc-anchor Stimulus
     controller (app/javascript/controllers/toc_anchor_controller.js) can
     dynamically push the TOC below the post header at page-top in opt-in
     tracking mode. In the #895 pinned default this fallback (`9rem`) is
     the only governing value — pinned mode never writes the inline
     property. Bumped from 7rem in #893 to leave 48px of breathing room
     below the 96px fixed nav bar at all `>=1440px` viewport widths
     (breakpoint raised from 1280px in #895). See #850 for the originating
     context. */
  top: var(--article-toc-top, 9rem);
  /* Cap height so long TOCs (many H2+H3 entries) scroll internally instead
     of overflowing off-screen, and so the TOC stays usable at short viewport
     heights. The 1rem bottom inset is a comfortable gutter at very short
     heights. The calc reads the same custom property as `top`, so the cap
     adjusts automatically when the controller pushes the TOC down at
     page-top. Introduced in #890 alongside the synthetic Scroll-to-Top
     entry; serves the viewport-height resilience requirement. The 9rem
     fallback (was 7rem in #890; bumped in #893) tightens the page-top
     ceiling by 32px — the 4rem floor below still protects the synthetic
     entry plus at least one heading row at short viewport heights. */
  /* Floor at 4rem so a tall article header writing a large
     --article-toc-top value can't collapse the TOC to zero height. Per
     the CSS overflow spec, `max-height` clamps negative values to 0,
     which would hide the entire TOC even though `top` and `display`
     are satisfied. The 4rem floor guarantees the synthetic Scroll-to-Top
     entry plus at least one heading row stay visible. Per Greptile
     review on #891 round 2. */
  max-height: max(4rem, calc(100vh - var(--article-toc-top, 9rem) - 1rem));
  overflow-y: auto;
  /* Explicit horizontal overflow lock. Per the CSS overflow spec,
     setting `overflow-y` to anything other than `visible` implicitly
     computes `overflow-x` to `auto` as well, which would surface a
     stray horizontal scrollbar inside the bordered/rounded TOC box if
     any heading label (or a future icon on the synthetic link) ever
     exceeds the 180px container width. `overflow-x: hidden` locks the
     intended behaviour. Per Greptile review on #891 round 2. */
  overflow-x: hidden;
  /* Reserve the scrollbar gutter symmetrically on both sides. On Windows
     and Linux with classic (non-overlay) scrollbars, the moment
     `overflow-y: auto` engages the ~17px scrollbar is taken from the fixed
     180px container width, which can cause longer heading labels to
     suddenly wrap to two lines. `scrollbar-gutter: stable` reserves the
     gutter regardless of whether content currently overflows, preventing
     the layout jump (per Greptile review on #891 round 1).
     The `both-edges` extension (#895) reserves the gutter on BOTH sides
     so the inner content (the `<hr>` divider in particular) reads as
     visually centered. Without `both-edges` the single-side reserved
     gutter leaves the inner content visually offset to the left, which
     made the divider under the synthetic "↑ Top" entry look asymmetric.
     Both keywords (`stable` and `both-edges`) shipped together in
     Chrome/Edge 94+, Firefox 97+, and Safari 18.2+ — so every browser
     that supports `scrollbar-gutter` at all also supports `both-edges`.
     Browsers without `scrollbar-gutter` support drop the whole
     declaration (per CSS error recovery, an unrecognized token
     invalidates the entire declaration — not a selective keyword
     fallback), leaving the no-gutter baseline that pre-#891 behavior
     had — same as today's behavior on those browsers. */
  scrollbar-gutter: stable both-edges;
  /* Position in the left margin, relative to the max-w-4xl (56rem) content column */
  left: max(1rem, calc((100vw - 56rem) / 2 - 13rem));
  /* Width bumped from 170px to 180px (#863) to absorb the 0.5rem total
     horizontal outer padding without forcing more link-text wraps. The
     180px (not 190px) decision originated when the minimum visible
     viewport was 1280px: with #895 raising that floor to 1440px the
     collision margin is much more comfortable (at 1440px the article
     column starts at ~288px while the TOC right edge sits at ~244px —
     ~44px gap), but the 180px width is retained so heading-wrap behavior
     stays stable across the breakpoint bump. The original 1280px gap
     math is preserved in commit history (Greptile review #866) for
     future reference if the breakpoint is ever lowered again. */
  width: 180px;
  z-index: 20;
  /* Soft container treatment so the floating TOC reads as a distinct sidebar
     component instead of bare text against the page background (#863).
     --color-border-decorative is the same token used by .blog-tag borders, so
     this reads at a consistent weight in both light and dark mode. */
  border: 1px solid var(--color-border-decorative);
  border-radius: 0.75rem;
  padding: 0.5rem 0.25rem;
  display: none;
}

/* Smooth the TOC's vertical slide between header-aligned and pinned positions.
   Only applies to .article-toc (blog posts), not .research-toc — the research
   variant has no JS wired to it and keeps the static 9rem fallback (per #893,
   shared with .article-toc via the fallback in `var(--article-toc-top, 9rem)`
   above). Gated on prefers-reduced-motion so reduced-motion users get hard
   cuts per frame. Note: with the #895 pin-mode flag defaulting to "pinned",
   this transition is effectively dormant in the default code path — pinned
   mode never changes the inline `--article-toc-top` property, so there's
   nothing to transition. The rule is retained for the opt-in "tracking" mode
   (data-toc-anchor-mode-value="tracking"). */
@media (prefers-reduced-motion: no-preference) {
  .article-toc {
    transition: top 120ms linear;
  }
}

@media (min-width: 1440px) {
  .research-toc,
  .article-toc {
    display: block;
  }
}

.research-toc__link,
.article-toc__link {
  display: block;
  padding: 0.375rem 0.75rem;
  font-size: 0.8125rem;
  line-height: 1.4;
  color: var(--color-foreground-secondary);
  text-decoration: none;
  border-left: 2px solid transparent;
  transition: color 0.2s ease, border-color 0.2s ease;
}

.research-toc__link:hover,
.article-toc__link:hover {
  color: var(--color-foreground-primary);
}

.research-toc__link--active,
.article-toc__link--active {
  color: var(--color-accent);
  border-left-color: var(--color-accent);
  font-weight: 600;
}

.research-toc__sublist,
.article-toc__sublist {
  margin-top: 0.125rem;
  padding-left: 0.75rem;
  border-left: 1px dashed var(--color-border);
}

.research-toc__sublink,
.article-toc__sublink {
  display: block;
  padding: 0.25rem 0.5rem;
  font-size: 0.6875rem;
  line-height: 1.35;
  color: var(--color-foreground-secondary);
  opacity: 0.75;
  text-decoration: none;
  transition: color 0.2s ease, opacity 0.2s ease;
}

.research-toc__sublink:hover,
.article-toc__sublink:hover {
  color: var(--color-foreground-primary);
  opacity: 1;
}

.research-toc__sublink--active,
.article-toc__sublink--active {
  color: var(--color-accent);
  font-weight: 600;
  opacity: 1;
}

/* TOC links: suppress browser default focus outline at rest (clicked links
   keep :focus through the smooth scroll, which renders as a lingering
   indicator on the active item — see GH#881 thread). Restore a clean
   focus indicator only for keyboard-tab navigation via :focus-visible so
   the a11y contract is preserved.

   #895: switched from `outline + outline-offset` to `inset box-shadow`.
   The parent `.article-toc` container has `overflow-x: hidden` (per #891
   round 2), which clips any outline rendered outside the link's box. With
   the previous outline at 2px solid + 2px offset + 2px border-radius, the
   horizontal portions of the outline got clipped, leaving only the
   rounded-corner arc fragments visible at the link's right edge — a
   distracting "bubble" artifact that followed the active link as scrollspy
   moved it. An `inset` box-shadow sits entirely within the link's content
   box and is immune to parent overflow clipping, so the focus indicator
   renders cleanly without artifacts in both light and dark mode and for
   both mouse-click and keyboard-tab activation. */
.research-toc__link:focus,
.article-toc__link:focus,
.research-toc__sublink:focus,
.article-toc__sublink:focus {
  outline: none;
}

.research-toc__link:focus-visible,
.article-toc__link:focus-visible,
.research-toc__sublink:focus-visible,
.article-toc__sublink:focus-visible {
  outline: none;
  box-shadow: inset 0 0 0 2px var(--color-accent-primary);
  border-radius: 2px;
}

/* Synthetic "Scroll to Top" entry (#890; visual refinement #893): visually
   a sibling of .article-toc__link but explicitly non-heading. The modifier
   overrides the base rule's heading-entry feel (left-aligned secondary text
   with a 2px gutter for the active-state indicator) and instead renders
   the entry as a centered uppercase tertiary control: small font, wide
   letter-spacing, muted color, paired with an aria-hidden up-arrow glyph.
   Four layered signals (center-align + uppercase + smaller size + arrow)
   ensure the reader recognises this pre-attentively as "the way back to
   the top" rather than as the first heading. The synthetic link must NEVER
   receive the --active modifier — that's enforced by the partial omitting
   the data-toc-scrollspy-target attribute, not by CSS.

   border-left-color: transparent suppresses the heading-entry indicator
   track on the synthetic entry; the 2px gutter from the base rule stays
   in place so vertical alignment with heading entries remains consistent.

   Click routes through the delegated anchor handler in
   animations_controller.js (Lenis smooth scroll), the same path used by
   the floating .back-to-top button (#881). */
.article-toc__link--synthetic {
  text-align: center;
  font-size: 0.6875rem;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--color-foreground-muted);
  border-left-color: transparent;
  padding: 0.5rem 0.5rem;
}

.article-toc__link--synthetic:hover {
  color: var(--color-accent-primary);
}

/* Horizontal divider between the synthetic Scroll-to-Top entry and the
   auto-generated heading entries (#890; restyled in #893). Uses the same
   border token as the .article-toc outer border for visual consistency in
   both light and dark mode. Horizontal inset margins (0.5rem each side)
   keep the divider from touching the rounded TOC container border —
   reads as a deliberate gutter rather than a clipped edge. Opacity 0.6
   softens the line so it complements the new synthetic-link treatment
   above without competing with it. Rendered inside an <li aria-hidden="true">
   wrapper so the semantic list contract stays clean while the divider
   remains a sibling of the link entries. */
.article-toc__divider {
  border: 0;
  border-bottom: 1px solid var(--color-border-decorative);
  margin: 0.375rem 0.5rem;
  opacity: 0.6;
}

/* Decorative opening quote mark for research carousel slides — CSS-only ::before approach.
   The blockquote is constrained to max-w-2xl / lg:max-w-3xl with mx-auto, making the left edge predictable.
   Uses em units for vertical offset so it auto-scales with responsive font-size. */
.research-quote::before {
  content: '\201C';
  position: absolute;
  left: -0.1em;
  top: -0.25em;
  font-size: 3.25rem;
  color: color-mix(in srgb, var(--color-accent-primary) 25%, transparent);
  line-height: 1;
  font-family: Georgia, serif;
  pointer-events: none;
}

@media (min-width: 768px) {
  .research-quote::before {
    left: -0.5em;
    font-size: 4.5rem;
  }
}

@media (min-width: 1024px) {
  .research-quote::before {
    font-size: 6rem;
  }
}

.dark .research-quote::before {
  color: color-mix(in srgb, var(--color-accent-primary) 15%, transparent);
}

/* ==========================================================================
   BACK-TO-TOP BUTTON
   --------------------------------------------------------------------------
   Floating circular button rendered on every blog post show page. Visibility
   is toggled by the `back-to-top` Stimulus controller (adds/removes
   `.back-to-top--visible` based on window.scrollY). The click is handled by
   the delegated anchor handler in animations_controller.js (Lenis +
   prefers-reduced-motion-aware native fallback). See GH#881.
   ========================================================================== */

.back-to-top {
  position: fixed;
  bottom: 1.5rem;
  right: 1.5rem;
  width: 3rem;
  height: 3rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 9999px;
  background-color: var(--color-accent-primary);
  color: #ffffff;
  border: 1px solid color-mix(in srgb, var(--color-accent-primary) 80%, black);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
  /* Hidden by default; the controller toggles --visible to show it. */
  opacity: 0;
  pointer-events: none;
  transform: translateY(0.5rem);
  z-index: 20;
  /* Smooth fade-in/out for motion-allowed users. The
     prefers-reduced-motion media query below overrides this to instant. */
  transition: opacity 200ms ease, transform 200ms ease, background-color 200ms ease;
}

.back-to-top:hover {
  background-color: var(--color-accent-hover);
}

/* The button's background is also --color-accent-primary, so using the same
   token for the outline would make the focus ring blend into the fill.
   Use --color-bg-primary so the ring is the page background color, producing
   a visible contrast halo around the button against any underlying content. */
.back-to-top:focus-visible {
  outline: 2px solid var(--color-bg-primary);
  outline-offset: 2px;
  box-shadow: 0 0 0 4px var(--color-accent-primary);
}

.back-to-top__icon {
  width: 1.25rem;
  height: 1.25rem;
}

.back-to-top--visible {
  opacity: 1;
  pointer-events: auto;
  transform: translateY(0);
}

/* Dark mode: accent-primary inverts to a light cyan in dark theme
   (see themes.css), so the white arrow becomes invisible. Flip
   the icon color to the dark theme's bg-primary so it reads correctly. */
.dark .back-to-top {
  color: var(--color-bg-primary);
  border-color: color-mix(in srgb, var(--color-accent-primary) 80%, white);
}

@media (prefers-reduced-motion: reduce) {
  .back-to-top {
    transition: none;
    transform: none;
  }
  .back-to-top--visible {
    transform: none;
  }
}

/* ==========================================================================
   BUTTON COMPONENT SYSTEM
   ========================================================================== */

/**
 * Centralized button styles for consistent UI across the site.
 *
 * Variants:
 * - button-primary: Accent background with proper contrast text
 * - button-secondary: Ghost/outline button with border
 * - button-gradient: Gradient background (accent → purple)
 *
 * Sizes:
 * - Default (large): px-8 py-2.5 text-lg - for page CTAs
 * - button-small: px-6 py-2 text-sm - for cards, inline CTAs
 * - button-extra-small: px-5 py-1.5 text-sm - for header, compact areas
 *
 * Usage:
 *   <a class="button-primary">Get Started</a>
 *   <a class="button-secondary">Learn More</a>
 *   <a class="button-primary button-small">Small CTA</a>
 */

/* Base button styles (shared by all variants) */
.button-primary,
.button-secondary,
.button-gradient {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-weight: 500;
  border-radius: 9999px; /* rounded-full */
  transition: all 0.3s ease;
  /* Default size (large) */
  padding: 0.625rem 2rem; /* py-2.5 px-8 */
  font-size: 1.125rem; /* text-lg */
  line-height: 1.75rem;
}

/* Primary button - accent background with contrast text */
.button-primary {
  background-color: var(--color-accent-primary);
  color: #ffffff;
}

.button-primary:hover {
  background-color: var(--color-accent-hover);
  transform: scale(1.05);
}

/* Dark mode: text needs to be dark on light cyan background */
.dark .button-primary {
  color: var(--color-bg-primary);
}

/* Primary inverted button - white bg, blue text (for bold/dark sections in light mode)
   Dark mode: reverts to standard button-primary appearance */
.button-primary-inverted {
  background-color: #ffffff;
  color: var(--color-accent-primary);
}

.button-primary-inverted:hover {
  background-color: #e8f1f8;
  transform: scale(1.05);
}

.dark .button-primary-inverted {
  background-color: var(--color-accent-primary);
  color: var(--color-bg-primary);
}

.dark .button-primary-inverted:hover {
  background-color: var(--color-accent-hover);
}

/* Secondary button - ghost/outline style */
.button-secondary {
  background-color: rgba(0, 0, 0, 0.03); /* Subtle fill for visibility on light panels */
  color: var(--color-foreground-primary);
  border: 1px solid var(--color-border-decorative);
}

.button-secondary:hover {
  background-color: rgba(0, 0, 0, 0.08); /* More pronounced hover state */
  border-color: var(--color-border-decorative-hover);
}

/* Dark mode: filled background with accent text (matches Webflow template) */
/* Opaque backgrounds prevent grid/pattern bleed-through (see global button rule) */
.dark .button-secondary {
  background-color: color-mix(in srgb, white 8%, var(--color-bg-primary));
  color: var(--color-accent-primary);           /* Light blue #83d3ff - matches primary button bg */
  border-color: rgba(255, 255, 255, 0.12);      /* Subtle border */
}

.dark .button-secondary:hover {
  background-color: color-mix(in srgb, white 12%, var(--color-bg-primary));
  border-color: rgba(255, 255, 255, 0.18);
}

/* Gradient button - accent to purple gradient */
.button-gradient {
  background: linear-gradient(to right, var(--color-accent-primary), var(--color-purple-accent));
  color: var(--color-bg-primary);
  box-shadow: 0 10px 15px -3px rgba(var(--color-accent-primary), 0.25);
}

.button-gradient:hover {
  background: linear-gradient(to right, var(--color-accent-hover), rgba(var(--color-purple-accent), 0.8));
  box-shadow: 0 10px 15px -3px rgba(var(--color-accent-primary), 0.4);
}

/* Size modifiers */
.button-small {
  padding: 0.5rem 1.5rem; /* py-2 px-6 */
  font-size: 0.875rem; /* text-sm */
  line-height: 1.25rem;
}

.button-extra-small {
  padding: 0.375rem 1.25rem; /* py-1.5 px-5 */
  font-size: 0.875rem; /* text-sm */
  line-height: 1.25rem;
}

/* No scale on hover variant (for smaller buttons) */
.button-no-scale:hover {
  transform: none;
}

/* Full width variant */
.button-block {
  display: flex;
  width: 100%;
  text-align: center;
}

/* Shadow variant */
.button-shadow {
  box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
}

/* text-on-accent: defined as @utility in app/assets/tailwind/application.css (gh #917) */

/* ==========================================================================
   LOGO HOVER EFFECT
   ========================================================================== */

/**
 * Shimmer sweep effect for logo on hover.
 * Uses a pseudo-element with animated gradient overlay.
 * Loops continuously while hovering.
 */
.logo-hover-effect {
  position: relative;
}

.logo-hover-effect::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(
    90deg,
    transparent 0%,
    transparent 40%,
    rgba(255, 255, 255, 0.3) 50%,
    transparent 60%,
    transparent 100%
  );
  background-size: 250% 100%;
  background-position: 100% 0;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.2s ease;
}

.logo-hover-effect:hover::after {
  opacity: 1;
  animation: logo-shimmer 1.5s ease-in-out infinite;
}

@keyframes logo-shimmer {
  0% {
    background-position: 100% 0;
  }
  100% {
    background-position: -50% 0;
  }
}

/* Dark mode: use the page background color (#040c11) as the shimmer.
 * This makes the shimmer invisible on the dark background (same color blends)
 * while creating a subtle darkening sweep on the light logo elements.
 * Mirrors light mode approach where white shimmer blends with light background. */
.dark .logo-hover-effect::after {
  background: linear-gradient(
    90deg,
    transparent 0%,
    transparent 40%,
    rgba(4, 12, 17, 0.4) 50%,
    transparent 60%,
    transparent 100%
  );
  background-size: 250% 100%;
  background-position: 100% 0;
}

/* ==========================================================================
   SESSION CARD SHIMMER (Programs page)
   ========================================================================== */

/**
 * Radial shimmer glow in the bottom-right corner of session cards on hover.
 * Uses a pseudo-element with a radial gradient that fades in on hover
 * and pulses subtly with an animation loop.
 */
.session-card-shimmer::after {
  content: '';
  position: absolute;
  bottom: -20%;
  right: -20%;
  width: 60%;
  height: 60%;
  background: radial-gradient(
    circle at center,
    rgba(131, 211, 255, 0.2) 0%,
    rgba(131, 211, 255, 0.08) 40%,
    transparent 70%
  );
  border-radius: 50%;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.4s ease;
}

.session-card-shimmer:hover::after {
  opacity: 1;
  animation: session-shimmer 2s ease-in-out infinite;
}

@keyframes session-shimmer {
  0%, 100% {
    transform: scale(1);
    opacity: 1;
  }
  50% {
    transform: scale(1.15);
    opacity: 0.7;
  }
}

/* Reduced motion: disable shimmer animation */
@media (prefers-reduced-motion: reduce) {
  .session-card-shimmer:hover::after {
    animation: none;
    opacity: 0.6;
  }
}

/* ==========================================================================
   SEGMENTED CONTROL ANIMATIONS
   ========================================================================== */

/**
 * Segmented control container needs relative positioning for the slider.
 * The slider is an absolutely positioned pill that slides behind the active tab.
 */
.segmented-control {
  position: relative;
  overflow: visible;
}

/* Sliding pill indicator */
/* Note: Container has p-1 (4px) padding, so slider must be inset to align with tabs */
.segmented-control-slider {
  position: absolute;
  top: 4px;    /* Match container's p-1 padding */
  left: 4px;   /* Match container's p-1 padding */
  height: calc(100% - 8px);  /* Exclude top and bottom padding */
  width: calc(50% - 4px);  /* CSS fallback: half the container minus padding (2 tabs) */
  background-color: var(--color-accent-primary);
  border-radius: 9999px;
  /* Initial position - GSAP handles all transforms, no CSS transition needed */
  transform: translateX(0);
  /* Use will-change to hint browser for smoother animation */
  will-change: transform, width;
  z-index: 0;
}

/* Tab elements sit above the slider */
/* Uses <div> instead of <button> to avoid inherited active/focus background states */
.segmented-control-tab {
  position: relative;
  z-index: 1;
  /* Text color animation handled by GSAP in audience_state_controller.js */
  /* Prevent any background on tabs - only slider provides background */
  background: transparent !important;
  /* Suppress browser tap-highlight overlay (Chrome blue flash on click) */
  -webkit-tap-highlight-color: transparent;
  /* Default text color for non-selected tabs */
  color: var(--color-foreground-secondary);
}

/* Suppress all focus/active/hover background states on tabs */
.segmented-control-tab:hover,
.segmented-control-tab:focus,
.segmented-control-tab:active {
  background: transparent !important;
  outline: none;
}

/* Accessible focus indicator for keyboard navigation */
.segmented-control-tab:focus-visible {
  background: transparent !important;
  outline: 2px solid var(--color-accent-primary);
  outline-offset: 2px;
}

/* Visually selected tab text color - sits on top of the accent slider */
/* Updated AFTER the slider animation completes via data-visually-selected attribute */
/* Must also apply on hover to prevent color change when hovering selected tab */
.segmented-control-tab[data-visually-selected="true"],
.segmented-control-tab[data-visually-selected="true"]:hover {
  color: var(--color-bg-primary);
}

/* Hover effect only for non-selected tabs */
.segmented-control-tab:not([data-visually-selected="true"]):hover {
  color: var(--color-foreground-primary);
}

/* Tooltip for unselected tabs — styled to match Chromium's validation popup.
   Arrow uses rotated-square technique for a seamless speech-bubble connection.
   Base styles on [data-tooltip] so fade-out transition runs when
   [data-show-tooltip] is removed on segment switch. */
.segmented-control-tab[data-tooltip]::after {
  content: attr(data-tooltip);
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  background: #fff;
  color: #202124;
  font-size: 0.8125rem;
  font-weight: 400;
  line-height: 1.4;
  padding: 8px 16px;
  border-radius: 16px;
  border: 1px solid #bfbfbf;
  box-shadow: 0 3px 8px rgba(0, 0, 0, 0.15);
  white-space: nowrap;
  pointer-events: none;
  z-index: 1000;
  opacity: 0;
  transition: opacity 1s ease;
}

.segmented-control-tab[data-tooltip]::before {
  content: '';
  position: absolute;
  top: calc(100% + 4px);
  left: 50%;
  width: 10px;
  height: 10px;
  transform: translateX(-50%) rotate(45deg);
  background: #fff;
  border-top: 1px solid #bfbfbf;
  border-left: 1px solid #bfbfbf;
  pointer-events: none;
  z-index: 1001;
  opacity: 0;
  transition: opacity 1s ease;
}

@media (hover: hover) {
  .segmented-control-tab[data-show-tooltip]:hover::after,
  .segmented-control-tab[data-show-tooltip]:hover::before {
    opacity: 1;
    transition: opacity 0.15s ease 0.4s;
  }
}

/* ==========================================================================
   CARD FLIP ANIMATION
   ========================================================================== */

/**
 * 3D card flip animation for content panels.
 * Cards flip on the Y-axis (like playing cards flipping sideways).
 *
 * Structure:
 *   <div class="flip-card-container">  <!-- Perspective container -->
 *     <div class="flip-card">          <!-- The flipping element -->
 *       Content here
 *     </div>
 *   </div>
 */

/* Container provides 3D perspective */
.flip-card-container {
  perspective: 1000px;
}

/* The card that flips */
.flip-card {
  transform-style: preserve-3d;
  backface-visibility: hidden;
  /* Explicit none prevents CSS build from merging transitions from flip state classes */
  transition: none;
}

/* Transition only applies during flip animation (not scroll entrance) */
/* Duration reduced from 0.6s to 0.3s for snappier feel */
.flip-card.flip-out,
.flip-card.flip-in,
.flip-card.flip-in-start {
  transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.15s ease;
}

/* Flip out state (hiding) - rotates away */
.flip-card.flip-out {
  transform: rotateY(-90deg);
  opacity: 0;
}

/* Flip in state (showing) - starts rotated, animates to flat */
.flip-card.flip-in {
  transform: rotateY(0deg);
  opacity: 1;
}

/* Initial state for cards that will flip in */
.flip-card.flip-in-start {
  transform: rotateY(90deg);
  opacity: 0;
}

/* Staggered animation delays for grid cards */
.flip-card-stagger-1 { transition-delay: 0ms; }
.flip-card-stagger-2 { transition-delay: 50ms; }
.flip-card-stagger-3 { transition-delay: 100ms; }
.flip-card-stagger-4 { transition-delay: 150ms; }
.flip-card-stagger-5 { transition-delay: 200ms; }
.flip-card-stagger-6 { transition-delay: 250ms; }

/* ==========================================================================
   HERO HEADLINE TYPOGRAPHY
   ========================================================================== */


/* ==========================================================================
   SECTION SUBTITLE TYPOGRAPHY — WIDOW PREVENTION
   text-wrap: balance redistributes words across lines for visual evenness.
   Works on blocks up to ~6 lines (perfect for subtitles, not for prose).
   Browser support: Chrome 114+, Firefox 121+, Safari 17.5+.
   Degrades gracefully — unsupported browsers wrap normally.
   ========================================================================== */

p[class*="text-foreground-secondary"][class*="max-w-"] {
  text-wrap: balance;
}

/* --------------------------------------------------------------------------
   TEXT ORPHAN ELIMINATION — text-wrap: pretty
   Prevents 1-2 orphaned words on the last line of centered text blocks.
   Applied via data-reflow="optimize" attribute on individual elements.
   Works on blocks of any length (unlike balance which caps at ~6 lines).
   Browser support: Chrome 117+, Firefox 131+. Degrades gracefully.
   -------------------------------------------------------------------------- */

[data-reflow] {
  text-wrap: pretty;
}

/* ==========================================================================
   SHIMMER TEXT HIGHLIGHT EFFECT
   ========================================================================== */

/**
 * Gradient shimmer sweep effect for text emphasis.
 * Uses background-clip: text with an animated gradient position.
 *
 * The gradient has three sections: base color → bright highlight → base color
 * GSAP animates backgroundPosition from right (100%) to left (0%) to create
 * the "sweeping highlight" effect.
 *
 * Usage:
 *   <p class="shimmer-text">Text to shimmer</p>
 *   // Then animate with GSAP: gsap.to(el, { backgroundPosition: '0% 0' })
 */
.shimmer-text {
  background: linear-gradient(
    90deg,
    var(--color-foreground-primary) 0%,
    var(--color-foreground-primary) 40%,
    var(--color-accent-primary) 50%,
    var(--color-foreground-primary) 60%,
    var(--color-foreground-primary) 100%
  );
  background-size: 250% 100%;
  background-position: 100% 0; /* Start with highlight off-screen right */
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
}

/**
 * Shimmer text on bold backgrounds (light mode only): the underlying surface
 * is the dark bold bg (#0c2048), so the text must read in light tones.
 *
 * Iteration history:
 *   1. Original (pre-#865): white base → #b1d4e0 sky-blue peak. Peak was
 *      perceptually DARKER than base, so the sweep read as a dim band.
 *   2. #865 "torch sweep": #dbe5ee → #e8f4ff → #ffffff white-only stops.
 *      Mathematically a visible luminance delta (~27 Rec.709 units), but
 *      perceptually INVISIBLE on dark navy — the eye reads all three
 *      near-white values as "uniform bright text" against the dark backdrop.
 *   3. Current (#877) "chromatic peak": cool off-white base (#dbe5ee),
 *      cyan-tinted transition (#a8e0ff), bright cyan core (#83d3ff — the
 *      same color the dark-mode override uses for its highlight). The hue
 *      shift gives the eye a perceptible "color sweep" to latch onto,
 *      mirroring what makes the logo hover-shimmer perceptible on the dark
 *      logo against a light nav. The base stays a soft cool off-white so
 *      the text is highly legible at rest.
 *
 * The .dark override below restores the default shimmer gradient
 * (with --color-accent-primary highlight) in dark mode — left untouched.
 */
.bg-bg-bold .shimmer-text {
  background: linear-gradient(
    90deg,
    #dbe5ee 0%,
    #dbe5ee 40%,
    #a8e0ff 47%,
    #83d3ff 50%,
    #a8e0ff 53%,
    #dbe5ee 60%,
    #dbe5ee 100%
  );
  background-size: 250% 100%;
  background-position: 100% 0;
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
}

/* Dark mode: restore the default shimmer gradient (accent highlight) */
.dark .bg-bg-bold .shimmer-text {
  background: linear-gradient(
    90deg,
    var(--color-foreground-primary) 0%,
    var(--color-foreground-primary) 40%,
    var(--color-accent-primary) 50%,
    var(--color-foreground-primary) 60%,
    var(--color-foreground-primary) 100%
  );
  background-size: 250% 100%;
  background-position: 100% 0;
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
}

/* ==========================================================================
   ANIMATED ARROW LINK — right-shift on hover
   A reusable utility for text links with a trailing → that shifts right.

   Usage:
     <a href="..." class="link-arrow [text/color classes]">
       Link text <span class="link-arrow-icon">&rarr;</span>
     </a>

   .link-arrow enables inline-flex layout on the anchor.
   .link-arrow-icon wraps the → and shifts 4px right on hover.
   ========================================================================== */

.link-arrow {
  display: inline-flex;
  align-items: center;
}

.link-arrow .link-arrow-icon {
  display: inline-block;
  margin-left: 0.25rem; /* ml-1 */
  transition: transform 0.2s ease;
}

.link-arrow:hover .link-arrow-icon {
  transform: translateX(4px);
}

/* ==========================================================================
   ACCESSIBILITY - REDUCED MOTION SUPPORT
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
  .segmented-control-slider {
    transition: none;
  }
  /* Disable shimmer animation for users who prefer reduced motion.
     The override selectors below mirror the specificity of the matching
     full-motion declarations so this rule actually wins — without them,
     `.bg-bg-bold .shimmer-text { background-position: 100% 0 }` outranks
     the bare `.shimmer-text` selector and the highlight stays parked
     off-screen (#865 added the regression test that surfaces this). */
  .shimmer-text,
  .bg-bg-bold .shimmer-text,
  .dark .bg-bg-bold .shimmer-text {
    background-position: 50% 0; /* Show at rest state (highlight centered/visible once) */
  }
  .link-arrow .link-arrow-icon {
    transition: none;
  }
  /* Disable flip card 3D transitions — JS short-circuits the class application,
     but this CSS rule provides belt-and-suspenders coverage for any CSS path. */
  .flip-card.flip-out,
  .flip-card.flip-in,
  .flip-card.flip-in-start {
    transition: none;
  }
}

/* ==========================================================================
   STANDARD CARD CORNER GLOW
   ========================================================================== */

/**
 * Corner glow effect for standard cards (challenge cards, outcome cards, etc.).
 * Each card can have a subtle radial gradient glow in a specified corner.
 *
 * Positions:
 *   - glow-tl: top-left corner
 *   - glow-tr: top-right corner
 *   - glow-bl: bottom-left corner
 *   - glow-br: bottom-right corner
 *
 * Uses CSS custom property --glow-color to support different accent colors
 * (accent for business, highlight for individual).
 *
 * Note: .challenge-card kept for backwards compatibility with existing usage.
 */
.challenge-card,
.standard-card,
.blog-card {
  position: relative;
  overflow: hidden;
}

.challenge-card::before,
.standard-card::before,
.blog-card::before {
  content: '';
  position: absolute;
  width: 200px;
  height: 200px;
  border-radius: 50%;
  background: radial-gradient(circle, var(--glow-color, var(--color-accent-primary)) 0%, transparent 70%);
  opacity: 0.15;
  pointer-events: none;
  z-index: 0;
}

/* Position variants - outermost corner for each card */
.challenge-card.glow-tl::before,
.standard-card.glow-tl::before,
.blog-card.glow-tl::before {
  top: -100px;
  left: -100px;
}

.challenge-card.glow-tr::before,
.standard-card.glow-tr::before,
.blog-card.glow-tr::before {
  top: -100px;
  right: -100px;
}

.challenge-card.glow-bl::before,
.standard-card.glow-bl::before,
.blog-card.glow-bl::before {
  bottom: -100px;
  left: -100px;
}

.challenge-card.glow-br::before,
.standard-card.glow-br::before,
.blog-card.glow-br::before {
  bottom: -100px;
  right: -100px;
}

/* Ensure card content sits above the glow */
.challenge-card > *,
.standard-card > *,
.blog-card > * {
  position: relative;
  z-index: 1;
}

/* Light mode: reduce glow intensity to 25% of original - subtle on light backgrounds */
:root:not(.dark) .challenge-card::before,
:root:not(.dark) .standard-card::before,
:root:not(.dark) .blog-card::before {
  opacity: 0.04;
}

/* ==========================================================================
   CARD HOVER ANIMATION - SMOOTH "MOON FLOATING" EFFECT
   ========================================================================== */

/**
 * Creates an ultra-smooth, airy hover lift like an astronaut floating on the moon.
 * Uses a very long duration (5s) with gentle ease-out curve for that
 * dreamy, weightless deceleration feel.
 *
 * The cubic-bezier(0.05, 0.9, 0.1, 1) creates:
 * - Immediate response (starts right away)
 * - Very gradual, floating movement throughout
 * - Extremely soft landing at the end
 *
 * HOVER STABILITY:
 * Uses a wrapper (.card-hover-wrapper) that handles hover detection while staying
 * in place. This prevents flicker when the card lifts and the mouse would otherwise
 * leave the card's visual bounds. The wrapper has bottom padding to extend the
 * hover detection zone below where the card lifts from.
 */
.standard-card,
.challenge-card,
.blog-card {
  transition:
    transform 5000ms cubic-bezier(0.05, 0.9, 0.1, 1),
    border-color 300ms ease,
    box-shadow 300ms ease,
    background-color 300ms ease;
}

/* Wrapper handles hover detection - stays in place while card floats */
.card-hover-wrapper {
  padding-bottom: 12px;  /* Extend hover zone below card */
  margin-bottom: -12px;  /* Compensate visually */
  height: 100%;          /* Fill grid cell for equal heights */
  display: flex;
  flex-direction: column;
}

/* Cards fill wrapper height for equal heights in grid */
.card-hover-wrapper > .standard-card,
.card-hover-wrapper > .challenge-card,
.card-hover-wrapper > .blog-card {
  flex: 1;
  display: flex;
  flex-direction: column;
}

/* Blog card inner content fills card height */
.blog-card > div {
  flex: 1;
  display: flex;
  flex-direction: column;
}

/* Push description to bottom of card */
.blog-card > div > p:last-child {
  margin-top: auto;
}

/* Card lifts when wrapper is hovered (not the card itself) */
.card-hover-wrapper:hover .standard-card,
.card-hover-wrapper:hover .challenge-card,
.card-hover-wrapper:hover .blog-card {
  transform: translateY(-6px);
}

/* ==========================================================================
   MISSION SECTION IMAGE - MOBILE SIZING
   ========================================================================== */

/**
 * On mobile (<640px), constrain the mission section cartoon image to be
 * small decorative adornment rather than viewport-dominating.
 * The image is low-res, so smaller size also improves visual quality.
 */
.mission-image-mobile {
  max-height: 220px;
  object-fit: contain;
}

@media (min-width: 640px) {
  .mission-image-mobile {
    max-height: none;
    object-fit: cover;
  }
}

/* ==========================================================================
   LIGHTBOX MODAL SCROLLBAR
   ========================================================================== */

/**
 * Always-visible scrollbar for lightbox modals.
 * Uses webkit scrollbar customization to ensure visibility and styling.
 *
 * Features:
 * - Always shows scrollbar track (even when not scrolling)
 * - Styled to match dark theme
 * - Subtle blue tint to match modal accent color
 */
.lightbox-scrollable {
  /* Force scrollbar to always be visible */
  scrollbar-gutter: stable;
}

/* Webkit browsers (Chrome, Safari, Edge) */
.lightbox-scrollable::-webkit-scrollbar {
  width: 8px;
}

.lightbox-scrollable::-webkit-scrollbar-track {
  background: rgba(255, 255, 255, 0.05);
  border-radius: 4px;
}

.lightbox-scrollable::-webkit-scrollbar-thumb {
  background: rgba(96, 165, 250, 0.4); /* blue-400 with opacity */
  border-radius: 4px;
}

.lightbox-scrollable::-webkit-scrollbar-thumb:hover {
  background: rgba(96, 165, 250, 0.6);
}

/* Firefox */
.lightbox-scrollable {
  scrollbar-width: thin;
  scrollbar-color: rgba(96, 165, 250, 0.4) rgba(255, 255, 255, 0.05);
}

/* ==========================================================================
   READING CONTAINER UTILITIES
   Blog/prose reading area with softer contrast in dark mode
   ========================================================================== */

/**
 * Reading Container
 *
 * Wraps blog post content for comfortable reading in dark mode.
 * In dark mode, applies softer charcoal (#18181b) instead of harsh near-black (#040c11).
 * Light mode has no visible container (content sits on page background).
 */
.reading-container {
  /* Light mode: no special styling, content sits on page background */
}

/* Dark mode: charcoal background with padding and rounded corners */
.dark .reading-container {
  background-color: var(--color-bg-reading);
  border-radius: 0.75rem; /* rounded-xl */
  padding: 2.5rem 2rem; /* pt-10 px-8 pb-8 */
  margin-left: -2rem;
  margin-right: -2rem;
}

/* Mobile: tighter padding */
@media (max-width: 768px) {
  .dark .reading-container {
    padding: 1.5rem 1.25rem;
    margin-left: -1rem;
    margin-right: -1rem;
  }
}

/* Body text size — bump up over prose-lg's 1.125rem (≈18px) for blog readability.
   Spacing/list margins use em units, so they scale proportionally with this. */
.reading-container .prose {
  font-size: 1.2rem; /* ≈ +1pt */
}

/* ==========================================================================
   BLOG POST HEADER - LIGHT MODE CONTRAST
   Increase contrast for metadata in light mode for better readability
   ========================================================================== */

/* Light mode: make date, author, and subtitle slightly more readable */
:root:not(.dark) .reading-container header .text-foreground-muted {
  color: rgb(100, 116, 139); /* slate-500: more contrast than default muted */
}

/* ==========================================================================
   BLOG POST NAVIGATION
   Back to Blog link styling with hover background
   ========================================================================== */

/* Back to Blog link: add padding for hover background.
   Exclude the fixed article TOC nav; it is also a direct child of <article>
   and needs to keep its own left-rail active treatment without rounded
   hover/focus artifacts. */
article > nav:not(.article-toc) a {
  padding: 0.375rem 0.75rem;
  margin-left: -0.75rem; /* Offset padding to maintain left alignment */
  border-radius: 0.375rem;
  transition: background-color 0.2s ease, color 0.2s ease;
}

/* Hover: solid background to indicate actionability */
article > nav:not(.article-toc) a:hover {
  background-color: var(--color-bg-tertiary);
}

/* ==========================================================================
   BLOG POST COMMENTS SECTION
   Surrounds the CommentBox.io widget on /blog/:slug pages.
   The widget itself owns its internal styles; we only style the surround.
   See: docs/agentic-knowledge/development/blog-comments.md
   ========================================================================== */

.comments-section {
  margin-top: 3rem; /* mt-12 — match existing post footer spacing */
  padding-top: 2rem; /* pt-8 — match existing post footer spacing */
  border-top: 1px solid var(--color-border-decorative);
}

.comments-section h2 {
  font-size: 1.5rem; /* text-2xl */
  font-weight: 700;
  color: var(--color-foreground-primary);
  margin-bottom: 1.5rem;
}

/* The mount node CommentBox attaches to. Give it a min-height to avoid
   layout shift between IntersectionObserver firing and widget render. */
.comments-section .commentbox {
  min-height: 200px;
}

/* Dark-mode framing for the CommentBox widget container.
 *
 * CommentBox's sign-in modal is rendered inside a cross-origin iframe
 * (commentbox.io/embed/…) that we cannot style from the parent page.
 * The modal background is hardcoded white inside CommentBox's infrastructure
 * and is not reachable via the three color init params (backgroundColor,
 * textColor, subtextColor).
 *
 * This rule adds a persistent dark-mode border around the .commentbox container
 * so the widget area (including the white modal when it opens) is visually
 * contained rather than floating as an unstyled white card against the dark
 * page background. The border is always-on in dark mode — pure CSS cannot
 * detect when the cross-origin iframe has opened its sign-in modal.
 *
 * Property choices:
 * - box-shadow (not outline): outline does not respect border-radius on
 *   Safari < 16.4 (March 2023), producing a rectangular outline around a
 *   rounded background. box-shadow follows border-radius universally and
 *   renders outside the box, so it is unaffected by overflow:hidden.
 * - overflow: hidden: border-radius alone does NOT clip child iframes —
 *   the CommentBox iframes would render with square corners poking past
 *   the rounded boundary. overflow:hidden clips children to the rounded
 *   shape. The widget's iframes are height-managed by CommentBox via
 *   postMessage, so vertical content is not at risk of being hidden.
 * - background-color: var(--color-bg-reading): matches the value
 *   themeColors() passes to the CommentBox iframe (--color-bg-reading,
 *   #18181b in dark mode). Using the same token ensures the container
 *   and widget are flush at the rounded edges instead of producing a
 *   lighter halo from --color-bg-reading-surface (#202024).
 *
 * pointer-events intentionally left at auto (the default) — we must NOT block
 * clicks on the widget or modal.
 *
 * Refs: docs/agentic-knowledge/development/blog-comments.md (Bug 1, #830).
 */
.dark .comments-section .commentbox {
  box-shadow: 0 0 0 1px var(--color-border);
  border-radius: 0.5rem; /* 8px — soften the container boundary */
  overflow: hidden; /* clip iframe corners to match border-radius */
  background-color: var(--color-bg-reading);
}

/* ==========================================================================
   BLOG INDEX CARDS
   Stretched link and light mode hover styles
   (Glow effects inherited from shared card system above)
   ========================================================================== */

/* Stretched link - makes entire card clickable */
.blog-card-link {
  text-decoration: none;
  color: inherit;
  transition: color 0.2s ease;
}

.blog-card-link::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 2;
}

.blog-card:hover .blog-card-link {
  color: var(--color-accent-primary);
}

/* Light mode: neutral hover background for better text contrast */
:root:not(.dark) .blog-card:hover {
  background-color: rgb(243, 244, 246); /* gray-100 - neutral, maintains text contrast */
}

/* ==========================================================================
   READING CONTAINER PROSE OVERRIDES
   Override prose element backgrounds to use charcoal variants in dark mode
   ========================================================================== */

/**
 * When prose elements (blockquotes, code, tables) are inside the reading container,
 * they should use charcoal-family backgrounds instead of the site's dark blue-black.
 * This maintains visual harmony with the softer reading background.
 */

/* Blockquotes: charcoal surface with subtle border */
.dark .reading-container .prose blockquote {
  background-color: var(--color-bg-reading-surface);
  border-left-color: var(--color-accent-primary);
  border: 0.5px solid var(--color-border-reading);
  border-left: 3px solid var(--color-accent-primary);
  border-radius: 0 0.375rem 0.375rem 0;
}

/* Code blocks (pre): elevated charcoal with thin border */
.dark .reading-container .prose pre {
  background-color: var(--color-bg-reading-elevated);
  border: 0.5px solid var(--color-border-reading);
  border-radius: 0.375rem;
}

/* Inline code: surface charcoal (only for code NOT inside pre blocks) */
.dark .reading-container .prose code {
  background-color: var(--color-bg-reading-surface);
}

/* Code inside pre blocks: no background (pre already has its own) */
.dark .reading-container .prose pre code {
  background-color: transparent;
}

/* Tables: charcoal variants with thin borders */
.dark .reading-container .prose th {
  background-color: var(--color-bg-reading-surface);
  border-color: var(--color-border-reading);
}

.dark .reading-container .prose td {
  border-color: var(--color-border-reading);
}

.dark .reading-container .prose tbody tr:nth-child(even) {
  background-color: var(--color-bg-reading-surface);
}

/* Table wrapper: add subtle outer border */
.dark .reading-container .prose table {
  border: 0.5px solid var(--color-border-reading);
  border-radius: 0.375rem;
  overflow: hidden;
}

/* ==========================================================================
   PROSE TYPOGRAPHY CUSTOMIZATION
   ========================================================================== */

/**
 * Custom styles for Tailwind's prose class to match theme colors.
 * Used for blog posts and content pages with markdown rendering.
 *
 * Color handling: Theme variables (--color-foreground-primary, etc.) automatically
 * switch for dark mode via themes.css. The `dark:prose-invert` class provides
 * fallback inversion for any prose defaults not overridden below.
 */

/* Map prose CSS variables to theme colors */
.prose {
  --tw-prose-body: var(--color-foreground-secondary);
  --tw-prose-headings: var(--color-foreground-primary);
  --tw-prose-links: var(--color-accent-primary);
  --tw-prose-bold: var(--color-foreground-primary);
  --tw-prose-code: var(--color-foreground-primary);
  --tw-prose-quotes: var(--color-foreground-muted);
  --tw-prose-quote-borders: var(--color-accent-primary);
  --tw-prose-counters: var(--color-foreground-muted);
  --tw-prose-bullets: var(--color-foreground-muted);
  --tw-prose-hr: var(--color-border);
  --tw-prose-th-borders: var(--color-border);
  --tw-prose-td-borders: var(--color-border-subtle);

  /* Serif typography for blog content (Substack/Medium aesthetic)
     Lora pairs well with geometric sans (Jost) for headings */
  font-family: var(--font-body-serif, var(--font-body));
  letter-spacing: -0.01em; /* Tighten slightly for serif */

  /* Substack/Medium-inspired line height for comfortable reading */
  line-height: 1.8;
}

/* ==========================================================================
   HEADING HIERARCHY
   Distinct sizes and spacing for clear visual hierarchy (Substack/Medium style)
   ========================================================================== */

/* Shared heading styles - tighter tracking improves display at large sizes */
.prose h1,
.prose h2,
.prose h3,
.prose h4 {
  font-family: var(--font-sans);
  letter-spacing: -0.02em;
  color: var(--tw-prose-headings);
}

.prose h1 {
  font-size: 2.5rem;
  font-weight: 700;
  line-height: 1.2;
  margin-top: 1.6em;
  margin-bottom: 0.75em;
}

.prose h2 {
  font-size: 1.875rem;
  font-weight: 600;
  line-height: 1.3;
  margin-top: 1.3em;
  margin-bottom: 0.5em;
}

.prose h3 {
  font-size: 1.5rem;
  font-weight: 600;
  line-height: 1.4;
  margin-top: 1.1em;
  margin-bottom: 0.5em;
}

.prose h4 {
  font-size: 1.25rem;
  font-weight: 500;
  line-height: 1.4;
  margin-top: 1em;
  margin-bottom: 0.5em;
}

/* First heading in content - no top margin needed */
.prose > h1:first-child,
.prose > h2:first-child,
.prose > h3:first-child,
.prose > h4:first-child {
  margin-top: 0;
}

/* ==========================================================================
   PARAGRAPH SPACING
   Generous vertical rhythm for readability
   ========================================================================== */

.prose p {
  margin-bottom: 1.75em;
}

/* First paragraph after heading - tighter coupling */
.prose h1 + p,
.prose h2 + p,
.prose h3 + p,
.prose h4 + p {
  margin-top: 0;
}

/* ==========================================================================
   LIST STYLING
   Proper indentation and vertical rhythm

   NOTE: Tailwind's preflight CSS removes default list-style markers.
   We must explicitly restore them for .prose content.
   ========================================================================== */

.prose ul,
.prose ol {
  padding-left: 1.5em;
  margin-bottom: 1.75em;
}

/* Restore list markers (removed by Tailwind preflight) */
.prose ul,
.prose ol {
  list-style-position: outside;
}

.prose ul { list-style-type: disc; }
.prose ol { list-style-type: decimal; }

/* Nested list variations for visual hierarchy */
.prose ul ul { list-style-type: circle; }
.prose ul ul ul { list-style-type: square; }

/* Marker color using theme-aware CSS variable (muted, not bold black) */
.prose ul li::marker,
.prose ol li::marker {
  color: var(--tw-prose-bullets);
}

.prose li {
  margin-bottom: 0.75em;
}

.prose li:last-child {
  margin-bottom: 0;
}

/* Task list checkbox styling */
.prose .task-list-item {
  list-style: none;
  position: relative;
  padding-left: 1rem; /* Space between checkbox and text */
}

.prose .task-list-checkbox {
  appearance: none;
  -webkit-appearance: none;
  width: 1.125rem;
  height: 1.125rem;
  border: 2px solid var(--color-foreground-muted);
  border-radius: 0.25rem;
  /* Position checkbox aligned with bullets, with gap before text */
  position: absolute;
  left: -0.75rem;
  top: 0.35rem;
  cursor: default;
}

.prose .task-list-checkbox:checked {
  background-color: var(--color-accent-primary);
  border-color: var(--color-accent-primary);
}

.prose .task-list-checkbox:checked::after {
  content: "";
  position: absolute;
  left: 0.3rem;
  top: 0.1rem;
  width: 0.35rem;
  height: 0.6rem;
  border: solid white;
  border-width: 0 2px 2px 0;
  transform: rotate(45deg);
}

/* ==========================================================================
   EMPHASIS STYLING
   Strong text stands out clearly
   ========================================================================== */

.prose strong {
  font-weight: 700;
  color: var(--tw-prose-bold);
}

/* Link styling with hover state — dotted underline in accent color, same in both states */
.prose a {
  text-decoration: underline dotted;
  text-decoration-thickness: 1px;
  text-decoration-color: var(--color-accent-hover);
  text-underline-offset: 4px;
  transition: color 0.2s ease, text-decoration-color 0.2s ease;
}

.prose a:hover {
  color: var(--color-accent-hover);
  text-decoration-color: var(--color-accent-hover);
}

/* Styled text blocks - for conversation snippets, advice, sidebars, etc.
   Uses body serif font (not monospace) since content is narrative, not code */
.prose pre {
  background-color: var(--color-bg-tertiary);
  border: 1px solid var(--color-border-subtle);
  border-radius: 0.5rem;
  overflow-x: auto;
  padding: 1.25rem 1.5rem;
  font-family: var(--font-body-serif, var(--font-body));
  font-size: 1rem;
  line-height: 1.75;
  white-space: pre-wrap; /* Wrap long lines naturally */
  margin-bottom: 1.5rem; /* Breathing room below code blocks */
}

.prose code {
  background-color: var(--color-bg-secondary);
  padding: 0.125rem 0.375rem;
  border-radius: 0.25rem;
  font-size: 0.875em;
}

/* Text inside styled blocks - inherits the body font styling */
.prose pre code {
  background-color: transparent;
  padding: 0;
  border-radius: 0;
  font-family: inherit;
  font-size: inherit;
}

/* Actual code blocks (with language specified) - use monospace font
   Redcarpet adds a class to code element when language is specified:
   ```bash => <pre><code class="bash">...</code></pre> */
.prose pre code[class] {
  font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;
  font-size: 0.9rem;
  line-height: 1.6;
}

/* Table styling */
.prose table {
  border-collapse: collapse;
  width: 100%;
}

.prose th,
.prose td {
  border: 1px solid var(--color-border-subtle);
  padding: 0.5rem 1rem;
}

.prose th {
  background-color: var(--color-bg-secondary);
  font-weight: 600;
}

/* Alternate row colors for readability */
.prose tbody tr:nth-child(even) {
  background-color: var(--color-bg-secondary);
}

/* Blockquote accent styling */
.prose blockquote {
  border-left-color: var(--color-accent-primary);
  background-color: var(--color-bg-secondary);
  padding: 1rem 1.5rem;
  border-radius: 0 0.5rem 0.5rem 0;
  font-style: normal;
}

.prose blockquote p {
  margin: 0;
}

/* Footnotes styling */
.prose .footnotes {
  margin-top: 2rem;
  padding-top: 1rem;
  border-top: 1px solid rgba(128, 128, 128, 0.2); /* Subtle separator */
  font-size: 0.875rem;
}

/* Hide auto-generated hr inside/before footnotes (Redcarpet adds one) */
.prose .footnotes > hr,
.prose > hr:has(+ .footnotes) {
  display: none;
}

.prose .footnotes ol {
  padding-left: 1.5rem;
}

/* Footnote reference styling (inline superscript link)
 * Redcarpet outputs: <sup id="fnref1"><a href="#fn1">1</a></sup>
 * Styled as pill badge instead of underlined link
 */
.prose sup[id^="fnref"] a {
  font-size: 0.7rem;
  font-weight: 600;
  color: var(--color-foreground-primary);
  background-color: var(--color-bg-tertiary);
  padding: 0.1rem 0.28rem;
  border-radius: 0.25rem;
  text-decoration: none;
  transition: background-color 0.2s ease, color 0.2s ease;
}

.prose sup[id^="fnref"] a:hover {
  background-color: var(--color-accent-primary);
  color: var(--color-bg-primary);
}

/* Dark mode footnote reference */
.dark .prose sup[id^="fnref"] a {
  background-color: var(--color-bg-reading-surface);
  color: var(--color-foreground-reading);
}

.dark .prose sup[id^="fnref"] a:hover {
  background-color: var(--color-accent-primary);
  color: var(--color-bg-primary);
}

/* Footnote backref styling (return arrows in footnotes section)
 * Redcarpet outputs: <a href="#fnref1">&#8617;</a>
 */
.prose .footnotes a[href^="#fnref"] {
  color: var(--color-accent-primary);
  text-decoration: none;
}

/* Horizontal rule styling */
.prose hr {
  border-color: var(--color-border);
  margin: 2rem 0;
}

/* Balance spacing when heading follows hr - reduce heading's top margin */
.prose hr + h1,
.prose hr + h2,
.prose hr + h3,
.prose hr + h4 {
  margin-top: 1.5rem; /* Match hr's bottom margin for visual balance */
}

/* Image styling — used by Tier 2 native Markdown images (![alt](path)) and
   Tier 3 raw-HTML <figure class="figure-*"> blocks. See
   docs/agentic-knowledge/development/blog-prose-blocks-system.md */
.prose img {
  display: block;
  max-width: 100%;
  height: auto;
  border-radius: 1rem;
  margin: 2rem auto;
}

/* Dark-mode prose images: subtle border to prevent harsh edges against
   reading-surface background */
.dark .reading-container .prose img {
  border: 1px solid var(--color-border-decorative);
}

/* Nested lists - tighter spacing to avoid excessive vertical rhythm */
.prose li ul,
.prose li ol {
  margin-top: 0.5em;
  margin-bottom: 0.5em;
}

/* ==========================================================================
   DARK MODE READING OPTIMIZATION
   Softer contrast for extended reading sessions
   Uses charcoal (#18181b) instead of near-black, off-white (#E8E8E8) instead of pure white
   Contrast ratio: ~14.5:1 (exceeds WCAG AAA 7:1 requirement)
   ========================================================================== */

.dark .prose {
  --tw-prose-body: var(--color-foreground-reading);
  --tw-prose-headings: #F5F5F5;
  --tw-prose-bold: #F5F5F5;
  --tw-prose-quotes: var(--color-foreground-muted);
  --tw-prose-code: var(--color-foreground-reading);
}

/* ==========================================================================
   FIGCAPTION STYLING
   Muted caption text beneath images for editorial aesthetic.
   Used by Tier 3 raw-HTML <figure class="figure-*"> blocks and the
   .video-embed pattern.
   ========================================================================== */

.prose figcaption {
  font-size: 0.875rem;
  color: var(--color-foreground-muted);
  text-align: center;
  margin-top: 0.5rem;
  line-height: 1.5;
  text-wrap: pretty; /* prevent single-word orphan lines; graceful fallback to normal wrap */
}

/* Float-variant captions: half-column-width sits better left-aligned,
   using text-wrap: pretty for natural orphan elimination at any length.
   Mirrors the [data-reflow] pattern documented above. */
.prose figure.figure-float-left figcaption,
.prose figure.figure-float-right figcaption {
  text-align: left;
  text-wrap: pretty;
}

.prose figure {
  margin: 2rem auto;
}

.prose figure img,
.prose figure .video-embed {
  margin: 0; /* Remove all margins - figure handles spacing */
}

/* ==========================================================================
   FIGURE LAYOUT CLASSES (Tier 3)
   Five layout variants for raw-HTML <figure class="figure-*"> blocks.
   Mobile always stacks; floats activate at md: (768px) and up.
   Bleed and wide variants break beyond the prose column at md: and up.
   See docs/agentic-knowledge/development/blog-prose-blocks-system.md
   ========================================================================== */

/* Default content-column figure — matches plain <figure> behavior */
.prose figure.figure-full {
  margin: 2rem auto;
  max-width: 100%;
}

/* Wide: breaks slightly outside the prose column on md+ */
@media (min-width: 768px) {
  .prose figure.figure-wide {
    margin-left: -2rem;
    margin-right: -2rem;
    max-width: calc(100% + 4rem);
  }
}

/* Bleed: edge-to-edge full-viewport-width on md+ */
@media (min-width: 768px) {
  .prose figure.figure-bleed {
    width: 100vw;
    max-width: 100vw;
    margin-left: calc(50% - 50vw);
    margin-right: calc(50% - 50vw);
    border-radius: 0; /* edge-to-edge looks better without rounded corners */
  }

  .prose figure.figure-bleed img {
    border-radius: 0;
  }
}

/* Float right: image right, prose flows left on md+ */
.prose figure.figure-float-right {
  margin: 1rem 0;
}

@media (min-width: 768px) {
  .prose figure.figure-float-right {
    float: right;
    width: 41.67%; /* matches md:w-5/12 */
    margin: 0 0 1rem 1.5rem;
  }
}

/* Float left: image left, prose flows right on md+ */
.prose figure.figure-float-left {
  margin: 1rem 0;
}

@media (min-width: 768px) {
  .prose figure.figure-float-left {
    float: left;
    width: 41.67%;
    margin: 0 1.5rem 1rem 0;
  }
}

/* Prevent floats from bleeding into subsequent block elements.
   Each major block element clears any pending float before laying out.
   .callout and .pullquote are added so they clear floats from preceding
   figure-float-left / figure-float-right elements. */
.prose h1,
.prose h2,
.prose h3,
.prose h4,
.prose hr,
.prose blockquote,
.prose pre,
.prose table,
.prose p.callout,
.prose blockquote.pullquote {
  clear: both;
}

/* ==========================================================================
   CALLOUT AND PULLQUOTE BLOCKS
   Print/magazine-style typographic emphasis blocks rendered by
   FigureRedcarpetParser from ::: callout and ::: pullquote fenced markup.
   See docs/agentic-knowledge/development/blog-prose-blocks-system.md
   for the authoring API and rendering specs.

   READER-MODE FOOLPROOFING:
   - The em-dash glyph (&mdash;) is in the HTML, NOT added by CSS,
     because reader-mode parsers (Readwise Reader, Safari Reader,
     Firefox Reader) strip CSS classes and ::before content.
   - The pullquote uses <blockquote>+<cite> rather than <figure>+<figcaption>
     because Readability.js strips <figure> wrappers and orphans attribution.
   See docs/solutions/integration-issues/readwise-reader-mode-compatibility.md.
   ========================================================================== */

/* ----- Callout (thesis-emphasis, no attribution) ----- */
.prose p.callout {
  font-size: 1.5rem;
  font-weight: 500;
  line-height: 1.5;
  margin: 2rem auto;
  padding: 1.5rem 0;
  border-top: 1px solid var(--color-border-reading);
  border-bottom: 1px solid var(--color-border-reading);
  text-wrap: pretty;
  /* Body font inherited from .prose; callout stays in the reading voice,
     unlike pullquote which inherits the global blockquote --font-quote. */
}

/* ----- Pullquote (attributed quote) - LIGHT MODE + UNIVERSAL ------------
   Explicit resets against the existing .prose blockquote rule (~line 1525)
   which sets: border-left-color, background-color, padding, border-radius,
   font-style. We zero out the bare-blockquote treatment so the pullquote
   gets the rule-pair (top/bottom border) editorial treatment instead.
   The font-family inherits from fonts.css's `blockquote { font-family:
   var(--font-quote); }` and is intentionally NOT overridden — pullquote
   IS a quote and earns the display serif in branded-font mode. */
.prose blockquote.pullquote {
  /* Resets against .prose blockquote (line 1525) */
  border-left: 0;
  background-color: transparent;
  border-radius: 0;
  padding: 1.5rem 0;
  font-style: normal;
  /* Our editorial treatment */
  border-top: 1px solid var(--color-border-reading);
  border-bottom: 1px solid var(--color-border-reading);
  margin: 2rem auto;
  font-size: 1.5rem;
  font-weight: 500;
  line-height: 1.5;
  text-wrap: pretty;
}

/* Body paragraph inside pullquote — kill the outer blockquote's child
   margin so the rule pair owns the vertical spacing. */
.prose blockquote.pullquote > p {
  margin: 0;
  font-style: normal;
}

/* Attribution line */
.prose blockquote.pullquote .pullquote-attribution {
  font-size: 0.9375rem;
  font-weight: 400;
  line-height: 1.5;
  color: var(--color-foreground-muted);
  margin: 0.75rem 0 0;
  font-style: normal;
  /* Counter the .prose blockquote.pullquote font-size + font-weight so the
     attribution does not inherit the larger / heavier quote-body type. */
}

.prose blockquote.pullquote .pullquote-attribution cite {
  font-style: normal;
}

/* ----- Pullquote - DARK MODE
   Specificity 0,5,1 to win over the existing 0,4,1 rule at line 1204
   (.dark .reading-container .prose blockquote) which sets background,
   border, and border-radius. The `border: 0` shorthand resets all four
   sides (including border-left) — we then redeclare the editorial
   top/bottom rules below. */
.dark .reading-container .prose blockquote.pullquote {
  /* Resets against .dark .reading-container .prose blockquote (line 1204) */
  background-color: transparent;
  border: 0;
  border-radius: 0;
  /* Our editorial treatment */
  border-top: 1px solid var(--color-border-reading);
  border-bottom: 1px solid var(--color-border-reading);
}

/* Dark-mode-only cool tint on callout/pullquote body text.
   On the dark reading surface, size + weight alone do not give enough
   visual separation from surrounding prose. A 35% blend toward
   --color-accent-primary (the pastel cyan also used by the active TOC
   link) shifts the text to a cool off-white that stands out without
   sacrificing readability — still ~13:1 contrast against #18181b.
   The blend sits on the blockquote (not the inner <p>) so the
   attribution's --color-foreground-muted rule continues to override. */
.dark .reading-container .prose p.callout,
.dark .reading-container .prose blockquote.pullquote {
  color: color-mix(in srgb, var(--color-foreground-reading) 65%, var(--color-accent-primary) 35%);
}

/* ==========================================================================
   VIDEO EMBED STYLING
   Responsive 16:9 container for YouTube/Vimeo embeds
   ========================================================================== */

.prose .video-embed {
  position: relative;
  width: 100%;
  padding-bottom: 56.25%; /* 16:9 aspect ratio */
  margin: 2rem 0;
  border-radius: 0.5rem;
  overflow: hidden;
  background-color: var(--color-bg-tertiary);
}

.prose .video-embed iframe {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  border: none;
}

/* ==========================================================================
   LIGHT MODE FORM INPUT STYLING
   Newsletter email input needs softer colors in light mode.
   Dark mode zinc-800/zinc-950 are preserved via Tailwind classes.
   ========================================================================== */

/* Light mode: soft gray background instead of dark zinc */
:root:not(.dark) #newsletter input[type="email"] {
  background-color: #f9fafb; /* gray-50 - soft, neutral */
  border-color: #d1d5db; /* gray-300 - visible but subtle border */
}

/* Light mode focus: very light blue background to indicate selection */
:root:not(.dark) #newsletter input[type="email"]:focus {
  background-color: #eff6ff; /* blue-50 - light brand blue tint */
  border-color: transparent;
}

/* ==========================================================================
   LIGHT MODE HEADER BORDER
   The dark border (#1e2a36) is too prominent in light mode.
   Use a softer gray that matches the scrolled state.
   ========================================================================== */

:root:not(.dark) header[data-controller="header"] {
  border-color: #e5e7eb; /* gray-200 - subtle in light mode */
}

/* ==========================================================================
   CALENDLY POPUP WIDGET
   Ensure Calendly overlay renders above all site content including
   the fixed header (z-50 = 50) and any GSAP-animated elements.
   Lock body scroll while popup is open to prevent scroll passthrough.
   ========================================================================== */

.calendly-overlay {
  z-index: 9999 !important;
}

/* Make the popup use more viewport space so Calendly's stacked layout
   (description on top, calendar below) fits without internal scrolling.
   Defaults: max-height 700px, max-width 1000px, width 80%, min-width 900px. */
.calendly-popup {
  max-height: 85vh !important;
  max-width: 1060px !important;
  width: 90% !important;
  min-width: 0 !important;
}

/* Hide the outer loading spinner injected by widget.js into our DOM.
   The Calendly iframe renders its own internal spinner, so the outer
   one is redundant and creates a distracting duplicate animation. */
.calendly-spinner {
  display: none !important;
}

/* ==========================================================================
   HOW IT WORKS — ILLUSTRATION EDGE BLENDING
   Soft-edge effect via border-radius + overflow:hidden on the <picture> wrapper.
   Replaced mask-image radial-gradient + transform:scale(1.08) which created a
   promoted compositing layer PER illustration (10+ layers across both audience
   panels), each requiring runtime mask evaluation on every scroll frame — the
   primary cause of Chrome scroll jank (#289). border-radius is GPU-native.
   ========================================================================== */
picture:has(.how-it-works-illustration) {
  background: color-mix(in srgb, var(--color-bg-primary) 88%, transparent);
  overflow: hidden;
  border-radius: 1.25rem;
}

/* Mobile trail dashed pattern (shared by ghost + animated segments) */
.mobile-trail-dash {
  background: repeating-linear-gradient(to bottom,
    var(--color-accent-primary) 0px, var(--color-accent-primary) 8px,
    transparent 8px, transparent 14px);
}

/* will-change: clip-path removed — persistent GPU layers for all 6 segments even when
   off-screen created unnecessary compositor overhead on Safari. The browser auto-promotes
   layers during active clip-path animation; static hints are not needed here. */

/* ==========================================================================
   GUARANTEE SECTION — TYPOGRAPHIC ANCHOR
   Hero-scale "100%" gradient text with separator, pull-quote, and trust pills.
   ========================================================================== */

.guarantee-big-number {
  font-family: 'Jost', system-ui, sans-serif;
  font-size: clamp(6rem, 16vw, 10rem);
  font-weight: 800;
  margin: 0;
  letter-spacing: -0.25rem;
  line-height: 0.9;
  display: block;
  background: linear-gradient(180deg, var(--color-guarantee-from) 0%, var(--color-guarantee-via) 60%, var(--color-guarantee-to) 100%);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
}

.guarantee-subtitle {
  font-family: 'Jost', system-ui, sans-serif;
  display: block;
  font-size: clamp(1.125rem, 3vw, 1.625rem);
  font-weight: 500;
  letter-spacing: 0.375rem;
  text-transform: uppercase;
  color: color-mix(in srgb, var(--color-foreground-primary) 50%, transparent);
  -webkit-text-fill-color: color-mix(in srgb, var(--color-foreground-primary) 50%, transparent);
  background: none;
  margin-top: 0.25rem;
}

@media (max-width: 639px) {
  .guarantee-subtitle {
    letter-spacing: 0.2rem;
  }
}

/* Radial glow — ambient depth behind heading block */
.guarantee-glow {
  pointer-events: none;
  position: absolute;
  inset: -4rem;
}

.guarantee-glow-b2b {
  background: radial-gradient(ellipse 80% 70% at 50% 45%, color-mix(in srgb, var(--color-accent-primary) 18%, transparent) 0%, transparent 70%);
}

.dark .guarantee-glow-b2b {
  background: radial-gradient(ellipse 80% 70% at 50% 45%, color-mix(in srgb, var(--color-accent-primary) 14%, transparent) 0%, transparent 70%);
}

.guarantee-glow-individual {
  background: radial-gradient(ellipse 80% 70% at 50% 45%, color-mix(in srgb, var(--color-accent-primary) 18%, transparent) 0%, transparent 70%);
}

.dark .guarantee-glow-individual {
  background: radial-gradient(ellipse 80% 70% at 50% 45%, color-mix(in srgb, var(--color-accent-primary) 8%, transparent) 0%, transparent 70%);
}

/* Gradient rule lines — subtle section boundaries */
.guarantee-rule-top,
.guarantee-rule-bottom {
  position: absolute;
  left: 10%;
  right: 10%;
  height: 1px;
  background: linear-gradient(to right, transparent, color-mix(in srgb, var(--color-accent-primary) 25%, transparent), transparent);
}

.guarantee-rule-top { top: 0; }
.guarantee-rule-bottom { bottom: 0; }

/* B2B pyramid heading — forced line breaks create wide→medium→narrow funnel shape */
.guarantee-pyramid-heading-wrap {
  position: relative;
  display: inline-block;
  width: 100%;
}

.guarantee-pyramid-heading {
  font-family: 'Jost', system-ui, sans-serif;
  font-size: clamp(1.75rem, 4.5vw, 2.75rem);
  font-weight: 700;
  line-height: 1.2;
  margin: 0;
  color: var(--color-foreground-primary);
  position: relative;
  z-index: 1;
}

/* "100%" tip of the pyramid — gradient accent, subordinate scale */
.guarantee-trailing-number {
  display: block;
  font-family: 'Jost', system-ui, sans-serif;
  font-size: clamp(1.5rem, 4vw, 2.75rem);
  font-weight: 800;
  letter-spacing: -0.03em;
  line-height: 1;
  margin-top: 0.5rem;
  background: linear-gradient(180deg, var(--color-guarantee-from) 0%, var(--color-guarantee-via) 60%, var(--color-guarantee-to) 100%);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
  position: relative;
  z-index: 1;
}

/* Pull-quote — Cormorant Garamond italic closer */
.guarantee-pull-quote {
  font-family: 'Cormorant Garamond', Georgia, serif;
  font-style: italic;
  font-size: clamp(1.5rem, 3vw, 1.875rem);
  color: color-mix(in srgb, var(--color-foreground-primary) 60%, transparent);
  line-height: 1.5;
  margin: 2rem auto 0;
  max-width: 32.5rem;
  position: relative;
  padding: 0 1.5rem;
}

.guarantee-pull-quote::before {
  content: '\201C';
  position: absolute;
  left: 0;
  top: -1rem;
  font-size: 4.5rem;
  color: color-mix(in srgb, var(--color-accent-primary) 25%, transparent);
  line-height: 1;
  font-family: Georgia, serif;
}

/* Trust pills — scannable summary strip
   Breaks out of parent max-w-2xl via negative margin + padding to use
   the full section width, so pills stay on one row at desktop. */
.guarantee-trust-strip {
  display: flex;
  flex-wrap: nowrap;
  justify-content: center;
  gap: 1.5rem;
  margin-top: 2.5rem;
  margin-left: -2rem;
  margin-right: -2rem;
  padding: 2rem 2rem 0;
  border-top: 1px solid color-mix(in srgb, var(--color-foreground-primary) 6%, transparent);
}

@media (max-width: 639px) {
  .guarantee-trust-strip {
    flex-direction: column;
    align-items: center;
    gap: 0.5rem;
  }
}

.guarantee-trust-pill {
  display: inline-flex;
  align-items: center;
  gap: 0.4375rem;
  white-space: nowrap;
  background: color-mix(in srgb, var(--color-accent-primary) 5%, transparent);
  border: 1px solid color-mix(in srgb, var(--color-accent-primary) 12%, transparent);
  border-radius: 100px;
  padding: 0.375rem 1rem;
  font-size: 0.8125rem;
  font-weight: 500;
  color: var(--color-foreground-secondary);
}

.guarantee-trust-pill::before {
  content: '\2713';
  color: var(--color-success);
  font-size: 0.875rem;
  font-weight: 700;
}

/* Bold section overrides — white-tinted pill borders on dark backgrounds */
.section-bold .guarantee-trust-pill {
  background: rgba(255, 255, 255, 0.05);
  border-color: rgba(255, 255, 255, 0.15);
  color: var(--color-foreground-secondary-on-bold);
}

.dark .section-bold .guarantee-trust-pill {
  background: color-mix(in srgb, var(--color-accent-primary) 5%, transparent);
  border-color: color-mix(in srgb, var(--color-accent-primary) 12%, transparent);
  color: var(--color-foreground-secondary);
}

/* Bold section — guarantee trust strip border override */
.section-bold .guarantee-trust-strip {
  border-top-color: rgba(255, 255, 255, 0.1);
}

.dark .section-bold .guarantee-trust-strip {
  border-top-color: color-mix(in srgb, var(--color-foreground-primary) 6%, transparent);
}

/* Bold section — guarantee pull-quote color override */
.section-bold .guarantee-pull-quote {
  color: color-mix(in srgb, var(--color-foreground-on-bold) 60%, transparent);
}

.dark .section-bold .guarantee-pull-quote {
  color: color-mix(in srgb, var(--color-foreground-primary) 60%, transparent);
}

/* Bold section — guarantee pull-quote curly-quote color */
.section-bold .guarantee-pull-quote::before {
  color: rgba(255, 255, 255, 0.25);
}

.dark .section-bold .guarantee-pull-quote::before {
  color: color-mix(in srgb, var(--color-accent-primary) 25%, transparent);
}

/* Bold section — guarantee rule lines hidden in light mode */
.section-bold .guarantee-rule-top,
.section-bold .guarantee-rule-bottom {
  display: none;
}

.dark .section-bold .guarantee-rule-top,
.dark .section-bold .guarantee-rule-bottom {
  display: block;
}

/* Bold section — separator line override */
.section-bold .guarantee-separator-line {
  background: linear-gradient(to right, transparent, rgba(255, 255, 255, 0.2), transparent) !important;
}

.dark .section-bold .guarantee-separator-line {
  background: linear-gradient(to right, transparent, color-mix(in srgb, var(--color-accent-primary) 20%, transparent), transparent) !important;
}

/* Bold section — separator shield border */
.section-bold .guarantee-separator-shield {
  border-color: rgba(255, 255, 255, 0.25) !important;
}

.dark .section-bold .guarantee-separator-shield {
  border-color: color-mix(in srgb, var(--color-accent-primary) 25%, transparent) !important;
}

/* Anchor card icon circle — light blue border on dark card bg in light mode.
   In dark mode, revert to the audience-appropriate accent color passed via
   --icon-border-color custom property on the element. */
.anchor-icon-border {
  border-color: #d4e8f0 !important;
}

.dark .anchor-icon-border {
  border-color: var(--icon-border-color) !important;
}

/* ==========================================================================
   BRANDED FONT OVERRIDES
   Adjustments when branded fonts (Jost) are active via site.yml fonts: "branded".
   Jost is the primary heading font everywhere; Montserrat is retained on
   three high-impact display surfaces only (hero, blog post show H1, blog
   index card titles). Section H2s on home/programs/contact pages render
   in the default --font-heading (Instrument Sans in hybrid mode) — this
   matches the production state and was the user's final choice after
   testing Montserrat at multiple weights and finding it didn't suit.
   ========================================================================== */

.hybrid-fonts .hero-headline {
  font-family: 'Montserrat', system-ui, -apple-system, sans-serif;
  font-weight: 800;
}

/* .post-title applies only to the blog show-page H1
   (app/views/content/posts/show.html.erb). The /blog index H1 has no
   override class — it renders in the default heading register. */
.hybrid-fonts .post-title {
  font-family: 'Montserrat', system-ui, -apple-system, sans-serif;
  font-weight: 800;
  letter-spacing: -0.02em;
  line-height: 1.2;
}

.hybrid-fonts .blog-card h2 {
  font-family: 'Montserrat', system-ui, -apple-system, sans-serif;
  font-weight: 700;
}

/* ==========================================================================
   BLOG TAG CHIPS
   Display-only tag styling — span, no hover state, no cursor change.
   ========================================================================== */

.blog-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 0.375rem;
  padding: 0;
  /* Bottom margin separates chips from the next element (e.g., H1 on
     show page). A utility class like Tailwind's mb-4 cannot win against
     this rule — components layer beats utilities layer in v4. */
  margin: 0.75rem 0 1rem;
  list-style: none;
}

.blog-tag {
  display: inline-block;
  padding: 0.125rem 0.625rem;
  font-size: 0.75rem;
  font-weight: 500;
  color: var(--color-foreground-muted);
  background: var(--color-bg-tertiary);
  border: 1px solid var(--color-border-decorative);
  border-radius: 9999px;
  white-space: nowrap;
}

