/* ============================================
   DESIGNWEALTH DESIGN SYSTEM
   Brand Tokens, Typography, Components

   ACCESSIBILITY PASS 1 — 2026-08-16
   Target: WCAG 2.2 AA (4.5:1 text, 3:1 UI), AAA where free.
   Brand colours are unchanged as FILLS. What changed is where
   they are allowed to be used as TEXT. See notes inline.
   ============================================ */

/* ── CSS Custom Properties (Design Tokens) ── */
:root {
  /* Brand Colors — from DesignWealth Style Guide V.1 */
  --color-navy: #1D174B;
  --color-navy-light: #2E2768;
  --color-navy-dark: #140F35;
  --color-blue: #4F7FC0;
  --color-blue-light: #6E96CE;
  --color-teal: #38BAA9;
  --color-teal-light: #5CD4C4;
  --color-teal-dark: #2A9A8C;
  --color-purple: #AB3994;
  --color-grey: #B7B6BB;

  /* ── ACCESSIBLE TEXT VARIANTS OF THE BRAND COLOURS ──
     The brand hues are logo colours. They were never derived for
     use as text, and several of them fail badly in one direction
     while passing in the other. Use these instead of the raw brand
     tokens whenever the colour is applied to a `color:` property.

     Measured contrast (WCAG 2.x):
       --color-teal        #38BAA9  on white 2.40 FAIL  | on navy 6.87 PASS
       --color-teal-text   #17635A  on white 7.07 AAA   | on navy 2.33 — LIGHT BACKGROUNDS ONLY
       --color-purple      #AB3994  on white 5.61 PASS  | on navy 2.93 FAIL
       --color-purple-on-dark #CE7CBE on navy 5.68 PASS | on white 2.90 — DARK BACKGROUNDS ONLY
       --color-blue        #4F7FC0  on white 4.09 FAIL  | on navy 4.02 FAIL
       --color-blue-light  #6E96CE  on navy 5.42 PASS   | on white 3.04 — DARK BACKGROUNDS ONLY
       --color-blue-text   #3A6299  on white 5.74 PASS  — LIGHT BACKGROUNDS ONLY

     Rule of thumb: teal and purple and blue each work on exactly
     one background family. Pick the variant that matches. */
  --color-teal-text: #17635A;        /* teal AS TEXT on white / off-white / light tints */
  --color-purple-on-dark: #CE7CBE;   /* purple AS TEXT or ICON on navy */
  --color-blue-text: #3A6299;        /* blue AS TEXT on white / off-white */


/* ── NEUTRAL RAMP — DERIVED FROM V.1 NEUTRALS ──
   Style Guide V.1 section 3.1 defines the neutral palette as Navy #1D174B,
   White #FFFFFF and Grey #B7B6BB, permits them to be used as tints and shades,
   and says they "should be the default for paragraphs of text."

   The scale this replaces was a stock cool-grey ramp that appears nowhere in
   the guide. Brand grey was used zero times site-wide while off-guide neutrals
   outnumbered brand colours on nine of eleven pages.

   Surfaces, borders and dividers are now tints of Grey #B7B6BB.
   Text is now tints of Navy #1D174B.

   Brand grey is far too light to pass AA as text at any size, so it never
   carries text. Navy tints do, and every step was verified against white,
   off-white, gray-100 and gray-200:
     gray-400  5.83:1 on white, 4.56:1 worst surface   (was 5.13:1)
     gray-500  7.16:1 / 5.60:1
     gray-800  13.61:1 / 10.64:1   body copy          (was 14.68:1)
     border-strong 3.49:1 worst surface, clears the 3:1 UI minimum
   ────────────────────────────────────────────────────────────── */
  /* Neutrals */
  --color-white: #FFFFFF;
  --color-off-white: #F8F8F8;
  --color-gray-100: #F1F0F1;
  --color-gray-200: #E4E3E5;
  --color-gray-300: #D2D2D5;
  /* --color-gray-400 was #9AA3B4 (2.54:1 on white). It had become the
     de-facto colour for disclosures, fee ranges, form hints and legal
     footnotes across the site — i.e. it was illegible in exactly the
     places that matter most. It is now 5.13:1 on white / 4.88:1 on
     off-white / 4.62:1 on gray-100, so it passes AA on every surface
     the site actually uses. The old value is preserved below as
     --color-gray-350 for DECORATIVE use only (never text). */
  --color-gray-400: #656185;
  --color-gray-350: #BEBDC2;  /* decorative only — NEVER use for text */
  --color-gray-500: #58537A;
  --color-gray-600: #4F4A73;
  --color-gray-700: #3D3764;
  --color-gray-800: #2D2758;
  --color-gray-900: #1D174B;

  /* Borders. gray-200 (1.25:1) and gray-300 (1.58:1) are decorative
     only. Anything that must be *perceived* as a boundary — form
     fields, focus rings, controls — needs 3:1 per WCAG 1.4.11. */
  --color-border-strong: #777493;    /* 4.02:1 on white, 3.82:1 on off-white */

  /* Semantic Colors.
     The -500 hues below are FILL colours (banner backgrounds, dots, bars).
     As text on white they all fail: #10B981 = 2.54:1, #F59E0B = 2.15:1,
     #EF4444 = 3.76:1. The amber in particular was being used for review
     stars and for "partial" markers in the comparison table. Use the
     -text variants for anything a person has to read. */
  --color-success: #10B981;
  --color-warning: #F59E0B;
  --color-error: #EF4444;
  --color-success-text: #047857;   /* 5.48:1 on white */
  --color-warning-text: #B45309;   /* 5.02:1 on white — still reads as gold/amber */
  --color-error-text: #B91C1C;     /* 6.47:1 on white */

  /* Typography — from DesignWealth Style Guide V.1 */
  --font-heading: 'Libre Franklin', -apple-system, BlinkMacSystemFont, sans-serif;
  --font-subhead: 'Nunito Sans', 'Avenir', -apple-system, BlinkMacSystemFont, sans-serif;
  --font-body: 'Nunito Sans', 'Avenir', -apple-system, BlinkMacSystemFont, sans-serif;

  /* ── Font Sizes ──
     PASS 2 RESCALE. The old scale had a 16px body that almost nothing used;
     running prose had drifted to 14px and every disclosure to 12px, so legal
     weight and legibility were inversely correlated across the site.

     The scale now has a floor. Nothing renders below 14px, and 14px is
     reserved for genuine LABELS — one to three words that name a thing.
     Anything a person reads for meaning, including fee disclosures and
     regulatory text, is --text-base or larger.

     These three tokens are deliberately NOT reduced at any breakpoint.
     Body copy does not shrink on phones. */
  --text-xs: 0.875rem;    /* 14px — DEPRECATED ALIAS of --text-sm. Was 12px.
                             Kept only so legacy rules resolve at a legible
                             size; do not use it in new work. */
  --text-sm: 0.875rem;    /* 14px — LABELS ONLY: nav items, badges, eyebrows,
                             tags, column headings, meta. Never running prose. */
  --text-base: 1.0625rem; /* 17px — BODY. Paragraphs, list items, table cells,
                             excerpts, AND all disclosure / legal / fee text. */
  --text-lg: 1.1875rem;   /* 19px — lead paragraphs and intros */
  --text-nav: 1rem;       /* 16px — navigation and global chrome. One step
                             below body on purpose; see .nav__link. */
  --text-xl: 1.25rem;     /* 20px */
  --text-2xl: 1.5rem;     /* 24px */
  --text-3xl: 1.875rem;   /* 30px */
  --text-4xl: 2.25rem;    /* 36px */
  --text-5xl: 3rem;       /* 48px */
  --text-6xl: 3.75rem;    /* 60px */
  --text-7xl: 4.5rem;     /* 72px */

  /* Line Heights.
     --leading-normal was 1.5, the WCAG floor rather than a comfortable
     value, and it was what every unstyled paragraph inherited. Prose now
     sits at 1.6 by default and 1.7 where it runs long.
     --leading-snug (1.3) is for HEADINGS ONLY — it was being applied to
     wrapping 14px labels and job titles. */
  --leading-none: 1;
  --leading-tight: 1.15;
  --leading-snug: 1.3;
  --leading-normal: 1.6;
  --leading-relaxed: 1.7;
  --leading-loose: 1.85;

  /* Line length. Prose past ~75 characters is hard to track back from the
     end of one line to the start of the next; under ~45 it fragments.
     Several card descriptions were constrained to 110–260px, i.e. roughly
     15–35 characters. Use this on any long-form text container. */
  --measure-body: 68ch;

  /* Letter Spacing */
  --tracking-tight: -0.025em;
  --tracking-normal: 0;
  --tracking-wide: 0.05em;
  --tracking-wider: 0.1em;

  /* Alpha floor for white text on navy. Composited against --color-navy:
       0.60 = 6.62:1 PASS   0.55 = 5.79:1 PASS   0.50 = 5.00:1 PASS
       0.45 = 4.31:1 FAIL   0.40 = 3.69:1 FAIL   0.30 = 2.65:1 FAIL
     Never set white text below 0.6 on a navy surface. */
  --alpha-text-on-dark: 0.6;

  /* Spacing Scale */
  --space-1: 0.25rem;    /* 4px */
  --space-2: 0.5rem;     /* 8px */
  --space-3: 0.75rem;    /* 12px */
  --space-4: 1rem;       /* 16px */
  --space-5: 1.25rem;    /* 20px */
  --space-6: 1.5rem;     /* 24px */
  --space-8: 2rem;       /* 32px */
  --space-10: 2.5rem;    /* 40px */
  --space-12: 3rem;      /* 48px */
  --space-16: 4rem;      /* 64px */
  --space-20: 5rem;      /* 80px */
  --space-24: 6rem;      /* 96px */
  --space-32: 8rem;      /* 128px */

  /* Border Radius */
  --radius-sm: 0.25rem;
  --radius-md: 0.5rem;
  --radius-lg: 0.75rem;
  --radius-xl: 1rem;
  --radius-2xl: 1.5rem;
  --radius-full: 9999px;

  /* Shadows */
  --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05);
  --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.07), 0 2px 4px -1px rgba(0, 0, 0, 0.04);
  --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.08), 0 4px 6px -2px rgba(0, 0, 0, 0.04);
  --shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.08), 0 10px 10px -5px rgba(0, 0, 0, 0.03);
  --shadow-2xl: 0 25px 50px -12px rgba(0, 0, 0, 0.15);
  --shadow-card: 0 0 0 1px rgba(0, 0, 0, 0.03), 0 2px 4px rgba(0, 0, 0, 0.05), 0 12px 24px rgba(0, 0, 0, 0.05);

  /* Transitions */
  --transition-fast: 150ms ease;
  --transition-base: 250ms ease;
  --transition-slow: 350ms ease;

  /* Layout */
  --container-max: 1280px;
  --container-narrow: 960px;
  --container-wide: 1440px;
  --nav-height: 80px;
}

/* ── Google Fonts Import ── */
@import url('https://fonts.googleapis.com/css2?family=Libre+Franklin:ital,wght@0,300;0,400;0,500;0,600;0,700;1,300;1,400&family=Nunito+Sans:ital,opsz,wght@0,6..12,300;0,6..12,400;0,6..12,500;0,6..12,600;0,6..12,700;0,6..12,800;1,6..12,400&display=swap');

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

html {
  font-size: 16px;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  scroll-behavior: smooth;
}

body {
  font-family: var(--font-body);
  font-size: var(--text-base);
  line-height: var(--leading-normal);
  color: var(--color-gray-800);
  background: var(--color-white);
}

img {
  max-width: 100%;
  height: auto;
  display: block;
}

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

/* ── Typography Classes ── */
h1, h2, h3, h4, h5, h6,
.h1, .h2, .h3, .h4, .h5, .h6 {
  font-family: var(--font-heading);
  font-weight: var(--weight-heading, 400);
  line-height: var(--leading-tight);
  color: var(--color-navy);
}

/* ── TYPOGRAPHY PASS — HEADING WEIGHT RAMP ──
   Style Guide V.1 section 4.1 specifies Libre Franklin Light for headlines,
   with bold reserved for headlines "close in size to the body copy." That is
   not an exception, it is a statement that weight runs inverse to size. This
   block implements that relationship rather than collapsing it to one number.

   Weight is keyed to RENDERED size, not semantic level, because the scale
   shrinks at every breakpoint. An h2 at 48px desktop takes 300; the same h2
   at 30px on a phone takes 400. Without the breakpoint rules below, Light
   looks correct on a monitor and fragile on the device most traffic uses.

   Thresholds:
     >= 44px  300 Light      display voice, the guide's identity
     >= 28px  400 Regular
     >= 22px  500 Medium
     <  22px  600 SemiBold   the guide's "close to body copy" case (body 17px)

   Weight is NOT a WCAG criterion. Contrast is computed from colour alone, so
   Light costs nothing in conformance. The ramp exists for legibility at small
   sizes, which is a usability concern, not a compliance one. */

h1, .h1 { --weight-heading: 300; }   /* 60px */
h2, .h2 { --weight-heading: 300; }   /* 48px */
h3, .h3 { --weight-heading: 400; }   /* 36px */
h4, .h4 { --weight-heading: 500; }   /* 24px */
h5, .h5 { --weight-heading: 600; }   /* 20px */
h6, .h6 { --weight-heading: 600; }   /* 19px */

/* Light text on a dark field reads thinner than the same weight on white.
   The effect is real but scales with size: at 48px and above the strokes are
   heavy enough that 300 holds, and lifting the hero to 400 would surrender
   Light exactly where the guide most wants it. So NO bump at display sizes.
   Below ~36px the thinning does bite, so h3 and smaller take one step up on
   navy. The breakpoint rules further down already handle the rest. */
.hero h3, .hero .h3,
.final-cta h3, .final-cta .h3,
.on-navy h3, .on-navy .h3 {
  --weight-heading: 500;
}

/* Display numerals are data, not headlines. The ramp would drop them to 400
   at 30-36px where they stop reading as figures. Deliberate carve-out. */
.hero__stat-number, .roi-card__number,
.testimonials-stat__number, .stat__number {
  --weight-heading: 700;
}

/* Negative tracking is an optical correction for display sizes. Applied
   below ~30px it closes counters and costs legibility, and the blanket
   h1–h6 rule was pushing it onto 16px and 18px subheads that pages had
   resized down. It is now scoped to the display headings only. */
h1, h2, .h1, .h2 {
  letter-spacing: var(--tracking-tight);
}

h3, h4, h5, h6,
.h3, .h4, .h5, .h6 {
  letter-spacing: var(--tracking-normal);
}

h1, .h1 { font-size: var(--text-6xl); }
h2, .h2 { font-size: var(--text-5xl); }
h3, .h3 { font-size: var(--text-4xl); }
h4, .h4 { font-size: var(--text-2xl); }
h5, .h5 { font-size: var(--text-xl); }
h6, .h6 { font-size: var(--text-lg); }

.text-body-lg {
  font-size: var(--text-lg);
  line-height: var(--leading-relaxed);
}

.text-body {
  font-size: var(--text-base);
  line-height: var(--leading-normal);
}

/* 14px, for LABELS. Not a smaller body style — do not set paragraphs in it. */
.text-body-sm {
  font-size: var(--text-sm);
  line-height: var(--leading-normal);
}

/* Long-form prose container. Caps the measure and gives generous leading. */
.prose {
  font-size: var(--text-base);
  line-height: var(--leading-relaxed);
  max-width: var(--measure-body);
}

/* Disclosure / legal / fee text. Deliberately the SAME size as body copy.
   It is muted by colour, not by size — muted-but-legible (5.13:1) rather
   than small-and-illegible. Apply to MER notes, fee bounds, clawback terms,
   regulatory statements, and compliance footnotes. */
.disclosure {
  font-size: var(--text-base);
  line-height: var(--leading-relaxed);
  color: var(--color-gray-400);
}

/* .eyebrow appears on nearly every section of every page. At 14px it is
   normal-size text and needs 4.5:1. Raw --color-teal gave 2.40:1 on white
   and 2.28:1 on off-white. On navy surfaces, override back to
   --color-teal (6.87:1) — see .eyebrow--on-dark below. */
.eyebrow {
  font-family: var(--font-body);
  font-size: var(--text-sm);
  font-weight: 600;
  letter-spacing: var(--tracking-wider);
  text-transform: uppercase;
  color: var(--color-teal-text);
}

/* Use on navy / dark sections, where --color-teal-text would be too dark. */
.eyebrow--on-dark {
  color: var(--color-teal);
}

/* ── Layout ── */
.container {
  width: 100%;
  max-width: var(--container-max);
  margin: 0 auto;
  padding: 0 var(--space-6);
}

.container--narrow {
  max-width: var(--container-narrow);
}

.container--wide {
  max-width: var(--container-wide);
}

.section {
  padding: var(--space-24) 0;
}

.section--sm {
  padding: var(--space-16) 0;
}

.section--lg {
  padding: var(--space-32) 0;
}

/* ── Button Components ── */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  font-family: var(--font-body);
  font-size: var(--text-base);
  font-weight: 600;
  line-height: 1;
  padding: var(--space-4) var(--space-8);
  border: 2px solid transparent;
  border-radius: var(--radius-lg);
  cursor: pointer;
  transition: all var(--transition-base);
  text-decoration: none;
  white-space: nowrap;
}

/* PRIMARY CTA. Previously white on teal = 2.40:1 — the single most
   repeated failure on the site, on every conversion button.
   Navy on the SAME unmodified brand teal = 6.87:1 (AA, and AAA at
   large sizes). The brand fill is untouched; only the label changed. */
.btn--primary {
  background: var(--color-teal);
  color: var(--color-navy);
  border-color: var(--color-teal);
}

.btn--primary:hover {
  background: var(--color-teal-dark);   /* navy on teal-dark = 4.78:1 */
  border-color: var(--color-teal-dark);
  color: var(--color-navy);
  transform: translateY(-1px);
  box-shadow: var(--shadow-lg);
}

.btn--secondary {
  background: transparent;
  color: var(--color-navy);
  border-color: var(--color-navy);
}

.btn--secondary:hover {
  background: var(--color-navy);
  color: var(--color-white);
  transform: translateY(-1px);
}

.btn--white {
  background: var(--color-white);
  color: var(--color-navy);
  border-color: var(--color-white);
}

.btn--white:hover {
  background: var(--color-off-white);
  transform: translateY(-1px);
  box-shadow: var(--shadow-lg);
}

/* Ghost button border was rgba(255,255,255,0.3) = 2.65:1 on navy, below
   the 3:1 minimum for a control boundary. 0.5 = 5.00:1. */
.btn--ghost {
  background: transparent;
  color: var(--color-white);
  border-color: rgba(255, 255, 255, 0.5);
}

.btn--ghost:hover {
  background: rgba(255, 255, 255, 0.1);
  border-color: rgba(255, 255, 255, 0.8);
}

.btn--lg {
  font-size: var(--text-lg);
  padding: var(--space-5) var(--space-10);
}

/* Was 14px with 12px padding = a 42px control, and it is the persistent nav
   CTA on every page. 16px with 16px padding and line-height:1 lands at
   exactly 44px, the Apple/Google minimum. */
.btn--sm {
  font-size: var(--text-nav);
  padding: var(--space-4) var(--space-5);
}

.btn--icon-right svg,
.btn--icon-right .icon {
  margin-left: var(--space-2);
  transition: transform var(--transition-fast);
}

.btn--icon-right:hover svg,
.btn--icon-right:hover .icon {
  transform: translateX(3px);
}

/* ── Card Components ── */
.card {
  background: var(--color-white);
  border-radius: var(--radius-xl);
  padding: var(--space-8);
  box-shadow: var(--shadow-card);
  transition: all var(--transition-base);
}

.card:hover {
  transform: translateY(-4px);
  box-shadow: var(--shadow-xl);
}

.card--bordered {
  border: 1px solid var(--color-gray-200);
  box-shadow: none;
}

.card--bordered:hover {
  border-color: var(--color-teal-text);
  box-shadow: var(--shadow-md);
}

/* ── Badge / Tag ── */
/* Text sits on a 10% teal tint that composites to #EBF8F6. teal-dark on
   that was 3.16:1; teal-text is 6.50:1. */
.badge {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  padding: var(--space-1) var(--space-3);
  border-radius: var(--radius-full);
  background: rgba(56, 186, 169, 0.1);
  color: var(--color-teal-text);
}

.badge--navy {
  background: rgba(27, 20, 68, 0.08);
  color: var(--color-navy);
}

/* ── Trust Bar ── */
.trust-bar {
  display: flex;
  align-items: center;
  gap: var(--space-6);
  flex-wrap: wrap;
}

.trust-item {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--text-sm);
  color: var(--color-gray-500);
}

/* Icon was raw teal on white = 2.40:1, under the 3:1 non-text minimum. */
.trust-item svg {
  width: 16px;
  height: 16px;
  color: var(--color-teal-text);
}

/* ── Navigation ── */
.nav {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 1000;
  background: rgba(255, 255, 255, 0.95);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  border-bottom: 1px solid rgba(0, 0, 0, 0.05);
  height: var(--nav-height);
}

.nav__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  height: 100%;
  max-width: var(--container-wide);
  margin: 0 auto;
  padding: 0 var(--space-6);
}

.nav__logo {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  font-family: var(--font-heading);
  font-size: var(--text-xl);
  font-weight: 700;
  color: var(--color-navy);
  /* Must be allowed to shrink, or it pushes the rest of the bar out of the
     viewport on narrow screens. */
  min-width: 0;
  flex-shrink: 1;
}

.nav__logo img {
  max-width: 100%;
  height: auto;
}

.nav__logo-icon {
  width: 40px;
  height: 40px;
  background: linear-gradient(135deg, var(--color-teal), var(--color-blue));
  border-radius: var(--radius-lg);
  display: flex;
  align-items: center;
  justify-content: center;
}

.nav__links {
  display: flex;
  align-items: center;
  gap: var(--space-1);
  list-style: none;
}

/* PASS 3A. Nav links were 14px/500 with 8px vertical padding — a ~38px
   target, and after the Pass 2 body rescale they were the only text on the
   page SMALLER than body copy, which read as subordinate to the content.
   Now 16px/600: a 50px target, and a deliberate one-step drop from the 17px
   body so the chrome reads as chrome without receding. 16px rather than 17px
   is load-bearing — at 17px the five links plus logo and CTA exceed 1024px
   and the bar breaks before its own breakpoint.
   inline-flex is also load-bearing: an <a> is inline by default, so its box height
   comes from the font's content area and vertical padding does NOT produce a
   real hit target. Measured at 41px as a plain inline element; 50px as
   inline-flex. Only the Services link passed before, and only because its
   dropdown modifier already set display:flex. */
.nav__link {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  font-size: var(--text-nav);
  font-weight: 600;
  color: var(--color-gray-600);
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-md);
  transition: all var(--transition-fast);
}

.nav__link:focus-visible {
  outline: 2px solid var(--color-teal-text);
  outline-offset: 2px;
}

.nav__link:hover {
  color: var(--color-navy);
  background: var(--color-gray-100);
}

.nav__link--has-dropdown {
  display: flex;
  align-items: center;
  gap: var(--space-1);
}

.nav__actions {
  display: flex;
  align-items: center;
  gap: var(--space-3);
}

.nav__cta {
  font-size: var(--text-sm);
}

/* Mobile Nav Toggle.
   Was ~32x40px. Now a true 48x48 target. This button was previously inert on
   every page — the drawer it is supposed to open did not exist. See
   .nav__drawer below and the nav-drawer script that must be on every page. */
.nav__toggle {
  display: none;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 5px;
  width: 48px;
  height: 48px;
  /* It is a flex item inside .nav__inner and was shrinking to the 24px width
     of its own bars — measured 24x48 before this. */
  flex: 0 0 48px;
  min-width: 48px;
  padding: 0;
  background: none;
  border: none;
  border-radius: var(--radius-md);
  cursor: pointer;
}

.nav__toggle:hover {
  background: var(--color-gray-100);
}

.nav__toggle:focus-visible {
  outline: 2px solid var(--color-teal-text);
  outline-offset: 2px;
}

.nav__toggle span {
  display: block;
  width: 24px;
  height: 2px;
  background: var(--color-navy);
  border-radius: 2px;
  transition: all var(--transition-fast);
}

/* ── Mobile Navigation Drawer ──
   Below 1024px .nav__links is hidden and .nav__toggle appears. Before this
   pass the toggle had no handler and no drawer markup on any page, so the
   entire site navigation was unreachable on every phone and every tablet,
   including iPad in landscape (exactly 1024px). Every page must now include
   the .nav__drawer markup block and the nav-drawer script. */
.nav__drawer {
  position: fixed;
  inset: 0;
  z-index: 1100;
  background: var(--color-white);
  display: none;
  flex-direction: column;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
  padding: 0 var(--space-6) var(--space-8);
}

.nav__drawer[data-open="true"] {
  display: flex;
}

body.is-nav-open {
  overflow: hidden;
}

.nav__drawer-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  min-height: var(--nav-height);
  position: sticky;
  top: 0;
  background: var(--color-white);
  border-bottom: 1px solid var(--color-gray-200);
  margin: 0 calc(var(--space-6) * -1) var(--space-4);
  padding: 0 var(--space-6);
}

.nav__drawer-close {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  flex-shrink: 0;
  background: none;
  border: none;
  border-radius: var(--radius-md);
  color: var(--color-navy);
  font-size: var(--text-2xl);
  line-height: 1;
  cursor: pointer;
}

.nav__drawer-close:hover {
  background: var(--color-gray-100);
}

.nav__drawer-close:focus-visible,
.nav__drawer a:focus-visible {
  outline: 2px solid var(--color-teal-text);
  outline-offset: 2px;
}

.nav__drawer-group {
  border-bottom: 1px solid var(--color-gray-200);
  padding: var(--space-2) 0;
}

.nav__drawer-group:last-of-type {
  border-bottom: none;
}

.nav__drawer-title {
  font-family: var(--font-body);
  font-size: var(--text-sm);
  font-weight: 700;
  letter-spacing: var(--tracking-wider);
  text-transform: uppercase;
  color: var(--color-gray-400);
  padding: var(--space-4) 0 var(--space-2);
}

/* 56px targets, comfortably above the 44px minimum, because these are the
   primary navigation on a device held in one hand. */
.nav__drawer a {
  display: flex;
  align-items: center;
  min-height: 56px;
  padding: var(--space-3) 0;
  font-size: var(--text-lg);
  font-weight: 600;
  color: var(--color-navy);
  border-radius: var(--radius-md);
}

.nav__drawer a:hover {
  color: var(--color-teal-text);
}

.nav__drawer a.nav__drawer-sub {
  font-size: var(--text-base);
  font-weight: 500;
  color: var(--color-gray-600);
  padding-left: var(--space-4);
}

/* Sticky so the primary conversion action stays reachable without scrolling
   the drawer — at 390x844 the link list alone runs past the fold. */
.nav__drawer-cta {
  position: sticky;
  bottom: 0;
  margin-top: auto;
  padding: var(--space-4) 0 var(--space-2);
  background: var(--color-white);
  box-shadow: 0 -12px 16px -8px rgba(0, 0, 0, 0.08);
}

.nav__drawer-cta .btn {
  width: 100%;
  white-space: normal;
  text-align: center;
}

.nav__drawer-contact {
  margin-top: var(--space-6);
  font-size: var(--text-base);
  color: var(--color-gray-500);
}

.nav__drawer-contact a {
  min-height: 48px;
  font-size: var(--text-base);
  font-weight: 600;
  color: var(--color-teal-text);
}

/* The drawer is only ever a mobile/tablet affordance. Force it shut above the
   breakpoint so a stale data-open cannot leak onto desktop after a resize. */
@media (min-width: 1025px) {
  .nav__drawer[data-open="true"] {
    display: none;
  }
}

/* ── Responsive ──
   NOTE: the page-level stylesheets historically broke at 767px while this
   file breaks at 768px, leaving a 1px band where the type tokens went
   mobile but the layout stayed tablet. Page files are now aligned to 768. */
@media (max-width: 1024px) {
  :root {
    --text-6xl: 2.75rem;
    --text-5xl: 2.25rem;
    --text-4xl: 1.875rem;
  }

  .section {
    padding: var(--space-16) 0;
  }

  .section--lg {
    padding: var(--space-20) 0;
  }

  .nav__links {
    display: none;
  }

  .nav__toggle {
    display: flex;
  }
}

/* MEASURED BUG, all 11 pages: at 390px the bar tried to fit the logo (~250px
   after its 64vw cap) + the full CTA button (~200px) + the 48px hamburger +
   32px of container padding = ~460px inside 390px. The hamburger was pushed
   clean off the right edge, so on a phone the menu button was not merely
   small — it was unreachable. Below 700px the persistent CTA is dropped; the
   drawer carries its own sticky "Book Your Complimentary Consultation" button,
   so no conversion path is lost. */
@media (max-width: 700px) {
  .nav__actions {
    display: none;
  }
}

@media (max-width: 768px) {
  :root {
    --text-6xl: 2.25rem;
    --text-5xl: 1.875rem;
    --text-4xl: 1.5rem;
    --text-3xl: 1.375rem;
    --nav-height: 68px;
  }

  .container {
    padding: 0 var(--space-4);
  }

  .section {
    padding: var(--space-12) 0;
  }

  .section--lg {
    padding: var(--space-16) 0;
  }

  .btn--lg {
    font-size: var(--text-base);
    padding: var(--space-4) var(--space-8);
    width: 100%;
  }
}

@media (max-width: 480px) {
  :root {
    --text-6xl: 1.875rem;
    --text-5xl: 1.625rem;
    /* --text-4xl was 1.375rem (22px), which made h3 SMALLER than the
       unscaled h4 (24px) and inverted the heading hierarchy. Held at
       1.5rem so h3 >= h4 at every breakpoint. */
    --text-4xl: 1.5rem;
  }
}

/* ── Credibility Logo Bars ──
   Reusable component for "As Seen In", "Member Of", and "Awards" rows.
   Uniform-height, aspect-preserving, grayscale-by-default for press/memberships,
   full-color for awards. Wraps cleanly on small screens without breaking rows. */

.credibility-section {
  padding: var(--space-16) 0;
  background: var(--color-off-white);
}

.credibility-section--white {
  background: var(--color-white);
}

.credibility-section--navy {
  background: var(--color-navy);
}

/* was rgba(255,255,255,0.55) = 5.79:1 — passing, but this is 12px text,
   so it is lifted to the 0.6 floor for consistency with every other
   white-on-navy label. */
.credibility-section--navy .credibility-section__label {
  color: rgba(255, 255, 255, 0.6);
}

.credibility-section__label {
  font-family: var(--font-body);
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: var(--tracking-wider);
  text-transform: uppercase;
  color: var(--color-gray-500);
  text-align: center;
  margin-bottom: var(--space-8);
}

.credibility-group {
  margin-bottom: var(--space-12);
}

.credibility-group:last-child {
  margin-bottom: 0;
}

.logo-bar {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-12);
  flex-wrap: wrap;
  list-style: none;
}

.logo-bar__item {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

.logo-bar__img {
  display: block;
  max-width: 100%;
  width: auto;
  object-fit: contain;
  transition: all var(--transition-base);
}

/* Press variant — grayscale, hover-to-color */
.logo-bar--press .logo-bar__img {
  height: 78px;
  filter: grayscale(100%);
  opacity: 0.85;
}

.logo-bar--press .logo-bar__img:hover {
  filter: grayscale(0%);
  opacity: 1;
}

/* On dark backgrounds — apply via .credibility-section--navy OR .logo-bar--on-dark */
.credibility-section--navy .logo-bar--press .logo-bar__img,
.credibility-section--navy .logo-bar--members .logo-bar__img,
.logo-bar--on-dark.logo-bar--press .logo-bar__img,
.logo-bar--on-dark.logo-bar--members .logo-bar__img {
  filter: grayscale(100%) brightness(0) invert(1);
  opacity: 0.75;
}

.credibility-section--navy .logo-bar--press .logo-bar__img:hover,
.credibility-section--navy .logo-bar--members .logo-bar__img:hover,
.logo-bar--on-dark.logo-bar--press .logo-bar__img:hover,
.logo-bar--on-dark.logo-bar--members .logo-bar__img:hover {
  opacity: 0.9;
}

/* Memberships variant — slightly taller, similar treatment */
.logo-bar--members .logo-bar__img {
  height: 68px;
  filter: grayscale(100%);
  opacity: 0.85;
}

.logo-bar--members .logo-bar__img:hover {
  filter: grayscale(0%);
  opacity: 1;
}

/* When membership logos sit on a dark background, give each one a white card
   backdrop. We don't try to invert the JPGs (their white backgrounds would
   collapse the logo into a solid block). Cards keep the brand colors intact
   and read as professional credentials rather than monochrome decoration. */
/* Each membership mark gets an identical box and fills it via object-fit,
   rather than being constrained by height alone. These logos have very
   different aspect ratios, so height-only sizing renders the wide ones
   (chambers, wordmarks) far smaller in area than the square ones. The source
   files also carry baked-in whitespace, so the box has to be generous. */
.logo-bar--on-dark.logo-bar--members .logo-bar__item {
  background: #fff;
  border-radius: var(--radius-lg);
  width: 232px;
  height: 132px;
  padding: var(--space-5) var(--space-6);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.18);
  transition: transform var(--transition-base);
}
.logo-bar--on-dark.logo-bar--members .logo-bar__item:hover {
  transform: translateY(-2px);
}
.logo-bar--on-dark.logo-bar--members .logo-bar__img {
  filter: none;
  opacity: 1;
  width: 100%;
  height: 100%;
  max-width: none;
  object-fit: contain;
}

/* Awards variant — full color, larger badges */
.logo-bar--awards {
  gap: var(--space-10);
}

.logo-bar--awards .logo-bar__img {
  height: 140px;
}

.logo-bar--awards .logo-bar__img:hover {
  transform: scale(1.04);
}

/* Tablet adjustments */
@media (max-width: 1024px) {
  .logo-bar { gap: var(--space-8); }
  .logo-bar--press .logo-bar__img { height: 66px; }
  .logo-bar--members .logo-bar__img { height: 58px; }
  .logo-bar--awards .logo-bar__img { height: 118px; }
  .logo-bar--on-dark.logo-bar--members .logo-bar__item { width: 196px; height: 116px; }
}

/* Mobile — keep proportions but tighten spacing */
@media (max-width: 768px) {
  .credibility-section { padding: var(--space-12) 0; }
  .logo-bar { gap: var(--space-6); }
  .logo-bar--press .logo-bar__img { height: 56px; }
  .logo-bar--members .logo-bar__img { height: 50px; }
  .logo-bar--awards .logo-bar__img { height: 100px; }
  .logo-bar--on-dark.logo-bar--members .logo-bar__item { width: 168px; height: 100px; }
  .credibility-group { margin-bottom: var(--space-8); }
}

/* ============================================
   PASS 3B — INTERACTION CORRECTNESS
   Components below replace affordances that looked interactive but were not:
   FAQ rows that were <div>s with cursor:pointer and no handler, category
   "tabs" that filtered nothing, and a form whose labels were not attached to
   its inputs. Everything here is keyboard-operable and screen-reader-legible.
   ============================================ */

/* ── Utility ── */

/* Available to assistive tech, invisible on screen. Use for form labels that
   the visual design expresses some other way — never to hide a label entirely. */
.visually-hidden {
  position: absolute !important;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* One focus treatment for everything, at 3:1 against both light and dark. */
.btn:focus-visible,
.faq-item__q:focus-visible,
.category-tab:focus-visible,
.form-group input:focus-visible,
.form-group select:focus-visible,
.form-group textarea:focus-visible,
.search-bar input:focus-visible {
  outline: 3px solid var(--color-teal-text);
  outline-offset: 2px;
}

.final-cta .btn:focus-visible,
.hero .btn:focus-visible,
.nav__drawer .btn:focus-visible {
  outline-color: var(--color-teal);
}

/* ── FAQ Accordion ──
   The markup ships with every answer visible and the trigger as a plain
   element, so with JavaScript disabled the page is a readable FAQ — no
   content is ever hidden behind a script. The enhancement script upgrades
   each trigger to a real <button>, which is why these rules are typed on
   `button.` — that beats the page-level `.faq-item__q` rules on specificity
   and undoes the UA button styling without disturbing each page's own
   typography. */
/* The typography reset is wrapped in :where() so it carries ZERO specificity.
   It beats the UA button stylesheet (which every author rule does) but LOSES
   to each page's own `.faq-item__q` rule at (0,1,0) — so the question keeps
   the heading font the page gave it. Written as plain `button.faq-item__q`
   this reset measured (0,1,1), outranked the page, and silently downgraded
   every question from Libre Franklin 19px/500 navy to Nunito Sans 17px/400
   grey the moment the script ran. */
:where(button.faq-item__q) {
  font-family: inherit;
  font-size: inherit;
  font-weight: inherit;
  line-height: inherit;
  color: inherit;
}

button.faq-item__q {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  width: 100%;
  min-height: 44px;
  margin: 0;
  padding-left: 0;
  padding-right: 0;
  text-align: left;
  background: none;
  border: none;
  border-radius: var(--radius-md);
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
}

button.faq-item__q svg {
  flex-shrink: 0;
  transition: transform var(--transition-base);
}

button.faq-item__q[aria-expanded="false"] svg {
  transform: rotate(-90deg);
}

.faq-item__a[hidden] {
  display: none;
}

@media (prefers-reduced-motion: reduce) {
  button.faq-item__q svg {
    transition: none;
  }
}

/* ── Tablist (Resources categories) ──
   Was seven <div>s with cursor:pointer, no roles, no keyboard access, and no
   filtering behind them. Now a real tablist driving the article grid. */
button.category-tab {
  font-family: inherit;
  background: none;
  border: none;
  border-bottom: 2px solid transparent;
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
  min-height: 44px;
  white-space: nowrap;
}

button.category-tab[aria-selected="true"] {
  color: var(--color-teal-text);
  border-bottom-color: var(--color-teal-text);
  font-weight: 700;
}

/* The tab row scrolls horizontally on small screens; without this the last
   tabs are simply unreachable with no indication they exist. */
.category-tabs__inner {
  scrollbar-width: thin;
}

.blog-card[hidden],
.featured-post[hidden] {
  display: none;
}

.resources-empty {
  padding: var(--space-12) 0;
  text-align: center;
  font-size: var(--text-lg);
  color: var(--color-gray-500);
}

/* ── Accessible form fields ── */

/* The resting border was #E2E6EE at 1.25:1 — the field boundary was
   effectively invisible before focus. --color-border-strong is 4.02:1. */
.form-group input,
.form-group select,
.form-group textarea {
  border-color: var(--color-border-strong);
}

.form-group label .required {
  color: var(--color-error-text);
  margin-left: 2px;
}

.form-group .field-hint {
  display: block;
  margin-top: var(--space-1);
  font-size: var(--text-base);
  color: var(--color-gray-400);
}

.form-group .field-error {
  display: none;
  align-items: center;
  gap: var(--space-2);
  margin-top: var(--space-2);
  font-size: var(--text-base);
  font-weight: 600;
  color: var(--color-error-text);
}

.form-group[data-invalid="true"] .field-error {
  display: flex;
}

/* Never colour alone — the border weight changes too, so the error is legible
   to someone who cannot distinguish red from grey. */
.form-group[data-invalid="true"] input,
.form-group[data-invalid="true"] select,
.form-group[data-invalid="true"] textarea {
  border-color: var(--color-error-text);
  border-width: 2px;
}

.form-consent {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  margin-bottom: var(--space-6);
}

.form-consent input[type="checkbox"] {
  width: 24px;
  height: 24px;
  min-width: 24px;
  margin-top: 2px;
  accent-color: var(--color-teal-text);
  cursor: pointer;
}

.form-consent label {
  font-size: var(--text-base);
  line-height: var(--leading-relaxed);
  color: var(--color-gray-600);
  cursor: pointer;
}

.form-consent a {
  color: var(--color-teal-text);
  text-decoration: underline;
  font-weight: 600;
}

/* Announced to screen readers on submit failure, and visible to everyone. */
.form-status {
  display: none;
  margin-bottom: var(--space-6);
  padding: var(--space-4) var(--space-5);
  border-radius: var(--radius-lg);
  border-left: 4px solid var(--color-error-text);
  background: #FEF2F2;
  font-size: var(--text-base);
  line-height: var(--leading-relaxed);
  color: var(--color-error-text);
  font-weight: 600;
}

.form-status[data-state="error"] {
  display: block;
}

.form-status[data-state="success"] {
  display: block;
  border-left-color: var(--color-success-text);
  background: #ECFDF5;
  color: var(--color-success-text);
}

/* ── Non-interactive placeholder ──
   For UI that illustrates something not yet wired up. It must not present
   pointer or focus affordances it cannot honour. */
.is-placeholder,
.is-placeholder * {
  cursor: default !important;
  pointer-events: none;
  user-select: none;
}


/* ============================================
   PASS 3C — LAYOUT
   ============================================ */

/* ── The min-width:auto trap ──
   Grid and flex items default to `min-width: auto`, which means an item's
   minimum size is its CONTENT's minimum size. A single unbreakable child then
   forces its track wider than the container, and the whole document scrolls
   sideways. Measured on five pages before this rule:

     .pricing-inner   track 429.75px inside a 358px container  (03 @390)
     .approach-inner  track 361.75px inside a 343px container  (09/10 @375)
     .tier-grid       track 337.28px inside a 288px container  (05 @320)
     .myth-inner      track 308.23px inside a 288px container  (02 @320)
     .hero__inner     388px inside a 320px viewport            (00 @320)

   `min-width: 0` opts each track back into shrinking. Listed explicitly rather
   than applied with a wildcard so it stays greppable and cannot surprise a
   layout that genuinely wants intrinsic sizing. */
.hero__inner > *,
.booking-hero__inner > *,
.pricing-inner > *,
.approach-inner > *,
.myth-inner > *,
.review-inner > *,
.solutions-inner > *,
.mission-inner > *,
.community-inner > *,
.lead-magnet__inner > *,
.tier-grid > *,
.impl-cards > *,
.icp-grid > *,
.steps-grid > *,
.testimonials-grid > *,
.blog-grid > *,
.pillars-grid > *,
.footer__grid > * {
  min-width: 0;
}

/* Replaced elements carry an intrinsic min-content width, so an <img> inside a
   flex or grid container resists shrinking below its natural size even with
   max-width:100%. */
img {
  min-width: 0;
}

/* .btn sets white-space:nowrap so labels never break mid-phrase on desktop.
   Below 768px .btn--lg goes full-width, and "Book Your Complimentary
   Consultation" at 16px needs ~300px plus 64px of padding — 364px inside a
   320px viewport. Allow it to wrap once the button is full-width. */
@media (max-width: 768px) {
  .btn--lg,
  .btn[style*="width:100%"] {
    white-space: normal;
  }
}

/* ── HEADING WEIGHT RAMP: BREAKPOINTS ──
   The scale shrinks at each breakpoint, so the weight ramp follows it down.
   Rendered sizes and the weight each lands on:
     <=1024   h1 44px/300   h2 36px/400   h3 30px/400
     <=768    h1 36px/400   h2 30px/400   h3 24px/500
     <=480    h1 30px/400   h2 26px/500   h3 24px/500 */

@media (max-width: 1024px) {
  h2, .h2 { --weight-heading: 400; }
  h3, .h3 { --weight-heading: 400; }
}

@media (max-width: 768px) {
  h1, .h1 { --weight-heading: 400; }
  h2, .h2 { --weight-heading: 400; }
  h3, .h3 { --weight-heading: 500; }
  /* Negative tracking is a display correction. Below ~30px it closes
     counters, so it comes off entirely at this breakpoint. */
  h1, h2, .h1, .h2 { letter-spacing: var(--tracking-normal); }
}

@media (max-width: 480px) {
  h2, .h2 { --weight-heading: 500; }
  h3, .h3 { --weight-heading: 500; }
}

/* Nunito Sans ships an optical size axis and it is already being loaded.
   Letting the browser drive it adjusts stroke contrast and spacing between
   14px labels and 19px leads at no cost. */
body { font-optical-sizing: auto; }


/* ── TEMPORARILY HIDDEN (Oct 2026) ──────────────────────────────
   data-quiz-hidden    : Certainty Score widget, quiz/assessment CTAs and links.
                         Delete this line to bring them all back once the
                         assessment page exists.
   data-pending-hidden : Terms and Disclosures footer links, until those pages exist. */
[data-quiz-hidden]{display:none !important}
[data-pending-hidden]{display:none !important}
