/*
 * dg-global.css — Davis Group Child Theme
 * Design system: "Granite & Ponderosa"
 * DeadStop Creative · 2026
 *
 * Sections:
 *   1. @font-face
 *   2. Design tokens (:root)
 *   3. Base / reset
 *   4. Skip navigation + focus
 *   5. Typography utility classes
 *   6. Eyebrow component
 *   7. Stat block component
 *   8. Section heading overrides
 *   9. Button styles
 *  10. Community card
 *  11. Card-lift shadow effect
 *  12. Official-link / external link
 *  13. Header (dg-header, dg-scroll-bar, page-template-*)
 *  14. Footer (dg-footer)
 *  15. Forms — Fluent Forms skin
 *  16. VisionBand (vision-band, vision-photo-*, vision-text-col)
 *  17. SHomesites release rows (Stringfield "Now Selling" section)
 *  18. Team cards
 *  19. Image hover
 *  20. Reduced motion
 *  21. Master plan — release strip, land ledger, lightbox (added July 2026)
 *  22. Sub-brand scoping — Stringfield / Serenity brand-guide palettes
 *      and typefaces, scoped to .sf-scope / .sr-scope so the parent
 *      Davis Group tokens above are untouched everywhere else.
 *      (added July 2026)
 *  23. Stringfield Standard — masthead + proof list (Stringfield page,
 *      redesigned July 2026)
 */


/* ============================================================
   1. @FONT-FACE
   Download WOFF2 files and place in davis-group-child/fonts/
   Source: https://google-webfonts-helper.herokuapp.com
   ============================================================ */

/* Bodoni Moda — display / editorial */
@font-face {
  font-family: 'Bodoni Moda';
  src: url('../../fonts/bodoni-moda-400.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Bodoni Moda';
  src: url('../../fonts/bodoni-moda-400-italic.woff2') format('woff2');
  font-weight: 400;
  font-style: italic;
  font-display: swap;
}

/* Hanken Grotesk — body / UI / labels */
@font-face {
  font-family: 'Hanken Grotesk';
  src: url('../../fonts/hanken-grotesk-300.woff2') format('woff2');
  font-weight: 300;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Hanken Grotesk';
  src: url('../../fonts/hanken-grotesk-400.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Hanken Grotesk';
  src: url('../../fonts/hanken-grotesk-500.woff2') format('woff2');
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Hanken Grotesk';
  src: url('../../fonts/hanken-grotesk-600.woff2') format('woff2');
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Hanken Grotesk';
  src: url('../../fonts/hanken-grotesk-700.woff2') format('woff2');
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

/* Stringfield at Granite Mountain sub-brand — Fraunces stands in for the
   guide's Boreal Regular (a paid font we don't hold a license for); Open
   Sans Condensed is the guide's literal, freely-licensed spec. See
   .sf-scope in section 22. */
@font-face {
  font-family: 'Fraunces';
  src: url('../../fonts/fraunces-400.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Fraunces';
  src: url('../../fonts/fraunces-500.woff2') format('woff2');
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Fraunces';
  src: url('../../fonts/fraunces-600.woff2') format('woff2');
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Fraunces';
  src: url('../../fonts/fraunces-400-italic.woff2') format('woff2');
  font-weight: 400;
  font-style: italic;
  font-display: swap;
}
@font-face {
  font-family: 'Open Sans Condensed';
  src: url('../../fonts/open-sans-condensed-300.woff2') format('woff2');
  font-weight: 300;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Open Sans Condensed';
  src: url('../../fonts/open-sans-condensed-700.woff2') format('woff2');
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

/* Serenity at Stringfield sub-brand — Roboto is the guide's literal
   "Primary Headers" spec (a free family). Lora stands in for the guide's
   Bennet Banner "Secondary Paragraph" (paid, unlicensed here). Cormorant
   stands in for the guide's Trajan Pro 3 "Logo Font" (paid, unlicensed)
   and is used only for the wordmark and the hero's italic accent line —
   see --font-accent in .sr-scope, section 22. */
@font-face {
  font-family: 'Roboto';
  src: url('../../fonts/roboto-400.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Roboto';
  src: url('../../fonts/roboto-500.woff2') format('woff2');
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Roboto';
  src: url('../../fonts/roboto-400-italic.woff2') format('woff2');
  font-weight: 400;
  font-style: italic;
  font-display: swap;
}
@font-face {
  font-family: 'Lora';
  src: url('../../fonts/lora-400.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Lora';
  src: url('../../fonts/lora-400-italic.woff2') format('woff2');
  font-weight: 400;
  font-style: italic;
  font-display: swap;
}
@font-face {
  font-family: 'Lora';
  src: url('../../fonts/lora-500.woff2') format('woff2');
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Cormorant';
  src: url('../../fonts/cormorant-400.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Cormorant';
  src: url('../../fonts/cormorant-500.woff2') format('woff2');
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Cormorant';
  src: url('../../fonts/cormorant-600.woff2') format('woff2');
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Cormorant';
  src: url('../../fonts/cormorant-500-italic.woff2') format('woff2');
  font-weight: 500;
  font-style: italic;
  font-display: swap;
}


/* ============================================================
   2. DESIGN TOKENS
   Single source of truth. All components reference var() only —
   never hardcoded hex values anywhere else in the theme.
   ============================================================ */

:root {
  /* —— Core palette —— */
  --paper:        #F6F1E7;
  --paper-alt:    #EFE8DA;
  --card:         #FFFDF7;
  --sand:         #E5DBC8;
  --ink-700:      #46433B;
  --ink-900:      #1E1D17;
  /* Darkened from #7E7460 — the original only reached 4.1:1 on --paper and
     3.8:1 on --paper-alt against WCAG AA's 4.5:1 floor for normal text
     (used for muted/caption text at 12-15px sitewide). This hue-preserving
     adjustment clears 4.5:1 against both paper surfaces. */
  --taupe:        #716856;

  /* —— Pine (brand green) —— */
  --pine-900:     #16241A;
  --pine-800:     #1C2E21;
  --pine-700:     #294234;
  --pine-600:     #335041;
  --pine-500:     #436454;
  /* Lightened from #708A78 — the original only reached 4.3:1 against
     --pine-900 (used for footer address/copyright text at 12-13px on the
     dark footer), just under WCAG AA's 4.5:1 floor for normal text. */
  --pine-300:     #748E7C;
  --pine-100:     #C3CFC4;

  /* —— Bronze / clay (accent, CTAs) —— */
  --bronze-600:   #875A35;
  /* #9C6B42 is the reference's exact accent — restored July 2026 after a
     WCAG-motivated darkening to #8B5F3B made the accent CTAs visibly
     off-tone next to the reference (client-flagged on the hero). Note:
     as --accent this is also small eyebrow text, where #9C6B42 reaches
     only ~4.1:1 on --paper vs AA's 4.5:1 — accepted deviation in favor
     of exact reference parity; revisit with the client if AA text
     compliance becomes a requirement. */
  --bronze-500:   #9C6B42;
  --bronze-400:   #B0814F;
  --bronze-200:   #D8BE9C;

  /* —— Sky (dusty blue) —— */
  --sky-600:      #4F6E7C;
  --sky-500:      #6B8896;
  --sky-300:      #A8BEC7;

  /* —— Stone neutrals —— */
  --stone-100:    #DCD2BE;
  --stone-200:    #CABEA6;
  --stone-300:    #B6A98E;

  /* —— Functional —— */
  --success:      #4B6B4E;

  /* —— Semantic surface aliases —— */
  --surface-page:      var(--paper);
  --surface-page-alt:  var(--paper-alt);
  --surface-card:      var(--card);
  --surface-inverse:   var(--pine-900);

  /* —— Semantic text aliases —— */
  --text-heading:       var(--ink-900);
  --text-body:          var(--ink-700);
  --text-muted:         var(--taupe);
  --text-inverse:       var(--paper);
  --text-on-dark-muted: var(--pine-100);

  /* —— Brand / accent aliases —— */
  --brand:         var(--pine-700);
  --brand-strong:  var(--pine-900);
  --accent:        var(--bronze-500);
  --accent-strong: var(--bronze-600);
  --accent-soft:   var(--sky-500);

  /* —— Borders —— */
  --border-hairline: rgba(30, 29, 23, 0.14);
  --border-soft:     rgba(30, 29, 23, 0.08);
  --border-on-dark:  rgba(246, 241, 231, 0.22);
  --rule-accent:     var(--bronze-500);

  /* —— Shadows —— */
  --shadow-xs:  0 1px 2px rgba(30, 29, 23, 0.06);
  --shadow-sm:  0 2px 8px rgba(30, 29, 23, 0.07);
  --shadow-md:  0 10px 30px -12px rgba(30, 29, 23, 0.18);
  --shadow-lg:  0 28px 60px -28px rgba(22, 36, 26, 0.34);

  /* —— Paper opacity variants (for overlays) —— */
  --paper-98: rgba(246, 241, 231, 0.98);
  --paper-96: rgba(246, 241, 231, 0.96);
  --paper-94: rgba(246, 241, 231, 0.94);
  --paper-92: rgba(246, 241, 231, 0.92);
  --paper-90: rgba(246, 241, 231, 0.90);
  --paper-78: rgba(246, 241, 231, 0.78);
  --paper-75: rgba(246, 241, 231, 0.75);
  --paper-72: rgba(246, 241, 231, 0.72);
  --paper-60: rgba(246, 241, 231, 0.60);
  --paper-55: rgba(246, 241, 231, 0.55);
  --paper-50: rgba(246, 241, 231, 0.50);
  --paper-40: rgba(246, 241, 231, 0.40);
  --paper-32: rgba(246, 241, 231, 0.32);
  --paper-22: rgba(246, 241, 231, 0.22);
  --paper-12: rgba(246, 241, 231, 0.12);

  /* —— Typography scale —— */
  --t-title:   28px;
  --t-lead:    21px;
  --t-body:    17px;
  --t-small:   15px;
  --t-caption: 13px;
  --t-eyebrow: 12.5px;

  /* —— Line heights —— */
  --lh-tight:   1.02;
  --lh-snug:    1.12;
  --lh-display: 1.06;
  --lh-body:    1.70;
  --lh-relaxed: 1.75;

  /* —— Letter spacing —— */
  --ls-display: -0.02em;
  --ls-tight:   -0.01em;
  --ls-normal:  0;
  --ls-eyebrow: 0.22em;
  --ls-caps:    0.14em;

  /* —— Font weights —— */
  --w-light:    300;
  --w-regular:  400;
  --w-medium:   500;
  --w-semibold: 600;
  --w-bold:     700;

  /* —— Font families —— */
  --font-display: 'Bodoni Moda', 'Didot', Georgia, serif;
  --font-sans:    'Hanken Grotesk', -apple-system, 'Segoe UI', system-ui, sans-serif;

  /* —— Layout —— */
  --content-max:     1280px;
  --content-text:    680px;
  --gutter:          clamp(20px, 5vw, 80px);
  --section-y:       clamp(80px, 10vw, 128px);
  --section-y-tight: clamp(56px, 7.5vw, 96px);

  /* —— Radius —— */
  --radius-xs:   2px;  /* added July 2026 — used by the master plan ledger/marker (Section 21); matches globals.css */
  --radius-card: 4px;
  --radius-sm:   4px;
  --radius-md:   6px;
  --radius-pill: 9999px;

  /* —— Motion —— */
  /* These three durations mirror the reference site's tokens exactly
     (deadstop-web-projects.vercel.app, app/globals.css). A July 2026 pass
     briefly retimed them to 150/250/450ms; reverted per client — every
     transition must behave exactly like the reference. */
  --ease-out:   cubic-bezier(0.22, 0.61, 0.36, 1);
  --ease-inout: cubic-bezier(0.65, 0, 0.35, 1);
  --dur-fast:   180ms;
  --dur-base:   320ms;
  --dur-slow:   560ms;

  /* —— Focus ring —— */
  --focus-ring: 0 0 0 3px var(--bronze-500);

  /* —— Text shadow —— */
  --text-shadow-on-dark: 0 1px 3px rgba(20, 28, 20, 0.35);

  /* —— Overlays —— */
  --overlay-pine: rgba(22, 36, 26, 0.55);
  --img-overlay-bottom: linear-gradient(
    to top, rgba(22,36,26,0.78) 0%, rgba(22,36,26,0.28) 38%, rgba(22,36,26,0) 70%
  );
}


/* ============================================================
   3. BASE / RESET
   ============================================================ */

html {
  scroll-behavior: smooth;
  scroll-padding-top: 96px; /* clears sticky header on anchor jumps */
  color-scheme: light;
}

body {
  background: var(--surface-page);
  color: var(--text-body);
  font-family: var(--font-sans);
  font-size: var(--t-body);
  line-height: var(--lh-body);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* Divi resets <a> color globally — re-establish brand link color */
a {
  color: var(--accent-strong);
}

/* Images are block by default (prevents descender gap below inline images) */
img {
  display: block;
  max-width: 100%;
}

/* Divi's own base.css sets `blockquote { border-left: 5px solid;
   padding-left: 20px }` with no border-color of its own, so it inherits
   the browser's default currentColor-ish link-blue — the "blue left
   border" on every quote site-wide. The reference
   (deadstop-web-projects.vercel.app/about) has no border on its quotes
   at all, just italic display type. This is a plain, unscoped reset (no
   class, no !important) so it applies everywhere automatically; sections
   that set their own border inline (e.g. Legacy's bronze accent line)
   are untouched, since an inline style always wins over an external
   stylesheet rule regardless of what this says. */
blockquote {
  border-left: none;
  padding-left: 0;
}


/* ============================================================
   4. SKIP NAVIGATION + FOCUS
   ============================================================ */

.skip-to-content {
  position: absolute;
  top: -100%;
  left: 16px;
  z-index: 99999;
  background: var(--bronze-500);
  color: var(--paper);
  padding: 8px 16px;
  font-family: var(--font-sans);
  font-size: 14px;
  font-weight: var(--w-semibold);
  text-decoration: none;
  border-radius: var(--radius-sm);
  transition: top var(--dur-fast) var(--ease-out);
}
.skip-to-content:focus {
  top: 16px;
}

/* Global focus ring — overrides Divi's focus reset */
*:focus-visible {
  outline: none !important;
  box-shadow: var(--focus-ring) !important;
}


/* ============================================================
   5. TYPOGRAPHY UTILITY CLASSES
   Divi Presets accept fixed px values only — no clamp() support.
   Apply these classes via Module > Advanced > CSS Class in Divi.
   ============================================================ */

/* Hero H1 — home, Stringfield, Serenity, Legacy heroes */
.hero-headline {
  font-family: var(--font-display) !important;
  font-size: clamp(48px, 7.4vw, 104px) !important;
  font-weight: 400 !important;
  line-height: 0.98 !important;
  letter-spacing: var(--ls-display) !important;
  color: var(--paper) !important;
}
.hero-headline em {
  font-style: italic;
  color: var(--bronze-200);
}

/* Client feedback (July 2026): "Scroll" showed behind The Vision button —
   see the comment in home/hero.php on .hero-scroll-cue for why. Hidden
   below 768px rather than fine-tuning its position. */
@media (max-width: 768px) {
  .hero-scroll-cue {
    display: none;
  }
}

/* Homepage hero background — dg-hero.js drives the scroll-linked zoom via
   inline transform; this only disables the frame-to-frame transition smoothing
   for users who've asked for reduced motion (the JS itself no-ops for them). */
@media (prefers-reduced-motion: reduce) {
  .hero-img { transition: none; }
}

/* Section H1 — LegacyHero editorial headline */
.dg-h1-display {
  font-family: var(--font-display) !important;
  font-size: clamp(44px, 7vw, 96px) !important;
  font-weight: 400 !important;
  line-height: 1.0 !important;
  letter-spacing: var(--ls-display) !important;
}

/* Section H2 — main section headings */
.dg-h2-section {
  font-family: var(--font-display) !important;
  font-size: clamp(30px, 3.8vw, 52px) !important;
  font-weight: 400 !important;
  line-height: 1.06 !important;
  letter-spacing: var(--ls-display) !important;
}

/* Editorial paragraph headings — VEthos, IntroStatement, JeffSection quote */
.dg-h3-editorial {
  font-family: var(--font-display) !important;
  font-size: clamp(26px, 3.4vw, 40px) !important;
  font-weight: 400 !important;
  line-height: 1.32 !important;
  letter-spacing: var(--ls-tight) !important;
}

/* Hero sub-paragraph — large intro text below hero headlines */
.dg-hero-sub {
  font-family: var(--font-sans) !important;
  font-size: clamp(17px, 1.6vw, 22px) !important;
  line-height: 1.6 !important;
}

/* Eyebrow override class for Divi Text modules */
.dg-eyebrow {
  font-family: var(--font-sans) !important;
  font-size: var(--t-eyebrow) !important;
  font-weight: var(--w-semibold) !important;
  letter-spacing: var(--ls-eyebrow) !important;
  text-transform: uppercase !important;
  color: var(--accent) !important;
}


/* ============================================================
   6. EYEBROW COMPONENT
   Used in SectionHeading and stand-alone as Code Module HTML.
   ============================================================ */

.eyebrow-rule {
  display: flex;
  align-items: center;
  gap: 14px;
  font-family: var(--font-sans);
  font-size: var(--t-eyebrow);
  font-weight: var(--w-semibold);
  letter-spacing: var(--ls-eyebrow);
  text-transform: uppercase;
  color: var(--accent);
  margin: 0;
}
.eyebrow-rule::before {
  content: '';
  display: block;
  width: 24px;
  height: 1.5px;
  background: var(--rule-accent);
  flex-shrink: 0;
}

/* Centered variant — IntroStatement, VEthos */
.eyebrow-center {
  justify-content: center;
  text-align: center;
}

/* On-dark variant — hero, VisionBand, VInquiry */
.eyebrow-on-dark {
  color: var(--paper-78);
}
.eyebrow-on-dark::before {
  background: var(--paper-78);
}


/* ============================================================
   7. STAT BLOCK COMPONENT
   HTML lives in Divi Code Modules. counter.js animates .stat-value.
   ============================================================ */

.stat-block {
  padding: 0;
}

.stat-number {
  display: flex;
  align-items: baseline;
  gap: 6px;
  line-height: 1;
}

.stat-value {
  font-family: var(--font-display);
  font-size: clamp(36px, 4.5vw, 60px);
  font-weight: 400;
  letter-spacing: var(--ls-display);
  color: var(--text-heading);
  font-variant-numeric: lining-nums;
}

.stat-unit {
  font-family: var(--font-display);
  font-size: clamp(18px, 2vw, 26px);
  font-weight: 400;
  font-style: italic;
  color: var(--accent);
  letter-spacing: 0;
}

.stat-label {
  font-family: var(--font-sans);
  font-size: var(--t-small);
  font-weight: var(--w-medium);
  letter-spacing: var(--ls-caps);
  text-transform: uppercase;
  color: var(--text-muted);
  margin: 10px 0 0;
}

/* Dark-surface variant — used inside inverse sections */
.stat-block.stat-on-dark .stat-value {
  color: var(--paper);
}
.stat-block.stat-on-dark .stat-unit {
  color: var(--bronze-200);
}
.stat-block.stat-on-dark .stat-label {
  color: var(--pine-100);
}

/* Stat grid — 4-col on desktop, 2-col on mobile */
.stat-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 8px;
  border-top: 1px solid var(--border-hairline);
  padding-top: 48px;
  margin-top: 72px;
}
.stat-grid > * + * {
  border-left: 1px solid var(--border-soft);
  padding-left: clamp(16px, 2.5vw, 40px);
}
.stat-grid-3 {
  grid-template-columns: repeat(3, 1fr);
}

@media (max-width: 640px) {
  .stat-grid,
  .stat-grid-3 {
    grid-template-columns: repeat(2, 1fr);
    text-align: center;
  }
  .stat-grid > * + *,
  .stat-grid-3 > * + * {
    border-left: none;
    padding-left: 0;
  }
}


/* ============================================================
   8. SECTION HEADING OVERRIDES
   Target Divi Text modules assigned these CSS classes.
   ============================================================ */

/* SectionHeading wrappers */
.dg-section-heading {
  margin: 0;
}
.dg-section-heading .eyebrow-rule {
  margin-bottom: 20px;
}
.dg-section-heading h2 {
  font-family: var(--font-display);
  font-weight: 400;
  color: var(--text-heading);
  margin: 0 0 20px;
}
.dg-section-heading .intro {
  font-family: var(--font-sans);
  font-size: var(--t-lead);
  line-height: var(--lh-relaxed);
  color: var(--text-body);
  margin: 0;
}

/* Dark tone — VisionBand, hero overlays */
.dg-section-heading.tone-dark h2,
.dg-section-heading.tone-dark .intro {
  color: var(--paper);
}
.dg-section-heading.tone-dark .intro {
  color: var(--pine-100);
}


/* ============================================================
   9. BUTTON STYLES
   NOTE: originally written for native Divi Button Modules (hence the
   `.et_pb_button` co-selector on every rule below), from the pre-pivot
   plan described in SHORTCODE_IMPLEMENTATION.md §1. The shortcode
   partials actually render plain `<a class="btn dg-btn-*">` links —
   they never carry `.et_pb_button` — so every rule here was silently
   matching nothing site-wide. Rewritten to target `.btn` (the class
   every partial actually applies) instead, plus a `.btn` base rule
   for the display/cursor/text-decoration these links no longer
   inherited from Divi's own module CSS either.
   ============================================================ */

.btn,
.btn:active,
.btn:focus {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px; /* reference md gap; .dg-btn-lg widens to 12px below */
  text-align: center;
  text-decoration: none;
  line-height: 1;
  white-space: nowrap;
  cursor: pointer;
  transform: none !important;
}

/* Button icon — arrow nudges on hover/focus for EVERY .btn variant, at
   --dur-base, mirroring the reference's `.btn svg` rules exactly
   (app/globals.css §Button icon): same trigger set (hover AND
   focus-visible), same 3px nudge, same duration, same
   prefers-reduced-motion opt-out. */
.btn .btn-icon,
.btn svg {
  flex-shrink: 0;
  transition: transform var(--dur-base) var(--ease-out);
}
.btn:hover .btn-icon,
.btn:hover svg,
.btn:focus-visible .btn-icon,
.btn:focus-visible svg {
  transform: translateX(3px);
}
/* Back-to-top is not a .btn — its arrow lifts up 2px, per the reference
   BackToTop component. */
.footer-back-to-top:hover .btn-icon,
.footer-back-to-top:focus-visible .btn-icon {
  transform: translateY(-2px);
}
@media (prefers-reduced-motion: reduce) {
  .btn .btn-icon,
  .btn svg,
  .footer-back-to-top .btn-icon {
    transition: none;
  }
  .btn:hover .btn-icon,
  .btn:hover svg,
  .btn:focus-visible .btn-icon,
  .btn:focus-visible svg,
  .footer-back-to-top:hover .btn-icon,
  .footer-back-to-top:focus-visible .btn-icon {
    transform: none;
  }
}

/* — Primary / pine background — */
.dg-btn-primary.btn,
.dg-btn-primary.btn:hover {
  font-family: var(--font-sans) !important;
  font-size: 13px !important;
  font-weight: var(--w-semibold) !important;
  letter-spacing: var(--ls-caps) !important;
  text-transform: uppercase !important;
  background-color: var(--pine-700) !important;
  color: var(--paper) !important;
  /* Reference gives EVERY button a 1px border (transparent on solid
     variants) so solid and outline buttons render identical heights. */
  border: 1px solid transparent !important;
  border-radius: var(--radius-sm) !important;
  padding: 14px 28px !important;
  transition: background-color var(--dur-fast) var(--ease-out),
              color var(--dur-fast) var(--ease-out),
              border-color var(--dur-fast) var(--ease-out) !important;
}
.dg-btn-primary.btn:hover {
  background-color: var(--pine-900) !important;
}

/* — Accent / bronze background (primary CTA) — */
.dg-btn-accent.btn,
.dg-btn-accent.btn:hover {
  font-family: var(--font-sans) !important;
  font-size: 13px !important;
  font-weight: var(--w-semibold) !important;
  letter-spacing: var(--ls-caps) !important;
  text-transform: uppercase !important;
  background-color: var(--bronze-500) !important;
  color: var(--paper) !important;
  border: 1px solid transparent !important;
  border-radius: var(--radius-sm) !important;
  padding: 14px 28px !important;
  transition: background-color var(--dur-fast) var(--ease-out),
              color var(--dur-fast) var(--ease-out),
              border-color var(--dur-fast) var(--ease-out) !important;
}
.dg-btn-accent.btn:hover {
  background-color: var(--bronze-600) !important;
}

/* — Outline — transparent with pine border — */
.dg-btn-outline.btn,
.dg-btn-outline.btn:hover {
  font-family: var(--font-sans) !important;
  font-size: 13px !important;
  font-weight: var(--w-semibold) !important;
  letter-spacing: var(--ls-caps) !important;
  text-transform: uppercase !important;
  background-color: transparent !important;
  color: var(--pine-700) !important;
  /* 1px like the reference — solid variants carry a transparent 1px
     border, so heights match with identical 14px padding, no
     compensation needed. */
  border: 1px solid var(--pine-700) !important;
  border-radius: var(--radius-sm) !important;
  padding: 14px 28px !important;
  transition: background-color var(--dur-fast) var(--ease-out),
              color var(--dur-fast) var(--ease-out),
              border-color var(--dur-fast) var(--ease-out) !important;
}
.dg-btn-outline.btn:hover {
  background-color: var(--pine-700) !important;
  color: var(--paper) !important;
}

/* — Outline on dark — paper border (transparent header hero) — */
.dg-btn-outline-dark.btn {
  color: var(--paper) !important;
  border-color: var(--paper-55) !important;
}
.dg-btn-outline-dark.btn:hover {
  background-color: var(--paper-12) !important;
  border-color: var(--paper-78) !important;
}

/* — Link / text button — */
.dg-btn-link.btn,
.dg-btn-link.btn:hover {
  font-family: var(--font-sans) !important;
  font-size: 13px !important;
  font-weight: var(--w-semibold) !important;
  letter-spacing: -0.01em !important;
  background: none !important;
  /* Reference link variant underlines with a 1px accent border-bottom
     (transparent on the other edges), animating to pine on hover. */
  border: 1px solid transparent !important;
  border-bottom-color: var(--accent) !important;
  border-radius: 0 !important;
  color: var(--accent-strong) !important;
  padding: 0 !important;
  text-decoration: none !important;
  transition: color var(--dur-fast) var(--ease-out),
              border-color var(--dur-fast) var(--ease-out) !important;
}
.dg-btn-link.btn:hover {
  color: var(--pine-700) !important;
  border-bottom-color: var(--pine-700) !important;
}

/* Large size modifier — hero CTAs. Reference lg spec: 18px 38px padding,
   14px type, 12px icon gap. No outline compensation needed — every
   variant carries a 1px border (transparent on solids), so paddings
   stay uniform.
   The :hover co-selector is load-bearing: the variant rules above declare
   their md-size padding/font-size on `.dg-btn-*.btn:hover` (specificity
   0,3,0), which out-ranks a plain `.dg-btn-lg.btn` (0,2,0) the moment the
   button is hovered — large buttons visibly SHRANK to md size on hover
   (client-reported July 2026). Declaring lg with the same :hover
   co-selector ties the specificity and wins by source order in both
   states. */
.dg-btn-lg.btn,
.dg-btn-lg.btn:hover {
  padding: 18px 38px !important;
  font-size: 14px !important;
  gap: 12px;
}


/* ============================================================
   10. COMMUNITY CARD
   Card HTML lives in Divi Code Modules. 3-column grid on desktop.
   ============================================================ */

.community-card {
  position: relative;
  border-radius: var(--radius-card);
  overflow: hidden;
  background: var(--surface-card);
  box-shadow: var(--shadow-sm);
  transition: box-shadow var(--dur-base) var(--ease-out),
              transform var(--dur-base) var(--ease-out);
}
.community-card:hover {
  transform: translateY(-3px);
  /* Client revision (July 2026): was var(--shadow-lg) (0 28px 60px), which
     read much heavier than the team cards further down the page. This is
     the team-card hover shadow from the design system, so both card
     families lift with the same weight. */
  box-shadow: 0 16px 30px -18px rgba(22, 36, 26, 0.28);
}

/* Full-card clickable overlay — stretches over the entire card */
.card-link-overlay {
  position: absolute;
  inset: 0;
  z-index: 1;
  text-indent: -9999px;
}

/* Prevents the official external link from being covered by overlay */
.card-official-link {
  position: relative;
  z-index: 2;
}

.card-image {
  position: relative;
  overflow: hidden;
  aspect-ratio: 3 / 4;
}
.card-image img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform var(--dur-slow) var(--ease-out);
}
.community-card:hover .card-image img {
  transform: scale(1.04);
}

.card-tag {
  position: absolute;
  bottom: 14px;
  left: 14px;
  z-index: 2;
  font-family: var(--font-sans);
  font-size: 11px;
  font-weight: var(--w-semibold);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  padding: 5px 10px;
  border-radius: var(--radius-pill);
}
.tag-available {
  background: var(--pine-700);
  color: var(--paper);
}
.tag-reserved {
  background: var(--bronze-500);
  color: var(--paper);
}
.tag-sold {
  background: var(--ink-700);
  color: var(--paper);
}

.card-content {
  padding: 22px 24px 28px;
}
.card-content .eyebrow-rule {
  font-size: 11px;
  margin-bottom: 8px;
}
.card-content h3 {
  font-family: var(--font-display);
  font-size: 22px;
  font-weight: 400;
  color: var(--text-heading);
  margin: 0 0 10px;
  line-height: 1.15;
}
.card-excerpt {
  font-family: var(--font-sans);
  font-size: var(--t-small);
  line-height: 1.65;
  color: var(--text-body);
  margin: 0 0 8px;
}
.card-meta {
  font-family: var(--font-sans);
  font-size: 12.5px;
  color: var(--text-muted);
  letter-spacing: 0.04em;
  margin: 0 0 14px;
}

/* Official external link inside the card */
.official-link {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: var(--font-sans);
  font-size: 13px;
  font-weight: var(--w-semibold);
  letter-spacing: 0.01em;
  color: var(--accent-strong);
  text-decoration: none;
}
.official-link svg {
  width: 13px;
  height: 13px;
  transition: transform var(--dur-base) var(--ease-out);
}
.official-link:hover svg,
.official-link:focus-visible svg {
  transform: translate(2px, -2px);
}


/* ============================================================
   11. CARD-LIFT SHADOW EFFECT
   Applied to the inquiry form card and any elevated card surface.
   ============================================================ */

.card-lift {
  position: relative;
}
.card-lift::before,
.card-lift::after {
  content: '';
  position: absolute;
  z-index: -1;
  bottom: 26px;
  top: 80%;
  width: 47%;
  max-width: 350px;
  background: rgba(22, 36, 26, 0.5);
  box-shadow: 0 26px 28px rgba(22, 36, 26, 0.5);
}
.card-lift::before {
  left: 14px;
  transform: rotate(-6deg);
}
.card-lift::after {
  right: 14px;
  transform: rotate(6deg);
}


/* ============================================================
   12. OFFICIAL-LINK / EXTERNAL LINK (standalone, outside cards)
   ============================================================ */

.link-external {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-family: var(--font-sans);
  font-size: 13px;
  font-weight: var(--w-semibold);
  letter-spacing: 0.04em;
  color: var(--accent-strong);
  text-decoration: none;
  text-transform: uppercase;
}
.link-external svg {
  transition: transform var(--dur-base) var(--ease-out);
}
.link-external:hover svg,
.link-external:focus-visible svg {
  transform: translate(2px, -2px);
}


/* ============================================================
   13. HEADER (dg-header, dg-scroll-bar, page-template-*)
   .dg-header must be assigned as a CSS Class on the Theme Builder
   header Section (Section > Advanced > CSS Class).
   ============================================================ */

/* Base transition — always present */
.dg-header {
  /* The reference header is pinned via `position: fixed`. Divi's Theme
     Builder header template has its own "Fixed Position" toggle that's
     meant to do this, but if that toggle is ever off (or reset) the header
     silently falls back to static/relative flow and scrolls away with the
     page. Setting it here in CSS makes the pinned header a guarantee of
     the theme rather than a Divi setting someone has to remember to keep
     enabled. */
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 500;
  /* Divi's Theme Builder assigns this header section a Custom Margin of
     15px top/bottom by default (its own generated inline rule,
     `.et_pb_section_0_tb_header.et_pb_section { margin: 15px 0 }` — 2
     classes). That beats a plain `.dg-header { margin: 0 }` (1 class) on
     specificity alone even with neither side using !important, which is
     why a first pass at this rule had no effect — confirmed directly by
     inspecting computed styles after deploying it. A fixed-position
     element still respects its own margin box, so that 15px top margin
     was pushing the header down from the viewport's actual top edge — the
     "gap above the header" visible on the public, logged-out site
     (nothing to do with the wp-admin toolbar). !important forces the win
     regardless of Divi's class count. */
  margin: 0 !important;
  /* No `top` in this transition list. Below, dg-header.js re-reads the
     WordPress admin bar's real position once per animation frame while
     scrolling (mobile, logged-in, ≤600px) and writes it straight to `top`
     via a CSS custom property — a transition on `top` would fight that
     per-frame write and read as lag/rubber-banding rather than the header
     tracking the bar 1:1. Nothing to disable for reduced-motion either:
     there's no animation here, just a value re-read on scroll. */
  transition: background var(--dur-base) var(--ease-out),
              backdrop-filter var(--dur-base) var(--ease-out),
              box-shadow var(--dur-base) var(--ease-out);
}

/* Logged-in admin-bar offset — public/logged-out visitors must always see
   `top: 0` (the rule above); WordPress's own black toolbar is fixed at
   32px (46px under its own 782px mobile breakpoint) and pushes fixed-
   position elements down to clear it. Scoped strictly to `body.admin-bar`
   so this never affects the real, logged-out site. */
body.admin-bar .dg-header {
  top: 32px;
}
@media (max-width: 782px) {
  body.admin-bar .dg-header {
    top: 46px;
  }
}

/* Mobile-breakpoint recurrence of the "gap above the header" bug fixed
   above for desktop. Divi's Theme Builder lets a Custom Margin be set
   independently per responsive breakpoint (Desktop/Tablet/Phone), each
   generating its own per-instance rule
   (`.et_pb_section_0_tb_header.et_pb_section { margin: ... }`, 2 classes)
   inside its own `@media` block — fixing the desktop-tier value above did
   nothing for the Tablet/Phone tiers, which are separate declarations, not
   inherited overrides.
   Reuses the same `body #page-container` ID-anchored specificity boost
   used elsewhere in this file to beat Divi's per-instance rules outright,
   rather than trying to out-count Divi's class total.
   `top` is intentionally split by admin-bar state, not just forced to 0 —
   an earlier version of this rule forced `top: 0 !important`
   unconditionally, which (being !important) beat the plain, non-important
   `body.admin-bar .dg-header { top: 46px }` rule above regardless of
   specificity, shoving the header up under the WP admin toolbar for any
   logged-in visitor testing on a phone and breaking the hamburger's click
   target — confirmed as the cause of the "hamburger doesn't open"
   regression this introduced. Matching each case's own correct value
   instead of overriding both to 0 fixes the gap without re-breaking the
   logged-in case. */
@media (max-width: 980px) {
  body #page-container .dg-header {
    margin: 0 !important;
  }
  body:not(.admin-bar) #page-container .dg-header {
    top: 0 !important;
  }
  body.admin-bar #page-container .dg-header {
    top: 46px !important;
  }
}

/* Continuous admin-bar tracking — companion to the rule directly above,
   not a replacement for it. Below WordPress core's own 600px breakpoint,
   WordPress itself switches #wpadminbar from position: fixed to
   position: absolute (wp-includes/css/admin-bar.min.css — not this theme),
   specifically so the toolbar stops permanently occupying screen space on a
   phone. The `top: 46px` rule above assumes the bar stays fixed and visible
   forever; it doesn't below 600px — it scrolls away with the page like any
   other in-flow content. A discrete "has it fully cleared yet" toggle still
   leaves a real, visible gap for the entire scroll distance while the bar
   is mid-scroll (up to ~46px, however briefly) — closing the gap only once
   scrolling is already finished doesn't satisfy "no gap at any point."
   dg-header.js instead re-reads the bar's own actual
   getBoundingClientRect().bottom once per animation frame while scrolling
   (clamped to 0 once it's fully off-screen) and writes it to
   --dg-admin-bar-offset on this element — so `top` here always exactly
   equals however much of the bar is still visible, continuously, not just
   at rest or once-cleared. The `46px` fallback only matters for the first
   paint before that JS has run even once — it matches the bar's own full
   height, i.e. the correct value at scrollY 0, so there's no flash of an
   incorrect gap before JS takes over. Same specificity as the plain
   `body.admin-bar #page-container .dg-header` rule above; wins at ≤600px
   purely on source order (this block comes later), so it doesn't need to
   out-specificity that rule or duplicate its media query. Logged-out
   visitors never gain `.admin-bar`, so this selector never matches for
   them — the "do not affect logged-out users" requirement holds
   structurally, not just by convention. */
@media (max-width: 600px) {
  body.admin-bar #page-container .dg-header {
    top: var(--dg-admin-bar-offset, 46px) !important;
  }
}

/* Theme Builder header row — cancel Divi's generated margin-top: -8px.
   Confirmed present at both mobile (400px) and desktop (1400px) widths, so
   this is unscoped by breakpoint rather than living inside a media query —
   it's a flat Divi default, not one of the per-breakpoint Custom Margin
   values fought elsewhere in this file. Scoped to .et_pb_row_0_tb_header
   specifically (Divi's own per-instance class for this exact Theme Builder
   row) inside .dg-header, so no other Divi row on the site is touched.
   .dg-header sets no explicit height for this row to fill (only desktop
   gets min-height: 104px, below) — its own height is auto, computed from
   this row's box. With the -8px margin in place, the row rendered 8px
   taller than .dg-header's auto-computed height (74px row vs. 66px header
   at 400px width, confirmed live), so the row's top edge poked 8px above
   .dg-header's own top edge — exactly the "aerial image strip" gap
   mechanism, independent of the admin-bar issue above. Zeroing the margin
   doesn't shrink the row or clip anything: .dg-header's auto height simply
   grows to match the row's real height (66px -> 74px), so the row ends up
   fully contained instead of escaping past either edge. No negative margin
   used anywhere to compensate. */
.dg-header .et_pb_row_0_tb_header {
  margin-top: 0 !important;
}

/* Header row width/gutter/height — Divi's row default (1080px max-width,
   no horizontal padding, ~70px tall) was never overridden, so the header
   was noticeably more cramped than every other section on the site. The
   rest of the theme already standardizes on --content-max (1280px) and
   --gutter (clamp 20–80px, 72px at typical desktop widths) — reusing them
   here instead of guessing new values matches the reference's own
   computed 1280px / 72px / 104px exactly (checked directly). Scoped to
   Divi's own desktop breakpoint (980px+) so the mobile header (measured
   ~57–60px tall — see "MOBILE NAV PARITY LOCK" below) is untouched. */
@media (min-width: 981px) {
  .dg-header .et_pb_row {
    max-width: var(--content-max) !important;
    padding-left: var(--gutter) !important;
    padding-right: var(--gutter) !important;
    min-height: 104px;
  }

  /* Divi renders each header column as `flex-direction: column` with
     `justify-content: normal` (-> flex-start), which packs the logo/nav/
     button to the TOP of the 104px row instead of centering them —
     confirmed directly: logo sat 5px from the row top instead of the
     22px a centered 60px-tall logo needs, nav sat 12px instead of 36.5px.
     The row itself was never too tall; the leftover space this left at
     the bottom of the row is exactly the "cream band" / "too much
     height" the header appeared to have. Centering the column's main
     axis (column direction = vertical main axis, so this is
     justify-content, not align-items) fixes logo, nav, and the INQUIRE
     button in one rule since all three columns share this layout. */
  .dg-header .et_pb_row > .et_pb_column {
    justify-content: center;
  }
}

/* Divi's own section-level default (`padding: 10px 10px 0`, asymmetric —
   10px top, 0 bottom) is superfluous now that the row above sets its own
   exact height and left/right gutter directly, and its asymmetry was
   compounding the top-packed-content issue above. */
.dg-header {
  padding: 0 !important;
}

/* Scrolled / solid state (JS adds .scrolled after 40px scroll) — applies
   once scrolled on every page, dark-hero or light-hero alike.
   Divi auto-generates its own per-instance rule for this exact header
   section's own (blank/none) Background Color setting:
   `.et-l--header > .et_builder_inner_content .et_pb_section.et_pb_section_0_tb_header
   { background-color: rgba(255,255,255,0) !important; }` — 4 classes,
   !important, beating a plain `.dg-header.scrolled`/`.dg-hero-light
   .dg-header` selector (2-3 classes) even with our own !important. This is
   why the header was staying visually transparent on every inner page
   (and once scrolled on the homepage) despite this rule "matching" —
   Divi's rule won specifically on the background-color component (the
   only one that actually needs opacity to render; the dark-hero
   transparent-gradient state below is unaffected because a gradient is a
   background-IMAGE, which Divi's rule never touches). `body
   #page-container` is the same ID-anchored specificity fix used
   elsewhere in this file for the same Divi-per-instance-rule problem. */
body #page-container .dg-header.scrolled {
  background: rgba(246, 241, 231, 0.78) !important;
  backdrop-filter: blur(18px);
  -webkit-backdrop-filter: blur(18px);
  box-shadow: 0 10px 30px -18px rgba(22, 36, 26, 0.30);
}

/* Light-hero pages — About, Inquire (body class set by functions.php's
   dg-hero-dark/dg-hero-light filter; NOT a home-vs-inner split, see that
   filter's comment) — transparent before scroll, same as dark-hero pages
   below, just without a gradient: these heroes are already a flat light
   surface (a portrait card on cream for About, the cream-gradient forest
   photo for Inquire), not a photo needing a scrim for text contrast, so
   the header simply has no fill until .scrolled. The existing ink-colored
   nav-link/logo/button rules elsewhere in this file already apply to
   `.dg-hero-light .dg-header` unconditionally (never scoped to
   `.scrolled`), so no companion color rule is needed here — only the
   background itself was ever forced solid pre-scroll.
   Client revision (July 2026): previously these pages had NO pre-scroll
   transparent state at all (solid immediately, unlike every other page) —
   restored here to match Home/Stringfield/Serenity/Legacy's behavior. */
.dg-hero-light .dg-header:not(.scrolled) {
  background: transparent !important;
  box-shadow: none;
}

/* Dark-hero pages — Home, Stringfield, Serenity, Legacy — transparent
   gradient before scroll */
.dg-hero-dark .dg-header:not(.scrolled) {
  background: linear-gradient(
    to bottom,
    rgba(22, 36, 26, 0.62) 0%,
    rgba(22, 36, 26, 0.30) 54%,
    rgba(22, 36, 26, 0) 100%
  ) !important;
  box-shadow: none;
}

/* Confirmed live (July 2026): the header row is intentionally translucent
   pre-scroll on dark-hero pages (the gradient above, a see-through
   overlay on the hero photo, not a fill) — correct behind just the logo,
   but wrong once the mobile nav panel opens directly beneath it, since
   that panel is solid (--paper-98). The translucent row sitting on a
   solid panel reads as a broken transparent gap right at the seam
   between them, not two parts of one header. dg-header.js adds
   `.dg-mobile-nav-is-open` to `.dg-header` for exactly this window, so
   the row can go solid to match the panel regardless of scroll or hero
   state. `body #page-container` + both classes matches or exceeds every
   selector this needs to beat — the gradient rule above (3 classes),
   Divi's own generated per-instance background-color rule (4 classes),
   and the .scrolled/light-hero solid rule (ID + 2 classes) alike. */
body #page-container .dg-header.dg-mobile-nav-is-open {
  background: var(--paper-98) !important;
  backdrop-filter: saturate(140%) blur(10px);
  -webkit-backdrop-filter: saturate(140%) blur(10px);
  box-shadow: var(--shadow-md);
}

/* Nav link typography — the Divi Menu module ships its own theme default
   (Abel, 700, 14px, no letter-spacing, 0.4s ease-in-out color transition)
   and nothing here was ever overriding it, only color was. That default
   font is exactly why the header read as "still Divi" rather than the
   reference — values below are the reference's own computed styles
   (Hanken Grotesk / 500 / 15px / 0.6px letter-spacing / 0.18s cubic-bezier),
   not a guess.
   NOTE: the Divi Menu module renders the real nav as .et-menu-nav > ul.et-menu,
   not .et_pb_menu__nav — that class does not exist in the rendered DOM, so
   every rule below targets both to cover Divi's actual markup. */
.dg-header .et_pb_menu__nav > ul > li > a,
.dg-header .et-menu-nav > ul > li > a {
  font-family: var(--font-sans) !important;
  font-size: 15px !important;
  font-weight: var(--w-medium) !important;
  letter-spacing: 0.04em !important;
  transition: color var(--dur-fast) var(--ease-out) !important;
  position: relative;
  padding-bottom: 2px;
}
.dg-header .et_pb_menu__nav > ul,
.dg-header .et-menu-nav > ul {
  gap: 32px;
}
/* Divi's own <li> already carries `padding: 0 11px` as its spacing
   mechanism — adding `gap` on top of that (rather than instead of it)
   stacked both, pushing the effective gap to ~54px and overflowing the
   row width, which is what wrapped "About"/INQUIRE onto a second line.
   Zeroing it out here makes `gap: 32px` the only spacing mechanism,
   matching the reference exactly (a plain flex `gap`, no per-item
   padding). */
.dg-header .et_pb_menu__nav > ul > li,
.dg-header .et-menu-nav > ul > li {
  padding-left: 0 !important;
  padding-right: 0 !important;
}

/* Nav link color — dark-hero pages before scroll (paper text).
   Deliberately NOT using the bare `.et_pb_menu__nav a` / `.et-menu-nav a`
   descendant form here (only the `> ul > li > a` top-level form) — that
   broader selector also matches links inside `ul.sub-menu` (About Jeff,
   Legacy), and at 4 classes it beat the dedicated `.sub-menu a { color:
   ink-700 !important }` rule below (3 classes) on specificity. The
   dropdown panel itself is always the solid paper-98 fill regardless of
   header state, so its links forcing paper-96 text read as
   near-invisible white-on-cream — confirmed directly on a dark-hero page
   before scroll. Scoping to top-level links only lets the submenu rule's
   ink-700 apply the way it already does correctly once scrolled. */
.dg-hero-dark .dg-header:not(.scrolled) .et_pb_menu__nav > ul > li > a,
.dg-hero-dark .dg-header:not(.scrolled) .et-menu-nav > ul > li > a {
  color: var(--paper-96) !important;
  text-shadow: var(--text-shadow-on-dark);
}
.dg-hero-dark .dg-header:not(.scrolled) .et_pb_menu__nav > ul > li > a:hover,
.dg-hero-dark .dg-header:not(.scrolled) .et-menu-nav > ul > li > a:hover {
  color: var(--paper) !important;
}

/* Divi auto-generates its own per-instance rule for the active nav item —
   `.et_pb_menu_0_tb_header.et_pb_menu ul li.current-menu-item > a { color:
   var(--gcid-body-color) !important }` (3 classes, !important) — which beat
   both color rules below (2 classes each, also !important) specifically on
   "The Communities" (the current-page link), leaving it stuck gray in every
   header state instead of following paper/ink like every other link.
   `body #page-container` is the same ID-anchored specificity fix already
   used elsewhere in this file for the same class of Divi-rule conflict. */
body #page-container .dg-hero-dark .dg-header:not(.scrolled) .et-menu-nav > ul > li.current-menu-item > a {
  color: var(--paper-96) !important;
}
body #page-container .dg-header.scrolled .et-menu-nav > ul > li.current-menu-item > a,
body.dg-hero-light #page-container .dg-header .et-menu-nav > ul > li.current-menu-item > a {
  color: var(--ink-700) !important;
}

/* Nav link color — solid header (ink text) */
.dg-header.scrolled .et_pb_menu__nav a,
.dg-hero-light .dg-header .et_pb_menu__nav a,
.dg-header.scrolled .et-menu-nav a,
.dg-hero-light .dg-header .et-menu-nav a {
  color: var(--ink-700) !important;
  text-shadow: none;
}
.dg-header.scrolled .et_pb_menu__nav > ul > li > a:hover,
.dg-hero-light .dg-header .et_pb_menu__nav > ul > li > a:hover,
.dg-header.scrolled .et-menu-nav > ul > li > a:hover,
.dg-hero-light .dg-header .et-menu-nav > ul > li > a:hover {
  color: var(--accent-strong) !important;
}

/* Active-page underline. On the reference this is NOT a hover effect —
   confirmed directly: hovering a non-current link does nothing, only the
   link matching aria-current="page" keeps a permanent underline
   (scaleX(1), transform-origin left, 0.32s reveal on the route that just
   became active). The previous version of this rule also fired on
   `:hover`, which the reference never does — every link would show a
   transient underline that isn't part of the real design. */
.dg-header .et_pb_menu__nav > ul > li:not(.menu-item-has-children) > a::after,
.dg-header .et-menu-nav > ul > li:not(.menu-item-has-children) > a::after {
  content: '';
  position: absolute;
  bottom: -3px;
  left: 0;
  width: 100%;
  height: 1px;
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--dur-base) var(--ease-out);
}
.dg-header.scrolled .et_pb_menu__nav > ul > li:not(.menu-item-has-children) > a::after,
.dg-hero-light .dg-header .et_pb_menu__nav > ul > li:not(.menu-item-has-children) > a::after,
.dg-header.scrolled .et-menu-nav > ul > li:not(.menu-item-has-children) > a::after,
.dg-hero-light .dg-header .et-menu-nav > ul > li:not(.menu-item-has-children) > a::after {
  background: var(--accent);
}
.dg-hero-dark .dg-header:not(.scrolled) .et_pb_menu__nav > ul > li:not(.menu-item-has-children) > a::after,
.dg-hero-dark .dg-header:not(.scrolled) .et-menu-nav > ul > li:not(.menu-item-has-children) > a::after {
  background: var(--paper-75);
}
.dg-header .et_pb_menu__nav > ul > li.current-menu-item:not(.menu-item-has-children) > a::after,
.dg-header .et-menu-nav > ul > li.current-menu-item:not(.menu-item-has-children) > a::after {
  transform: scaleX(1);
}

/* Dropdown caret ("About") — Divi's own ::after icon-font indicator on
   menu-item-has-children. Excluded from the underline rules above (they'd
   otherwise clip its glyph to height:1px, i.e. this exact bug — invisible
   regardless of color). Only recolor it here to follow the same
   paper/ink swap the link text itself uses. */
.dg-hero-dark .dg-header:not(.scrolled) .et_pb_menu__nav > ul > li.menu-item-has-children > a::after,
.dg-hero-dark .dg-header:not(.scrolled) .et-menu-nav > ul > li.menu-item-has-children > a::after {
  color: var(--paper-96) !important;
}
.dg-header.scrolled .et_pb_menu__nav > ul > li.menu-item-has-children > a::after,
.dg-hero-light .dg-header .et_pb_menu__nav > ul > li.menu-item-has-children > a::after,
.dg-header.scrolled .et-menu-nav > ul > li.menu-item-has-children > a::after,
.dg-hero-light .dg-header .et-menu-nav > ul > li.menu-item-has-children > a::after {
  color: var(--ink-700) !important;
}

/* Dropdown menu — fully opaque --paper, not --paper-98. This panel has no
   backdrop-filter to mask the underlying 2% transparency, and near the
   bottom of a short page it overlays the dark footer directly (fixed
   header, dropdown extending below it) — confirmed live: --paper-98's
   0.98 alpha was just enough for the "Back to top" button to ghost
   through the panel's cream fill. --paper is the same #F6F1E7 color at
   100% alpha, so this is opacity-only, no visible color change on any
   page where the bleed-through wasn't happening. */
.dg-header .et_pb_menu__nav ul.sub-menu,
.dg-header .et-menu-nav ul.sub-menu {
  background: var(--paper) !important;
  border-top: 2px solid var(--accent) !important;
  box-shadow: var(--shadow-md);
  border-radius: 0 0 var(--radius-md) var(--radius-md);
}
.dg-header .et_pb_menu__nav ul.sub-menu a,
.dg-header .et-menu-nav ul.sub-menu a {
  font-family: var(--font-sans) !important;
  font-size: 14px !important;
  font-weight: var(--w-medium) !important;
  letter-spacing: 0.04em !important;
  color: var(--ink-700) !important;
  padding: 11px 22px !important;
  transition: color var(--dur-fast) var(--ease-out),
              background-color var(--dur-fast) var(--ease-out) !important;
}
.dg-header .et_pb_menu__nav ul.sub-menu a:hover,
.dg-header .et-menu-nav ul.sub-menu a:hover {
  color: var(--accent-strong) !important;
  background-color: rgba(156, 107, 66, 0.06) !important;
}

/* Logo sizing — originally matched the reference's own fixed pixel sizes
   exactly (248x60 unscrolled, 210x48 scrolled/inner — read directly from
   its rendered inline styles, not a guess). The unscrolled height was
   bumped from 60px to 68px on an earlier client request, then to 87px
   (July 2026: "increase Davis Group logo by 25-30% at least" — 68px
   +28%). Scrolled/inner height scaled by the same ~28% (48px → 61px) to
   keep the same before/after size ratio on scroll, rather than leaving
   it fixed and shrinking the jump disproportionately.
   The logo is TWO separate Divi Image modules (dark + light variants,
   see "INQUIRE header CTA" note below on the button for the parallel
   story) — `.et_pb_menu__logo`/`.logo_container` were leftover from
   when this assumed the Divi Menu module's own built-in logo slot.
   Since the dark/light swap moved it to plain Image modules, those
   selectors never matched anything and the logo rendered completely
   unconstrained (auto-sized off the source file's natural dimensions)
   at every viewport, not just mobile — this is why it looked wrong
   everywhere, not only on narrow screens. `.et_pb_image_wrap` is
   Divi's own stable wrapper class for every Image module, not a
   fragile per-instance one. */
.dg-header .et_pb_image_wrap img {
  height: 40px !important;
  width: auto !important;
  /* The mark is a wide horizontal co-brand lockup ("The Davis Group" +
     "Realty ONE Group Mountain Desert"), viewBox 642.26 x 135.25 (~4.75:1).
     Height-pinned with width:auto, so 40px tall renders ~190px wide on
     desktop, 34px ~161px scrolled/mobile. Divi's own phone-breakpoint
     per-instance width (e.g. `.et_pb_image_1_tb_header { width: 55px }`,
     generated by the Theme Builder's responsive image-module-width setting)
     squeezes the flex item's cross size below the logo's true aspect ratio;
     `flex-shrink: 0` on the image and its two ancestor wrappers stops that
     per-instance width from compressing it. */
  flex-shrink: 0 !important;
  transition: height var(--dur-base) var(--ease-out);
}
.dg-header .et_pb_image_0_tb_header,
.dg-header .et_pb_image_1_tb_header,
.dg-header .et_pb_image_wrap {
  width: auto !important;
  flex-shrink: 0 !important;
}
.dg-header.scrolled .et_pb_image_wrap img,
.dg-hero-light .dg-header .et_pb_image_wrap img {
  height: 34px !important;
}

/* Dark/light logo swap — two Divi Image modules in the same header row:
   et_pb_image_0_tb_header (dark logo) and et_pb_image_1_tb_header (white
   logo). Divi has its own generated rule for the white-logo module,
   `.et_pb_image_1_tb_header { display: none; }` — a module-level toggle
   set in the Divi builder itself, not anything in this theme's files —
   which hides it unconditionally. That never mattered while
   dg-hero-dark pages were incorrectly forced solid (dark logo on a solid
   header is correct), but now that they correctly go transparent before
   scroll, the white logo needs to actually show there. Divi's rule is a
   single class with no !important, so a plain override here is enough. */
.dg-hero-dark .dg-header:not(.scrolled) .et_pb_image_1_tb_header {
  display: flex !important;
}
.dg-hero-dark .dg-header:not(.scrolled) .et_pb_image_0_tb_header {
  display: none !important;
}
/* The white logo variant above is only legible against the transparent/
   dark-gradient header. Once .dg-mobile-nav-is-open forces the header
   solid cream (see that rule's comment), the white logo would go almost
   invisible — swap back to the dark logo for as long as the panel is
   open, the same pairing already used for .scrolled. */
body #page-container .dg-header.dg-mobile-nav-is-open .et_pb_image_1_tb_header {
  display: none !important;
}
body #page-container .dg-header.dg-mobile-nav-is-open .et_pb_image_0_tb_header {
  display: flex !important;
}

/* INQUIRE header CTA — a Divi Button module in the Theme Builder header,
   not a menu item, so it doesn't inherit any of the nav-link rules above.
   Divi's own module defaults render it as a solid dark-green fill; these
   overrides match the reference's ghost button (values measured off the
   reference's rendered computed styles). `body #page-container` matches
   Divi's own wrapper for specificity.
   Forensic parity fix (July 2026): line-height, display, and white-space
   are set explicitly because Divi's module defaults (1.7em line-height,
   inline-block) otherwise leak through and render the button 40.4px tall
   vs the reference's 32px; the transition carries !important because
   Divi's own `transition: all` outranks it otherwise. Box math:
   12px text + 2x9px padding + 2x1px border = 32px tall. */
body #page-container .dg-header a.et_pb_button {
  display: inline-flex !important;
  align-items: center !important;
  justify-content: center !important;
  line-height: 1 !important;
  white-space: nowrap !important;
  border-radius: var(--radius-sm) !important;
  padding: 9px 18px !important;
  font-family: var(--font-sans) !important;
  font-size: 12px !important;
  font-weight: var(--w-semibold) !important;
  letter-spacing: 0.14em !important;
  text-transform: uppercase !important;
  color: var(--paper) !important;
  background: transparent !important;
  border: 1px solid rgba(246, 241, 231, 0.5) !important;
  transition: background-color var(--dur-fast) var(--ease-out),
              color var(--dur-fast) var(--ease-out),
              border-color var(--dur-fast) var(--ease-out) !important;
}
/* Measured directly on the reference: on dark-hero pages the ghost button
   persists in EVERY scroll state. Only light-hero pages (About, Inquire)
   render the solid primary button: pine-700, transparent border, pine-900
   on hover. */
body.dg-hero-light #page-container .dg-header a.et_pb_button {
  background: var(--pine-700) !important;
  border-color: transparent !important;
}
/* Ghost hover (dark-hero pages, any scroll state) — reference outline
   hover fills solid pine-700 and keeps the paper-50 border. */
body #page-container .dg-header a.et_pb_button:hover {
  background: var(--pine-700) !important;
  border-color: rgba(246, 241, 231, 0.5) !important;
}
/* Solid (light-hero) hover — reference primary hover: pine-900. */
body.dg-hero-light #page-container .dg-header a.et_pb_button:hover {
  background: var(--pine-900) !important;
  border-color: transparent !important;
}
/* Client revision (July 2026): once the header goes sticky (.scrolled) the
   ghost button read as lost/washed-out against page content — fill it with
   the solid dark green instead. Intentional divergence from the reference
   (which keeps the ghost in all scroll states on dark-hero pages); client
   preference wins. Declared after the ghost rules so it takes the cascade
   when both apply. */
body #page-container .dg-header.scrolled a.et_pb_button {
  background: var(--pine-700) !important;
  border-color: transparent !important;
}
body #page-container .dg-header.scrolled a.et_pb_button:hover {
  background: var(--pine-900) !important;
  border-color: transparent !important;
}
body #page-container .dg-header a.et_pb_button:active,
body #page-container .dg-header a.et_pb_button:focus {
  transform: none !important;
}
/* Divi's default Button-module arrow icon (::after, ETmodules glyph) —
   fades in on hover by default. The reference's INQUIRE button is plain
   text, no icon in any state. */
body #page-container .dg-header a.et_pb_button::after {
  display: none !important;
  content: none !important;
}
/* The button's own column shares the row's right gutter with everything
   else, but the CTA reads too flush against it — nothing else in the row
   sits at that edge the way this button does. Extra breathing room on the
   wrapper (not the row gutter itself) so only the button moves in from
   the edge; nav links and logo are untouched. Desktop only — below Divi's
   980px breakpoint this button is display:none (see MOBILE NAV PARITY
   LOCK below), replaced by the .dg-mobile-nav panel's own CTA. */
@media (min-width: 981px) {
  .dg-header .et_pb_button_module_wrapper {
    margin-right: 24px;
  }
}

/* Scroll progress bar — created by dg-header.js inside .dg-header.
   Absolute (not fixed) on purpose: .dg-header is position: fixed, so
   bottom: 0 here pins the bar to the underside of the sticky nav — the
   reference site's placement. The old position: fixed put it at the
   bottom of the *viewport* except when the header's backdrop-filter
   happened to capture it as a containing block.
   z-index kept low (not 9999, which is what any open nav dropdown/sub-
   menu also uses, per Divi core) on purpose: this bar sits at .dg-header's
   own bottom edge, only ~27px below the nav links — an open dropdown
   attached to a top-level item necessarily spans across that same band,
   so at equal z-index this bar (appended to .dg-header after the nav
   markup, so it wins DOM-order ties) painted a second, unrelated bronze
   line across the top of any open dropdown, reading as a detached menu.
   Confirmed live: lowering this alone (no change to the dropdown's own
   position, padding, or size) fully resolves it, since it only needs to
   sit above the plain header background/hero photo, never above menu
   content, and .dg-header's own z-index:500 already gives it its own
   stacking context to be low within. */
.dg-scroll-bar {
  position: absolute;
  bottom: 0;
  left: 0;
  height: 3px;
  background: var(--accent);
  width: 0%;
  transition: width 0.1s linear, opacity 0.2s var(--ease-out);
  z-index: 1;
  opacity: 0;
  pointer-events: none;
}

/* Mobile menu — matches the reference's full-width dropdown flush under
   the header exactly (colors, spacing, dividers, submenu treatment).
   Divi's own `.et_mobile_menu` is `position: absolute` relative to
   whatever positioned ancestor happens to be nearest in the header's
   internal column structure, which caps it to that column's width (a
   right-anchored floating box, not full-width). `position: fixed` here
   bypasses that entirely and anchors to the viewport instead, which is
   also why it doesn't fight Divi's own inline width/positioning styles
   the way another `position: absolute` override would. `top` matches
   `.dg-header`'s own height (68px at the sizes set elsewhere in this
   file — logo/nav padding don't scale with viewport, so this holds
   across mobile widths). */
/* Custom animated hamburger, replacing Divi's static icon-font glyph
   (.mobile_menu_bar::before, ETmodules content:"a") — that's a single
   character, so it can't morph into an "X" on its own. Built instead
   from the span itself (middle bar) plus ::before/::after (top/bottom
   bars), each independently transformable. Divi toggles `.opened` on
   the parent `.mobile_nav` on click — no JS beyond that is needed. */
.dg-header .mobile_menu_bar {
  position: relative;
  display: inline-block;
  width: 24px;
  height: 2px;
  vertical-align: middle;
  background-color: var(--paper-96);
  transition: background-color var(--dur-base) var(--ease-out),
              opacity var(--dur-fast) var(--ease-out);
}
.dg-header .mobile_menu_bar::before {
  font: unset !important;
}
.dg-header .mobile_menu_bar::before,
.dg-header .mobile_menu_bar::after {
  content: '' !important;
  position: absolute;
  left: 0;
  width: 24px;
  height: 2px;
  background-color: var(--paper-96);
  transition: transform 0.32s var(--ease-out), top 0.32s var(--ease-out),
              background-color var(--dur-base) var(--ease-out);
}
.dg-header .mobile_menu_bar::before { top: -7px; }
.dg-header .mobile_menu_bar::after  { top: 7px; }

/* Solid header / light-hero pages — ink instead of paper. Also applies
   whenever .dg-mobile-nav-is-open forces the header solid (see that
   rule's comment) — same reasoning as the logo swap just above: the
   paper-colored X reads fine on a transparent/dark header, not on the
   solid cream one the open panel forces. */
.dg-header.scrolled .mobile_menu_bar,
.dg-header.scrolled .mobile_menu_bar::before,
.dg-header.scrolled .mobile_menu_bar::after,
body.dg-hero-light .dg-header .mobile_menu_bar,
body.dg-hero-light .dg-header .mobile_menu_bar::before,
body.dg-hero-light .dg-header .mobile_menu_bar::after,
.dg-header.dg-mobile-nav-is-open .mobile_menu_bar,
.dg-header.dg-mobile-nav-is-open .mobile_menu_bar::before,
.dg-header.dg-mobile-nav-is-open .mobile_menu_bar::after {
  background-color: var(--ink-900);
}

/* Opened — collapse the middle bar, rotate top/bottom into an X.
   Color intentionally NOT overridden here — confirmed directly against
   the reference that the X keeps whatever color the bars already had
   (paper on a dark-hero page, ink once scrolled/light), the same as
   every other header element (logo, nav links). A previous version of
   this rule forced ink-900 unconditionally on the assumption the panel
   behind it was always the solid fill it opens onto, but the header
   itself (where the icon actually sits) stays in its own transparent/
   dark-hero state independent of the panel opening below it — the
   existing `.dg-header.scrolled` / `.dg-hero-light` (ink) and
   `.dg-hero-dark .dg-header:not(.scrolled)` (paper) rules above already
   apply regardless of `.opened`, so removing the override here is enough. */
.dg-header .mobile_nav.opened .mobile_menu_bar {
  background-color: transparent;
}
.dg-header .mobile_nav.opened .mobile_menu_bar::before,
.dg-header .mobile_nav.opened .mobile_menu_bar::after {
  top: 0;
}
.dg-header .mobile_nav.opened .mobile_menu_bar::before {
  transform: rotate(45deg);
}
.dg-header .mobile_nav.opened .mobile_menu_bar::after {
  transform: rotate(-45deg);
}
/* START MOBILE NAV PARITY LOCK
   Divi's own `.et_mobile_menu` dropdown is replaced outright, not patched
   further — it's built by Divi's own JS at runtime rather than server-
   rendered, and on every real page load it simply didn't exist yet at the
   point dg-header.js ran (a timing race, not a selector bug), which is why
   the INQUIRE CTA never actually made it into that panel despite code that
   was supposed to clone it in. The replacement panel (`.dg-mobile-nav`,
   built in dg-header.js from the same `.et-menu-nav` link data and the
   real INQUIRE button) is fully self-contained and doesn't depend on
   Divi's menu JS running at all.
   Scoped to Divi's own 980px breakpoint throughout — none of this reaches
   desktop. */
.dg-mobile-nav {
  /* Unconditional, outside the media query below on purpose: a bare
     appended <div> defaults to `display: block` with no rule to stop it,
     so without this a desktop viewport would render the panel the moment
     dg-header.js appends it. dg-header.js also guards its own
     `panel.style.display = 'block'` behind a matchMedia(980px) check —
     belt and suspenders, since an inline style would otherwise beat this
     rule regardless of viewport. */
  display: none;
}
@media (max-width: 980px) {
  .dg-header .et_mobile_menu {
    display: none !important;
  }

  /* The real header-bar INQUIRE button stays hidden on mobile — the
     `.dg-mobile-nav__cta` link inside the custom panel below is built
     from its href/label in dg-header.js, so leaving the original visible
     too would show INQUIRE twice. */
  .dg-header .et_pb_button_module_wrapper a.et_pb_button {
    display: none !important;
  }

  /* Divi's own phone-breakpoint responsive column widths (its per-
     instance `.et_flex_column_24_24_phone` etc., generated by the Theme
     Builder's row/column width settings for the "Phone" breakpoint) stack
     the header's 3 columns to 100% width each below ~767px — confirmed
     directly: logo, nav/hamburger, and button columns each rendered full-
     width and stacked vertically, which pushed the hamburger to x:535 on
     a 485px-wide viewport, off-screen and untappable. The header row was
     never meant to reflow like a normal content row; forcing it back to a
     single non-wrapping row (content-sized columns) keeps the hamburger
     in place at every width down to the narrowest phones, matching the
     reference (which never stacks its header at any width). */
  .dg-header .et_pb_row {
    flex-wrap: nowrap !important;
    justify-content: space-between !important;
  }
  .dg-header .et_pb_row > .et_pb_column {
    width: auto !important;
    flex: 0 0 auto !important;
  }
  /* Column 3 (the header-bar INQUIRE button) has nothing left to show —
     its button is already hidden above — so drop the column too instead
     of leaving an empty 0-width flex item in the row. */
  .dg-header .et_pb_row > .et_pb_column:nth-child(3) {
    display: none !important;
  }
  /* The hamburger's column still collapses to 0 width even with the
     overrides above (Divi's per-instance phone rule wins on some inner
     dimension we didn't chase further), but `justify-content: space-
     between` above already lands that 0-width column's own box exactly
     on the row's right edge — confirmed directly (column box x matched
     the row's right edge to the pixel). Positioning the hamburger
     absolutely within that correctly-placed column, rather than relying
     on the column's collapsed width to contain it, keeps it pinned to
     the true right edge instead of overflowing off-screen.
     Both wrapper divs between `.mobile_nav` and the column are
     `position: relative` themselves — left alone, `position: absolute`
     below would bind to the nearer of those two (whichever still has an
     intrinsic width, e.g. the menu module's own fixed-width phone rule)
     instead of the correctly-positioned column, landing off-center again.
     Neutralizing them here makes the column the actual containing block. */
  .dg-header .et_pb_menu_inner_container,
  .dg-header .et_pb_menu_0_tb_header {
    position: static !important;
  }
  .dg-header .mobile_nav {
    position: absolute !important;
    right: var(--gutter);
    top: 50%;
    transform: translateY(-50%);
    margin: 0 !important;
  }

  /* Client request (July 2026): the logo reads cramped against the top
     edge of the mobile header row — the hamburger is vertically centered
     via its own absolute positioning above, but the logo just sits in
     normal flex flow with no equivalent breathing room. A little top
     margin nudges it down without touching the row height or the
     logo's own width/height sizing above. */
  .dg-header .et_pb_image_wrap img {
    height: 34px !important;
    margin-top: 8px;
  }

  /* Confirmed live (July 2026): `.dg-header` is a Divi-generated
     `display: flex; flex-direction: column` container with its own
     `gap: 60px` (the section's row/column gutter setting, generated for
     spacing Divi's own children — never meant to apply here). The mobile
     nav panel is appended as a plain flex sibling of `.et_pb_row`
     (dg-header.js), so it inherits that same 60px gap between itself and
     the row above it. Nothing paints that gap — not the row, not the
     panel's own background, which only starts at the panel's own top
     edge — so the header's unscrolled gradient overlay (a fade from ~62%
     to fully transparent, sized for the ~80px-tall row alone) shows
     through it as a translucent band of the hero photo, read as "a
     transparent gap" between the header and the dropdown. `.dg-scroll-bar`
     is unaffected (it's `position: absolute`, outside flex flow
     entirely). Zeroing the gap is safe at every width: it only had an
     effect when 2+ flex children exist in normal flow at once, which
     before this panel existed, never happened. */
  .dg-header {
    gap: 0 !important;
  }

  .dg-mobile-nav {
    width: 100%;
    background: var(--paper-98);
    backdrop-filter: saturate(140%) blur(10px);
    -webkit-backdrop-filter: saturate(140%) blur(10px);
    box-shadow: var(--shadow-md);
    border-top: 1px solid var(--border-hairline);
    max-height: calc(100vh - 68px);
    overflow-y: auto;
    opacity: 0;
    transform: translateY(-8px);
    transition: opacity var(--dur-base) var(--ease-out),
                transform var(--dur-base) var(--ease-out);
    /* Confirmed live (July 2026): on first tap, this panel briefly paints
       with no background at all — just the unstyled link text overlapping
       the hero photo behind it — before self-correcting a moment later.
       Computed styles are correct throughout (opacity, background-color,
       display all report right even during the broken frame), so this
       isn't a wrong value, it's the same Chrome compositing race already
       fixed on the homepage team cards: the panel is appended to the DOM
       and immediately transitioned (opacity 0→1) in the same tick, and
       Chrome sometimes hasn't allocated its compositor layer — including
       the backdrop-filter and background paint — before that transition
       starts running. will-change forces the layer to exist upfront
       instead of being promoted reactively mid-transition. */
    will-change: opacity, transform;
  }
  .dg-mobile-nav.dg-mobile-nav--open {
    opacity: 1;
    transform: translateY(0);
  }
  .dg-mobile-nav__inner {
    display: grid;
    gap: 8px;
    padding: 24px var(--gutter) 32px;
  }
  .dg-mobile-nav__link,
  .dg-mobile-nav__link:visited {
    font-family: var(--font-sans);
    font-size: 16px;
    font-weight: var(--w-medium);
    color: var(--ink-900);
    text-decoration: none;
    border-bottom: 1px solid var(--border-soft);
    padding: 10px 0;
  }
  .dg-mobile-nav__link--sub {
    font-size: 14px;
    font-weight: var(--w-regular);
    color: var(--taupe);
    padding: 8px 0 8px 16px;
  }
  .dg-mobile-nav__cta {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    font-family: var(--font-sans);
    font-size: 13px;
    font-weight: var(--w-semibold);
    letter-spacing: var(--ls-caps);
    text-transform: uppercase;
    text-decoration: none;
    line-height: 1;
    color: var(--paper);
    background: var(--bronze-500);
    border: 1px solid transparent;
    border-radius: var(--radius-sm);
    padding: 14px 28px;
    margin-top: 16px;
    transition: background-color var(--dur-fast) var(--ease-out),
                color var(--dur-fast) var(--ease-out),
                border-color var(--dur-fast) var(--ease-out);
    /* `.dg-mobile-nav__inner` is a CSS grid, and grid items default to
       `justify-items: stretch` — that silently overrode the button's own
       `display: inline-flex` and stretched it to the full row width.
       The reference's CTA is compact/content-width, not full-bleed. */
    justify-self: start;
  }
  /* Reference accent-variant hover: bronze-600. */
  .dg-mobile-nav__cta:hover,
  .dg-mobile-nav__cta:focus-visible {
    background: var(--bronze-600);
    color: var(--paper);
  }
}
/* END MOBILE NAV PARITY LOCK */


/* ============================================================
   14. FOOTER (dg-footer)
   Rendered by partials/footer/site-footer.php, appended via the
   wp_footer action in functions.php (see the comment there — a
   child-theme footer.php template override was tried first and had no
   effect on this install, and a whole-page output-buffer regex swap
   after that caused a fatal error in production; wp_footer is the
   same core hook every enqueued script on this theme already relies
   on, so it's the most-proven option available).
   Every value below was read directly off the reference's rendered
   computed styles, not estimated: colors map exactly onto existing
   tokens (pine-900 bg, pine-100 links, pine-300 dim text, bronze-400
   accent, the existing --border-on-dark divider), confirming this
   token set was already correct — only the layout rules to actually
   use them were missing. Font sizes (11/14/13/12px) are hardcoded
   rather than reusing --t-eyebrow (12.5px) / --t-small (15px), because
   those tokens measured a half-to-full pixel off the reference's real
   values and this task calls for an exact match.
   ============================================================ */

/* Removing Divi's default footer shell.
   functions.php's widget_block_content filter already strips the actual
   widget CONTENT (the default Archives/Categories blocks) at the data
   level — after that filter runs, `#footer-widgets` genuinely has
   nothing left inside it, so hiding the now-empty wrapper here is
   cleanup of dead space, not content removal. `#footer-bottom` (Divi's
   hardcoded "Designed by Elegant Themes | Powered by WordPress" credit
   line + default social icons) has no equivalent WordPress filter this
   child theme's code has visibility into without server-side access to
   the parent theme's source, so it's suppressed here instead — `display:
   none` genuinely removes an element from the accessibility tree (unlike
   visibility:hidden/opacity:0), so screen-reader users don't encounter
   it either. Scoped to these two specific IDs only, not a general rule. */
#main-footer #footer-widgets,
#main-footer #footer-bottom {
  display: none;
}

/* Client feedback (July 2026): "keep all text white (no green)" — the
   footer previously used --pine-100/--pine-300 (a light sage-green tint)
   across description, address, links, and copyright text for tonal
   hierarchy against the dark background. Flattened to --paper throughout;
   link hover now uses the accent gold instead of the paper→paper jump
   that would otherwise give white text no visible hover state. */
.dg-footer {
  background: var(--pine-900) !important;
  color: var(--paper);
}

.dg-footer .footer-inner {
  max-width: var(--content-max);
  margin: 0 auto;
  padding: 60px var(--gutter) 40px;
}

/* Back-to-top row — the reference's only footer divider sits here, below
   the button and above the columns. There is no second divider before
   the copyright row (see .footer-copyright-row below) — confirmed
   directly, not a guess, since it would be easy to assume symmetry. */
.footer-top-row {
  display: flex;
  justify-content: flex-end;
  padding-bottom: 44px;
  margin-bottom: 48px;
  border-bottom: 1px solid var(--border-on-dark);
}
.footer-back-to-top {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-family: var(--font-sans);
  font-size: 11px;
  font-weight: var(--w-semibold);
  letter-spacing: var(--ls-caps);
  text-transform: uppercase;
  color: var(--paper) !important;
  background: var(--bronze-400);
  border-radius: var(--radius-pill);
  padding: 11px 24px;
  text-decoration: none !important;
  line-height: 1;
  cursor: pointer;
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.30);
  transition: background-color var(--dur-base) var(--ease-out),
              box-shadow var(--dur-base) var(--ease-out),
              opacity var(--dur-base) var(--ease-out),
              visibility 0s linear 0s;
}
.footer-back-to-top:hover,
.footer-back-to-top:focus-visible {
  background: var(--bronze-500);
  color: var(--paper) !important;
  box-shadow: 0 6px 24px rgba(0, 0, 0, 0.45);
}

/* Hide the footer's Back-to-top button while a desktop nav dropdown or
   the mobile nav panel is open. Both panels are geometrically independent
   of the footer — one is a fixed-header dropdown, the other a static
   in-flow button — so no z-index or background fix can stop them landing
   in the same screen-space near the bottom of a shorter page; confirmed
   live on staging (both the desktop "About" dropdown and the mobile nav
   panel end a few dozen pixels above this button, close enough to read as
   overlapping). Keyed via :has() off the header's own existing open-state
   markers rather than a new state: .et-show-dropdown is added by Divi's
   own menu JS to the hovered/focused top-level <li> (harmless to also
   match here on items without children, since combined with
   .menu-item-has-children it only ever matches "About", the one item with
   a sub-menu); .dg-mobile-nav-is-open is dg-header.js's existing class for
   the mobile panel (already used above at line ~1349 for the same
   reason). transition-delay staggers visibility so hiding fades out
   first, then drops from the accessibility tree/tab order — reappearing
   is immediate, no delay before the fade-in starts. Reduced-motion is
   handled by the sitewide `transition-duration: 0.01ms !important` rule
   already in this file, with no page-specific override needed. */
body:has(.dg-header.dg-mobile-nav-is-open) .footer-back-to-top,
body:has(.et-menu-nav > ul > li.menu-item-has-children.et-show-dropdown) .footer-back-to-top,
body:has(.et_pb_menu__nav > ul > li.menu-item-has-children.et-show-dropdown) .footer-back-to-top {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: background-color var(--dur-base) var(--ease-out),
              box-shadow var(--dur-base) var(--ease-out),
              opacity var(--dur-base) var(--ease-out),
              visibility 0s linear var(--dur-base);
}

.footer-columns {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 48px;
}
@media (max-width: 767px) {
  .footer-columns {
    grid-template-columns: 1fr;
  }
}

.footer-logo {
  height: 44px;
  width: auto;
}
.footer-desc {
  font-family: var(--font-sans);
  font-size: 14px;
  line-height: 1.7;
  color: var(--paper);
  margin: 22px 0 0;
  max-width: 30ch;
}
.footer-address {
  font-family: var(--font-sans);
  font-style: normal;
  font-size: 13px;
  line-height: 1.8;
  color: var(--paper);
  margin-top: 18px;
}
.footer-address a {
  line-height: inherit;
}

.dg-footer .footer-col-eyebrow {
  font-family: var(--font-sans);
  font-size: 11px;
  font-weight: 400;
  letter-spacing: var(--ls-eyebrow);
  text-transform: uppercase;
  color: var(--bronze-400);
  margin: 0 0 16px;
}

.dg-footer a {
  font-family: var(--font-sans);
  font-size: 14px;
  color: var(--paper) !important;
  text-decoration: none;
  line-height: 2;
  transition: color var(--dur-fast) var(--ease-out);
}
.dg-footer a:hover,
.dg-footer a:focus-visible {
  color: var(--bronze-200) !important;
}

.footer-copyright-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
  gap: 12px;
  padding-top: 28px;
}
.footer-copyright-row p {
  font-family: var(--font-sans);
  font-size: 12px;
  color: var(--paper);
  margin: 0;
}


/* ============================================================
   15. FORMS — FLUENT FORMS SKIN
   Overrides Fluent Forms' default styles to match the design system.
   Replaces the theme's original Gravity Forms skin — that plugin was
   never actually installed on this site (only an inert Gravity Forms
   Zero Spam add-on was), so these rules never had anything to style.
   Class names below (.ff-el-form-control, .ff-el-group, etc.) are read
   directly off Fluent Forms' own rendered markup, not guessed from docs.
   ============================================================ */

.fluentform .ff-el-form-control {
  font-family: var(--font-sans) !important;
  font-size: var(--t-body) !important;
  color: var(--text-heading) !important;
  background: var(--paper) !important;
  border: 1px solid var(--border-hairline) !important;
  border-radius: var(--radius-sm) !important;
  padding: 14px 16px !important;
  width: 100% !important;
  transition: border-color var(--dur-fast) var(--ease-out),
              box-shadow var(--dur-fast) var(--ease-out) !important;
  box-shadow: none !important;
}
.fluentform .ff-el-form-control:focus {
  outline: none !important;
  border-color: var(--accent) !important;
  box-shadow: var(--focus-ring) !important;
}

.fluentform textarea.ff-el-form-control {
  min-height: 120px !important;
  resize: vertical !important;
}

.fluentform .ff-el-input--label label {
  font-family: var(--font-sans) !important;
  font-size: var(--t-small) !important;
  font-weight: var(--w-medium) !important;
  color: var(--text-body) !important;
  letter-spacing: 0.02em !important;
  margin-bottom: 8px !important;
  display: inline-block;
}

/* Required asterisk — Fluent renders it as a label::after, not a separate
   element, so recolor it in place rather than styling a nonexistent node. */
.fluentform .ff-el-is-required label::after {
  color: var(--bronze-500) !important;
}

/* Submit button — mirrors the reference's form submit exactly: an accent
   Button at size lg (18px 38px, 14px type, --ls-caps tracking, 12px icon
   gap) with a trailing 16px arrow, and NOT full-width — the reference
   submit hugs its label. Fluent Forms renders a bare <button> with no
   icon slot, so the arrow is a ::after mask painted in the button's own
   text color, nudging on hover/focus at --dur-base like every other
   .btn arrow. */
.fluentform .ff-btn-submit {
  display: inline-flex !important;
  align-items: center !important;
  justify-content: center !important;
  gap: 12px !important;
  font-family: var(--font-sans) !important;
  font-size: 14px !important;
  font-weight: var(--w-semibold) !important;
  letter-spacing: var(--ls-caps) !important;
  text-transform: uppercase !important;
  line-height: 1 !important;
  white-space: nowrap !important;
  background: var(--accent) !important;
  color: var(--paper) !important;
  border: 1px solid transparent !important;
  border-radius: var(--radius-sm) !important;
  padding: 18px 38px !important;
  width: auto !important;
  cursor: pointer !important;
  transition: background var(--dur-fast) var(--ease-out),
              color var(--dur-fast) var(--ease-out),
              border-color var(--dur-fast) var(--ease-out) !important;
}
.fluentform .ff-btn-submit::after {
  content: "";
  width: 16px;
  height: 16px;
  flex-shrink: 0;
  background-color: currentColor;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12h14'/%3E%3Cpath d='m12 5 7 7-7 7'/%3E%3C/svg%3E") center / contain no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12h14'/%3E%3Cpath d='m12 5 7 7-7 7'/%3E%3C/svg%3E") center / contain no-repeat;
  transition: transform var(--dur-base) var(--ease-out);
}
.fluentform .ff-btn-submit:hover {
  background: var(--accent-strong) !important;
}
.fluentform .ff-btn-submit:hover::after,
.fluentform .ff-btn-submit:focus-visible::after {
  transform: translateX(3px);
}
@media (prefers-reduced-motion: reduce) {
  .fluentform .ff-btn-submit::after {
    transition: none;
  }
  .fluentform .ff-btn-submit:hover::after,
  .fluentform .ff-btn-submit:focus-visible::after {
    transform: none;
  }
}

/* Field spacing */
.fluentform .ff-el-group {
  margin-bottom: 20px !important;
}

/* Validation error state */
.fluentform .ff-el-is-error .ff-el-form-control {
  border-color: #8B4A3A !important;
}
.fluentform .error {
  font-family: var(--font-sans) !important;
  font-size: 13px !important;
  color: #8B4A3A !important;
  margin-top: 4px !important;
}

/* Confirmation message */
.ff-message-success {
  font-family: var(--font-sans);
  font-size: var(--t-body);
  color: var(--text-body);
  padding: 32px;
  background: var(--surface-card);
  border-radius: var(--radius-card);
  border-left: 3px solid var(--success);
}


/* ============================================================
   16. VISIONBAND ("Land Stewardship")
   Assign .vision-band as CSS Class on the Divi Section.
   Background gradient and photo-mask values below are read directly off
   the reference (deadstop-web-projects.vercel.app #vision, computed
   styles) for an exact match — not re-derived from design tokens.
   ============================================================ */

.vision-band {
  position: relative;
  overflow: hidden;
  /* 5-stop wash, dark pine fading into the photo's own golden-hour bronze
     tones, so the handoff to the masked image below isn't a hard seam. */
  background: linear-gradient(
    to right,
    rgb(22, 36, 26) 0%,
    rgb(28, 46, 33) 42%,
    rgb(51, 80, 65) 70%,
    rgb(135, 90, 53) 92%,
    rgb(156, 107, 66) 108%
  );
}

/* Photo sits above the gradient, masked so it only reveals itself on the
   right half — a real <img> (see vision-band.php) rather than a CSS
   custom-property background-image: WordPress's content sanitizer strips
   `--custom-prop:url(...)` out of inline style attributes, which is why
   the previous version of this section never actually showed a photo. */
.vision-photo-wrap {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
}

.vision-photo-img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 38%;
  -webkit-mask-image: linear-gradient(to right, transparent 0%, transparent 50%, #000 90%, #000 100%);
  mask-image: linear-gradient(to right, transparent 0%, transparent 50%, #000 90%, #000 100%);
}

/* Mobile/tablet: reference hides the photo outright (matches its
   "max-md:hidden!" wrapper class) AND drops the gradient for a flat wash —
   confirmed directly against the reference's computed styles at 500px
   (background-image: none, background-color: rgb(22, 36, 26), i.e. plain
   --pine-900), not the gradient's own 0% stop carried through. */
@media (max-width: 768px) {
  .vision-photo-wrap {
    display: none;
  }
  .vision-band {
    background: var(--pine-900);
  }
}

/* Content sits above the pseudo-element */
.vision-band .et_pb_row {
  position: relative;
  z-index: 1;
}

/* Text column — flush with the same left margin every other homepage
   section uses (its containing div is max-width:var(--content-max), see
   vision-band.php), capped to a readable width here. Reference keeps this
   left-aligned on desktop and centers it only at the mobile breakpoint. */
.vision-text-col {
  max-width: 640px;
  text-align: left;
}

@media (max-width: 768px) {
  .vision-text-col {
    margin: 0 auto;
    text-align: center;
  }
  /* .eyebrow-rule is display:flex, so text-align alone won't center its
     dash + label row — needs justify-content directly (same fix as the
     existing .eyebrow-center utility, scoped here instead of applied
     globally). */
  .vision-text-col .eyebrow-rule {
    justify-content: center;
  }
}


/* ============================================================
   17. SHOMESITES RELEASE ROWS ("Now Selling" — Stringfield page)
   HTML lives in a Divi Code Module on the Stringfield page, inside the
   SHomesites section (id="homesites"). Replaces the old invented 8-lot
   grid (Available/Reserved/Sold) — that mock data never matched a real
   release and was removed in the July 2026 master plan overhaul.
   ============================================================ */

.release-row {
  border-top: 1px solid var(--border-hairline);
  padding: 24px 0;
}
.release-row-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 24px;
  flex-wrap: wrap;
}
.release-row-name {
  font-family: var(--font-display);
  font-size: var(--t-title);
  font-weight: 400;
  color: var(--text-heading);
  margin: 0;
}
.release-row-meta {
  font-family: var(--font-sans);
  font-size: 12px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  font-weight: var(--w-semibold);
  color: var(--accent-strong);
  white-space: nowrap;
}
.release-row-blurb {
  font-family: var(--font-sans);
  font-size: 15px;
  line-height: 1.65;
  color: var(--text-body);
  margin: 8px 0 0;
  max-width: 52ch;
}
.release-row-link {
  margin-top: 4px;
  color: var(--accent-strong);
}


/* ============================================================
   18. TEAM CARDS
   Homepage only (JeffSection) — a 3D flip card ported from the
   approved Next.js reference (JeffSection.tsx's TeamCard): front
   face is the photo with a name/role caption; hovering/focusing
   flips it to a back face with name/role and a "Read bio" link to
   the matching About-page team row (#slug anchor, see
   about-team.php). A card-stack shadow fan + lift also plays on
   hover, layered on the outer link.
   The About page's own team rows (.about-team-row) are a separate,
   simpler two-column layout — see dg-shortcodes.css.
   ============================================================ */

.dg-team-card {
  display: block;
  position: relative;
  aspect-ratio: 4 / 5;
  border-radius: var(--radius-card);
  perspective: 1400px;
  text-decoration: none;
  /* Was a hardcoded 0.55s — now the shared --dur-slow token, same tier as
     every other large reveal/hover-zoom on the site. The 0.12s stagger
     delay is this component's own intentional timing, kept as-is. */
  transition: transform var(--dur-slow) var(--ease-out) 0.12s;
}
.dg-team-card:hover,
.dg-team-card:focus-within {
  transform: translateY(-6px);
}

/* Card-stack shadow panels — fan out ±6° behind the card on hover */
.dg-team-card::before,
.dg-team-card::after {
  content: '';
  position: absolute;
  z-index: -1;
  opacity: 0;
  width: 46%;
  top: 80%;
  bottom: 22px;
  background: rgba(22, 36, 26, 0.48);
  box-shadow: 0 24px 26px rgba(22, 36, 26, 0.48);
  transition: opacity 60ms var(--ease-out);
}
.dg-team-card::before { left: 14px; transform: rotate(-6deg); }
.dg-team-card::after  { right: 14px; transform: rotate(6deg); }
.dg-team-card:hover::before,
.dg-team-card:hover::after,
.dg-team-card:focus-within::before,
.dg-team-card:focus-within::after {
  opacity: 1;
  transition: opacity 0.3s var(--ease-out) 0.12s;
}

/* The flip itself — a rotator that fills the card, holding both faces */
.dg-team-card-rotator {
  position: relative;
  width: 100%;
  height: 100%;
  transform-style: preserve-3d;
  transition: transform 0.7s var(--ease-out);
}
.dg-team-card:hover .dg-team-card-rotator,
.dg-team-card:focus-within .dg-team-card-rotator {
  transform: rotateY(180deg);
}

.dg-team-card-face {
  position: absolute;
  inset: 0;
  overflow: hidden;
  border-radius: var(--radius-card);
  backface-visibility: hidden;
  box-shadow: var(--shadow-sm);
}

/* Front face — photo + gradient name/role caption.
   The source photos are ~1:2 three-quarter-body shots; unzoomed in a 4:5
   card the subjects read small with a lot of office background. The scale
   + matching object-position/transform-origin crop each one to an
   editorial head-and-shoulders framing. Keeping object-position and
   transform-origin at the same focal point means that point stays fixed
   while the image scales, so the face lands at the same card position at
   every breakpoint (the card is 4:5 at all sizes). Per-person values
   below compensate for how far from the camera each subject stood, so
   all four faces render at the same visual size (~40% of card height)
   with the eyes in the upper third. */
.dg-team-card-face--front img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% var(--team-focus-y, 30%);
  transform: scale(var(--team-zoom, 1.5));
  transform-origin: var(--team-focus-x, 50%) var(--team-focus-y, 30%);
  /* Intermittent bug (confirmed live, July 2026): on a fresh page load, one
     of the four cards — not always the same one — sometimes paints as a
     blank gradient with no photo, even though the <img> itself reports
     complete:true and a real naturalWidth in devtools. Root cause is a
     Chrome compositing race, not a bad image or a bad --team-focus/--team-
     zoom value: these images sit inside a 3D transform context (.dg-team-
     card's `perspective` + .dg-team-card-rotator's `preserve-3d`) and
     *also* carry their own `transform: scale()` above, and Chrome
     sometimes finishes decoding the image after it already composited
     that layer, then never repaints it until some later trigger (hover,
     scroll, resize). will-change forces the browser to allocate this
     image's compositor layer eagerly instead of reactively, which avoids
     the race. If this recurs, it's a paint-timing bug to chase, not a
     reason to re-tune any card's focal point. */
  will-change: transform;
}
/* Person-specific focal points — Pam stands farthest from camera (most
   zoom), Jim closest (least). X pulls off-center subjects back to the
   middle of the card. */
.dg-team-card--pam-berry     { --team-zoom: 1.65; --team-focus-x: 58%; --team-focus-y: 37%; }
.dg-team-card--gianna-minton { --team-zoom: 1.5;  --team-focus-x: 71%; --team-focus-y: 26%; }
.dg-team-card--jim-clark     { --team-zoom: 1.35; --team-focus-x: 85%; --team-focus-y: 23%; }
.dg-team-card--debbie        { --team-zoom: 1.4;  --team-focus-x: 57%; --team-focus-y: 32%; }
.dg-team-caption {
  position: absolute;
  inset: auto 0 0 0;
  padding: 22px 20px;
  background: linear-gradient(to top, rgba(22, 36, 26, 0.82) 8%, rgba(22, 36, 26, 0) 100%);
}
.dg-team-caption-name {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 21px;
  line-height: 1.5;
  color: var(--paper);
  margin: 0;
}
.dg-team-caption-role {
  font-family: var(--font-sans);
  font-size: 11.5px;
  letter-spacing: var(--ls-caps);
  text-transform: uppercase;
  color: rgba(246, 241, 231, 0.78);
  margin: 6px 0 0;
}

/* Back face — name/role + "Read bio" link, bronze inner frame */
.dg-team-card-face--back {
  transform: rotateY(180deg);
  background: var(--paper-alt);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 28px 24px;
}
.dg-team-card-face--back::after {
  content: '';
  position: absolute;
  inset: 10px;
  border: 4px solid var(--bronze-400);
  pointer-events: none;
}
.dg-team-card-face--back .team-name {
  font-family: var(--font-display);
  font-size: 24px;
  color: var(--text-heading);
  margin: 0;
  font-weight: 400;
}
.dg-team-card-face--back .team-role {
  font-family: var(--font-sans);
  font-size: 11.5px;
  font-weight: var(--w-semibold);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--text-muted);
  margin: 10px 0 0;
}
.dg-team-divider {
  display: block;
  width: 34px;
  height: 2px;
  background: var(--bronze-400);
  margin: 20px 0;
}
.team-readmore {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-family: var(--font-sans);
  font-size: 13px;
  font-weight: var(--w-semibold);
  letter-spacing: 0.02em;
  color: var(--accent-strong);
}


/* ============================================================
   19. IMAGE HOVER
   Apply .img-hover to Divi Image Modules via CSS Class field.
   ============================================================ */

.img-hover {
  transition: transform var(--dur-slow) var(--ease-out);
}
.img-hover:hover {
  transform: scale(1.04);
}

/* Wrap image containers that should clip the scale */
.img-hover-wrap {
  overflow: hidden;
  border-radius: var(--radius-card);
}
.img-hover-wrap .img-hover:hover {
  transform: scale(1.04);
}


/* ============================================================
   20. REDUCED MOTION
   Disables all animations and transitions for users who request it.
   Applies to Divi's scroll reveal animations as well.
   ============================================================ */

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto !important;
  }
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
  .img-hover:hover,
  .community-card:hover,
  .dg-team-card:hover {
    transform: none !important;
  }
  .dg-team-card::before,
  .dg-team-card::after {
    transition: none !important;
  }
}


/* ============================================================
   21. MASTER PLAN — RELEASE STRIP, LAND LEDGER, LIGHTBOX
   Stringfield page, SMasterPlan section (id="master-plan"), sits between
   SStats and SFeatures. Added July 2026 with the master plan overhaul.
   Full HTML + build notes: WORDPRESS_IMPLEMENTATION.md → DA.2 → Section 3.
   JS behavior (accordion toggle + lightbox open/close): dg-masterplan.js.
   ============================================================ */

/* — Release strip: segment width = homesite share of the 340 total — */
.plan-strip {
  display: flex;
  gap: 3px;
}
.plan-strip-seg {
  height: 10px;
  border-radius: var(--radius-xs);
  flex-basis: 0;
}
.plan-seg-sold {
  background: var(--stone-300);
}
.plan-seg-selling {
  background: var(--bronze-400);
}
.plan-seg-future {
  background: var(--paper-12);
  border: 1px solid var(--paper-22);
}

.plan-legend {
  display: flex;
  gap: 28px;
  flex-wrap: wrap;
  margin-top: 16px;
}
.plan-legend-item {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  font-family: var(--font-sans);
  font-size: 12px;
  letter-spacing: var(--ls-caps);
  text-transform: uppercase;
  color: var(--pine-100);
}
.plan-legend-swatch {
  display: inline-block;
  width: 18px;
  height: 8px;
  border-radius: var(--radius-xs);
}
.plan-legend-sold    { background: var(--stone-300); }
.plan-legend-selling { background: var(--bronze-400); }
.plan-legend-future  { background: var(--paper-12); border: 1px solid var(--paper-22); }

/* — Land ledger: 7-row accordion of every release — */
.plan-ledger {
  border-bottom: 1px solid var(--border-on-dark);
}
.plan-ledger-row {
  border-top: 1px solid var(--border-on-dark);
}

.plan-ledger-toggle {
  all: unset;
  display: grid;
  grid-template-columns: 44px 1fr auto auto;
  align-items: center;
  gap: 16px;
  padding: 20px 8px;
  width: 100%;
  box-sizing: border-box;
  cursor: pointer;
  transition: background var(--dur-fast) var(--ease-out);
}
.plan-ledger-toggle:hover {
  background: rgba(246, 241, 231, 0.045);
}
.plan-ledger-toggle:focus-visible {
  outline: 2px solid var(--bronze-400);
  outline-offset: 4px;
}

.plan-ledger-phase {
  font-family: var(--font-display);
  font-style: italic;
  font-size: 15px;
  letter-spacing: 0.04em;
  color: var(--bronze-200);
}
.plan-ledger-name {
  font-family: var(--font-display);
  font-size: clamp(20px, 2.2vw, 26px);
  color: var(--paper);
  line-height: 1.15;
}
.plan-ledger-chip {
  font-family: var(--font-sans);
  font-size: 10.5px;
  font-weight: var(--w-semibold);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  padding: 6px 12px;
  border-radius: var(--radius-pill);
  border: 1px solid;
  white-space: nowrap;
}
.plan-chip-sold    { color: var(--paper-50); border-color: var(--paper-22); }
.plan-chip-selling { color: var(--bronze-200); border-color: var(--bronze-400); }
.plan-chip-future  { color: var(--pine-100); border-color: var(--paper-22); }

.plan-ledger-marker {
  position: relative;
  width: 12px;
  height: 12px;
  flex-shrink: 0;
}
.plan-ledger-marker::before,
.plan-ledger-marker::after {
  content: '';
  position: absolute;
  background: var(--bronze-200);
  transition: transform var(--dur-base) var(--ease-out),
              opacity var(--dur-base) var(--ease-out);
}
.plan-ledger-marker::before {
  left: 0;
  right: 0;
  top: 5.25px;
  height: 1.5px;
}
.plan-ledger-marker::after {
  top: 0;
  bottom: 0;
  left: 5.25px;
  width: 1.5px;
}
.plan-ledger-toggle[aria-expanded="true"] .plan-ledger-marker::after {
  transform: scaleY(0);
  opacity: 0;
}

.plan-ledger-detail {
  display: none;
  padding: 0 8px 28px 60px;
}
.plan-ledger-detail p {
  font-family: var(--font-sans);
  font-size: 15.5px;
  line-height: 1.7;
  color: var(--pine-100);
  max-width: 52ch;
  margin: 0;
}
.plan-ledger-stats {
  display: flex;
  gap: 36px;
  flex-wrap: wrap;
  margin: 20px 0 0;
}
.plan-ledger-stats dt {
  font-family: var(--font-sans);
  font-size: 10.5px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--paper-50);
}
.plan-ledger-stats dd {
  font-family: var(--font-display);
  font-size: 22px;
  color: var(--paper);
  margin: 4px 0 0;
}

/* — Plan plate: click-to-enlarge affordance — */
.plan-plate {
  display: block;
  width: 100%;
  padding: 0;
  border: none;
  background: none;
  cursor: zoom-in;
}
.plan-plate-frame {
  position: relative;
  background: var(--paper);
  padding: 10px;
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-lg);
  overflow: hidden;
}
.plan-plate-frame img {
  display: block;
  width: 100%;
  border-radius: var(--radius-xs);
}
.plan-plate:focus-visible .plan-plate-frame {
  outline: 2px solid var(--bronze-400);
  outline-offset: 4px;
}
.plan-plate-hint {
  position: absolute;
  inset: 10px;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  padding-bottom: 26px;
  background: linear-gradient(to top, rgba(22, 36, 26, 0.4), rgba(22, 36, 26, 0) 46%);
  opacity: 0;
  transition: opacity var(--dur-base) var(--ease-out);
}
.plan-plate:hover .plan-plate-hint,
.plan-plate:focus-visible .plan-plate-hint {
  opacity: 1;
}
.plan-plate-badge {
  padding: 10px 18px;
  border-radius: var(--radius-pill);
  background: var(--paper-92);
  color: var(--ink-900);
  font-family: var(--font-sans);
  font-size: 11.5px;
  font-weight: var(--w-semibold);
  letter-spacing: var(--ls-caps);
  text-transform: uppercase;
  box-shadow: var(--shadow-md);
}
.plan-plate-caption {
  font-family: var(--font-sans);
  font-size: 11px;
  letter-spacing: var(--ls-caps);
  text-transform: uppercase;
  color: var(--paper-50);
  margin-top: 14px;
  text-align: center;
}

/* Sticky on desktop so the plate stays in view while the ledger scrolls */
.plan-sticky {
  position: sticky;
  top: 108px;
  align-self: start;
}
@media (max-width: 768px) {
  .plan-sticky {
    position: static;
  }
}

/* — Lightbox: fade + scale, not a shared-element morph —
   The Next.js version uses Motion's layoutId to make the plate itself grow
   into the full-screen view. That has no practical vanilla-JS equivalent;
   this fade-in overlay reads as equally premium without it. Do not attempt
   to replicate the morph. */
.plan-lightbox {
  position: fixed;
  inset: 0;
  z-index: 9990;
  display: none;
  align-items: center;
  justify-content: center;
  padding: clamp(20px, 6vw, 72px);
  background: rgba(10, 15, 11, 0.88);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
}
.plan-lightbox.is-open {
  display: flex;
}
.plan-lightbox-frame {
  position: relative;
  background: var(--paper);
  padding: 14px;
  border-radius: var(--radius-card);
  box-shadow: 0 48px 120px -24px rgba(0, 0, 0, 0.6);
}
.plan-lightbox-frame img {
  display: block;
  width: min(78vw, calc(80vh * 0.857));
  max-width: 1400px;
  border-radius: var(--radius-xs);
}
.plan-lightbox-close {
  position: absolute;
  top: -18px;
  right: -18px;
  width: 40px;
  height: 40px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius-pill);
  background: var(--pine-900);
  color: var(--paper);
  border: 1px solid var(--paper-22);
  box-shadow: var(--shadow-md);
  cursor: pointer;
  font-size: 22px;
  line-height: 1;
}

/* Hide .dg-header while the lightbox is open — raising the lightbox's own
   z-index further cannot fix this, confirmed live: #plan-lightbox sits
   inside .et_pb_column_0 (Divi's own per-instance markup for this
   section), which Divi gives `position:relative; z-index:2`. That
   combination creates a stacking context, so everything inside it —
   including this lightbox's z-index:9990 — is capped at effective level
   "2" once compared against .dg-header (z-index:500) in the shared root
   context. No z-index on the lightbox itself can escape an ancestor's
   stacking context; only moving the lightbox out of the DOM (out of
   scope here) or removing the header from the comparison entirely would.
   Same :has() pattern already used above for the footer's Back-to-top
   button, keyed off the lightbox's own existing .is-open class (no new
   state). #wpadminbar is untouched and unaffected — it's a sibling of
   #page-container, outside the trapping column entirely, and already
   sits above everything at z-index:110000. */
body:has(#plan-lightbox.is-open) .dg-header {
  visibility: hidden;
  pointer-events: none;
}


/* ============================================================
   22. SUB-BRAND SCOPING — STRINGFIELD / SERENITY
   Each community has its own brand guide (logo, palette, type) distinct
   from the parent Davis Group system above. Rather than re-skin every
   component, both scopes simply redeclare the same custom-property names
   already consumed by .dg-h2-section, .stat-*, .dg-btn-*, .eyebrow-rule,
   .release-row-*, .plan-*, etc. — the cascade does the rest. Apply
   .sf-scope / .sr-scope to the root <section> of every Stringfield /
   Serenity partial; everything outside those subtrees is unaffected.

   Typeface substitutions: both guides specify paid fonts we don't hold a
   license for (Boreal Regular, Bennet Banner, Trajan Pro 3) — see the
   @font-face comments in section 1 for the free equivalents used instead.
   ============================================================ */

/* —— Stringfield at Granite Mountain ——
   Rustic Gold / White / Shadow Gray / Buff Black. */
.sf-scope {
  --font-display: 'Fraunces', 'Didot', Georgia, serif;
  --font-sans:    'Open Sans Condensed', -apple-system, 'Segoe UI', system-ui, sans-serif;

  --accent:        #8B6F4C; /* Rustic Gold */
  --accent-strong: #6F5A3D;
  --bronze-500:    #8B6F4C;
  --bronze-600:    #6F5A3D;
  --bronze-400:    #8B6F4C;
  --bronze-200:    #D8C7AE;
  --stone-300:     #C5C0BB; /* Shadow Gray — "sold out" neutral */

  --text-heading: #3A3B3F;
  --text-body:    #55565B;
  --text-muted:   #8B8C90;

  --surface-page:     #FFFFFF;
  --surface-page-alt: #F7F6F4;
  --surface-card:     #FFFFFF;
  --surface-inverse:  #2B2C2F;
  --pine-900: #2B2C2F; /* dark hero / inverse sections */
  --pine-700: #47484D; /* Buff Black — outline-button border/text */
  --pine-100: #C5C0BB; /* Shadow Gray — labels on dark */

  --border-hairline: rgba(71, 72, 77, 0.16);
  --border-soft:     rgba(71, 72, 77, 0.10);
  --border-on-dark:  rgba(255, 255, 255, 0.16);
  --rule-accent:     #8B6F4C;

  --paper:    #FFFFFF;
  --paper-92: rgba(255, 255, 255, 0.92);
  --paper-90: rgba(255, 255, 255, 0.90);
  --paper-78: rgba(255, 255, 255, 0.78);
  --paper-55: rgba(255, 255, 255, 0.55);
  --paper-50: rgba(255, 255, 255, 0.50);
  --paper-22: rgba(255, 255, 255, 0.22);
  --paper-12: rgba(255, 255, 255, 0.12);
}

/* —— Serenity at Stringfield ——
   Charcoal Grey / Grey / Blue Grey / Charcoal Tan / White. The submark's
   gold sunburst is reserved for the mark itself per the guide — it never
   appears as a site accent color, so the accent role falls to the
   guide's tertiary Blue Grey instead. */
.sr-scope {
  --font-display: 'Roboto', -apple-system, 'Segoe UI', system-ui, sans-serif;
  --font-sans:    'Lora', Georgia, serif;
  --font-accent:  'Cormorant', Georgia, serif; /* wordmark + hero accent line only */

  --accent:        #9CA6B8; /* Blue Grey */
  --accent-strong: #7E8CA3;
  --bronze-500:    #9CA6B8;
  --bronze-600:    #7E8CA3;
  --bronze-400:    #9CA6B8;
  --bronze-200:    #C9D2DC;
  --stone-300:     #C4BFBA; /* Charcoal Tan */

  --text-heading: #323234; /* Charcoal Grey */
  --text-body:    #47474D; /* Grey */
  --text-muted:   #86868C;

  --surface-page:     #FFFFFF;
  --surface-page-alt: #F7F7F7;
  --surface-card:     #FFFFFF;
  --surface-inverse:  #2B2B2B;
  --pine-900: #2B2B2B;
  --pine-700: #323234;
  --pine-100: #C4BFBA; /* Charcoal Tan — labels on dark */

  --border-hairline: rgba(50, 50, 52, 0.14);
  --border-soft:     rgba(50, 50, 52, 0.08);
  --border-on-dark:  rgba(255, 255, 255, 0.16);
  --rule-accent:     #9CA6B8;

  --paper:    #FFFFFF;
  --paper-92: rgba(255, 255, 255, 0.92);
  --paper-90: rgba(255, 255, 255, 0.90);
  --paper-78: rgba(255, 255, 255, 0.78);
  --paper-55: rgba(255, 255, 255, 0.55);
  --paper-50: rgba(255, 255, 255, 0.50);
  --paper-22: rgba(255, 255, 255, 0.22);
  --paper-12: rgba(255, 255, 255, 0.12);
}

/* ============================================================
   23. STRINGFIELD STANDARD — masthead + proof list
   [dg_stringfield_gallery] (partials/sections/stringfield/sgallery.php).
   Redesigned July 2026: replaces a 3-photo craft gallery, then a
   3-column icon grid, with an asymmetric split — a short statement in a
   narrow left column, three hairline-divided proof points set as full
   sentences (display serif, same weight as the headline) in a wider
   right column. Deliberately not a card grid or icon grid — this site
   already has two of those (SFeatures, VPillars); a third would read as
   a template being filled in. Grid columns are a named class (not
   inline, like SFeatures/VPillars use) specifically so this gets a real
   mobile collapse, matching the .stat-grid / .footer-columns pattern
   elsewhere in this file.
   ============================================================ */

.standard-split {
  display: grid;
  grid-template-columns: 0.62fr 1fr;
  gap: clamp(40px, 6vw, 88px);
}

@media (max-width: 768px) {
  .standard-split {
    grid-template-columns: 1fr;
    gap: 32px;
  }
}

.standard-proof-row {
  border-top: 1px solid var(--border-hairline);
  padding: 26px 0;
}

.standard-proof-label {
  font-family: var(--font-sans);
  font-size: var(--t-eyebrow);
  font-weight: var(--w-semibold);
  letter-spacing: var(--ls-eyebrow);
  text-transform: uppercase;
  color: var(--accent-strong);
  margin: 0 0 12px;
}

.standard-proof-desc {
  font-family: var(--font-display);
  font-size: 19px;
  line-height: 1.5;
  color: var(--text-heading);
  margin: 0;
  max-width: 56ch;
}
