/* ===== FONTS =====
   Self-hosted from R2 rather than fetched from Google. Three reasons, in order
   of how much they cost: a third-party font host is a second DNS lookup, a
   second TLS handshake and a dependency whose downtime is invisible to us; the
   files are served with max-age=31536000, immutable, which Google caps far
   lower; and nothing about a visitor is announced to a third party.

   These are the same subsetted WOFF2 files Google serves - same unicode-range
   splits, so a page still downloads only the latin range it needs - copied to
   c21-branding/fonts/ and served from our own domain. Regenerate them with the
   manifest rather than editing by hand: the file names encode style, weight
   and subset, and a mismatch here fails silently as a fallback face.
   ================= */
@font-face {
  font-family: 'DM Serif Display';
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url(https://library.c21masters.com/c21-branding/fonts/dm-serif-display/dm-serif-display-italic-400-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'DM Serif Display';
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url(https://library.c21masters.com/c21-branding/fonts/dm-serif-display/dm-serif-display-italic-400-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'DM Serif Display';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(https://library.c21masters.com/c21-branding/fonts/dm-serif-display/dm-serif-display-normal-400-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'DM Serif Display';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(https://library.c21masters.com/c21-branding/fonts/dm-serif-display/dm-serif-display-normal-400-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Plus Jakarta Sans';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url(https://library.c21masters.com/c21-branding/fonts/plus-jakarta-sans/plus-jakarta-sans-normal-400-700-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Plus Jakarta Sans';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url(https://library.c21masters.com/c21-branding/fonts/plus-jakarta-sans/plus-jakarta-sans-normal-400-700-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* =====================================================================
   CALIFORNIA — Century 21 Masters agent template
   Mirror of https://library.c21masters.com/global-css/california.css
   --------------------------------------------------------------------
   Warm coastal editorial. DM Serif Display over Plus Jakarta Sans, deep
   teal and gold on a sand ground.

   Derived from "California Luxury". Rules dropped for markup that no longer
   exists: stat bands, hero counters, the invented property cards, the team
   grid, and the hand-written form.

   The .footer-* rules are dropped for a different reason: footer.js injects
   an element with class footer-bottom, and the source defines that same
   class. Keeping them would restyle the injected footer.

   Fonts are loaded by head-meta.njk, not here.
   ===================================================================== */

/* ==========================================================================
   CALIFORNIA LUXURY — Alta Mar Estates
   Warm, modern West Coast real estate template
   Fonts: DM Serif Display (display) / Plus Jakarta Sans (body)
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Design Tokens
   -------------------------------------------------------------------------- */
:root {
  /* Brand palette */
  --color-primary: #2A3D45;
  --color-secondary: #C9A86A;
  --color-accent: #F3EBDD;
  --color-background: #FFFFFF;
  --color-surface: #F7F5F2;
  --color-text: #2C2C2C;
  --color-muted: #707070;
  --color-border: #E8E2D6;

  /* Derived states */
  --color-primary-hover: #223239;
  --color-primary-soft: #3C535D;
  --color-secondary-hover: #B8945A;
  --color-secondary-active: #A5834E;
  --color-accent-deep: #EADFC9;
  --color-success: #4A7C59;
  --color-error: #B0413E;

  /* On-dark */
  --color-on-dark: #F7F5F2;
  --color-on-dark-muted: rgba(247, 245, 242, 0.62);
  --color-on-dark-border: rgba(247, 245, 242, 0.15);

  /* Sun glow gradient */
  --gradient-sun: radial-gradient(circle at 50% 50%, rgba(201, 168, 106, 0.28) 0%, rgba(243, 235, 221, 0) 65%);

  /* Typography */
  --font-display: "DM Serif Display", Georgia, serif;
  --font-body: "Plus Jakarta Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;

  /* The ceiling is 4.5rem rather than 5.75rem because this size never gets the
     viewport it is scaled against. Every headline using it sits in the 7fr
     column of a 7fr/5fr grid inside a 78rem container - about 634px at 1440 -
     so 5.8vw kept growing the type while its column stayed still. At 92px the
     home headline broke over four lines, two of them a single word, and the
     interior bands stopped matching: five came out at 465px and About and
     Buyers at 556px, because their headlines needed a third line the
     min-height was never set for. At 72px every interior headline holds two
     lines and all seven bands land on the 29rem floor. Mobile and tablet are
     unchanged - the clamp does not reach its ceiling until about 855px. */
  --text-display: clamp(2.875rem, 1.4rem + 5.8vw, 4.5rem);
  --text-h1: clamp(2.5rem, 1.5rem + 3.8vw, 4.25rem);
  --text-h2: clamp(1.875rem, 1.3rem + 2.3vw, 2.875rem);
  --text-h3: clamp(1.375rem, 1.15rem + 1vw, 1.875rem);
  --text-h4: clamp(1.125rem, 1rem + 0.5vw, 1.375rem);
  --text-body-lg: clamp(1.0625rem, 1rem + 0.25vw, 1.1875rem);
  --text-body: 1rem;
  --text-caption: 0.875rem;
  --text-label: 0.75rem;

  /* Spacing */
  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-6: 1.5rem;
  --space-8: 2rem;
  --space-12: 3rem;
  --space-16: 4rem;
  --space-20: 5rem;
  --space-24: 6rem;

  --section-padding: clamp(4.5rem, 3rem + 6vw, 8.5rem);
  --container-max: 78rem;
  --container-pad: clamp(1.25rem, 4vw, 2.5rem);

  /* Elevation */
  --shadow-sm: 0 2px 8px rgba(42, 61, 69, 0.06);
  --shadow-md: 0 14px 40px -16px rgba(42, 61, 69, 0.18);
  --shadow-lg: 0 30px 70px -24px rgba(42, 61, 69, 0.28);

  /* Motion */
  --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
  --duration-fast: 200ms;
  --duration-med: 450ms;
  --duration-slow: 900ms;

  /* Radii — soft, coastal, arched */
  --radius-md: 1rem;
  --radius-lg: 1.5rem;
  --radius-pill: 999px;
  --radius-arch: 12rem 12rem 0 0;
}

/* --------------------------------------------------------------------------
   2. Reset & Base
   -------------------------------------------------------------------------- */
*,
*::before,
*::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

html {
  scroll-behavior: smooth;
  -webkit-text-size-adjust: 100%;
}

body {
  font-family: var(--font-body);
  font-size: var(--text-body);
  line-height: 1.75;
  color: var(--color-text);
  background-color: var(--color-background);
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

img {
  max-width: 100%;
  height: auto;
  display: block;
}

a {
  color: inherit;
  text-decoration: none;
}

ul, ol {
  list-style: none;
}

/* The same reset again, keyed to this template's own lists.
   `ul` is one element selector, so anything else that says `ul { list-style:
   disc }` matches it and the later sheet wins. On the contact page there are
   twelve later sheets: form-inject.js pulls the WordPress side of the Fluent
   Forms embed - Kadence's global.min.css and content.min.css among them - into
   the page after this file, and one of them restores disc.
   The result was bullets down the middle of the navigation bar, on the contact
   page only, on all 582 sites. Nothing reported it, and it did not reproduce
   on any other page, because no other page loads the form.
   A class beats an element selector at any cascade position, which is the
   whole fix. Do not reach for !important here. */
.nav-list,
.nav-sub,
.check-list,
.checklist {
  list-style: none;
}

button {
  font: inherit;
  border: none;
  background: none;
  cursor: pointer;
}

::selection {
  background: var(--color-primary);
  color: var(--color-accent);
}

:focus-visible {
  outline: 2px solid var(--color-secondary);
  outline-offset: 3px;
}

.skip-link {
  position: absolute;
  top: -100%;
  left: var(--space-4);
  z-index: 200;
  padding: var(--space-3) var(--space-6);
  background: var(--color-primary);
  color: var(--color-on-dark);
  font-size: var(--text-caption);
  border-radius: var(--radius-pill);
}

.skip-link:focus {
  top: var(--space-4);
}

/* --------------------------------------------------------------------------
   3. Typography
   -------------------------------------------------------------------------- */
h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-weight: 400;
  line-height: 1.08;
  color: var(--color-primary);
  letter-spacing: 0.005em;
}

h1 { font-size: var(--text-h1); }
h2 { font-size: var(--text-h2); }
h3 { font-size: var(--text-h3); }
h4 { font-size: var(--text-h4); }

.text-display {
  font-size: var(--text-display);
  line-height: 1.02;
}

.text-lead {
  font-size: var(--text-body-lg);
  line-height: 1.85;
  color: var(--color-muted);
}

/* Search, Sold and Calculator each open with a .text-lead and then put a block
   straight after it - the listings widget, .sold-empty, the calculator. With no
   margin those blocks began on the paragraph's last line: .sold-empty drew its
   border-top through the text, and the widget's first row of cards touched it. */
.text-lead + * { margin-top: var(--space-8); }

em, .text-italic {
  font-style: italic;
}

.text-gold {
  color: var(--color-secondary);
}

h1 em, h2 em {
  color: var(--color-secondary);
}

/* Eyebrow — pill chip */
.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--text-label);
  font-weight: 700;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--color-primary);
  background: var(--color-accent);
  border-radius: var(--radius-pill);
  padding: 0.5rem 1.125rem;
  margin-bottom: var(--space-6);
}

.eyebrow::before {
  content: "";
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 50%;
  background: var(--color-secondary);
}

.eyebrow--on-dark {
  background: rgba(247, 245, 242, 0.1);
  color: var(--color-on-dark);
}

/* The chip's fill is --color-accent and .section--accent paints its whole band
   that same #F3EBDD, so on those four sections the pill was invisible against
   its own background: "How I Help" read as loose text beside a floating dot.
   White is the one fill that separates from the accent band while keeping the
   chip the same component it is on the surface sections. The dot and the label
   are unchanged - only the fill they sit on has to move. */
.section--accent .eyebrow {
  background: var(--color-background);
}

/* A pill chip has to stay one line, and tracking is what to give up for it
   rather than size - the label stays at --text-label everywhere.
   At 0.22em, "California Coastal Real Estate" needs the full 335px a 390px
   phone has, so any heroSubtitle a character longer wraps the pill into a
   two-line rounded box with the dot beside the middle of it. 0.15em and
   slightly tighter padding buy about 30px, four characters of headroom.
   Subtitles longer than that are a data problem, not a CSS one: this is a
   chip, and there is no size at which a sentence fits in one. */
@media (max-width: 30em) {
  .eyebrow {
    letter-spacing: 0.15em;
    padding: 0.45rem 0.95rem;
  }
}

/* --------------------------------------------------------------------------
   4. Layout Primitives
   -------------------------------------------------------------------------- */
.container {
  width: 100%;
  max-width: var(--container-max);
  margin-inline: auto;
  padding-inline: var(--container-pad);
}

.section {
  padding-block: var(--section-padding);
}

.section--surface { background: var(--color-surface); }
.section--accent { background: var(--color-accent); }
.section--dark { background: var(--color-primary); }

.section--dark h2,
.section--dark h3 { color: var(--color-on-dark); }
.section--dark p { color: var(--color-on-dark-muted); }

.section-head {
  max-width: 42rem;
  margin-bottom: clamp(2.5rem, 2rem + 3vw, 4.5rem);
}

.section-head--centered {
  margin-inline: auto;
  text-align: center;
}

/* :not(.eyebrow) for the same reason the two .hero-copy rules carry it. Every
   section head opens with a <p class="eyebrow">, so `.section-head p` at
   (0,1,1) outranked `.eyebrow` at (0,1,0) and took the pill over: 19px instead
   of 12px, muted grey instead of primary, and a 16px top margin the chip is
   not supposed to have. It made the eight section pills a third taller than
   the identical chip in the hero directly above them. */
.section-head p:not(.eyebrow) {
  margin-top: var(--space-4);
  color: var(--color-muted);
  font-size: var(--text-body-lg);
}

.section--dark .section-head p { color: var(--color-on-dark-muted); }

/* --------------------------------------------------------------------------
   5. Buttons — pill-shaped, warm
   -------------------------------------------------------------------------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  padding: 1.05rem 2.25rem;
  font-size: var(--text-caption);
  font-weight: 700;
  letter-spacing: 0.04em;
  border-radius: var(--radius-pill);
  border: 1.5px solid transparent;
  transition: background-color var(--duration-fast) var(--ease-out),
              color var(--duration-fast) var(--ease-out),
              border-color var(--duration-fast) var(--ease-out),
              box-shadow var(--duration-fast) var(--ease-out),
              transform var(--duration-fast) var(--ease-out);
}

.btn:hover { transform: translateY(-2px); box-shadow: var(--shadow-md); }
.btn:active { transform: translateY(0); box-shadow: none; }

.btn svg { width: 1.05rem; height: 1.05rem; }

.btn--primary {
  background: var(--color-primary);
  color: var(--color-on-dark);
}

.btn--primary:hover { background: var(--color-primary-hover); }

.btn--gold {
  background: var(--color-secondary);
  color: #FFFFFF;
}

.btn--gold:hover { background: var(--color-secondary-hover); }
.btn--gold:active { background: var(--color-secondary-active); }

.btn--outline {
  border-color: var(--color-primary);
  color: var(--color-primary);
}

.btn--outline:hover {
  background: var(--color-primary);
  color: var(--color-on-dark);
}

.btn--outline-light {
  border-color: var(--color-on-dark-border);
  color: var(--color-on-dark);
}

.btn--outline-light:hover {
  border-color: var(--color-secondary);
  color: var(--color-secondary);
}

/* Text link */
.link-arrow {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--text-caption);
  font-weight: 700;
  color: var(--color-primary);
}

.link-arrow svg {
  width: 1rem;
  height: 1rem;
  /* --color-secondary is 1.90:1 on the accent card behind these links. The
     arrow travels with a text label so it is closer to decoration than to a
     meaningful graphic, but at 1.90:1 it is barely there at all; this is
     3.31:1 and still reads as the same gold. */
  color: #9E7B39;
  transition: transform var(--duration-med) var(--ease-out);
}

.link-arrow:hover svg {
  transform: translateX(5px);
}

/* --------------------------------------------------------------------------
   6. Header & Navigation
   -------------------------------------------------------------------------- */
.site-header {
  position: sticky;
  top: 0;
  z-index: 100;
  background: rgba(255, 255, 255, 0.92);
  -webkit-backdrop-filter: blur(14px);
  backdrop-filter: blur(14px);
  border-bottom: 1px solid transparent;
  transition: border-color var(--duration-med) var(--ease-out),
              box-shadow var(--duration-med) var(--ease-out);
}

.site-header.is-scrolled {
  border-color: var(--color-border);
  box-shadow: var(--shadow-sm);
}

/* The header row is not capped at --container-max the way page content is.
   Measured at 1440: the full Gold nav needs 1255px of row (208 for the agent's
   name, 929 for eight links, the rest burger and gutters) while the 78rem
   container only ever offers 1168 - so the nav did not fit at any screen size,
   and nav-fit was nesting three items on a desktop to compensate.

   Uncapping it buys 105px of headroom at 1440 and more above that, which also
   leaves room for the names this has to survive: the row carries the agent's
   name, and "Christopher Vanderhoeven" is not "Cali Doe". Page content stays
   capped, so only the header spans wider. */
.site-header .container {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-8);
  height: 5.5rem;
  max-width: none;
}

.brand {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  white-space: nowrap;
}

.brand-mark {
  display: grid;
  place-items: center;
  width: 2.75rem;
  height: 2.75rem;
  border-radius: 50% 50% 4px 4px;   /* miniature arch */
  background: var(--color-primary);
  color: var(--color-secondary);
}

.brand-mark svg {
  width: 1.35rem;
  height: 1.35rem;
}

.brand-name {
  font-family: var(--font-display);
  font-size: 1.4rem;
  color: var(--color-primary);
  line-height: 1;
}

.brand-name small {
  display: block;
  font-family: var(--font-body);
  font-size: 0.5625rem;
  font-weight: 700;
  letter-spacing: 0.34em;
  text-transform: uppercase;
  color: var(--color-secondary);
  margin-top: 0.3rem;
}

.site-nav {
  display: flex;
  align-items: center;
  gap: var(--space-8);
}

.nav-list {
  display: flex;
  align-items: center;
  gap: clamp(1rem, 2vw, 2rem);
}

.nav-list a {
  font-size: var(--text-caption);
  font-weight: 600;
  color: var(--color-text);
  padding: 0.5rem 0.875rem;
  border-radius: var(--radius-pill);
  transition: background-color var(--duration-fast) var(--ease-out),
              color var(--duration-fast) var(--ease-out);
}

.nav-list a:hover {
  background: var(--color-accent);
  color: var(--color-primary);
}

.nav-list a[aria-current="page"] {
  background: var(--color-primary);
  color: var(--color-on-dark);
}

.nav-cta { padding: 0.8rem 1.6rem; }

/* The header CTA inherits .btn--gold, whose white-on-gold is 2.26:1. Ink on
   the gold is 5.15:1, so the label is legible at rest. Hover then inverts to
   the primary fill (10.4:1) instead of .btn--gold's darker gold, which would
   have taken ink text down to 4.04:1 - darkening the fill under dark text is
   the wrong direction once the text is no longer white.
   Scoped to .nav-cta on purpose: .btn--gold carries the same 2.26:1 in the
   page body, and that is a template-wide decision rather than a header one. */
.nav-cta.btn--gold { color: var(--color-primary); }
.nav-cta.btn--gold:hover,
.nav-cta.btn--gold:focus-visible {
  background: var(--color-primary);
  color: var(--color-on-dark);
}

.nav-toggle {
  display: none;
  color: var(--color-primary);
  width: 2.75rem;
  height: 2.75rem;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: var(--color-accent);
}

.nav-toggle svg { width: 1.4rem; height: 1.4rem; }
.nav-toggle .icon-close { display: none; }
.nav-open .nav-toggle .icon-menu { display: none; }
.nav-open .nav-toggle .icon-close { display: block; }

/* Burger panel — the overflow menu, and the phone menu, and the same thing at
   every width in between. This used to be @media (max-width: 63.99em), one
   number standing in for 586 different agent-name lengths, and it left this
   nav 26px over the viewport before the Home Valuation link was even added.
   What replaced it is global-js/nav-fit.js: it keeps as many items inline as
   the row can hold and nests the rest here. This template's container caps at
   1248px, so a couple of links nest even on a large screen — that is the
   honest answer, and it is the one the breakpoint was hiding. */
/* A drawer, not a band: anchored to the right edge, sized to its contents, and
   sliding in from the side with a fade rather than dropping the full width of
   the window down over the page.

   Width is set by breakpoint rather than by content: half the window from
   442px up, the whole window at 441 and below. Sizing to the longest label
   read as arbitrary - the same menu came out a different width on every
   template, because it was really measuring the font - whereas half the
   screen is a proportion a visitor recognises and it is reproducible across
   designs. On a phone there is no useful page left to show behind a drawer,
   so it takes the lot.

   Height fills the screen instead, and that is a change. It was auto for a
   good reason under the old policy: the panel could hold a single leftover
   link, and a full-height column containing one word reads as a broken page.
   data-nav-fit="all" removes that case - the drawer now holds either the
   entire nav or nothing at all, so it is never nearly empty. Left on auto it
   stopped partway down and opened a dead band between its bottom edge and the
   foot of the window. Reaching the bottom is also most of what makes this read
   as a drawer rather than a dropdown.

   This pairs with the all-or-nothing policy. A template still running
   priority+ wants the old auto height, for the reason above.

   visibility is in the transition with a delay so it flips instantly on open
   and only after the slide has finished on close. Without that the panel
   disappears on the first frame of closing and the animation is never seen. */
.nav-panel {
  position: fixed;
  top: 5.5rem;
  right: 0;
  left: auto;
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  align-items: stretch;
  /* The rhythm is on the rows now, not on this gap. Every child used to sit
     2rem from the next, which on a 390x844 phone put the CTA 71px past the
     bottom of the drawer; the rows carry their own padding and rules instead,
     so the whole menu including the CTA is reachable without scrolling. */
  gap: 0;
  padding: var(--space-6) var(--space-8) var(--space-8);
  /* Teal, with the sun behind it. --gradient-sun is the same wash the page
     heroes put in their top corner; at this size and this low a stop it reads
     as depth in the ground rather than as a shape, and it keeps the drawer
     from being a flat rectangle of primary. The gold rule at the top is what
     separates the drawer from the header, which turns --color-primary while
     the menu is open - without it the two are one unbroken block of teal and
     the panel has no edge at all. */
  background:
    linear-gradient(90deg, var(--color-secondary) 0%, rgba(201, 168, 106, 0.35) 38%, transparent 100%) top left / 100% 2px no-repeat,
    var(--gradient-sun) top right / 26rem 26rem no-repeat,
    var(--color-primary);
  box-shadow: var(--shadow-lg);
  width: 50%;
  height: calc(100svh - 5.5rem);
  overflow-y: auto;
  /* Reaching the last link and having the page start moving underneath is the
     part that reads as broken. */
  overscroll-behavior: contain;
  transform: translateX(100%);
  opacity: 0;
  visibility: hidden;
  transition: transform var(--duration-med) var(--ease-out),
              opacity var(--duration-med) var(--ease-out),
              visibility 0s linear var(--duration-med);
  z-index: 99;
}

.nav-open .nav-panel {
  transform: translateX(0);
  opacity: 1;
  visibility: visible;
  /* Nothing waits on the way in. */
  transition-delay: 0s;
}

/* Phones take the whole window. Half of 400px is a 200px column of menu beside
   200px of a page nobody can read, which serves neither. 441 is the ceiling
   rather than a round 440 so that a 440px-wide phone still gets the full
   width. */
@media (max-width: 441px) {
  .nav-panel { width: 100%; }
}

/* The fade carries the state change on its own, so the slide is the part that
   goes. Keeping visibility out of the transition here means it still flips
   immediately rather than lingering for a duration that no longer runs. */
@media (prefers-reduced-motion: reduce) {
  .nav-panel {
    transform: none;
    transition: opacity var(--duration-fast) linear, visibility 0s linear var(--duration-fast);
  }
  .nav-open .nav-panel { transform: none; }
}

.nav-open .site-header {
  background: var(--color-primary);
  border-color: transparent;
}

.nav-open .site-header .brand-name { color: var(--color-on-dark); }
.nav-open .site-header .nav-toggle { background: rgba(247,245,242,0.12); color: var(--color-on-dark); }

.nav-panel .nav-list {
  flex-direction: column;
  align-items: stretch;
  gap: 0;
  width: 100%;
}

/* Top-level rows in the display face. Plus Jakarta at 1.25rem/600 is the bar's
   voice, which is right for eight items in an 88px band and wrong for a column
   with a drawer to itself: it made the menu read as a settings list. DM Serif
   names the pages, and the sub-rows below stay in Jakarta's uppercase, which
   is what makes them read as belonging to the row above rather than competing
   with it. */
.nav-panel .nav-list > li > a {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  font-family: var(--font-display);
  font-size: clamp(1.25rem, 1.1rem + 0.6vw, 1.55rem);
  font-weight: 400;
  line-height: 1.25;
  color: var(--color-on-dark);
  padding: 0.5rem 0;
  transition: color var(--duration-fast) var(--ease-out),
              transform var(--duration-fast) var(--ease-out);
}

/* Hairlines between the top-level entries, in the template's own on-dark
   border tone. */
.nav-panel .nav-list > li + li { border-top: 1px solid var(--color-on-dark-border); }

/* The marker is .eyebrow's gold dot, reused: it is this template's smallest
   brand unit, it already means "you are here" beside every section label on
   the site, and it needs no box around it. Held at zero scale until the row is
   hovered, focused or current, so the column stays quiet at rest. */
.nav-panel .nav-list > li > a::before {
  content: "";
  flex: none;
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 50%;
  background: var(--color-secondary);
  transform: scale(0);
  transition: transform var(--duration-fast) var(--ease-out);
}
.nav-panel .nav-list > li > a:hover,
.nav-panel .nav-list > li > a:focus-visible { color: var(--color-secondary); }
.nav-panel .nav-list > li > a:hover::before,
.nav-panel .nav-list > li > a:focus-visible::before { transform: scale(1); }

/* The page you are on: gold ink and the dot already lit, so the drawer answers
   "where am I" before anything is touched. The gold FILL this used to paint
   behind the label goes: at 1.55rem in a serif it read as a highlighter pen
   across the row, and it is kept for the sub-rows below, where a chip is what
   this template does with small caps. */
.nav-panel .nav-list > li > a[aria-current="page"] { color: var(--color-secondary); }
.nav-panel .nav-list > li > a[aria-current="page"]::before { transform: scale(1); }

/* ---- The drawer's CTA -------------------------------------------------
   Full width, and taller than the bar's version: it is the last thing in the
   column the menu makes, and at .nav-cta's own 0.8rem/1.6rem it sat in the
   drawer like a button that had wandered in from the header. The pill shape is
   this template's, so it stays a pill rather than becoming a bar. */
.nav-panel .nav-cta {
  width: 100%;
  margin-top: var(--space-6);
  padding: 1.05rem 1.6rem;
  /* order, because the DOM order is not ours to keep. nav-fit.js sends this
     element home with panel.appendChild() - its panel home is the panel itself
     rather than the list, because this template's list is a <ul> - so the first
     layout() moves it to the END of the panel, below the foot. Ordering both
     here means the drawer reads list, CTA, foot whichever of them the script
     has just re-appended. */
  order: 1;
}

/* ---- The foot --------------------------------------------------------
   Whose menu this is, and the one number that reaches them. Quiet by
   construction: the last thing in the drawer, not a second CTA. */
.nav-panel__foot {
  order: 2;
  margin-top: var(--space-6);
  padding-top: var(--space-4);
  border-top: 1px solid var(--color-on-dark-border);
}
.nav-panel__who {
  display: block;
  font-family: var(--font-display);
  font-size: var(--text-h4);
  color: var(--color-on-dark);
}
.nav-panel__tel {
  display: inline-block;
  margin-top: var(--space-1);
  font-size: var(--text-caption);
  font-weight: 600;
  letter-spacing: 0.08em;
  color: var(--color-on-dark-muted);
  text-decoration: none;
  transition: color var(--duration-fast) var(--ease-out);
}
.nav-panel__tel:hover,
.nav-panel__tel:focus-visible { color: var(--color-secondary); }

body.nav-open { overflow: hidden; }

/* The burger appears only when the panel has something in it. nav-fit.js sets
   this to "false" when every item fits inline; it is absent until the script
   runs, and absent has to mean visible - that is the state a phone loads in,
   with every item still in the panel. */
.nav-toggle { display: inline-flex; }
[data-nav-overflow="false"] .nav-toggle { display: none; }

/* An inline nav link that wraps to a second line is the thing overflow is
   there to prevent, so it must not be an option the row can take instead. */
.site-nav .nav-list a,
.site-nav .nav-cta { white-space: nowrap; }

/* --------------------------------------------------------------------------
   6b. Nav submenus
   --------------------------------------------------------------------------
   Buyers carries Calculator; Sellers carries Home Valuation and Sold. A group
   is ONE element, so nav-fit.js moves it whole and knows nothing about the
   nesting - all that is left is how it reads in each of the two places it can
   land.

   Inline it is an absolutely positioned dropdown, and that is not a styling
   preference: a submenu in flow would make the group as wide as its widest
   child, nav-fit would measure that width, and the group would nest at every
   screen size - so the dropdown would never once be seen.

   It opens on :hover and on :focus-within, and no script owns either. Focus
   reaches the parent link, which is always visible, before it can reach into
   the submenu, so :focus-within is already true by the time the next Tab
   lands inside. That is what lets the closed state use visibility:hidden and
   keep the submenu out of the tab order until it is on screen. */
.nav-group { position: relative; display: flex; align-items: center; }
.nav-group > a { display: inline-flex; align-items: center; gap: 0.45em; }
.nav-sub { display: flex; flex-direction: column; }

/* Drawn from borders rather than an icon: Lucide is inlined in
   global-js/california.js and runs after first paint, so an <i data-lucide>
   here would be an empty box in the bar until that script landed. */
.nav-caret {
  width: 0.34em; height: 0.34em; flex: none;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: translateY(-0.1em) rotate(45deg);
  transition: transform var(--duration-fast) var(--ease-out);
}

/* Inline: the dropdown */
[data-nav-fit-inline] .nav-sub {
  position: absolute;
  top: 100%; left: 0;
  min-width: max-content;
  gap: var(--space-1);
  margin-top: var(--space-3);
  padding: var(--space-2);
  background: var(--color-background);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md);
  opacity: 0;
  visibility: hidden;
  transform: translateY(-4px);
  transition: opacity var(--duration-fast) var(--ease-out),
              transform var(--duration-fast) var(--ease-out),
              visibility var(--duration-fast) var(--ease-out);
  z-index: 110;
}
/* The gap between the label and the card is dead ground the pointer has to
   cross, and crossing it would close the menu. This bridges it. */
[data-nav-fit-inline] .nav-sub::before {
  content: ""; position: absolute; left: 0; right: 0;
  top: calc(var(--space-3) * -1); height: var(--space-3);
}
[data-nav-fit-inline] .nav-group:hover .nav-sub,
[data-nav-fit-inline] .nav-group:focus-within .nav-sub {
  opacity: 1; visibility: visible; transform: translateY(0);
}
[data-nav-fit-inline] .nav-group:hover .nav-caret,
[data-nav-fit-inline] .nav-group:focus-within .nav-caret { transform: translateY(0.08em) rotate(-135deg); }
[data-nav-fit-inline] .nav-sub a { display: block; padding: var(--space-2) var(--space-4); }

/* Panel: an indented block, always open. There is no disclosure to tap - the
   panel exists to show what did not fit, so hiding half of it behind a second
   interaction would defeat it. */
[data-nav-fit-panel] .nav-group {
  flex-direction: column;
  align-items: stretch;
  /* Tight to its parent: the group is one entry with its pages under it, and
     0.75rem here made the children read as siblings of the row above. */
  gap: 0;
}
[data-nav-fit-panel] .nav-sub {
  gap: 0;
  /* Indented to sit under the parent row's label rather than starting a second
     column, and the rule is the on-dark border rather than a full-strength
     line: at seven sub-rows a heavier one turns the drawer into a table. */
  margin: 0 0 var(--space-3) 1.25rem;
  padding-left: var(--space-4);
  border-left: 1px solid var(--color-on-dark-border);
}
[data-nav-fit-panel] .nav-sub a {
  display: inline-flex;
  font-family: var(--font-body);
  font-size: var(--text-label);
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--color-on-dark-muted);
  padding: 0.4rem 0;
  transition: color var(--duration-fast) var(--ease-out);
}
[data-nav-fit-panel] .nav-sub a:hover,
[data-nav-fit-panel] .nav-sub a:focus-visible { color: var(--color-on-dark); }

/* The chip, kept for the sub-rows: small caps inside a pill is what this
   template does everywhere else - it is .eyebrow's own shape - and at this
   size it reads as a chip rather than as a highlighter. Ink on gold is 5.15:1;
   white on the same gold is 2.26:1, which is why the label is --color-primary. */
[data-nav-fit-panel] .nav-sub a[aria-current="page"] {
  background: var(--color-secondary);
  color: var(--color-primary);
  border-radius: var(--radius-pill);
  padding-inline: 0.75rem;
}
[data-nav-fit-panel] .nav-caret { display: none; }

/* --------------------------------------------------------------------------
   7. Split Hero (home)
   -------------------------------------------------------------------------- */
.hero-split {
  position: relative;
  background: var(--color-surface);
  overflow: hidden;
}

.hero-split::before {
  content: "";
  position: absolute;
  top: -22rem;
  left: -14rem;
  width: 44rem;
  height: 44rem;
  background: var(--gradient-sun);
  border-radius: 50%;
  pointer-events: none;
}

.hero-split .container {
  display: grid;
  gap: clamp(2.5rem, 2rem + 3vw, 4rem);
  align-items: center;
  padding-block: clamp(3rem, 2rem + 4vw, 5.5rem);
}

@media (min-width: 64em) {
  .hero-split .container {
    grid-template-columns: 7fr 5fr;
    min-height: calc(100svh - 5.5rem);
  }
}

.hero-copy { position: relative; z-index: 1; }

.hero-copy h1 {
  margin-bottom: var(--space-6);
  /* The headline is agent copy, so its longest word is not known at design
     time. A word with no break opportunity has to break rather than run out
     of the hero, which clips it. Same guard as timeless and aurelia. */
  overflow-wrap: break-word;
}

/* :not(.eyebrow) for the same reason the .page-hero rule carries it, and this
   is the copy of the rule that was missing it. The eyebrow is a <p> and a
   direct child of .hero-copy, so `.hero-copy > p` at (0,1,1) outranks
   `.eyebrow` at (0,1,0) and took the pill over: 17px instead of 12px, muted
   grey instead of primary, and a 32rem max-width that made it wrap to two
   lines on a phone. The home hero was the only place it happened, so the chip
   looked like a different component there than on the other seven pages. */
.hero-copy > p:not(.eyebrow) {
  font-size: var(--text-body-lg);
  color: var(--color-muted);
  max-width: 32rem;
  margin-bottom: var(--space-8);
}

.hero-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
}

/* Once these wrap they are a stack, and a stack of two pills sized to their own
   labels is ragged - "Find Your Home" came out 213px against "Talk to Cali" at
   153px. Below the width where they can sit side by side they share it instead.
   Not on .btn generally: the same class is a lone inline button elsewhere. */
@media (max-width: 30em) {
  .hero-actions { flex-direction: column; align-items: stretch; }
  .hero-actions .btn { width: 100%; }
}

.hero-figure {
  position: relative;
  justify-self: center;
  width: min(100%, 26rem);
}

.hero-figure img {
  width: 100%;
  aspect-ratio: 4 / 5.2;
  object-fit: cover;
  border-radius: var(--radius-arch);
  box-shadow: var(--shadow-lg);
}

.hero-figure::before {
  content: "";
  position: absolute;
  inset: -1.1rem -1.1rem auto -1.1rem;
  height: 55%;
  border: 1.5px solid var(--color-secondary);
  border-bottom: none;
  border-radius: var(--radius-arch);
  opacity: 0.55;
  pointer-events: none;
}

/* Rotating circular badge */
.spin-badge {
  position: absolute;
  bottom: -2.25rem;
  left: -2.75rem;
  width: 8.5rem;
  height: 8.5rem;
  display: grid;
  place-items: center;
}

.spin-badge .spin-text {
  position: absolute;
  inset: 0;
  animation: spin 22s linear infinite;
}

.spin-badge .spin-text text {
  font-family: var(--font-body);
  font-size: 8.2px;
  font-weight: 700;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  fill: var(--color-primary);
}

.spin-badge-core {
  display: grid;
  place-items: center;
  width: 4.25rem;
  height: 4.25rem;
  background: var(--color-secondary);
  color: #fff;
  border-radius: 50%;
}

.spin-badge-core svg { width: 1.5rem; height: 1.5rem; }

.spin-badge::before {
  content: "";
  position: absolute;
  inset: 0.65rem;
  background: var(--color-accent);
  border-radius: 50%;
  z-index: -1;
  box-shadow: var(--shadow-md);
}

@keyframes spin {
  to { transform: rotate(360deg); }
}

@media (max-width: 47.99em) {
  .spin-badge { left: auto; right: -0.75rem; bottom: -1.75rem; transform: scale(0.85); }
}

/* --------------------------------------------------------------------------
   8. Marquee strip
   -------------------------------------------------------------------------- */
.marquee {
  background: var(--color-primary);
  color: var(--color-accent);
  overflow: hidden;
  padding-block: var(--space-4);
  border-block: 1px solid var(--color-primary);
}

.marquee-track {
  display: flex;
  gap: var(--space-8);
  width: max-content;
  animation: marquee 32s linear infinite;
}

.marquee:hover .marquee-track { animation-play-state: paused; }

.marquee-track span {
  display: inline-flex;
  align-items: center;
  gap: var(--space-8);
  font-family: var(--font-display);
  font-size: 1.2rem;
  letter-spacing: 0.06em;
  white-space: nowrap;
}

.marquee-track i {
  font-style: normal;
  color: var(--color-secondary);
  font-size: 0.9rem;
}

@keyframes marquee {
  to { transform: translateX(-50%); }
}

/* --------------------------------------------------------------------------
   9. Page hero (interior pages) — the home hero's band, text-led
   --------------------------------------------------------------------------
   Deliberately the same ground, glow, measure and load-in as .hero-split, so
   an interior page reads as the same site rather than a second design. It
   differs in the two ways it has to: it is not full-height, and it carries no
   figure, because only some interior pages have a second image to spare and a
   hero that appears on four pages of seven is the inconsistency this replaced.

   Every child of .container here must be inside .hero-copy. The grid places
   direct children, so a bare <p class="eyebrow"> and <h1> land in separate
   columns - which is exactly what these pages shipped as, the eyebrow stranded
   in the wide column and the headline squeezed into the narrow one. */
.page-hero {
  position: relative;
  background: var(--color-surface);
  border-bottom: 1px solid var(--color-border);
  overflow: hidden;
}

.page-hero::before {
  content: "";
  position: absolute;
  top: -22rem;
  left: -14rem;
  width: 44rem;
  height: 44rem;
  background: var(--gradient-sun);
  border-radius: 50%;
  pointer-events: none;
}

.page-hero .container {
  position: relative;
  display: grid;
  gap: clamp(2.5rem, 2rem + 3vw, 4rem);
  align-items: center;
  padding-block: clamp(3.5rem, 2.5rem + 4vw, 6rem);
}

/* Same split as the home hero, so a headline wraps on the same measure. The
   second column stays empty by design - it is the white space the home hero
   fills with its arch.

   min-height is what stops the band from being a different height on every
   page. It is set just above what a two-line headline needs, which is what
   six of the seven interior pages render, so those six come out identical and
   only a long bioTitle on About grows past it. */
@media (min-width: 64em) {
  .page-hero .container {
    grid-template-columns: 7fr 5fr;
    min-height: 29rem;
  }
}

.page-hero h1 { margin-bottom: var(--space-4); }

/* :not(.eyebrow) because the eyebrow is a <p> too, and a bare `> p` here beats
   .eyebrow on specificity - it would take the pill's own bottom margin away and
   sit it straight on the headline, which the home hero does not do. */
.page-hero .hero-copy > p:not(.eyebrow) {
  font-size: var(--text-body-lg);
  color: var(--color-muted);
  max-width: 34rem;
}

/* The headline is the last child on every one of these pages today, and its
   margin would push the copy off centre inside the band. */
.page-hero .hero-copy > :last-child { margin-bottom: 0; }

/* --------------------------------------------------------------------------
   10. Statement section — big serif with inline images
   -------------------------------------------------------------------------- */
.statement {
  max-width: 56rem;
  margin-inline: auto;
  text-align: center;
  font-family: var(--font-display);
  font-size: clamp(1.75rem, 1.2rem + 2.4vw, 3rem);
  line-height: 1.35;
  color: var(--color-primary);
}

.statement .inline-img {
  display: inline-block;
  width: clamp(3.5rem, 3rem + 2vw, 5.5rem);
  height: clamp(2.25rem, 2rem + 1.2vw, 3.25rem);
  border-radius: var(--radius-pill);
  object-fit: cover;
  vertical-align: middle;
  margin-inline: 0.35rem;
  transform: translateY(-4px);
  box-shadow: var(--shadow-sm);
}

.statement em { color: var(--color-secondary); }

.statement-attribution {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-4);
  margin-top: var(--space-8);
}

.statement-attribution img {
  width: 3.25rem;
  height: 3.25rem;
  border-radius: 50%;
  object-fit: cover;
}

.statement-attribution strong {
  display: block;
  font-family: var(--font-body);
  font-size: var(--text-caption);
  font-weight: 700;
  color: var(--color-primary);
  text-align: left;
}

.statement-attribution span {
  font-size: var(--text-label);
  color: var(--color-muted);
}

/* --------------------------------------------------------------------------
   11. Property cards
   -------------------------------------------------------------------------- */
.section-foot {
  margin-top: clamp(2.5rem, 2rem + 3vw, 4rem);
  text-align: center;
}

/* --------------------------------------------------------------------------
   12. Neighborhoods — horizontal snap row of arches
   -------------------------------------------------------------------------- */
.hood-scroller {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(15rem, 1fr);
  gap: var(--space-6);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  padding-bottom: var(--space-6);
  -webkit-overflow-scrolling: touch;
  scrollbar-color: var(--color-secondary) var(--color-accent);
  scrollbar-width: thin;
}

.hood-card {
  scroll-snap-align: start;
  text-align: center;
}

.hood-card figure {
  position: relative;
  overflow: hidden;
  border-radius: var(--radius-arch);
  aspect-ratio: 3 / 4;
  margin-bottom: var(--space-4);
}

.hood-card img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 1.3s var(--ease-out);
}

.hood-card:hover img { transform: scale(1.07); }

.hood-card figcaption {
  position: absolute;
  inset-inline: var(--space-3);
  bottom: var(--space-3);
  background: rgba(255, 255, 255, 0.92);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  border-radius: var(--radius-pill);
  padding: 0.6rem 1rem;
  font-family: var(--font-display);
  font-size: 1.1rem;
  color: var(--color-primary);
}

.hood-card p {
  font-size: var(--text-label);
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--color-muted);
}

/* --------------------------------------------------------------------------
   13. Services
   -------------------------------------------------------------------------- */
.service-grid {
  display: grid;
  gap: var(--space-6);
  grid-template-columns: 1fr;
}

@media (min-width: 48em) { .service-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 64em) { .service-grid { grid-template-columns: repeat(3, 1fr); } }

/* A four-card grid stays 2x2 at every width above the phone, rather than going
   three across and stranding the fourth on a row of its own. Buyers and
   sellers carry four; home carries two and about three, which is why this is a
   modifier and not a change to .service-grid itself. */
@media (min-width: 64em) { .service-grid--4 { grid-template-columns: repeat(2, 1fr); } }

/* And --2 for the same reason in the other direction. Home's "Two ways in"
   carries two cards into the base three-column grid, which left a third of the
   band empty beside them and read as a card that had failed to render. */
@media (min-width: 64em) { .service-grid--2 { grid-template-columns: repeat(2, 1fr); } }

/* Static white, no hover state. Hover used to repaint the card --color-accent,
   which is the exact colour of the .section--accent band every service grid in
   this template sits on, so the card dissolved into its own background as the
   pointer crossed it. The card is not a link - the .link-arrow inside it is,
   and that keeps its own hover - so there is nothing the card-level state has
   to signal. Nothing animates any more, so the transition goes with it. */
.service-card {
  position: relative;
  background: var(--color-background);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  padding: var(--space-8);
}

.service-icon {
  display: grid;
  place-items: center;
  width: 3.5rem;
  height: 3.5rem;
  border-radius: 50% 50% 8px 8px;
  background: var(--color-primary);
  color: var(--color-secondary);
  margin-bottom: var(--space-6);
}

.service-icon svg { width: 1.4rem; height: 1.4rem; }

.service-card h3 { font-size: 1.45rem; margin-bottom: var(--space-3); }

.service-card p {
  color: var(--color-muted);
  font-size: var(--text-caption);
  line-height: 1.8;
}

.service-card .link-arrow { margin-top: var(--space-6); }

/* Alternating service features (services page) */
.feature {
  display: grid;
  gap: clamp(2.5rem, 2rem + 3.5vw, 5rem);
  align-items: center;
}

@media (min-width: 64em) {
  .feature { grid-template-columns: repeat(12, 1fr); }

  /* The gap above is the space between the image and the text when this grid
     is one column on a phone. Spent 11 times across 12 columns it is not a
     gutter, it is the layout: at 5rem it left each column 24px wide, so the
     two blocks came out 90px narrower than the .contact-layout columns they
     sit alongside, with 184px of dead ground between them. The row gap is
     what the stacked layout needs; the column gap is a gutter. */
  .feature { column-gap: var(--space-6); }

  /* grid-row is the load-bearing half of each of these. Auto-placement walks
     the items in order-modified document order and moves DOWN a row whenever
     an item's column-start is left of where the cursor already is - so a
     partial whose text comes before its image silently drops the image into a
     second row, left column, with a column of white space above it. That is
     how Buyers shipped. Pinning the row makes the placement independent of
     the order the partial happens to write the two blocks in. */
  .feature-media { grid-column: 1 / 6; grid-row: 1; }
  .feature-body { grid-column: 7 / 13; grid-row: 1; }
  .feature--reverse .feature-media { grid-column: 8 / 13; grid-row: 1; }
  .feature--reverse .feature-body { grid-column: 1 / 7; grid-row: 1; }
}

.feature + .feature { margin-top: var(--section-padding); }

/* Stacked, this figure gets the whole container, and at 707px wide the 4/4.4
   ratio made it 777px tall - taller than a tablet viewport, for what is a
   supporting image beside a paragraph. Capping it at the width it has in the
   two-column layout keeps it the same picture at every size, and centring it
   stops the cap reading as a left-aligned image in a wide band. */
.feature-media {
  width: min(100%, 28rem);
  margin-inline: auto;
}

@media (min-width: 64em) {
  .feature-media { width: 100%; margin-inline: 0; }
}

.feature-media img {
  width: 100%;
  aspect-ratio: 4 / 4.4;
  object-fit: cover;
  border-radius: var(--radius-arch);
  box-shadow: var(--shadow-md);
}

.feature-media--round img { border-radius: var(--radius-lg); aspect-ratio: 4 / 3; }

.feature-num {
  font-family: var(--font-display);
  font-size: 1.05rem;
  color: var(--color-secondary);
  letter-spacing: 0.14em;
  display: block;
  margin-bottom: var(--space-3);
}

.feature-body h2, .feature-body h3 { margin-bottom: var(--space-4); }

.feature-body > p {
  color: var(--color-muted);
  margin-bottom: var(--space-4);
}

.feature-body .btn, .feature-body .link-arrow { margin-top: var(--space-4); }

/* --------------------------------------------------------------------------
   14. Checklist & value pills
   -------------------------------------------------------------------------- */
.checklist {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  margin-block: var(--space-6);
}

.checklist li {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  font-size: var(--text-caption);
}

.checklist svg {
  width: 1.2rem;
  height: 1.2rem;
  color: var(--color-secondary);
  flex-shrink: 0;
  margin-top: 2px;
}

.value-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-6);
  margin-top: var(--space-8);
}

.value-item {
  display: flex;
  gap: var(--space-4);
  align-items: flex-start;
}

.value-item .service-icon {
  margin-bottom: 0;
  flex-shrink: 0;
  width: 3rem;
  height: 3rem;
}

.value-item .service-icon svg { width: 1.2rem; height: 1.2rem; }

.value-item h4 {
  font-family: var(--font-body);
  font-weight: 700;
  font-size: 1rem;
  margin-bottom: var(--space-1);
  color: var(--color-text);
}

.value-item p {
  font-size: var(--text-caption);
  color: var(--color-muted);
}

/* --------------------------------------------------------------------------
   15. Timeline (vertical process)
   -------------------------------------------------------------------------- */
.timeline {
  position: relative;
  max-width: 44rem;
  margin-inline: auto;
  padding-left: 3.5rem;
}

.timeline::before {
  content: "";
  position: absolute;
  left: 1.05rem;
  top: 0.5rem;
  bottom: 0.5rem;
  width: 1.5px;
  background: linear-gradient(to bottom, var(--color-secondary), var(--color-border));
}

.timeline-item {
  position: relative;
  padding-bottom: var(--space-12);
}

.timeline-item:last-child { padding-bottom: 0; }

.timeline-item::before {
  content: "";
  position: absolute;
  left: -3.5rem;
  top: 0.4rem;
  width: 2.2rem;
  height: 2.2rem;
  border-radius: 50% 50% 6px 6px;
  background: var(--color-accent);
  border: 1.5px solid var(--color-secondary);
}

.timeline-item::after {
  content: attr(data-step);
  position: absolute;
  left: -3.5rem;
  top: 0.4rem;
  width: 2.2rem;
  height: 2.2rem;
  display: grid;
  place-items: center;
  font-family: var(--font-display);
  font-size: 0.95rem;
  color: var(--color-primary);
}

.timeline-item h3 { font-size: 1.4rem; margin-bottom: var(--space-2); }

.timeline-item p {
  color: var(--color-muted);
  font-size: var(--text-caption);
  max-width: 36rem;
}

.section--dark .timeline-item p { color: var(--color-on-dark-muted); }
.section--dark .timeline-item::before { background: var(--color-primary-soft); }
.section--dark .timeline-item::after { color: var(--color-accent); }
.section--dark .timeline::before { background: linear-gradient(to bottom, var(--color-secondary), var(--color-on-dark-border)); }

/* --------------------------------------------------------------------------
   16. Stats band
   -------------------------------------------------------------------------- */
.faq-list {
  max-width: 46rem;
  margin-inline: auto;
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

.faq-item {
  background: var(--color-background);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  overflow: hidden;
  transition: border-color var(--duration-fast) var(--ease-out);
}

.faq-item.is-open { border-color: var(--color-secondary); }

.faq-question {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-6);
  padding: var(--space-6);
  text-align: left;
  font-family: var(--font-display);
  font-size: 1.15rem;
  color: var(--color-primary);
}

.faq-question svg {
  width: 1.15rem;
  height: 1.15rem;
  color: var(--color-secondary);
  flex-shrink: 0;
  transition: transform var(--duration-med) var(--ease-out);
}

.faq-item.is-open .faq-question svg { transform: rotate(45deg); }

.faq-answer {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows var(--duration-med) var(--ease-out);
}

.faq-item.is-open .faq-answer { grid-template-rows: 1fr; }

.faq-answer-inner { overflow: hidden; }

.faq-answer p {
  padding: 0 var(--space-6) var(--space-6);
  color: var(--color-muted);
  font-size: var(--text-caption);
  line-height: 1.85;
}

/* --------------------------------------------------------------------------
   20. CTA band — warm arch
   -------------------------------------------------------------------------- */
.cta-band {
  position: relative;
  background: var(--color-primary);
  color: var(--color-on-dark);
  overflow: hidden;
}

.cta-band::before {
  content: "";
  position: absolute;
  bottom: -24rem;
  left: 50%;
  transform: translateX(-50%);
  width: 52rem;
  height: 52rem;
  background: radial-gradient(circle at 50% 50%, rgba(201, 168, 106, 0.32) 0%, rgba(42, 61, 69, 0) 62%);
  border-radius: 50%;
  pointer-events: none;
}

.cta-band .container {
  position: relative;
  display: grid;
  gap: clamp(2.5rem, 2rem + 3vw, 4.5rem);
  align-items: center;
}

@media (min-width: 64em) {
  .cta-band .container { grid-template-columns: 7fr 4fr; }
}

.cta-band h2 {
  color: var(--color-on-dark);
  margin-bottom: var(--space-4);
}

/* :not(.eyebrow) again - see .section-head. Every page closes on this band and
   every one of them opens it with a <p class="eyebrow eyebrow--on-dark">, so
   this rule was overriding the chip's size, its colour and its bottom margin
   on all eight pages. .eyebrow--on-dark is a single class too and lost the
   same way, which is why the pill's translucent fill never showed. */
.cta-band p:not(.eyebrow) {
  color: var(--color-on-dark-muted);
  font-size: var(--text-body-lg);
  max-width: 32rem;
  margin-bottom: var(--space-8);
}

.cta-figure {
  justify-self: center;
  width: min(100%, 20rem);
}

.cta-figure img {
  width: 100%;
  aspect-ratio: 4 / 4.6;
  object-fit: cover;
  border-radius: var(--radius-arch);
  border: 1.5px solid rgba(201, 168, 106, 0.4);
}

/* --------------------------------------------------------------------------
   21. Forms
   -------------------------------------------------------------------------- */
.contact-layout {
  display: grid;
  gap: clamp(2.5rem, 2rem + 4vw, 5rem);
}

/* The form takes the wide column and the details the narrow one. It was the
   other way round: the injected form - five fields, two of them side by side,
   a message box and a consent paragraph - was folded into 453px while four
   lines of address and phone number had 635px and left most of it empty. */
@media (min-width: 64em) {
  .contact-layout {
    grid-template-columns: 7fr 5fr;
    align-items: start;
  }
}

.contact-info {
  display: flex;
  flex-direction: column;
  gap: var(--space-8);
}

.contact-item {
  display: flex;
  gap: var(--space-4);
  align-items: flex-start;
}

/* The label and the value are one column beside the icon, not two more items
   in its row. Without this wrapper the three children of .contact-item lay out
   as icon | OFFICE | 222 Demo State St on a single line, which put every value
   at a different left edge and wrapped the long ones under their own label. */
.contact-item__text { min-width: 0; }

.contact-item .service-icon {
  margin-bottom: 0;
  flex-shrink: 0;
  width: 3rem;
  height: 3rem;
}

.contact-item .service-icon svg { width: 1.2rem; height: 1.2rem; }

.contact-item h3 {
  font-family: var(--font-body);
  font-size: var(--text-label);
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--color-muted);
  margin-bottom: var(--space-1);
}

.contact-item p,
.contact-item a {
  font-size: var(--text-body-lg);
  color: var(--color-primary);
  line-height: 1.5;
}

.contact-item a:hover { color: var(--color-secondary-hover); }

.contact-form-panel {
  background: var(--color-background);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  padding: clamp(1.75rem, 1.4rem + 2vw, 3rem);
  box-shadow: var(--shadow-md);
}

.contact-form-panel h2 { margin-bottom: var(--space-2); }

.contact-form-panel > p {
  color: var(--color-muted);
  font-size: var(--text-caption);
  margin-bottom: var(--space-8);
}

.contact-map { margin-top: var(--section-padding); }

.contact-map img {
  width: 100%;
  aspect-ratio: 21 / 9;
  object-fit: cover;
  border-radius: var(--radius-lg);
}

/* --------------------------------------------------------------------------
   23. Footer
   -------------------------------------------------------------------------- */
.reveal {
  opacity: 0;
  transform: translateY(30px);
  transition: opacity var(--duration-slow) var(--ease-out),
              transform var(--duration-slow) var(--ease-out);
  transition-delay: var(--reveal-delay, 0ms);
}

.reveal.is-visible {
  opacity: 1;
  transform: translateY(0);
}

/* Hero load-in */
.hero-copy > * {
  animation: hero-rise 1s var(--ease-out) both;
}

.hero-copy > *:nth-child(1) { animation-delay: 0.05s; }
.hero-copy > *:nth-child(2) { animation-delay: 0.18s; }
.hero-copy > *:nth-child(3) { animation-delay: 0.32s; }
.hero-copy > *:nth-child(4) { animation-delay: 0.46s; }
.hero-copy > *:nth-child(5) { animation-delay: 0.6s; }

.hero-figure {
  animation: hero-rise 1.1s var(--ease-out) 0.25s both;
}

@keyframes hero-rise {
  from { opacity: 0; transform: translateY(34px); }
  to { opacity: 1; transform: translateY(0); }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }

  .reveal { opacity: 1; transform: none; }
  .marquee-track { animation: none; }
  .spin-badge .spin-text { animation: none; }
}


/* =====================================================================
   ADDED IN CONVERSION — markup the source template did not have
   ===================================================================== */

.ylopo-easy-widget { min-height: 420px; position: relative; }
.ylopo-easy-widget.ylopo-loading::before {
  content: ""; position: absolute; inset: 0;
  border-radius: var(--radius, 8px);
  background: linear-gradient(90deg, var(--color-surface, #f1ece4) 25%, #fff 37%, var(--color-surface, #f1ece4) 63%);
  background-size: 400% 100%;
  animation: california-shimmer 1.4s ease infinite;
}
.ylopo-easy-widget.ylopo-ready::before { display: none; }
@keyframes california-shimmer { 0% { background-position: 100% 0; } 100% { background-position: 0 0; } }

/* ---- Market trends host (Gold, one page per community) ----------------
   Same job as the rail above, and it was not doing it: this host reserved no
   height at all, so on a Market Trends page the listings band and the two
   below it sat 724px too high and dropped the moment the chart landed. It gets
   the listings widget's own floor and shimmer, so the two read as one system.

   The hook is :not(:has(*)) rather than the .ylopo-loading class the rail uses
   - ylopo-bundle.js only sets that class on the listings widget. :empty would
   not work either: the Nunjucks source leaves a newline inside this div, and a
   text node is enough to fail :empty.

   The floor is deliberately BELOW the widget's real height (measured 724px at
   1440). min-height only reserves, so a low floor absorbs most of the shift and
   can never leave a hole under a widget that came in shorter. */
.ylopo-market-trends { position: relative; }
.ylopo-market-trends:not(:has(*)) { min-height: 420px; }
.ylopo-market-trends:not(:has(*))::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: var(--radius-md);
  background: linear-gradient(90deg, var(--color-surface) 25%, #fff 37%, var(--color-surface) 63%);
  background-size: 400% 100%;
  animation: california-shimmer 1.4s ease infinite;
}

/* ---- Chart clearance under the metric tabs ---------------------------
   The four metric tabs carry 0.6rem below them and the chart no margin at all,
   and the chart's top axis label is drawn ABOVE its own box: the skin gives
   that svg overflow:visible so the vendor's fixed 600x200 viewBox is not
   clipped. Measured, the top label lands 5px under the tab row at 1440 - close
   enough to read as a collision. 1.75rem puts it in proportion with the 2.75rem
   the skin sets between the stat tiles and the tabs.

   WHY THE SELECTOR IS SHAPED LIKE THIS. The rule it corrects lives in the
   OTHER project - ylopo-grid's templates/california.css - which
   ylopo-bundle.js appends AFTER this stylesheet, so an equal-specificity rule
   here loses on cascade order. That skin selects with six classes; this
   restates the same six and adds one element, which outranks it without
   !important. It is a copy of a selector this repo does not own: if the tab or
   chart spacing is ever set deliberately in the skin, delete this block rather
   than tuning it, and make the change there where it belongs. */
.ylopo-market-trends .YLOPO-widget .market-trends .market-trends-content .market-trends-area div.market-trends-desktop {
  margin-top: 1.75rem;
}

/* Credential list on About. The source had no bulleted list of its own. */
.check-list { list-style: none; padding: 0; margin: 1.5rem 0 0; display: grid; gap: 0.85rem; }
.check-list li { display: flex; align-items: flex-start; gap: 0.7rem; line-height: 1.5; }
.check-list svg { flex: none; width: 1.1rem; height: 1.1rem; margin-top: 0.2rem; color: var(--color-secondary, #c9a86a); }

/* QA build notices, visible while the reviews, sold-properties and contact
   widgets are being built. Remove once all three ship. */
.qa-note {
  display: flex; align-items: flex-start; gap: 1rem; flex-wrap: wrap;
  max-width: 60ch; margin-inline: auto;
  padding: 1.4rem 1.6rem;
  border: 1px dashed var(--color-secondary, #c9a86a);
  border-radius: var(--radius, 8px);
  background: color-mix(in srgb, var(--color-secondary, #c9a86a) 8%, transparent);
  text-align: left;
}
.qa-note__tag {
  flex: none;
  font-size: 0.62rem; font-weight: 700; letter-spacing: 0.16em; text-transform: uppercase;
  color: #fff; background: var(--color-secondary, #c9a86a);
  border-radius: 999px; padding: 0.35rem 0.8rem;
}
.qa-note p { font-size: 0.94rem; flex: 1 1 22ch; margin: 0; }

@media (max-width: 640px) { .qa-note { flex-direction: column; gap: 0.8rem; } }

/* Mobile CTA width ----------------------------------------------------
   At phone widths a standalone CTA goes full width with its label centred.
   Sized to its own text it leaves a ragged edge against the copy above it,
   and of two stacked buttons the shorter reads as the lesser one purely
   because it is narrower.

   .hero-actions already stacks below 30em; this raises that to the same
   breakpoint as the buttons so the two cannot disagree.

   Card actions and widget-injected markup are excluded. Written as a
   max-width override rather than a mobile-first base rule so the desktop
   layout cannot be affected by construction. */
@media (max-width: 640px) {
  .btn { width: 100%; justify-content: center; text-align: center; }
  .community .btn,
  .ylopo-easy-widget .btn { width: auto; }

  .hero-actions { flex-direction: column; align-items: stretch; }

  /* .link-arrow is a text CTA rather than a button, so it is centred without
     being stretched. fit-content keeps its underline and arrow tight to the
     label instead of dragging them across the column. */
  .link-arrow { display: flex; width: fit-content; margin-inline: auto; }
}

/* Sold page with nothing to show.
   The visitor-facing counterpart to .qa-note: an agent whose Ylopo agent ids
   are not on file yet gets this instead of an empty band. Which of the two
   renders is decided in Nunjucks - the widget has to be absent from the page,
   not hidden here. */
.sold-empty {
  max-width: 46ch; margin-inline: auto;
  padding: var(--space-8, 2rem) var(--space-4, 1rem);
  text-align: center;
  border-top: 1px solid var(--color-border, #E8E2D6);
  border-bottom: 1px solid var(--color-border, #E8E2D6);
}
.sold-empty .sold-empty__title {
  font-family: var(--font-display, Georgia, serif);
  font-size: var(--text-h4, 1.375rem); font-weight: 400;
  margin: 0 0 var(--space-3, 0.75rem);
  color: var(--color-text, #2C2C2C);
}
.sold-empty p { margin: 0; font-size: var(--text-body, 1rem); color: var(--color-muted, #707070); }
.sold-empty a { color: var(--color-secondary, #C9A86A); text-decoration: underline; text-underline-offset: 0.2em; }
.sold-empty a:hover { color: var(--color-secondary-hover, #B8945A); }

/* Sale date on sold cards - OFF unless SHOW_SOLD_DATE is on in
   scripts/feature-flags.mjs, which is what emits data-sold-date on the widget.

   The Ylopo widget puts the date in .gallery-card-b-generate-sort-block, which
   this template's card CSS in the ylopo-grid project hides outright. Overriding
   that !important needs both the flag attribute and this specificity, so the
   rule lives here rather than there - and so the per-template design of the bar,
   when it happens, sits with the rest of this template's tokens.

   :has(.sold-date) is load-bearing, not decoration. For-sale cards reuse the
   same container for "Listed 4 Months Ago", so revealing it unscoped would put
   that strip on every listing card on every home and search page. Only a sold
   card has .sold-date inside.

   Two selectors, not one: the card redesign takes .property-details-wrap out of
   layout with display:none, and on these templates that wrapper holds the sort
   block and nothing else - so the block alone computes to a 0x0 box inside a
   hidden parent. Revealing the wrapper duplicates no content precisely because
   it is otherwise empty; check that still holds before copying this to a new
   template.

   Still wearing the widget's own grey bar styling: designing it per template is
   the work that has to happen before the flag is turned on. */
.ylopo-easy-widget[data-sold-date="true"] .property-details-wrap:has(.sold-date),
.ylopo-easy-widget[data-sold-date="true"] .gallery-card-b-generate-sort-block:has(.sold-date) {
  display: flex !important;
}

/* Backdrop for the nav drawer. Created by the template's script, not by the
   layout, so no markup changes. It exists as much to swallow the click as to
   dim the page: tapping beside an open drawer should dismiss it and nothing
   else, and a dim painted with a shadow on the panel would let that tap fall
   through to a link underneath. Sits one below the drawer. */
.nav-backdrop {
  position: fixed;
  inset: 0;
  /* This template's own ink at 0.55 rather than neutral black, with a little
     blur: the page behind the drawer should read as set down, not switched
     off. The blur is on the backdrop and not on the panel - backdrop-filter on
     the panel would make it the containing block for anything fixed inside
     it, which is the trap the header note above already describes. */
  background: rgba(42, 61, 69, 0.55);
  -webkit-backdrop-filter: blur(3px);
  backdrop-filter: blur(3px);
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--duration-med) var(--ease-out), visibility 0s linear var(--duration-med);
  z-index: 98;
}
.nav-backdrop.is-open {
  opacity: 1;
  visibility: visible;
  transition-delay: 0s;
}
