/* ==========================================================================
   Fonts — Fraunces, self-hosted, the site's only font family (client wants
   one typeface site-wide, not a heading/body pairing — Inter and its Google
   Fonts CDN link were removed 2026-08-16). Served as a variable font
   (Latin-subset only — this is an English-only site, no need for the
   Latin-Extended/Vietnamese subsets Google also offers), so one file each
   for roman/italic covers the full 400-700 weight range via the
   `font-weight` range syntax below — normal `font-weight: 500` etc. in any
   rule using --font-heading/--font-body just works, no
   font-variation-settings needed.
   ========================================================================== */
@font-face {
  font-family: "Fraunces";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("../fonts/fraunces-variable-latin.woff2") format("woff2");
}

@font-face {
  font-family: "Fraunces";
  font-style: italic;
  font-weight: 400 700;
  font-display: swap;
  src: url("../fonts/fraunces-variable-italic-latin.woff2") format("woff2");
}

/* ==========================================================================
   Reset
   ========================================================================== */
*, *::before, *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}

body {
  min-height: 100vh;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

img, picture, svg, video {
  display: block;
  max-width: 100%;
}

input, button, textarea, select {
  font: inherit;
}

a {
  color: inherit;
  text-decoration: none;
}

ul, ol {
  list-style: none;
}

/* ==========================================================================
   Custom properties — confirmed brand palette (client-approved)
   Accent briefly swapped to gold 2026-07-26, then reverted to sage the same
   day — gold was a UI-only experiment, never client-confirmed. Sage is the
   palette that's actually signed off. The --color-sage* tokens are the
   single point of truth for the accent (buttons, icons, borders, focus
   rings, links, the hero ornament dividers on ethical-investing.html).
   ========================================================================== */
:root {
  --color-bg: #FAF8F2;
  --color-navy: #14213D;
  --color-cream: #F5EFD9;
  --color-sage: #6B7F5E;
  --color-sage-light: #E4E9DD;
  /* Deeper sage for cream-on-sage solid fills (the primary button) —
     --color-sage itself only clears 3.78:1 against cream text, short of
     WCAG AA's 4.5:1 for normal text. This shade clears 4.74:1 on cream and
     comfortably passes on --color-sage-light (the icon-badge fill), so it covers both
     text-on-cream and text-on-sage-light uses. */
  --color-sage-deep: #5c6f50;
  /* Lighter sage for accent TEXT on the dark navy card (--color-ink) — plain
     --color-sage on navy is only ~3.9:1, short of AA for normal text (the
     ethical-investing.html hero highlight words "wealth"/"values" were
     failing this). This shade clears ~6.9:1 on navy while still reading as a
     sage-green accent, not white. Dark-card text only. */
  --color-sage-bright: #93AD82;

  --color-text: var(--color-navy);
  --color-text-muted: #545f74;
  --color-text-inverse: var(--color-cream);
  --color-border: rgba(20, 33, 61, 0.12);

  /* Card-system aliases: dark "authority bookend" cards use --color-ink,
     light cards use --color-surface — kept distinct from --color-bg so
     the page's neutral base is visible between cards. */
  --color-ink: var(--color-navy);
  --color-surface: var(--color-cream);

  --font-heading: "Fraunces", "Georgia", serif;
  --font-body: "Fraunces", "Georgia", serif;

  /* Spacing scale — every value is a multiple of 8px (0.5rem), so gaps and
     padding read as one deliberate rhythm rather than per-section guesses.
     --space-sm moved from 12px to 16px to fit that rule; md/lg/xl were
     already clean multiples (24/48/96px) and are unchanged. */
  --space-2xs: 0.5rem;  /* 8px  — tight gaps: icon+label, inline chips */
  --space-sm: 1rem;     /* 16px — within-component spacing */
  --space-md: 1.5rem;   /* 24px — between related elements/cards */
  --space-lg: 3rem;     /* 48px — card internal padding, section gaps */
  --space-xl: 6rem;     /* 96px — section block padding */

  /* Type scale — h1-h3 + body, so every heading/paragraph on the page
     pulls from one set of sizes instead of ad-hoc per-section values. */
  --fs-h1: clamp(1.75rem, 5vw, 3.25rem);   /* hero title only — sized down from 2.25-4rem so the longer "…financial independence starts here." headline isn't cramped */
  --fs-h2: clamp(1.75rem, 4vw, 2.5rem);    /* section titles */
  --fs-h3: clamp(1.25rem, 2.5vw, 1.5rem);  /* card/FAQ headings */
  --fs-body-lg: clamp(1rem, 2.2vw, 1.2rem); /* lead paragraphs/subtitles */
  --fs-body: 1rem;                          /* default body text */
  --fs-small: 0.875rem;                     /* meta/footer text */

  --card-gap: 2rem;
  --card-radius: 16px;

  --radius: 8px;
  --radius-sm: 12px;
  --radius-xs: 10px;
  --transition-base: 400ms ease;
  /* Faster variant for anything tightly coupled to scroll position (Why
     Ethical's active/inactive item state, its description cross-fade) —
     --transition-base's 400ms reads as laggy/delayed there, visibly
     playing catch-up behind the actual scroll input rather than tracking
     it, especially under a normal-to-fast scroll gesture. */
  --transition-fast: 180ms ease;
  --container-width: 1100px;
  /* Desktop nav is ~61px (44px touch-target links + 8px padding block).
     Referenced by .why-ethical__pin's sticky `top` and by .card's
     scroll-margin-top (so anchor jumps land clear of the sticky nav).
     Re-measured after the 44px tap-target pass — the responsive overrides
     below track the taller wrapped nav at narrow widths. */
  --nav-height: 64px;

  /* Elevation scale — every "raised" surface (light card, service card,
     contact form, the Why Ethical active card) pulls from one of these
     three, navy-tinted for consistency, instead of each declaring its own
     shadow recipe (previously 5 different ones, one of them plain black
     instead of navy-tinted). */
  --shadow-sm: 0 4px 16px rgba(20, 33, 61, 0.08);
  --shadow-md: 0 10px 28px rgba(20, 33, 61, 0.14);
  --shadow-lg: 0 16px 40px rgba(20, 33, 61, 0.24);
}

/* ==========================================================================
   Base
   ========================================================================== */
body {
  font-family: var(--font-body);
  color: var(--color-text);
  background: var(--color-bg);
  /* Justify body copy site-wide — an inherited default, not a rule on `p`
     directly, so every element that already sets its own text-align
     (.about__copy/.hero__subtitle/.section__title etc. centered, nav/
     buttons effectively unaffected since they're single-line) keeps that
     explicit alignment; only the plain left-aligned long-form paragraphs
     (FAQ answers, accordion/approach bodies, blog posts, disclosures)
     pick up justify. hyphens:auto keeps justified word-spacing from
     opening up ugly gaps/rivers on narrow columns. */
  text-align: justify;
  hyphens: auto;
}

/* Mobile: drop the justify. In a ~340px serif column it opens loose rivers
   between words and the auto-hyphenation adds broken words on top — both
   read worse than a clean ragged-right edge. This only flips the inherited
   default; every block with its own explicit text-align (centered titles,
   left-aligned lists, etc.) keeps it. */
@media (max-width: 640px) {
  body {
    text-align: left;
    hyphens: manual;
  }
}

/* Weight 500 site-wide, including the hero — matches .why-ethical__headline's
   upright, medium-weight treatment (client preference, after seeing both
   side by side; the hero was tried at italic/700 first and dropped). */
h1, h2, h3 {
  font-family: var(--font-heading);
  font-weight: 500;
  line-height: 1.2;
}

h3 {
  font-size: var(--fs-h3);
}

.container {
  width: 100%;
  max-width: var(--container-width);
  margin-inline: auto;
  padding-inline: var(--space-md);
}

/* Visually-hidden but screen-reader-accessible — used for form field
   labels where the visible affordance is a placeholder instead (the
   contact form), since placeholders alone aren't a reliable substitute
   for a real, programmatically-associated label. */
/* Skip link — hidden off-screen until focused, then pinned over the nav.
   NOT `display:none`/`visibility:hidden`: either would remove it from the tab
   order entirely, which defeats the point. It sits above the sticky nav's
   z-index (200 is the FAB, the nav is below that) so it can't appear behind it. */
.skip-link {
  position: absolute;
  top: -100px;
  left: var(--space-md);
  z-index: 300;
  padding: var(--space-sm) var(--space-md);
  background: var(--color-cream);
  color: var(--color-navy);
  font-size: var(--fs-small);
  font-weight: 600;
  border-radius: 0 0 var(--radius) var(--radius);
  box-shadow: var(--shadow-md);
  transition: top var(--transition-fast);
}

.skip-link:focus {
  top: 0;
}

.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;
}

.section {
  padding-block: var(--space-xl);
}

@media (max-width: 767px) {
  /* --space-xl (96px) top+bottom per section reads as unused chrome on a
     phone screen rather than breathing room — halve it there, unrelated
     to the card's own margin/radius mobile overrides below. */
  .section {
    padding-block: var(--space-lg);
  }
}

/* Small uppercase label above a .section__title — "SERVICES", "CONTACT",
   etc. Shared component so this eyebrow+headline pattern is consistent
   wherever it's used, not re-declared per section. */
.section__eyebrow {
  display: block;
  font-size: var(--fs-small);
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--color-sage-deep);
  text-align: center;
  margin-bottom: var(--space-sm);
}

.section__title {
  font-size: var(--fs-h2);
  margin-bottom: var(--space-lg);
  text-align: center;
}

/* One button component, one set of dimensions/weight/transition. Every CTA
   on the site is .btn + a .btn--* modifier — sizing, radius, font-weight,
   the 44px touch floor and the hover/focus transition list all live here so
   buttons never drift apart per section (client "CTA standardization" pass,
   2026-08-29). Only colour/border differs between --primary and --secondary
   below; --primary is the single primary action (WhatsApp) everywhere. */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5em;
  min-height: 44px; /* touch target (WCAG 2.5.5 / Apple HIG) — consistent across every .btn */
  padding: var(--space-sm) var(--space-lg);
  border-radius: 999px;
  font-weight: 600;
  font-size: var(--fs-body);
  font-family: var(--font-body);
  line-height: 1.2;
  /* Override the inherited body{text-align:justify} default — a button
     label is never long-form copy, and on narrow mobile widths where a
     longer label wraps to 2 lines (e.g. services.html's "Learn About
     Ethical Investing"), justify stretched huge gaps between the words on
     the first line. Centered reads better than left for a symmetric pill
     shape when a label does wrap. */
  text-align: center;
  transition: transform var(--transition-base), background var(--transition-base), box-shadow var(--transition-base), border-color var(--transition-base);
}

.btn--primary {
  background: var(--color-sage-deep);
  color: var(--color-cream);
  box-shadow: 0 8px 24px rgba(107, 127, 94, 0.35);
}

.btn--primary:hover,
.btn--primary:focus-visible {
  background: #4d5f43;
  transform: translateY(-2px);
  box-shadow: 0 12px 28px rgba(107, 127, 94, 0.45);
}

/* Ghost/outline secondary — cream-on-navy is the default, correct for the
   hero (a dark card). The .card--light override just below swaps in a
   navy-based treatment, so the same class reads correctly whichever
   surface it lands on without needing a second button component. */
.btn--secondary {
  background: transparent;
  color: var(--color-cream);
  border: 1.5px solid rgba(245, 239, 217, 0.5);
}

.btn--secondary:hover,
.btn--secondary:focus-visible {
  border-color: var(--color-cream);
  background: rgba(245, 239, 217, 0.08);
  transform: translateY(-2px);
}

.card--light .btn--secondary {
  color: var(--color-navy);
  border-color: rgba(20, 33, 61, 0.35);
}

.card--light .btn--secondary:hover,
.card--light .btn--secondary:focus-visible {
  border-color: var(--color-navy);
  background: rgba(20, 33, 61, 0.06);
}

.btn__icon {
  width: 1.15em;
  height: 1.15em;
  flex-shrink: 0;
}

/* ==========================================================================
   Focus-visible — keyboard-navigation outline for every interactive
   element on the page (buttons, links, nav, and the FAQ accordion
   trigger added later). Kept as one rule so focus styling is consistent
   site-wide rather than added ad hoc per component.
   ========================================================================== */
a:focus-visible,
button:focus-visible,
.btn:focus-visible {
  outline: 2px solid var(--color-sage);
  outline-offset: 3px;
}

/* ==========================================================================
   Nav — the only full-width element on the page. Sticky (was non-sticky) —
   see the .nav rule below for why.
   ========================================================================== */
/* Sticky, not fixed — same "always visible while scrolling" result (nav is
   the first element, so sticky's "stick once past its natural position"
   collapses to "stick immediately"), without fixed's need to manually
   compensate with padding-top elsewhere to avoid content jumping under it.
   Keeps the WhatsApp CTA and nav links reachable throughout the scroll,
   which matters more for a conversion-focused site than the page reading
   as a calmer, nav-recedes-once-you-scroll editorial piece. */
.nav {
  position: sticky;
  top: 0;
  z-index: 100;
  width: 100%;
  background: var(--color-navy);
  border-bottom: 1px solid rgba(245, 239, 217, 0.12);
}

.nav__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  /* Trimmed from --space-sm (16px) to --space-2xs (8px): the nav links now
     carry their own 44px min-height for touch, so this keeps the overall
     desktop nav height roughly where it was (~60px) rather than growing it. */
  padding-block: var(--space-2xs);
}

.nav__brand {
  position: relative; /* anchors .nav__brand-spark over the logo mark */
  display: flex;
  align-items: center;
  gap: 0.6rem;
}

/* 34px, up from 26px when this became the full logo mark (logo-mark.png).
   Not a style tweak — the full mark surrounds the tree with stars, so the
   crescent only spans ~76% of the frame (measured) versus tree.png where it
   fills the width. At the old 26px the tree rendered ~40% smaller than before
   and the stars became 1–2px specks that read as dust. 26 / 0.76 ≈ 34 puts the
   tree back at its previous size. Same reasoning for the footer/About marks. */
.nav__logo-mark {
  width: 34px;
  height: auto;
  transition: transform var(--transition-fast) ease;
}

.nav__wordmark {
  font-family: var(--font-body);
  font-weight: 600;
  font-size: var(--fs-small); /* was a one-off 0.9rem — on the type scale now */
  color: var(--color-cream);
  white-space: nowrap;
  transition: color var(--transition-fast);
}

/* Brand hover — the mark's own stars catch the light. The logo image is a
   flat raster (logo-mark.png), so the twinkle lives in an SVG sparkle
   cluster (.nav__brand-spark) laid over it: at rest it's invisible and the
   logo is untouched; on hover each sparkle blinks in and drifts a hair,
   staggered + de-synced like the hero star field. The image itself just
   does a whisper of scale — no tilt. */
.nav__brand-spark {
  position: absolute;
  left: 0;
  top: 50%;
  width: 34px; /* matches .nav__logo-mark */
  height: 36px;
  transform: translateY(-50%);
  overflow: visible; /* let sparkles drift past the logo box without clipping */
  pointer-events: none;
}

.nav__brand-spark path {
  fill: var(--color-cream);
  opacity: 0;
  transform-box: fill-box;
  transform-origin: center;
  transition: opacity var(--transition-base) ease; /* fade back out when hover ends */
}

.nav__brand:hover .nav__logo-mark,
.nav__brand:focus-visible .nav__logo-mark {
  transform: scale(1.04);
}

.nav__brand:hover .nav__wordmark,
.nav__brand:focus-visible .nav__wordmark {
  color: var(--color-sage-light);
}

.nav__brand:hover .nav__brand-spark path,
.nav__brand:focus-visible .nav__brand-spark path {
  animation: nav-brand-spark 1.7s ease-in-out infinite;
}

/* Per-sparkle phase + period offsets so they never pulse in lockstep —
   same trick as .hero__star:nth-child(). */
.nav__brand:hover .nav__brand-spark g:nth-child(1) path,
.nav__brand:focus-visible .nav__brand-spark g:nth-child(1) path { animation-delay: 0.05s; animation-duration: 1.5s; }
.nav__brand:hover .nav__brand-spark g:nth-child(2) path,
.nav__brand:focus-visible .nav__brand-spark g:nth-child(2) path { animation-delay: 0.34s; animation-duration: 2s; }
.nav__brand:hover .nav__brand-spark g:nth-child(3) path,
.nav__brand:focus-visible .nav__brand-spark g:nth-child(3) path { animation-delay: 0.56s; animation-duration: 1.65s; }
.nav__brand:hover .nav__brand-spark g:nth-child(4) path,
.nav__brand:focus-visible .nav__brand-spark g:nth-child(4) path { animation-delay: 0.19s; animation-duration: 2.15s; }
.nav__brand:hover .nav__brand-spark g:nth-child(5) path,
.nav__brand:focus-visible .nav__brand-spark g:nth-child(5) path { animation-delay: 0.72s; animation-duration: 1.8s; }

@keyframes nav-brand-spark {
  0%,
  100% { opacity: 0.12; transform: scale(0.5) rotate(-20deg); }
  30%  { opacity: 1;    transform: scale(1) rotate(0deg); }
  52%  { opacity: 0.35; transform: scale(0.78) rotate(13deg) translateY(-2px); }
  74%  { opacity: 1;    transform: scale(1.06) rotate(-5deg); }
}

.nav__links {
  display: flex;
  /* Gap trimmed to --space-2xs; the links now carry --space-2xs of inline
     padding each, so text-to-text spacing stays ~the old --space-md while
     the padding widens short links (FAQ, About) to clear the 44px touch
     minimum on width, not just height. */
  gap: var(--space-2xs);
  /* Push the links (and the header CTA after them) to the right of the
     brand — .nav__inner is space-between, this keeps brand hard-left and
     the links+CTA group hard-right even with three flex children. */
  margin-left: auto;
}

.nav__links a {
  position: relative; /* anchors the ::before underline */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px; /* touch target (WCAG 2.5.5 / Apple HIG) — text is only ~18px tall */
  padding-inline: var(--space-2xs); /* widens short links to >=44px too */
  font-family: var(--font-body);
  font-size: var(--fs-small);
  font-weight: 500;
  color: var(--color-cream);
  transition: color var(--transition-fast);
}

/* Centre-out underline on hover/focus. scaleX (not width) keeps it a
   transform-only animation — the site's motion rule. Sits just under the
   text baseline, not the full 44px touch box. Disabled inside the dropdown
   panel (see .nav__dropdown a::before) and on the stacked mobile menu. */
.nav__links a::before {
  content: '';
  position: absolute;
  left: var(--space-2xs);
  right: var(--space-2xs);
  bottom: 7px;
  height: 2px;
  border-radius: 2px;
  background: var(--color-sage-bright);
  transform: scaleX(0);
  transform-origin: center;
  transition: transform var(--transition-fast) ease;
}

.nav__links a:hover,
.nav__links a:focus-visible {
  color: var(--color-sage-light);
}

.nav__links a:hover::before,
.nav__links a:focus-visible::before {
  transform: scaleX(1);
}

/* Current page — a persistently-shown underline + the hover colour, so the
   active section reads at a glance. Carried by aria-current="page" on this
   page's own nav link. */
.nav__links a[aria-current="page"] {
  color: var(--color-sage-light);
}

.nav__links a[aria-current="page"]::before {
  transform: scaleX(1);
}

/* Persistent header CTA — client request, 2026-08-29. Glyph only (the
   "Book a Free Consultation" label was dropped 2026-08-29 at the client's
   request). Reuses .btn.btn--primary for colour/hover/focus so it matches
   every other primary CTA; overridden to a 44x44 circular icon button.
   Hidden <=640px, where the nav is a hamburger and the floating
   .whatsapp-fab already carries the same WhatsApp action. */
.nav__cta {
  margin-left: var(--space-sm);
  width: 44px;
  min-width: 44px;
  height: 44px;
  min-height: 44px; /* keep the 44px touch floor */
  padding: 0;
  border-radius: 50%;
  flex-shrink: 0;
  /* Snappier than .btn's 400ms base — nav interactions should feel quick
     (same reasoning as --transition-fast on the mobile menu). Source order
     puts this after .btn--primary:hover, so the lift below wins. */
  transition: transform var(--transition-fast), background var(--transition-fast), box-shadow var(--transition-fast);
}

/* Icon-only, so give it a little more character than the plain .btn lift:
   the button lifts + swells, the glyph tilts. */
.nav__cta:hover,
.nav__cta:focus-visible {
  transform: translateY(-2px) scale(1.06);
}

.nav__cta .btn__icon {
  width: 1.4em;
  height: 1.4em;
  transition: transform var(--transition-fast) ease;
}

.nav__cta:hover .btn__icon,
.nav__cta:focus-visible .btn__icon {
  transform: rotate(-8deg) scale(1.08);
}

@media (max-width: 640px) {
  .nav__cta {
    display: none;
  }
}

/* Services dropdown — the client's own nav spec (15 Aug doc) calls this out
   explicitly as "Services ▾ (dropdown: ...)". Desktop: absolute-positioned
   panel shown on hover/focus-within (keyboard tabbing into any dropdown
   link keeps it open via :focus-within, no JS needed). Mobile: flattened
   into an always-visible indented sub-list instead — hover has no touch
   equivalent, and adding a second tap-to-expand layer inside the hamburger
   menu isn't worth the complexity for one four-item list. */
.nav__item--has-dropdown {
  position: relative;
}

.nav__item--has-dropdown > a::after {
  content: '';
  display: inline-block;
  width: 6px;
  height: 6px;
  margin-left: 6px;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: translateY(-2px) rotate(45deg);
}

.nav__dropdown {
  position: absolute;
  top: 100%;
  left: calc(-1 * var(--space-2xs)); /* align first row's text with the trigger, not its padding box */
  margin-top: 10px; /* detached card, not a flush skirt off the bar */
  min-width: 244px;
  max-width: 300px;
  padding: var(--space-2xs);
  /* Slightly lifted off the bar's navy so it reads as a separate surface,
     plus a real dark shadow — the --shadow-* tokens are navy-tinted for
     light cards and vanish on a dark panel over a light page. */
  background: #1a2c4d;
  border: 1px solid rgba(245, 239, 217, 0.14);
  border-radius: var(--radius-sm);
  box-shadow: 0 18px 44px -12px rgba(0, 0, 0, 0.55), 0 6px 16px rgba(0, 0, 0, 0.28);
  opacity: 0;
  visibility: hidden;
  transform: translateY(-6px) scale(0.97);
  transform-origin: top left;
  transition: opacity var(--transition-fast), transform var(--transition-fast), visibility 0s linear var(--transition-fast);
  z-index: 50;
}

/* Invisible bridge across the 10px gap — keeps :hover / :focus-within alive
   while the pointer travels from the trigger down to the panel. */
.nav__dropdown::before {
  content: '';
  position: absolute;
  top: -12px;
  left: 0;
  right: 0;
  height: 12px;
}

.nav__item--has-dropdown:hover .nav__dropdown,
.nav__item--has-dropdown:focus-within .nav__dropdown {
  opacity: 1;
  visibility: visible;
  transform: translateY(0) scale(1);
  transition-delay: 0s;
}

.nav__dropdown a {
  position: relative;
  display: flex;
  align-items: center;
  width: 100%;
  min-height: 44px; /* touch target — matches the top-level nav links */
  justify-content: flex-start;
  padding-inline: var(--space-sm);
  border-radius: var(--radius-xs);
  font-weight: 400;
  color: rgba(245, 239, 217, 0.82); /* resting rows sit back a touch; hover brings them to full cream */
  white-space: nowrap;
  transition: color var(--transition-fast), background var(--transition-fast), padding-left var(--transition-fast);
}

/* Kill the inherited .nav__links a::before centre-underline inside the
   panel — panel rows use an inset fill + a slide-in chevron instead. */
.nav__dropdown a::before {
  display: none;
}

/* Chevron that eases in from the left on hover/focus — the affordance that
   says "this goes somewhere". */
.nav__dropdown a::after {
  content: '›';
  margin-left: auto;
  padding-left: var(--space-sm);
  font-size: 1.15em;
  line-height: 1;
  color: var(--color-sage-bright);
  opacity: 0;
  transform: translateX(-5px);
  transition: opacity var(--transition-fast), transform var(--transition-fast);
}

.nav__dropdown a:hover,
.nav__dropdown a:focus-visible {
  color: var(--color-cream);
  background: rgba(245, 239, 217, 0.09);
  padding-left: calc(var(--space-sm) + 4px);
}

.nav__dropdown a:hover::after,
.nav__dropdown a:focus-visible::after {
  opacity: 1;
  transform: translateX(0);
}

/* Hamburger toggle — hidden on desktop (inline links are shown instead). */
.nav__toggle {
  display: none;
  width: 44px;
  height: 44px;
  align-items: center;
  justify-content: center;
  gap: 5px;
  flex-direction: column;
  background: none;
  border: none;
  cursor: pointer;
  padding: 0;
  transition: transform var(--transition-fast);
}

/* Focus — swell slightly and warm the bars to sage. Works in both the
   closed and open (X) states since it only touches transform + bar colour,
   not the bars' own morph transforms. The :hover half is gated to real
   pointers: on touch, :hover sticks after the open tap and would leave the
   X glowing sage until the next tap elsewhere. */
.nav__toggle:focus-visible {
  transform: scale(1.08);
}

.nav__toggle:focus-visible .nav__toggle-bar {
  background: var(--color-sage-bright);
}

@media (hover: hover) {
  .nav__toggle:hover {
    transform: scale(1.08);
  }

  .nav__toggle:hover .nav__toggle-bar {
    background: var(--color-sage-bright);
  }
}

.nav__toggle-bar {
  display: block;
  width: 22px;
  height: 2px;
  background: var(--color-cream);
  transition: transform var(--transition-base), opacity var(--transition-base), background var(--transition-fast);
}

/* Open state → morph the three bars into an X. */
.nav__toggle[aria-expanded="true"] .nav__toggle-bar:nth-child(1) {
  transform: translateY(7px) rotate(45deg);
}
.nav__toggle[aria-expanded="true"] .nav__toggle-bar:nth-child(2) {
  opacity: 0;
}
.nav__toggle[aria-expanded="true"] .nav__toggle-bar:nth-child(3) {
  transform: translateY(-7px) rotate(-45deg);
}

/* ==========================================================================
   Mobile nav (<=640px) — collapsing hamburger menu. Replaces the earlier
   "stack + wrap" fallback: with 5 links at 44px touch height, wrapping made
   the nav ~150px tall (ate the mobile viewport, broke anchor scroll-margin).
   The client now prioritises mobile, so a hamburger is the right call — the
   closed bar is a compact ~56px, the open menu is full-width 48px rows.
   ("no hamburger" was decided at 3 links, pre-mobile-priority — see
   CLAUDE.md/PROJECT_PLAN.md decision log.)
   ========================================================================== */
@media (max-width: 640px) {
  /* 3-column grid: a spacer the same width as the toggle on the left, the
     brand centred in the middle, the hamburger on the right — so the brand
     is TRULY centred (the left spacer balances the toggle), and the toggle
     stays pinned to the top row even when the menu drops to row 2. */
  .nav__inner {
    display: grid;
    grid-template-columns: 44px 1fr 44px;
    align-items: center;
    row-gap: 0;
  }

  .nav__brand {
    grid-column: 2;
    justify-self: center;
  }

  .nav__toggle {
    grid-column: 3;
    justify-self: end;
    display: inline-flex;
  }

  .nav__links {
    grid-column: 1 / -1; /* full-width second row */
    /* Reset the desktop `margin-left: auto` — as a grid item it otherwise
       shrink-wraps to the widest label and shoves the whole menu to the
       right edge (the long-standing cause of the indented/clipped mobile
       menu). */
    margin: 0;
    width: 100%;
    flex-direction: column;
    gap: 0;
    /* collapsed by default; initNav toggles .is-open */
    display: none;
    padding: var(--space-2xs) 0 var(--space-lg);
  }

  .nav__links.is-open {
    display: flex;
    /* A full-height navy sheet rather than a flap that stops mid-screen and
       leaves the page showing through below it. dvh so the iOS URL bar
       doesn't leave a cream gap; vh as the fallback. */
    min-height: calc(100vh - 61px);
    min-height: calc(100dvh - 61px);
    animation: nav-menu-in var(--transition-base) ease;
  }

  @keyframes nav-menu-in {
    from { opacity: 0; transform: translateY(-10px); }
  }

  /* Gentle per-row stagger as the sheet opens. */
  .nav__links.is-open > li {
    animation: nav-row-in var(--transition-base) ease both;
  }
  .nav__links.is-open > li:nth-child(1) { animation-delay: 30ms; }
  .nav__links.is-open > li:nth-child(2) { animation-delay: 60ms; }
  .nav__links.is-open > li:nth-child(3) { animation-delay: 90ms; }
  .nav__links.is-open > li:nth-child(4) { animation-delay: 120ms; }
  .nav__links.is-open > li:nth-child(5) { animation-delay: 150ms; }
  .nav__links.is-open > li:nth-child(6) { animation-delay: 180ms; }

  @keyframes nav-row-in {
    from { opacity: 0; transform: translateY(-6px); }
  }

  .nav__links a {
    width: 100%;
    justify-content: flex-start;
    min-height: 52px; /* a little more air than the desktop 44 */
    padding-inline: var(--space-sm);
  }

  /* Dividers only BETWEEN top-level rows, and faint — the old per-row
     border-top (submenu rows included) read as a busy ladder. */
  .nav__links > li + li > a {
    border-top: 1px solid rgba(245, 239, 217, 0.08);
  }

  /* The centre-out underline is a desktop affordance — on stacked full-width
     rows it reads as a stray dash. Swap it for a whole-row tint on
     hover/press instead (works for touch's brief :active flash too). */
  .nav__links a::before {
    display: none;
  }

  .nav__links a:hover,
  .nav__links a:active,
  .nav__dropdown a:hover,
  .nav__dropdown a:active {
    background: rgba(245, 239, 217, 0.08);
  }

  .nav__links a:active {
    box-shadow: inset 3px 0 0 var(--color-sage-bright); /* press feedback */
  }

  /* Current page — carried by aria-current="page" on this page's own nav
     link (see the per-page markup). */
  .nav__links a[aria-current="page"] {
    color: var(--color-sage-light);
    font-weight: 600;
    box-shadow: inset 3px 0 0 var(--color-sage-bright);
  }

  /* No --nav-height override needed: the closed hamburger bar is ~61px, the
     same as the desktop nav, so the base 64px token already clears it. */

  /* Services dropdown, flattened for touch — no hover state to trigger the
     desktop panel, so it's an always-visible sub-list. A sage rail down the
     left marks it as Services' children; no per-row borders, no dark fill. */
  .nav__item--has-dropdown > a::after {
    display: none;
  }

  .nav__dropdown {
    position: static;
    left: auto;
    margin: 2px 0 8px var(--space-sm);
    min-width: 0;
    max-width: none;
    opacity: 1;
    visibility: visible;
    transform: none;
    box-shadow: none;
    border: none;
    border-left: 2px solid rgba(147, 173, 130, 0.45); /* sage-bright, dimmed — the "child of Services" rail */
    border-radius: 0;
    background: none;
    padding: 0;
  }

  .nav__dropdown::before {
    display: none; /* no hover-bridge on the flattened touch list */
  }

  .nav__dropdown a {
    min-height: 46px;
    border: none;
    border-radius: 0;
  }

  /* Children a touch softer than the top-level rows, for hierarchy; no
     chevron or padding-nudge on the flat list. */
  .nav__dropdown a,
  .nav__dropdown a:hover,
  .nav__dropdown a:focus-visible {
    color: rgba(245, 239, 217, 0.82);
    padding-inline: var(--space-md);
    padding-left: var(--space-md);
  }

  .nav__dropdown a::after {
    display: none;
  }
}

/* Wordmark stays visible down to the smallest phones now — the centred brand
   has room for it (was hidden <=480px back when the brand shared a
   space-between row with the links/toggle). */

/* ==========================================================================
   Regulatory credentials — a quiet row of AMFI/SEBI/BASL/NISM badges.
   Originally a standalone strip between the nav and the hero (light bg);
   moved into the footer 2026-07-27 to sit with the rest of the compliance
   block instead of the top of the page. Colors below are the dark-card
   (footer) treatment — this component has no light-background use left,
   so the base rule targets the footer directly rather than carrying an
   unused light variant. .footer__credentials only adds the footer's own
   top margin; layout/colors live here.
   ========================================================================== */
.trust-bar__list {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: var(--space-sm) var(--space-lg);
}

.footer__credentials {
  margin-top: var(--space-md);
  padding-top: var(--space-md);
  border-top: 1px solid rgba(245, 239, 217, 0.15);
}

.trust-bar__item {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2xs);
  font-size: var(--fs-small);
  font-weight: 500;
  color: rgba(245, 239, 217, 0.75);
}

.trust-bar__icon {
  width: 17px;
  height: 17px;
  flex-shrink: 0;
  color: var(--color-sage-light);
}

/* ==========================================================================
   Card system — every section below the nav is a contained card so the
   page's neutral --color-bg shows through between them. .card carries the
   shared shape (size/margin/radius/clipping); .card--dark / .card--light
   carry the two surface treatments ("authority bookend" vs. everyday
   content). Combine with a component class (.hero, .services, etc.) for
   anything section-specific.
   ========================================================================== */
.card {
  position: relative;
  width: calc(100% - 2 * var(--space-md));
  max-width: 1320px;
  margin: var(--card-gap) auto;
  border-radius: var(--card-radius);
  overflow: hidden;
  /* Nav is position:sticky at the top — without this, any anchor jump
     (nav click, or another page's index.html#id link) lands a section
     flush under the nav, obscuring its heading. Applies to every card
     since every anchor target (#hero, #why-ethical, #services, #faq,
     #contact) is one. */
  scroll-margin-top: var(--nav-height);
}

.card--dark {
  background: var(--color-ink);
  color: var(--color-text-inverse);
}

/* Light cards need their own shadow to read as a distinct shape —
   --color-surface (cream) is close enough to --color-bg (off-white) that
   a boundary alone wouldn't otherwise be obvious. Shadow-only, no border —
   border+shadow together read as slightly busy/dated; shadow alone is the
   more contemporary, minimal way to separate a surface from its background. */
.card--light {
  background: var(--color-surface);
  box-shadow: var(--shadow-sm);
}

/* Subtle tone alternation for visual sequencing — applied to every other
   light section so the run of content cards between the dark hero and dark
   footer doesn't read as one flat cream block. Uses the warm-white page
   tone (--color-bg) against the cream (--color-surface) of the default
   light card — the two warm neutrals differ by only a few points, so it's
   a gentle rhythm, not a stripe. The shadow still defines the card even
   though its fill matches the page background. */
.card--light.card--alt {
  background: var(--color-bg);
}

@media (max-width: 767px) {
  .card {
    margin: var(--space-md) auto;
    border-radius: var(--radius-sm);
  }
}

/* ==========================================================================
   Hero card — the dark "authority bookend" card. A normal static card in
   document flow (no scroll-pin/scroll-jack — that machinery is gone along
   with the fragility it brought). Two real vertical zones stacked in flex
   flow keep text and tree from ever occupying the same space: content zone
   on top with its own height, tree zone taking the remaining space below
   and bottom-anchoring the tree with explicit breathing room (--space-lg)
   before the card's own bottom edge — the root fix for tree clipping.
   ========================================================================== */
.hero {
  display: flex;
  flex-direction: column;
  align-items: center;
  min-height: 480px; /* floor only, so a short card never looks cramped — the
                        tree's own intrinsic height is what actually sizes
                        the card now, not a fight over leftover flex space */
}

.hero__bg {
  position: absolute;
  inset: 0;
  z-index: 0;
}

/* Stars — real brand asset (assets/img/star.png), scattered as independent
   instances across the full hero background, independent of the tree's
   position. Gentle ambient opacity "twinkle": each star fades between its
   own base opacity (set per-star via the inline --star-opacity custom
   property, which preserves the depth those varied values give) and ~70% of
   it, like real starlight. Ordinary CSS loop, not scroll-tied. Organic /
   non-synced via per-star inline animation-delay (phase) + varied durations
   below (period) — so they never pulse in lockstep. */
.hero__star {
  position: absolute;
  height: auto;
  pointer-events: none;
  opacity: var(--star-opacity, 0.5);
  animation: star-twinkle 3.6s ease-in-out infinite;
}

/* Mobile-only extras — the desktop hero already has its full 10-star field and
   doesn't want these on top of it. Must stay ABOVE the max-width:767px block
   that flips this to `display:block` (equal specificity → last one wins). */
.hero__star--mobile-only {
  display: none;
}

/* Vary the period per star so phase + period both differ — no two stars
   share a cycle, so the field never visibly re-syncs. */
.hero__star:nth-child(3n)   { animation-duration: 3s; }
.hero__star:nth-child(3n+1) { animation-duration: 4.2s; }
.hero__star:nth-child(3n+2) { animation-duration: 5.1s; }

/* Pulses opacity between the star's base value (100%) and ~20% of it — the
   swing has been widened twice: a 70% floor was imperceptible, 40% still read
   as too subtle on a phone, so it now nearly fades out at the trough for a
   twinkle that actually registers. Uses the per-star --star-opacity so
   brighter/dimmer stars keep their relative depth. */
@keyframes star-twinkle {
  0%, 100% { opacity: var(--star-opacity, 0.5); }
  50%      { opacity: calc(var(--star-opacity, 0.5) * 0.2); }
}

.hero__content {
  position: relative;
  z-index: 1;
  flex: 0 0 auto;
  text-align: center;
  color: var(--color-text-inverse);
  padding-inline: var(--space-md);
  padding-top: var(--space-xl);
  max-width: 820px; /* widened from 720 so the longer headline wraps to fewer lines on desktop */
}

/* font-family/weight/style come from the global h1 rule — Fraunces,
   upright, weight 500, same treatment as .why-ethical__headline. Client
   preference, after also trying: italic+700, and Inter (no serif) here.
   Only hero-specific size/spacing need overriding below. */
.hero__title {
  font-size: var(--fs-h1);
  margin-bottom: var(--space-md);
}

.hero__subtitle {
  font-size: var(--fs-body-lg);
  color: rgba(245, 239, 217, 0.8);
  margin-bottom: var(--space-lg);
  max-width: 560px;
  margin-inline: auto;
}

.hero__ctas {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: var(--space-md);
}

/* Tree zone — normal flow, not a fixed-height box the tree has to compete
   for space in. Height is intrinsic: the tree's own rendered height plus
   explicit top/bottom padding, so the card grows to fit it instead of
   clipping it. This is the root fix for the clipping bug — the old
   flex:1-fills-leftover-space approach could size this zone shorter than
   the tree actually needed, and overflow:hidden silently ate the canopy. */
.hero__tree-zone {
  position: relative;
  width: 100%;
  display: flex;
  justify-content: center;
  padding-block: var(--space-lg);
}

/* Tree — real brand asset (assets/img/tree.png), the hero's large centered
   anchor (same compositional role as a hero photo subject). Normal flow +
   flex-centered (no absolute positioning/translate hack needed). Scroll
   parallax is applied via JS (assets/js/main.js, initHeroParallax) — see
   there for why the old ambient CSS float was dropped (both would have
   fought over the transform property). */
.hero__tree {
  /* Slightly smaller than before (max 380px -> 340px) — client feedback
     that it felt a bit tight/cramped against the curtain-occlusion card
     rising over it; a bit more breathing room around the branches. */
  width: clamp(200px, 28vw, 340px);
  height: auto;
}

@media (max-width: 767px) {
  .hero {
    min-height: 400px;
  }

  .hero__content {
    padding-top: var(--space-lg);
  }

  .hero__tree-zone {
    padding-block: var(--space-md);
  }

  .hero__tree {
    width: clamp(160px, 44vw, 220px);
  }

  /* Hide the stars that sit in the central title/subtitle column on the
     narrow mobile hero — they crowded the centred headline. The edge stars
     (corners) stay for atmosphere. */
  .hero__star--hide-mobile {
    display: none;
  }

  /* ...and add extras back in the lower side margins, so mobile isn't left with
     a sparse 4-star field. See the markup for how these positions were picked.
     The base `display:none` for this class is declared ABOVE (with .hero__star),
     deliberately — same specificity, so whichever comes last in source order
     wins, and putting it after this block would hide these on mobile too. */
  .hero__star--mobile-only {
    display: block;
  }
}

/* ==========================================================================
   Feature row — icon + label band, now a light card like everything else
   ========================================================================== */
.feature-row {
  padding-block: var(--space-lg);
}

/* DriveEazy-style row: each item is an icon badge (left) + a two-line label
   (bold title over a muted sub) on the right, with thin dividers between
   items. gap:0 so the dividers (border-right) sit evenly, not floating in a
   flex gap. */
.feature-row__list {
  display: grid;
  /* minmax(0, 1fr), NOT 1fr: a bare `1fr` is minmax(auto, 1fr), and that `auto`
     floor is min-content — so once the container gets tight the longer labels
     refuse to shrink and the four cells stop being equal. Measured at 768px
     they came out 206.8 / 202.9 / 157.6 / 174.9px, which reads as sloppy
     rather than as a grid. minmax(0, …) removes the floor and they stay equal. */
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 0;
}

.feature-row__item {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: var(--space-sm);
  padding-inline: var(--space-md);
  text-align: left;
}

.feature-row__item:not(:last-child) {
  border-right: 1px solid var(--color-border);
}

.feature-row__text {
  display: flex;
  flex-direction: column;
  line-height: 1.2;
}

.feature-row__title {
  font-weight: 600;
  font-size: var(--fs-body);
  color: var(--color-navy);
}

.feature-row__sub {
  font-size: var(--fs-small);
  color: var(--color-text-muted);
}

/* Rounded-SQUARE badge (was a circle) to match the DriveEazy reference —
   sage-light fill keeps it in the site's icon system. */
.feature-row__icon-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 44px;
  height: 44px;
  border-radius: var(--radius-sm);
  background: var(--color-sage-light);
}

.feature-row__icon {
  width: 22px;
  height: 22px;
  color: var(--color-sage-deep);
}

@media (max-width: 767px) {
  /* The 48px (--space-lg) block padding left the card looking half-empty on a
     phone — the divided cells are short. Tighten it so the card wraps the row. */
  .feature-row {
    padding-block: var(--space-md);
  }

  /* 2x2 grid on mobile — this WAS a swipeable DriveEazy-style row, changed after
     a UX review: only ~1.6 of the 4 cells fit on a phone, so half the content sat
     behind a gesture users may never try, and the peeking cell was cut mid-word
     ("Tran"), reading as broken text rather than "there's more to see". A
     horizontal scroll earns its keep with many items; with four short ones,
     showing all four at once is simply better. The cell styling (badge +
     two-line label) is unchanged — only the container changes. */
  .feature-row__list {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 0; /* dividers separate the cells, not a gap */
  }

  /* Icon stacked ABOVE the label here, rather than the desktop row's badge-left.
     In a half-width grid cell the horizontal arrangement leaves the text only
     ~75px, which isn't enough for a long single word — "Independent" can't wrap,
     so it either overflowed the card or (with overflow-wrap) broke mid-word into
     "Independen / t". Stacking gives the label the cell's full width, which fits
     every label cleanly down to 320px, and centred cells scan better in a grid. */
  .feature-row__item {
    min-width: 0; /* grid items floor at min-content — let cells shrink */
    flex-direction: column;
    align-items: center;
    text-align: center;
    padding: var(--space-md) var(--space-2xs);
    gap: var(--space-2xs);
  }

  .feature-row__text {
    min-width: 0;
    align-items: center;
  }

  /* Dividers re-mapped for a grid. The base `:not(:last-child)` rule borders
     items 1–3, which in a 2x2 draws a stray rule down the card's RIGHT edge
     (cell 2) and nothing under the top row. Instead: vertical rule on the left
     column only, horizontal rule under the top row only. */
  .feature-row__item:nth-child(even) {
    border-right: none;
  }

  .feature-row__item:nth-child(-n + 2) {
    border-bottom: 1px solid var(--color-border);
  }

  /* Deliberately NO nowrap here (the old scroll row had it): grid cells are only
     ~135px wide at 320px and "Direct WhatsApp" cannot fit on one line — nowrap
     would push it out of the card. Wrapping keeps it contained, and the grid
     equalises the heights of both cells in a row anyway. */
  .feature-row__title {
    font-size: var(--fs-small);
  }

  .feature-row__icon-badge {
    width: 36px;
    height: 36px;
    border-radius: var(--radius-xs);
  }

  .feature-row__icon {
    width: 18px;
    height: 18px;
  }
}

/* ==========================================================================
   Services teaser (homepage, #services-teaser)
   Was an Ethical Investing teaser (2026-07-16 -> 2026-08-16, see git history)
   — content swapped to Services per client request that the homepage's
   second card lead with Services, not Ethical Investing. Markup/CSS
   unchanged: still a condensed hook + CTA link out to a full page
   (services.html now, was ethical-investing.html), same pattern as the
   homepage About teaser just below it — reuses .about__copy/.about__cta
   rather than declaring new teaser CSS.
   ========================================================================== */

/* ==========================================================================
   Ethical Investing page (ethical-investing.html)
   Hero reuses .about-intro* (about.html's dark intro band) — no new CSS
   needed there. This block covers what's unique to this page: the four
   approaches as full-width stacked sections (not a pinned/scrolling list —
   this page has room to let each one breathe) and the India/International
   regulatory note (adapted from the old .why-ethical__context aside, renamed
   since it's no longer scoped under Why Ethical).
   ========================================================================== */
/* Hero ornaments (added in the UI pass, 2026-07-26) — a small flanking-line
   + sparkle motif, used three times in the hero: bracketing the eyebrow
   label, and as standalone dividers between headline/lead and lead/pills.
   Sage, decorative, aria-hidden — the accent color's job here, not a new
   component with its own meaning. */
.hero-ornament {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-sm);
  margin: var(--space-md) auto;
  max-width: 260px;
}

.hero-ornament::before,
.hero-ornament::after {
  content: '';
  flex: 1;
  height: 1px;
  background: linear-gradient(90deg, transparent, rgba(107, 127, 94, 0.7), transparent);
}

.hero-ornament__spark {
  flex-shrink: 0;
  width: 10px;
  height: 10px;
  color: var(--color-sage);
}

/* Eyebrow flanked by the same line motif, tight around the text rather
   than spanning a whole row — a variant of .hero-ornament, not a second
   component. Scoped to this hero only (.section__eyebrow itself, used on
   every other page, is untouched). */
.hero-eyebrow-row {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-sm);
  margin-bottom: var(--space-sm);
}

.hero-eyebrow-row::before,
.hero-eyebrow-row::after {
  content: '';
  width: 40px;
  height: 1px;
  background: rgba(107, 127, 94, 0.7);
}

.hero-eyebrow-row .section__eyebrow {
  margin-bottom: 0;
}

@media (max-width: 480px) {
  /* At 40px a side, the flanking lines + gap left too little room for
     "ETHICAL INVESTING" to fit on one line at a phone's hero width — it
     broke as "ETHICAL" / "INVESTING", off-center under its own dividers.
     Shorter lines + tighter gap free up enough width to keep it on one
     line down to a 320px viewport. */
  .hero-eyebrow-row {
    gap: var(--space-2xs);
  }

  .hero-eyebrow-row::before,
  .hero-eyebrow-row::after {
    width: 16px;
  }
}

/* Short-viewport tuning — independent of the width-based mobile block near
   .hero__tree. A windowed desktop browser (short but wide) or a phone/tablet
   in landscape can be shorter than the hero's natural content height,
   clipping the tree's base below the fold. Keyed on max-height, not
   max-width, since the failure mode is viewport height, not narrowness — a
   1440x700 window hits this, a 767px-wide-but-tall phone doesn't.
   Placed here (after the base .hero-eyebrow-row/.hero__subtitle rules)
   deliberately — same-specificity selectors resolve by source order, so a
   max-height override declared earlier in the file gets silently beaten by
   a later non-media rule. */
@media (max-height: 820px) {
  .hero__content {
    padding-top: var(--space-lg);
  }

  .hero-eyebrow-row {
    margin-bottom: var(--space-sm);
  }

  .hero__title {
    margin-bottom: var(--space-md);
  }

  .hero__subtitle {
    margin-bottom: var(--space-md);
  }

  .hero__tree-zone {
    padding-block: var(--space-md);
  }

  .hero__tree {
    width: clamp(180px, 24vw, 300px);
  }
}

@media (max-height: 520px) {
  /* Landscape phones/tablets: even the tightened spacing above can't fit
     the full stack. Drop the subtitle/eyebrow and shrink the title's own
     type size (never the tree) rather than let the tree clip — the
     headline + CTAs + full-size tree stay, the supporting text doesn't. */
  .hero__content {
    padding-top: var(--space-sm);
  }

  .hero-eyebrow-row {
    display: none;
  }

  .hero__title {
    font-size: clamp(1.5rem, 4vw, 2.25rem);
    margin-bottom: var(--space-2xs);
  }

  .hero__subtitle {
    display: none;
  }

  .hero__tree-zone {
    padding-block: var(--space-2xs);
  }
}

/* Sage italic emphasis for a word or two within the hero headline — the
   upright cream default carries the rest of the sentence, this is just
   the accent color's turn to appear in text rather than only icons/borders.
   Uses --color-sage-bright (not --color-sage): this only ever sits on the
   dark navy hero card, where plain --color-sage fails WCAG AA (~3.9:1). */
.hero-highlight {
  color: var(--color-sage-bright);
  font-style: italic;
}

/* Hero quick-jump strip — a row of pill links to each approach's anchor,
   echoing the homepage feature-row's icon+label idiom but on the dark hero
   card. Gives the page an "at a glance" moment before the full list, and a
   way back up top after reading any one approach (each .approach is
   `id`-anchored). Sage border/icon, cream label text — the sage pairs with
   the ornament dividers above; cream text keeps the label itself readable
   at this size (sage-on-navy body text is close to, not comfortably past,
   the 4.5:1 small-text threshold). */
.hero-jump {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--space-sm);
  margin-top: var(--space-lg);
}

.hero-jump__link {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2xs);
  padding: 0.5rem 1rem;
  border: 1px solid rgba(107, 127, 94, 0.55);
  border-radius: 999px;
  font-size: var(--fs-small);
  font-weight: 500;
  color: var(--color-text-inverse);
  transition: background var(--transition-fast), border-color var(--transition-fast);
}

.hero-jump__link:hover,
.hero-jump__link:focus-visible {
  background: rgba(107, 127, 94, 0.15);
  border-color: var(--color-sage);
}

.hero-jump__link svg {
  width: 16px;
  height: 16px;
  color: var(--color-sage);
}

/* ==========================================================================
   Teaser-card decoration — shared by the homepage's Services teaser
   (#services-teaser, was an Ethical Investing teaser until 2026-08-16) and
   About teaser (#about), both redesigned
   2026-07-26/27 to match reference lockups the client shared: flanking
   sparkle/line ornaments around the eyebrow and headline (reuses
   .hero-ornament/.hero-highlight from the ethical-investing.html hero —
   both are colour-agnostic, so they drop onto any LIGHT card unchanged),
   decorative corner branches, and scattered sparkles. Genericized under
   .teaser-* / .decor-branch rather than named per-section, since it's now
   used in two places with a third not implausible. The references used a
   gold accent for the ornamental bits; this uses sage instead, since gold
   was deliberately removed site-wide the same day — ask if an actual gold
   touch is wanted here specifically.
   ========================================================================== */
.teaser-content {
  position: relative;
  z-index: 1;
}

.decor-branch {
  position: absolute;
  bottom: -8px;
  width: 150px;
  height: auto;
  color: var(--color-sage);
  opacity: 0.16;
  pointer-events: none;
  z-index: 0;
}

.decor-branch--left {
  left: -12px;
}

.decor-branch--right {
  right: -12px;
  transform: scaleX(-1);
}

.teaser-spark {
  position: absolute;
  color: var(--color-sage);
  opacity: 0.55;
  z-index: 0;
  animation: star-twinkle 3.6s ease-in-out infinite;
}

.teaser-badge {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 96px;
  height: 96px;
  margin: 0 auto var(--space-md);
  border-radius: 50%;
  border: 1px solid rgba(107, 127, 94, 0.35);
  background: var(--color-bg);
}

.teaser-badge svg {
  width: 40px;
  height: 40px;
  color: var(--color-sage-deep);
}

.teaser-title {
  margin-bottom: 0;
}

.teaser-cta {
  gap: 0.6em;
}

/* Leaf icon reads sage even where the button text is navy (the About
   teaser's outline .btn--secondary on a light card) — matches the
   reference's two-tone icon/label treatment. Scoped to --secondary only:
   a blanket ".teaser-cta .btn__icon" rule was also catching the
   .btn--primary teaser-cta buttons (Services/Ethical Investing teasers),
   forcing their icon to sage-on-sage-deep — nearly invisible against the
   button's own solid sage-deep fill. Primary buttons keep the icon on
   inherited cream (matching the button text) instead. */
.btn--secondary.teaser-cta .btn__icon {
  color: var(--color-sage);
}

@media (max-width: 600px) {
  .decor-branch {
    width: 90px;
    opacity: 0.12;
  }
}

/* About teaser (index.html, #about) specifics — the mini single-sparkle
   divider under the headline (no flanking lines, unlike .hero-ornament)
   and the credentials row (icon + label, bullet-separated). */
.teaser-mini-spark {
  display: flex;
  justify-content: center;
  margin: var(--space-sm) 0;
  color: var(--color-sage);
}

.teaser-mini-spark svg {
  width: 12px;
  height: 12px;
}

.credentials-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: var(--space-sm) var(--space-md);
  margin-bottom: var(--space-lg);
  color: var(--color-text);
  font-size: var(--fs-small);
  font-weight: 500;
}

@media (max-width: 640px) {
  /* Flex-wrap centres each wrapped LINE independently, which stranded a
     lone "•" at the end of line 1 and another at the start of line 3 —
     orphaned separators, not a clean wrap. Stack instead and hide the
     separators; each credential reads as its own line, which is what the
     3 wrapped lines amounted to visually anyway. */
  .credentials-row {
    flex-direction: column;
    gap: var(--space-sm);
  }

  .credentials-row__sep {
    display: none;
  }
}

.credentials-row__item {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2xs);
}

.credentials-row__item svg {
  width: 18px;
  height: 18px;
  color: var(--color-sage-deep);
  flex-shrink: 0;
}

.credentials-row__sep {
  color: var(--color-sage);
}

.approach-list {
  max-width: 820px;
  margin-top: var(--space-xl);
  margin-inline: auto;
  display: flex;
  flex-direction: column;
  gap: var(--space-lg);
}

/* Each approach is now its own card — the same "card floating on a card"
   recipe .service-accordion__item already uses (var(--color-bg) against
   this section's cream .card--light), plus a sage left-accent to tie it
   to the regulatory note's visual language below. Replaces the earlier
   plain divided-list treatment: this page has the room, and a run of four
   bordered cards reads as more considered than a bare list. */
.approach {
  padding: var(--space-lg);
  background: var(--color-bg);
  border-left: 4px solid var(--color-sage);
  border-radius: 0 var(--radius) var(--radius) 0;
  box-shadow: var(--shadow-sm);
  scroll-margin-top: var(--nav-height);
}

.approach__head {
  display: flex;
  align-items: center;
  gap: var(--space-md);
  margin-bottom: var(--space-md);
}

/* Reuses about.html's .about-principle__icon circle (sage-light fill,
   sage-deep glyph) — no new icon treatment needed, just the same
   component in a new context. */
.approach__head .about-principle__icon {
  flex-shrink: 0;
  margin-bottom: 0;
}

.approach__eyebrow {
  display: block;
  font-size: var(--fs-small);
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--color-sage-deep);
  /* Guard against inherited body{text-align:justify} — a short, letter-
     spaced uppercase label reads badly justified if it ever wraps. */
  text-align: left;
}

.approach__title {
  font-size: var(--fs-h3);
  margin-top: 0.15em;
  /* Same justify-on-wrap guard as .about-principle__title. */
  text-align: left;
}

.approach__body {
  color: var(--color-text-muted);
  max-width: 68ch;
}

.approach__body > * + * {
  margin-top: var(--space-sm);
}

@media (max-width: 767px) {
  /* --space-lg (48px) padding on both sides ate over 90px of a ~320-375px
     phone's already-narrow content column — measured: it left the ESG
     card's text column at ~64px wide, just enough for "APPROACH 01" to
     break mid-phrase ("APPROACH" / "01") instead of wrapping at a normal
     word boundary. Halving the padding here (not touching desktop) fixes
     the eyebrow break. (.reg-note gets the same treatment further down,
     in the media block right after its own base rule — same-specificity
     rules resolve by source order regardless of @media nesting, so an
     override has to come after the rule it's overriding, not just be
     inside a narrower query.) */
  .approach {
    padding: var(--space-md);
  }
}

@media (max-width: 480px) {
  /* Icon + eyebrow/title crowd a narrow phone width — drop to a tighter
     gap rather than wrapping the head onto three lines. */
  .approach__head {
    gap: var(--space-sm);
  }
}

/* India/International regulatory note — the client's closing paragraph,
   split at its own sentence boundary into two columns (formatting only,
   both sentences verbatim). Same sage-accent aside treatment the homepage
   used to carry as .why-ethical__context. */
.reg-note {
  max-width: 800px;
  margin-inline: auto;
  padding: var(--space-lg);
  border-left: 3px solid var(--color-sage);
  border-radius: 0 var(--radius) var(--radius) 0;
  background: var(--color-sage-light);
  color: var(--color-text-muted);
  font-size: var(--fs-small);
}

.reg-note__label {
  display: block;
  margin-bottom: var(--space-sm);
  font-size: var(--fs-small);
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  /* Not --color-sage-deep — that's tuned for the cream page background and
     only reaches 4.42:1 on this aside's sage-light fill (marginal WCAG AA
     fail at this size). This darker green measures 5.03:1 on sage-light. */
  color: #556648;
  /* Guard against inherited body{text-align:justify} — short uppercase
     label, reads badly justified if it ever wraps. */
  text-align: left;
}

.reg-note__cols {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-md) var(--space-xl);
}

.reg-note__cols p {
  max-width: 52ch;
}

@media (max-width: 767px) {
  /* Same --space-lg -> --space-md padding fix as .approach above, applied
     here (after .reg-note's own base rule) so it actually wins the
     cascade — see the comment on .approach's mobile override for why
     source order matters here. Without it, this aside's body copy read as
     a single narrow ladder of 3-4-word lines on a phone. */
  .reg-note {
    padding: var(--space-md);
  }

  .reg-note__cols {
    grid-template-columns: 1fr;
  }
}

/* ==========================================================================
   Services — two deep-dive accordion cards (Retirement Planning, Wealth
   Management). Native <details>/<summary>, same no-JS/accessible pattern as
   the FAQ, but styled as full cards (the FAQ is a flat divided list) since
   each holds a lot of structured content. The +/- icon reuses the FAQ
   icon's technique.

   Note: an earlier 4-card grid (.services__grid + .service-card*) and the
   removed Testimonials section (.testimonials__grid + .testimonial-card)
   both lived here — that CSS was deleted 2026-07-14 when the grid was
   collapsed into these accordions and confirmed dead (no live markup used
   it). Recover from git history if either is ever wanted back.
   ========================================================================== */
.service-accordion {
  max-width: 820px;
  margin-inline: auto;
  display: flex;
  flex-direction: column;
  gap: var(--space-md);
}

.service-accordion__item {
  background: var(--color-bg);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
  transition: box-shadow var(--transition-base), transform var(--transition-fast);
  /* These are now real anchor targets (services.html's #plan-your-future
     etc., linked from the nav dropdown) — same nav-clearance rule .card
     uses elsewhere, needed here separately since a .service-accordion__item
     is a <details>, not a .card. */
  scroll-margin-top: var(--nav-height);
}

.service-accordion__item[open] {
  box-shadow: var(--shadow-md);
}

/* Subtle hover lift on collapsed cards only — signals interactivity without
   spectacle. An open card doesn't lift (it's already the focus). */
.service-accordion__item:not([open]):hover {
  transform: translateY(-2px);
  box-shadow: var(--shadow-md);
}

.service-accordion__head {
  display: flex;
  align-items: center;
  gap: var(--space-lg);
  padding: var(--space-lg) var(--space-md);
  cursor: pointer;
  list-style: none;
}

.service-accordion__head::-webkit-details-marker {
  display: none;
}

/* Icon badge — a dashed "halo" ring around a filled sage-light circle,
   matching the reference lockup the client shared. Two separate elements
   (not one circle with a dashed border) so the ring can sit a few px
   outside the fill, reading as a deliberate double-ring rather than one
   badge with an odd stroke style. */
.service-badge {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100px;
  height: 100px;
  flex-shrink: 0;
}

.service-badge__ring {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  border: 1px dashed rgba(107, 127, 94, 0.35);
}

.service-badge__icon {
  width: 76px;
  height: 76px;
  border-radius: 50%;
  background: var(--color-sage-light);
  display: flex;
  align-items: center;
  justify-content: center;
}

.service-badge__icon svg {
  width: 32px;
  height: 32px;
  color: var(--color-sage-deep);
}

/* ==========================================================================
   Process timeline (how-we-work.html "The 4-Step Process") — v2, rebuilt
   2026-08-16 against feedback that v1 read as 4 disconnected columns plus
   a busy, continuously leaf-covered vine. Concept now: "four steps
   connected by one quietly growing branch."

   .process-timeline__vine is ONE thin path, positioned behind the row of
   .process-marker circles (z-index 0 vs. 1) — its stroke visually
   disappears into each marker's opaque fill rather than looping around
   it, which is what reads as "the branch passes through/behind each
   step" instead of 4 separate icons near a squiggle.

   Each marker carries one small sage leaf sprig (.process-marker__sprout,
   inline SVG in the HTML — same sprig on all 4 steps, was a 1->4 growing
   count in an earlier pass, simplified per feedback), not scattered along
   the vine.

   .process-marker is new and deliberately does NOT reuse .service-badge —
   that component's dashed halo ring is exactly the "excessive decorative
   ring" flagged in feedback. .service-badge is untouched and still used
   as-is elsewhere (index.html#services, About's "Our Approach").
   ========================================================================== */
.process-timeline__intro {
  max-width: 46ch;
  margin: 0 auto var(--space-lg);
  text-align: center;
  color: var(--color-text-muted);
}

.process-timeline {
  --marker-size: 84px;
  position: relative;
}

.process-timeline__vine {
  display: block;
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: var(--marker-size);
  color: var(--color-sage);
  opacity: 0.55;
  pointer-events: none;
  z-index: 0;
}

.process-timeline__vine-path {
  /* Scroll-in "growing" draw, see .reveal.is-visible below; static (no
     dasharray) until JS marks the section visible or motion is reduced. */
}

.process-timeline__steps {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--space-lg);
}

.process-timeline__step {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
}

/* Opaque fill (a faint sage tint mixed into the card's own cream, not a
   flat color) so the vine behind reads as passing INTO the marker rather
   than being visible through it — thin single border, no halo ring, no
   shadow. */
.process-marker {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: var(--marker-size);
  height: var(--marker-size);
  border-radius: 50%;
  background: color-mix(in srgb, var(--color-surface) 88%, var(--color-sage-light) 12%);
  border: 1px solid rgba(107, 127, 94, 0.35);
  margin-bottom: var(--space-sm);
  flex-shrink: 0;
}

.process-marker__icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  color: var(--color-sage-deep);
}

.process-marker__icon svg {
  width: 100%;
  height: 100%;
}

/* One small sage leaf per marker (same sprig on all four steps — not a
   growing count) — sage rather than gold so it reads as part of the
   site's normal accent language instead of the one-off gold exception
   used for .process-timeline__number below. */
.process-marker__sprout {
  position: absolute;
  top: -6px;
  right: -10px;
  width: 34px;
  height: 26px;
  color: var(--color-sage);
  opacity: 0.85;
  pointer-events: none;
}

.process-timeline__number {
  display: inline-block;
  font-family: var(--font-heading);
  font-size: var(--fs-body-lg);
  font-weight: 500;
  padding-bottom: var(--space-2xs);
  margin-bottom: var(--space-sm);
  border-bottom: 2px solid #b89355;
}

.process-timeline__title {
  font-size: var(--fs-h3);
  margin-bottom: var(--space-2xs);
}

.process-timeline__spark {
  display: inline-flex;
  margin-bottom: var(--space-sm);
  color: #b89355;
}

.process-timeline__spark svg {
  width: 14px;
  height: 14px;
}

.process-timeline__desc {
  color: var(--color-text-muted);
}

/* Subtle scroll-in growth: the vine draws itself and each step fades up
   in sequence. Gated entirely behind .reveal.is-visible (JS-toggled, see
   assets/js/main.js) and skipped under reduced motion below — this is
   additive polish on top of the existing reveal utility, not a new
   mechanism. */
.process-timeline__vine-path {
  stroke-dasharray: 1400;
  stroke-dashoffset: 1400;
  transition: stroke-dashoffset 1.1s ease-out;
}

.reveal.is-visible .process-timeline__vine-path {
  stroke-dashoffset: 0;
}

.process-timeline__step {
  opacity: 0;
  transform: translateY(10px);
  transition: opacity 0.5s ease-out, transform 0.5s ease-out;
}

.reveal.is-visible .process-timeline__step {
  opacity: 1;
  transform: translateY(0);
}

.process-timeline__steps .process-timeline__step:nth-child(1) { transition-delay: 0.15s; }
.process-timeline__steps .process-timeline__step:nth-child(2) { transition-delay: 0.35s; }
.process-timeline__steps .process-timeline__step:nth-child(3) { transition-delay: 0.55s; }
.process-timeline__steps .process-timeline__step:nth-child(4) { transition-delay: 0.75s; }

.process-timeline__banner {
  display: flex;
  align-items: center;
  gap: var(--space-md);
  margin-top: var(--space-xl);
  padding: var(--space-md) var(--space-lg);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  background: var(--color-surface);
}

.process-timeline__banner-icon {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 56px;
  height: 56px;
  border-radius: 50%;
  background: var(--color-sage-light);
  color: var(--color-sage-deep);
}

.process-timeline__banner-icon svg {
  width: 24px;
  height: 24px;
}

.process-timeline__banner-text {
  flex: 1;
  min-width: 0;
}

.process-timeline__banner-title {
  font-family: var(--font-heading);
  font-style: italic;
  font-size: var(--fs-body-lg);
  color: var(--color-sage-deep);
  margin-bottom: var(--space-2xs);
}

.process-timeline__banner-sub {
  color: var(--color-text-muted);
  font-size: var(--fs-small);
}

.process-timeline__banner .btn {
  flex-shrink: 0;
}

/* Tablet: keep the connected horizontal journey — shrink the marker/type
   scale before touching layout, per design direction ("reduce typography
   and spacing before changing the layout"). Still 4-across, still one
   branch. */
@media (max-width: 900px) {
  .process-timeline {
    --marker-size: 68px;
  }

  .process-timeline__steps {
    gap: var(--space-md);
  }

  .process-marker__icon {
    width: 24px;
    height: 24px;
  }

  .process-marker__sprout {
    width: 26px;
    height: 20px;
    top: -4px;
    right: -6px;
  }

  .process-timeline__title {
    font-size: 1.05rem;
  }
}

/* Mobile: the branch turns vertical and runs down the left side instead
   of disappearing — .process-timeline__steps::before is the stem, each
   .process-marker sits on it, .process-timeline__step-body grows to its
   right. Not a fallback grid; the "growing branch" idea carries through. */
@media (max-width: 720px) {
  .process-timeline {
    --marker-size: 64px;
  }

  .process-timeline__vine {
    display: none;
  }

  .process-timeline__steps {
    display: flex;
    flex-direction: column;
    gap: var(--space-xl);
  }

  .process-timeline__steps::before {
    content: "";
    position: absolute;
    left: calc(var(--marker-size) / 2 - 1px);
    top: calc(var(--marker-size) / 2);
    bottom: calc(var(--marker-size) / 2);
    width: 2px;
    background: linear-gradient(
      to bottom,
      transparent,
      rgba(107, 127, 94, 0.45) 10%,
      rgba(107, 127, 94, 0.45) 90%,
      transparent
    );
  }

  .process-timeline__step {
    flex-direction: row;
    align-items: flex-start;
    text-align: left;
    gap: var(--space-md);
  }

  .process-marker {
    margin-bottom: 0;
  }

  .process-marker__sprout {
    top: -4px;
    right: -8px;
  }

  .process-timeline__step-body {
    padding-top: var(--space-2xs);
  }

  .process-timeline__spark {
    margin-left: 0;
  }
}

@media (max-width: 640px) {
  .process-timeline__banner {
    flex-direction: column;
    text-align: center;
  }
}

.service-accordion__head-text {
  display: flex;
  align-items: stretch;
  gap: var(--space-md);
  flex: 1;
  min-width: 0;
}

/* Thin vertical rule between the badge and the text block — the same
   left-accent vocabulary as .approach/.reg-note elsewhere on the site,
   just a hairline instead of a solid 3-4px bar since here it's a
   secondary divider, not the card's primary accent. */
.service-accordion__accent {
  align-self: stretch;
  width: 1px;
  background: rgba(107, 127, 94, 0.4);
  flex-shrink: 0;
}

.service-accordion__text {
  display: flex;
  flex-direction: column;
  gap: var(--space-2xs);
  min-width: 0;
}

/* Card title — the client's own section name ("Retirement Planning" /
   "Wealth Management"). Small sage eyebrow above the hero tagline, same
   treatment as .section__eyebrow so the two service names read as labels,
   not competing headlines with the hero line below them. */
.service-accordion__title {
  font-size: var(--fs-small);
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--color-sage-deep);
  /* Guard against inherited body{text-align:justify} — on a narrow mobile
     card this eyebrow wraps to 2 lines ("GROW & MANAGE / YOUR WEALTH"),
     and justify stretched huge gaps into the short first line. */
  text-align: left;
}

.service-accordion__hero {
  font-family: var(--font-heading);
  font-size: var(--fs-h3);
  font-weight: 500;
  color: var(--color-ink);
  /* Same justify-on-wrap guard as .about-principle__title. */
  text-align: left;
}

/* The alternating navy/sage headline color (2nd card in sage-deep) was
   flagged twice as a readability problem even after being bumped from
   plain --color-sage to the WCAG-AA-passing --color-sage-deep (5.14:1 on
   this card's --color-bg fill) — green body-sized headline text reads as
   "off"/low-emphasis regardless of measured contrast. Dropped the
   alternation: every .service-accordion__hero is --color-ink (navy) now,
   same as every other heading site-wide. */

/* Mini divider under the hero line — a short line + sparkle, the same
   ornament vocabulary as .hero-ornament elsewhere, just left-aligned and
   smaller since it's inside a card, not a full section header. */
.service-accordion__divider {
  display: flex;
  align-items: center;
  gap: var(--space-2xs);
  margin: 2px 0;
}

.service-accordion__divider::before {
  content: '';
  width: 32px;
  height: 1px;
  background: rgba(107, 127, 94, 0.5);
}

.service-accordion__divider svg {
  width: 8px;
  height: 8px;
  color: var(--color-sage);
  flex-shrink: 0;
}

.service-accordion__summary {
  font-size: var(--fs-small);
  color: var(--color-text-muted);
}

/* Toggle — the +/- icon now sits centred inside a ringed circle button
   instead of floating bare in the card corner, matching the reference. */
.service-accordion__toggle {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 52px;
  height: 52px;
  border-radius: 50%;
  border: 1px solid rgba(107, 127, 94, 0.3);
  flex-shrink: 0;
  transition: border-color var(--transition-fast);
}

.service-accordion__head:hover .service-accordion__toggle,
.service-accordion__head:focus-visible .service-accordion__toggle {
  border-color: var(--color-sage);
}

/* +/- icon — same construction as .faq__icon, collapsing the vertical bar
   to a minus on [open]. */
.service-accordion__icon {
  position: relative;
  width: 18px;
  height: 18px;
  color: var(--color-sage-deep);
}

.service-accordion__icon::before,
.service-accordion__icon::after {
  content: '';
  position: absolute;
  inset: 0;
  margin: auto;
  background: currentColor;
  /* --transition-fast (~180ms), close to the 280ms body slide, so the icon
     resolves to its minus/plus in step with the panel rather than lagging on
     the slower 400ms base. */
  transition: transform var(--transition-fast);
}

.service-accordion__icon::before {
  width: 14px;
  height: 2px;
}

.service-accordion__icon::after {
  width: 2px;
  height: 14px;
}

.service-accordion__item[open] .service-accordion__icon::after {
  transform: rotate(90deg) scaleX(0);
}

@media (max-width: 640px) {
  /* v2 (2026-08-16, client feedback on the earlier badge-beside-text row):
     squeezing the badge, eyebrow+title text, and toggle into one row left
     the eyebrow ("PLAN YOUR FUTURE") wrapping into a cramped 2-line column
     between two circles, with the toggle floating disconnected near the
     card's rounded corner. Wrap the head instead: badge + toggle form a
     top row (badge left, toggle pinned right via margin-left:auto), and
     .service-accordion__head-text drops to its own full-width row below,
     so the eyebrow/title/summary get the whole card width to breathe in
     instead of a narrow column squeezed between two icons. */
  .service-accordion__head {
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-sm);
    padding: var(--space-md) var(--space-sm);
  }

  .service-badge {
    order: 1;
    width: 56px;
    height: 56px;
  }

  .service-badge__icon {
    width: 44px;
    height: 44px;
  }

  .service-badge__icon svg {
    width: 22px;
    height: 22px;
  }

  .service-accordion__head-text {
    order: 3;
    flex-basis: 100%;
    gap: var(--space-sm);
    margin-top: var(--space-sm);
  }

  .service-accordion__accent {
    display: none;
  }

  .service-accordion__toggle {
    order: 2;
    margin-left: auto;
    width: 36px;
    height: 36px;
  }

  .service-accordion__icon {
    width: 14px;
    height: 14px;
  }

  .service-accordion__icon::before {
    width: 10px;
  }

  .service-accordion__icon::after {
    height: 10px;
  }
}

.service-accordion__body {
  padding: 0 var(--space-md) var(--space-lg);
  color: var(--color-text-muted);
  /* height is animated inline by initAccordionMotion (main.js) between 0 and
     the measured height; overflow:hidden clips the padding during the slide.
     ~280ms sits in the requested 250-300ms range and reads as considered,
     not sluggish. The reduced-motion block below removes this so the JS
     bail-out leaves a clean instant toggle. */
  overflow: hidden;
  transition: height 280ms ease;
}

.service-accordion__body > p {
  max-width: 68ch;
}

.service-accordion__subhead {
  font-family: var(--font-heading);
  font-size: var(--fs-body-lg);
  font-weight: 500;
  color: var(--color-ink);
  margin-top: var(--space-lg);
  margin-bottom: var(--space-sm);
}

.service-accordion__list {
  display: flex;
  flex-direction: column;
  gap: var(--space-sm);
  max-width: 68ch;
}

.service-accordion__list > li {
  position: relative;
  padding-left: var(--space-md);
}

.service-accordion__list > li::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0.6em;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--color-sage);
}

.service-accordion__list strong {
  color: var(--color-ink);
  font-weight: 600;
}

.service-accordion__sublist {
  margin-top: var(--space-sm);
  display: flex;
  flex-direction: column;
  gap: var(--space-2xs);
  padding-left: var(--space-md);
}

.service-accordion__sublist > li {
  position: relative;
  padding-left: var(--space-md);
}

.service-accordion__sublist > li::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0.55em;
  width: 5px;
  height: 2px;
  background: var(--color-sage);
}

/* Mobile indentation: the indent stacked three times (parent li 24 + sublist 24
   + sublist li 24 = 72px), squeezing sub-point text into a narrow column that
   wrapped every 3–4 words, and leaving a ~19px gutter between each dash and its
   text. Tightened to 16 + 8 + 16 = 40px, which keeps the nesting legible while
   giving the text back ~32px of line width and pulling the markers in close. */
@media (max-width: 767px) {
  .service-accordion__list > li {
    padding-left: var(--space-sm);
  }

  .service-accordion__sublist {
    padding-left: var(--space-2xs);
  }

  .service-accordion__sublist > li {
    padding-left: var(--space-sm);
  }
}

.service-accordion__cta {
  margin-top: var(--space-lg);
  /* Smaller text + tighter inline padding than the base button so "Book a
     Free Consultation" is a compact CTA (one line at ~390px+, a tidy two
     lines on the narrowest phones) rather than the tall wrapped pill the
     full-length label produced. */
  font-size: var(--fs-small);
  padding-inline: var(--space-md);
}

.service-accordion__disclaimer {
  margin-top: var(--space-md);
  font-size: var(--fs-small);
  color: var(--color-text-muted);
  opacity: 0.85;
}

.testimonial-card cite {
  display: block;
  margin-top: var(--space-sm);
  font-style: normal;
  color: var(--color-text-muted);
}

/* ==========================================================================
   About
   ========================================================================== */
.about__copy {
  max-width: 720px;
  margin-inline: auto;
  text-align: center;
}

.about__copy p + p {
  margin-top: var(--space-md);
}

/* Mobile: these section-lead / narrative blocks run 4–8 lines on a phone,
   and centred long-form copy is slow to read (every line start is in a
   different place). Left-align them — the centred section title above still
   anchors the block. */
@media (max-width: 640px) {
  .about__copy,
  .about__copy p {
    text-align: left;
  }
}

/* Homepage About is a teaser — this centres the "Learn More About Us" link
   to about.html below the hook sentence. */
.about__cta {
  margin-top: var(--space-lg);
  text-align: center;
}

.about__stats {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-lg);
  margin-top: var(--space-xl);
  padding-top: var(--space-lg);
  border-top: 1px solid var(--color-border);
}

.about__stat {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: var(--space-2xs);
}

.about__stat-value {
  font-family: var(--font-heading);
  font-size: var(--fs-h2);
  font-weight: 500;
  color: var(--color-sage);
}

.about__stat-label {
  font-size: var(--fs-small);
  color: var(--color-text-muted);
  max-width: 20ch;
}

/* Standalone stat row (about.html Credentials card) — drop the top border/
   margin that .about__stats carries for when it sits *below* other content. */
.about__stats--plain {
  margin-top: 0;
  padding-top: 0;
  border-top: none;
}

@media (max-width: 767px) {
  .about__stats {
    grid-template-columns: 1fr;
    gap: var(--space-md);
  }
}

/* ==========================================================================
   About page (about.html) — dark intro band, principles, CTA. Built to echo
   the homepage's system (dark "authority" card, sage icons, stat row) so the
   sub-page reads as part of the same site.
   ========================================================================== */
.about-intro {
  position: relative;
  overflow: hidden;
  padding-block: clamp(3rem, 9vw, 6rem);
  text-align: center;
}

.about-intro__stars {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
}

.about-intro__star {
  position: absolute;
  height: auto;
  opacity: var(--star-opacity, 0.5);
  animation: star-twinkle 3.6s ease-in-out infinite; /* shares the star-twinkle keyframe with .hero__star */
}

.about-intro__star:nth-child(3n)   { animation-duration: 3s; }
.about-intro__star:nth-child(3n+1) { animation-duration: 4.2s; }
.about-intro__star:nth-child(3n+2) { animation-duration: 5.1s; }

.about-intro__content {
  position: relative;
  z-index: 1;
}

/* 64px (was 54) — same 76%-of-frame correction as the nav/footer marks. This
   is the one slot big enough for the mark's stars to actually read. */
.about-intro__mark {
  width: 64px;
  height: auto;
  margin: 0 auto var(--space-md);
  opacity: 0.9;
}

/* Eyebrow on a dark card — the base .section__eyebrow is sage-deep, which
   disappears on navy; lift it to sage-light. */
.section__eyebrow--on-dark {
  color: var(--color-sage-light);
}

.about-intro__title {
  font-family: var(--font-heading);
  font-weight: 500;
  font-size: var(--fs-h1);
  color: var(--color-text-inverse);
  margin-bottom: var(--space-md);
}

.about-intro__lead {
  font-family: var(--font-heading);
  font-style: italic;
  font-weight: 500;
  font-size: var(--fs-body-lg);
  line-height: 1.4;
  color: rgba(245, 239, 217, 0.92);
  max-width: 34ch;
  margin-inline: auto;
}

/* Wider variant for ethical-investing.html's lead — a full multi-sentence
   paragraph, not the one-line hook every other .about-intro__lead reuse
   has (about.html, services.html, how-we-work.html, etc.) — 34ch wrapped
   it into a narrow tower of short lines. Scoped modifier rather than
   widening the shared class, since the short leads elsewhere read fine
   (better, even) at 34ch. */
.about-intro__lead--wide {
  max-width: 62ch;
}

.about-principles {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--space-lg);
  max-width: 900px;
  margin-inline: auto;
}

/* Column-count variants — ethical-investing.html's new "How It Works"
   (3-step) and "Four Pathways" teaser sections, added 2026-08-16. */
.about-principles--three {
  grid-template-columns: repeat(3, 1fr);
  max-width: 1000px;
}

.about-principles--four {
  grid-template-columns: repeat(4, 1fr);
  max-width: 1100px;
}

/* Grid items stretch to equal row height by default, but the *content*
   inside each plain-block .about-principle didn't use that height — when
   one title wraps to 2 lines ("Socially Responsible") its paragraph and
   "Learn more" link sit lower than the other three columns, so the links
   read as a staggered row instead of a lined-up one. Flex column + margin-
   top:auto on the link pins every column's link to the same baseline
   regardless of how many lines its title/paragraph wrap to. Scoped to the
   4-column variant (homepage's Ethical Investing "at a glance" grid) since
   that's the one with uneven title lengths; other .about-principles reuses
   are unaffected. */
.about-principles--four .about-principle {
  display: flex;
  flex-direction: column;
}

.about-principles--four .about-principle__text {
  display: flex;
  flex-direction: column;
  flex: 1;
}

.about-principles--four .pathway-link {
  margin-top: auto;
  padding-top: var(--space-sm);
}

/* ==========================================================================
   Homepage "From the Blog" teaser (index.html#blog) — a decorative lockup
   the client mocked up: each card centres a haloed icon flanked by leaf
   sprigs, a "— NN —" number rule, title, excerpt, and a "Read the guide"
   link; the "Visit the Blog" button is flanked by larger sprigs. Sprigs
   are sage, colour-agnostic, and extend the site's existing leaf
   vocabulary (.decor-branch / .teaser-spark). The icon badge reuses
   .about-principle__icon unchanged.
   ========================================================================== */
.sprig-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-md);
  max-width: 1000px;
  margin-inline: auto;
}

/* 4-up variant (homepage #ethical-investing "at a glance" grid) — one row
   of four on desktop; the base .sprig-grid media queries below still drop
   it to 2-up (≤900) and 1-up (≤620). Tighter padding + smaller flanking
   sprigs so four cards fit a row without crowding. */
.sprig-grid--four {
  grid-template-columns: repeat(4, 1fr);
  max-width: 1140px;
}

.sprig-grid--four .sprig-card {
  padding: var(--space-lg) var(--space-sm);
}

.sprig-grid--four .sprig-card__figure {
  gap: var(--space-2xs);
}

.sprig-grid--four .sprig-card__sprig {
  width: 44px;
}

.sprig-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  padding: var(--space-lg) var(--space-md);
  background: var(--color-bg);
  border: 1px solid rgba(107, 127, 94, 0.28);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
  transition: transform var(--transition-base), box-shadow var(--transition-base);
}

.sprig-card:hover,
.sprig-card:focus-within {
  transform: translateY(-2px);
  box-shadow: var(--shadow-md);
}

.sprig-card__figure {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-sm);
  margin-bottom: var(--space-md);
}

.sprig-card__figure .about-principle__icon {
  margin-bottom: 0;
}

.sprig-card__sprig {
  width: 54px;
  height: auto;
  color: var(--color-sage);
  opacity: 0.75;
  flex-shrink: 0;
}

.sprig-card__sprig--right {
  transform: scaleX(-1);
}

.sprig-card__num {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin-bottom: var(--space-sm);
  font-size: var(--fs-small);
  font-weight: 600;
  letter-spacing: 0.18em;
  color: var(--color-sage-deep);
}

.sprig-card__num::before,
.sprig-card__num::after {
  content: "";
  width: 18px;
  height: 1px;
  background: currentColor;
  opacity: 0.6;
}

.sprig-card__title {
  font-family: var(--font-heading);
  font-weight: 500;
  font-size: var(--fs-h3);
  line-height: 1.25;
  text-align: center;
}

.sprig-card__title a {
  color: inherit;
}

.sprig-card__title a:hover,
.sprig-card__title a:focus-visible {
  color: var(--color-sage-deep);
  text-decoration: underline;
}

.sprig-card__excerpt {
  margin-top: var(--space-sm);
  color: var(--color-text-muted);
  font-size: var(--fs-small);
  line-height: 1.65;
  text-align: center;
  hyphens: none;
  flex: 1;
}

.sprig-card__link {
  align-self: flex-start;
  margin-top: var(--space-md);
  color: var(--color-sage-deep);
  font-weight: 600;
  font-size: var(--fs-small);
}

.sprig-card__link:hover,
.sprig-card__link:focus-visible {
  text-decoration: underline;
}

.sprig-grid__cta {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-md);
  margin-top: var(--space-xl);
}

.sprig-grid__cta-sprig {
  width: 92px;
  height: auto;
  color: var(--color-sage);
  opacity: 0.5;
  flex-shrink: 0;
}

.sprig-grid__cta-sprig--right {
  transform: scaleX(-1);
}

@media (max-width: 900px) {
  .sprig-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (max-width: 620px) {
  .sprig-grid {
    grid-template-columns: 1fr;
  }

  .sprig-grid__cta-sprig {
    display: none;
  }
}

@media (max-width: 900px) {
  .about-principles--three,
  .about-principles--four {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (max-width: 560px) {
  .about-principles--three,
  .about-principles--four {
    grid-template-columns: 1fr;
  }

  /* Single column at this width turned the 4-item ethical-investing grid
     into a bare list — icon, title, paragraph, link, repeated 4 times with
     nothing to group each one visually. Framing each as its own light
     card (same var(--color-bg)-on-cream recipe as .approach/.service-
     accordion__item) gives it the structure a plain vertical list lacks.
     Scoped to --four only — the other .about-principles reuses (About's
     2-up grid, ethical-investing.html's 3-step "How It Works") keep their
     original bare-list mobile treatment. */
  .about-principles--four .about-principle {
    padding: var(--space-md);
    background: var(--color-bg);
    border-radius: var(--radius);
    box-shadow: var(--shadow-sm);
  }
}

.pathway-link {
  display: inline-block;
  margin-top: var(--space-sm);
  color: var(--color-sage-deep);
  font-weight: 600;
  font-size: var(--fs-small);
}

.pathway-link:hover,
.pathway-link:focus-visible {
  text-decoration: underline;
}

.about-principle__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  border-radius: 50%;
  background: var(--color-sage-light);
  color: var(--color-sage-deep);
  margin-bottom: var(--space-md);
  /* Dashed "halo" ring added 2026-07-27 to match .service-badge's icon
     treatment — an outline (not a wrapper element) so the ring applies
     everywhere this class is already reused (about.html's principles,
     the approach cards on ethical-investing.html) without new markup.
     outline follows the circular border-radius in every browser this
     site supports, unlike an actual border, which would need a second
     wrapping element to sit outside the fill. */
  outline: 1px dashed rgba(107, 127, 94, 0.35);
  outline-offset: 6px;
}

.about-principle__icon svg {
  width: 24px;
  height: 24px;
}

.about-principle__title {
  font-family: var(--font-heading);
  font-weight: 500;
  font-size: var(--fs-h3);
  margin-bottom: var(--space-sm);
  /* Guard against inherited body{text-align:justify} — numbered headings
     like "01. Your Financial Roadmap" wrap in narrow grid columns, and
     justify stretched the first line apart ("01.   Your   Financial" /
     "Roadmap"). Headings are never justify candidates, only long-form
     body paragraphs are. */
  text-align: left;
}

.about-principle p {
  color: var(--color-text-muted);
}

/* About page's "Our Approach" only (--approach modifier — the shared
   .about-principles/.about-principle classes stay as the stacked
   icon-above-text layout everywhere else they're reused: this page's own
   Credentials-adjacent usage doesn't exist, but investment-advisory.html/
   how-we-work.html's "Who This Is For" and ethical-investing.html's
   approach cards all keep the original treatment). Icon sits to the left,
   vertically centered against the full height of its title+paragraph
   text block instead of stacked above it; paragraph text is justified. */
.about-principles--approach .about-principle {
  display: flex;
  align-items: center;
  gap: var(--space-lg);
  text-align: left;
}

.about-principles--approach .about-principle__icon {
  flex-shrink: 0;
  margin-bottom: 0;
}

.about-principles--approach .about-principle__text {
  min-width: 0;
}

.about-principles--approach .about-principle p {
  text-align: justify;
}

@media (max-width: 640px) {
  /* Stack the icon above the text, all left-aligned. (This block used to
     centre everything, but .about-principle__title keeps its own
     text-align:left guard, so the result was a left title over a centred
     paragraph — inconsistent and harder to read. Left throughout matches
     the title and the rest of the site's mobile body copy.) */
  .about-principles--approach .about-principle {
    flex-direction: column;
    align-items: flex-start;
    text-align: left;
  }

  .about-principles--approach .about-principle p {
    text-align: left;
  }
}

/* Adviser bio (About page) — avatar + name/role/bio, side by side on
   desktop, stacked and centered on mobile. Avatar is the logo mark inside
   a sage-ringed circle (same dashed-halo language as .service-badge/
   .about-principle__icon) — a placeholder until a real photo exists, not a
   fabricated headshot. */
.about-adviser {
  display: flex;
  align-items: center;
  gap: var(--space-lg);
  max-width: 720px;
  margin-inline: auto;
}

.about-adviser__avatar {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 140px;
  height: 140px;
  border-radius: 50%;
  background: var(--color-navy);
  outline: 1px dashed rgba(107, 127, 94, 0.45);
  outline-offset: 8px;
}

.about-adviser__avatar img {
  width: 84px;
  height: auto;
}

.about-adviser__text {
  text-align: left;
}

.about-adviser__name {
  text-align: left;
  margin-bottom: var(--space-2xs);
}

.about-adviser__role {
  color: var(--color-sage-deep);
  font-weight: 600;
  margin-bottom: var(--space-md);
}

@media (max-width: 640px) {
  .about-adviser {
    flex-direction: column;
    text-align: center;
  }

  .about-adviser__text,
  .about-adviser__name {
    text-align: center;
  }
}

.about-cta {
  text-align: center;
}

.about-cta__text {
  max-width: 46ch;
  margin: 0 auto var(--space-lg);
  color: var(--color-text-muted);
}

.about-cta__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: var(--space-md);
}

/* ==========================================================================
   Contact CTA, two-column variant (ethical-investing.html) — the plain
   centered .about-cta content (unchanged) plus a divider and a "why talk to
   us" trio on desktop. Mobile-first: single column, trio stacks below the
   CTA content and the divider disappears (a horizontal rule between two
   stacked columns would read as a stray line, not a divider).
   ========================================================================== */
.contact-cta {
  position: relative;
}

.contact-cta__watermark {
  position: absolute;
  bottom: -30px;
  left: -40px;
  width: 220px;
  height: auto;
  opacity: 0.12;
  pointer-events: none;
  z-index: 0;
}

.contact-cta__grid {
  position: relative;
  z-index: 1;
  display: grid;
  gap: var(--space-lg);
}

.contact-cta__divider {
  display: none;
}

.contact-cta__trust-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-md);
}

.contact-cta__trust-item {
  display: flex;
  align-items: flex-start;
  gap: var(--space-sm);
  padding-bottom: var(--space-md);
  border-bottom: 1px solid var(--color-border);
}

.contact-cta__trust-item:last-child {
  border-bottom: none;
  padding-bottom: 0;
}

.contact-cta__trust-item .about-principle__icon {
  margin-bottom: 0;
  flex-shrink: 0;
}

.contact-cta__trust-title {
  font-family: var(--font-heading);
  font-size: var(--fs-body-lg);
  color: var(--color-ink);
  margin-bottom: 0.25rem;
}

.contact-cta__trust-text {
  color: var(--color-text-muted);
  font-size: var(--fs-small);
  line-height: 1.5;
}

@media (min-width: 900px) {
  .contact-cta__grid {
    grid-template-columns: 1.3fr 1px 1fr;
    align-items: center;
  }

  .contact-cta__divider {
    display: block;
    align-self: stretch;
    width: 1px;
    background: var(--color-border);
  }
}

@media (max-width: 767px) {
  .about-principles {
    grid-template-columns: 1fr;
    gap: var(--space-lg);
  }
}

/* ==========================================================================
   thanks.html — the post-submit card. Same tree-mark-in-a-ring badge idea
   as the social-icons modal, but a plain outline ring instead of a filled
   dark roundel: at this larger size (120px vs the modal's 56px) the tree
   asset's own pale gold tone has enough weight to read directly on the
   cream card, so no dark backing is needed here.
   ========================================================================== */
.thanks-card {
  position: relative;
}

.thanks-card__watermark {
  position: absolute;
  bottom: -20px;
  width: 180px;
  height: auto;
  opacity: 0.12;
  pointer-events: none;
  z-index: 0;
}

.thanks-card__watermark--left {
  left: -30px;
  transform: rotate(-6deg);
}

.thanks-card__watermark--right {
  right: -30px;
  transform: scaleX(-1) rotate(-6deg);
}

.thanks-card__content {
  position: relative;
  z-index: 1;
}

.thanks-card__badge-row {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 1.5rem;
  margin-bottom: var(--space-md);
}

.thanks-card__spark {
  flex-shrink: 0;
  width: 14px;
  height: 14px;
  color: var(--color-sage);
}

/* Fixed 2026-08-10: the tree asset's pale gold tone turned out to be
   nearly invisible against the cream card even at 120px — a hollow
   outline ring wasn't enough contrast, contrary to the original guess.
   Same navy-fill fix as the social-icons modal's badge, not a hollow ring. */
.thanks-card__badge {
  flex-shrink: 0;
  width: 120px;
  height: 120px;
  border-radius: 50%;
  background: var(--color-ink);
  box-shadow: 0 6px 20px rgba(20, 33, 61, 0.25);
  display: flex;
  align-items: center;
  justify-content: center;
}

.thanks-card__badge-icon {
  width: 78px;
  height: auto;
  display: block;
}

.thanks-card__back {
  display: inline-flex;
  align-items: center;
  gap: 0.4em;
  color: var(--color-ink);
  font-weight: 600;
}

.thanks-card__back svg {
  width: 16px;
  height: 16px;
  transition: transform var(--transition-base);
}

.thanks-card__back:hover svg,
.thanks-card__back:focus-visible svg {
  transform: translateX(3px);
}

/* ==========================================================================
   FAQ — native <details>/<summary> accordion, no JS. Marker removed and
   replaced with a CSS-drawn +/x icon that rotates on [open], matching the
   nav/button hover-state treatment used everywhere else on the page.
   ========================================================================== */
.faq__list {
  max-width: 760px;
  margin-inline: auto;
}

.faq__item {
  border-bottom: 1px solid var(--color-border);
}

.faq__item:first-child {
  border-top: 1px solid var(--color-border);
}

.faq__question {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-md);
  padding-block: var(--space-md);
  font-family: var(--font-heading);
  font-size: var(--fs-h3);
  font-weight: 500;
  cursor: pointer;
  list-style: none;
  transition: color var(--transition-base);
}

.faq__question::-webkit-details-marker {
  display: none;
}

.faq__question:hover,
.faq__question:focus-visible {
  color: var(--color-sage);
}

.faq__icon {
  flex: 0 0 auto;
  position: relative;
  width: 20px;
  height: 20px;
}

.faq__icon::before,
.faq__icon::after {
  content: '';
  position: absolute;
  inset: 0;
  margin: auto;
  background: currentColor;
  /* --transition-fast to resolve in step with the ~280ms answer slide,
     matching the Services accordion icon. */
  transition: transform var(--transition-fast);
}

.faq__icon::before {
  width: 14px;
  height: 2px;
}

.faq__icon::after {
  width: 2px;
  height: 14px;
}

.faq__item[open] .faq__icon::after {
  transform: rotate(90deg) scaleX(0);
}

.faq__answer {
  padding-bottom: var(--space-md);
  color: var(--color-text-muted);
  max-width: 65ch;
  /* Height animated inline by initAccordionMotion (main.js), same ~280ms
     slide as the Services accordion — overflow:hidden clips the padding
     during the transition. Removed under reduced motion (below). */
  overflow: hidden;
  transition: height 280ms ease;
}

/* ==========================================================================
   Contact — two columns: info (eyebrow/headline/intro/WhatsApp/phone/email)
   on the left, a contact form on the right. .section__eyebrow/__title are
   centered by default (every other section using them wants that); this
   is the one place that needs them left-aligned instead.
   ========================================================================== */
.contact__grid {
  display: grid;
  gap: var(--space-xl);
}

/* Card treatment (was plain, unstyled text) — with the phone/email rows
   still removed pending real details, this column was just an eyebrow +
   headline + intro + one button next to the form's full boxed-in card,
   reading as sparse/unfinished rather than intentionally minimal. Matches
   .contact-form's own background/padding/radius/shadow so the two columns
   carry equal visual weight, instead of collapsing to one column — the
   channels rows (see the TODO above) will live in this same box once real
   contact details are ready, so it needs to hold together as a card either
   way, not just as a patch for the current sparse content. */
.contact__info {
  background: var(--color-bg);
  padding: var(--space-lg);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
}

@media (max-width: 480px) {
  .contact__info {
    padding: var(--space-md);
  }
}

.contact__info .section__eyebrow,
.contact__info .section__title {
  text-align: left;
  margin-inline: 0;
}

.contact__info .btn {
  margin-bottom: var(--space-lg);
}

/* No trailing margin when the button is the last thing in the card (true
   right now, with .contact__channels still removed — see the TODO above
   .contact-form) — otherwise the card has empty space hanging below it. */
.contact__info .btn:last-child {
  margin-bottom: 0;
}

/* Smaller WhatsApp button on mobile — the base button's wide 48px inline
   padding made it oversized here on phones. Trims text + horizontal
   padding while keeping the vertical padding (so it stays >=44px tall). */
@media (max-width: 767px) {
  .contact__info .btn {
    font-size: var(--fs-small);
    padding-inline: var(--space-md);
  }
}

.contact__intro {
  max-width: 480px;
  margin-top: 0;
  margin-bottom: var(--space-lg);
  color: var(--color-text-muted);
}

.contact__channels {
  display: flex;
  flex-direction: column;
  gap: var(--space-md);
}

.contact__channel {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  transition: color var(--transition-base);
}

.contact__channel:hover,
.contact__channel:focus-visible {
  color: var(--color-sage-deep);
}

.contact__channel-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  flex-shrink: 0;
  border-radius: 50%;
  background: var(--color-sage-light);
  color: var(--color-sage-deep);
}

.contact__channel-icon svg {
  width: 18px;
  height: 18px;
}

.contact__channel-text {
  display: flex;
  flex-direction: column;
  font-size: var(--fs-small);
}

.contact__channel-label {
  font-weight: 600;
  color: var(--color-ink);
}

.contact__channel-value {
  color: var(--color-text-muted);
}

/* Non-interactive channel (the office address — it's a location, not a
   tel:/mailto: link), so it drops the pointer cursor and the hover colour
   shift the linked channels use. */
.contact__channel--static {
  cursor: default;
}

.contact__channel--static:hover,
.contact__channel--static:focus-visible {
  color: inherit;
}

/* Wrapping <address> — reset the browser's default italic so the address
   matches the rest of the info column. */
address.contact__channels {
  font-style: normal;
}

/* Short market-risk line under the contact grid (see the comment in
   index.html for why it's the short form, not the full footer disclaimer). */
.contact__disclaimer {
  margin-top: var(--space-lg);
  font-size: var(--fs-small);
  color: var(--color-text-muted);
  opacity: 0.85;
  text-align: center;
  max-width: 70ch;
  margin-inline: auto;
}

.contact-form {
  display: flex;
  flex-direction: column;
  gap: var(--space-md);
  background: var(--color-bg);
  padding: var(--space-lg);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
}

@media (max-width: 480px) {
  /* --space-lg (48px) on all sides, stacked with the container's and
     card's own mobile padding, leaves as little as ~130px of usable
     width for the inputs on a 320-375px phone — halve it there. */
  .contact-form {
    padding: var(--space-md);
  }
}

.contact-form__field input,
.contact-form__field textarea {
  width: 100%;
  font-family: var(--font-body);
  font-size: var(--fs-body);
  color: var(--color-text);
  background: var(--color-bg);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  padding: var(--space-sm) var(--space-md);
  transition: border-color var(--transition-base);
}

.contact-form__field textarea {
  resize: vertical;
}

/* A 1px border-colour change was the ONLY focus indicator here — every other
   control on the site gets a 2px sage ring, and a keyboard user tabbing into
   the form effectively lost their place. The ring is the indicator; the border
   change stays as reinforcement. */
.contact-form__field input:focus-visible,
.contact-form__field textarea:focus-visible {
  outline: 2px solid var(--color-sage);
  outline-offset: 2px;
  border-color: var(--color-sage);
}

.contact-form__submit {
  width: 100%;
  justify-content: space-between;
}

.contact-form__status {
  font-size: var(--fs-small);
  color: var(--color-text-muted);
  text-align: center;
  min-height: 1.2em; /* reserves space so it appearing doesn't shift the form/button below it */
}

@media (min-width: 768px) {
  .contact__grid {
    grid-template-columns: 1fr 1fr;
    /* Was align-items: start — with the phone/email rows removed, the left
       column (eyebrow/headline/intro/WhatsApp button) is noticeably shorter
       than the form now, and top-aligning left it looking like it was
       missing something below. Centering it against the form reads as
       intentional rather than incomplete. */
    align-items: center;
  }
}

/* ==========================================================================
   Footer — a dark bar (unlike every other card, which is either the hero's
   navy or a light card): sits last on the page, so it reads as a closing
   "base" rather than another content card. .card--dark supplies the
   background/inherited text color; everything else here is layout.
   ========================================================================== */
.footer {
  padding-block: var(--space-lg);
  font-size: var(--fs-small);
}

.footer__inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-md);
  text-align: center;
}

.footer__brand {
  display: inline-flex;
}

/* 42px (was 32) — see .nav__logo-mark for why the full mark needs ~1.3x the
   old tree.png sizing to render the tree at the same size. */
.footer__logo-mark {
  width: 42px;
  height: auto;
}

.footer__links {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--space-2xs); /* trimmed — links carry inline padding (see below) */
}

.footer__links a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px; /* touch target — the link text alone is only ~17px tall */
  padding-inline: var(--space-2xs); /* widens "About"/etc. to >=44px too */
  transition: color var(--transition-base);
}

.footer__links a:hover,
.footer__links a:focus-visible {
  color: var(--color-sage-light);
}

.footer__copyright {
  color: rgba(245, 239, 217, 0.75);
}

.footer__credit {
  text-align: center;
  color: rgba(245, 239, 217, 0.6);
  font-size: var(--fs-small);
  margin-top: var(--space-md);
}

.footer__credit a {
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 2px;
  transition: color var(--transition-base);
}

.footer__credit a:hover,
.footer__credit a:focus-visible {
  color: var(--color-sage-light);
}

/* Social "find us elsewhere" row — quiet secondary signal below the
   brand/links/copyright row. Sage to tie into the site's icon
   system (trust bar / accordion icons), brightening to sage-light on
   hover exactly like the footer text links. Static — no sticky/float. */
.footer__social {
  display: flex;
  justify-content: center;
  gap: var(--space-sm);
  margin-top: var(--space-2xs);
}

.footer__social-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 44px;
  min-height: 44px; /* touch target — was 36px (20px glyph + 8px padding) */
  color: var(--color-sage);
  transition: color var(--transition-base), transform var(--transition-base);
  /* These are <button> elements (not links — clicking opens the "coming
     soon" modal, there's nowhere real to navigate to yet), so undo default
     button chrome. */
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
  font: inherit;
}

.footer__social-link:hover,
.footer__social-link:focus-visible {
  color: var(--color-sage-light);
  transform: translateY(-2px);
}

.footer__social-icon {
  width: 20px;
  height: 20px;
}

/* ==========================================================================
   Floating WhatsApp button — the persistent primary CTA (WhatsApp is the
   primary channel across the whole site). Fixed bottom-right, above content;
   56px so it clears the 44px touch minimum comfortably. Uses the site's sage
   treatment (matching every other WhatsApp CTA here — the site deliberately
   doesn't use WhatsApp's native green) with the WhatsApp glyph for instant
   recognition. `wa.me` deep-links straight into the WhatsApp app on iOS and
   Android. Hides itself (initWhatsAppFab in main.js) over the contact/CTA
   sections and the footer, so it never collides with the inline WhatsApp
   button, the form's submit, or the footer text.
   ========================================================================== */
.whatsapp-fab {
  position: fixed;
  right: clamp(1rem, 4vw, 1.5rem);
  bottom: clamp(1rem, 4vw, 1.5rem);
  z-index: 200;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 56px;
  height: 56px;
  border-radius: 50%;
  background: var(--color-sage-deep);
  color: var(--color-cream);
  /* Own shadow, not --shadow-lg: that token's wide 40px navy blur got clipped
     by the viewport corner into a rounded-SQUARE patch ("boxed" on mobile).
     Negative spread pulls it in tight so it hugs the circle, and a sage tint
     makes it read as the button's own glow rather than a stray navy box. */
  box-shadow: 0 8px 22px -6px rgba(58, 74, 48, 0.5), 0 2px 6px rgba(20, 33, 61, 0.12);
  transition: transform var(--transition-base), opacity var(--transition-base),
              visibility var(--transition-base), background var(--transition-base);
}

.whatsapp-fab svg {
  width: 30px;
  height: 30px;
}

.whatsapp-fab:hover {
  background: #4f6045;
  transform: translateY(-3px) scale(1.04);
}

.whatsapp-fab:focus-visible {
  outline: 2px solid var(--color-sage);
  outline-offset: 3px;
}

/* Toggled by initWhatsAppFab when a [data-fab-hide] zone (contact/CTA/footer)
   scrolls into view — collapses out so it can't overlap those. */
.whatsapp-fab.is-hidden {
  opacity: 0;
  visibility: hidden;
  transform: scale(0.8) translateY(12px);
  pointer-events: none;
}

/* Two paragraphs now (the real SEBI/BASL/NISM disclaimer is two separate
   sentences) — divider (margin/border) belongs on the first only, so
   they don't read as two separately-boxed disclaimers.

   Color raised from rgba(cream, 0.6) — that already cleared WCAG AA
   (~5.85:1 against navy) on paper, but cream at low opacity over dark
   navy reads as a dim, desaturated grey rather than legible cream, and
   this is mandatory regulatory text (SEBI/BASL/NISM). 0.75 gives a more
   comfortable margin and actually looks legible, not just technically compliant. */
.footer__disclaimer {
  text-align: center;
  color: rgba(245, 239, 217, 0.75);
  font-size: var(--fs-small);
}

.footer__disclaimer + .footer__disclaimer {
  margin-top: var(--space-sm);
}

/* Border-top used to live on .footer__disclaimer:first-of-type — moved here
   now that .footer__credentials sits above it, so the separator reads as
   "compliance block starts here" (credentials + disclaimer together) rather
   than splitting the two apart. */
.footer__disclaimer:first-of-type {
  margin-top: var(--space-md);
}

@media (min-width: 768px) {
  /* 3-column grid (equal 1fr flanks) so the links sit dead-centre in the
     footer regardless of the brand/copyright widths — space-between only
     centred them when those two happened to match. */
  .footer__inner {
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    align-items: center;
    text-align: left;
  }

  .footer__brand {
    justify-self: start;
  }

  .footer__links {
    justify-self: center;
  }

  .footer__copyright {
    justify-self: end;
  }
}

/* ==========================================================================
   Scroll-reveal utility (JS toggles .is-visible — see assets/js/main.js)
   ========================================================================== */
.reveal {
  opacity: 0;
  transform: translateY(24px);
  transition: opacity var(--transition-base), transform var(--transition-base);
}

.reveal.is-visible {
  opacity: 1;
  transform: translateY(0);
}

/* ==========================================================================
   Reduced motion — reveals show instantly, hero parallax/twinkle disabled
   (JS also skips initHeroParallax entirely under this media query)
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  .hero__tree,
  .hero__content {
    animation: none !important;
    transform: none !important;
    opacity: 1 !important;
  }

  /* Stop the twinkle but keep each star's resting --star-opacity (do NOT
     force opacity:1 — that made them full-bright instead of subtle). */
  .hero__star {
    animation: none !important;
    transform: none !important;
  }

  .about-intro__star {
    animation: none !important;
  }

  .teaser-spark {
    animation: none !important;
  }

  .reveal {
    opacity: 1;
    transform: none;
    transition: none;
  }

  .process-timeline__vine-path {
    stroke-dashoffset: 0;
    transition: none;
  }

  .process-timeline__step {
    opacity: 1;
    transform: none;
    transition: none;
    transition-delay: 0s;
  }

  .btn:hover,
  .footer__social-link:hover,
  .footer__social-link:focus-visible {
    transform: none;
  }

  /* Nav hovers — keep the state cues (colour, underline, row tint, chevron)
     but strip the motion: no lifts, no swells, no tilts, no slide, and the
     underline / panel / chevron snap rather than ease. */
  .nav__links a::before,
  .nav__dropdown,
  .nav__dropdown a,
  .nav__dropdown a::after {
    transition: none;
  }

  .nav__dropdown {
    transform: none;
  }

  .nav__item--has-dropdown:hover .nav__dropdown,
  .nav__item--has-dropdown:focus-within .nav__dropdown {
    transform: none;
  }

  .nav__dropdown a:hover::after,
  .nav__dropdown a:focus-visible::after {
    transform: none;
  }

  .nav__cta:hover,
  .nav__cta:focus-visible,
  .nav__cta:hover .btn__icon,
  .nav__cta:focus-visible .btn__icon,
  .nav__toggle:hover,
  .nav__toggle:focus-visible,
  .nav__brand:hover .nav__logo-mark,
  .nav__brand:focus-visible .nav__logo-mark {
    transform: none;
  }

  /* Brand sparkles — no blink/drift; hover just reveals them, held steady. */
  .nav__brand-spark path {
    animation: none !important;
    transform: none !important;
    transition: opacity var(--transition-fast);
  }

  .nav__brand:hover .nav__brand-spark path,
  .nav__brand:focus-visible .nav__brand-spark path {
    opacity: 0.8;
  }

  /* Mobile menu opens instantly — no sheet slide, no row stagger. */
  .nav__links.is-open,
  .nav__links.is-open > li {
    animation: none;
  }

  .thanks-card__back:hover svg,
  .thanks-card__back:focus-visible svg {
    transform: none;
  }

  /* FAB still hides/shows (a functional visibility change, not decorative
     motion) but without the slide/scale — snap it, and no hover lift. */
  .whatsapp-fab {
    transition: opacity var(--transition-base), visibility var(--transition-base);
  }

  .whatsapp-fab:hover {
    transform: none;
  }

  .whatsapp-fab.is-hidden {
    transform: none;
  }

  .faq__icon::before,
  .faq__icon::after,
  .service-accordion__icon::before,
  .service-accordion__icon::after,
  .nav__toggle-bar {
    transition: none;
  }

  /* initAccordionMotion bails under reduced motion (native instant toggle
     stands) — make sure no height transition is left declared to fire, and
     the collapsed-card hover lift is neutralised too. */
  .service-accordion__body,
  .faq__answer {
    transition: none;
  }

  .service-accordion__item:not([open]):hover {
    transform: none;
  }

}

/* "Coming soon" modal — opens when a footer social icon is clicked, since
   the client doesn't have real YouTube/Facebook/Instagram/LinkedIn profiles
   yet (see initSocialModal in main.js). Native <dialog>, not a custom
   overlay: free focus-trapping, Escape-to-close, and ::backdrop. */
.social-modal {
  border: none;
  border-radius: var(--card-radius);
  padding: 0;
  max-width: 440px;
  width: calc(100% - 2rem);
  background: var(--color-surface);
  color: var(--color-ink);
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.25);
  /* A native <dialog> centers itself via the UA stylesheet's `margin: auto`
     on the fixed-positioned top-layer box — but this site's global reset
     (`*, *::before, *::after { margin: 0; }`) zeroes that out, so it needs
     to be centered explicitly instead. */
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  margin: 0;
}

.social-modal::backdrop {
  background: rgba(0, 0, 0, 0.5);
}

.social-modal__close {
  position: absolute;
  top: 14px;
  right: 14px;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  border: 1px solid var(--color-border);
  background: transparent;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--color-ink);
  cursor: pointer;
  z-index: 2;
  transition: border-color var(--transition-base), color var(--transition-base);
}

.social-modal__close svg {
  width: 15px;
  height: 15px;
}

.social-modal__close:hover,
.social-modal__close:focus-visible {
  border-color: var(--color-sage);
  color: var(--color-sage-deep);
}

/* Inner bordered panel — the "double border" frame from the reference
   design — plus room at the edges for the corner watermark sprigs to
   bleed off without spilling past the outer card's rounded corners. */
.social-modal__frame {
  position: relative;
  margin: 14px;
  padding: 2.75rem 1.75rem 2rem;
  border: 1px solid rgba(107, 127, 94, 0.3);
  border-radius: calc(var(--card-radius) - 6px);
  overflow: hidden;
  text-align: center;
}

/* The brand tree mark (assets/img/tree.png) — same asset as the hero and
   nav/footer logo. It's a pale cream/gold silhouette designed to sit on the
   dark navy cards elsewhere on the site; here at low opacity on the cream
   modal it reads as a faint tone-on-tone watermark instead, which is the
   point at this size/opacity — not a legibility bug. */
.social-modal__watermark {
  position: absolute;
  bottom: -10px;
  display: block;
  width: 110px;
  height: auto;
  opacity: 0.16;
  pointer-events: none;
}

.social-modal__watermark img {
  display: block;
  width: 100%;
  height: auto;
}

.social-modal__watermark--left {
  left: -26px;
  transform: rotate(-6deg);
}

.social-modal__watermark--right {
  right: -26px;
  transform: scaleX(-1) rotate(-6deg);
}

/* Flexbox row, not absolute-positioned layers — a "spark — badge — spark"
   arrangement the browser centers and spaces itself, so it can't end up
   lopsided the way hand-placed absolute coordinates did (an earlier arc +
   pixel-positioned sparks + overlapping badge was consistently rendering
   asymmetric — removed rather than re-tuned blind). */
.social-modal__ornament {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 1.25rem;
  margin: 0 auto 0.75rem;
}

.social-modal__ornament-spark {
  flex-shrink: 0;
  width: 11px;
  height: 11px;
  color: var(--color-sage);
}

/* The tree mark again, full opacity — but it's pale-on-pale against the
   cream card, so it sits on a small dark roundel (same navy as the
   "authority bookend" cards) for contrast, echoing how the mark is always
   shown on a dark background elsewhere on the site (nav, footer, About's
   intro card). */
.social-modal__branch-badge {
  flex-shrink: 0;
  width: 56px;
  height: 56px;
  border-radius: 50%;
  background: var(--color-ink);
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 4px 14px rgba(20, 33, 61, 0.25);
}

.social-modal__branch-icon {
  width: 34px;
  height: auto;
  display: block;
}

.social-modal__title {
  font-family: var(--font-heading);
  font-weight: 500;
  font-size: var(--fs-h2);
  color: var(--color-ink);
  margin-bottom: 0;
}

.social-modal .hero-ornament {
  max-width: 160px;
}

.social-modal p {
  line-height: 1.6;
  color: var(--color-text-muted);
  margin-bottom: 1.5rem;
}

/* Long-form legal copy (Privacy Policy, Disclosures) — plain readable prose
   inside the existing .section card, not a new page pattern. No new colors,
   just spacing/line-length tuned for paragraphs of text instead of the
   marketing copy the rest of the site is built around. */
.legal {
  max-width: 720px;
  margin: 0 auto;
}

.legal__updated {
  color: var(--color-sage-deep);
  font-size: var(--fs-small);
  margin-bottom: 2rem;
}

.legal h2 {
  font-family: var(--font-heading);
  font-size: var(--fs-h3);
  margin: 2.5rem 0 1rem;
}

.legal h2:first-of-type {
  margin-top: 0;
}

.legal h3 {
  font-family: var(--font-heading);
  font-size: var(--fs-body-lg);
  margin: 1.75rem 0 0.75rem;
}

.legal p,
.legal li {
  line-height: 1.7;
  margin-bottom: 1rem;
}

.legal ul,
.legal ol {
  padding-left: 1.25rem;
  margin-bottom: 1.25rem;
}

.legal a {
  color: var(--color-sage-deep);
  text-decoration: underline;
}

/* ==========================================================================
   Blog — index card grid (.insight-*) + long-form article typography
   (.article*). Added 2026-08-28, UI polish pass. Reuses the site's existing
   card vocabulary rather than inventing a new one: var(--color-bg) panels
   on the cream .card--light, a sage left-accent (same as .approach /
   .reg-note), --shadow-sm at rest lifting to --shadow-md + translateY(-2px)
   on hover (same as .service-accordion__item). No new colours or tokens.
   ========================================================================== */

/* --- Blog index: hero lead + article card grid --- */
.blog-index__lead {
  max-width: 56ch;
  margin: var(--space-md) auto 0;
  text-align: center;
  color: var(--color-text-inverse);
  font-size: var(--fs-body-lg);
  opacity: 0.92;
}

.insight-list {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--space-md);
  max-width: 900px;
  margin-inline: auto;
}

/* Whole card is one <a>. Flex column so the "Read the guide" row pins to a
   shared baseline no matter how many lines each title/excerpt wraps to. */
.insight-card {
  display: flex;
  flex-direction: column;
  padding: var(--space-lg);
  background: var(--color-bg);
  border-left: 4px solid var(--color-sage);
  border-radius: 0 var(--radius) var(--radius) 0;
  box-shadow: var(--shadow-sm);
  color: var(--color-text);
  transition: transform var(--transition-base), box-shadow var(--transition-base);
}

.insight-card:hover,
.insight-card:focus-visible {
  transform: translateY(-2px);
  box-shadow: var(--shadow-md);
}

.insight-card:focus-visible {
  outline: 2px solid var(--color-sage-deep);
  outline-offset: 3px;
}

.insight-card__kicker {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  font-size: var(--fs-small);
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  text-align: left;
  color: var(--color-sage-deep);
}

/* Small sage diamond — the site's spark motif, distilled. Cleaner than a
   14px star SVG, which reads as a plus sign at that size. */
.insight-card__kicker::before {
  content: "";
  flex-shrink: 0;
  width: 7px;
  height: 7px;
  background: var(--color-sage);
  transform: rotate(45deg);
}

.insight-card__title {
  font-family: var(--font-heading);
  font-size: var(--fs-h3);
  line-height: 1.25;
  text-align: left;
  margin-top: var(--space-sm);
}

.insight-card__excerpt {
  margin-top: var(--space-2xs);
  color: var(--color-text-muted);
  line-height: 1.65;
  flex: 1;
  /* Cards aren't long-form prose — left-align rather than inherit the
     site-wide body{text-align:justify}, which opens loose rivers in a
     narrow 2-3 line card. */
  text-align: left;
  hyphens: none;
}

.insight-card__more {
  margin-top: var(--space-md);
  font-weight: 600;
  text-align: left;
  color: var(--color-sage-deep);
}

.insight-card:hover .insight-card__more,
.insight-card:focus-visible .insight-card__more {
  text-decoration: underline;
}

@media (max-width: 767px) {
  .insight-list {
    grid-template-columns: 1fr;
  }

  .insight-card {
    padding: var(--space-md);
  }
}

/* --- Blog article: long-form prose (replaces the borrowed .legal look) --- */
.article {
  max-width: 68ch;
  margin-inline: auto;
}

.article__back {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2xs);
  font-size: var(--fs-small);
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--color-sage-deep);
  transition: gap var(--transition-fast);
}

.article__back:hover,
.article__back:focus-visible {
  gap: 0.7rem;
  text-decoration: underline;
}

.article__back-icon {
  width: 16px;
  height: 16px;
}

.article__meta {
  margin: var(--space-sm) 0 var(--space-lg);
  padding-bottom: var(--space-sm);
  border-bottom: 1px solid var(--color-border);
  font-size: var(--fs-small);
  color: var(--color-sage-deep);
}

/* First real paragraph after the meta line = standfirst / lead. */
.article > p.article__meta + p {
  font-size: var(--fs-body-lg);
  line-height: 1.7;
  color: var(--color-text);
}

.article h2 {
  font-family: var(--font-heading);
  font-size: var(--fs-h3);
  line-height: 1.3;
  margin-top: 2.75rem;
  /* Guard against inherited body{text-align:justify} (see Base). */
  text-align: left;
}

.article h2::before {
  content: "";
  display: block;
  width: 32px;
  height: 3px;
  margin-bottom: 0.75rem;
  border-radius: 2px;
  background: var(--color-sage);
}

.article p,
.article li {
  line-height: 1.75;
  margin-bottom: 1.1rem;
}

.article ul,
.article ol {
  margin: 0 0 1.5rem;
}

.article ul {
  padding-left: 0;
}

.article ul li {
  position: relative;
  padding-left: 1.6rem;
  margin-bottom: 0.6rem;
  list-style: none;
}

/* Small sage diamond — echoes the site's 12-point spark motif. */
.article ul li::before {
  content: "";
  position: absolute;
  left: 0.2rem;
  top: 0.62em;
  width: 7px;
  height: 7px;
  background: var(--color-sage);
  transform: translateY(-50%) rotate(45deg);
}

.article ol {
  padding-left: 1.3rem;
  list-style: decimal;
}

.article a {
  color: var(--color-sage-deep);
  text-decoration: underline;
  text-underline-offset: 2px;
}

.article a:hover,
.article a:focus-visible {
  text-decoration-thickness: 2px;
}

.article strong {
  font-weight: 600;
}

/* Quiet end-mark, no per-article markup needed. */
.article::after {
  content: "";
  display: block;
  width: 44px;
  height: 3px;
  border-radius: 2px;
  margin: var(--space-lg) auto 0;
  background: var(--color-sage-light);
}

@media (max-width: 767px) {
  .article h2 {
    margin-top: 2.25rem;
  }
}

/* Honeypot — must be invisible to humans but still SUBMITTED by the browser, so
   `display:none` on the input itself is fine here (unlike the skip link, where
   it would break tabbing). Positioned off-canvas rather than hidden so that a
   bot parsing computed styles is less likely to spot it as a trap. */
.honeypot-field {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* ==========================================================================
   Who We Help — homepage audience-pathway cards (client request 2026-08-29).
   Plain info cards, deliberately not links. Same sage line-icon vocabulary
   as .about-principle / .feature-row.
   ========================================================================== */
.who-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--space-md);
  max-width: 900px;
  margin-inline: auto;
}

.who-card {
  padding: var(--space-md);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-bg);
  text-align: left;
}

.who-card__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  margin-bottom: var(--space-sm);
  border-radius: 50%;
  background: var(--color-sage-light);
  color: var(--color-sage-deep);
}

.who-card__icon svg {
  width: 22px;
  height: 22px;
}

.who-card__title {
  font-size: var(--fs-h3);
  margin-bottom: var(--space-2xs);
}

.who-card__text {
  color: var(--color-text-muted);
  text-align: left;
}

@media (max-width: 600px) {
  .who-grid {
    grid-template-columns: 1fr;
  }
}

/* ==========================================================================
   How It Works — condensed four-step summary on the homepage, linking to the
   full how-we-work.html. A lighter treatment than that page's
   .process-timeline (no vine/spark ornament) — just a numbered list.
   ========================================================================== */
.steps {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--space-md);
  max-width: 900px;
  margin: 0 auto var(--space-lg);
  counter-reset: none;
}

.step {
  display: flex;
  gap: var(--space-sm);
  align-items: flex-start;
}

.step__num {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: var(--color-sage-deep);
  color: var(--color-cream);
  font-family: var(--font-heading);
  font-weight: 500;
  font-size: 1.1rem;
}

.step__title {
  font-size: var(--fs-h3);
  margin-bottom: var(--space-2xs);
}

.step__text {
  color: var(--color-text-muted);
  text-align: left;
}

.steps__cta {
  text-align: center;
}

@media (max-width: 640px) {
  .steps {
    grid-template-columns: 1fr;
  }
}
