/* ==========================================================================
   Financial Wellbeing — Brand Kit tokens + fonts
   Colors and fonts are locked to the Network FP Brand Kit ONLY — see
   financial-health-check-design-plan.md §6.1. No values outside this set.
   ========================================================================== */

@font-face {
  font-family: "Lato";
  src: url("../assets/fonts/lato-regular.ttf") format("truetype");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Lato";
  src: url("../assets/fonts/lato-medium.ttf") format("truetype");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "The Youngest Serif";
  src: url("../assets/fonts/the-youngest-serif-book.ttf") format("truetype");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "The Youngest Serif";
  src: url("../assets/fonts/the-youngest-serif-bold.ttf") format("truetype");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}
:root {
  /* Brand Kit raw tokens — do not add colors outside this set */
  --brand-orange: #ff5000; /* NFP Orange — primary accent */
  --brand-dark: #333333; /* NFP Dark — body text on white, never pure black */
  --brand-white: #ffffff;
  --brand-slate: #6a7d8b; /* captions, footnotes, secondary labels */
  --brand-cream: #efe7dc; /* testimonial/section backgrounds, cell fills only */
  --brand-mint: #d7e7df; /* small accent blocks only, never a full background */
  --brand-gray: #b0b0b0; /* never a full background, low-contrast use only */
  --brand-border: rgba(176, 176, 176, 0.4);

  /* Semantic status color, not a Brand Kit accent — already used ad hoc for
     "success"/"strong" states (newsletter signup confirmation, results insight
     cards) before this was pulled into one named token. */
  --status-strong: #2e7d4f;

  --font-body: "Lato", Arial, Helvetica, sans-serif;
  --font-heading: "The Youngest Serif", Georgia, serif;

  --max-width: 1280px;
  --radius: 10px;
  --radius-lg: 24px;
}

/* ==========================================================================
   Reset / base
   ========================================================================== */
*,
*::before,
*::after {
  box-sizing: border-box;
}
/* The browser's own [hidden] { display: none } lives in the UA stylesheet, which
   loses to ANY author rule that also sets `display` on the same element once that
   rule has equal-or-higher specificity — e.g. `.btn { display: inline-flex }` on a
   button that also has the `hidden` attribute. Found this the hard way on the PFP
   portal's sign-out button (visibly showing while "signed out"). Global, !important
   fix so no individual component has to special-case it — a component-specific
   override (like .matches-section[hidden] elsewhere in this file) is a workaround
   for this same bug, not a different bug each time it appears. */
[hidden] {
  display: none !important;
}
html {
  scroll-behavior: smooth;
}
body {
  margin: 0;
  font-family: var(--font-body);
  color: var(--brand-dark);
  background: var(--brand-white);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  /* Site-wide safety net (2026-09-19) — there was no guard anywhere against
     a stray wide/off-position element creating real horizontal scroll (the
     .match-list fix above addresses one confirmed cause of content reading
     as "cut off/overlapping" on mobile; this catches any other one, known
     or not, without needing to hunt down each individually). Doesn't affect
     position:sticky/fixed elements, which are positioned against the
     viewport regardless of this. */
  overflow-x: hidden;
}
img {
  max-width: 100%;
  display: block;
}
a {
  color: inherit;
  text-decoration: none;
}
.container {
  max-width: var(--max-width);
  margin: 0 auto;
  padding: 0 1.5rem;
}
h1,
h2,
h3 {
  font-family: var(--font-heading);
  font-weight: 700;
  margin: 0;
  line-height: 1.1;
  /* Orphan control — a lone short word stranded on its own last line reads as
     unfinished on a display serif. text-wrap:balance is ignored silently by
     browsers that don't support it yet, so this is a free upgrade with no
     fallback needed. */
  text-wrap: balance;
}
p {
  margin: 0;
  /* Same orphan-control idea as headings above, tuned for running body copy
     instead of short headlines (balance evens every line; pretty only fixes
     the last one, which is what a paragraph needs). Also silently ignored
     where unsupported. */
  text-wrap: pretty;
}
button {
  font-family: inherit;
  cursor: pointer;
}

/* Focus visibility — accessibility baseline, design plan §6.4 */
a:focus-visible,
button:focus-visible {
  outline: 3px solid var(--brand-orange);
  outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }
  * {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
}

/* Anchor-jump targets (nav links like #how-it-works, #faq, #for-families)
   land flush under the sticky .site-header without this — the header covers
   the first ~1-2 lines of whatever heading was just jumped to. Generic rule
   on any section with an id, rather than hand-listing each anchor target. */
section[id] {
  scroll-margin-top: 5.5rem;
}

/* ==========================================================================
   Scroll reveal — a small, one-time fade + 8px rise as section headings and
   cards enter the viewport (Jakub Krehel's "materializing" enter recipe,
   minus the blur — blur on body-copy-sized text just reads as a rendering
   glitch, not polish). Driven by IntersectionObserver in js/main.js, which
   adds .is-visible once an element crosses the viewport and never removes it
   — a one-time entrance, not a parallax/scroll-tied effect (avoids the
   vestibular-trigger territory the accessibility guidance warns about).

   Gated behind the .js class (set synchronously by main.js before this
   stylesheet's rules can apply) so a page with JS disabled or still loading
   never ships content at opacity:0 with nothing to reveal it — the .reveal
   class alone, without .js on <html>, does nothing and content stays
   visible by default. Progressive enhancement, not a dependency.

   Motion is fully neutralized by the prefers-reduced-motion block above
   (transition-duration: 0.01ms !important on *) rather than a second,
   duplicate query here — reduced-motion users still get .is-visible added
   on scroll, it just applies instantly instead of transitioning. */
/* Scoped to .is-home (set only on index.html's <html> tag) — per instruction
   (2026-09-10), every other page shows .reveal/.fade-up-in content immediately
   at full opacity with no entrance animation at all, homepage keeps it. */
.js.is-home .reveal {
  opacity: 0;
  transform: translateY(28px);
  transition: opacity 420ms ease, transform 420ms ease;
}
.js.is-home .reveal.is-visible {
  opacity: 1;
  transform: translateY(0);
}
/* Staggered entry for a row of siblings (card grids, FAQ list, journey
   stages) — cascades in instead of all mounting at once. Capped at 6 steps;
   grids wider than that repeat the last delay rather than growing unbounded. */
.js.is-home .reveal-group > .reveal:nth-child(1) { transition-delay: 0ms; }
.js.is-home .reveal-group > .reveal:nth-child(2) { transition-delay: 70ms; }
.js.is-home .reveal-group > .reveal:nth-child(3) { transition-delay: 140ms; }
.js.is-home .reveal-group > .reveal:nth-child(4) { transition-delay: 210ms; }
.js.is-home .reveal-group > .reveal:nth-child(5) { transition-delay: 280ms; }
.js.is-home .reveal-group > .reveal:nth-child(n+6) { transition-delay: 350ms; }

/* Named beats for a *choreographed* one-time sequence — used where the
   grouping isn't "every sibling, evenly spaced, on scroll" (that's
   .reveal-group above) but a deliberate on-load story: some elements land
   together on purpose, others wait their turn. Pairs with .fade-up-in
   (plays once, unconditionally, the moment the element is painted) rather
   than .reveal — .reveal is scroll-position-driven (an IntersectionObserver
   toggling visibility as elements cross the viewport edge), which is the
   wrong tool for "this plays once when the page loads": an element sitting
   near the fold would flicker in/out as that scroll boundary is crossed
   during normal scrolling, instead of just playing its entrance once and
   being done. Declares both delay properties so the same class works
   whichever animation type an element actually uses.
   Currently used by the hero (see index.html): beat 1 eyebrow+headline+
   photo, beat 2 subtext, beat 3 CTA+skip-line. (The advisor trust line
   below the hero deliberately isn't on this timeline at all — see its own
   comment in index.html for why.) Gaps widen toward the end — a slight
   deceleration reads more natural than perfectly even spacing. Slower and
   more deliberate than .fade-up-in's own default 420ms/instant-delay (that
   default is tuned for its OTHER uses — results.js match cards, the
   program video overlay — which shouldn't get slower just because the
   hero should), so the hero's own animation-duration is overridden
   separately below too. */
/* Compound (two-class) selectors, not bare .reveal-beat-N — needed because
   .fade-up-in (defined further down this file) sets the `animation`
   SHORTHAND, which implicitly resets animation-delay to 0 for every
   sub-property it doesn't mention. A bare single-class .reveal-beat-N rule
   has the same specificity as .fade-up-in, so which one wins depends on
   source order — .fade-up-in comes later in this file, so it was silently
   winning and wiping out every beat's delay, which is why the whole
   sequence appeared to land all at once regardless of these values. A
   compound selector (two classes) has higher specificity than either alone,
   so it reliably wins no matter where either rule sits in the file. If a
   future element needs a beat delay on plain .reveal instead of
   .fade-up-in, add a matching .reveal-beat-N.reveal rule rather than
   reintroducing the bare (unreliable) version. */
.is-home .reveal-beat-1.fade-up-in { animation-delay: 0ms; animation-duration: 800ms; }
.is-home .reveal-beat-2.fade-up-in { animation-delay: 600ms; animation-duration: 800ms; }
.is-home .reveal-beat-3.fade-up-in { animation-delay: 1400ms; animation-duration: 800ms; }

/* ==========================================================================
   Buttons
   ========================================================================== */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  padding: 0.85rem 1.75rem;
  border-radius: 999px;
  font-family: var(--font-body);
  font-weight: 700;
  font-size: 0.95rem;
  border: none;
  transition: background-color 200ms ease, transform 150ms ease, box-shadow 200ms ease;
  min-height: 44px; /* touch target baseline */
}
/* Press feedback — a subtle scale(0.97) on :active reads as a physical
   click, not just a color swap. Skipped for :disabled so a greyed-out
   button doesn't also feel clickable. */
.btn:active:not(:disabled) {
  transform: scale(0.97);
}
/* Global disabled dimming (2026-09-15) — this used to exist only scoped to
   .flow-nav, so every OTHER disabled .btn on the site (e.g. booking.html's
   guest-form "Confirm Booking", which stays disabled until a time-preference
   chip is picked) had zero visual difference from enabled: explicit
   background-color on .btn-primary/.btn-ghost fully overrides the browser's
   own default disabled dimming. Reported as "nothing happens when I click
   Confirm Booking" — the button was correctly disabled the whole time, it
   just looked identical to ready. */
.btn:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}
.btn-primary {
  background: var(--brand-orange);
  color: var(--brand-white);
  /* Tinted, not pure black — carries the brand hue so the shadow reads as
     part of this button, not a generic drop-shadow bolted on. */
  box-shadow: 0 1px 2px rgba(255, 80, 0, 0.15);
}
.btn-primary:hover {
  background: #e64800;
  box-shadow: 0 6px 16px rgba(255, 80, 0, 0.28);
}
.btn-ghost {
  background: transparent;
  color: var(--brand-dark);
  font-weight: 500;
}
.btn-ghost:hover {
  background: var(--brand-cream);
}
/* Compact sizing for header buttons specifically — the default .btn padding is
   tuned for hero/standalone CTAs, not a button sharing a row with the logo and
   nav links at header scale. */
.btn--header {
  padding: 0.6rem 1.3rem;
  font-size: 0.85rem;
  min-height: 38px;
}

/* ==========================================================================
   Header
   ========================================================================== */
.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  background: rgba(255, 255, 255, 0.95);
  backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--brand-border);
}
.site-header .container {
  position: relative; /* anchors the mobile nav dropdown */
}
.site-header__row {
  /* Was a fixed height:4rem — switched to auto (via padding) so the bar always
     fits whatever the logo's current size is instead of needing a hand-tuned
     height every time the logo changes. */
  padding: 0.75rem 0;
  display: flex;
  align-items: center;
  /* Matches .main-nav's own gap (2026-09-19) — this is what actually spaces
     the last nav pill from the "Get Free 1:1 Consultation" button (the
     logo/nav pairing is spaced by margin-left:auto instead, not this), so
     it needs the same value for all 4 buttons to read as one evenly-spaced
     row rather than the CTA looking like its own separate group. */
  gap: 0.75rem;
}
.logo {
  display: inline-flex;
  align-items: center;
  gap: 0.65rem;
}
.logo img {
  height: 50px;
  width: auto;
}
.site-header__actions {
  display: flex;
  align-items: center;
  gap: 1rem;
  /* Pins this to the row's right edge below 768px, where .main-nav is
     display:none and can't carry its own margin-left:auto for that job (see
     that rule's comment) — this is the only remaining flex child after the
     logo there, so it needs the auto margin itself. Handed off to .main-nav
     instead at 768px+ (reset to 0 below) once .main-nav is actually in the
     layout and sits before this. */
  margin-left: auto;
}
/* Persistent, always-visible "Start Health Check" button to the right of the
   nav — networkfp.com's own header layout (logo / nav / right-aligned button),
   reproduced structurally, not its content. Hidden below 768px: with the logo,
   nav, and a full-size button there's no room left for the hamburger toggle on
   real phone widths (same 320px-wide constraint the mobile CTA placement below
   already accounts for) — reachable instead via .main-nav__mobile-actions
   inside the dropdown. */
.header-actions-buttons {
  display: none;
  align-items: center;
  gap: 0.6rem;
}

.mobile-nav-toggle {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border: 1px solid var(--brand-border);
  border-radius: var(--radius);
  background: var(--brand-white);
  color: var(--brand-dark);
  cursor: pointer;
}
.mobile-nav-toggle:hover {
  border-color: var(--brand-orange);
  color: var(--brand-orange);
}

/* Below 768px (exactly where .main-nav becomes a hamburger dropdown instead of an
   inline row — see the min-width:768px block below): logo + toggle + the header
   buttons don't reliably fit together on real phone widths as the logo has grown,
   verified via headless-browser layout + font-metrics measurement against the
   narrowest width this site is checked against (320px). The buttons live inside
   .main-nav__mobile-actions instead of the persistent actions row specifically so
   they stop competing with the logo for space here — reachable via the hamburger
   on mobile, same as "How it works"/"FAQ", plus the hero below has its own
   prominent CTA regardless. That leaves only the logo + toggle to fit in this
   row, so this cap can stay put even as the desktop size above changes. */
@media (max-width: 767px) {
  .logo img {
    height: 40px;
  }
}

/* Mobile: nav is a dropdown panel, toggled via .is-open (JS-controlled) rather than
   just being unreachable — this used to be `display: none` below 768px with no way
   to open it at all. */
.main-nav {
  display: none;
  flex-direction: column;
  gap: 0.25rem;
  position: absolute;
  top: calc(100% + 1px);
  left: 0;
  right: 0;
  background: var(--brand-white);
  border-bottom: 1px solid var(--brand-border);
  box-shadow: 0 12px 24px rgba(0, 0, 0, 0.08);
  padding: 0.75rem 1.5rem 1.25rem;
}
.main-nav.is-open {
  display: flex;
}
.main-nav a:not(.btn) {
  padding: 0.6rem 0;
  font-size: 0.95rem;
  font-weight: 500;
  color: rgba(51, 51, 51, 0.8);
  transition: color 150ms ease;
}
.main-nav a:not(.btn):hover {
  color: var(--brand-orange);
}
/* Marks the current page's nav link (e.g. "FW Checkup" on results.html) —
   orange text everywhere (mobile dropdown); the desktop treatment below
   replaces the old underline with a filled pill instead, to match the
   button look every nav link gets there now. */
.main-nav a.is-active:not(.btn) {
  color: var(--brand-orange);
  font-weight: 700;
}
@media (min-width: 768px) {
  /* Every nav link reads as its own button now (2026-09-19, explicit
     instruction), not plain text — a light outline/ghost pill, not the
     CTA's solid orange, so "Get Free 1:1 Consultation" still stands out as
     the one filled action among a row of otherwise-equal buttons. */
  .main-nav a:not(.btn) {
    padding: 0.55rem 1.1rem;
    border-radius: 999px;
    border: 1.5px solid var(--brand-border);
    color: var(--brand-dark);
    font-weight: 600;
    transition: border-color 150ms ease, color 150ms ease, background-color 150ms ease;
  }
  .main-nav a:not(.btn):hover {
    border-color: var(--brand-orange);
    color: var(--brand-orange);
    background: rgba(255, 80, 0, 0.04);
  }
  .main-nav a.is-active:not(.btn) {
    border-color: var(--brand-orange);
    background: rgba(255, 80, 0, 0.06);
  }
}
/* Mobile-only duplicate of .header-actions-buttons, inside the dropdown — see the
   comment on .header-actions-buttons above for why these live in two places. */
.main-nav__mobile-actions {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  margin-top: 0.75rem;
  padding-top: 0.75rem;
  border-top: 1px solid var(--brand-border);
}
.main-nav__mobile-actions .btn {
  width: 100%;
}

@media (min-width: 768px) {
  .mobile-nav-toggle {
    display: none;
  }
  .header-actions-buttons {
    display: flex;
  }
  .main-nav {
    display: flex;
    flex-direction: row;
    align-items: center;
    position: static;
    /* Matches .site-header__row's own gap (2026-09-19) — now that every nav
       link is a pill button same as the CTA, the gap between nav items and
       the gap between the last nav item and that CTA need to match too, or
       the CTA reads as its own separate group instead of the 4th button in
       one evenly-spaced row. */
    gap: 0.75rem;
    border: none;
    box-shadow: none;
    padding: 0;
    background: transparent;
    /* Was .site-header__row's own justify-content:space-between doing this
       spacing — with exactly 3 children (logo/nav/actions) that put the nav
       links at the ROW'S OWN visual center, floating apart from the "Get
       Free 1:1 Consultation" button at the far right (reported: "the 2
       [groups] are in the middle right, I need all of them at the right
       side"). margin-left:auto here instead pins the logo left and pushes
       the nav+actions block together as one unit flush against the right
       edge, with .site-header__actions right after it needing no margin of
       its own (it just follows immediately, same row). */
    margin-left: auto;
  }
  /* .main-nav (above) takes over the auto margin at this width — reset here
     so both don't carry one at once, which would split the free space
     between the two and reopen the exact gap this is fixing. */
  .site-header__actions {
    margin-left: 0;
  }
  /* .main-nav a:not(.btn) no longer resets padding to 0 here — it's a pill
     button now (see the earlier @media(min-width:768px) block), which
     needs its own padding to look like one; this rule used to blow that
     away since it comes later in source order at equal specificity. */
  .main-nav__mobile-actions {
    display: none;
  }
}

/* ==========================================================================
   Hero
   ========================================================================== */
.hero {
  position: relative;
  overflow: hidden;
  /* Plain white here (matching .site-header above and .advisors-section--top
     below) - the actual cream/artwork background lives on .hero-bg, a
     separate layer behind the content (see below), so it can fade to
     transparent at the top/bottom edges and reveal this white instead of
     cutting off hard against the sections next to it. */
  background: var(--brand-white);
}
/* Plain cream layer only (2026-09-11: the dotted/orange-blob artwork image was
   removed per instruction — "just keep the clean cream" background) - kept as
   its own element rather than folding straight into .hero so the fade-to-
   transparent top/bottom mask (revealing .hero's white, avoiding a hard seam
   against the white header/advisors-strip) still only affects this decorative
   layer, not the actual headline/video content near those edges. */
.hero-bg {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background-color: var(--brand-cream);
  -webkit-mask-image: linear-gradient(
    to bottom,
    transparent 0,
    black 72px,
    black calc(100% - 96px),
    transparent 100%
  );
  mask-image: linear-gradient(
    to bottom,
    transparent 0,
    black 72px,
    black calc(100% - 96px),
    transparent 100%
  );
}
/* Decorative layer — soft blobs + a hairline curved stroke + two small dot-grid
   patches, all CSS/SVG (no image asset), sitting between .hero-bg and the real
   content. Brand-orange only, low opacity, generously spaced so it reads as
   quiet texture rather than another thing competing for attention. Hidden
   below 1024px (see the media query further down) — on narrow viewports the
   same shapes read as clutter rather than atmosphere. */
.hero-decor {
  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
}
.hero-decor__blob {
  position: absolute;
  border-radius: 50%;
  background: var(--brand-orange);
}
.hero-decor__blob--a {
  top: -4rem;
  left: 38%;
  width: 22rem;
  height: 22rem;
  opacity: 0.07;
}
.hero-decor__blob--b {
  bottom: -8rem;
  left: -6rem;
  width: 18rem;
  height: 18rem;
  background: var(--brand-cream);
  opacity: 0.9;
}
.hero-decor__blob--c {
  bottom: -10rem;
  right: -8rem;
  width: 24rem;
  height: 24rem;
  opacity: 0.1;
}
.hero-decor__dots {
  position: absolute;
  background-image: radial-gradient(var(--brand-orange) 1.5px, transparent 1.5px);
  background-size: 14px 14px;
  opacity: 0.3;
}
.hero-decor__dots--a {
  top: 6.5rem;
  right: 3rem;
  width: 5.5rem;
  height: 5.5rem;
}
.hero-decor__dots--b {
  bottom: 3rem;
  right: 9rem;
  width: 4rem;
  height: 4rem;
}
.hero-decor__line {
  position: absolute;
  top: 2rem;
  left: 0;
  width: 60%;
  height: auto;
  opacity: 0.15;
}
@media (max-width: 1023px) {
  .hero-decor {
    display: none;
  }
}

.hero-grid {
  position: relative;
  z-index: 1;
  display: grid;
  gap: 3rem;
  padding-top: 2.5rem;
  padding-bottom: 2.5rem;
  /* Top-aligned, not centered — with .hero-media taller than .hero-copy,
     center alignment was pulling the copy column down to split the
     difference instead of both columns starting level with each other. */
  align-items: start;
}
@media (min-width: 1024px) {
  .hero-grid {
    grid-template-columns: 1.05fr 0.95fr;
    gap: 4.5rem;
    padding-top: 3rem;
    padding-bottom: 3rem;
  }
}

/* "Step N" badges (2026-09-11) — sit above the eyebrow on the three main
   homepage flow sections (FW Program, FW Checkup, Free 1:1 Consultation) so the
   page reads as a numbered sequence instead of three unrelated pitches. */
.step-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.35rem 1rem 0.35rem 0.35rem;
  border-radius: 999px;
  background: rgba(255, 80, 0, 0.08);
  margin-bottom: 0.5rem;
}
.step-badge__number {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 1.5rem;
  height: 1.5rem;
  border-radius: 50%;
  background: var(--brand-orange);
  color: var(--brand-white);
  font-size: 0.75rem;
  font-weight: 700;
  flex-shrink: 0;
}
/* Same treatment as .script-word (the highlighted half of the h2 headings, e.g.
   "Actually Means") — italic heading serif in brand orange, per instruction, rather
   than a small uppercase sans label. */
.step-badge__label {
  font-family: var(--font-heading);
  font-style: italic;
  font-weight: 400;
  font-size: 1.05rem;
  color: var(--brand-orange);
}

.eyebrow {
  font-family: var(--font-body);
  font-size: 0.85rem;
  font-weight: 700;
  letter-spacing: 0.15em;
  color: var(--brand-orange);
  margin: 0 0 1rem;
}

.explainer-section {
  padding: 2.5rem 0;
}
.explainer-text {
  max-width: 46rem;
  font-size: 1.05rem;
  line-height: 1.7;
  color: var(--brand-slate);
}
.program-video-section {
  padding: 1rem 0 3rem;
}
.program-video-frame {
  max-width: 50rem;
  margin: 0 auto;
  aspect-ratio: 16 / 9;
  max-height: none;
}
.program-video-frame .video-frame__video {
  object-fit: contain;
  background: var(--brand-dark);
}
.program-video-note {
  max-width: 50rem;
  margin: 1rem auto 0;
  font-size: 0.9rem;
  color: var(--brand-slate);
  text-align: center;
}

/* Back-to-calculators link — top-left of each standalone calculator page
   (wealth-staircase, retirement-calculator, life-goals-matrix, real-statement).
   These pages sit under .site-header but had no way back to the tools.html
   hub other than the browser's own back button. Kept plain (no button chrome)
   since it's a wayfinding link, not an action. */
.tool-back-link {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  font-family: var(--font-body);
  font-size: 0.85rem;
  font-weight: 700;
  color: var(--brand-slate);
  text-decoration: none;
  margin-bottom: 1rem;
  transition: color 150ms ease, transform 150ms ease;
}
.tool-back-link:hover {
  color: var(--brand-orange);
  transform: translateX(-2px);
}
.tool-back-link svg {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
}
/* "Welcome, you were referred by X" — js/referral-banner.js, only ever shown
   when a ?ref=<code> link resolved to a real name. A real popup (2026-09-18,
   replacing an earlier thin inline banner that read as too easy to miss) —
   same fixed, full-viewport, dimmed-backdrop shape as .program-gate-modal so
   it feels like the rest of the site's popup family, shown once per tab
   (sessionStorage) the moment referral-lookup resolves a name. */
.referral-welcome-modal {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1.5rem;
  background: rgba(30, 26, 20, 0.55);
  backdrop-filter: blur(2px);
}
.referral-welcome-modal__panel {
  position: relative;
  max-width: 28rem;
  width: 100%;
  padding: 2.25rem;
  border-radius: var(--radius-lg);
  background: var(--brand-white);
  text-align: center;
  box-shadow: 0 24px 48px rgba(0, 0, 0, 0.25);
}
.referral-welcome-modal__close {
  position: absolute;
  top: 1rem;
  right: 1rem;
}
.referral-welcome-modal__badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 3rem;
  height: 3rem;
  border-radius: 50%;
  background: rgba(255, 80, 0, 0.1);
  font-size: 1.5rem;
}
.referral-welcome-modal__panel h3 {
  margin-top: 1rem;
  font-size: 1.3rem;
}
.referral-welcome-modal__panel > p {
  margin-top: 0.6rem;
  font-size: 0.95rem;
  line-height: 1.55;
  color: var(--brand-slate);
}
.referral-welcome-modal__points {
  margin: 1.25rem 0 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  text-align: left;
}
.referral-welcome-modal__points li {
  display: flex;
  align-items: flex-start;
  gap: 0.6rem;
  font-size: 0.88rem;
  line-height: 1.5;
  color: var(--brand-dark);
}
.referral-welcome-modal__num {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.5rem;
  height: 1.5rem;
  border-radius: 50%;
  background: var(--brand-orange);
  color: #fff;
  font-size: 0.78rem;
  font-weight: 700;
}
.referral-welcome-modal__actions {
  margin-top: 1.5rem;
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
}
.hero-heading {
  font-size: 2.5rem;
  line-height: 1.12;
}
/* "Family" — plain (not italic) heading serif in brand orange, with a small
   hand-drawn-style curved stroke riding just under the baseline. Distinct
   from .script-line/.script-word (those are italic accents used elsewhere on
   the page) — this one is a color emphasis on a word inside a running line,
   so it stays upright to read as part of the same headline, not a different
   voice. */
.hero-heading__accent {
  position: relative;
  display: inline-block;
  color: var(--brand-orange);
}
.hero-heading__stroke {
  position: absolute;
  left: 0;
  bottom: -0.22em;
  width: 100%;
  height: 0.22em;
  color: var(--brand-orange);
}
@media (min-width: 640px) {
  .hero-heading {
    font-size: 3.25rem;
  }
}
@media (min-width: 1200px) {
  .hero-heading {
    font-size: 3.75rem;
  }
}
.hero-tagline {
  margin-top: 1.25rem;
  font-size: 1.15rem;
  font-weight: 600;
  color: var(--brand-dark);
}
.hero-sub {
  max-width: 32rem;
  margin-top: 0.75rem;
  font-size: 1.1rem;
  line-height: 1.5;
  color: var(--brand-dark);
}
.hero-stat {
  display: inline-block;
  margin-top: 1.1rem;
  padding: 0.5rem 1rem;
  border-radius: 1.25rem;
  background: rgba(255, 80, 0, 0.08);
  font-size: 1rem;
  color: var(--brand-dark);
}
.hero-stat strong {
  font-family: var(--font-heading);
  font-size: 1.25rem;
  color: var(--brand-orange);
}
.hero-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1rem;
  margin-top: 1.75rem;
}
.btn--hero {
  padding: 1rem 2rem;
  font-size: 1rem;
}
.btn--hero svg {
  transition: transform 200ms ease;
}
.btn--hero:hover svg {
  transform: translateX(3px);
}
/* Three compact trust/value points below the CTA — a small icon chip (same
   rgba(255,80,0,.08) tint .step-badge already uses elsewhere) plus a short
   label. Row on desktop with hairline dividers, stacked on mobile. */
.hero-trust {
  display: flex;
  flex-direction: column;
  gap: 1.1rem;
  margin: 2.25rem 0 0;
  padding: 0;
  list-style: none;
}
.hero-trust li {
  display: flex;
  align-items: center;
  gap: 0.65rem;
}
.hero-trust__icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 2.5rem;
  height: 2.5rem;
  flex-shrink: 0;
  border-radius: 50%;
  background: rgba(255, 80, 0, 0.08);
  color: var(--brand-orange);
}
.hero-trust span:last-child {
  font-size: 0.9rem;
  font-weight: 600;
  color: var(--brand-dark);
  line-height: 1.25;
}
@media (min-width: 640px) {
  .hero-trust {
    flex-direction: row;
    align-items: flex-start;
    gap: 1.75rem;
  }
  .hero-trust li:not(:last-child) {
    padding-right: 1.75rem;
    border-right: 1px solid var(--brand-border);
  }
}
/* Hero video frame — Mindly-style bordered device frame */
.hero-media {
  position: relative;
  width: 100%; /* required: without an explicit width, `margin: 0 auto` on a grid
    item makes it shrink-to-fit its content instead of stretching to the column —
    and since .video-frame's width is a percentage (no intrinsic size), that
    collapses the whole box to ~0px. Explicit 100% avoids the shrink-to-fit path. */
  max-width: 26rem;
  margin: 0 auto;
}
@media (min-width: 1024px) {
  .hero-media {
    /* Capped well short of the column width so it still reads as a card,
       not a full-bleed panel. */
    max-width: 28rem;
    margin-left: auto;
  }
}
.video-frame {
  position: relative;
  aspect-ratio: 4 / 5;
  width: 100%;
  /* Was 24rem, then 28rem — extended further to land closer to the bottom
     of the "I am visiting as a" cards beside it. */
  max-height: min(31rem, 58vh);
  overflow: hidden;
  border-radius: var(--radius-lg);
  border: 1px solid var(--brand-border);
  background: linear-gradient(to bottom right, var(--brand-dark), var(--brand-dark) 60%, #4a3a2e);
  box-shadow: 0 20px 40px rgba(0, 0, 0, 0.15);
}
@media (min-width: 640px) {
  .video-frame {
    aspect-ratio: 3 / 4;
  }
}
/* Hero-specific sizing only — same card, same JS/interaction, just given more
   vertical room now that the hero has the space (the strip that used to cap
   how tall this could go is gone). */
.video-frame--hero {
  aspect-ratio: 1 / 1;
  max-height: min(34rem, 62vh);
}
@media (min-width: 640px) {
  .video-frame--hero {
    aspect-ratio: 4 / 5;
  }
}
.video-frame__video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
/* Real poster image (2026-09-11, e.g. FW Program's Sadique Neelgund thumbnail) —
   sits behind .video-frame__placeholder, filling the frame exactly like a real
   <video>'s poster attribute would. Frames with no thumbnail just show the
   existing dark gradient background instead (this element simply isn't present). */
.video-frame__thumbnail {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
/* FW Program entry transition panel (js/main.js's setupProgramEntryTransition) —
   a plain solid-color div, NOT a clone of the thumbnail image (an earlier
   version scaled the actual image up and it read as stretched/ugly) —
   positioned/sized via inline styles to start exactly where the thumbnail
   sits, then grown via transform only (never width/height/top/left, which
   would thrash layout) to cover the viewport before navigating to
   program.html. White matches --brand-white (every page's own background
   here), so program.html's own arrival fade starts from this same white and
   the two page loads read as one continuous transition, not two unrelated
   flashes. */
.program-entry-transition-panel {
  position: fixed;
  top: 0;
  left: 0;
  margin: 0;
  z-index: 10000;
  background: var(--brand-white);
  pointer-events: none;
  transform-origin: top left;
  transition: transform 550ms cubic-bezier(0.22, 1, 0.36, 1), border-radius 550ms ease;
}
@media (prefers-reduced-motion: reduce) {
  .program-entry-transition-panel {
    transition: none;
  }
}
.video-frame__placeholder {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1rem;
  padding: 2rem;
  text-align: center;
  cursor: pointer;
  transition: opacity 300ms ease;
  /* Darkens a thumbnail photo just enough to keep the white play-button/caption
     readable — harmless no-op tint over frames that only have the dark gradient. */
  background: rgba(0, 0, 0, 0.3);
}
/* js/main.js's activateVideoFrame — fades the placeholder out once a real
   <video> underneath it starts playing, instead of it staying on top forever. */
.video-frame__placeholder.is-fading-out {
  opacity: 0;
  pointer-events: none;
}
/* Pre-launch stand-in for "the video just started" on a frame that has no real
   <video> yet — a brief scale pulse so clicking the placeholder still feels like
   it did something, not a dead button. */
.video-frame--pulse {
  animation: video-frame-pulse 550ms ease;
}
@keyframes video-frame-pulse {
  0%, 100% { transform: scale(1); }
  50% { transform: scale(1.015); }
}
.play-button {
  width: 4rem;
  height: 4rem;
  border-radius: 999px;
  border: 2px solid rgba(255, 255, 255, 0.7);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--brand-white);
  transition: transform 200ms ease, background-color 200ms ease;
}
.video-frame__placeholder:hover .play-button {
  background: rgba(255, 255, 255, 0.15);
  transform: scale(1.06);
}
.video-frame__placeholder p {
  max-width: 220px;
  font-size: 0.875rem;
  color: rgba(255, 255, 255, 0.7);
}
/* Generic image placeholder (2026-09-11) — lighter, neutral variant of
   .video-frame__placeholder for sections waiting on a real photo/illustration
   rather than a video. Reused by the FW Checkup and combined Consultation/What-
   to-Expect sections. */
.image-placeholder {
  position: relative;
  /* 16/9, matching .video-frame--wide's proportions (2026-09-11) — the earlier
     4/3 + 14rem min-height made this box noticeably taller than Step 1's video
     frame, which was most of why the combined Step 3 section ran so much
     longer/scrollier than the other two Step sections. */
  aspect-ratio: 16 / 9;
  width: 100%;
  border-radius: var(--radius-lg);
  overflow: hidden;
  background: var(--brand-cream);
}
.image-placeholder img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
/* Generic two-column split (2026-09-11) — content one side, media the other.
   Reused by the FW Checkup and combined Consultation/What-to-Expect sections,
   same breakpoint/proportions as .program-section__grid. */
.split-content-grid {
  display: grid;
  gap: 2.5rem;
  align-items: center;
  margin-top: 2rem;
}
@media (min-width: 900px) {
  .split-content-grid {
    grid-template-columns: 1.1fr 0.9fr;
  }
}
/* Left column reuses .section-heading for its type styles (eyebrow/h2 sizing) but
   needs left-aligned, uncapped text here instead of that class's default centered
   block — the centering only makes sense for a full-width heading above content,
   not a column sitting next to an image. */
.split-content-grid .section-heading {
  text-align: left;
  max-width: none;
  margin: 0;
}
/* ==========================================================================
   Section heading — reused site-wide (homepage sections, results pages, etc.)
   ========================================================================== */
.section-heading {
  max-width: 40rem;
  margin: 0 auto;
  text-align: center;
}
.section-heading h2 {
  font-size: 2.25rem;
  margin-top: 1rem;
}
.section-heading h2 .script-word {
  font-family: var(--font-heading);
  font-style: italic;
  font-weight: 400;
  color: var(--brand-orange);
}
@media (min-width: 640px) {
  .section-heading h2 {
    font-size: 2.75rem;
  }
}

/* Section banding — from here through .faq, each homepage section gets a
   hairline top border and alternates between the plain white body
   background and a light cream tint (same rgba(239,231,220,*) tone
   .trust-strip/.insight-card already use elsewhere on this page). Before
   this, every section here had only vertical padding and no visual
   boundary of its own, so the page read as one continuous scroll rather
   than a set of distinct sections. .insight-section is the one exception
   left white out of the alternating pattern — its .insight-card is already
   cream-tinted, and a cream section band behind it would make that card
   blend into its surroundings instead of standing out. */

/* ==========================================================================
   The Behavior Gap — single-insight card, home page only. Mirrors the
   category-bar-row pattern from results.js so bar styling stays consistent
   site-wide rather than inventing a second visual language for one section.
   ========================================================================== */
.insight-section {
  padding: 5rem 0;
  border-top: 1px solid var(--brand-border);
}
.insight-card {
  display: grid;
  gap: 2.5rem;
  padding: 2.25rem;
  border: 1px solid rgba(176, 176, 176, 0.25);
  border-radius: var(--radius-lg);
  background: rgba(239, 231, 220, 0.35);
}
@media (min-width: 800px) {
  .insight-card {
    grid-template-columns: 1.1fr 1fr;
    gap: 3.5rem;
    padding: 3rem;
    align-items: center;
  }
}
.insight-copy h2 {
  font-size: 2rem;
}
.insight-lead {
  margin-top: 1rem;
  font-size: 1.05rem;
  line-height: 1.6;
  color: var(--brand-dark);
}
.insight-note {
  margin-top: 1rem;
  font-size: 0.85rem;
  line-height: 1.6;
  color: var(--brand-slate);
}
.insight-visual {
  padding: 1.75rem;
  background: var(--brand-white);
  border: 1px solid rgba(176, 176, 176, 0.2);
  border-radius: var(--radius);
}
.insight-visual-label {
  margin: 0 0 1.25rem;
  font-size: 0.8rem;
  font-weight: 500;
  color: var(--brand-slate);
}
.insight-bar-row + .insight-bar-row {
  margin-top: 1.25rem;
}
.insight-bar-head {
  display: flex;
  justify-content: space-between;
  font-size: 0.9rem;
  font-weight: 500;
  margin-bottom: 0.4rem;
}
.insight-bar-track {
  height: 10px;
  border-radius: 999px;
  background: var(--brand-cream);
  overflow: hidden;
}
.insight-bar-fill {
  height: 100%;
  border-radius: 999px;
  background: var(--brand-gray);
}
.insight-bar-fill--strong {
  background: var(--brand-orange);
}
.insight-gap-callout {
  display: inline-flex;
  align-items: center;
  margin: 0.75rem 0;
  padding: 0.35rem 0.75rem;
  background: rgba(255, 80, 0, 0.08);
  border: 1px dashed rgba(255, 80, 0, 0.35);
  border-radius: 999px;
  font-size: 0.75rem;
  font-weight: 700;
  color: var(--brand-orange);
}
.insight-source {
  margin: 1.25rem 0 0;
  font-size: 0.75rem;
  color: var(--brand-slate);
}

/* ==========================================================================
   Real Advisors — a continuous, self-looping strip of real PFP headshots
   (js/main.js fetches them from the pfp-showcase Edge Function). Full-bleed on
   purpose: the marquee track sits outside .container so it can scroll edge to
   edge, while the heading above it stays contained to the normal reading width.

   The track renders the PFP list TWICE back to back and animates translateX
   from 0 to exactly -50% — since both halves are identical, the loop point is
   invisible and the strip reads as continuous rather than restarting. Paused
   on hover (skimming names shouldn't fight a moving target) and disabled
   entirely under prefers-reduced-motion. Stays [hidden] until js/main.js has
   fetched at least a handful of real photos to show — an empty or sparse
   strip would look broken rather than just quietly not rendering.
   ========================================================================== */
.advisors-section {
  padding: 3.5rem 0 5.5rem;
  border-top: 1px solid var(--brand-border);
}
/* Below-the-hero placement — compact on purpose. A single trust-line caption
   sits ABOVE the marquee (short, not a full heading, so it doesn't compete
   with the hero for space) introducing the strip, rather than below it —
   see the .advisors-trust-line comment for why. Drops the section's usual
   top border too, since it sits directly under the hero rather than
   between two content sections. */
.advisors-section--top {
  padding: 1.5rem 0 2rem;
  border-top: none;
}
.advisors-section--top .advisors-marquee {
  margin-top: 0.6rem;
}
.advisors-marquee {
  margin-top: 3rem;
  overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg, transparent, black 6%, black 94%, transparent);
  mask-image: linear-gradient(90deg, transparent, black 6%, black 94%, transparent);
}
/* Above the marquee, not below — introduces the strip instead of
   summarizing it after the fact. Kept short on purpose: this is a caption,
   not competing with the hero's own headline for attention. */
.advisors-trust-line {
  margin: 0;
  text-align: center;
  font-size: 0.875rem;
  color: var(--brand-slate);
}
.advisors-track {
  display: flex;
  align-items: flex-start;
  gap: 2.25rem;
  width: max-content;
  padding: 0.35rem 0;
  animation: advisors-scroll 100s linear infinite;
}
.advisors-marquee:hover .advisors-track {
  animation-play-state: paused;
}
.advisor-avatar {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.4rem;
  /* min-width, not width — a fixed width forced longer names ("Anil Kumar
     Batchu") to wrap to two lines while shorter ones sat in a mostly-empty
     box. min-width keeps the photo centered in a sensible column for short
     names, while .advisor-avatar__name's white-space:nowrap (below) lets a
     longer name grow the column exactly as wide as it needs, instead of
     wrapping. */
  width: auto;
  min-width: 7.25rem;
  padding: 0 0.25rem;
  flex-shrink: 0;
}
.advisor-avatar img {
  width: 5.5rem;
  height: 5.5rem;
  border-radius: 50%;
  object-fit: cover;
  border: 1.5px solid var(--brand-cream);
}
/* Slightly smaller in the compact above-the-fold placement — this variant is
   meant to fit in the first viewport alongside the hero, not claim as much
   vertical space as a full mid-page section would. */
.advisors-section--top .advisor-avatar {
  min-width: 8rem;
}
.advisors-section--top .advisor-avatar img {
  width: 5rem;
  height: 5rem;
}
.advisors-section--top .advisors-track {
  gap: 1.75rem;
}
/* Three-color rotation, not a full rainbow — enough variety to echo the
   reference design's per-avatar ring color without turning the strip into
   circus confetti. All three are already-locked Brand Kit tokens. */
.advisor-avatar img { border-color: var(--brand-orange); }
.advisor-avatar__name {
  font-size: 0.95rem;
  font-weight: 600;
  color: var(--brand-dark);
  text-align: center;
  line-height: 1.3;
  white-space: nowrap;
}
/* The one real, synced credibility signal available per person (qualification
   + years of experience, falling back to experience/clients — see
   pfp-showcase's buildCredential()) — a bare name under a stranger's face
   doesn't build any confidence on its own. Orange, not slate: this is meant
   to read as a highlight, not a muted caption. */
.advisor-avatar__credential {
  margin-top: -0.3rem;
  font-size: 0.82rem;
  font-weight: 700;
  color: var(--brand-orange);
  text-align: center;
  line-height: 1.3;
  white-space: nowrap;
}
/* City, shown alongside (not instead of) the credential line above — a plain
   muted caption rather than a highlight, since it's location context, not a
   credibility signal. */
.advisor-avatar__city {
  margin-top: -0.15rem;
  font-size: 0.82rem;
  color: var(--brand-slate);
  text-align: center;
  line-height: 1.3;
  white-space: nowrap;
}
@keyframes advisors-scroll {
  from { transform: translateX(0); }
  to { transform: translateX(-50%); }
}
@media (prefers-reduced-motion: reduce) {
  .advisors-track {
    animation: none;
  }
}

/* ==========================================================================
   Step 3 (Free 1:1 Consultation) — same structure as Step 1/.program-section:
   full-width heading, then one image+bullets row (2026-09-11, replacing an
   earlier version that also had a second heading + a separate 4-card "What to
   Expect" grid below it — those four points are bullets in the list now).
   ========================================================================== */
.expect-section {
  padding: 4rem 0;
  border-top: 1px solid var(--brand-border);
  background: rgba(239, 231, 220, 0.4);
}

/* ==========================================================================
   What Changes — before/after comparison list.
   ========================================================================== */
.compare-section {
  padding: 6rem 0;
  border-top: 1px solid var(--brand-border);
  background: rgba(239, 231, 220, 0.4);
}
.compare-card {
  margin-top: 3.5rem;
  border: 1px solid rgba(176, 176, 176, 0.25);
  border-radius: var(--radius-lg);
  overflow: hidden;
}
.compare-head,
.compare-row {
  display: grid;
  grid-template-columns: 1fr;
}
@media (min-width: 700px) {
  .compare-head,
  .compare-row {
    grid-template-columns: 1fr 1fr;
  }
}
.compare-head {
  background: rgba(239, 231, 220, 0.5);
}
.compare-head span {
  padding: 1rem 1.5rem;
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--brand-dark);
}
.compare-row {
  border-top: 1px solid rgba(176, 176, 176, 0.2);
}
.compare-cell {
  position: relative;
  padding: 1rem 1.5rem 1rem 2.75rem;
  font-size: 0.92rem;
  line-height: 1.5;
}
.compare-cell--before {
  color: var(--brand-slate);
}
.compare-cell--before::before {
  content: "\2013";
  position: absolute;
  left: 1.5rem;
  color: var(--brand-gray);
  font-weight: 700;
}
.compare-cell--after {
  color: var(--brand-dark);
  font-weight: 500;
  background: rgba(255, 80, 0, 0.03);
}
.compare-cell--after::before {
  content: "\2713";
  position: absolute;
  left: 1.5rem;
  color: var(--brand-orange);
  font-weight: 700;
}
.compare-disclaimer {
  margin: 1.5rem 0 0;
  font-size: 0.78rem;
  color: var(--brand-slate);
  text-align: center;
}

/* ==========================================================================
   Myth vs. Fact
   ========================================================================== */
.myths-section {
  padding: 6rem 0;
  border-top: 1px solid var(--brand-border);
}
.myths-grid {
  display: grid;
  gap: 1.5rem;
  margin-top: 3.5rem;
}
@media (min-width: 700px) {
  .myths-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}
.myth-card {
  border: 1px solid rgba(176, 176, 176, 0.25);
  border-radius: var(--radius-lg);
  padding: 1.75rem;
}
.myth-label,
.fact-label {
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.1em;
}
.myth-label {
  color: var(--brand-gray);
}
.myth-text {
  margin: 0.35rem 0 0;
  font-size: 0.95rem;
  font-style: italic;
  color: var(--brand-slate);
  text-decoration: line-through;
  text-decoration-color: rgba(176, 176, 176, 0.6);
}
.fact-label {
  margin-top: 1.1rem;
  color: var(--brand-orange);
}
.fact-text {
  margin: 0.35rem 0 0;
  font-size: 0.95rem;
  line-height: 1.55;
  color: var(--brand-dark);
  font-weight: 500;
}

/* ==========================================================================
   Legal / prose pages (privacy-consent.html) — plain long-form content, so
   unlike the rest of the site (built element-by-element in JS with explicit
   classes) this needs generic p/h2/ul spacing the global reset strips out.
   ========================================================================== */
.legal-container {
  max-width: 42rem;
  padding-top: 4rem;
  padding-bottom: 6rem;
}
.legal-container h1 {
  margin-top: 0.5rem;
  font-size: 2.25rem;
}
.legal-updated {
  margin-top: 0.75rem;
  font-size: 0.85rem;
  color: var(--brand-slate);
}
.legal-container h2 {
  margin-top: 2.5rem;
  font-size: 1.5rem;
}
.legal-container p {
  margin-top: 1.25rem;
  font-size: 1rem;
  line-height: 1.7;
  color: var(--brand-dark);
}
.legal-container a {
  color: var(--brand-orange);
  text-decoration: underline;
}
.legal-container a:hover {
  color: #e64800;
}
.legal-list {
  margin: 1.25rem 0 0;
  padding-left: 1.25rem;
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
}
.legal-list li {
  font-size: 1rem;
  line-height: 1.6;
  color: var(--brand-dark);
}
.legal-callout {
  margin-top: 2.5rem;
  padding: 1.5rem 1.75rem;
  background: rgba(239, 231, 220, 0.4);
  border-left: 3px solid var(--brand-orange);
  border-radius: var(--radius);
}
.legal-callout p {
  margin-top: 0;
}
.legal-callout p + p {
  margin-top: 1rem;
}
.legal-table-wrap {
  margin-top: 1.25rem;
  overflow-x: auto;
}
.legal-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.92rem;
}
.legal-table th,
.legal-table td {
  text-align: left;
  padding: 0.65rem 0.85rem;
  border: 1px solid var(--brand-border);
  vertical-align: top;
  line-height: 1.5;
}
.legal-table th {
  background: rgba(239, 231, 220, 0.5);
  font-weight: 600;
  color: var(--brand-dark);
}
.legal-todo {
  background: rgba(255, 80, 0, 0.12);
  padding: 0.1em 0.4em;
  border-radius: 4px;
  font-style: italic;
}

/* ==========================================================================
   FAQ — native <details>/<summary>, no JS needed, accessible by default.
   ========================================================================== */
.faq {
  padding: 6rem 0;
  background: rgba(239, 231, 220, 0.4);
}
.faq-list {
  max-width: 44rem;
  margin: 3rem auto 0;
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}
.faq-item {
  border: 1px solid rgba(176, 176, 176, 0.25);
  border-radius: var(--radius);
  padding: 1.25rem 1.5rem;
}
.faq-item summary {
  cursor: pointer;
  list-style: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  font-family: var(--font-heading);
  font-weight: 700;
  font-size: 1.05rem;
  color: var(--brand-dark);
  transition: color 150ms ease;
}
.faq-item summary:hover {
  color: var(--brand-orange);
}
.faq-item summary::-webkit-details-marker {
  display: none;
}
.faq-item summary::after {
  content: "+";
  flex-shrink: 0;
  font-family: var(--font-body);
  font-size: 1.5rem;
  font-weight: 400;
  color: var(--brand-orange);
  transition: transform 200ms ease;
}
.faq-item[open] summary::after {
  transform: rotate(45deg);
}
.faq-item p {
  margin-top: 1rem;
  font-size: 0.95rem;
  line-height: 1.6;
  color: var(--brand-slate);
}
@media (prefers-reduced-motion: reduce) {
  .faq-item summary::after {
    transition: none;
  }
}

/* ==========================================================================
   CTA band
   ========================================================================== */
.cta-band {
  background: var(--brand-dark);
}
.cta-band .container {
  max-width: 48rem;
  padding-top: 6rem;
  padding-bottom: 6rem;
  text-align: center;
}
.cta-band h2 {
  color: var(--brand-white);
  font-size: 2.25rem;
}
@media (min-width: 640px) {
  .cta-band h2 {
    font-size: 2.75rem;
  }
}
.cta-band p {
  max-width: 32rem;
  margin: 1.25rem auto 0;
  font-size: 1.125rem;
  color: rgba(255, 255, 255, 0.7);
}
.cta-band .btn {
  margin-top: 2rem;
}

/* ==========================================================================
   Footer
   ========================================================================== */
.site-footer {
  border-top: 1px solid rgba(176, 176, 176, 0.25);
}
.footer-grid {
  display: grid;
  gap: 3rem;
  padding-top: 4rem;
}
@media (min-width: 640px) {
  .footer-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}
@media (min-width: 1024px) {
  .footer-grid {
    grid-template-columns: repeat(4, 1fr);
  }
}
.footer-about img {
  height: 69px;
  width: auto;
}
.footer-about p {
  margin-top: 1rem;
  max-width: 20rem;
  font-size: 0.875rem;
  color: var(--brand-dark);
  opacity: 0.8;
}
.footer-col h3 {
  font-size: 0.875rem;
}
.footer-col ul {
  list-style: none;
  margin: 1rem 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}
.footer-col a {
  font-size: 0.875rem;
  color: var(--brand-dark);
  opacity: 0.8;
  transition: color 150ms ease;
}
.footer-col a:hover {
  color: var(--brand-orange);
  opacity: 1;
}
.footer-bottom {
  margin-top: 3rem;
  padding: 2rem 0;
  border-top: 1px solid rgba(176, 176, 176, 0.2);
  display: flex;
  flex-direction: column;
  gap: 1rem;
  font-size: 0.875rem;
  color: var(--brand-slate);
}
@media (min-width: 640px) {
  .footer-bottom {
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
  }
}

/* ==========================================================================
   Assessment flow — deliberately minimal chrome (logo + progress only, no full
   site nav) so nothing distracts from finishing the 21 questions. Design plan §1/§2.
   ========================================================================== */
.flow-body {
  /* height, not min-height (2026-09-15) — min-height only guarantees a FLOOR,
     it never stops the page growing taller than the viewport when a question's
     content needs more room, which is exactly what still let this page scroll
     despite the "no scroll" pass on 2026-09-12 (that pass fixed Back/Next
     staying pinned, but never actually capped the page's own height). height
     is a real ceiling: content that doesn't fit clips (see
     .flow-question-area below) instead of growing the page. */
  height: 100vh; /* fallback for browsers without dvh support */
  height: 100dvh; /* iOS Safari's address bar resizes the viewport as it
    shows/hides — 100vh is measured against the tallest state, so a shorter
    real viewport leaves a gap or forces scroll on a page meant to fit in one
    screen. dvh tracks the actual visible height instead. */
  overflow: hidden;
  display: flex;
  flex-direction: column;
}
/* FW Checkup only — two very faint warm-peach corner shapes (derived from the
   one brand accent, not a new color), per the redesign brief's "extremely
   subtle... must not feel like a marketing landing page." Pure CSS, no
   image assets. position: fixed so .flow-body's overflow: hidden (needed for
   the one-viewport question layout) doesn't clip them, and z-index: 0 with
   .flow-main lifted to z-index: 1 keeps them strictly behind all content. */
.fw-checkup::before,
.fw-checkup::after {
  content: "";
  position: fixed;
  z-index: 0;
  width: 26rem;
  height: 26rem;
  border-radius: 50%;
  background: rgba(255, 80, 0, 0.05);
  pointer-events: none;
}
.fw-checkup::before {
  bottom: -14rem;
  left: -10rem;
}
.fw-checkup::after {
  bottom: -16rem;
  right: -12rem;
  background: rgba(255, 80, 0, 0.035);
}
.fw-checkup .flow-main {
  position: relative;
  z-index: 1;
}
@media (max-width: 640px) {
  .fw-checkup::before,
  .fw-checkup::after {
    width: 16rem;
    height: 16rem;
  }
}

.flow-header {
  position: sticky;
  top: 0;
  z-index: 50;
  background: var(--brand-white);
  border-bottom: 1px solid var(--brand-border);
}
/* Exact rendered height of .flow-header (row padding 0.85rem*2 + logo height +
   1px border-bottom below), so pages that ALSO have their own sticky in-app
   header (retirement-calculator.html, life-goals-matrix.html, real-statement.html
   — ported from standalone-tools/, which had no site chrome above them to
   account for) can stick right below this one instead of both locking to
   viewport top:0 and overlapping. Kept in sync with the logo-height media
   query above by hand — there are only these two breakpoints. */
:root {
  --flow-header-h: 92px; /* 0.85rem*2 (27.2px) + 63px logo + 1px border, rounded up */
}
@media (max-width: 767px) {
  :root {
    --flow-header-h: 75px; /* 0.85rem*2 (27.2px) + 46px logo + 1px border, rounded up */
  }
}
.flow-header__row {
  padding: 0.85rem 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.flow-header__row .logo img {
  height: 63px;
  width: auto;
}
/* Same reasoning as .site-header's mobile cap above — this row also has to fit
   the step label (or, on the PFP portal, a "Sign out" button) alongside the
   logo. Verified via font-metrics measurement against the longest step label
   ("Question 21 of 21"). */
@media (max-width: 767px) {
  .flow-header__row .logo img {
    height: 46px;
  }
}
.flow-step-label {
  font-size: 0.85rem;
  font-weight: 500;
  color: var(--brand-slate);
}
/* Visually hidden but still reachable by assistive tech — used on
   health-check.html's #step-label (aria-live="polite") once the visible
   question counter moved out of the header and above the question itself
   (see .question-badge below). Keeps auto-advance between questions
   announced to screen readers without moving focus, without also showing a
   second, redundant counter next to the logo (the user explicitly asked for
   the count to live only in the middle of the screen, not top-right). */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* health-check.html only — 2026-09-15 premium/minimal redesign: a small pill
   badge ("Question 2") centered above the prompt, replacing both the earlier
   header-corner counter and the icon+category line that came before it.
   Purely decorative (aria-hidden — the header's sr-only #step-label carries
   the same text for screen readers), warm-peach tint derived from the one
   brand accent color rather than a new token. */
.question-badge {
  display: inline-block;
  margin: 0 0 1rem;
  padding: 0.4rem 1rem;
  border-radius: 999px;
  background: rgba(255, 80, 0, 0.08);
  color: var(--brand-orange);
  font-size: 0.85rem;
  font-weight: 500;
}
/* Hidden on the FW Checkup's 2026-09-17 redesign — the dot progress in
   .flow-nav now carries this visually, and the header's sr-only #step-label
   already carries it for screen readers, so this pill (still aria-hidden,
   still in the DOM) would just be a redundant second counter. */
.fw-checkup .question-badge {
  display: none;
}

/* Single thin hairline — a segmented per-category bar was tried here first and
   read as gamified rather than calm; one quiet line reads more editorial. */
.progress-track {
  height: 2px;
  background: var(--brand-cream);
}
.progress-fill {
  height: 100%;
  background: var(--brand-orange);
  width: 5%;
  transition: width 400ms ease;
}
@media (prefers-reduced-motion: reduce) {
  .progress-fill {
    transition: none;
  }
}

/* FW Checkup only (health-check.html) — one dot per question, sitting between
   Back/Next instead of a hairline bar up in the header (2026-09-17 redesign).
   Wraps to its own centered row on narrow screens (see .flow-nav below) rather
   than fighting the two buttons for space. */
.progress-dots {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 0.3rem;
}
.progress-dots .dot {
  width: 6px;
  height: 6px;
  border-radius: 999px;
  background: var(--brand-border);
  transition: width 200ms ease, background-color 200ms ease;
}
.progress-dots .dot.is-done {
  background: var(--brand-orange);
}
.progress-dots .dot.is-current {
  width: 20px;
  background: var(--brand-orange);
}
@media (prefers-reduced-motion: reduce) {
  .progress-dots .dot {
    transition: none;
  }
}

/* Replays on every render() (health-check.js's playEnterAnimation) so each of
   the 20 questions arrives with a small amount of motion rather than an
   instant text swap. A slower, smaller drift than the first pass — reads
   calmer/more premium. Transform/opacity only — no layout height change, so
   it can't reopen the one-viewport overflow this page was just fixed for. */
@keyframes question-card-enter {
  from {
    opacity: 0;
    transform: translateY(3px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}
.question-card--entering {
  animation: question-card-enter 420ms ease both;
}
@media (prefers-reduced-motion: reduce) {
  .question-card--entering {
    animation: none;
  }
}

.flow-main {
  flex: 1;
  display: flex;
  align-items: center;
  /* Trimmed from 3rem — a question with a full 8-option list (e.g. Q4)
     plus this padding plus .flow-header overflowed a normal laptop screen
     (700-820px tall), forcing page scroll on what's meant to be a single
     self-contained question per screen. Harmless for short-content states
     (the welcome screen, a lone spinner) since those are still centered
     within the min-height below regardless of how much padding surrounds
     them — only long-content questions actually get shorter from this.
     Stays min-height here in the base rule — this class is also used by
     booking.html/cancel.html/admin.html/debug-seed.html (no .flow-body on
     their <body>), which are NOT single-viewport pages and must still be
     free to grow taller than one screen with normal page scroll. The hard
     height cap for the actual questionnaire flows lives in the
     .flow-body .flow-main override below, scoped to just those two pages. */
  padding: 0.75rem 0;
  min-height: calc(100vh - 6rem);
  min-height: calc(100dvh - 6rem); /* see .flow-body's comment on dvh vs vh */
}
.flow-container {
  max-width: 40rem;
}
/* Rebuilt 2026-09-12 — Back/Next used to sit right after the question card in
   normal document flow, so a fixed 16rem card min-height (meant to stop the
   page visually "jumping" between short and long questions) instead reserved
   dead space below short questions and, combined with header + padding, could
   push Next past the fold on a shorter viewport or 100% browser zoom exactly
   what "Next button must be seen without scroll" was reporting. Standard
   fix (same pattern Typeform-style flows use): make .flow-container fill the
   FULL remaining viewport height, let .flow-question-area (flex: 1) center
   the question within whatever space is left, and pin .flow-nav to the
   bottom of that fixed-height column instead of flowing after the card —
   Back/Next then stay in the same place regardless of question length, and a
   question tall enough to not fit scrolls internally rather than pushing nav
   off-screen. */
.flow-body .flow-main {
  align-items: stretch;
  /* Real height cap, scoped to just the two questionnaire flows (.flow-body is
     exclusive to health-check.html/consultation.html) — min-height: 0 lets
     flexbox actually shrink this to fit .flow-body's fixed 100dvh instead of
     the base rule's min-height forcing it taller and getting clipped at the
     .flow-body boundary (which would risk cutting off .flow-nav at the
     bottom rather than clipping question content in the middle). */
  min-height: 0;
  height: calc(100vh - var(--flow-header-h));
  height: calc(100dvh - var(--flow-header-h));
}
.flow-body .flow-container {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-height: 0;
}
.flow-question-area {
  flex: 1;
  display: flex;
  align-items: center;
  min-height: 0;
  /* overflow: hidden, not auto (2026-09-15, explicit "nothing scrollable") —
     .flow-main above is now a real height cap, so this is the last line of
     defense: content that still doesn't fit clips silently instead of
     scrolling. Every FW Checkup question is a short, uniform 5-option Likert
     prompt (see js/lib/questions.js), so in practice this should never
     actually need to clip anything — it's a safety net, not the plan. */
  overflow: hidden;
}
.question-card {
  width: 100%;
}
.question-prompt {
  font-size: 1.75rem;
  line-height: 1.2;
}
@media (min-width: 640px) {
  .question-prompt {
    font-size: 2.1rem;
  }
}
.question-helper {
  margin-top: 0.75rem;
  font-size: 0.95rem;
  color: var(--brand-slate);
}

/* FW Checkup only (.fw-checkup) — 2026-09-15 premium/minimal redesign, restyled
   again 2026-09-17 to a left-aligned card + tip-box layout. Scoped everywhere
   here so consultation.html, which shares these same class names
   (.flow-container/.question-card/.question-prompt/.option-card), keeps its
   existing look; only health-check.html changes. */
.fw-checkup .flow-container {
  /* Wider than the shared 40rem default — five answer cards need the room —
     but still well short of the site's 72rem .container, so the page doesn't
     stretch edge-to-edge on a wide monitor. */
  max-width: 54rem;
}
.fw-checkup .question-card.is-question {
  text-align: left;
}
/* Personal greeting above the card — see health-check.js's render(). Plain
   bold body text, not the serif/italic .script-word accent treatment used
   elsewhere, so it reads as a short spoken line, not a headline. */
.question-greeting {
  margin: 0 0 0.6rem;
  font-family: var(--font-body);
  font-size: 1.05rem;
  font-weight: 700;
  color: var(--brand-orange);
}
/* The actual question card — heading, helper, and options together in one
   panel; the greeting above and the tip box below sit outside it. Cream tint
   is the same card-surface treatment .insight-card/.fw-summary-banner already
   use elsewhere, not a new token. */
.fw-checkup .question-card__panel {
  padding: 1.25rem 1.5rem;
  border-radius: var(--radius-lg);
  background: rgba(239, 231, 220, 0.35);
}
.fw-checkup .question-card.is-question .question-prompt {
  max-width: none;
  margin: 0;
  font-size: 1.35rem;
  font-weight: 700;
}
@media (min-width: 640px) {
  .fw-checkup .question-card.is-question .question-prompt {
    font-size: 1.55rem;
  }
}
.fw-checkup .question-card.is-question .question-helper {
  max-width: none;
  margin: 0.35rem 0 0;
}
/* Tip box below the card — a short, general "why this matters" for the
   current question's category (health-check.js pulls the copy from
   js/lib/result-copy.js's WHY_IT_MATTERS, the same source results.js used to
   use for its own now-removed per-category detail section). */
.question-tip {
  display: flex;
  align-items: flex-start;
  gap: 0.75rem;
  margin-top: 0.85rem;
  padding: 0.75rem 1.1rem;
  border-radius: var(--radius);
  background: rgba(255, 80, 0, 0.08);
}
.question-tip__icon {
  display: flex;
  flex-shrink: 0;
  margin-top: 0.15rem;
  color: var(--brand-orange);
}
.question-tip p {
  font-size: 0.9rem;
  line-height: 1.5;
  color: var(--brand-dark);
}
.question-tip strong {
  color: var(--brand-orange);
}

/* Free 1:1 Consultation only (.consultation-flow, consultation.html's body
   class) — bug fix, 2026-09-17. .flow-question-area vertically centers
   .question-card and clips anything taller than the available space
   (overflow: hidden, same one-viewport lock health-check.html uses). That's
   harmless for the FW Checkup (every question is a uniform 5-option Likert),
   but this flow's c2_needs (11 checkboxes) and especially c3_language (13
   checkboxes) are tall enough to get symmetrically clipped top AND bottom —
   reported as "the question is missing" and "the language question is also
   missing", because the clipped-off top was the heading itself and the
   clipped-off bottom was the question's last few options. Fix: cap the card
   to the available height and let ONLY the option list scroll internally,
   so the heading/helper stay pinned and visible no matter how many options a
   question has. Short questions (a handful of options, or the plain text
   city question) are completely unaffected — they're shorter than the cap,
   so this is a no-op for them and .flow-question-area's existing
   align-items: center still centers the whole (shorter) card exactly as
   before. */
.consultation-flow .question-card {
  display: flex;
  flex-direction: column;
  min-height: 0;
  max-height: 100%;
}
.consultation-flow .question-prompt,
.consultation-flow .question-helper {
  flex-shrink: 0;
}
.consultation-flow .option-grid {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  /* A couple of px so the scrollbar doesn't sit flush against the option
     cards' own right edge/focus outline. */
  padding-right: 0.25rem;
}

/* Welcome screen — reassurance list (design plan §2's "Screen 1"). Tightened
   2026-09-15 alongside .flow-body's hard viewport cap — this screen (heading +
   helper + this list + the full intake form below) is the tallest one in
   either flow, so it's the one most likely to actually hit the new
   overflow: hidden safety net on a shorter viewport. */
.welcome-list {
  list-style: none;
  margin: 1.1rem 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
}
.welcome-list li {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  font-size: 0.95rem;
}
.welcome-list svg {
  flex-shrink: 0;
  color: var(--brand-orange);
}

.option-grid {
  display: grid;
  /* Both trimmed (was 0.75rem gap / 2rem margin-top) — the same overflow
     this question (8 options) triggered pushes back against every pixel
     of padding, and this compounds across up to 8 cards. */
  gap: 0.4rem;
  margin-top: 0.85rem;
}
.option-card {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.55rem 1.1rem;
  border: 1.5px solid var(--brand-border);
  border-radius: var(--radius);
  cursor: pointer;
  font-size: 1rem;
  transition: border-color 150ms ease, background-color 150ms ease;
}
.option-card:hover {
  border-color: var(--brand-orange);
  background: rgba(255, 80, 0, 0.03);
}
.option-card input[type="radio"],
.option-card input[type="checkbox"] {
  width: 20px;
  height: 20px;
  accent-color: var(--brand-orange);
  flex-shrink: 0;
}
.option-card:has(input:checked),
.option-card.is-selected {
  border-color: var(--brand-orange);
  background: rgba(255, 80, 0, 0.06);
  font-weight: 500;
}

/* Pill variant — same .option-card markup/inputs/event handling, just styled
   as rounded toggle pills instead of checkbox rows, to match c1_city's
   quick-pick-chip look (e.g. c3_language, 2026-09-17 explicit instruction). */
.option-grid--pills {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}
.option-grid--pills .option-card {
  position: relative;
  padding: 0.45rem 1rem;
  border-radius: 999px;
  font-size: 0.88rem;
}
.option-grid--pills .option-card input[type="checkbox"] {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}
.option-grid--pills .option-card:has(input:checked),
.option-grid--pills .option-card.is-selected {
  background: rgba(255, 80, 0, 0.08);
  font-weight: 700;
  color: var(--brand-orange);
}

/* FW Checkup only (.fw-checkup, health-check.html's body class) — restyled
   2026-09-17: full-width stacked bars (radio hidden, visually-hidden-but-
   focusable — same technique .option-grid--pills's checkbox already uses),
   selection shown by a solid orange fill + a checkmark icon on the right
   rather than a visible radio dot. Scoped so consultation.html is untouched. */
.fw-checkup .option-card {
  padding: 1rem 1.25rem;
  border-width: 1.5px;
  border-radius: 14px;
  transition: border-color 150ms ease, background-color 150ms ease, color 150ms ease;
}
.fw-checkup .option-card span {
  font-size: 1rem;
  line-height: 1.3;
  color: var(--brand-dark);
}
.fw-checkup .option-card:has(input:checked),
.fw-checkup .option-card.is-selected {
  border-color: var(--brand-orange);
  background: var(--brand-orange);
}
.fw-checkup .option-card:has(input:checked) span,
.fw-checkup .option-card.is-selected span {
  color: var(--brand-white);
  font-weight: 600;
}
.fw-checkup .option-card:has(input:focus-visible) {
  outline: 2px solid var(--brand-orange);
  outline-offset: 2px;
}
@media (prefers-reduced-motion: reduce) {
  .fw-checkup .option-card {
    transition: none;
  }
}
/* Three-class selector so this reliably beats .option-grid--likert
   .option-card (styles.css's shared likert rule, same 2-class specificity)
   regardless of which one happens to come later in the file — every FW
   Checkup question is this likert type, so this is the rule that actually
   applies in practice. */
.fw-checkup .option-grid--likert {
  grid-template-columns: 1fr;
  gap: 0.5rem;
}
.fw-checkup .option-grid--likert .option-card {
  flex-direction: row;
  align-items: center;
  justify-content: space-between;
  text-align: left;
  gap: 0.75rem;
  /* 0.75rem vertical keeps each bar at/near the 44px touch-target floor
     (padding + line-height) without the roomier 1rem this briefly had —
     that overflowed a normal ~720px-tall laptop viewport (this page is a
     hard one-viewport, no-scroll layout; see .flow-body's own comment). */
  padding: 0.75rem 1.25rem;
}
.fw-checkup .option-grid--likert .option-card span {
  font-size: 1rem;
}
/* Radio kept in the DOM (name/value/checked drive health-check.js's existing
   change handling unchanged) but visually hidden — the bar's own fill color
   and the checkmark below carry selection instead of a dot. Same
   clip-to-1px technique .option-grid--pills's checkbox already uses. */
.fw-checkup .option-grid--likert .option-card input[type="radio"] {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}
.option-card__check {
  display: none;
  flex-shrink: 0;
  color: var(--brand-white);
}
.fw-checkup .option-grid--likert .option-card:has(input:checked) .option-card__check,
.fw-checkup .option-grid--likert .option-card.is-selected .option-card__check {
  display: flex;
}
/* Comfortable spacing between cards (spec: "consistent height, comfortable
   spacing") — wider than the shared 0.4rem/0.5rem gaps, which were trimmed
   for a since-superseded 8-option question this bank no longer has. */
.fw-checkup .option-grid {
  gap: 0.5rem;
  margin-top: 0.85rem;
}

/* Short viewports only (height, not width — a narrow-but-TALL phone like a
   390x844 iPhone already fits fine; it's a SHORT one, e.g. a 375x667 iPhone
   SE or a laptop browser window, that doesn't). This page is a hard
   one-viewport, no-scroll layout (.flow-body), and the greeting + tip box
   added 2026-09-17 pushed those short viewports into clipping. The generic
   "Select the option..." helper line is redundant with the options right
   below it, so it's the first thing to go; tighter padding and a 2-line cap
   on the tip's own text recover the rest. Placed after the base fw-checkup
   rules above (not just inside a media query near them) so it actually wins
   the cascade — equal-specificity rules resolve by source order regardless
   of which one sits in a media block, so an override placed earlier in the
   file loses to a plain rule declared later even when its condition matches. */
@media (max-height: 700px) {
  .fw-checkup .question-card.is-question .question-helper {
    display: none;
  }
  .fw-checkup .question-card__panel {
    padding: 0.9rem 1.1rem;
  }
  .fw-checkup .option-grid--likert .option-card {
    padding: 0.5rem 1.1rem;
  }
  .fw-checkup .option-grid {
    gap: 0.4rem;
    margin-top: 0.6rem;
  }
  .question-tip {
    margin-top: 0.6rem;
    padding: 0.6rem 0.9rem;
  }
  .question-tip p {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    overflow: hidden;
  }
  .question-greeting {
    margin-bottom: 0.4rem;
  }
  .fw-checkup .question-card.is-question .question-prompt {
    font-size: 1.15rem;
  }
  /* .flow-body.fw-checkup (both classes on <body>, health-check.js's own
     scoping) rather than plain .fw-checkup — the base .fw-checkup .flow-nav
     rule lives much later in this file in the general .flow-nav section, so
     matching its (0,2,0) specificity here would lose on source order alone;
     this compound bumps to (0,3,0) so the override wins regardless of where
     either rule sits in the file. */
  .flow-body.fw-checkup .flow-nav {
    padding-top: 0.6rem;
  }
}

.text-input {
  width: 100%;
  margin-top: 2rem;
  padding: 0.9rem 1.1rem;
  font-size: 1.1rem;
  font-family: var(--font-body);
  border: 1.5px solid var(--brand-border);
  border-radius: var(--radius);
  color: var(--brand-dark);
}
.text-input:focus-visible {
  outline: 2px solid var(--brand-orange);
  outline-offset: 1px;
  border-color: var(--brand-orange);
}

/* "How many family members depend on you financially?" (c9_family) — a small
   stack of label+dropdown rows, one per dependent category, styled like a
   compact form rather than the option-card grid every other question uses
   (a grid of cards doesn't fit a numeric count well). */
.family-field-group {
  display: flex;
  flex-direction: column;
  gap: 0.9rem;
  margin-top: 2rem;
}
.family-field-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.9rem 1.1rem;
  border: 1.5px solid var(--brand-border);
  border-radius: var(--radius);
}
.family-field-row__label {
  font-weight: 600;
  color: var(--brand-dark);
}
/* Spouse (yes/no) — same .quick-pick-chip pair look as c1_city's own
   quick-picks, not a native <select>, to match this site's one selection
   language instead of a stray browser dropdown next to it. */
.family-field-row__chips {
  display: flex;
  gap: 0.5rem;
}

/* +/- stepper for numeric family-count fields (Dependent Children/Parents) —
   Spouse stays the dropdown above (a yes/no, not a count). */
.family-field-row__stepper {
  display: flex;
  align-items: center;
  gap: 0.9rem;
}
.family-field-row__step {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.1rem;
  height: 2.1rem;
  border: 1.5px solid var(--brand-border);
  border-radius: 50%;
  background: var(--brand-cream);
  color: var(--brand-dark);
  font-size: 1.1rem;
  font-weight: 700;
  line-height: 1;
  transition: border-color 150ms ease, color 150ms ease;
}
.family-field-row__step:hover:not(:disabled) {
  border-color: var(--brand-orange);
  color: var(--brand-orange);
}
.family-field-row__step:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}
.family-field-row__count {
  min-width: 1.5rem;
  text-align: center;
  font-weight: 700;
  color: var(--brand-dark);
}

/* Quick-pick chips under a text question (e.g. "Which city are you in?") —
   tapping one fills the field directly instead of typing. */
.quick-pick-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-top: 0.9rem;
}
.quick-pick-chip {
  padding: 0.45rem 1rem;
  border: 1.5px solid var(--brand-border);
  border-radius: 999px;
  background: var(--brand-white);
  font-family: var(--font-body);
  font-size: 0.88rem;
  color: var(--brand-dark);
  cursor: pointer;
  transition: border-color 150ms ease, background-color 150ms ease;
}
.quick-pick-chip:hover {
  border-color: var(--brand-orange);
  background: rgba(255, 80, 0, 0.03);
}
.quick-pick-chip.is-selected {
  border-color: var(--brand-orange);
  background: rgba(255, 80, 0, 0.08);
  font-weight: 700;
  color: var(--brand-orange);
}

.consent-notice {
  margin-top: 1.5rem;
  font-size: 0.9rem;
  line-height: 1.55;
  color: var(--brand-slate);
}
.consent-notice a {
  color: var(--brand-orange);
  text-decoration: underline;
  white-space: nowrap;
}

.consent-check {
  display: flex;
  align-items: flex-start;
  gap: 0.75rem;
  margin-top: 1.25rem;
  padding: 1.25rem;
  border: 1.5px solid var(--brand-border);
  border-radius: var(--radius);
  cursor: pointer;
  font-size: 0.95rem;
  line-height: 1.5;
}
.consent-check:first-of-type {
  margin-top: 2rem;
}
.consent-check input {
  width: 20px;
  height: 20px;
  margin-top: 0.15rem;
  accent-color: var(--brand-orange);
  flex-shrink: 0;
}
.consent-check a {
  color: var(--brand-orange);
  text-decoration: underline;
}
.consent-check a:hover {
  color: #e64800;
}
/* Welcome screen's intake fields (2026-09-11) — name/email/phone + terms +
   newsletter, collected up front instead of a separate end-of-flow consent
   screen. Reuses .text-input/.consent-check as-is, just overrides their
   standalone top-margins in favor of one consistent flex gap here. */
.welcome-intake {
  margin-top: 1.1rem;
  display: flex;
  flex-direction: column;
  gap: 0.65rem;
}
.welcome-intake .text-input {
  margin-top: 0;
}
.welcome-intake .consent-check {
  margin-top: 0.3rem;
  padding: 0.75rem 0.9rem;
}
.welcome-intake .consent-check:first-of-type {
  margin-top: 0.3rem;
}

.consent-signin {
  margin-top: 1.25rem;
}
.consent-signin .google-signin-btn {
  margin-top: 0;
}
.consent-signin-status {
  padding: 0.85rem 1.1rem;
  border-radius: var(--radius);
  background: var(--brand-mint);
  color: var(--brand-dark);
  font-size: 0.9rem;
}

.flow-nav {
  flex-shrink: 0;
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  margin-top: 1.25rem;
}
.flow-nav .btn:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}
/* FW Checkup only — a subtle divider above Back/Next, per the redesign brief
   ("clean navigation area... use a subtle horizontal divider"). */
.fw-checkup .flow-nav {
  padding-top: 0.85rem;
  border-top: 1px solid var(--brand-border);
  align-items: center;
  flex-wrap: wrap;
}
/* The dot progress (2026-09-17) drops to its own centered row below Back/Next
   on narrow screens — 20 dots fighting two buttons for one row reads cramped
   at phone widths — and sits centered between them from 640px up, where
   flex: 1 lets .progress-dots' own internal justify-content: center actually
   center it in the real leftover space instead of an even three-way
   space-between split. */
.fw-checkup .progress-dots {
  order: 3;
  flex-basis: 100%;
}
@media (min-width: 640px) {
  .fw-checkup .progress-dots {
    order: 0;
    flex: 1;
    flex-basis: auto;
  }
}

/* ==========================================================================
   Results page — design plan §3.3/§3.4, staged narrative rewrite:
   #matches-stage renders first in DOM (empty at load) and #score-stage
   second, so populating matches-stage later (the finding-loader, then the
   match cards) pushes the score stage down the page by ordinary document
   flow — the "score sits alone, then automatically moves down as PFPs take
   the top of the page" sequence needs no scroll trickery, just this order.
   ========================================================================== */
.results-container {
  max-width: 90rem; /* full dashboard width — was 58rem, left huge unused margins on anything wider than a laptop */
  padding-top: 1.5rem;
  padding-bottom: 2rem;
}
/* Tighter page chrome scoped to the Free 1:1 Consultation results page only
   (2026-09-11, "I don't want scrolls") — .results-container/.section-heading are
   shared with the FW Checkup score dashboard (results.html), which still wants
   its original spacing; this page's own vertical rhythm just needed cutting. */
.consultation-results-page .results-container {
  padding-top: 1rem;
  padding-bottom: 1.5rem;
}
.consultation-results-page .section-heading .eyebrow {
  margin-bottom: 0.35rem;
}
.consultation-results-page .section-heading h1 {
  font-size: 1.6rem;
}
.consultation-results-page .section-heading p {
  margin-top: 0.3rem;
  font-size: 0.88rem;
  line-height: 1.4;
  color: var(--brand-slate);
}
.consultation-results-page .footer-bottom {
  margin-top: 1.25rem;
  padding: 1rem 0;
}

/* Fade-up entrance for content injected well after page load (the finding
   loader and the match cards) — the site's usual .reveal/.reveal-group
   system only observes elements present at DOMContentLoaded, so it never
   sees anything results.js adds later. Same visual (opacity + translateY) as
   .js .reveal, just self-playing on insertion instead of waiting on an
   IntersectionObserver that will never fire for it. */
@keyframes fadeUpIn {
  from {
    opacity: 0;
    transform: translateY(28px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}
/* Scoped to .is-home (see the .reveal rules above) — everywhere else,
   .fade-up-in content (results.js match cards, skeleton loaders, etc.) just
   shows immediately with no animation at all, per instruction (2026-09-10). */
.is-home .fade-up-in {
  animation: fadeUpIn 420ms ease both;
}
@media (prefers-reduced-motion: reduce) {
  .is-home .fade-up-in {
    animation: none;
  }
}

/* --------------------------------------------------------------------------
   Matches stage — empty on load (renders as nothing), then the finding
   loader, then the match grid. The only thing in #results-root on this page
   now (a leftover margin-bottom/padding-bottom/border-bottom here, sized to
   visually separate this from a #score-stage that followed it on the
   original pre-split results page, was still costing ~130px of dead space at
   the bottom of THIS page even though #score-stage hasn't existed since the
   FW Checkup / Consultation split — removed 2026-09-12, a real contributor
   to this page needing to scroll). Fills the rest of .results-container's
   locked height (see .consultation-results-page above) so .match-columns
   below can stretch to fill whatever's actually left after the intro. */
#matches-stage {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
}
/* ==========================================================================
   Loading screen (finding loader + skeleton match cards) — deleted and
   rebuilt mobile-first, 2026-09-19, per explicit instruction, after two
   patch attempts (a scroll-container overflow fix, then a global
   overflow-x: hidden safety net) didn't resolve a reported mobile "content
   overlapping/cut off" bug. Root cause, found on rebuild: .skeleton-card__top
   was a single flex ROW holding a fixed-width photo (3.6rem) AND a
   fixed-width button (5.5rem) on either side of the flexible title/stats/
   chips content — comfortable on desktop, but on a ~360-390px phone the
   fixed children alone (photo + button + 2 gaps) ate roughly 180px, leaving
   the flexible middle content only ~100px to work with. That's not a
   scrollable-overflow bug (nothing was technically wider than the viewport,
   so overflow-x: hidden had nothing to catch) — it's a genuinely too-tight
   layout that reads as cramped/overlapping regardless of overflow handling.
   The rebuild below is written mobile-first (every rule assumes a narrow
   screen by default; a min-width query only ADDS density back for wider
   screens) and never puts a fixed-width element in the same flex row as
   flexible content, so this specific failure mode can't recur at any width.
   ========================================================================== */

/* Cross-fading headline over a skeleton preview of the incoming match grid —
   see renderFindingLoader()'s header comment in results.js for why this
   replaced a stacked checklist (that left a large empty gap under itself
   until it finished; this fills the same space immediately). */
.finding-loader {
  width: 100%;
  max-width: 28rem;
  margin: 0 auto;
  padding: 2rem 1rem 0;
  text-align: center;
}
.finding-loader__eyebrow {
  font-family: var(--font-body);
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  color: var(--brand-orange);
}
.finding-loader__cycle {
  margin-top: 0.6rem;
  font-family: var(--font-heading);
  font-size: 1.25rem;
  color: var(--brand-dark);
  transition: opacity 220ms ease, transform 220ms ease;
}
@media (min-width: 480px) {
  .finding-loader__cycle {
    font-size: 1.4rem;
  }
}
.finding-loader__cycle.is-fading {
  opacity: 0;
  transform: translateY(6px);
}

.skeleton-grid {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  width: 100%;
  max-width: 46rem; /* roughly the eventual left column's width, not full page width */
  margin: 1.5rem auto 0;
  padding: 0 1rem;
}
@media (min-width: 640px) {
  .skeleton-grid {
    padding: 0;
  }
}

.skeleton-card {
  display: flex;
  flex-direction: column;
  gap: 0.85rem;
  width: 100%;
  border: 1px solid var(--brand-border);
  border-radius: var(--radius-lg);
  padding: 1.1rem;
  background: var(--brand-white);
}
@media (min-width: 480px) {
  .skeleton-card {
    padding: 1.35rem;
  }
}

/* Photo + name/meta only — the button lives in its own full-width row below
   (see .skeleton-line--btn), never sharing a flex row with a fixed width on
   both sides the way the old layout did. */
.skeleton-card__head {
  display: flex;
  align-items: center;
  gap: 0.85rem;
}
.skeleton-photo {
  flex-shrink: 0;
  width: 3rem;
  height: 3rem;
  border-radius: 50%;
}
.skeleton-card__head-lines {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}
.skeleton-line {
  height: 0.75rem;
  max-width: 100%;
  border-radius: 999px;
}
.skeleton-line--title {
  width: 60%;
  height: 1rem;
}
.skeleton-line--meta {
  width: 42%;
}

/* 2x2 by default (comfortable at any phone width), 4-in-a-row only once
   there's real room for it — matches .match-stats-row's own real-card
   breakpoint so the loading state and the loaded state never disagree on
   how many columns fit at a given width. minmax(0, 1fr), not plain 1fr, so
   a track can never be forced wider than its share by an oversized
   sibling (same reasoning as .fw-glance-grid elsewhere in this file). */
.skeleton-stats-row {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.6rem;
  margin-top: 0.3rem;
  padding-top: 0.6rem;
  border-top: 1px solid var(--brand-border);
}
@media (min-width: 900px) {
  .skeleton-stats-row {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}
.skeleton-line--stat {
  height: 0.75rem;
  width: 65%;
}

.skeleton-chips-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
}
.skeleton-chip {
  flex-shrink: 0;
  height: 1.3rem;
  width: 5rem;
  max-width: 40%;
  border-radius: 999px;
}

/* Full-width on its own row (not a corner button squeezed into the head row
   above) — see this block's header comment for why. */
.skeleton-line--btn {
  width: 100%;
  height: 2.4rem;
  border-radius: 999px;
}
@media (min-width: 480px) {
  .skeleton-line--btn {
    width: 6rem;
    align-self: flex-start;
  }
}

.shimmer {
  background: linear-gradient(90deg, var(--brand-cream) 25%, rgba(255, 255, 255, 0.9) 37%, var(--brand-cream) 63%);
  background-size: 400% 100%;
  animation: shimmer 1.4s ease infinite;
}
@keyframes shimmer {
  0% {
    background-position: 100% 50%;
  }
  100% {
    background-position: 0% 50%;
  }
}
@media (prefers-reduced-motion: reduce) {
  .shimmer {
    animation: none;
  }
  .finding-loader__cycle {
    transition: none;
  }
}

.matches-stage__title {
  font-size: 1.6rem;
  text-align: center;
}
.muted {
  color: var(--brand-slate);
}
.matches-fallback-note {
  margin-top: 0.5rem;
  font-size: 0.9rem;
  text-align: center;
}
.matches-error {
  padding: 2rem 0;
  text-align: center;
}

.spinner {
  display: inline-block;
  width: 2rem;
  height: 2rem;
  border: 3px solid var(--brand-cream);
  border-top-color: var(--brand-orange);
  border-radius: 999px;
  animation: spin 800ms linear infinite;
}
@keyframes spin {
  to {
    transform: rotate(360deg);
  }
}
@media (prefers-reduced-motion: reduce) {
  .spinner {
    animation: none;
  }
}
/* --------------------------------------------------------------------------
   FW Checkup results (js/results.js). Originally a single-viewport "at a
   glance" dashboard (2026-09-11) — a fixed-width score panel + one merged
   category+insight grid, deliberately capped to one screen with an internal
   scroll safety net. Extended 2026-09-16 into a full report (score
   decomposition, per-category answer detail, an action plan) that's
   intentionally longer than one viewport by design, so that single-viewport
   lock (main height: calc(100vh - header), overflow-y: auto, footer hidden)
   was removed — the page is now a normal scrolling page, footer included,
   same as every other content page on the site. The hero (score panel +
   glance grid) below keeps its own layout/sizing untouched. */

/* Same fits-in-one-view-with-a-scroll-safety-net treatment as the FW Checkup
   dashboard above (2026-09-12) — overflow-y: auto, not overflow: hidden, for
   the same cross-browser/zoom reason: a hard clip can lose real content
   (the 3rd match card), a scrollbar never does. */
.consultation-results-page {
  --cr-header-h: 76px; /* same .site-header as results.html — see that block's comment */
}
@media (min-width: 1024px) {
  .consultation-results-page main {
    height: calc(100vh - var(--cr-header-h));
    overflow-y: auto;
  }
  .consultation-results-page .site-footer {
    display: none;
  }
  .consultation-results-page .results-container {
    height: 100%;
    display: flex;
    flex-direction: column;
    box-sizing: border-box;
  }
}

/* Spacing scale for every results-page section below (both the original hero
   and the 2026-09-16 additions) — scoped to .fw-checkup-dashboard-page
   (results.html's body class) so it can't leak onto any other page. Added
   2026-09-16 (spacing pass): before this, every section picked its own
   one-off rem value for what was functionally the same gap (0.5–1.1rem for
   "heading to content," 0.65–1rem for "gap between sibling cards," etc.) —
   this scale replaces all of those so the whole page shares one rhythm. */
.fw-checkup-dashboard-page {
  --fw-space-section: 1.25rem; /* vertical rhythm between major panels/sections */
  --fw-space-grid: 0.75rem; /* gap between sibling cards in a row (glance grid, summary stats, action columns) */
  --fw-space-list: 0.6rem; /* gap between stacked rows in a vertical list (decomposition rows, answer rows, action items) */
  --fw-space-content: 0.85rem; /* gap from a heading down to the content under it */
  --fw-card-padding: 0.65rem 0.9rem; /* small text-only card padding (summary stat, action item, answer row) */
}

/* Single source of truth for the gap between EVERY top-level section
   results.js appends to #results-root (summary banner, the score+glance
   hero, decomposition panel, details panel, action plan) — fixes a real bug
   found in review: .fw-dashboard only had `gap` between its own two children
   (score panel / glance panel), nothing pulling it away from the summary
   banner above it, so that card visually crowded/overlapped the score panel
   below it. An id-selector rule here safely wins over any section's own
   margin-top without the two fighting or stacking. */
#results-root > * + * {
  margin-top: var(--fw-space-section);
}

.fw-dashboard {
  display: flex;
  flex-direction: column;
  gap: var(--fw-space-section);
  height: 100%;
}
@media (min-width: 1024px) {
  .fw-dashboard {
    display: grid;
    grid-template-columns: 17rem 1fr;
    align-items: stretch;
    min-height: 0;
  }
}

/* Left: score panel -------------------------------------------------------- */
.fw-score-panel {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  padding: var(--fw-space-section) 1.5rem;
  border-radius: var(--radius-lg);
  background: rgba(239, 231, 220, 0.5);
  overflow: hidden;
  min-height: 0;
}
.fw-score-panel__title {
  font-size: 1.3rem;
  line-height: 1.25;
}
.fw-score-panel__ring {
  position: relative;
  width: fit-content;
  margin: 1rem auto 0;
}
.fw-score-panel__ring-center {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}
.fw-score-panel__number {
  font-family: var(--font-heading);
  font-weight: 700;
  font-size: 2.1rem;
  color: var(--brand-orange);
  line-height: 1;
}
.fw-score-panel__of {
  margin-top: 0.1rem;
  font-size: 0.8rem;
  color: var(--brand-slate);
}
.fw-score-panel__level {
  margin-top: 0.85rem;
  font-size: 1.25rem;
}
.fw-score-panel__opening {
  margin-top: 0.4rem;
  font-size: 0.85rem;
  line-height: 1.4;
  color: var(--brand-slate);
  max-width: 16rem;
}
/* text-align: center is load-bearing here, not decorative — justify-content:
   center only centers the label's box as a whole; on a button this narrow the
   label often wraps to two lines, and without text-align each wrapped line is
   still left-aligned within that box by the browser's own default, making the
   second line look shifted left relative to the first. Slightly smaller
   font-size + tighter padding also makes wrapping less likely in the first
   place, on top of fixing it when it does happen. */
.fw-score-panel__cta,
.fw-score-panel__retake {
  display: flex;
  width: 100%;
  text-align: center;
  font-size: 0.88rem;
  padding-left: 1.1rem;
  padding-right: 1.1rem;
}
.fw-score-panel__cta {
  margin-top: 1.1rem;
}
.fw-score-panel__retake {
  margin-top: 0.6rem;
  border: 1px solid var(--brand-border);
}
/* Auto-send status only now (2026-09-16 — the opt-in checkbox/email
   input/Send button were removed; the report is emailed automatically to
   whatever address intake already collected, see results.js's
   buildEmailReportStatus). Empty (no border, no height) whenever there's no
   intake email to send to, since results.js leaves the wrap childless in
   that case. */
.fw-score-panel__email {
  width: 100%;
}
.fw-score-panel__email:has(.fw-score-panel__email-status) {
  margin-top: 0.85rem;
  padding-top: 0.75rem;
  border-top: 1px solid var(--brand-border);
}
.fw-score-panel__email-status {
  font-size: 0.78rem;
  color: var(--brand-slate);
}

/* Right: unified "at a glance" panel --------------------------------------- */
.fw-glance-panel {
  display: flex;
  flex-direction: column;
  min-height: 0;
  padding: var(--fw-space-section) 1.5rem;
  border: 1px solid var(--brand-border);
  border-radius: var(--radius-lg);
  background: var(--brand-white);
}
.fw-glance-panel__header {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
}
.fw-glance-panel__heading h2 {
  font-size: 1.2rem;
}
.fw-glance-panel__heading p {
  margin-top: 0.3rem;
  font-size: 0.82rem;
  color: var(--brand-slate);
  max-width: 34rem;
}
.fw-glance-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 0.9rem;
  padding-top: 0.3rem;
}
.fw-glance-legend li {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  font-size: 0.72rem;
  font-weight: 600;
  color: var(--brand-slate);
  white-space: nowrap;
}
.fw-glance-legend__dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
}
.fw-glance-legend__dot--strong {
  background: var(--status-strong);
}
.fw-glance-legend__dot--good {
  background: var(--brand-slate);
}
.fw-glance-legend__dot--attention {
  background: var(--brand-orange);
}

/* Fixed 3x3 on desktop — minmax(0, 1fr), not plain 1fr, on both axes. Plain
   `1fr` tracks still carry an automatic MINIMUM size equal to their content's
   max-content (same root cause as flexbox's classic min-width:auto overflow
   bug, just for grid tracks), so a row/column with slightly more content than
   its neighbors was winning extra space instead of all three staying equal —
   exactly the "alignment issues" a mismatched card grid produces. minmax(0, 1fr)
   removes that automatic minimum so every row/column is truly equal, and any
   card whose content doesn't fit clips via line-clamp instead of growing. */
.fw-glance-grid {
  flex: 1;
  min-height: 0;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--fw-space-grid);
  margin-top: var(--fw-space-content);
}
@media (min-width: 1024px) {
  .fw-glance-grid {
    grid-template-rows: repeat(3, minmax(0, 1fr));
  }
}
@media (max-width: 1023px) {
  .fw-glance-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}
@media (max-width: 640px) {
  .fw-glance-grid {
    grid-template-columns: minmax(0, 1fr);
  }
  .fw-glance-panel__header {
    flex-direction: column;
  }
}

/* Each card merges what used to be two separate cards (a plain score ring,
   and a fuller detailed-insight card elsewhere on the page) into one. Plain,
   static content (2026-09-11 — was briefly a link into the consultation
   flow, removed per explicit "cards shouldn't be clickable" feedback), so no
   hover/focus/cursor affordance here. align-items: center (not flex-start)
   keeps the icon/ring vertically centered against the label+badge+text block
   regardless of how tall that block ends up next to its row-mates. */
.fw-glance-card {
  display: flex;
  align-items: center;
  gap: 0.65rem;
  padding: var(--fw-space-content);
  border-radius: var(--radius-lg);
  border: 1px solid var(--brand-border);
  background: var(--brand-white);
  text-align: left;
  min-height: 0;
  overflow: hidden;
}
.fw-glance-card--attention {
  background: rgba(255, 80, 0, 0.04);
  border-color: rgba(255, 80, 0, 0.2);
}
.fw-glance-card--strong {
  background: rgba(46, 125, 79, 0.05);
  border-color: rgba(46, 125, 79, 0.2);
}
.fw-glance-card__icon {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  color: var(--brand-slate);
  background: rgba(106, 125, 139, 0.12);
}
.fw-glance-card--attention .fw-glance-card__icon {
  color: var(--brand-orange);
  background: rgba(255, 80, 0, 0.12);
}
.fw-glance-card--strong .fw-glance-card__icon {
  color: var(--status-strong);
  background: rgba(46, 125, 79, 0.12);
}
.fw-glance-card__ring {
  position: relative;
  flex-shrink: 0;
  width: 46px;
  height: 46px;
}
.fw-glance-card__number {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-heading);
  font-weight: 700;
  font-size: 0.78rem;
  color: var(--brand-dark);
}
.fw-glance-card__body {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
  min-width: 0;
}
.fw-glance-card__label {
  font-weight: 700;
  font-size: 0.8rem;
  line-height: 1.2;
  color: var(--brand-dark);
  /* Defensive, same reasoning as .fw-glance-card__text below (2026-09-19) —
     the parent card is overflow: hidden inside a height-equalized grid row;
     without a clamp here, a long category name (e.g. "Savings & Emergency
     Preparedness") wrapping to 2 lines could silently lose its second line
     to that clip instead of the card just growing. Ellipsis is the visible,
     honest failure mode; a silent clip is not. */
  display: -webkit-box;
  -webkit-line-clamp: 1;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.fw-glance-card__badge {
  display: inline-block;
  width: fit-content;
  padding: 0.08rem 0.5rem;
  border-radius: 999px;
  background: rgba(106, 125, 139, 0.12);
  font-size: 0.58rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--brand-slate);
}
.fw-glance-card--attention .fw-glance-card__badge {
  background: rgba(255, 80, 0, 0.12);
  color: var(--brand-orange);
}
.fw-glance-card--strong .fw-glance-card__badge {
  background: rgba(46, 125, 79, 0.12);
  color: var(--status-strong);
}
.fw-glance-card__text {
  margin-top: 0.1rem;
  font-size: 0.72rem;
  line-height: 1.3;
  color: var(--brand-slate);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.fw-glance-cta {
  display: flex;
  align-items: center;
  gap: 0.9rem;
  margin-top: var(--fw-space-content);
  padding: 0.75rem 1.1rem;
  border-radius: var(--radius-lg);
  border: 1px solid var(--brand-border);
  background: rgba(239, 231, 220, 0.4);
}
.fw-glance-cta__icon {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  color: var(--brand-orange);
  background: rgba(255, 80, 0, 0.12);
}
.fw-glance-cta__text {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.35rem;
  font-size: 0.82rem;
  color: var(--brand-slate);
}
.fw-glance-cta__text strong {
  color: var(--brand-dark);
  font-size: 0.9rem;
}
.fw-glance-cta__btn {
  flex-shrink: 0;
  padding: 0.6rem 1.2rem;
  font-size: 0.85rem;
  min-height: 40px;
  text-align: center;
}
@media (max-width: 640px) {
  .fw-glance-cta {
    flex-wrap: wrap;
  }
  .fw-glance-cta__btn {
    width: 100%;
  }
}

/* Small addition to the existing glance card body — pairs the status badge with
   computeScoreDecomposition's points-lost figure (js/results.js's buildGlanceCard),
   so the category weight scheme (previously invisible) is visible at a glance. */
.fw-glance-card__meta {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-wrap: wrap;
}
.fw-glance-card__cost {
  font-size: 0.68rem;
  font-weight: 600;
  color: var(--brand-slate);
}

/* --------------------------------------------------------------------------
   Results-page summary banner (2026-09-16). Same visual language as the
   existing .fw-glance-panel/.fw-glance-card above: white/cream cards, 1px
   --brand-border, --radius-lg corners, --brand-orange accents only, serif h2
   headings (global h1/h2/h3 rule already sets font-family: var(--font-heading)).
   No gradients, no drop shadows beyond what .btn already carries. The score-
   decomposition, per-category answer detail, and action-plan sections that
   used to follow this (their own .fw-panel/.fw-decomp-*/.fw-detail-*/
   .fw-action-* rules) were removed again 2026-09-17 along with the results.js
   code that rendered them — see git history to bring either back together. */

/* Overall Wellness Summary's strongest/concern/priority stats,
   sitting above the existing score-panel + glance-grid hero. No margin-top:
   this is always the first section results.js appends to #results-root, so a
   top margin here was only ever adding to .results-container's own
   padding-top — .results-container's padding already places it correctly. */
.fw-summary-banner {
  padding: var(--fw-space-section) 1.5rem;
  border-radius: var(--radius-lg);
  background: rgba(239, 231, 220, 0.5);
}
.fw-summary-banner__line {
  font-size: 1rem;
  line-height: 1.5;
  color: var(--brand-dark);
  /* No max-width (was 52rem) — that was narrower than the panel itself and
     the main cause of "score back." stranding alone on its own short line.
     text-wrap: balance (supported in current Chrome/Edge/Firefox/Safari;
     unsupported browsers just fall back to normal wrapping, never broken)
     also keeps any wrap that does happen even across lines instead of
     leaving 1-2 orphan words. */
  text-wrap: balance;
}
.fw-summary-banner__line strong {
  color: var(--brand-orange);
  font-weight: 700;
}
.fw-summary-stats {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--fw-space-grid);
  margin-top: var(--fw-space-content);
}
.fw-summary-stat {
  padding: var(--fw-card-padding);
  border: 1px solid var(--brand-border);
  border-radius: var(--radius);
  background: var(--brand-white);
}
.fw-summary-stat--priority {
  border-color: rgba(255, 80, 0, 0.25);
  background: rgba(255, 80, 0, 0.04);
}
.fw-summary-stat__label {
  display: block;
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--brand-slate);
}
.fw-summary-stat__value {
  display: block;
  margin-top: 0.25rem;
  font-family: var(--font-heading);
  font-size: 1.05rem;
  color: var(--brand-dark);
}
@media (max-width: 640px) {
  .fw-summary-stats {
    grid-template-columns: 1fr;
  }
}

.results-empty {
  text-align: center;
  padding: 4rem 0;
}
.results-empty p {
  margin: 1rem 0 2rem;
  color: var(--brand-slate);
}

/* ==========================================================================
   Two-column matching experience — a compact list of the 3 matches on the
   left, one detail panel on the right for whichever match is selected.
   .match-columns stretches to fill 100% of whatever height #matches-stage
   has left after the intro (both are flex parents up the chain — see
   #matches-stage/.consultation-results-page above), both columns stretch to
   that same full height.

   2026-09-12's original version forced each of the 3 left cards into an
   equal 1/3 of that height via flex, hard-clipping (overflow: hidden)
   anything that didn't fit — this reliably lost real content (reported
   2026-09-19: the AUM Managed stat's value, added after this was built,
   was being cut off mid-card on ordinary laptop-height windows). Same class
   of bug .profile-panel__body was already fixed for on 2026-09-12 ("a hard
   clip can lose real content... a scrollbar never does") — .match-list now
   gets the identical treatment: cards size to their own natural content
   (flex: 0 0 auto), and the LIST scrolls internally (overflow-y: auto) if
   all 3 don't fit, rather than any one of them losing content.
   ========================================================================== */
.match-columns {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  flex: 1;
  min-height: 0;
  max-width: 80rem;
  width: 100%;
  margin: 0.75rem auto 0;
}
@media (min-width: 900px) {
  .match-columns {
    flex-direction: row;
    align-items: stretch;
  }
  .match-columns__left,
  .match-columns__right {
    min-height: 0;
  }
  .match-columns__left {
    flex: 1.3;
  }
  .match-columns__right {
    flex: 1;
  }
}

.match-list {
  display: flex;
  flex-direction: column;
  height: 100%;
  min-height: 0;
  gap: 0.6rem;
  /* Scrollable, not clipped (2026-09-19, fixing a real bug: the old equal-
     thirds-per-card + hard-clip trick below was silently cutting off the
     stats row — e.g. AUM Managed's value half-visible — the moment 3 cards'
     real content (name + meta + 4-column stats + reason chips) didn't fit
     the available laptop-window height. Same "scrollable, not clipped"
     fix .profile-panel__body already uses for the identical class of
     problem on the right column. */
  overflow-y: auto;
}

/* Left column: compact match rows --------------------------------------- */
.match-list-card {
  position: relative;
  /* Natural height (not the old flex:1 equal-thirds split) — a card is
     exactly as tall as its own content now; .match-list above scrolls if
     all 3 don't fit, rather than squeezing/clipping any one of them. */
  flex: 0 0 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
  border: 1px solid var(--brand-border);
  border-radius: var(--radius-lg);
  padding: 0.85rem 1rem;
  background: var(--brand-white);
  cursor: pointer;
  transition: border-color 180ms ease, background-color 180ms ease, box-shadow 180ms ease;
}
.match-list-card:focus-visible {
  outline: 2px solid var(--brand-orange);
  outline-offset: 2px;
}
.match-list-card--selected {
  border-color: var(--brand-orange);
  border-width: 1.5px;
  background: rgba(255, 80, 0, 0.04);
  box-shadow: 0 8px 20px -8px rgba(255, 80, 0, 0.25);
}
.match-list-card__top {
  flex: 1;
  min-height: 0;
  overflow: visible;
  display: flex;
  gap: 0.7rem;
  align-items: flex-start;
}

.match-photo {
  flex-shrink: 0;
  width: 2.6rem;
  height: 2.6rem;
  border-radius: 50%;
  background: var(--brand-cream);
  color: var(--brand-orange);
  font-family: var(--font-heading);
  font-weight: 700;
  font-size: 1.1rem;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}
.match-photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.match-list-card__body {
  min-width: 0;
  flex: 1;
}
.match-name-row {
  display: flex;
  align-items: center;
  gap: 0.4rem;
}
.match-name-row h3,
.match-name-row h2 {
  font-size: 1.05rem;
}
.verified-badge {
  flex-shrink: 0;
  width: 18px;
  height: 18px;
  border-radius: 999px;
  background: var(--brand-orange);
  border: 2px solid var(--brand-white);
  display: flex;
  align-items: center;
  justify-content: center;
}
.match-meta {
  margin-top: 0.15rem;
  font-size: 0.8rem;
  color: var(--brand-slate);
}

/* Four-column stat row (Experience / Clients Served / Qualification / AUM
   Managed) with vertical dividers between columns, matching the supplied
   reference layout. AUM Managed added 2026-09-17 — "—" for anyone not in the
   AUM export (see directory-client.js's AUM_LOOKUP_URL comment), same as the
   other columns' existing missing-data fallback. */
.match-stats-row {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 0 0.65rem;
  margin-top: 0.4rem;
  padding-top: 0.35rem;
  border-top: 1px solid var(--brand-border);
}
.match-stat {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  padding-left: 0.65rem;
  border-left: 1px solid var(--brand-border);
  min-width: 0;
}
.match-stat:first-child {
  padding-left: 0;
  border-left: none;
}
.match-stat__label {
  font-size: 0.68rem;
  color: var(--brand-slate);
}
.match-stat__value {
  font-weight: 700;
  color: var(--brand-orange);
  font-size: 0.85rem;
}

.match-reasons {
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem;
  margin-top: 0.35rem;
}
.match-reason-chip {
  padding: 0.25rem 0.6rem;
  border-radius: 999px;
  font-size: 0.7rem;
  background: rgba(255, 80, 0, 0.08);
  color: var(--brand-dark);
}
/* The "+N more" chip capping a long qualifications/needTags list (see
   buildProfilePanel's MAX_CHIPS) — visually muted so it reads as "there's
   more, not shown" rather than as just another fact. */
.match-reason-chip--more {
  background: var(--brand-cream);
  color: var(--brand-slate);
  font-weight: 600;
}

/* Full-width row of its own, below .match-list-card__top (2026-09-19,
   fixing a real bug — twice: first as a flex sibling of the name row, where
   its box spanned the row's full width regardless of how short the name
   text was, stranding it far from short names; then corner-pinned via
   position: absolute, which fixed that gap but reserved the same width on
   EVERY line of the name/firm/city text above it, forcing awkward extra
   wrapping on a long firm name like "Aristobizz Financial Services Pvt
   Ltd" even though only the first line actually sat next to the button.
   Neither problem can happen once the button isn't sharing horizontal
   space with that text at all — the name/firm/city block above always gets
   the entire card width, on every line, and the button gets its own
   full-width tap target below it instead of a small corner pill. */
.match-select-btn {
  display: block;
  width: 100%;
  margin-top: 0.85rem;
  padding: 0.6rem;
  border-radius: 999px;
  border: 1.5px solid var(--brand-orange);
  background: var(--brand-white);
  color: var(--brand-orange);
  font-family: var(--font-body);
  font-size: 0.85rem;
  font-weight: 700;
  text-align: center;
  cursor: pointer;
  transition: background-color 180ms ease, color 180ms ease;
}
.match-select-btn:hover {
  background: rgba(255, 80, 0, 0.08);
}
.match-select-btn--selected {
  background: var(--brand-orange);
  color: var(--brand-white);
  cursor: default;
}
.match-select-btn--selected:hover {
  background: var(--brand-orange);
}

/* Right column: selected-PFP detail panel -------------------------------- */
.profile-panel {
  /* Was position: sticky — replaced 2026-09-12 along with the rest of this
     rebuild: sticky only mattered for a page that scrolls, and this page no
     longer does. Stretches to fill .match-columns__right's full height
     instead (its parent is flex:1 in a stretched row — see .match-columns),
     display:flex + overflow:hidden so .profile-panel__body (flex:1 below)
     can claim exactly the remaining space and clip rather than overflow. */
  height: 100%;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  border: 1px solid var(--brand-border);
  border-radius: var(--radius-lg);
  background: var(--brand-white);
  padding: 1.1rem 1.35rem;
  box-shadow: 0 12px 30px rgba(0, 0, 0, 0.06);
}
.profile-panel__header {
  display: flex;
  gap: 1rem;
  align-items: center;
}
.profile-panel__photo {
  flex-shrink: 0;
  width: 4.5rem;
  height: 4.5rem;
  border-radius: 50%;
  background: var(--brand-cream);
  color: var(--brand-orange);
  font-family: var(--font-heading);
  font-weight: 700;
  font-size: 1.6rem;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}
.profile-panel__photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.profile-panel__identity {
  min-width: 0;
}

.profile-panel__directory-link {
  display: inline-block;
  margin-top: 0.75rem;
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--brand-orange);
  text-decoration: none;
}
.profile-panel__directory-link:hover {
  text-decoration: underline;
}

.profile-panel__badges {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin-top: 0.75rem;
}
.profile-panel__badge {
  padding: 0.3rem 0.75rem;
  border-radius: 999px;
  background: var(--brand-cream);
  color: var(--brand-dark);
  font-size: 0.75rem;
  font-weight: 600;
}

/* One flowing view, not tabs (2026-09-11) — each section is just a heading +
   content, stacked, with a hairline divider above the first one. */
.profile-panel__body {
  flex: 1;
  min-height: 0;
  /* Scrollable, not clipped (2026-09-12, explicit instruction) — .match-cta-btn
     stays put regardless: it's a separate flex item after this one in
     .profile-panel's column, sized to its own content (flex-shrink: 0), so it
     never scrolls out of view no matter how much this body scrolls. */
  overflow-y: auto;
  margin-top: 0.85rem;
  padding-top: 0.7rem;
  border-top: 1px solid var(--brand-border);
}
.profile-panel__body h3 {
  font-size: 0.9rem;
}
.profile-panel__body h3:not(:first-child) {
  margin-top: 1rem;
}
.profile-panel__facts {
  margin: 0.85rem 0 0;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.6rem 1rem;
}
.profile-panel__facts > div {
  min-width: 0;
}
.profile-panel__facts dt {
  font-size: 0.72rem;
  color: var(--brand-slate);
}
.profile-panel__facts dd {
  margin: 0.15rem 0 0;
  font-size: 0.88rem;
  font-weight: 600;
  color: var(--brand-dark);
}
.profile-panel__reasons {
  list-style: none;
  margin: 0.85rem 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
}
.profile-panel__reasons li {
  display: flex;
  align-items: flex-start;
  gap: 0.6rem;
  font-size: 0.9rem;
  color: var(--brand-dark);
}
.profile-panel__reasons svg {
  flex-shrink: 0;
  margin-top: 0.15rem;
  color: var(--brand-orange);
}
.profile-panel__chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
}

.match-cta-btn {
  flex-shrink: 0;
  width: 100%;
  margin-top: 0.85rem;
  padding: 0.75rem;
  border-radius: 999px;
  border: 1.5px solid var(--brand-border);
  background: var(--brand-white);
  color: var(--brand-slate);
  font-family: var(--font-body);
  font-size: 0.95rem;
  font-weight: 500;
  cursor: not-allowed;
}
.match-cta-btn--enabled {
  border-color: var(--brand-orange);
  background: var(--brand-orange);
  color: var(--brand-white);
  font-weight: 700;
  cursor: pointer;
  transition: background-color 200ms ease;
}
.match-cta-btn--enabled:hover {
  background: #e64800;
}

@media (max-width: 899px) {
  .profile-panel {
    height: auto;
    overflow: visible;
  }
  .profile-panel__body {
    overflow: visible;
  }
  /* .match-list-card__top no longer needs an override here — it's
     overflow: visible at every width now (2026-09-19), not just below 900px. */

  /* 2x2 grid, not the desktop's 4-in-a-row (2026-09-19 mobile redesign) —
     4 columns in a single stacked-width card left "₹35 Cr"/qualification
     values cramped into ~80px slivers; a full 1-column stack (the previous
     mobile treatment) was clear but doubled each card's scroll height for
     no real gain over a 2-column grid, which stays just as readable in
     half the vertical space. Applies across the whole stacked-layout range
     (phones AND tablets in portrait — .match-columns itself stacks below
     900px), not just narrow phones. */
  .match-stats-row {
    grid-template-columns: repeat(2, 1fr);
    gap: 0.5rem 0.65rem;
  }
  .match-stat:nth-child(odd) {
    padding-left: 0;
    border-left: none;
  }
  .match-stat:nth-child(n + 3) {
    padding-top: 0.5rem;
    border-top: 1px solid var(--brand-border);
  }
  /* .skeleton-stats-row needs no override here — its own mobile-first rules
     (above, near .finding-loader) already default to this same 2-column
     grid and only widen to 4 at 900px, so the loading state and the loaded
     state agree at every width without duplicating the rule here. */
}
@media (max-width: 480px) {
  /* .match-list-card__top no longer needs flex-wrap, and .match-select-btn
     no longer needs a margin override to line up under the name (2026-09-19)
     — now that the button is corner-pinned (position: absolute) instead of a
     flex sibling in this row, it never wraps or needs manual alignment at
     any width. */
  .profile-panel__header {
    flex-wrap: wrap;
  }
}

/* ==========================================================================
   PFP Portal — Tier 2
   ========================================================================== */
.portal-container {
  max-width: 40rem;
  padding-top: 3rem;
  padding-bottom: 6rem;
}
.portal-container--wide {
  max-width: 64rem;
}

/* Signed-out landing explainer ("For Financial Advisors") — the .steps/.step-card/
   .section-heading rules it reuses are the same ones the home page's "How It Works"
   section defines (styles.css's generic step-card block), kept deliberately
   unscoped so this portal page can use them too without duplicating the pattern. */
.portal-explainer {
  margin-bottom: 4rem;
}
.portal-explainer__note {
  max-width: 34rem;
  margin: 2.5rem auto 0;
  text-align: center;
}

/* Dashboard shell — the signed-in, opted-in profile view only. Every other
   portal state (signed-out, link-sent, opt-in, not-found) stays a narrow
   centered card via .portal-container's default width. */
.portal-dashboard {
  display: flex;
  flex-direction: column;
  gap: 1.5rem;
  align-items: flex-start;
}
.portal-sidebar {
  width: 100%;
  border: 1px solid var(--brand-border);
  border-radius: var(--radius-lg);
  padding: 1.5rem;
}
.portal-sidebar__name {
  margin-top: 0.35rem;
  font-size: 1.35rem;
}
.portal-sidebar__nav {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-top: 1.5rem;
}
.portal-sidebar__link {
  padding: 0.6rem 1rem;
  border: none;
  border-radius: var(--radius-lg);
  background: transparent;
  color: var(--brand-dark);
  font-family: inherit;
  font-size: 0.9rem;
  font-weight: 500;
  text-align: left;
  cursor: pointer;
  transition: background-color 150ms ease, color 150ms ease;
}
.portal-sidebar__link:hover {
  background: var(--brand-cream);
}
.portal-sidebar__link.is-active {
  background: var(--brand-orange);
  color: var(--brand-white);
}
.portal-sidebar__opt-out {
  display: block;
  width: 100%;
  margin-top: 1.5rem;
  padding-top: 1.5rem;
  border: none;
  border-top: 1px solid var(--brand-border);
  background: transparent;
  color: var(--brand-slate);
  font-family: inherit;
  font-size: 0.85rem;
  text-align: left;
  cursor: pointer;
}
.portal-sidebar__opt-out:hover {
  color: var(--brand-orange);
}
.portal-dashboard__panel {
  flex: 1;
  min-width: 0;
  width: 100%;
  border: 1px solid var(--brand-border);
  border-radius: var(--radius-lg);
  padding: 2.5rem;
}
@media (min-width: 768px) {
  .portal-dashboard {
    flex-direction: row;
    align-items: flex-start;
  }
  .portal-sidebar {
    width: 15rem;
    flex-shrink: 0;
    position: sticky;
    top: 6rem;
  }
  .portal-sidebar__nav {
    flex-direction: column;
  }
}
.portal-card {
  border: 1px solid var(--brand-border);
  border-radius: var(--radius-lg);
  padding: 2.5rem;
}
.portal-card--narrow {
  max-width: 30rem;
  margin: 0 auto;
  text-align: center;
}

/* No-login booking form (js/booking.js renderBookingConsentNoAuth) — name,
   phone, email, preferred-time chips, consent, and a submit button all have
   to fit in one viewport with no scroll, which the rest of this file's
   generous form spacing (built for one or two fields at a time) doesn't
   allow, so this compacts every piece of it: tighter labels, denser inputs,
   a 2-column name/phone row, and a merged consent line instead of a
   separate disclosure paragraph above it. #booking-root.booking-guest-page
   also drops .portal-container's own top/bottom padding, and js/booking.js
   tightens .flow-main's padding directly while this screen is showing (that
   padding is tuned for a vertically-centered one-liner elsewhere on this
   page, not a form this size). */
#booking-root.booking-guest-page {
  max-width: 72rem;
  width: 100%;
  padding: 1.5rem 1.25rem 2.5rem;
}
.booking-guest-layout {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1.5rem;
  align-items: start;
}
@media (min-width: 900px) {
  .booking-guest-layout {
    grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr);
    gap: 2rem;
  }
  .booking-guest-card--aside {
    position: sticky;
    top: 1.5rem;
  }
}
.booking-guest-card {
  padding: 1.75rem;
  text-align: left;
  background: #fff;
}
.booking-guest-card--aside {
  background: var(--brand-cream);
  border-color: transparent;
}
.booking-guest-card .eyebrow {
  margin: 0;
}
.booking-guest-title {
  margin: 0.35rem 0 0;
  font-size: 1.6rem;
  font-family: var(--font-heading);
}
.booking-guest-card .portal-heading {
  margin-top: 0.25rem;
  font-size: 1.6rem;
}
.booking-guest-card .portal-sub {
  margin-top: 0.4rem;
  font-size: 0.95rem;
}
.booking-guest-card .portal-form {
  margin-top: 1.25rem;
  display: grid;
  gap: 0.75rem;
}
.booking-guest-card .name-phone-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1rem;
}
.booking-guest-card .portal-field-label {
  display: block;
  margin-top: 1.1rem;
  font-size: 0.8rem;
}
.booking-guest-card .portal-form > .portal-field-label {
  margin: 0 0 -0.4rem;
}
.booking-guest-card .text-input {
  margin-top: 0.35rem;
  padding: 0.65rem 0.9rem;
  font-size: 0.95rem;
}
.booking-guest-card .portal-chip-grid {
  gap: 0.5rem;
  margin-top: 0.6rem;
}
.booking-guest-card .portal-chip {
  padding: 0.45rem 0.8rem;
  font-size: 0.82rem;
}
.booking-guest-card #booking-guest-time-note {
  margin-top: 0.75rem;
}
.booking-guest-card--aside .booking-summary {
  margin-top: 1.25rem;
  background: #fff;
}
.booking-guest-card .consent-check {
  margin-top: 1rem;
  padding: 0.7rem 0.85rem;
  gap: 0.65rem;
  background: #fff;
}
.booking-guest-card .consent-check span {
  font-size: 0.82rem;
  line-height: 1.45;
}
.booking-guest-card .portal-submit-btn {
  margin-top: 1rem;
}
@media (max-width: 560px) {
  .booking-guest-card {
    padding: 1.25rem;
  }
  .booking-guest-card .name-phone-row {
    grid-template-columns: 1fr;
  }
}
.portal-heading {
  margin-top: 0.5rem;
  font-size: 1.75rem;
}
.portal-sub {
  margin-top: 0.85rem;
  font-size: 1rem;
  line-height: 1.6;
  color: var(--brand-slate);
}
.portal-card--narrow #login-form {
  margin-top: 1.75rem;
  display: flex;
  flex-direction: column;
  gap: 1rem;
}
.portal-submit-btn {
  width: 100%;
}

/* "Refer a Friend" block — booking.js's renderConfirmed, only when this
   booking got a referral_code assigned (0037_referrals.sql). */
.referral-block {
  margin-top: 1.5rem;
  padding: 1rem 1.1rem;
  background: rgba(255, 80, 0, 0.06);
  border: 1px solid rgba(255, 80, 0, 0.2);
  border-radius: var(--radius);
  text-align: left;
}
.referral-block__congrats {
  margin: 0;
  font-weight: 700;
  color: var(--brand-orange);
}
.referral-block__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem;
  margin-top: 0.85rem;
}
.referral-block__actions .btn {
  flex: 1 1 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
}

/* Google sign-in — deliberately NOT styled as .btn-primary (orange fill). Google's
   own branding guidance discourages recoloring their button, and a neutral treatment
   also visually signals "this is Google's identity system," not a generic form
   submit — same reasoning the brand kit already applies to icons (single consistent
   language, no ad-hoc styling per instance). Radius/sizing still match this site's
   pill buttons so it doesn't look like a foreign component. */
.google-signin-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.65rem;
  width: 100%;
  margin-top: 1.75rem;
  padding: 0.85rem 1.75rem;
  border-radius: 999px;
  border: 1.5px solid var(--brand-border);
  background: var(--brand-white);
  color: var(--brand-dark);
  font-family: var(--font-body);
  font-weight: 700;
  font-size: 0.95rem;
  cursor: pointer;
  min-height: 44px;
  transition: border-color 150ms ease, background-color 150ms ease;
}
.google-signin-btn:hover {
  border-color: var(--brand-orange);
  background: rgba(255, 80, 0, 0.03);
}
.google-signin-btn:disabled {
  opacity: 0.6;
  cursor: not-allowed;
}

.portal-error {
  margin-top: 1rem;
  font-size: 0.9rem;
  color: var(--brand-orange);
}
.portal-loading {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 4rem 0;
}
/* booking.js's completeBooking() loader — same cross-fade technique as
   results.js's .finding-loader__cycle (fade out, swap text, fade back in),
   just a plain paragraph here rather than a display headline since this
   sits under a small spinner, not a whole loading stage of its own. */
.booking-loader__cycle {
  margin-top: 1rem;
  color: var(--brand-slate);
  transition: opacity 220ms ease, transform 220ms ease;
}
.booking-loader__cycle.is-fading {
  opacity: 0;
  transform: translateY(6px);
}
@media (prefers-reduced-motion: reduce) {
  .booking-loader__cycle {
    transition: none;
  }
}

.portal-form {
  margin-top: 2rem;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}
.portal-field-label {
  margin-top: 1.5rem;
  font-size: 0.85rem;
  font-weight: 700;
  color: var(--brand-dark);
}
.portal-form .text-input {
  margin-top: 0.6rem;
}
.option-grid--row {
  flex-direction: row;
  flex-wrap: wrap;
  margin-top: 0.6rem;
}
.option-grid--row .option-card {
  flex: 1;
  min-width: 7rem;
  justify-content: center;
  padding: 0.75rem 1rem;
}

/* 5-point agree/disagree scale (questions.js's LIKERT_LABELS) — one row of five
   on wide screens, wraps to two rows on narrow ones rather than shrinking text. */
.option-grid--likert {
  grid-template-columns: repeat(5, 1fr);
  gap: 0.5rem;
}
.option-grid--likert .option-card {
  flex-direction: column-reverse;
  text-align: center;
  gap: 0.5rem;
  padding: 0.85rem 0.5rem;
}
.option-grid--likert .option-card span {
  font-size: 0.85rem;
  line-height: 1.2;
}
@media (max-width: 640px) {
  .option-grid--likert {
    grid-template-columns: repeat(2, 1fr);
  }
}

/* Bordered box around the whole time-preference question (2026-09-15) — same
   visual language as .consent-check below it, so this reads as its own
   distinct, grouped field instead of a few pills floating loose on the page. */
.portal-time-box {
  margin-top: 1.25rem;
  padding: 1.1rem 1.25rem;
  border: 1.5px solid var(--brand-border);
  border-radius: var(--radius);
}
.portal-time-box .text-input {
  margin-top: 0.75rem;
}
.portal-chip-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-top: 0.6rem;
}
.slot-date-group + .slot-date-group {
  margin-top: 1.5rem;
}
.slot-date-heading {
  font-size: 0.85rem;
  font-weight: 700;
  color: var(--brand-dark);
}
.portal-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.5rem 0.9rem;
  border: 1.5px solid var(--brand-border);
  border-radius: 999px;
  font-size: 0.85rem;
  cursor: pointer;
  transition: border-color 150ms ease, background-color 150ms ease;
}
.portal-chip input {
  width: 14px;
  height: 14px;
  accent-color: var(--brand-orange);
}
.portal-chip:hover {
  border-color: var(--brand-orange);
}
.portal-chip.is-selected {
  border-color: var(--brand-orange);
  background: rgba(255, 80, 0, 0.06);
  font-weight: 500;
}
/* Call-type chip is a plain <button class="portal-chip">, not a checkbox
   label — .portal-chip's own base/hover/is-selected rules already cover it;
   this just removes the button-element defaults (border/background/font)
   .portal-chip doesn't already reset via <label>. */
.call-type-chip {
  background: var(--brand-white);
  font-family: var(--font-body);
}

/* "Summary of your details" (2026-09-17) — a plain recap card on both booking
   consent screens, shown right before the consumer confirms. */
.booking-summary {
  margin: 1rem 0 0;
  padding: 1.1rem 1.25rem;
  background: var(--brand-cream);
  border-radius: var(--radius-lg);
}
.booking-summary__title {
  margin: 0 0 0.85rem;
  padding-bottom: 0.6rem;
  border-bottom: 1px solid var(--brand-border);
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--brand-orange);
}
.booking-summary__grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.85rem 1.25rem;
  margin: 0;
}
.booking-summary__item {
  min-width: 0;
}
.booking-summary__item.is-wide {
  grid-column: 1 / -1;
}
.booking-summary__item dt {
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--brand-slate);
}
.booking-summary__item dd {
  margin: 0.15rem 0 0;
  font-size: 0.92rem;
  line-height: 1.4;
  color: var(--brand-dark);
  overflow-wrap: break-word;
}
@media (max-width: 420px) {
  .booking-summary__grid {
    grid-template-columns: 1fr;
  }
}

/* Compact multi-select "day of the week" dropdown (js/booking.js's
   renderDayDropdown) — replaces a 7-pill grid that, combined with call-type
   and the summary above, pushed the no-login booking form past one
   viewport's height. */
.day-dropdown {
  position: relative;
  margin-top: 0.3rem;
}
.day-dropdown__toggle {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.55rem 0.8rem;
  border: 1.5px solid var(--brand-border);
  border-radius: var(--radius);
  background: var(--brand-white);
  font-family: var(--font-body);
  font-size: 0.88rem;
  color: var(--brand-dark);
  cursor: pointer;
  text-align: left;
}
.day-dropdown__toggle:hover {
  border-color: var(--brand-orange);
}
.day-dropdown__label {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.day-dropdown__panel {
  position: absolute;
  z-index: 5;
  top: calc(100% + 0.3rem);
  left: 0;
  right: 0;
  display: grid;
  gap: 0.15rem;
  padding: 0.5rem;
  background: var(--brand-white);
  border: 1.5px solid var(--brand-border);
  border-radius: var(--radius);
  box-shadow: 0 8px 20px rgba(0, 0, 0, 0.08);
}
.day-dropdown__option {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.3rem 0.4rem;
  border-radius: 6px;
  font-size: 0.85rem;
  cursor: pointer;
}
.day-dropdown__option:hover {
  background: rgba(255, 80, 0, 0.05);
}
.day-dropdown__option input {
  width: 14px;
  height: 14px;
  accent-color: var(--brand-orange);
}
.portal-removable-chip {
  cursor: default;
}
.portal-removable-chip__remove {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.1rem;
  height: 1.1rem;
  margin: -0.1rem -0.3rem -0.1rem 0.1rem;
  padding: 0;
  border: none;
  border-radius: 999px;
  background: transparent;
  color: var(--brand-slate);
  font-size: 1rem;
  line-height: 1;
  cursor: pointer;
}
.portal-removable-chip__remove:hover {
  background: rgba(255, 80, 0, 0.15);
  color: var(--brand-orange);
}
.portal-field-note {
  margin-top: 0.5rem;
  font-size: 0.8rem;
  color: var(--brand-slate);
}
.portal-field-note a {
  color: var(--brand-orange);
  text-decoration: underline;
  font-weight: 500;
}
.portal-field-note a:hover {
  color: #e64800;
}

.portal-booking-card {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.9rem 1rem;
  border: 1px solid var(--brand-border);
  border-radius: 0.5rem;
  margin-top: 0.6rem;
  text-align: left;
}
.portal-booking-card__name {
  font-weight: 600;
  color: var(--brand-dark);
}
.portal-booking-card__actions {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-shrink: 0;
}
.portal-booking-status {
  margin-left: 0.5rem;
  padding: 0.15rem 0.55rem;
  border-radius: 999px;
  background: var(--brand-cream);
  color: var(--brand-slate);
  font-size: 0.7rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  vertical-align: middle;
}
.portal-booking-status--completed {
  background: var(--brand-mint);
  color: var(--brand-dark);
}

.portal-submit-btn {
  margin-top: 2rem;
}
.portal-save-status {
  margin-top: 0.75rem;
  font-size: 0.9rem;
  color: var(--brand-orange);
  text-align: center;
}
.portal-save-status--error {
  /* No error/destructive color exists in the Brand Kit — same open gap flagged
     back when the assessment form was built. Reusing Brand Dark, not inventing
     an off-brand red, until a real decision is made (design plan §7). */
  color: var(--brand-dark);
  font-weight: 700;
}
.portal-opt-out-btn {
  display: block;
  margin: 2rem auto 0;
}

/* ==========================================================================
   Admin dashboard — master plan §8
   ========================================================================== */
.admin-stat-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
  gap: 1rem;
  margin-top: 1.5rem;
}
.admin-stat-card {
  border: 1px solid var(--brand-border);
  border-radius: var(--radius);
  padding: 1.25rem;
  text-align: center;
}
.admin-stat-card__value {
  font-family: var(--font-heading);
  font-size: 1.9rem;
  color: var(--brand-dark);
}
.admin-stat-card__label {
  margin-top: 0.35rem;
  font-size: 0.8rem;
  color: var(--brand-slate);
}

.admin-section {
  margin-top: 2.5rem;
}
.admin-section__title {
  font-size: 1.2rem;
}
.admin-section__header-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
}
.admin-section__header-row .admin-section__title {
  margin: 0;
}
.admin-section__hint {
  margin-top: 0.35rem;
  font-size: 0.82rem;
  color: var(--brand-slate);
}

/* Settings tab — toggle row (currently just the Google auth switch) */
.admin-toggle-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
  margin-top: 1rem;
  padding: 1.25rem;
  border: 1px solid var(--brand-border);
  border-radius: var(--radius-lg);
}
.admin-toggle-row__label {
  font-weight: 700;
}
.admin-toggle-row__desc {
  margin-top: 0.35rem;
  max-width: 34rem;
  font-size: 0.85rem;
  line-height: 1.5;
  color: var(--brand-slate);
}
.admin-toggle-switch {
  flex-shrink: 0;
  position: relative;
  width: 3rem;
  height: 1.75rem;
  border-radius: 999px;
  border: none;
  background: var(--brand-border);
  cursor: pointer;
  transition: background-color 150ms ease;
}
.admin-toggle-switch.is-on {
  background: var(--brand-orange);
}
.admin-toggle-switch:disabled {
  opacity: 0.6;
  cursor: default;
}
.admin-toggle-switch__knob {
  position: absolute;
  top: 0.2rem;
  left: 0.2rem;
  width: 1.35rem;
  height: 1.35rem;
  border-radius: 999px;
  background: var(--brand-white);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25);
  transition: transform 150ms ease;
}
.admin-toggle-switch.is-on .admin-toggle-switch__knob {
  transform: translateX(1.25rem);
}

.admin-bar-row {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin-top: 0.6rem;
}
.admin-bar-row__label {
  width: 9rem;
  flex-shrink: 0;
  font-size: 0.85rem;
  color: var(--brand-dark);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.admin-bar-row__track {
  flex: 1;
  height: 0.6rem;
  background: var(--brand-cream);
  border-radius: 999px;
  overflow: hidden;
}
.admin-bar-row__fill {
  height: 100%;
  background: var(--brand-orange);
  border-radius: 999px;
}
.admin-bar-row__value {
  width: 3rem;
  flex-shrink: 0;
  text-align: right;
  font-size: 0.82rem;
  font-weight: 700;
  color: var(--brand-dark);
}

.admin-funnel {
  margin-top: 1.5rem;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}
.admin-funnel__step {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.7rem 1rem;
  border: 1px solid var(--brand-border);
  border-radius: var(--radius);
  font-size: 0.9rem;
}
.admin-funnel__step-count {
  font-weight: 700;
  color: var(--brand-orange);
}

.admin-table-wrap {
  margin-top: 1.5rem;
  overflow-x: auto;
  border: 1px solid var(--brand-border);
  border-radius: var(--radius);
}
.admin-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.85rem;
}
.admin-table th,
.admin-table td {
  padding: 0.65rem 0.9rem;
  text-align: left;
  white-space: nowrap;
  border-bottom: 1px solid var(--brand-border);
  /* Table cells default to vertical-align:middle — the title column is two
     lines (title + slug) while every other column is one, so without this
     every other column centers against that taller row instead of lining up
     with the title's own top line. */
  vertical-align: top;
}
.admin-table th {
  background: var(--brand-cream);
  font-weight: 700;
  color: var(--brand-dark);
}
.admin-table tr:last-child td {
  border-bottom: none;
}
.admin-refresh-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  margin-top: 1rem;
}
.admin-generated-at {
  font-size: 0.78rem;
  color: var(--brand-slate);
}

/* ---------- Data Rights Requests (admin.js) — the tool that fulfils
   access/correction/erasure requests in a few clicks instead of hand-written
   SQL. Reuses .admin-section/.admin-table/.text-input above for everything
   that already fits; these are just the pieces unique to this panel. ---------- */
.admin-lookup-row {
  display: flex;
  gap: 0.75rem;
  flex-wrap: wrap;
  margin-top: 0.5rem;
}
.admin-lookup-row .text-input {
  flex: 1;
  min-width: 14rem;
}
.admin-consumer-card {
  margin-top: 1.5rem;
  padding: 1.25rem 1.5rem;
  border: 1px solid var(--brand-border);
  border-radius: var(--radius-lg);
  background: var(--brand-white);
}
.admin-consumer-card + .admin-consumer-card {
  margin-top: 1rem;
}
.admin-field-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 0.9rem;
  margin-top: 0.75rem;
}
.admin-field-grid label {
  display: block;
  margin-bottom: 0.3rem;
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--brand-slate);
}
@media (max-width: 560px) {
  .admin-field-grid { grid-template-columns: 1fr; }
}
.admin-meta-row {
  margin-top: 0.9rem;
  padding-top: 0.9rem;
  border-top: 1px dashed var(--brand-border);
  font-size: 0.8rem;
  color: var(--brand-slate);
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem 1.25rem;
}
.admin-consumer-actions {
  margin-top: 1.1rem;
  display: flex;
  gap: 0.6rem;
  flex-wrap: wrap;
}
.admin-danger-btn {
  border: 1.5px solid #dc2626;
  color: #dc2626;
  background: var(--brand-white);
}
.admin-danger-btn:hover {
  background: rgba(220, 38, 38, 0.06);
}
.admin-sub-heading {
  margin: 1.1rem 0 0.5rem;
  font-size: 0.85rem;
  font-weight: 700;
  color: var(--brand-dark);
}
.admin-save-status {
  margin-left: 0.75rem;
  font-size: 0.82rem;
  font-weight: 600;
}
.admin-save-status.is-ok { color: #15803d; }
.admin-save-status.is-err { color: #dc2626; }

/* Tools hub (tools.html) — plain marketing card grid, same idiom as the
   home page's .steps/.step-card. */
.tools-hero {
  padding: 2.5rem 0 6rem;
}
/* No eyebrow/description above the h2 here (unlike other .section-heading
   uses), so drop the eyebrow-clearance top margin the shared rule adds. */
.tools-hero .section-heading h2 {
  margin-top: 0;
}
.tools-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 1.5rem;
  margin-top: 2.5rem;
  align-items: start;
  /* Own stacking context, so the z-index values below only ever compete
     against each other - never against something unrelated elsewhere on
     the page. */
  isolation: isolate;
}
/* The actual grid item. Stays a normal in-flow box sized to a card's
   COLLAPSED content only - .tool-card inside it is absolutely positioned,
   so it contributes nothing to this box's height. Without the fixed
   min-height here, an empty slot would collapse to 0 and the grid would
   have nowhere to put anything. 11.3rem matches the real collapsed card
   height (measured: ~178px at this padding/font-size) with a small buffer
   for cross-browser font-metric differences. */
.tool-card-slot {
  position: relative;
  min-height: 11.3rem;
  /* Explicit (not auto) so this grid item becomes a directly-comparable
     stacking unit against its sibling slots - see the note below on why
     that specifically, not the .tool-card inside it, is what has to carry
     the z-index. */
  z-index: 1;
}
/* Elevates the SLOT (grid item), not the .tool-card inside it. This is
   the actual fix for the reported overlap bug, and it's a real CSS Grid
   gotcha: a grid item with z-index:auto paints as one atomic unit in DOM
   order - a descendant's z-index can only reorder painting *within* that
   unit, it can never outrank a sibling grid item's unit. Confirmed live
   with Playwright: giving .tool-card itself z-index:10 on hover measured
   correctly via getComputedStyle, but REAL Statement (a later, unrelated
   grid item) still visually painted on top of the hovered Wealth
   Staircase card underneath it, because REAL Statement's *slot* was
   still z-index:auto and simply painted its whole unit after Wealth
   Staircase's slot, regardless of what z-index its descendant carried. */
.tool-card-slot:has(.tool-card:hover),
.tool-card-slot:has(.tool-card:focus-visible) {
  z-index: 10;
}
.tool-card {
  /* Positioned against its own .tool-card-slot (not the grid), so
     expanding on hover grows past the slot's bottom edge IN PLACE -
     without pushing the grid's row-track height, which would otherwise
     shove every unrelated card below it down the page just because one
     card elsewhere expanded (reported: hovering Retirement Calculator
     was shifting REAL Statement, a card in a completely different
     column, straight down).

     Growing in place instead of pushing means an expanded card can
     overlap whatever sits directly below it - that's expected for this
     pattern (a hover-expand overlay), not a bug, as long as the expanded
     card's slot is the one elevated (see .tool-card-slot:has above). */
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  padding: 2rem;
  border: 1px solid var(--brand-border);
  border-radius: var(--radius-lg);
  background: var(--brand-white);
  text-decoration: none;
  color: inherit;
  transition: border-color 150ms ease, transform 150ms ease, box-shadow 150ms ease, bottom 200ms ease;
}
.tool-card:hover,
.tool-card:focus-visible,
.tool-card:focus-within {
  bottom: auto;
  border-color: var(--brand-orange);
  transform: translateY(-2px);
  box-shadow: 0 16px 32px rgba(0, 0, 0, 0.12);
}
.tool-card h3 {
  font-size: 1.25rem;
}
/* Description stays collapsed until the card is hovered/focused, per request -
   revealed instead of always-on, so the card list reads shorter by default. */
.tool-card p {
  color: var(--brand-slate);
  font-size: 0.95rem;
  line-height: 1.6;
  max-height: 0;
  margin: 0;
  opacity: 0;
  overflow: hidden;
  transition: max-height 200ms ease, opacity 200ms ease, margin-top 200ms ease;
}
.tool-card:hover p,
.tool-card:focus-visible p,
.tool-card:focus-within p {
  max-height: 8rem;
  margin-top: 0.25rem;
  opacity: 1;
}
.tool-card .btn {
  align-self: flex-start;
  margin-top: 1rem;
}

/* ==========================================================================
   The Financial Wellbeing Journey — five stages, badge outline fills solid
   only on the final stage (the outcome), everything else stays a plain
   orange-on-white outline. No rainbow per-stage colors (reference site uses
   one), single brand-orange token only, per design plan §6.1's constraint.
   ========================================================================== */
.journey-section {
  padding: 6rem 0;
  border-top: 1px solid var(--brand-border);
}
.journey-grid {
  display: grid;
  gap: 1.25rem;
  margin-top: 3rem;
}
@media (min-width: 640px) {
  .journey-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}
@media (min-width: 960px) {
  .journey-grid {
    grid-template-columns: repeat(5, 1fr);
  }
}
.journey-stage {
  padding: 1.5rem 1.25rem;
  border-radius: var(--radius-lg);
  background: var(--brand-white);
  border: 1px solid var(--brand-border);
  text-align: center;
}
.journey-stage__badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.25rem;
  height: 2.25rem;
  border-radius: 999px;
  background: var(--brand-white);
  border: 2px solid var(--brand-orange);
  color: var(--brand-orange);
  font-family: var(--font-heading);
  font-weight: 700;
  font-size: 1.05rem;
}
.journey-stage h3 {
  margin-top: 1rem;
  font-size: 1rem;
}
.journey-stage p {
  margin-top: 0.5rem;
  font-size: 0.82rem;
  line-height: 1.55;
  color: var(--brand-slate);
}
.journey-cta-line {
  margin: 3rem auto 0;
  text-align: center;
  font-size: 0.95rem;
  color: var(--brand-slate);
}
.journey-cta-line a {
  color: var(--brand-orange);
  font-weight: 700;
  text-decoration: none;
}
.journey-cta-line a:hover {
  text-decoration: underline;
}

/* ==========================================================================
   Admin — Blog Editorial (admin.html's Blog Editorial tab)
   ========================================================================== */
.admin-tabs {
  display: flex;
  gap: 0.5rem;
  margin-bottom: 1.5rem;
  border-bottom: 1px solid var(--brand-border);
}
.admin-tab {
  padding: 0.6rem 1rem;
  border: none;
  background: none;
  font-family: var(--font-body);
  font-size: 0.9rem;
  font-weight: 700;
  color: var(--brand-slate);
  cursor: pointer;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
}
.admin-tab:hover {
  color: var(--brand-dark);
}
.admin-tab.is-active {
  color: var(--brand-orange);
  border-bottom-color: var(--brand-orange);
}
.admin-blog-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  margin-bottom: 1.5rem;
}
.admin-blog-slug {
  margin-top: 0.2rem;
  font-size: 0.78rem;
  color: var(--brand-slate);
}
.admin-blog-status {
  display: inline-block;
  padding: 0.2rem 0.6rem;
  border-radius: 999px;
  font-size: 0.72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.02em;
}
.admin-blog-status--draft {
  background: var(--brand-cream);
  color: var(--brand-slate);
}
.admin-blog-status--published {
  background: var(--brand-mint);
  color: #15803d;
}
/* A <div> INSIDE the <td>, deliberately not display:flex on the <td> itself —
   that used to make this one cell's row-height/border math render at a
   slightly different sub-pixel position than its plain sibling cells (visible
   as the row divider line stepping right at this column's boundary instead
   of running straight across). Keeping the <td> a normal table-cell and
   putting flex on this wrapper instead avoids that entirely. */
.admin-blog-actions {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-wrap: wrap;
}
/* The default .btn sizing (padding 0.85rem 1.75rem, min-height 44px) is tuned
   for standalone CTAs, not three actions sharing one dense table cell — at
   full size only two fit per row before wrapping, and .btn-ghost has no
   border at all, so Edit/Unpublish read as plain text next to Delete's
   obviously-a-button red pill. Compact + consistently outlined here so all
   three read as one button group, same size, same row. */
.admin-blog-actions .btn {
  padding: 0.4rem 0.9rem;
  font-size: 0.78rem;
  min-height: 30px;
}
.admin-blog-actions .btn-ghost {
  border: 1.5px solid var(--brand-border);
}
.admin-blog-editor {
  margin-top: 1.5rem;
}
.admin-field-grid--single {
  grid-template-columns: 1fr;
}
.admin-blog-body-input {
  width: 100%;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.85rem;
  line-height: 1.5;
  resize: vertical;
}
.admin-blog-image-preview {
  display: flex;
  align-items: center;
  gap: 1rem;
  margin-bottom: 0.5rem;
}
.admin-blog-image-preview img {
  width: 140px;
  height: 74px;
  object-fit: cover;
  border-radius: var(--radius);
  border: 1px solid var(--brand-border);
}
.admin-blog-file-input {
  display: block;
  margin-top: 0.4rem;
  font-size: 0.85rem;
}

/* ==========================================================================
   Blog (blog/index.html, blog/<slug>.html) — statically generated by
   admin-blog's publish action. Body typography mirrors .legal-container
   (generic h2/p/ul spacing for HTML written without page-specific classes),
   since a blog post body is authored HTML, not built element-by-element in JS.
   ========================================================================== */
.blog-index {
  padding: 3.5rem 0 6rem;
}
.blog-grid {
  margin-top: 2.5rem;
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 1.5rem;
}
@media (max-width: 720px) {
  .blog-grid { grid-template-columns: 1fr; }
}
.blog-card {
  display: block;
  padding: 1.5rem;
  border: 1px solid var(--brand-border);
  border-radius: var(--radius-lg);
  background: var(--brand-white);
  text-decoration: none;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
.blog-card:hover {
  border-color: var(--brand-orange);
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.06);
}
.blog-card__image {
  display: block;
  width: calc(100% + 3rem);
  height: 160px;
  object-fit: cover;
  margin: -1.5rem -1.5rem 1rem;
  border-radius: var(--radius-lg) var(--radius-lg) 0 0;
}
.blog-card__date {
  font-size: 0.78rem;
  color: var(--brand-slate);
  margin-bottom: 0.5rem;
}
.blog-card h2 {
  font-family: var(--font-heading);
  font-size: 1.25rem;
  color: var(--brand-dark);
  margin: 0 0 0.5rem;
}
.blog-card p {
  font-size: 0.92rem;
  line-height: 1.6;
  color: var(--brand-slate);
  margin: 0;
}
.blog-empty {
  grid-column: 1 / -1;
  text-align: center;
  color: var(--brand-slate);
  padding: 3rem 0;
}
.blog-post {
  padding: 3rem 0 6rem;
}
.blog-post__container {
  max-width: 42rem;
}
.blog-post__breadcrumb {
  font-size: 0.85rem;
  color: var(--brand-slate);
}
.blog-post__breadcrumb a {
  color: var(--brand-slate);
}
.blog-post h1 {
  margin-top: 0.5rem;
  font-size: 2.25rem;
}
.blog-post__meta {
  margin-top: 0.75rem;
  font-size: 0.85rem;
  color: var(--brand-slate);
}
.blog-post__image {
  display: block;
  width: 100%;
  max-height: 420px;
  object-fit: cover;
  margin-top: 1.75rem;
  border-radius: var(--radius-lg);
}
.blog-post__body {
  margin-top: 2rem;
}
.blog-post__body h2 {
  margin-top: 2.5rem;
  font-size: 1.5rem;
}
.blog-post__body h3 {
  margin-top: 2rem;
  font-size: 1.2rem;
}
.blog-post__body p {
  margin-top: 1.25rem;
  font-size: 1rem;
  line-height: 1.7;
  color: var(--brand-dark);
}
.blog-post__body a {
  color: var(--brand-orange);
  text-decoration: underline;
}
.blog-post__body a:hover {
  color: #e64800;
}
.blog-post__body ul,
.blog-post__body ol {
  margin: 1.25rem 0 0;
  padding-left: 1.25rem;
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
}
.blog-post__body li {
  font-size: 1rem;
  line-height: 1.6;
  color: var(--brand-dark);
}
.blog-post__body blockquote {
  margin: 1.75rem 0 0;
  padding: 1.25rem 1.5rem;
  background: rgba(239, 231, 220, 0.4);
  border-left: 3px solid var(--brand-orange);
  border-radius: var(--radius);
  font-style: italic;
  color: var(--brand-dark);
}
.blog-post__body blockquote p {
  margin-top: 0;
}
.blog-post__cta {
  margin-top: 3rem;
  padding: 1.75rem;
  border-radius: var(--radius-lg);
  background: var(--brand-cream);
  text-align: center;
}
.blog-post__cta p {
  margin: 0 0 1rem;
  font-weight: 700;
  color: var(--brand-dark);
}

/* ==========================================================================
   FW Checkup / One-on-One Consultation sections — plain write-up + single CTA
   (simplified 2026-09-11, replacing the old 5-stage journey grid).
   ========================================================================== */
.fw-checkup-cta {
  display: inline-block;
  margin-top: 1.75rem;
}

/* ==========================================================================
   FW Program section — heading/description stay full-width on top (see
   index.html's header comment), video + points/CTAs split left/right below.
   ========================================================================== */
.program-section__grid {
  display: grid;
  gap: 2.5rem;
  align-items: center;
  margin-top: 3rem;
}
@media (min-width: 900px) {
  .program-section__grid {
    grid-template-columns: 1.1fr 0.9fr;
  }
}
.video-frame--wide {
  aspect-ratio: 16 / 9;
  max-height: none;
}
/* This .video-frame instance is a plain link into program.html (2026-09-17),
   not a data-play-video trigger — needs display:block since it's an <a>
   (block-level by default for a div, not for a link) plus its own hover
   affordance so it reads as clickable the way a link normally would. */
.program-preview-card {
  display: block;
  transition: transform 150ms ease, box-shadow 150ms ease;
}
.program-preview-card:hover,
.program-preview-card:focus-visible {
  transform: translateY(-2px);
  box-shadow: 0 20px 40px rgba(0, 0, 0, 0.14);
}
@media (prefers-reduced-motion: reduce) {
  .program-preview-card {
    transition: none;
  }
}
.program-section__points {
  margin: 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 0.9rem;
}
.program-section__points li {
  display: flex;
  align-items: flex-start;
  gap: 0.75rem;
  font-size: 0.95rem;
  color: var(--brand-slate);
}
.program-section__points svg {
  flex-shrink: 0;
  margin-top: 0.15rem;
  color: var(--brand-orange);
}
.program-section__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
  margin-top: 2rem;
}

/* ==========================================================================
   FW Guidebook — StPageFlip-powered flipbook (js/guidebook.js). This file
   only styles the surrounding chrome (toolbar, page-jump input, bottom nav) —
   the actual page-curl/canvas rendering inside .book-flip is drawn by the
   library itself into DOM it creates, not by CSS here.
   ========================================================================== */
.book-viewer {
  max-width: 48rem;
  margin: 3rem auto 0;
}
.book-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  padding: 0.6rem 1rem;
  border: 1px solid var(--brand-border);
  border-bottom: none;
  border-radius: var(--radius) var(--radius) 0 0;
  background: rgba(239, 231, 220, 0.5);
}
.book-toolbar__group {
  display: flex;
  align-items: center;
  gap: 0.6rem;
}
.book-toolbar__of {
  font-size: 0.85rem;
  color: var(--brand-slate);
}
.book-toolbar__hint {
  font-size: 0.8rem;
  color: var(--brand-slate);
}
@media (max-width: 640px) {
  .book-toolbar__hint {
    display: none;
  }
}
.book-toolbar__link {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--brand-dark);
  text-decoration: none;
}
.book-toolbar__link:hover {
  color: var(--brand-orange);
}
.book-icon-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  border-radius: var(--radius);
  border: 1px solid var(--brand-border);
  background: var(--brand-white);
  color: var(--brand-dark);
  cursor: pointer;
}
.book-icon-btn:hover:not(:disabled) {
  border-color: var(--brand-orange);
  color: var(--brand-orange);
}
.book-icon-btn:disabled {
  opacity: 0.3;
  cursor: default;
}
.book-page-input {
  width: 3.25rem;
  padding: 0.35rem 0.4rem;
  text-align: center;
  border: 1px solid var(--brand-border);
  border-radius: var(--radius);
  font-family: var(--font-body);
  font-size: 0.9rem;
}
/* Plain "stretch" size mode (see js/guidebook.js) — resolution ties directly to this
   element's live CSS size, which is soft on retina/HiDPI screens at small display
   sizes (no devicePixelRatio awareness in the library itself). Attempts to force a
   higher, DPR-aware resolution via a fixed-size + CSS-transform wrapper were reverted
   (2026-09-10): StPageFlip's "fixed" mode turned out to still be elastic between a
   single-page and two-page-spread width and auto-switches portrait/landscape based on
   available space (confirmed via live DevTools inspection, not documented up front),
   which conflicted with a fixed-aspect-ratio wrapper in ways that took three attempts
   to characterize and never landed cleanly. Left as the simple, correctly-laid-out
   version rather than continuing to guess. */
.book-flip {
  width: 100%;
  aspect-ratio: 993 / 705.75; /* two guidebook pages side by side */
  border: 1px solid var(--brand-border);
  border-top: none;
  border-radius: 0 0 var(--radius) var(--radius);
  box-shadow: 0 24px 48px rgba(0, 0, 0, 0.15);
  background: var(--brand-cream);
}
@media (max-width: 640px) {
  .book-flip {
    aspect-ratio: 496.5 / 705.75; /* usePortrait mode shows a single page */
  }
}
/* Positioning parent for the lead-capture gate overlay (js/guidebook.js) — plain
   wrapper, no visual styling of its own. */
.book-flip-wrap {
  position: relative;
}
/* Lead-capture gate — shown over the book once a reader goes past the free preview
   limit (js/guidebook.js's PREVIEW_PAGE_LIMIT). Covers the flip surface entirely
   rather than replacing it, so the book (specifically the locked page behind it)
   stays visible as a teaser through the dim backdrop. */
.guidebook-gate {
  position: absolute;
  inset: 0;
  z-index: 5;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1.5rem;
  background: rgba(30, 26, 20, 0.55);
  backdrop-filter: blur(2px);
  border-radius: 0 0 var(--radius) var(--radius);
}
.guidebook-gate__card {
  max-width: 24rem;
  width: 100%;
  padding: 2rem;
  border-radius: var(--radius-lg);
  background: var(--brand-white);
  text-align: center;
  box-shadow: 0 24px 48px rgba(0, 0, 0, 0.25);
}
.guidebook-gate__lock {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.75rem;
  height: 2.75rem;
  border-radius: 50%;
  background: rgba(255, 80, 0, 0.1);
  color: var(--brand-orange);
}
.guidebook-gate__card h3 {
  margin-top: 1rem;
  font-size: 1.15rem;
}
.guidebook-gate__card p {
  margin-top: 0.5rem;
  font-size: 0.85rem;
  color: var(--brand-slate);
}
.guidebook-gate__form {
  margin-top: 1.25rem;
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  text-align: left;
}
.guidebook-gate__form .text-input {
  margin-top: 0;
}
.guidebook-gate__checkbox {
  display: flex;
  align-items: flex-start;
  gap: 0.5rem;
  font-size: 0.8rem;
  color: var(--brand-slate);
  text-align: left;
}
.guidebook-gate__checkbox input {
  margin-top: 0.2rem;
}
/* FW Program's pre-start intake gate (program-learn.js) — a real popup:
   fixed, full-viewport, dimmed backdrop, same shape as .guidebook-gate
   itself (reuses its .guidebook-gate__card/__form/__lock look) but
   position:fixed rather than absolute over one wrapping element, since this
   needs to sit above the whole page (header included), not just the course
   content behind it. Centers via flex on a fixed full-viewport box, so it's
   always dead-center regardless of any grid/column layout in the page
   underneath — the earlier non-modal version could end up sitting inside one
   grid column instead of spanning the full page width. */
.program-gate-modal {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1.5rem;
  background: rgba(30, 26, 20, 0.55);
  backdrop-filter: blur(2px);
}

/* FW Tools popup on program-learn.html (js/program-learn.js) — same fixed,
   full-viewport, dimmed-backdrop shape as .program-gate-modal above (so the
   two popups on this page feel like one family), just sized to hold the
   tools-grid card pair rather than a small form card. Tool cards themselves
   open target="_blank" (program-learn.html itself), so this modal is only
   ever a picker — it never has to render tool content inline. */
.program-tools-modal {
  position: fixed;
  inset: 0;
  z-index: 150;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1.5rem;
  background: rgba(30, 26, 20, 0.55);
  backdrop-filter: blur(2px);
}
.program-tools-modal__panel {
  position: relative;
  max-width: 44rem;
  width: 100%;
  max-height: 90vh;
  overflow-y: auto;
  padding: 2.5rem;
  border-radius: var(--radius-lg);
  background: var(--brand-white);
  box-shadow: 0 24px 48px rgba(0, 0, 0, 0.25);
}
/* Plain, always-full-height cards (not .tool-card's hover-expand version) —
   see program-learn.html's own comment on why: hover-expand grows via
   position:absolute, which doesn't count toward this panel's own
   overflow-y:auto scroll height, so an expanded card could overlap/clip the
   button beneath it inside this cramped a container. Description text is
   just always visible here instead. */
.program-tools-modal__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 1.25rem;
  margin-top: 2rem;
}
.program-tools-modal__card {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  padding: 1.5rem;
  border: 1px solid var(--brand-border);
  border-radius: var(--radius-lg);
  background: var(--brand-white);
}
.program-tools-modal__card h3 {
  font-size: 1.15rem;
}
.program-tools-modal__card p {
  flex: 1;
  color: var(--brand-slate);
  font-size: 0.9rem;
  line-height: 1.55;
}
.program-tools-modal__card .btn {
  align-self: flex-start;
}
/* Shared circle-close-button look — .program-tools-modal__close adds the
   "float in the panel's own corner" positioning on top of this for the
   picker; the viewer's own close button uses this base alone, since it sits
   inline in a flex toolbar row instead (position:absolute here would pull it
   out of that row entirely, onto the viewer's own corner instead of next to
   the title where it visually belongs). */
.program-tools-close-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.25rem;
  height: 2.25rem;
  border-radius: 50%;
  border: 1px solid var(--brand-border);
  background: var(--brand-white);
  color: var(--brand-slate);
  transition: color 150ms ease, border-color 150ms ease;
}
.program-tools-close-btn:hover,
.program-tools-close-btn:focus-visible {
  color: var(--brand-orange);
  border-color: var(--brand-orange);
}
.program-tools-modal__close {
  position: absolute;
  top: 1rem;
  right: 1rem;
}
@media (max-width: 640px) {
  .program-tools-modal__panel {
    padding: 1.75rem;
  }
}

/* FW Tool viewer (program-learn.html/js) — a large popup, not an edge-to-edge
   full screen (revised 2026-09-18, explicit instruction: "curve borders,
   dont make very full") — same dimmed-backdrop-with-padding shape as
   .program-tools-modal/.program-gate-modal, just a bigger panel to hold a
   whole tool comfortably rather than a small card. Above
   .program-tools-modal's own z-index (150) since opening a tool replaces
   that picker rather than stacking visually on top of it. */
.program-tools-viewer {
  position: fixed;
  inset: 0;
  z-index: 160;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 2rem;
  background: rgba(30, 26, 20, 0.55);
  backdrop-filter: blur(2px);
}
.program-tools-viewer__panel {
  display: flex;
  flex-direction: column;
  width: 100%;
  max-width: 90rem;
  height: 90vh;
  border-radius: var(--radius-lg);
  background: var(--brand-white);
  box-shadow: 0 24px 48px rgba(0, 0, 0, 0.25);
  overflow: hidden;
}
.program-tools-viewer__bar {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: 0.75rem 1.25rem;
  border-bottom: 1px solid var(--brand-border);
}
.program-tools-viewer__title {
  margin: 0 auto 0 0;
  font-family: var(--font-heading);
  font-size: 1rem;
  color: var(--brand-dark);
}
.program-tools-viewer__frame {
  flex: 1;
  width: 100%;
  border: 0;
}
@media (max-width: 640px) {
  .program-tools-viewer {
    padding: 0;
  }
  .program-tools-viewer__panel {
    max-height: none;
    border-radius: 0;
  }
}
.book-toolbar__link--disabled {
  opacity: 0.4;
  pointer-events: none;
}
/* Each page passed to StPageFlip's loadFromHTML (js/guidebook.js) — the library wraps
   these in its own positioning divs, so this only needs to fill whatever box it's
   given. */
.guidebook-page {
  width: 100%;
  height: 100%;
  background: var(--brand-cream);
  overflow: hidden;
}
.guidebook-page img {
  width: 100%;
  height: 100%;
  display: block;
  object-fit: cover;
}
.book-bottom-nav {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 1.5rem;
  margin-top: 1.5rem;
}
.book-bottom-nav .btn {
  gap: 0.4rem;
}
.book-page-counter {
  font-size: 0.9rem;
  font-weight: 600;
  color: var(--brand-dark);
  min-width: 8rem;
  text-align: center;
}

/* ==========================================================================
   Founder quote block.
   ========================================================================== */
.quote-block {
  max-width: 56rem;
  margin: 0 auto;
  padding: 1.25rem 1.5rem;
  text-align: center;
}
.quote-block blockquote {
  margin: 0;
  font-family: var(--font-heading);
  font-style: italic;
  font-size: 1.4rem;
  line-height: 1.5;
  color: var(--brand-dark);
}
.quote-block cite {
  display: block;
  margin-top: 1.25rem;
  font-style: normal;
  font-size: 0.85rem;
  font-weight: 700;
  letter-spacing: 0.05em;
  color: var(--brand-slate);
}

/* ==========================================================================
   Homepage section banding — same pattern as the pre-existing "Section
   banding" comment further up this file (hairline top border, alternating
   white/cream tint): these four sections were added for the 1:1-consultation
   revamp and need the same treatment so the page reads as distinct sections
   rather than one continuous scroll. .expect-section and .faq are scoped by
   their homepage ID rather than edited globally, since those class names are
   shared with other pages that shouldn't be affected by this change.
   ========================================================================== */
.quote-block-section {
  padding: 2rem 0;
  border-top: 1px solid var(--brand-border);
  background: var(--brand-white);
}
.fw-checkup-section {
  padding: 4rem 0;
  border-top: 1px solid var(--brand-border);
}
/* This section's image is now a real screenshot of the results dashboard
   (2026-09-17), not an illustrative photo — a dense, text-heavy UI reads as
   an illegible postage stamp at the shared .image-placeholder's default 16/9
   box and 0.9fr column share. Scoped here rather than changing the shared
   class, which .split-content-grid's other reuse (Consultation/What-to-
   Expect) still needs at its original size. */
/* Wider than the site's standard 1152px .container — the screenshot needs
   real pixels to be legible, and the standard width left it cramped even
   after widening the column split below. Scoped to this section only, so
   every other section on the page stays aligned to the normal 1152px edge. */
.fw-checkup-section .container {
  max-width: 84rem;
}
.fw-checkup-section .split-content-grid {
  gap: 3rem;
}
@media (min-width: 900px) {
  .fw-checkup-section .split-content-grid {
    /* Rebalanced 2026-09-19 for the browser-frame video (1094:838, ~1.3:1)
       — the old 0.8fr/1.6fr split was tuned for a very wide 1847:845
       screenshot; at that split this much taller frame would run far taller
       than the text column beside it. */
    grid-template-columns: 1fr 1.2fr;
  }
}
.fw-checkup-section .image-placeholder {
  /* Matches the screenshot's own 1847x845 pixel ratio exactly (not a
     tablet-like 3:2) — that's what let the laptop version fill its frame
     edge to edge at full size with nothing cropped or letterboxed; a
     tighter ratio only shrinks the visible dashboard to fit inside it. */
  aspect-ratio: 1847 / 845;
  /* No border/shadow of its own — .device-frame__screen below carries both,
     as the tablet bezel/shadow instead. */
  border: none;
  box-shadow: none;
  border-radius: 10px;
}
/* Tablet-style device mockup (2026-09-17, replacing an earlier laptop-style
   version — no base/stand, uniform bezel on every side, a front camera dot
   centered on the top edge) around the FW Checkup screenshot, sized back up
   to the same large scale the laptop version had (2026-09-17, follow-up —
   the tablet's narrower frame and 3:2 crop had shrunk the actual dashboard
   down; the bezel styling changed, not the underlying screen size). Bezel
   deliberately stays thin, not a thick device frame. brand-dark only (no
   new colors), same family as the video-frame's own dark gradient elsewhere
   on this page. */
.device-frame {
  width: 100%;
}
.device-frame__screen {
  position: relative;
  padding: 0.4rem;
  border-radius: 18px;
  background: var(--brand-dark);
  box-shadow: 0 24px 48px rgba(0, 0, 0, 0.16);
}

/* Browser-window frame for the FW Checkup preview video (2026-09-19) — the
   video is a screen recording of a web page, so a browser chrome (dots +
   address bar) frames it more naturally than the old tablet bezel did. The
   screen area is locked to the video's own 1094x838 so it fills edge to edge
   with no crop and no letterbox bars. brand tokens only, no new colors. */
.browser-frame {
  margin: 0;
  width: 100%;
  border-radius: 14px;
  overflow: hidden;
  background: var(--brand-white);
  border: 1px solid var(--brand-border);
  box-shadow: 0 24px 48px rgba(0, 0, 0, 0.14);
}
.browser-frame__bar {
  display: flex;
  align-items: center;
  gap: 0.9rem;
  padding: 0.6rem 0.9rem;
  background: var(--brand-cream);
  border-bottom: 1px solid var(--brand-border);
}
.browser-frame__dots {
  display: inline-flex;
  gap: 0.35rem;
  flex-shrink: 0;
}
.browser-frame__dots i {
  width: 0.6rem;
  height: 0.6rem;
  border-radius: 50%;
  background: rgba(106, 125, 139, 0.35);
}
.browser-frame__dots i:first-child {
  background: var(--brand-orange);
}
.browser-frame__url {
  flex: 1;
  min-width: 0;
  max-width: 24rem;
  margin: 0 auto;
  padding: 0.25rem 0.9rem;
  border-radius: 999px;
  background: var(--brand-white);
  color: var(--brand-slate);
  font-size: 0.72rem;
  line-height: 1.4;
  text-align: center;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.browser-frame__screen {
  aspect-ratio: 1094 / 838;
  background: var(--brand-white);
}
.browser-frame__video {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.program-section {
  padding: 4rem 0;
  border-top: 1px solid var(--brand-border);
  background: rgba(239, 231, 220, 0.4);
}
.guidebook-section {
  padding: 4rem 0;
  border-top: 1px solid var(--brand-border);
}
/* Wider than the site's default .section-heading max-width (40rem) specifically so
   "The Financial Wellbeing Guidebook" fits on one line instead of wrapping after
   "Financial" (reported 2026-09-11) — scoped to this section only, other headings
   still wrap at the narrower default on purpose. */
.guidebook-section .section-heading {
  max-width: 56rem;
}
/* .guidebook-section needs no background override at all: it's white by default,
   which is the correct next color in the sequence — cream .expect-section before
   it, cream #faq.faq after it (its own explicit background further below). */
#faq.faq {
  border-top: 1px solid var(--brand-border);
}

/* ==========================================================================
   FW Program — course overview (program.html) + learning interface
   (program-learn.html), 2026-09-17. Same Brand Kit tokens/components as the
   rest of the site (--brand-orange, --radius-lg, .btn/.step-badge/.eyebrow/
   .section-heading/.script-word, .curriculum-*/.course-* are new). No new
   colors, no new fonts.
   ========================================================================== */

/* Reusable across any .section-heading that needs to sit inside a two-thing
   layout instead of standing alone above full-width content (the default
   centered/capped block only makes sense for the latter). */
.section-heading--left {
  text-align: left;
  max-width: none;
  margin: 0;
}

/* --------------------------------------------------------------------------
   Overview page
   -------------------------------------------------------------------------- */
.program-overview-root {
  padding-top: 2.5rem;
}
.program-hero {
  display: grid;
  gap: 2.5rem;
  align-items: center;
  padding-bottom: 3.5rem;
}
@media (min-width: 900px) {
  .program-hero {
    grid-template-columns: 1.15fr 0.85fr;
    gap: 3.5rem;
  }
}
.program-hero h1 {
  font-size: 2.25rem;
  line-height: 1.15;
  margin-top: 0.75rem;
}
@media (min-width: 640px) {
  .program-hero h1 {
    font-size: 2.75rem;
  }
}
.program-hero h1 .script-word {
  font-family: var(--font-heading);
  font-style: italic;
  font-weight: 400;
  color: var(--brand-orange);
}
.program-hero__lead {
  margin-top: 1rem;
  max-width: 34rem;
  font-size: 1.05rem;
  line-height: 1.6;
  color: var(--brand-slate);
}
.program-hero__stats {
  display: flex;
  gap: 2rem;
  margin: 1.75rem 0 0;
  padding: 0;
  list-style: none;
}
.program-hero__stats li {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
}
.program-hero__stats strong {
  font-family: var(--font-heading);
  font-size: 1.6rem;
  color: var(--brand-dark);
}
.program-hero__stats span {
  font-size: 0.8rem;
  color: var(--brand-slate);
}
.program-hero__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1rem;
  margin-top: 1.75rem;
}
.program-hero__cta svg {
  transition: transform 200ms ease;
}
.program-hero__cta:hover svg {
  transform: translateX(3px);
}
@media (prefers-reduced-motion: reduce) {
  .program-hero__cta svg {
    transition: none;
  }
}
.program-hero__progress-label {
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--brand-orange);
}
.program-hero__media-card {
  position: relative;
  aspect-ratio: 4 / 3;
  border-radius: var(--radius-lg);
  overflow: hidden;
  border: 1px solid var(--brand-border);
  box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
}
.program-hero__media-card img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.program-hero__media-badge {
  position: absolute;
  left: 1rem;
  bottom: 1rem;
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.5rem 0.9rem;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.92);
  font-size: 0.8rem;
  font-weight: 700;
  color: var(--brand-dark);
}
.program-hero__media-badge svg {
  color: var(--brand-orange);
}
.program-curriculum {
  padding: 3rem 0 4rem;
  border-top: 1px solid var(--brand-border);
}
.curriculum-list {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  margin-top: 2rem;
}
.curriculum-chapter {
  padding: 1.5rem;
  border: 1px solid var(--brand-border);
  border-radius: var(--radius-lg);
  background: var(--brand-white);
}
.curriculum-chapter__head {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: 1rem;
}
.curriculum-chapter__num {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 2.75rem;
  height: 2.75rem;
  border-radius: 50%;
  background: rgba(255, 80, 0, 0.08);
  font-family: var(--font-heading);
  font-size: 1.05rem;
  color: var(--brand-orange);
}
.curriculum-chapter__heading {
  flex: 1;
  min-width: 12rem;
}
.curriculum-chapter__heading h3 {
  font-size: 1.15rem;
}
.curriculum-chapter__heading p {
  margin-top: 0.35rem;
  font-size: 0.9rem;
  line-height: 1.5;
  color: var(--brand-slate);
}
.curriculum-chapter__meta {
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 0.25rem;
  font-size: 0.8rem;
  color: var(--brand-slate);
  white-space: nowrap;
}
.curriculum-chapter__percent {
  font-weight: 700;
  color: var(--brand-orange);
}
/* One-card chapter (2026-09-19): a chapter with a single lesson is the whole
   card as one link — number, title/description, and the length once — instead
   of a chapter box wrapping a lesson row that repeated its title and time. */
.curriculum-chapter--single {
  display: flex;
  align-items: center;
  gap: 1rem;
  color: inherit;
  text-decoration: none;
  transition: border-color 150ms ease, box-shadow 150ms ease;
}
.curriculum-chapter--single:hover,
.curriculum-chapter--single:focus-visible {
  border-color: var(--brand-orange);
  box-shadow: 0 8px 20px -10px rgba(255, 80, 0, 0.3);
}
.curriculum-chapter--single .curriculum-chapter__heading {
  min-width: 0;
}
.curriculum-chapter__meta--single {
  flex-direction: row;
  align-items: center;
  gap: 0.6rem;
}
@media (max-width: 560px) {
  .curriculum-chapter--single {
    flex-wrap: wrap;
  }
  .curriculum-chapter--single .curriculum-chapter__heading {
    flex-basis: calc(100% - 3.75rem);
  }
  .curriculum-chapter__meta--single {
    margin-left: 3.75rem;
  }
}
.curriculum-lesson-list {
  margin: 1.1rem 0 0;
  padding: 0;
  list-style: none;
  border-top: 1px solid var(--brand-border);
}
.curriculum-lesson__row {
  display: flex;
  align-items: center;
  gap: 0.85rem;
  padding: 0.75rem 0.25rem;
  border-bottom: 1px solid var(--brand-border);
  color: inherit;
  text-decoration: none;
  transition: background-color 150ms ease;
}
a.curriculum-lesson__row {
  cursor: pointer;
}
a.curriculum-lesson__row:hover {
  background: rgba(255, 80, 0, 0.04);
}
.curriculum-lesson__icon {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 1.75rem;
  height: 1.75rem;
  border-radius: 50%;
  background: rgba(255, 80, 0, 0.08);
  color: var(--brand-orange);
}
.curriculum-lesson--locked .curriculum-lesson__icon {
  background: var(--brand-cream);
  color: var(--brand-slate);
}
.curriculum-lesson--complete .curriculum-lesson__icon {
  background: rgba(46, 125, 79, 0.12);
  color: var(--status-strong);
}
.curriculum-lesson__title {
  flex: 1;
  font-size: 0.92rem;
  color: var(--brand-dark);
}
.curriculum-lesson--locked .curriculum-lesson__title {
  color: var(--brand-slate);
}
.curriculum-lesson__duration {
  flex-shrink: 0;
  font-size: 0.8rem;
  color: var(--brand-slate);
}

.program-objectives-section {
  padding: 4rem 0;
  border-top: 1px solid var(--brand-border);
  background: rgba(239, 231, 220, 0.4);
}
.program-objectives-grid {
  display: grid;
  gap: 1rem;
  margin: 2rem 0 0;
  padding: 0;
  list-style: none;
}
@media (min-width: 700px) {
  .program-objectives-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}
.program-objectives-grid li {
  display: flex;
  align-items: flex-start;
  gap: 0.85rem;
  padding: 1.25rem;
  border: 1px solid rgba(176, 176, 176, 0.25);
  border-radius: var(--radius);
  background: var(--brand-white);
  font-size: 0.95rem;
  line-height: 1.5;
  color: var(--brand-dark);
}
.program-objectives-grid svg {
  flex-shrink: 0;
  margin-top: 0.15rem;
  color: var(--brand-orange);
}

.program-instructor-section {
  padding: 4rem 0;
  border-top: 1px solid var(--brand-border);
  background: rgba(239, 231, 220, 0.4);
}

.program-tools-section {
  padding: 4rem 0;
  border-top: 1px solid var(--brand-border);
  background: #fff;
}
.program-tools-section .section-heading p:not(.eyebrow) {
  margin-top: 0.75rem;
  color: var(--brand-slate);
}
.program-tools-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1.5rem;
  max-width: 56rem;
  margin: 2.5rem auto 0;
}
.program-tool-card {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.75rem;
  padding: 1.75rem;
  background: #fff;
  border: 1px solid var(--brand-border);
  border-radius: var(--radius-lg);
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.04);
}
.program-tool-card h3 {
  margin: 0;
  font-family: var(--font-heading);
}
.program-tool-card p {
  flex: 1;
  color: var(--brand-slate);
  line-height: 1.6;
}
.program-tool-card .btn {
  margin-top: 0.5rem;
}
@media (min-width: 700px) {
  .program-tools-grid {
    grid-template-columns: 1fr 1fr;
  }
}
.program-instructor-card {
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
  align-items: flex-start;
  max-width: 42rem;
  margin: 0 auto;
  padding: 2rem;
  border: 1px solid var(--brand-border);
  border-radius: var(--radius-lg);
  text-align: center;
}
@media (min-width: 640px) {
  .program-instructor-card {
    flex-direction: row;
    text-align: left;
  }
}
.program-instructor-card__photo {
  width: 88px;
  height: 88px;
  border-radius: 50%;
  object-fit: cover;
  margin: 0 auto;
  flex-shrink: 0;
}
@media (min-width: 640px) {
  .program-instructor-card__photo {
    margin: 0;
  }
}
.program-instructor-card__label {
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--brand-orange);
}
.program-instructor-card h3 {
  margin-top: 0.3rem;
  font-size: 1.2rem;
}
.program-instructor-card p {
  margin-top: 0.6rem;
  font-size: 0.92rem;
  line-height: 1.6;
  color: var(--brand-slate);
}

/* --------------------------------------------------------------------------
   Learning interface (program-learn.html) — its own minimal header (not
   .site-header — no full nav needed while learning, just a way back and
   overall progress), a two-column layout below it (video+info / sidebar),
   and a mobile drawer for the sidebar. Normal page scroll (unlike the FW
   Checkup's hard one-viewport .flow-body) — a course page is meant to be
   read down, not held to a single screen.
   -------------------------------------------------------------------------- */
.program-learn-page {
  background: var(--brand-white);
}
.program-learn-header {
  position: sticky;
  top: 0;
  z-index: 50;
  background: rgba(255, 255, 255, 0.95);
  backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--brand-border);
}
.program-learn-header__row {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: 0.75rem 1.25rem;
}
.program-learn-header__back {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  color: var(--brand-slate);
  transition: color 150ms ease;
}
.program-learn-header__back:hover {
  color: var(--brand-orange);
}
.program-learn-header__logo img {
  height: 28px;
  width: auto;
  display: block;
}
.program-learn-header__title {
  margin: 0;
  font-family: var(--font-heading);
  font-size: 1.1rem;
  color: var(--brand-dark);
  /* Hidden below 460px — the logo already carries the brand, and at phone
     widths this plus "Course Content" was wrapping the header to two lines
     (reported: the title itself wrapped mid-word). */
  display: none;
  white-space: nowrap;
}
@media (min-width: 460px) {
  .program-learn-header__title {
    display: block;
  }
}
.program-learn-header__toggle {
  padding: 0.5rem 0.9rem;
  font-size: 0.82rem;
  white-space: nowrap;
}
/* Tools is the FIRST of the two header toggles now (2026-09-18) — it, not
   the shared class, carries the "push everything from here to the right
   edge" margin, since it must stay visible (and therefore keep this margin)
   at every width, unlike Course Content below which hides at 1100px+. An ID
   selector here deliberately outranks the @media(min-width:700px) class rule
   below it in source order, so this margin is never overridden by that one. */
#program-tools-toggle {
  margin-left: auto;
}
/* Icon-only below 400px — same reasoning as the title above: the full
   "Course Content" label was the other half of the two-line wrap. */
@media (max-width: 399px) {
  .program-learn-header__toggle span {
    display: none;
  }
  .program-learn-header__toggle {
    padding: 0.5rem 0.65rem;
  }
}
@media (min-width: 700px) {
  .program-learn-header__toggle {
    margin-left: 0.5rem;
  }
}
/* Course Content only, not Tools (2026-09-18) — the sidebar this toggle
   opens/closes is already sitting inline in the grid at this width (see
   .program-learn-layout's own 1100px breakpoint), so the button genuinely
   has nothing left to do here. Tools has no such inline equivalent — it's
   the only way to reach the popup at any width — so it stays visible. */
@media (min-width: 1100px) {
  #course-content-toggle {
    display: none;
  }
}

.program-learn-main {
  padding: 1.5rem 1.25rem 4rem;
}
.program-learn-layout {
  display: grid;
  gap: 1.5rem;
  max-width: 92rem;
  margin: 0 auto;
}
@media (min-width: 1100px) {
  .program-learn-layout {
    grid-template-columns: 1fr 22rem;
    align-items: start;
  }
}

.course-video-player {
  position: relative;
  aspect-ratio: 16 / 9;
  border-radius: var(--radius-lg);
  overflow: hidden;
  background: var(--brand-dark);
  box-shadow: 0 20px 40px rgba(0, 0, 0, 0.12);
}
.course-video-player video {
  width: 100%;
  height: 100%;
  display: block;
  object-fit: contain;
  background: var(--brand-dark);
}
.course-video-placeholder {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1rem;
  padding: 2rem;
  text-align: center;
  color: rgba(255, 255, 255, 0.8);
}
.course-video-placeholder__icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 3.5rem;
  height: 3.5rem;
  border-radius: 50%;
  border: 2px solid rgba(255, 255, 255, 0.3);
}
.course-video-placeholder p {
  max-width: 24rem;
  font-size: 0.9rem;
  line-height: 1.5;
}

.course-lesson-info {
  margin-top: 1.5rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--brand-border);
}
.course-lesson-info__chapter {
  font-size: 0.8rem;
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--brand-orange);
}
.course-lesson-info__title {
  margin-top: 0.5rem;
  font-size: 1.5rem;
  line-height: 1.25;
}
.course-lesson-info__desc {
  margin-top: 0.75rem;
  max-width: 42rem;
  font-size: 0.95rem;
  line-height: 1.6;
  color: var(--brand-slate);
}
.course-lesson-info__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.85rem;
  margin-top: 1.25rem;
}
#mark-complete-btn svg {
  margin-right: 0.35rem;
  vertical-align: -2px;
}

/* --- Sidebar ------------------------------------------------------------ */
.course-sidebar {
  border: 1px solid var(--brand-border);
  border-radius: var(--radius-lg);
  background: var(--brand-white);
  overflow: hidden;
}
.course-sidebar__head {
  padding: 1.1rem 1.25rem;
  border-bottom: 1px solid var(--brand-border);
  background: rgba(239, 231, 220, 0.35);
}
.course-sidebar__title {
  margin: 0 0 0.6rem;
  font-family: var(--font-heading);
  font-size: 1.05rem;
  color: var(--brand-dark);
}
.course-sidebar__progress {
  display: flex;
  align-items: center;
  gap: 0.75rem;
}
.course-sidebar__progress-bar {
  flex: 1;
  height: 6px;
  border-radius: 999px;
  background: var(--brand-cream);
  overflow: hidden;
}
.course-sidebar__progress-bar span {
  display: block;
  height: 100%;
  border-radius: 999px;
  background: var(--brand-orange);
  transition: width 300ms ease;
}
@media (prefers-reduced-motion: reduce) {
  .course-sidebar__progress-bar span {
    transition: none;
  }
}
.course-sidebar__progress-label {
  flex-shrink: 0;
  font-size: 0.78rem;
  font-weight: 700;
  color: var(--brand-orange);
}

.course-sidebar__chapters {
  max-height: 70vh;
  overflow-y: auto;
}
.course-chapter {
  border-bottom: 1px solid var(--brand-border);
}
.course-chapter:last-child {
  border-bottom: none;
}
.course-chapter__summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 0.95rem 1.25rem;
  cursor: pointer;
  list-style: none;
}
.course-chapter__summary::-webkit-details-marker {
  display: none;
}
.course-chapter__label {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  min-width: 0;
}
.course-chapter__num {
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--brand-orange);
}
.course-chapter__title {
  font-size: 0.9rem;
  font-weight: 600;
  color: var(--brand-dark);
}
.course-chapter__right {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  gap: 0.6rem;
}
.course-chapter__percent {
  font-size: 0.75rem;
  font-weight: 700;
  color: var(--brand-orange);
}
.course-chapter__chevron {
  display: flex;
  color: var(--brand-slate);
  transition: transform 200ms ease;
}
.course-chapter[open] .course-chapter__chevron {
  transform: rotate(180deg);
}
@media (prefers-reduced-motion: reduce) {
  .course-chapter__chevron {
    transition: none;
  }
}

.course-lesson-list {
  margin: 0;
  padding: 0 0.75rem 0.75rem;
  list-style: none;
}
/* One-row chapter (2026-09-19) — see buildSidebarChapters in
   js/program-learn.js. Padded like .course-chapter__summary so the list keeps
   the same rhythm, full-bleed so the active highlight spans the whole row. */
.course-chapter--single .course-lesson-item__row {
  padding: 0.85rem 1.25rem;
  border-radius: 0;
}
.course-chapter--single .course-lesson-item__body {
  gap: 0.15rem;
}
.course-chapter--single .course-lesson-item__title {
  font-size: 0.9rem;
  font-weight: 600;
}
.course-lesson-item__row {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  padding: 0.6rem 0.5rem;
  border-radius: var(--radius);
  color: inherit;
  text-decoration: none;
  cursor: pointer;
  transition: background-color 150ms ease;
}
a.course-lesson-item__row:hover {
  background: rgba(255, 80, 0, 0.05);
}
.course-lesson-item__icon {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 1.6rem;
  height: 1.6rem;
  border-radius: 50%;
  background: var(--brand-cream);
  color: var(--brand-slate);
}
.course-lesson-item__body {
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
  min-width: 0;
}
.course-lesson-item__title {
  font-size: 0.85rem;
  color: var(--brand-dark);
  overflow-wrap: break-word;
}
.course-lesson-item__duration {
  font-size: 0.72rem;
  color: var(--brand-slate);
}
.course-lesson-item.is-active .course-lesson-item__row {
  background: rgba(255, 80, 0, 0.08);
}
.course-lesson-item.is-active .course-lesson-item__title {
  font-weight: 700;
  color: var(--brand-orange);
}
.course-lesson-item.is-active .course-lesson-item__icon {
  background: var(--brand-orange);
  color: var(--brand-white);
}
.course-lesson-item.is-complete .course-lesson-item__icon {
  background: rgba(46, 125, 79, 0.12);
  color: var(--status-strong);
}
.course-lesson-item.is-complete.is-active .course-lesson-item__icon {
  background: var(--brand-orange);
  color: var(--brand-white);
}
.course-lesson-item [aria-disabled="true"] {
  cursor: default;
  opacity: 0.55;
}

/* --- Mobile drawer -------------------------------------------------------
   Above 1100px the sidebar sits inline in the grid (see .program-learn-layout
   above) and this whole block is inert — .is-open is simply never toggled
   there since .program-learn-header__toggle is hidden at that width. */
.course-sidebar-scrim {
  position: fixed;
  inset: 0;
  z-index: 60;
  background: rgba(51, 51, 51, 0.4);
}
@media (max-width: 1099px) {
  .course-sidebar {
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    z-index: 61;
    width: min(22rem, 86vw);
    border-radius: 0;
    border-left: 1px solid var(--brand-border);
    transform: translateX(100%);
    transition: transform 250ms ease;
    display: flex;
    flex-direction: column;
  }
  .course-sidebar.is-open {
    transform: translateX(0);
  }
  .course-sidebar__chapters {
    max-height: none;
    flex: 1;
  }
}
@media (prefers-reduced-motion: reduce) {
  .course-sidebar {
    transition: none;
  }
}

/* FW Checkup results — "Download Report" (results.js) prints via window.print()
   rather than a PDF library, so this narrows the printed page down to just the
   score panel + glance grid. */
@media print {
  .site-header,
  .site-footer,
  .fw-score-panel__cta,
  .fw-score-panel__download,
  .fw-score-panel__retake,
  .fw-glance-cta {
    display: none !important;
  }
  .fw-dashboard {
    display: block;
  }
}

/* Booking form — desktop: everything incl. Confirm Booking visible without
   scrolling on a laptop-height viewport. */
@media (min-width: 900px) {
  #booking-root.booking-guest-page { padding: 0.75rem 1.25rem 1rem; }
  .booking-guest-layout { gap: 1.25rem; }
  .booking-guest-card { padding: 1.1rem 1.4rem; }
  .booking-guest-title, .booking-guest-card .portal-heading { font-size: 1.35rem; margin-top: 0.15rem; }
  .booking-guest-card .portal-sub { margin-top: 0.2rem; font-size: 0.88rem; }
  .booking-guest-card .portal-form { margin-top: 0.75rem; gap: 0.5rem; }
  .booking-guest-card .portal-field-label { margin-top: 0.7rem; }
  .booking-guest-card .text-input { padding: 0.5rem 0.8rem; margin-top: 0.25rem; }
  .booking-guest-card .portal-chip-grid { margin-top: 0.4rem; }
  .booking-guest-card .portal-chip { padding: 0.3rem 0.7rem; }
  .booking-guest-card #booking-guest-time-note { margin-top: 0.5rem; }
  .booking-guest-card--aside .booking-summary { margin-top: 0.75rem; padding: 0.8rem 1rem; }
  .booking-summary__title { margin-bottom: 0.6rem; padding-bottom: 0.45rem; }
  .booking-summary__grid { grid-template-columns: 1.05fr 0.85fr 1.5fr; gap: 0.6rem 0.9rem; }
  .booking-summary__item dd { font-size: 0.85rem; line-height: 1.3; }
  .booking-guest-card .consent-check { margin-top: 0.75rem; padding: 0.5rem 0.75rem; }
  .booking-guest-card .portal-submit-btn { margin-top: 0.75rem; }
}
.referral-welcome-modal__actions .btn-ghost {
  border: 1.5px solid var(--brand-orange);
  color: var(--brand-orange);
}

/* One arrow style on every button (inline SVG, not a text "→"). */
.btn .btn-arrow {
  flex-shrink: 0;
  margin-left: 0.35rem;
  vertical-align: -0.2em;
  transition: transform 200ms ease;
}
.btn:hover .btn-arrow {
  transform: translateX(3px);
}
/* Guidebook: slide a lone cover/back cover to the centre instead of leaving
   the other half of the spread blank. */
.book-flip {
  transition: transform 400ms ease;
}
.book-flip-wrap[data-spread="first"] .book-flip {
  transform: translateX(-25%);
}
.book-flip-wrap[data-spread="last"] .book-flip {
  transform: translateX(25%);
}
.book-bottom-nav {
  justify-content: center;
  gap: 1rem;
}
@media (min-width: 1600px) {
  :root {
    --max-width: 1400px;
  }
}
.book-flip {
  background: transparent;
  border-color: transparent;
  box-shadow: none;
}

/* Founder quote: two round portraits beside the text on desktop, stacked
   above it on mobile. */
.quote-block {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1.5rem;
}
.quote-block__photos {
  display: flex;
  flex-shrink: 0;
}
.quote-block__photos img {
  width: 6rem;
  height: 6rem;
  border-radius: 50%;
  object-fit: cover;
  object-position: center 25%;
  border: 3px solid var(--brand-white);
  box-shadow: 0 0 0 2px var(--brand-orange);
}
.quote-block__photos img + img {
  margin-left: -1.25rem;
}
@media (min-width: 768px) {
  .quote-block {
    flex-direction: row;
    gap: 2.5rem;
    text-align: left;
  }
  .quote-block__photos img {
    width: 8rem;
    height: 8rem;
  }
}

/* Corporate partner co-branding (js/lib/partner.js, 2026-09-19) — "NetworkFP x
   <logo>" in the nav plus a slim "for <company> employees" strip under it. */
.logo .logo__x {
  color: var(--brand-slate);
  font-size: 1.25rem;
  line-height: 1;
}
.logo img.logo__partner {
  height: 34px;
  max-width: 130px;
  object-fit: contain;
}
.flow-header__row .logo img.logo__partner {
  height: 40px;
}
@media (max-width: 767px) {
  .logo img.logo__partner,
  .flow-header__row .logo img.logo__partner {
    height: 26px;
    max-width: 84px;
  }
}
.partner-strip {
  background: var(--brand-cream);
  border-bottom: 1px solid var(--brand-border);
  font-size: 0.9rem;
  color: var(--brand-dark);
}
.partner-strip__inner {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: center;
  gap: 0.25rem 0.75rem;
  padding-top: 0.5rem;
  padding-bottom: 0.5rem;
  text-align: center;
}

/* ==========================================================================
   Admin shell (2026-09-19 revamp) — left sidebar navigation + card-based
   content, matching the public site's brand (orange/cream/slate, serif
   headings, rounded cards). Overrides earlier admin-* rules where needed.
   ========================================================================== */
.admin-body {
  margin: 0;
  background: #faf8f5;
}
.admin-app {
  display: grid;
  grid-template-columns: 264px minmax(0, 1fr);
  min-height: 100vh;
}
.admin-app.is-locked {
  grid-template-columns: minmax(0, 1fr);
}
.admin-app.is-locked .admin-sidebar {
  display: none;
}

/* ---------- Sidebar ---------- */
.admin-sidebar {
  position: sticky;
  top: 0;
  align-self: start;
  height: 100vh;
  display: flex;
  flex-direction: column;
  gap: 1.5rem;
  padding: 1.5rem 1rem 1.25rem;
  background: var(--brand-white);
  border-right: 1px solid var(--brand-border);
}
.admin-sidebar__brand {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0 0.5rem;
}
.admin-sidebar__brand img {
  height: 40px;
  width: auto;
}
.admin-sidebar__badge {
  padding: 0.15rem 0.5rem;
  border-radius: 999px;
  background: rgba(255, 80, 0, 0.1);
  color: var(--brand-orange);
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
.admin-sidebar__nav {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
}
.admin-sidebar .admin-tab {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  width: 100%;
  margin: 0;
  padding: 0.7rem 0.85rem;
  border: none;
  border-radius: 12px;
  background: none;
  font-family: var(--font-body);
  font-size: 0.95rem;
  font-weight: 700;
  text-align: left;
  color: var(--brand-slate);
  cursor: pointer;
  transition: background-color 150ms ease, color 150ms ease;
}
.admin-sidebar .admin-tab svg {
  flex-shrink: 0;
  width: 20px;
  height: 20px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.admin-sidebar .admin-tab:hover {
  background: #faf8f5;
  color: var(--brand-dark);
}
.admin-sidebar .admin-tab.is-active {
  background: rgba(255, 80, 0, 0.09);
  color: var(--brand-orange);
}
.admin-sidebar .admin-tab:focus-visible,
.admin-sidebar__lock:focus-visible,
.admin-sidebar__link:focus-visible {
  outline: 2px solid var(--brand-orange);
  outline-offset: 2px;
}
.admin-sidebar__foot {
  margin-top: auto;
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  padding-top: 1rem;
  border-top: 1px solid var(--brand-border);
}
.admin-sidebar__link,
.admin-sidebar__lock {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  width: 100%;
  padding: 0.6rem 0.85rem;
  border: none;
  border-radius: 12px;
  background: none;
  font-family: var(--font-body);
  font-size: 0.88rem;
  font-weight: 700;
  color: var(--brand-slate);
  text-align: left;
  cursor: pointer;
}
.admin-sidebar__lock svg {
  width: 18px;
  height: 18px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.admin-sidebar__link:hover,
.admin-sidebar__lock:hover {
  background: #faf8f5;
  color: var(--brand-dark);
}

/* ---------- Main content ---------- */
.admin-main {
  min-width: 0;
}
.admin-content {
  max-width: 1120px;
  margin: 0 auto;
  padding: 2rem 2rem 4rem;
  animation: admin-fade-in 180ms ease-out;
}
.admin-app.is-locked .admin-content {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
}
@keyframes admin-fade-in {
  from { opacity: 0; transform: translateY(4px); }
  to { opacity: 1; transform: none; }
}
.admin-content .portal-heading {
  margin: 0;
  font-size: 1.9rem;
}
.admin-content .portal-sub {
  margin-top: 0.35rem;
}

/* Sections become white cards */
.admin-content .admin-section {
  margin-top: 1.25rem;
  padding: 1.5rem;
  background: var(--brand-white);
  border: 1px solid var(--brand-border);
  border-radius: 16px;
  box-shadow: 0 1px 2px rgba(51, 51, 51, 0.04);
}
.admin-content .admin-section__title {
  margin: 0;
  font-size: 1.15rem;
}
.admin-content .admin-toggle-row {
  border-radius: 12px;
}

/* Stat tiles */
.admin-content .admin-stat-grid {
  margin-top: 1.25rem;
  grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
}
.admin-content .admin-stat-card {
  padding: 1.1rem 1.25rem;
  text-align: left;
  background: var(--brand-white);
  border-radius: 16px;
  box-shadow: 0 1px 2px rgba(51, 51, 51, 0.04);
  transition: box-shadow 150ms ease, transform 150ms ease;
}
.admin-content .admin-stat-card:hover {
  box-shadow: 0 6px 18px rgba(51, 51, 51, 0.08);
  transform: translateY(-1px);
}
.admin-content .admin-stat-card__value {
  font-size: 2rem;
  line-height: 1.1;
}
.admin-content .admin-stat-card__label {
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

/* Tables */
.admin-content .admin-table-wrap,
.admin-content .admin-section > div[style*="overflow-x"] {
  border-radius: 12px;
}
.admin-content .admin-table th {
  background: #faf8f5;
  font-size: 0.72rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--brand-slate);
}
.admin-content .admin-table tbody tr {
  transition: background-color 120ms ease;
}
.admin-content .admin-table tbody tr:hover {
  background: rgba(255, 80, 0, 0.035);
}
.admin-content .admin-funnel__step {
  background: #faf8f5;
  border-color: transparent;
}

/* Login card */
.admin-app.is-locked .portal-card--narrow {
  width: 100%;
  max-width: 26rem;
  padding: 2.25rem;
  background: var(--brand-white);
  border: 1px solid var(--brand-border);
  border-radius: 24px;
  box-shadow: 0 12px 40px rgba(51, 51, 51, 0.08);
}

/* Loading skeleton — same footprint as a real page so nothing jumps */
.admin-skeleton {
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
}
.admin-skeleton__bar,
.admin-skeleton__card,
.admin-skeleton__block {
  border-radius: 12px;
  background: linear-gradient(90deg, #efe9e1 25%, #f7f3ee 50%, #efe9e1 75%);
  background-size: 200% 100%;
  animation: admin-shimmer 1.2s linear infinite;
}
.admin-skeleton__bar--title {
  width: 14rem;
  height: 2rem;
}
.admin-skeleton__row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
  gap: 1rem;
}
.admin-skeleton__card {
  height: 5.5rem;
}
.admin-skeleton__block {
  height: 16rem;
}
@keyframes admin-shimmer {
  to { background-position: -200% 0; }
}
@media (prefers-reduced-motion: reduce) {
  .admin-content { animation: none; }
  .admin-skeleton__bar,
  .admin-skeleton__card,
  .admin-skeleton__block { animation: none; }
}

/* ---------- Narrow screens: sidebar becomes a top bar ---------- */
@media (max-width: 900px) {
  .admin-app {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto 1fr;
  }
  .admin-sidebar {
    position: sticky;
    z-index: 20;
    height: auto;
    flex-direction: row;
    align-items: center;
    gap: 0.75rem;
    padding: 0.6rem 0.75rem;
    overflow-x: auto;
    border-right: none;
    border-bottom: 1px solid var(--brand-border);
  }
  .admin-sidebar__brand img {
    height: 30px;
  }
  .admin-sidebar__badge {
    display: none;
  }
  .admin-sidebar__nav {
    flex-direction: row;
    gap: 0.25rem;
  }
  .admin-sidebar .admin-tab {
    width: auto;
    white-space: nowrap;
    padding: 0.55rem 0.75rem;
    font-size: 0.85rem;
  }
  .admin-sidebar__foot {
    margin: 0 0 0 auto;
    flex-direction: row;
    padding: 0;
    border-top: none;
  }
  .admin-sidebar__link {
    display: none;
  }
  .admin-sidebar__lock {
    width: auto;
    padding: 0.55rem 0.75rem;
  }
  .admin-content {
    padding: 1.25rem 1rem 3rem;
  }
}

.admin-content .admin-section > .admin-section__title {
  margin-bottom: 1rem;
}

/* ==========================================================================
   Home page revisions (2026-09-19 review): advisors heading, CFWP chapter
   list, laptop frame for the FW Checkup image, guidebook form note, and the
   Network FP-style dark footer (scoped to .site-footer--nfp so other pages
   keep their current footer until they're migrated).
   ========================================================================== */
.advisors-heading {
  text-align: center;
  font-size: clamp(1.4rem, 2.5vw, 1.9rem);
  margin: 0 auto 0.5rem;
  padding: 0 1rem;
}

.program-chapters {
  list-style: none;
  counter-reset: chapter;
  margin: 1.25rem 0 0;
  padding: 0;
  display: grid;
  gap: 0.5rem;
}
.program-chapters li {
  counter-increment: chapter;
  display: flex;
  align-items: baseline;
  gap: 0.75rem;
  font-size: 0.95rem;
  color: var(--brand-dark);
}
.program-chapters li::before {
  content: counter(chapter);
  flex: none;
  width: 1.5rem;
  height: 1.5rem;
  border-radius: 50%;
  background: var(--brand-orange);
  color: var(--brand-white);
  font-size: 0.75rem;
  font-weight: 700;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transform: translateY(0.2rem);
}
.program-chapters + .program-section__actions {
  margin-top: 1.5rem;
}

.laptop-frame {
  margin: 0;
  width: 100%;
}
.laptop-frame__lid {
  background: #1d1d1f;
  border: 2px solid #3a3a3d;
  border-bottom: none;
  border-radius: 14px 14px 0 0;
  padding: 10px 10px 12px;
  box-shadow: 0 24px 48px -24px rgba(0, 0, 0, 0.35);
}
.laptop-frame__lid img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 1847 / 845;
  object-fit: cover;
  object-position: top left;
  border-radius: 4px;
  background: var(--brand-white);
}
.laptop-frame__base {
  height: 14px;
  margin: 0 -4%;
  background: linear-gradient(#d9d9dc, #a8a8ad);
  border-radius: 0 0 16px 16px;
  position: relative;
}
.laptop-frame__base::before {
  content: "";
  position: absolute;
  top: 0;
  left: 50%;
  transform: translateX(-50%);
  width: 18%;
  height: 5px;
  background: #8a8a8f;
  border-radius: 0 0 8px 8px;
}

.guidebook-gate__why {
  margin: 0;
  font-size: 0.8rem;
  line-height: 1.4;
  color: var(--brand-slate);
}

.site-footer--nfp {
  background: #10243a;
  color: rgba(255, 255, 255, 0.8);
  border-top: none;
  margin-top: 4rem;
}
.site-footer--nfp .footer-about img {
  height: 56px;
}
.site-footer--nfp .footer-about p {
  color: rgba(255, 255, 255, 0.75);
  opacity: 1;
  max-width: 26rem;
  line-height: 1.6;
}
.site-footer--nfp .footer-about p.footer-founders {
  margin-top: 1.25rem;
  color: var(--brand-white);
  font-weight: 600;
}
.site-footer--nfp .footer-founders span {
  font-weight: 400;
  color: rgba(255, 255, 255, 0.65);
}
.site-footer--nfp .footer-grid {
  padding-top: 4rem;
}
@media (min-width: 1024px) {
  .site-footer--nfp .footer-grid {
    grid-template-columns: 2fr 1fr 1fr 1fr;
    gap: 3rem;
  }
}
.site-footer--nfp .footer-col h3 {
  color: var(--brand-white);
  font-size: 0.8rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
.site-footer--nfp .footer-col a {
  color: rgba(255, 255, 255, 0.8);
  opacity: 1;
}
.site-footer--nfp .footer-col a:hover {
  color: var(--brand-orange);
}
.site-footer--nfp .footer-bottom {
  border-top-color: rgba(255, 255, 255, 0.15);
  color: rgba(255, 255, 255, 0.7);
  flex-wrap: wrap;
}
.site-footer--nfp .footer-bottom p {
  margin: 0;
}
.site-footer--nfp .footer-bottom__initiative {
  color: var(--brand-white);
}
.site-footer--nfp .footer-bottom__legal {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.25rem;
}
.site-footer--nfp .footer-bottom__legal a {
  color: rgba(255, 255, 255, 0.7);
}
.site-footer--nfp .footer-bottom__legal a:hover {
  color: var(--brand-orange);
}
/* Don't show the heading alone if the professionals strip hasn't loaded. */
.advisors-section:has(#advisors-marquee[hidden]) .advisors-heading {
  display: none;
}

/* FW Program section redesign (2026-09-19): labelled blocks in the right
   column instead of one undifferentiated stack; meta tag on the video. */
.program-section__side {
  display: flex;
  flex-direction: column;
  gap: 1.75rem;
}
.program-section__side .program-section__actions {
  margin-top: 0;
}
.program-section__side .program-section__actions .btn {
  width: 100%;
  justify-content: center;
}
.program-block-title {
  margin: 0 0 0.9rem;
  font-family: inherit;
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--brand-orange);
}
.program-block-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 0.9rem;
}
.program-block-head .program-block-title {
  margin: 0;
}
.program-block-tag {
  font-size: 0.75rem;
  font-weight: 600;
  padding: 0.2rem 0.65rem;
  border-radius: 999px;
  background: rgba(255, 80, 0, 0.1);
  color: var(--brand-orange);
}
.program-section__side .program-section__points li {
  color: var(--brand-dark);
}
.program-section__side .program-chapters {
  margin: 0;
  gap: 0;
  background: var(--brand-white);
  border: 1px solid var(--brand-border);
  border-radius: 14px;
  padding: 0.35rem 1rem;
}
.program-section__side .program-chapters li {
  align-items: center;
  padding: 0.6rem 0;
  border-bottom: 1px solid var(--brand-border);
}
.program-section__side .program-chapters li:last-child {
  border-bottom: none;
}
.program-section__side .program-chapters li::before {
  transform: none;
}
.program-preview-card {
  position: relative;
}
.program-preview-card::after {
  content: attr(data-meta);
  position: absolute;
  left: 1rem;
  bottom: 1rem;
  padding: 0.35rem 0.8rem;
  border-radius: 999px;
  background: rgba(0, 0, 0, 0.55);
  color: var(--brand-white);
  font-size: 0.8rem;
  font-weight: 600;
  pointer-events: none;
}
.program-preview-card .video-frame__placeholder p {
  display: none;
}

/* Compact pass (2026-09-19): too much vertical scroll — chapters go two-up,
   spacing tightens. */
.program-section {
  padding: 2.5rem 0;
}
.program-section .program-section__grid {
  margin-top: 1.75rem;
  gap: 2rem;
}
.program-section__side {
  gap: 1.1rem;
}
.program-block-title {
  margin-bottom: 0.6rem;
}
.program-block-head {
  margin-bottom: 0.6rem;
}
.program-section__side .program-section__points {
  gap: 0.5rem;
}
.program-section__side .program-chapters {
  grid-template-columns: 1fr;
  padding: 0.2rem 0.9rem;
}
.program-section__side .program-chapters li {
  padding: 0.4rem 0;
  font-size: 0.875rem;
}
@media (min-width: 1100px) {
  .program-section__side .program-chapters {
    grid-template-columns: 1fr 1fr;
    column-gap: 1.5rem;
  }
  .program-section__side .program-chapters li:nth-last-child(2):nth-child(odd) {
    border-bottom: none;
  }
}

/* FW Program layout v3 (2026-09-19): video + topics side by side at equal
   height, then one slim strip (3 points + CTA) — replaces the tall stacked
   right column so the section fits close to one screen. */
.program-layout {
  display: grid;
  gap: 1.5rem;
  margin-top: 1.75rem;
  align-items: stretch;
}
@media (min-width: 900px) {
  .program-layout {
    grid-template-columns: 1fr 1fr;
  }
}
.program-layout .program-preview-card {
  aspect-ratio: 16 / 9;
  height: 100%;
  min-height: 240px;
}
.program-topics {
  background: var(--brand-white);
  border: 1px solid var(--brand-border);
  border-radius: 16px;
  padding: 1.1rem 1.25rem;
  display: flex;
  flex-direction: column;
  justify-content: center;
}
.program-topics .program-block-head {
  margin-bottom: 0.5rem;
}
.program-topics .program-chapters {
  margin: 0;
  padding: 0;
  border: none;
  background: none;
  display: grid;
  grid-template-columns: 1fr;
  column-gap: 1.5rem;
}
@media (min-width: 1100px) {
  .program-topics .program-chapters {
    grid-template-columns: 1fr 1fr;
  }
}
.program-topics .program-chapters li {
  padding: 0.5rem 0;
  font-size: 0.875rem;
  align-items: center;
  border-bottom: 1px solid var(--brand-border);
}
.program-topics .program-chapters li::before {
  transform: none;
}
.program-strip {
  margin-top: 1.25rem;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 1rem 2rem;
}
.program-strip__points {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.75rem;
  flex: 1 1 32rem;
}
.program-strip__points li {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.875rem;
  color: var(--brand-dark);
}
.program-strip__points svg {
  flex: none;
  color: var(--brand-orange);
}
.program-strip .btn {
  flex: none;
}

/* FW Program v4 (2026-09-19): the 7 topics as the original plain checklist
   beside the video, CTA under it. Overrides the earlier v2/v3 blocks. */
.program-section .program-section__grid {
  align-items: center;
}
.program-section__side {
  gap: 0.9rem;
}
.program-section__side .program-section__points {
  gap: 0.55rem;
}
.program-section__side .program-section__points li {
  color: var(--brand-dark);
  font-size: 0.95rem;
}
.program-section__side .program-section__actions {
  margin-top: 0.5rem;
}
.program-section__side .program-section__actions .btn {
  width: auto;
}
.program-section__grid .program-preview-card {
  height: auto;
  min-height: 0;
}

/* FW Checkup preview shown as a laptop (2026-09-19): dark bezel around the
   browser-window video, hinged base underneath. */
.laptop-device {
  width: 100%;
}
.laptop-device .browser-frame {
  background: #1d1d1f;
  border: 2px solid #3a3a3d;
  border-bottom: none;
  border-radius: 16px 16px 0 0;
  padding: 12px 12px 14px;
  box-shadow: none;
  overflow: visible;
}
.laptop-device .browser-frame__bar {
  border-radius: 8px 8px 0 0;
  border-bottom: 1px solid var(--brand-border);
}
.laptop-device .browser-frame__screen {
  border-radius: 0 0 6px 6px;
  overflow: hidden;
}
.laptop-device__base {
  position: relative;
  height: 16px;
  margin: 0 -5%;
  background: linear-gradient(#dcdcdf, #a6a6ab);
  border-radius: 0 0 18px 18px;
  box-shadow: 0 22px 36px -18px rgba(0, 0, 0, 0.35);
}
.laptop-device__base::before {
  content: "";
  position: absolute;
  top: 0;
  left: 50%;
  transform: translateX(-50%);
  width: 16%;
  height: 6px;
  background: #8a8a8f;
  border-radius: 0 0 10px 10px;
}

/* Wider laptop (2026-09-19): bigger share of the row for the preview. */
.fw-checkup-section .laptop-device {
  max-width: none;
}

/* Wider + shorter laptop (2026-09-19). The screen is cropped to a wide 16:10
   from the video's 1.3:1, anchored to the top so the score panel stays visible. */
.fw-checkup-section .laptop-device .browser-frame__screen {
  aspect-ratio: 16 / 9;
}
.fw-checkup-section .laptop-device .browser-frame__video {
  object-position: top center;
}

/* The recording has black margins on its left and top edges (the poster frame
   shows the same) — zoom in and shift so they fall outside the screen. */
.fw-checkup-section .laptop-device .browser-frame__video {
  transform-origin: 0 0;
  transform: scale(1.1) translate(-4.8%, -9%);
}

/* Less zoom (2026-09-19): back to the video's own 1094:838 shape so nothing is
   cropped vertically, and only the minimum scale needed to hide the black
   margins (4.8% left, 6.6% top). */
.fw-checkup-section .laptop-device .browser-frame__screen {
  aspect-ratio: 1094 / 838;
}
.fw-checkup-section .laptop-device .browser-frame__video {
  transform: scale(1.07) translate(-4.8%, -6.6%);
}

/* Short screen, minimal zoom (2026-09-19): 16:9 screen again. The top black
   margin is now hidden by shifting the video up inside the frame
   (object-position) instead of scaling, so only the left margin needs a 5%
   zoom. */
.fw-checkup-section .laptop-device .browser-frame__screen {
  aspect-ratio: 16 / 9;
}
.fw-checkup-section .laptop-device .browser-frame__video {
  object-position: 50% 25%;
  transform: scale(1.05) translate(-4.8%, 0);
}

/* Zoomed out (2026-09-19): no scaling at all. The recording's black left margin
   is covered by a strip of the report's own white page background instead of
   being cropped away, and the top margin is hidden by the object-position
   shift above. Laptop size/shape unchanged. */
.fw-checkup-section .laptop-device .browser-frame__screen {
  position: relative;
}
.fw-checkup-section .laptop-device .browser-frame__video {
  transform: none;
}
.fw-checkup-section .laptop-device .browser-frame__screen::before {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: 4.9%;
  background: var(--brand-white);
  z-index: 1;
  pointer-events: none;
}

/* FW Checkup questions on wide screens (2026-09-19): use the empty left/right
   space instead of one narrow centred column — question + helper on the left,
   answer options on the right. Only the Previous/Next/progress row stays in a
   narrow centred column. The welcome/intake form (no .is-question) is left
   alone. */
@media (min-width: 1000px) {
  .fw-checkup .flow-container:has(.question-card.is-question) {
    max-width: 76rem;
  }
  .fw-checkup .question-card.is-question .question-card__panel {
    display: grid;
    grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.25fr);
    column-gap: 3.5rem;
    align-items: start;
    padding: 2rem 2.5rem;
  }
  .fw-checkup .question-card.is-question .question-card__panel > * {
    grid-column: 1;
  }
  .fw-checkup .question-card.is-question .question-card__panel > .option-grid,
  .fw-checkup .question-card.is-question .question-card__panel > .text-input {
    grid-column: 2;
    grid-row: 1 / span 4;
  }
  .fw-checkup .question-card.is-question .question-prompt {
    font-size: 1.9rem;
  }
  .fw-checkup .flow-container:has(.question-card.is-question) .flow-nav {
    width: 100%;
    max-width: 40rem;
    margin-left: auto;
    margin-right: auto;
  }
}

/* Hero trust row v2 (2026-09-19): Qualified / Licensed / Experienced — white
   rounded icon tiles, navy title, grey description (replaces the round-chip
   "Guided by Experts…" row). */
.hero-trust {
  gap: 1.25rem 1.5rem;
  margin-top: 2rem;
}
.hero-trust li,
.hero-trust li:not(:last-child) {
  align-items: flex-start;
  gap: 0.85rem;
  padding-right: 0;
  border-right: none;
  flex: 1 1 0;
  min-width: 0;
}
.hero-trust__icon {
  width: 3.25rem;
  height: 3.25rem;
  border-radius: 12px;
  background: var(--brand-white);
  box-shadow: 0 2px 10px rgba(16, 36, 58, 0.08);
}
.hero-trust .hero-trust__text {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  font-size: inherit;
  font-weight: 400;
}
.hero-trust__text strong {
  font-size: 1rem;
  font-weight: 700;
  color: #12395f;
  line-height: 1.25;
}
.hero-trust .hero-trust__text span {
  font-size: 0.875rem;
  font-weight: 400;
  color: var(--brand-slate);
  line-height: 1.4;
}
.hero-trust {
  gap: 1.25rem 1rem;
}
.hero-trust .hero-trust__text span {
  color: #5b6670;
}
.hero-trust li,
.hero-trust li:not(:last-child) {
  align-items: center;
}
.reg-mark {
  font-size: 0.55em;
  line-height: 0;
  vertical-align: super;
  margin-left: 0.05em;
}

/* Question vertically centred against the answer list (2026-09-19). Spacer rows
   above/below share the leftover height so the question + helper sit at the
   middle of the left column. */
@media (min-width: 1000px) {
  .fw-checkup .question-card.is-question .question-card__panel {
    grid-template-rows: 1fr auto auto 1fr;
  }
  .fw-checkup .question-card.is-question .question-card__panel > .question-badge {
    grid-row: 1;
  }
  .fw-checkup .question-card.is-question .question-card__panel > .question-prompt {
    grid-row: 2;
  }
  .fw-checkup .question-card.is-question .question-card__panel > .question-helper {
    grid-row: 3;
  }
  .fw-checkup .question-card.is-question .question-card__panel > .option-grid,
  .fw-checkup .question-card.is-question .question-card__panel > .text-input {
    grid-row: 1 / -1;
    align-self: center;
  }
}

/* Free 1:1 Consultation top stack (2026-09-19 review) — site menu + masthead stripe
   + progress bar. The stripe is a full-width horizontal band carrying the page
   heading and the step counter. */
.flow-top {
  flex: none;
}
.flow-masthead {
  background: var(--brand-orange);
  color: var(--brand-white);
}
.flow-masthead__row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.85rem 0;
}
.flow-masthead__title {
  margin: 0;
  font-size: clamp(1.2rem, 2.4vw, 1.7rem);
  line-height: 1.2;
  color: var(--brand-white);
}
.flow-masthead .flow-masthead__step {
  margin: 0;
  color: rgba(255, 255, 255, 0.92);
  font-size: 0.9rem;
  white-space: nowrap;
}
.consult-select {
  appearance: auto;
  margin-top: 0.85rem;
  cursor: pointer;
}
.flow-top .progress-track {
  height: 4px;
}
.flow-top .progress-fill {
  background: #12395f;
}
/* Wider consultation column + two-column option lists so the 13-goal / 12-product
   lists fit without scrolling on desktop. */
@media (min-width: 760px) {
  .consultation-flow .flow-container {
    max-width: 52rem;
  }
  .consultation-flow .option-grid:not(.option-grid--pills) {
    grid-template-columns: 1fr 1fr;
    align-content: start;
  }
}

/* Booking form (2026-09-19 review): the free-text note sits at the end and gets real room. */
.portal-field-optional {
  font-weight: 400;
  color: var(--brand-slate);
}
textarea.booking-note {
  min-height: 8rem;
  resize: vertical;
  line-height: 1.5;
  font-family: inherit;
}

/* Match profile panel (2026-09-19): hug the content instead of stretching to the full
   column height, which left a big empty gap above the CTA. Long profiles still scroll
   inside the body (max-height) with the CTA pinned below. */
@media (min-width: 900px) {
  .profile-panel {
    height: auto;
    max-height: 100%;
  }
  .match-columns__right {
    align-self: start;
    max-height: 100%;
  }
}

.booking-back {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  margin: 0.25rem 0 0.25rem;
  padding: 0.45rem 1rem;
  border: 1px solid var(--brand-border);
  border-radius: 999px;
  background: var(--brand-white);
  color: var(--brand-dark);
  font-size: 0.9rem;
  font-weight: 600;
}
.booking-back[hidden] {
  display: none;
}
.booking-back:hover {
  border-color: var(--brand-orange);
  color: var(--brand-orange);
}

/* Booking page: the Back pill sits directly above the details card, left-aligned with
   it. .flow-main is a row flexbox, which put the pill's container beside the card. */
.flow-main:has(#booking-back) {
  flex-direction: column;
  align-items: stretch;
  justify-content: center;
}
.flow-main:has(#booking-back) > .container {
  width: 100%;
}
.flow-main:has(#booking-back) #booking-back {
  align-self: flex-start;
}
.booking-back-row {
  max-width: 40rem;
  padding-top: 1rem;
  padding-bottom: 0;
}
.flow-main:has(#booking-root.booking-guest-page) .booking-back-row {
  max-width: 72rem;
  padding-left: 1.25rem;
  padding-right: 1.25rem;
}

/* Booked screen: "Back to home" lines up with the confirmation card's left edge. */
.booking-back-row:has(#booking-back[data-mode="home"]) {
  max-width: 30rem;
  margin-inline: auto;
  padding-inline: 0;
}

/* Consultation questions: the welcome/intake screen (and any tall question) scrolls
   instead of being clipped, since the menu + masthead now use part of the viewport. */
.consultation-flow .flow-question-area {
  overflow-y: auto;
  align-items: flex-start;
}
.consultation-flow .question-card {
  margin-block: auto;
}
.consultation-flow .flow-masthead__row {
  padding: 0.6rem 0;
}
.consultation-flow .welcome-list {
  margin-top: 0.7rem;
  gap: 0.35rem;
}
.consultation-flow .welcome-intake {
  gap: 0.6rem;
}

/* FW Checkup top stack (2026-09-19 review): menu + masthead (see .flow-masthead above).
   The question area scrolls instead of clipping when the screen is short. */
.fw-checkup .flow-masthead__row {
  padding: 0.6rem 0;
}
.fw-checkup .flow-question-area {
  overflow-y: auto;
  align-items: flex-start;
}
.fw-checkup .question-card {
  margin-block: auto;
}
.fw-checkup .question-greeting {
  font-size: 0.95rem;
}

/* FW Checkup: "Question 3 of 20" sits above the question, and both it and the
   "Financial Wellbeing Checkup for <name>" line use the question's serif face. */
.fw-checkup .question-badge {
  display: block;
  margin: 0 0 0.45rem;
  padding: 0;
  background: none;
  border-radius: 0;
  font-family: var(--font-heading);
  font-size: 1.15rem;
  font-weight: 400;
  color: var(--brand-orange);
}
.fw-checkup .question-greeting {
  font-family: var(--font-heading);
  font-size: 1.15rem;
  font-weight: 400;
  color: var(--brand-dark);
  margin-bottom: 0.7rem;
}
