/* =============================================================================
   components.css — buttons, cards, forms, nav, utility bar, header, footer
   -----------------------------------------------------------------------------
   Everything here consumes semantic aliases from tokens.css. No primitives,
   no off-scale spacing, no hard-coded colors or radii.
   ============================================================================= */


/* -----------------------------------------------------------------------------
   Button
   ----------------------------------------------------------------------------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--jf-space-2);
  padding: var(--jf-space-3) var(--jf-space-5);
  font-family: var(--jf-font-body);
  font-size: var(--jf-size-button);
  font-weight: var(--jf-weight-semibold);
  line-height: 1;
  border: var(--jf-border-width) solid transparent;
  border-radius: var(--jf-radius-button);
  text-decoration: none;
  cursor: pointer;
  transition:
    background-color var(--jf-transition),
    color            var(--jf-transition),
    border-color     var(--jf-transition);
}
.btn:hover { text-decoration: none; }

.btn__arrow {
  display: inline-block;
  transition: transform var(--jf-transition);
}
.btn:hover .btn__arrow { transform: translateX(var(--jf-arrow-shift)); }

.btn--primary {
  background: var(--jf-color-btn-primary-bg);
  color: var(--jf-color-btn-primary-text);
}
.btn--primary:hover { background: var(--jf-color-btn-primary-bg-hover); }

.btn--secondary {
  background: var(--jf-color-btn-secondary-bg);
  color: var(--jf-color-btn-secondary-text);
  border-color: var(--jf-color-btn-secondary-border);
}
.btn--secondary:hover {
  background: var(--jf-color-btn-secondary-border);
  color: var(--jf-color-btn-secondary-bg);
}

.btn--full {
  display: flex;
  width: 100%;
}

.btn:focus-visible {
  outline: 2px solid var(--jf-color-link);
  outline-offset: 2px;
}


/* -----------------------------------------------------------------------------
   Card
   ----------------------------------------------------------------------------- */
.card {
  display: flex;
  flex-direction: column;
  background: var(--jf-color-bg);
  border: var(--jf-border-width) solid var(--jf-color-border);
  border-radius: var(--jf-radius-card);
  padding: var(--jf-space-5);
  transition: border-color var(--jf-transition);
}
.card:hover { border-color: var(--jf-color-border-hover); }

.card__title {
  font-family: var(--jf-font-display);
  font-size: var(--jf-size-card-title);
  line-height: var(--jf-lh-h3);
  font-weight: var(--jf-weight-semibold);
  color: var(--jf-color-heading);
  margin: 0 0 var(--jf-space-3);
}
.card__body {
  margin: 0 0 var(--jf-space-5);
  flex: 1;
}
.card__link {
  align-self: flex-start;
  font-family: var(--jf-font-body);
  font-size: var(--jf-size-nav);
  font-weight: var(--jf-weight-semibold);
  color: var(--jf-color-link);
  display: inline-flex;
  align-items: center;
  gap: var(--jf-space-2);
  text-decoration: none;
}
.card__link:hover { text-decoration: underline; }
.card__link-arrow {
  display: inline-block;
  transition: transform var(--jf-transition);
}
.card__link:hover .card__link-arrow { transform: translateX(var(--jf-arrow-shift)); }


/* -----------------------------------------------------------------------------
   Form field
   ----------------------------------------------------------------------------- */
.field { margin-bottom: var(--jf-space-5); }

.field__label {
  display: block;
  font-family: var(--jf-font-body);
  font-size: var(--jf-size-small);
  font-weight: var(--jf-weight-medium);
  color: var(--jf-color-heading);
  margin-bottom: var(--jf-space-2);
}

.field__input,
.field__textarea,
.field__select {
  display: block;
  width: 100%;
  padding: var(--jf-space-3) var(--jf-space-4);
  font-family: var(--jf-font-body);
  font-size: var(--jf-size-body);
  line-height: var(--jf-lh-small);
  color: var(--jf-color-heading);
  background: var(--jf-color-bg);
  border: var(--jf-border-width) solid var(--jf-color-border);
  border-radius: var(--jf-radius-button);
  transition: border-color var(--jf-transition);
}
.field__input:hover,
.field__textarea:hover,
.field__select:hover {
  border-color: var(--jf-color-border-hover);
}
.field__input::placeholder,
.field__textarea::placeholder {
  /* Was --jf-color-text-muted-large at 17px: 3.36:1, an AA failure on normal
     text that no check caught because the audit does not sample
     ::placeholder. Renaming the token is what made it visible. */
  color: var(--jf-color-text);
}
.field__textarea {
  min-height: var(--jf-space-10);
  resize: vertical;
}
.field__help {
  display: block;
  font-size: var(--jf-size-small);
  color: var(--jf-color-text);
  margin-top: var(--jf-space-2);
}

/* Field focus rings — visible on both light and dark surfaces */
.field__input:focus-visible,
.field__textarea:focus-visible,
.field__select:focus-visible {
  outline: 2px solid var(--jf-color-link);
  outline-offset: 2px;
  border-color: var(--jf-color-link);
}

/* On-dark field variant — navy footer form and future dark bands.
   Field sits on a subtle white overlay so the container is visible without
   competing with the surrounding content. Placeholder at 0.7 opacity gives
   ~8.13:1 contrast on navy-800 (#0E2549) — clears WCAG AAA (7:1). */
.field__input--dark,
.field__textarea--dark {
  color: var(--jf-color-text-on-dark);
  background: color-mix(in srgb, var(--jf-color-text-on-dark) 6%, transparent);
  border-color: color-mix(in srgb, var(--jf-color-text-on-dark) 20%, transparent);
}
.field__input--dark::placeholder,
.field__textarea--dark::placeholder {
  color: var(--jf-color-text-on-dark);
  opacity: 0.7;
}
.field__input--dark:hover,
.field__textarea--dark:hover {
  border-color: color-mix(in srgb, var(--jf-color-text-on-dark) 40%, transparent);
}
.field__input--dark:focus-visible,
.field__textarea--dark:focus-visible {
  outline: 2px solid var(--jf-color-text-on-dark);
  outline-offset: 2px;
  border-color: color-mix(in srgb, var(--jf-color-text-on-dark) 60%, transparent);
  background: color-mix(in srgb, var(--jf-color-text-on-dark) 10%, transparent);
}


/* -----------------------------------------------------------------------------
   Utility — visually hidden but accessible to screen readers
   ----------------------------------------------------------------------------- */
.visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}


/* -----------------------------------------------------------------------------
   Footer newsletter signup

   One email field and a button, side by side on desktop and stacked below
   1024. It reads as a line of the footer rather than as a marketing box —
   which is the point: this is the footer of every page, not a landing page.
   The four-field consultation form that used to live here asked the footer to
   do the contact page's job and put a second "Book a Consultation" button in
   the same viewport as the primary CTA.

   .footer-form__row is retained: nothing uses it today, but it is the two-up
   field row the contact form would want if a second field is ever added here.
   ----------------------------------------------------------------------------- */
.footer-form {
  display: grid;
  gap: 0;   /* .field carries its own bottom margin */
}

.footer-form__row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--jf-space-3);
}
@media (max-width: 480px) {
  .footer-form__row { grid-template-columns: 1fr; }
}
.footer-form .field { margin-bottom: var(--jf-space-3); }
.footer-form .field:last-of-type { margin-bottom: var(--jf-space-4); }

/* Inline variant — input and button share a row, input takes the slack.
   AFTER the base .field rules, not before. `.footer-form--inline .field:last-of-type`
   and `.footer-form .field:last-of-type` are both (0,3,0), so the tie is broken
   by source order alone. With this block above them the field kept its 16px
   bottom margin, the grid row measured 69px, and the stretched button rendered
   145x69 against a 53px field. Same class of bug as the h2 that sat after its
   own media queries: no error, no warning, just the wrong value. */
.footer-form--inline {
  grid-template-columns: 1fr auto;
  /* stretch, not start: the button matches the field's height so the two read
     as one control rather than a button parked beside a box. */
  align-items: stretch;
  gap: var(--jf-space-3);
}
.footer-form--inline .field,
.footer-form--inline .field:last-of-type { margin-bottom: 0; }
.footer-form--inline .btn { white-space: nowrap; }
@media (max-width: 1024px) {
  .footer-form--inline { grid-template-columns: 1fr; }
}

/* The one line under the field: what they get and how often. Small, muted to
   the on-dark body colour, and deliberately not a second heading. */
.footer-form__note {
  margin: var(--jf-space-3) 0 0;
  font-family: var(--jf-font-body);
  font-size: var(--jf-size-small);
  line-height: var(--jf-lh-small);
  color: var(--jf-color-text-on-dark);
  opacity: 0.7;
  max-width: 46ch;
}

/* Primary CTA on the dark footer inverts to white-on-navy so it reads on
   the same navy background. If we introduce a proper "primary on dark"
   variant later, remove this contextual override. */
.footer-form .btn--primary {
  background: var(--jf-color-text-on-dark);
  color: var(--jf-color-heading);
}
.footer-form .btn--primary:hover {
  background: color-mix(in srgb, var(--jf-color-text-on-dark) 88%, transparent);
}


/* -----------------------------------------------------------------------------
   Logo — used in header and footer
   Header: monogram (jf_initial_logo.png) + text lockup (row).
   Footer: text lockup only. The monogram is a navy square with white JF;
   it would disappear into the navy footer, so it's dropped there instead
   of leaning on a reversed raster.
   ----------------------------------------------------------------------------- */
.logo {
  display: inline-flex;
  align-items: center;
  gap: var(--jf-space-3);
  text-decoration: none;
}
.logo:hover { text-decoration: none; }

.logo__monogram {
  display: block;
  flex-shrink: 0;   /* keep the square from being squeezed by the flex row */
  height: 44px;
  width: auto;
}
@media (max-width: 1024px) {
  .logo__monogram { height: 38px; }
}
@media (max-width: 480px) {
  .logo__monogram { height: 34px; }
}

.logo__text {
  display: inline-flex;
  flex-direction: column;
  gap: var(--jf-space-1);
  text-align: left;
  line-height: 1;
}
.logo__name {
  font-family: var(--jf-font-display);
  font-size: var(--jf-size-wordmark);
  font-weight: var(--jf-weight-semibold);
  color: var(--jf-color-heading);
  letter-spacing: var(--jf-tracking-h1);
  line-height: 1.1;
  /* The firm name is a wordmark, not a paragraph. Left wrappable it broke
     word by word into three stacked lines on a phone. Size it to fit
     instead — see the compact-header block below. */
  white-space: nowrap;
}
.logo__tagline {
  font-family: var(--jf-font-body);
  font-size: var(--jf-size-eyebrow);
  font-weight: var(--jf-weight-medium);
  letter-spacing: var(--jf-tracking-eyebrow);
  text-transform: uppercase;
  color: var(--jf-color-text);
}

/* Inverse variant — dark backgrounds (footer today, dark bands later) */
.logo--inverse .logo__name    { color: var(--jf-color-text-on-dark); }
.logo--inverse .logo__tagline { color: var(--jf-color-text-on-dark); opacity: 0.7; }


/* -----------------------------------------------------------------------------
   Utility bar (thin strip above the main header, desktop only)
   ----------------------------------------------------------------------------- */
.utility-bar {
  background: var(--jf-color-bg-dark);
  color: var(--jf-color-text-on-dark);
  font-family: var(--jf-font-body);
  font-size: var(--jf-size-utility);
  overflow: hidden;
  max-height: var(--jf-space-8);   /* 64 — safe overestimate; collapses to 0 on scroll */
  padding-block: var(--jf-space-2);
  transition:
    max-height    var(--jf-transition),
    padding-block var(--jf-transition);
}
.utility-bar__inner {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--jf-space-5);
}
.utility-bar__note {
  color: var(--jf-color-text-on-dark);
  opacity: 0.75;
  font-family: var(--jf-font-body);
  font-size: var(--jf-size-utility);
}
.utility-bar__list {
  display: flex;
  align-items: center;
  margin: 0;
  padding: 0;
  list-style: none;
}
.utility-bar__list li { display: inline-flex; align-items: center; }
.utility-bar__list li + li::before {
  content: '·';
  margin-inline: var(--jf-space-3);
  opacity: 0.5;
  display: inline-block;
}
.utility-bar__link {
  color: var(--jf-color-text-on-dark);
  text-decoration: none;
  opacity: 0.85;
  transition: opacity var(--jf-transition);
}
.utility-bar__link:hover { opacity: 1; text-decoration: underline; }


/* -----------------------------------------------------------------------------
   Main nav
   ----------------------------------------------------------------------------- */
.main-nav {
  display: flex;
  align-items: center;
  gap: var(--jf-space-5);
  margin: 0;
  padding: 0;
  list-style: none;
}
.main-nav > li { flex-shrink: 0; }
.main-nav__link {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: var(--jf-space-1);
  padding-block: var(--jf-space-2);
  font-family: var(--jf-font-body);
  font-size: var(--jf-size-nav);
  font-weight: var(--jf-weight-medium);
  color: var(--jf-color-heading);
  text-decoration: none;
  white-space: nowrap;
  transition: color var(--jf-transition);
}
/* 2px navy underline on hover / active */
.main-nav__link::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 2px;
  background: var(--jf-color-heading);
  transform: scaleX(0);
  transform-origin: center;
  transition: transform var(--jf-transition);
}
.main-nav__link:hover::after,
.main-nav__link[aria-current="page"]::after { transform: scaleX(1); }
.main-nav__link:hover { text-decoration: none; }
.main-nav__caret {
  display: inline-block;
  transition: transform var(--jf-transition);
}


/* -----------------------------------------------------------------------------
   Primary nav dropdowns (Services, Industries)
   Structure:
     <li class="main-nav__item main-nav__item--has-dropdown">
       <a class="main-nav__link" href="…">Label</a>
       <button class="main-nav__toggle" aria-expanded=… aria-controls=…>
         <svg class="main-nav__caret">…</svg>
       </button>
       <ul class="main-nav__dropdown" id="…">…</ul>
     </li>
   The parent <a> is a real link to the section index. The adjacent
   <button> opens/closes the dropdown. On hover-capable pointers the
   dropdown opens on parent hover; on touch/keyboard the button toggles
   aria-expanded and JS reflects it. Both paths share the same show rule.
   ----------------------------------------------------------------------------- */
.main-nav__item { position: relative; }
.main-nav__item--has-dropdown {
  display: inline-flex;
  align-items: center;
  gap: 0;
}
.main-nav__item--has-dropdown > .main-nav__link {
  padding-inline-end: var(--jf-space-1);
}

.main-nav__toggle {
  display: inline-flex;
  align-items: center;
  padding: var(--jf-space-2);
  background: none;
  border: 0;
  cursor: pointer;
  color: var(--jf-color-heading);
  transition: color var(--jf-transition);
}
.main-nav__toggle:hover { color: var(--jf-color-link); }
.main-nav__toggle:focus-visible {
  outline: 2px solid var(--jf-color-link);
  outline-offset: 2px;
}
.main-nav__toggle[aria-expanded="true"] .main-nav__caret {
  transform: rotate(180deg);
}

.main-nav__dropdown {
  position: absolute;
  top: 100%;
  left: 0;
  min-width: 240px;
  padding: var(--jf-space-2) 0;
  margin: 0;
  list-style: none;
  background: var(--jf-color-bg);
  border: var(--jf-border-width) solid var(--jf-color-border);
  border-radius: var(--jf-radius-card);
  box-shadow: 0 8px 24px color-mix(in srgb, var(--jf-color-heading) 10%, transparent);
  opacity: 0;
  visibility: hidden;
  transform: translateY(-4px);
  transition:
    opacity var(--jf-transition),
    transform var(--jf-transition),
    visibility 0s linear var(--jf-transition);
  z-index: 200;
}
/* Hover-capable pointers (desktop): parent hover / focus-within opens */
@media (hover: hover) {
  .main-nav__item--has-dropdown:hover .main-nav__dropdown,
  .main-nav__item--has-dropdown:focus-within .main-nav__dropdown {
    opacity: 1;
    visibility: visible;
    transform: translateY(0);
    transition-delay: 0s;
  }
}
/* Click / keyboard driven state on any device */
.main-nav__toggle[aria-expanded="true"] ~ .main-nav__dropdown {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
  transition-delay: 0s;
}
.main-nav__dropdown a {
  display: block;
  padding: var(--jf-space-3) var(--jf-space-5);
  font-family: var(--jf-font-body);
  font-size: var(--jf-size-nav);
  font-weight: var(--jf-weight-medium);
  color: var(--jf-color-heading);
  text-decoration: none;
  white-space: nowrap;
  transition:
    color            var(--jf-transition),
    background-color var(--jf-transition);
}
.main-nav__dropdown a:hover,
.main-nav__dropdown a:focus-visible {
  color: var(--jf-color-link);
  background: var(--jf-color-bg-alt);
  text-decoration: none;
  outline: 0;
}
.main-nav__dropdown a[aria-current="page"] {
  color: var(--jf-color-link);
  background: var(--jf-color-bg-alt);
}

/* Grouped variant — pillars as headings, their children beneath.

   Two levels in one panel, not a flyout from a flyout. The whole reason is
   that a visitor looking for "IRS representation" should see it in the nav
   without knowing it lives under Tax, and the alternative we had was two tax
   children sitting as siblings of their own parent.

   It is deliberately not a mega-menu: one column, no imagery, no promotional
   panel, no second dropdown level to hover into. AFTER the base
   .main-nav__dropdown rules, so the group-title overrides win the tie on
   source order rather than by accident. */
.main-nav__dropdown--grouped {
  min-width: 264px;
  padding-block: var(--jf-space-3);
  /* Twelve items is 630px. That clears a 900px-tall window and does NOT clear
     a 1366x768 laptop, where the panel would be cut off at the bottom with no
     indication anything was missing. Cap it to the viewport and let it scroll;
     overscroll-behavior stops the page scrolling underneath once it does. */
  max-height: calc(100vh - 9rem);
  overflow-y: auto;
  overscroll-behavior: contain;
}
.main-nav__group + .main-nav__group {
  margin-top: var(--jf-space-2);
  padding-top: var(--jf-space-2);
  border-top: var(--jf-border-width) solid var(--jf-color-border);
}
/* The pillar. Still a link to the section index — a heading a visitor cannot
   click would be worse than no grouping at all. */
.main-nav__dropdown--grouped .main-nav__group-title {
  font-size: var(--jf-size-eyebrow);
  font-weight: var(--jf-weight-semibold);
  letter-spacing: var(--jf-tracking-eyebrow);
  text-transform: uppercase;
  color: var(--jf-color-eyebrow);
  padding-block: var(--jf-space-2);
}
.main-nav__sub {
  list-style: none;
  margin: 0;
  padding: 0;
}
/* Children indent under their pillar and keep the ordinary nav weight, so the
   eye reads heading-then-items rather than two competing levels.

   The vertical padding stays at space-3, matching every other dropdown item.
   Tightening it to space-2 to save panel height made each child a 37px target
   against the 45px of the items above them — a smaller hit area for the
   deeper, harder-to-reach links, which is backwards. The hierarchy is carried
   by the indent and the weight, not by shrinking the target. */
.main-nav__dropdown--grouped .main-nav__sub a {
  padding-left: var(--jf-space-6);
  font-weight: var(--jf-weight-regular);
}


/* -----------------------------------------------------------------------------
   Site header (sticky, condenses on scroll)
   ----------------------------------------------------------------------------- */
.site-header {
  position: sticky;
  top: 0;
  z-index: 100;
  background: var(--jf-color-bg);
}
.main-header {
  border-bottom: var(--jf-border-width) solid var(--jf-color-border);
  transition: padding-block var(--jf-transition);
  padding-block: var(--jf-space-5);
}
.main-header__inner {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: var(--jf-space-5);
}

.header-actions {
  display: inline-flex;
  align-items: center;
  gap: var(--jf-space-3);
}

/* Header phone — hidden on desktop, shown on mobile with visible number */
.header-phone {
  display: none;
  align-items: center;
  gap: var(--jf-space-2);
  color: var(--jf-color-heading);
  font-family: var(--jf-font-body);
  font-size: var(--jf-size-small);
  font-weight: var(--jf-weight-medium);
  text-decoration: none;
}
.header-phone:hover { text-decoration: none; }
.header-phone svg { width: 16px; height: 16px; flex-shrink: 0; }

/* Hamburger — hidden on desktop */
.menu-toggle {
  display: none;
  align-items: center;
  justify-content: center;
  width: var(--jf-space-7);
  height: var(--jf-space-7);
  color: var(--jf-color-heading);
  border-radius: var(--jf-radius-button);
}
.menu-toggle svg { width: 24px; height: 24px; }

/* Sticky condense on scroll */
.site-header.is-scrolled .utility-bar {
  max-height: 0;
  padding-block: 0;
}
.site-header.is-scrolled .main-header {
  padding-block: var(--jf-space-3);
}

/* --- Mobile / tablet header layout ---
   Two-row header kicks in at ≤1024 because at 1025–1200 the desktop nav
   (6 items + logo lockup + CTA) doesn't fit and wraps. Below 1024 we go
   to the compact 2-row layout for iPad-landscape sizes and down. */
@media (max-width: 1024px) {
  .main-header {
    padding-block: var(--jf-space-4);
  }
  .site-header.is-scrolled .main-header {
    padding-block: var(--jf-space-3);
  }
  /* ONE row: logo ......... phone hamburger.

     The second row existed only to carry "Book a Consultation", which sat
     roughly 40px above the hero's identical primary CTA — the same action
     twice on one screen, costing a permanent header row. The button moved to
     the top of the mobile panel; a tap-to-call icon replaced it, which is
     the action a person on a phone actually wants from a CPA firm. */
  .main-header__inner {
    grid-template-columns: 1fr auto auto;
    grid-template-areas: "logo phone hamburger";
    column-gap: var(--jf-space-2);
    row-gap: 0;
  }
  .logo             { grid-area: logo; }
  .main-nav-wrap    { display: none; }
  /* display: contents so the phone and the hamburger place themselves into
     their own grid areas rather than sitting in a wrapper. */
  .header-actions   { display: contents; }
  .header-phone     {
    grid-area: phone;
    display: inline-flex;
    justify-content: center;
    /* 44px tap target around a 24px icon. */
    width: 44px;
    height: 44px;
    gap: 0;
  }
  .header-phone svg { width: 24px; height: 24px; }
  /* The number itself is redundant next to a tap-to-call icon at this width,
     and it is still announced: the anchor carries aria-label="Call …". */
  .header-phone__number { display: none; }
  /* Desktop keeps the button. On a phone it is one tap away in the panel. */
  .header-cta       { display: none; }

  /* A heading size is not a wordmark size. 24px needs 265px to sit on one
     line and there is nowhere near that on a phone. This used to borrow
     --jf-size-lede; it now has its own token, because the lede step moved to
     21px for reasons that have nothing to do with the logo. */
  .site-header .logo__name { font-size: var(--jf-size-wordmark-mobile); }
  .main-header { padding-block: var(--jf-space-3); }

  /* One line made the logo link 34px tall, where the wrapped three-line
     version had been 79px and passed by accident. Row 1 is already 44px
     because of the hamburger, so this costs no header height. */
  .site-header .logo { min-height: 44px; }
  .menu-toggle      { display: inline-flex; grid-area: hamburger; justify-self: end; }

  /* Compact CTA so both the phone number and the full "Book a Consultation"
     label fit in row 2 at 768px and below. */
  .header-cta {
    padding: var(--jf-space-2) var(--jf-space-3);
    font-size: var(--jf-size-small);
  }
  .header-cta .btn__arrow { display: none; }

  /* Utility bar hidden on all compact-header sizes. */
  .utility-bar { display: none; }

  /* Tagline hidden below the desktop layout — noise at these widths. */
  .logo__tagline { display: none; }
}

/* Narrow phones. This has to live AFTER the 1024 block: at equal specificity
   the later rule wins, and when it sat up beside .logo__monogram the 19px
   above simply overrode it and 375 never got the smaller size. */
@media (max-width: 480px) {
  /* At 375 the wordmark needs 234px (monogram 34 + gap 12 + name 188) and the
     logo track offered 219, so the name ran 7px under the phone icon. The
     header — and only the header — trades gutter for that width. */
  .main-header__inner {
    padding-inline: var(--jf-space-4);
    column-gap: var(--jf-space-1);
  }
  /* 19px needs 210px of the 221px available at 375 — technically a fit, with
     11px to spare. 17px leaves real headroom so the wordmark cannot clip on
     the narrowest phones still in use. */
  .site-header .logo__name { font-size: var(--jf-size-body); }
}


/* -----------------------------------------------------------------------------
   Mobile panel
   ----------------------------------------------------------------------------- */
.mobile-panel {
  /* Closed state: display: none removes the panel from layout entirely, so
     its off-viewport width can't create horizontal overflow. Trade-off is
     no slide-in transition on open — acceptable for the design prototype.
     If a slide-in is wanted later, wire it via a keyframe animation on
     .is-open rather than transitioning the closed→open transform. */
  display: none;
  position: fixed;
  top: 0;
  right: 0;
  width: min(100%, 360px);
  height: 100vh;
  height: 100dvh;
  background: var(--jf-color-bg);
  border-left: var(--jf-border-width) solid var(--jf-color-border);
  /* Top padding clears the absolutely positioned close button (12px from the
     top, 48px tall) plus a gap. At the previous space-7 the close overlapped
     whatever came first in the panel — the first nav link before, and the
     CTA now. */
  padding: calc(var(--jf-space-3) + 48px + var(--jf-space-5)) var(--jf-space-5) var(--jf-space-5);
  z-index: 200;
  overflow-y: auto;
}
.mobile-panel.is-open { display: block; }
/* Primary CTA at the top of the panel, above the nav links. */
.mobile-panel__cta {
  margin-bottom: var(--jf-space-6);
}

.mobile-panel__close {
  position: absolute;
  top: var(--jf-space-3);
  right: var(--jf-space-3);
  width: var(--jf-space-7);
  height: var(--jf-space-7);
  color: var(--jf-color-heading);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--jf-radius-button);
}
.mobile-panel__close svg { width: 24px; height: 24px; }

.mobile-panel__nav {
  margin: 0 0 var(--jf-space-6);
  padding: 0;
  list-style: none;
}
.mobile-panel__nav li {
  border-bottom: var(--jf-border-width) solid var(--jf-color-border);
}
.mobile-panel__nav a {
  display: block;
  padding: var(--jf-space-4) 0;
  font-family: var(--jf-font-body);
  font-size: var(--jf-size-nav);
  font-weight: var(--jf-weight-medium);
  color: var(--jf-color-heading);
  text-decoration: none;
}
.mobile-panel__nav a:hover { text-decoration: none; color: var(--jf-color-link); }

.mobile-panel__utility {
  padding-top: var(--jf-space-6);
  border-top: var(--jf-border-width) solid var(--jf-color-border);
  display: grid;
  gap: var(--jf-space-2);
}
.mobile-panel__utility a {
  font-family: var(--jf-font-body);
  font-size: var(--jf-size-small);
  color: var(--jf-color-text);
  text-decoration: none;
  padding-block: var(--jf-space-2);
}
.mobile-panel__utility a:hover { color: var(--jf-color-heading); }

/* Scroll lock */
body.has-panel-open { overflow: hidden; }

/* Mobile panel is now display: none by default (see .mobile-panel rule) and
   only opens via the hamburger, which is itself hidden on desktop. No extra
   desktop rule needed. */


/* -----------------------------------------------------------------------------
   Site footer
   ----------------------------------------------------------------------------- */
.site-footer {
  background: var(--jf-color-bg-dark);
  color: var(--jf-color-text-on-dark);
  padding-block: var(--jf-space-9) var(--jf-space-6);
}
.site-footer__cols {
  display: grid;
  /* Five columns: identity, Services, Company, NAP, form. The form column is
     widest because it carries inputs; the two menu columns are narrowest
     because they carry short link lists. */
  grid-template-columns: 1.4fr 0.9fr 0.9fr 1.1fr 1.9fr;
  gap: var(--jf-space-6);
  margin-bottom: var(--jf-space-8);
}
@media (max-width: 1280px) {
  /* Form drops to its own full-width row before the menus start crushing. */
  .site-footer__cols { grid-template-columns: 1.4fr 0.9fr 0.9fr 1.1fr; }
  .site-footer__col--form { grid-column: 1 / -1; }
}
@media (max-width: 1024px) {
  .site-footer__cols { grid-template-columns: repeat(2, 1fr); }
  .site-footer__col--form { grid-column: 1 / -1; }
}
@media (max-width: 768px) {
  .site-footer__cols { grid-template-columns: 1fr; gap: var(--jf-space-6); }
}

.site-footer__desc {
  margin-top: var(--jf-space-4);
  font-size: var(--jf-size-small);
  line-height: var(--jf-lh-small);
  color: var(--jf-color-text-on-dark);
  opacity: 0.7;
  max-width: 32ch;
}

.site-footer__heading {
  font-family: var(--jf-font-body);
  font-size: var(--jf-size-small);
  font-weight: var(--jf-weight-semibold);
  letter-spacing: var(--jf-tracking-eyebrow);
  text-transform: uppercase;
  color: var(--jf-color-text-on-dark);
  opacity: 0.6;
  margin: 0 0 var(--jf-space-4);
}

.site-footer__nav {
  margin: 0; padding: 0; list-style: none;
  display: grid;
  /* gap reduced one step to offset the links' new vertical padding, so the
     visual rhythm between items stays at the original 12px. */
  gap: var(--jf-space-1);
}
.site-footer__nav a {
  color: var(--jf-color-text-on-dark);
  text-decoration: none;
  font-size: var(--jf-size-body);
  opacity: 0.9;
  transition: opacity var(--jf-transition);
  /* WCAG 2.2 AA target size (24x24): 20px text + 8px padding = 28px. */
  display: inline-block;
  padding-block: var(--jf-space-1);
}
.site-footer__nav a:hover { opacity: 1; text-decoration: underline; }

/* NAP block — light-bg default, inverse for dark surfaces (footer, dark bands) */
.nap {
  font-style: normal;
  line-height: var(--jf-lh-body);
  color: var(--jf-color-text);
}
.nap__name {
  display: block;
  font-weight: var(--jf-weight-semibold);
  color: var(--jf-color-heading);
  margin-bottom: var(--jf-space-1);
}
.nap a {
  color: var(--jf-color-link);
  text-decoration: none;
  /* WCAG 2.2 AA target size. As a bare inline element the link measured
     20px (font content box). inline-block + its own line-height:1 makes
     the box 17px of text + 8px padding = 25px, which clears the 24px
     minimum while still sitting INSIDE the address's 28px line box —
     so adjacent lines keep a 3px gap and the block's total height is
     unchanged. Raising .nap's line-height was unnecessary and only cost
     height (+9px at 1.75) for no extra separation. */
  display: inline-block;
  line-height: 1;
  padding-block: var(--jf-space-1);
}
.nap a:hover { text-decoration: underline; }

.nap--inverse                { color: var(--jf-color-text-on-dark); opacity: 0.9; }
.nap--inverse .nap__name     { color: var(--jf-color-text-on-dark); }
.nap--inverse a              { color: var(--jf-color-text-on-dark); }

.site-footer__bottom {
  border-top: var(--jf-border-width) solid color-mix(in srgb, var(--jf-color-text-on-dark) 15%, transparent);
  padding-top: var(--jf-space-5);
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: center;
  gap: var(--jf-space-4);
  color: var(--jf-color-text-on-dark);
  opacity: 0.7;
  font-size: var(--jf-size-small);
}
.site-footer__bottom p { margin: 0; max-width: none; }

.site-footer__legal {
  display: flex;
  gap: var(--jf-space-4);
  margin: 0; padding: 0;
  list-style: none;
}
.site-footer__legal a {
  color: var(--jf-color-text-on-dark);
  text-decoration: none;
  /* WCAG 2.2 AA target size (24x24): 19px text + 8px padding = 27px. */
  display: inline-block;
  padding-block: var(--jf-space-1);
}
.site-footer__legal a:hover { text-decoration: underline; }

.site-footer__social {
  display: flex;
  /* gap removed: the 44px targets below already carry 12px of internal
     padding per side, which supplies the visual separation. */
  gap: 0;
  margin: 0; padding: 0;
  list-style: none;
}
.site-footer__social a {
  color: var(--jf-color-text-on-dark);
  display: inline-flex;
  align-items: center;
  /* Icon stays 20px; the box is padded out to a 44x44 touch target. */
  justify-content: center;
  min-width: 44px;
  min-height: 44px;
  opacity: 0.7;
  transition: opacity var(--jf-transition);
}
.site-footer__social a:hover { opacity: 1; }
.site-footer__social svg { width: 20px; height: 20px; }


/* -----------------------------------------------------------------------------
   Sticky contact bar — desktop only, pinned to viewport bottom
   ----------------------------------------------------------------------------- */
.contact-bar {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  background: var(--jf-color-bg-dark);
  color: var(--jf-color-text-on-dark);
  border-top: var(--jf-border-width) solid color-mix(in srgb, var(--jf-color-text-on-dark) 15%, transparent);
  padding-block: var(--jf-space-3);
  z-index: 90;
}
.contact-bar__inner {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--jf-space-5);
}
.contact-bar__label {
  font-family: var(--jf-font-body);
  font-size: var(--jf-size-small);
  font-weight: var(--jf-weight-medium);
  color: var(--jf-color-text-on-dark);
  opacity: 0.85;
}
.contact-bar__actions {
  display: flex;
  align-items: center;
  gap: var(--jf-space-5);
}
.contact-bar__link {
  color: var(--jf-color-text-on-dark);
  text-decoration: none;
  font-size: var(--jf-size-small);
  font-weight: var(--jf-weight-medium);
  opacity: 0.9;
  transition: opacity var(--jf-transition);
}
.contact-bar__link:hover { opacity: 1; text-decoration: underline; }
.contact-bar__btn {
  padding: var(--jf-space-2) var(--jf-space-4);
  font-size: var(--jf-size-small);
}

/* Body padding-bottom so the fixed contact bar doesn't cover the footer's
   bottom row when scrolled to page end. Breakpoint matches the header +
   contact-bar visibility switch (1024). */
@media (min-width: 1025px) {
  body { padding-bottom: var(--jf-space-8); }
}
@media (max-width: 1024px) {
  .contact-bar { display: none; }
}


/* -----------------------------------------------------------------------------
   Numbered steps — used on service pages' "How it works" section
   ----------------------------------------------------------------------------- */
.numbered-steps {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--jf-space-7);
  counter-reset: step;
  max-width: 60ch;
}
.numbered-steps > li {
  counter-increment: step;
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--jf-space-5);
  align-items: start;
}
.numbered-steps > li::before {
  content: counter(step, decimal-leading-zero);
  font-family: var(--jf-font-display);
  font-size: var(--jf-size-h2);
  font-weight: var(--jf-weight-semibold);
  color: var(--jf-color-text-muted-large);
  line-height: 1;
  min-width: 3ch;
}
.numbered-steps__title {
  font-family: var(--jf-font-display);
  font-size: var(--jf-size-h3);
  color: var(--jf-color-heading);
  margin: 0 0 var(--jf-space-2);
  line-height: var(--jf-lh-h3);
}
.numbered-steps__body {
  font-family: var(--jf-font-body);
  font-size: var(--jf-size-body);
  color: var(--jf-color-text);
  margin: 0;
  line-height: var(--jf-lh-body);
}


/* -----------------------------------------------------------------------------
   Accordion — used on industry pages' "Common questions" section.
   Needs js/accordion.js loaded on the page. Aria contract in that file.
   ----------------------------------------------------------------------------- */
.accordion {
  border-top: var(--jf-border-width) solid var(--jf-color-border);
}
.accordion__item {
  border-bottom: var(--jf-border-width) solid var(--jf-color-border);
}
.accordion__toggle {
  display: flex;
  width: 100%;
  padding: var(--jf-space-5) 0;
  align-items: center;
  justify-content: space-between;
  gap: var(--jf-space-4);
  background: none;
  border: 0;
  cursor: pointer;
  font-family: var(--jf-font-display);
  font-size: var(--jf-size-h3);
  font-weight: var(--jf-weight-semibold);
  color: var(--jf-color-heading);
  text-align: left;
  line-height: var(--jf-lh-h3);
}
.accordion__toggle:focus-visible {
  outline: 2px solid var(--jf-color-link);
  outline-offset: 2px;
}
.accordion__icon {
  width: 20px;
  height: 20px;
  flex-shrink: 0;
  color: var(--jf-color-link);
  transition: transform var(--jf-transition);
}
.accordion__toggle[aria-expanded="true"] .accordion__icon {
  transform: rotate(180deg);
}
.accordion__panel {
  padding: 0 0 var(--jf-space-5);
  color: var(--jf-color-text);
  font-family: var(--jf-font-body);
  line-height: var(--jf-lh-body);
  max-width: 60ch;
}
.accordion__panel[hidden] { display: none; }


/* -----------------------------------------------------------------------------
   CTA band — full-bleed navy, heading + button. Same visual language as
   stats-band; used at the bottom of most inner pages.
   ----------------------------------------------------------------------------- */
.cta-band {
  background: var(--jf-color-bg-dark);
  color: var(--jf-color-text-on-dark);
  padding-block: var(--jf-space-9);
}
.cta-band__inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--jf-space-5);
  text-align: center;
  max-width: 720px;
  margin-inline: auto;
}
/* An <h2> at the h2 size. It was --jf-size-h1 (64px), which put a second
   64px display element on 19 of 24 pages, below the page's actual H1 and
   lower in the document hierarchy than it. The band is full-bleed navy and
   already carries the weight; it does not need to be the largest thing on
   the page. Responsive steps move with it, h1-tablet/h1-mobile becoming
   h2-tablet/h2-mobile. */
.cta-band__title {
  font-family: var(--jf-font-display);
  font-size: var(--jf-size-h2);
  font-weight: var(--jf-weight-semibold);
  color: var(--jf-color-text-on-dark);
  line-height: var(--jf-lh-h2);
  margin: 0;
  letter-spacing: var(--jf-tracking-h1);
}
@media (max-width: 1024px) {
  .cta-band__title { font-size: var(--jf-size-h2-tablet); }
}
@media (max-width: 768px) {
  .cta-band__title { font-size: var(--jf-size-h2-mobile); }
}
/* Primary button on the navy band inverts to white-on-navy so it reads. */
.cta-band .btn--primary {
  background: var(--jf-color-text-on-dark);
  color: var(--jf-color-heading);
}
.cta-band .btn--primary:hover {
  background: color-mix(in srgb, var(--jf-color-text-on-dark) 88%, transparent);
}


/* -----------------------------------------------------------------------------
   Team card — square photo, name, title, credentials, email
   ----------------------------------------------------------------------------- */
.team-card {
  display: flex;
  flex-direction: column;
  background: var(--jf-color-bg);
  border: var(--jf-border-width) solid var(--jf-color-border);
  border-radius: var(--jf-radius-card);
  overflow: hidden;
  transition: border-color var(--jf-transition);
}
.team-card:hover { border-color: var(--jf-color-border-hover); }
.team-card__photo {
  aspect-ratio: 1 / 1;
  background: var(--jf-color-bg-alt);
  border-bottom: var(--jf-border-width) solid var(--jf-color-border);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--jf-space-4);
  text-align: center;
  font-family: ui-monospace, 'SF Mono', Menlo, Consolas, monospace;
  font-size: var(--jf-size-small);
  color: var(--jf-color-text);
}

/* Initials avatar — stands in for a headshot without pretending to be one.
   A photo placeholder invites the reader to wonder what is missing; a set of
   initials reads as a deliberate mark. Real headshots drop into the same slot
   later: swap the span for an <img> and the geometry is unchanged. */
.team-card__initials,
.lead-contact__initials {
  flex-shrink: 0;
  width: 96px;
  height: 96px;
  border-radius: 50%;
  background: var(--jf-color-bg-dark);
  color: var(--jf-color-text-on-dark);
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--jf-font-display);
  font-size: var(--jf-size-card-title);
  font-weight: var(--jf-weight-semibold);
  letter-spacing: 0.02em;
  line-height: 1;
  user-select: none;
}
/* On a team card the avatar sits in the square photo slot, centred. */
.team-card__photo--initials {
  aspect-ratio: 1 / 1;
  background: var(--jf-color-bg-alt);
  border-bottom: var(--jf-border-width) solid var(--jf-color-border);
  display: flex;
  align-items: center;
  justify-content: center;
}
.team-card__body {
  padding: var(--jf-space-5);
  display: flex;
  flex-direction: column;
  gap: var(--jf-space-1);
  flex: 1;
}
.team-card__name {
  font-family: var(--jf-font-display);
  font-size: var(--jf-size-card-title);
  font-weight: var(--jf-weight-semibold);
  color: var(--jf-color-heading);
  margin: 0;
  line-height: var(--jf-lh-h3);
}
.team-card__title {
  font-family: var(--jf-font-body);
  font-size: var(--jf-size-small);
  color: var(--jf-color-text);
  margin: 0;
}
.team-card__credentials {
  font-family: var(--jf-font-body);
  font-size: var(--jf-size-eyebrow);
  font-weight: var(--jf-weight-semibold);
  letter-spacing: var(--jf-tracking-eyebrow);
  text-transform: uppercase;
  color: var(--jf-color-eyebrow);
  margin: var(--jf-space-2) 0 0;
}
.team-card__email {
  margin-top: var(--jf-space-3);
  font-family: var(--jf-font-body);
  font-size: var(--jf-size-small);
  color: var(--jf-color-link);
  text-decoration: none;
}
.team-card__email:hover { text-decoration: underline; }


/* -----------------------------------------------------------------------------
   Principle — "What we believe" items on the About page. No icon.
   ----------------------------------------------------------------------------- */
.principle {
  display: flex;
  flex-direction: column;
  gap: var(--jf-space-3);
  max-width: 40ch;
}
.principle__title {
  font-family: var(--jf-font-display);
  font-size: var(--jf-size-h3);
  font-weight: var(--jf-weight-semibold);
  color: var(--jf-color-heading);
  margin: 0;
  line-height: var(--jf-lh-h3);
}
.principle__body {
  font-family: var(--jf-font-body);
  font-size: var(--jf-size-body);
  color: var(--jf-color-text);
  line-height: var(--jf-lh-body);
  margin: 0;
}


/* -----------------------------------------------------------------------------
   Careers strip — soft-bg block with a paragraph + button
   ----------------------------------------------------------------------------- */
.careers-strip {
  display: flex;
  flex-direction: column;
  gap: var(--jf-space-4);
  padding: var(--jf-space-8);
  background: var(--jf-color-bg-alt);
  border: var(--jf-border-width) solid var(--jf-color-border);
  border-radius: var(--jf-radius-card);
  align-items: flex-start;
  max-width: 780px;
  margin-inline: auto;
}


/* -----------------------------------------------------------------------------
   Tag links — inline list of pill-less category links separated by dots
   ----------------------------------------------------------------------------- */
.tag-links {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: var(--jf-space-2) var(--jf-space-3);
}
/* Flex the item so the · separator centres against the taller padded link
   instead of sitting on its text baseline. */
.tag-links li {
  display: flex;
  align-items: center;
}
.tag-links li + li::before {
  content: '·';
  color: var(--jf-color-text-muted-large);
  margin-inline-end: var(--jf-space-3);
}
.tag-links a {
  font-family: var(--jf-font-body);
  font-size: var(--jf-size-body);
  color: var(--jf-color-link);
  text-decoration: none;
  /* Same 25px AA target treatment as .nap a — see the note there. */
  display: inline-block;
  line-height: 1;
  padding-block: var(--jf-space-1);
}
.tag-links a:hover { text-decoration: underline; }


/* -----------------------------------------------------------------------------
   Touch target sizing
   -----------------------------------------------------------------------------
   WCAG 2.2 AA requires 24x24 minimum; AAA (and the platform HIG guidance)
   asks for 44x44. The footer link/social rules above meet AA inline. The
   rules here lift the primary interactive elements to the 44px AAA target
   on touch viewports, where the extra area actually matters.

   Sizes are set with min-height rather than padding wherever the element is
   already inline-flex + align-items:center, so the box grows symmetrically
   without shifting the label off its baseline.
   ----------------------------------------------------------------------------- */
@media (max-width: 768px) {
  .btn {
    min-height: 44px;
    box-sizing: border-box;
  }
  /* card__link is a bare inline link, so pad it rather than force a box
     height — the padding is what widens the actual hit region. */
  .card__link {
    padding-block: var(--jf-space-3);
  }
}

/* .header-phone is only rendered at <=1024 (the compact-header range), so
   size it across that whole range rather than only under 768. */
@media (max-width: 1024px) {
  .header-phone {
    min-height: 44px;
    box-sizing: border-box;
  }
}


/* -----------------------------------------------------------------------------
   Lead contact — closes every service page with an accountable human.
   Pattern borrowed from LGT, who attach a named lead partner to each service
   line. The benchmark flags this as one of the credibility dividers: a service
   page with a name and a face reads as owned, an anonymous one does not.
   ----------------------------------------------------------------------------- */
.lead-contact {
  display: flex;
  align-items: flex-start;
  gap: var(--jf-space-5);
  padding: var(--jf-space-6);
  background: var(--jf-color-bg-alt);
  border: var(--jf-border-width) solid var(--jf-color-border);
  border-radius: var(--jf-radius-card);
  max-width: 680px;
}
@media (max-width: 768px) {
  .lead-contact { flex-direction: column; gap: var(--jf-space-4); }
}
.lead-contact__photo {
  flex-shrink: 0;
  width: 96px;
  height: 96px;
  border-radius: 50%;
  overflow: hidden;
  background: var(--jf-color-bg);
  border: var(--jf-border-width) dashed var(--jf-color-border);
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  font-family: ui-monospace, 'SF Mono', Menlo, Consolas, monospace;
  font-size: var(--jf-size-eyebrow);
  color: var(--jf-color-text);
}
.lead-contact__body { flex: 1; }
.lead-contact__prompt {
  font-family: var(--jf-font-body);
  font-size: var(--jf-size-small);
  color: var(--jf-color-text);
  margin: 0 0 var(--jf-space-3);
}
.lead-contact__name {
  font-family: var(--jf-font-display);
  font-size: var(--jf-size-h3);
  line-height: var(--jf-lh-h3);
  font-weight: var(--jf-weight-semibold);
  color: var(--jf-color-heading);
  margin: 0;
}
.lead-contact__title {
  font-family: var(--jf-font-body);
  font-size: var(--jf-size-small);
  color: var(--jf-color-text);
  margin: var(--jf-space-1) 0 var(--jf-space-3);
}
.lead-contact__email {
  font-family: var(--jf-font-body);
  font-size: var(--jf-size-body);
  color: var(--jf-color-link);
  text-decoration: none;
  display: inline-block;
  line-height: 1;
  padding-block: var(--jf-space-1);
}
.lead-contact__email:hover { text-decoration: underline; }


/* -----------------------------------------------------------------------------
   Form register — the named-IRS-form list that runs on every service page.
   The benchmark's sharpest credibility divider: only 3 of 15 firms name
   specific forms on a service page. Number and full title, always.
   ----------------------------------------------------------------------------- */
.form-register {
  list-style: none;
  margin: var(--jf-space-5) 0 0;
  padding: 0;
  display: grid;
  gap: var(--jf-space-3);
  max-width: 680px;
}
.form-register li {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--jf-space-4);
  align-items: baseline;
  padding-block: var(--jf-space-2);
  border-top: var(--jf-border-width) solid var(--jf-color-border);
}
.form-register__no {
  font-family: var(--jf-font-body);
  font-size: var(--jf-size-small);
  font-weight: var(--jf-weight-semibold);
  color: var(--jf-color-heading);
  white-space: nowrap;
}
.form-register__title {
  font-family: var(--jf-font-body);
  font-size: var(--jf-size-small);
  color: var(--jf-color-text);
}


/* -----------------------------------------------------------------------------
   Boundary note — states plainly what the firm does NOT do. Used on the
   estate page for the CPA-vs-attorney line, which the benchmark identifies
   as the point most CPA sites fumble.
   ----------------------------------------------------------------------------- */
.boundary-note {
  border-left: 3px solid var(--jf-color-link);
  background: var(--jf-color-bg-alt);
  padding: var(--jf-space-5) var(--jf-space-6);
  border-radius: var(--jf-radius-card);
  margin: var(--jf-space-6) 0;
  max-width: 680px;
}
.boundary-note p { margin: 0; }
.boundary-note p + p { margin-top: var(--jf-space-3); }


/* -----------------------------------------------------------------------------
   Blank field — a value that is genuinely unknown and must not be invented.
   Used for the Florida CPA licence number and the peer review result. These
   are regulatory credentials: a plausible-looking placeholder is worse than
   an obvious gap, because it can be mistaken for a real value. Rendering them
   as form-style blanks makes it visually unambiguous that a field is awaiting
   completion rather than that content is missing.
   ----------------------------------------------------------------------------- */
.blank-field {
  font-family: var(--jf-font-body);
  /* Inherit the surrounding colour rather than pinning one. The blank appears
     on the light trust band AND in the navy footer; a fixed --jf-color-text
     drops to 2.54:1 on navy. currentColor keeps both contexts legible. */
  color: inherit;
  white-space: nowrap;
}
.blank-field__rule {
  display: inline-block;
  min-width: 9ch;
  border-bottom: 1px solid currentColor;
  /* The rule reads as a field to fill, not as an underline on live text. */
  opacity: 0.55;
  margin-inline-start: 0.25ch;
}


/* -----------------------------------------------------------------------------
   Team card specialty line — one sentence on what this person actually works on.
   Sits below the credentials and above the email; the reason a visitor picks
   one name out of sixteen rather than defaulting to whoever is listed first.
   ----------------------------------------------------------------------------- */
.team-card__spec {
  font-family: var(--jf-font-body);
  font-size: var(--jf-size-small);
  line-height: var(--jf-lh-small);
  color: var(--jf-color-text);
  margin: var(--jf-space-3) 0 0;
}


/* -----------------------------------------------------------------------------
   Author bio — byline block at the foot of an article. Same initials avatar
   as the team card, laid out horizontally.
   ----------------------------------------------------------------------------- */
.author-bio {
  display: flex;
  gap: var(--jf-space-5);
  align-items: flex-start;
  max-width: 780px;
}
.author-bio__body { flex: 1; }
.author-bio__name {
  font-family: var(--jf-font-display);
  font-size: var(--jf-size-h3);
  line-height: var(--jf-lh-h3);
  font-weight: var(--jf-weight-semibold);
  color: var(--jf-color-heading);
  margin: 0 0 var(--jf-space-1);
}
.author-bio__title {
  font-family: var(--jf-font-body);
  font-size: var(--jf-size-small);
  color: var(--jf-color-text);
  margin: 0 0 var(--jf-space-3);
}
.author-bio__text {
  font-family: var(--jf-font-body);
  font-size: var(--jf-size-body);
  line-height: var(--jf-lh-body);
  color: var(--jf-color-text);
  margin: 0;
}


/* -----------------------------------------------------------------------------
   Job posting — one open role. Full width rather than a card in a 3-up grid:
   a real posting carries five responsibilities and four requirements, and
   that does not survive a 420px column.
   ----------------------------------------------------------------------------- */
/* Left-aligned, not centred: the postings sit under a left-aligned section
   head, and centring the list breaks that edge. */
.job-list {
  max-width: 980px;
}
.job {
  padding: var(--jf-space-7);
  background: var(--jf-color-bg);
  border: var(--jf-border-width) solid var(--jf-color-border);
  border-radius: var(--jf-radius-card);
}
.job + .job { margin-top: var(--jf-space-5); }
.job__title {
  font-family: var(--jf-font-display);
  font-size: var(--jf-size-h3);
  line-height: var(--jf-lh-h3);
  font-weight: var(--jf-weight-semibold);
  color: var(--jf-color-heading);
  margin: 0 0 var(--jf-space-2);
}
.job__meta {
  font-family: var(--jf-font-body);
  font-size: var(--jf-size-eyebrow);
  letter-spacing: var(--jf-tracking-eyebrow);
  text-transform: uppercase;
  font-weight: var(--jf-weight-semibold);
  color: var(--jf-color-eyebrow);
  margin: 0 0 var(--jf-space-4);
}
.job__summary {
  font-family: var(--jf-font-body);
  font-size: var(--jf-size-body);
  line-height: var(--jf-lh-body);
  color: var(--jf-color-text);
  /* No bottom margin: inside Elementor the summary is the last child of a
     Text Editor widget, whose trailing margin the bridge strips. The gap
     lives on .job__cols instead, where both contexts honour it. */
  margin: 0;
  max-width: 65ch;
}
.job__cols {
  margin-top: var(--jf-space-6);
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--jf-space-6) var(--jf-column-gap);
}
@media (max-width: 768px) {
  .job__cols { grid-template-columns: 1fr; }
  .job { padding: var(--jf-space-5); }
}
.job__col-label {
  font-family: var(--jf-font-body);
  font-size: var(--jf-size-eyebrow);
  letter-spacing: var(--jf-tracking-eyebrow);
  text-transform: uppercase;
  font-weight: var(--jf-weight-semibold);
  color: var(--jf-color-heading);
  margin: 0 0 var(--jf-space-3);
}
.job__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--jf-space-3);
}
.job__list li {
  position: relative;
  padding-inline-start: var(--jf-space-4);
  font-family: var(--jf-font-body);
  font-size: var(--jf-size-small);
  line-height: var(--jf-lh-small);
  color: var(--jf-color-text);
}
.job__list li::before {
  content: '';
  position: absolute;
  inset-inline-start: 0;
  top: 0.55em;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--jf-color-eyebrow);
}
.job__apply { margin-top: var(--jf-space-6); }


/* -----------------------------------------------------------------------------
   <picture> wrappers are emitted by the build for every responsive photograph.
   display: contents keeps them out of the box tree entirely, so every rule
   that already targets the <img> — .hero__bg, .image-frame img, object-fit —
   applies exactly as it did before the wrapper existed.
   ----------------------------------------------------------------------------- */
picture { display: contents; }


/* -----------------------------------------------------------------------------
   Map embed — click-to-load facade
   -----------------------------------------------------------------------------
   A plain Google Maps iframe pulls roughly 300KB of third-party JavaScript and
   sets cookies on every single page view, on the two pages that most need to be
   fast and before the visitor has consented to anything. So the slot renders a
   static facade instead, and the iframe is only injected when someone asks for
   it by clicking. No request reaches google.com until then.

   "Get directions" sits outside that trade entirely: a plain link, works with
   JavaScript off and never loads an iframe at all.

   Geometry matches the placeholder it replaces (4:3) so nothing reflows.
   ----------------------------------------------------------------------------- */
.map-embed {
  position: relative;
  aspect-ratio: 4 / 3;
  background: var(--jf-color-bg-alt);
  border: var(--jf-border-width) solid var(--jf-color-border);
  border-radius: var(--jf-radius-card);
  overflow: hidden;
}

/* The facade. Becomes display:none once the iframe is in. */
.map-embed__facade {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--jf-space-3);
  padding: var(--jf-space-5);
  text-align: center;
}
.map-embed__pin {
  width: 32px;
  height: 32px;
  color: var(--jf-color-heading);
  flex-shrink: 0;
}
.map-embed__address {
  font-family: var(--jf-font-body);
  font-size: var(--jf-size-small);
  line-height: var(--jf-lh-small);
  color: var(--jf-color-text);
  margin: 0;
  max-width: 34ch;
}
.map-embed__note {
  font-family: var(--jf-font-body);
  font-size: var(--jf-size-eyebrow);
  letter-spacing: var(--jf-tracking-eyebrow);
  text-transform: uppercase;
  /* Not --jf-color-text-muted-large. That alias is Gray 400 and tokens.css marks it
     "H1 second line only — large text"; at 13px it measures 3.13:1, under the
     4.5:1 normal-text bar. Gray 600 is 6.0:1. */
  color: var(--jf-color-text);
  margin: 0;
}

/* Direct mode: the iframe is in the markup from the start, lazily loaded.
   Used where seeing the location IS the task (contact) rather than incidental
   proof of it (homepage). Same box, same geometry — only the trigger differs,
   so nothing below needs a variant. The .map-embed background shows through
   until the frame paints. */

/* The injected iframe fills the same box. */
.map-embed__frame {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
  display: block;
}

/* Directions link sits beneath the box, not inside it. */
.map-embed-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--jf-space-4);
  margin-top: var(--jf-space-3);
}
.map-embed-actions a {
  font-family: var(--jf-font-body);
  font-size: var(--jf-size-small);
  color: var(--jf-color-link);
  /* 44px tap target without changing the visual line height. */
  display: inline-flex;
  align-items: center;
  min-height: 44px;
}
