/* ── Playfair Display, self-hosted ─────────────────────────────
   The display serif for this theme's headlines. SELF-HOSTED (Eric,
   2026-08-09): the two variable woff2 files live in assets/fonts, so
   the hero face never depends on Google being reachable and never
   changes under us when they revision the family. Latin subset,
   wght 400-900 in one file each. font-display:swap keeps the
   headline readable in the fallback serif while it arrives. */
@font-face{
  font-family:'Playfair Display';
  font-style:normal;
  font-weight:400 900;
  font-display:swap;
  src:url('fonts/playfair-display-latin.woff2') format('woff2');
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}
@font-face{
  font-family:'Playfair Display';
  font-style:italic;
  font-weight:400 900;
  font-display:swap;
  src:url('fonts/playfair-display-latin-italic.woff2') format('woff2');
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}

/* ── Instrument Serif, self-hosted ─────────────────────────────
   The HERO face as of the "Button and hero typography updates"
   design (2026-08-10): a taller, Times-like display serif. Single
   weight, roman + italic (the italic is the pop word). Playfair
   keeps every other display head. */
@font-face{
  font-family:'Instrument Serif';
  font-style:normal;
  font-weight:400;
  font-display:swap;
  src:url('fonts/instrument-serif-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:'Instrument Serif';
  font-style:italic;
  font-weight:400;
  font-display:swap;
  src:url('fonts/instrument-serif-latin-italic.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;
}

/* ── The other four families, self-hosted (Eric, 2026-08-09) ───
   Same treatment as Playfair above: latin-subset woff2 files pulled
   from Google's own serving CSS, so the Google Fonts stylesheet link
   in layout.php could go entirely. Besley and Inter are variable
   files (Besley roman + italic 400-700; one Inter file carries
   400-700, Google serves the identical file for every weight).
   Archivo Black and Ephesis are single-weight. */
@font-face{
  font-family:'Archivo Black';
  font-style:normal;
  font-weight:400;
  font-display:swap;
  src:url('fonts/archivo-black-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:'Besley';
  font-style:normal;
  font-weight:400 700;
  font-display:swap;
  src:url('fonts/besley-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:'Besley';
  font-style:italic;
  font-weight:400 700;
  font-display:swap;
  src:url('fonts/besley-latin-italic.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:'Ephesis';
  font-style:normal;
  font-weight:400;
  font-display:swap;
  src:url('fonts/ephesis-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:'Inter';
  font-style:normal;
  font-weight:400 700;
  font-display:swap;
  src:url('fonts/inter-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;
}

/* ============================================================
   grace-mid — the setting between grace and grace-alt
   ------------------------------------------------------------
   Her note on grace-alt: "it feels a bit too in your face. I like
   the femininity of the grace theme."

   So the split is voice vs structure. Her voice stays soft: Besley
   sets every headline in sentence case, Ephesis still signs them.
   The structure borrows grace-alt's discipline: a bigger type
   scale, hairline rules instead of floating boxes, and Archivo
   Black allowed ONLY where language isn't — eyebrows, stat
   numbers, buttons, labels. Bold bones, soft skin.

   Layered on top of grace's style.css, so this file only states
   what differs. Anything not mentioned here is inherited.
   ============================================================ */

:root{
  /* Same tokens she already has. What changes is the WEIGHTING:
     blush and cream carry the page, green stops being wallpaper and
     goes back to meaning something. No new hues invented. */
  --field:var(--blush);            /* the default section ground */
  --field-2:var(--paper);          /* the alternate, was the default */
  --rule:#D8CFC0;                  /* hairline, a touch warmer than --line */
  --rule-strong:#C3B7A4;
  --r-lg:6px; --r-md:6px; --r-sm:6px;   /* was 20/14: softened corners, not square */
  --shadow-1:none;                 /* structure comes from rules now */
  --shadow-2:none;
  --bold:'Archivo Black',system-ui,sans-serif;

  /* A readable clay. The token clay (#8C6A3F) measures 3.9:1 on blush, which
     fails WCAG AA for the 11px uppercase labels it was being used for. This is
     the same hue pulled down until it passes at small sizes. */
  --clay-ink:#6E5230;
  --gold-soft:#E9C88A;             /* the script line over footage */
  /* --slate is the base's colour for every piece of small print: footer
     headings, legal line, "brokered by", card kickers. Measured at 4.04:1 on
     these grounds, so all of it failed AA at 11-12px. Darkened once here rather
     than patching a dozen selectors. */
  --slate:#5A4E44;

  /* One spacing scale, so every band breathes the same amount instead of each
     section inventing its own padding. */
  --sp-sec:clamp(56px,7vw,104px);
  --sp-head:clamp(26px,3vw,40px);
  --sp-tight:clamp(14px,1.6vw,20px);
}

body{background:var(--field)}

/* ── type ──────────────────────────────────────────────────────
   Two serifs with distinct jobs, never uppercased (capitals are
   what made grace-alt shout):

   Playfair Display carries the DISPLAY level — hero, page heads,
   section heads. High-contrast hairline serifs read as couture at
   scale, which is the femininity she asked for wearing the
   confidence she liked. Tracked at -0.025em (Eric's "-25"): tight
   enough that a headline sets as one object, not so tight the
   hairlines weld together.

   Besley keeps everything below h3 — card titles, FAQ questions —
   where Playfair's contrast would go spindly at small sizes. */
h1,h2,.phead h1,.shead h2{
  font-family:'Playfair Display','Besley',Georgia,serif;
  font-weight:560;
  letter-spacing:-.025em;
  text-transform:none;
  text-wrap:balance;
}
h3{font-family:'Besley',Georgia,serif;font-weight:600;letter-spacing:-.012em;text-transform:none}
/* Playfair's ascenders run taller than Besley's, so every display
   line-height eases up a step or descenders shear off. */
.phead h1{font-size:clamp(34px,5vw,54px);line-height:1.08}
/* face/colour only — the hero's SIZES live in the end-of-file layer with the
   rest of the 2026-08-10 design pass */
.hero h1{font-family:'Instrument Serif',Georgia,serif;letter-spacing:-.01em;font-weight:400;color:#FBF8F0}
.shead h2{font-size:clamp(27px,3.5vw,40px);line-height:1.12}
/* The script line runs INLINE with the headline rather than dropping to its own
   line: one sentence in two voices, the way a signature sits at the end of a
   note instead of underneath it. The space has to be drawn in, because the
   markup puts <em> flush against the preceding text with no whitespace. */
h1 em,h2 em,.hero h1 em{
  font-family:'Ephesis',cursive;font-style:normal;font-weight:400;
  font-size:1.16em;line-height:.92;letter-spacing:.005em;color:var(--accent);
  display:inline;margin-left:.3em;
}
/* the hero script drops to its OWN line (the design's two-voice stack): smaller
   than the headline now (.72em vs 1.16), no lead-in indent after the <br>.
   Capped at 40px so the sentence holds ONE line in the desktop column. */
.hero h1 em{color:#E3C288;font-size:clamp(28px,.72em,40px);line-height:1.3;margin-left:0}

/* Archivo Black is allowed here and nowhere else: things that are
   labels or numbers, never things that are her speaking. */
.eyebrow,.stat-v,.ms-v,.tile b,.pill,.badge,.gh-k,.crumbs{
  font-family:var(--bold);
  font-weight:400;
  text-transform:uppercase;
}
.eyebrow{
  font-size:11.5px;letter-spacing:.15em;color:var(--clay-ink);
  display:flex;align-items:center;gap:11px;margin-bottom:var(--sp-tight);
}
/* The rule that starts every eyebrow: grace-alt's tell, kept. currentColor,
   not a fixed token: the hero's eyebrow is light green on footage while the
   page eyebrows are clay, and a clay dash on dark footage was invisible. */
.eyebrow::before{content:"";width:26px;height:1px;background:currentColor;flex:none}
.center .eyebrow,.shead.center .eyebrow{justify-content:center}
/* the HERO eyebrow steps out of Archivo Black: quiet sage caps over the footage
   (design 2026-08-10); page eyebrows keep the bold clay treatment above */
.hero .eyebrow{font-family:'Inter',sans-serif;font-weight:500;font-size:11px;letter-spacing:.2em;color:#B9C1A4}
.hero .eyebrow::before{background:#9AA583}
.stat-v,.ms-v{letter-spacing:-.04em;font-size:clamp(30px,3.6vw,42px)}
.stat-l,.ms-l{font-family:'Inter',sans-serif;font-weight:600;font-size:10.5px;
  letter-spacing:.12em;text-transform:uppercase;color:var(--clay-ink)}
/* Buttons wear the hero slab's type now (Eric, 2026-08-10): Inter 600 at 13
   with the same open .16em tracking, still square, still a label. Pairs keep
   the connected 1x2 geometry below. */
.btn{font-family:'Inter',sans-serif;font-weight:600;font-size:13px;
  letter-spacing:.16em;text-transform:uppercase;border-radius:0;box-shadow:none}
/* Every button PAIR is one object: square, connected, the shared edge collapsed.
   The hero pair set the pattern; Eric promoted it to the whole site. The inline
   pairs (buyers/sellers closing bands) become flex so the whitespace between
   inline-blocks cannot reopen the seam. */
.cta-row{gap:0}
.cta-row .btn + .btn{border-left:0;margin-left:0}
.sec p:has(> .btn + .btn),.band p:has(> .btn + .btn){display:inline-flex;gap:0;max-width:100%;flex-wrap:wrap}
.sec p > .btn + .btn,.band p > .btn + .btn{border-left:0;margin-left:0}
/* body copy sits at --slate in the base, which is 4.4:1 on blush. Nudged to the
   secondary ink so paragraphs clear AA with room to spare. */
/* Scoped to the light content bands ONLY. A blanket `p` rule (even with a
   :not() guard) reached into <footer> and the closing .band, both of which are
   dark, and dropped them to 1.27:1. Name the containers instead. */
.sec p,.prose p,.phead .psub,.sec .muted,.mqa p,.qa p{color:var(--ink-2)}
.muted{opacity:1}

/* ── surfaces: lines, not boxes ────────────────────────────────
   grace floats cards on shadows; grace-alt boxes them in hard
   squares. Here a hairline does the work and the corner barely
   rounds, so nothing looks clipped and nothing looks pillowy. */
.card,.lcard,.mstat,.mqa,.ghint,.pol,.panel,.tile,.qa,.acard{
  border:1px solid var(--rule);
  border-radius:var(--r-md);
  box-shadow:none;
  background:var(--field-2);
}
.sec{background:var(--field)}
.sec.alt{background:var(--field-2)}
/* a section change is announced by a line, the way an editorial page does it */
.sec+.sec{border-top:1px solid var(--rule)}
.shead{border-bottom:1px solid var(--rule);padding-bottom:18px;margin-bottom:30px}

/* photographs keep their own softness; the geometry never crops her */
.pol .pol-img img,.pol .pol-img video,.ed-photo img,.gh-img img{border-radius:var(--r-md)}
.me-circle,.agent-photo img{border-radius:50%}

/* ── neighborhood guide cards join the hairline system ─────────
   The base draws them as soft rounded photo cards (Besley, 14px
   corners). Here the name takes the hero serif, the corner barely
   rounds, and the hover is a firmer line, not a color change. */
.nbcard{border-color:var(--rule);border-radius:var(--r-md);background:var(--field-2)}
.nbcard:hover{border-color:var(--rule-strong)}
.nb-img{border-radius:4px}
.nb-t{font-family:'Instrument Serif',Georgia,serif;font-weight:400;letter-spacing:0;font-size:23px;line-height:1.08}
.nb-tile{font-family:'Instrument Serif',Georgia,serif;font-weight:400;background:var(--field);color:var(--ink-2)}
.nb-meta{font-family:'Inter',sans-serif;font-size:12.5px;color:var(--ink-2)}
.nb-d{color:var(--ink-2);font-size:13.5px}

/* ── the polaroid strip stays a slider ─────────────────────────
   Explicitly kept from grace-alt: it is the most personal thing on
   the home page and she likes it. Only the frame changes, from a
   thick white polaroid to a thin warm one. */
.pol{background:#FFFDFA;border:1px solid var(--rule);padding:11px 11px 0;box-shadow:none}
.pol figcaption{
  font-family:'Ephesis',cursive;font-size:20px;color:var(--ink-2);
  text-transform:none;letter-spacing:0;padding:9px 2px 13px;
}
.pol.is-front{border-color:var(--rule-strong)}

/* ── hero ──────────────────────────────────────────────────────
   The scrim lifts a little: grace-alt darkened the footage until
   the type had to shout to be seen. Lighter scrim, so Besley at a
   normal weight still reads. */
/* Contrast over moving footage cannot be left to luck: the clip runs from a pale
   bedroom to a dark window in the same 23 seconds. The scrim is heavy enough that
   white type clears AA against the BRIGHTEST frame, not the average one. */
.hero-scrim{
  background:
    linear-gradient(180deg,rgba(35,29,22,.62) 0%,rgba(35,29,22,.44) 45%,rgba(35,29,22,.82) 100%),
    linear-gradient(90deg,rgba(35,29,22,.42) 0%,rgba(35,29,22,0) 62%);
}
.hero-in{padding-block:clamp(64px,10vh,120px)}
.hero h1{margin-bottom:var(--sp-head)}
.hero .sub{font-size:clamp(16px,1.5vw,19px);max-width:36ch;line-height:1.62;color:rgba(255,255,255,.94)}
/* One gold slab and a spoken text link below it — the design's break from the
   50/50 connected pair (2026-08-10). The slab keeps square corners. */
.hero-ctas{margin-top:clamp(24px,3vw,34px);display:flex;flex-direction:column;align-items:flex-start;gap:18px}
.hero-ctas .btn{border-radius:0}
.hero-ctas .btn.primary{background:#D9B36C;border-color:#D9B36C;color:#2C2B23;font-weight:600;font-size:12.5px;letter-spacing:.15em;padding:15px 26px}
.hero-ctas .btn.primary:hover{background:#E8C684;border-color:#E8C684;color:#2C2B23;transform:none}
.hero-alt{margin:0;font-family:'Inter',sans-serif;font-size:15px;color:rgba(233,229,219,.85)}
.hero-alt a{color:#F2EFE8;text-decoration:none;border-bottom:1px solid rgba(242,239,232,.4);padding-bottom:2px;transition:color .2s,border-color .2s}
.hero-alt a:hover{color:#fff;border-bottom-color:#fff}
/* The stat band sits straight on the footage: no fill, no top rule. The
   separators are drawn, not borders, so they hold at 80% height and center
   themselves whatever the cell height. The scrim's deeper bottom stop carries
   the contrast the fill used to provide. */
.hero-stats{background:transparent;border-top:0}
.hero-stats .stat{position:relative}
.hero-stats .stat+.stat{border-left:0}
.hero-stats .stat+.stat::before{content:"";position:absolute;left:0;top:10%;height:80%;width:1px;
  background:rgba(255,255,255,.28)}
.hero-stats .stat{padding-block:clamp(18px,2.4vw,26px)}
/* the global label colour is a warm brown; on the dark band it has to go light */
.hero-stats .stat-l{color:rgba(255,255,255,.86);font-size:10.5px;letter-spacing:.14em;font-weight:500}
.hero-stats .stat-v{color:#FBF8F0}
/* stat values leave Archivo Black for the hero serif (design 2026-08-10); the
   uppercase transform stays so "4.8m" reads 4.8M, and word-stats switch it off */
.hero-stats .stat-v{font-family:'Instrument Serif',Georgia,serif;font-weight:400;letter-spacing:0;font-size:clamp(28px,3.2vw,40px)}
.hero-stats .stat-word{font-family:'Instrument Serif',Georgia,serif;font-style:normal;font-weight:400;letter-spacing:0;text-transform:none;font-size:clamp(24px,2.8vw,34px)}

/* ── breathing room ────────────────────────────────────────────
   One scale for every band. grace's sections each carried their own
   padding, which is why the page read as unevenly stacked. */
.sec{padding-block:var(--sp-sec)}
.sec .wrap>*+*{margin-top:var(--sp-tight)}
.shead+*{margin-top:var(--sp-head)}
.phead{padding-block:clamp(48px,6vw,84px)}
.phead .psub{margin-top:var(--sp-tight);max-width:56ch}
.band{padding-block:var(--sp-sec)}

/* ── the accent earns its keep ─────────────────────────────────
   Green stops being a background wash and becomes the thing that
   marks what matters: one word of a headline, a hovered rule, the
   primary button. */
.pop{color:var(--accent);font-style:normal}
/* primary buttons stay the accent green — only the hero's slab is gold
   (tried gold site-wide 2026-08-10, walked back same day) */
.btn.primary{background:var(--accent);border-color:var(--accent);color:#FCFBF8}
.btn.primary:hover{background:var(--accent-deep);border-color:var(--accent-deep)}
.btn.ghost{background:transparent;border:1px solid var(--rule-strong);color:var(--ink)}
.btn.ghost:hover{border-color:var(--accent);color:var(--accent-deep)}
a:hover .gh-t,.lcard:hover .l-title{color:var(--accent-deep)}

/* ── nav + footer ──────────────────────────────────────────────
   The wordmark loses its serif and picks up tracking, which is the
   one place grace-alt's restraint was right. */
.brand-word{
  font-family:'Inter',sans-serif;font-weight:600;
  letter-spacing:.09em;text-transform:uppercase;font-size:15px;
}
.nav{background:rgba(239,234,224,.92);border-bottom:1px solid var(--rule)}
.nav.overlay{background:transparent;border-bottom-color:transparent}
.links a{font-size:12.5px;letter-spacing:.055em;text-transform:uppercase;font-weight:600}
.foot{background:var(--field-2);border-top:1px solid var(--rule)}

/* ── mobile ────────────────────────────────────────────────────
   Rules get heavier proportionally on a phone or they vanish. */
@media (max-width:760px){
  .hero h1{font-size:clamp(38px,11.8vw,46px)}   /* 46 at the design's 390, easing down on small phones */
  /* subline: 1.62 leading read as gaps between lines at phone size. Tighter
     leading, slightly smaller type, and the full column width so the sentence
     wraps in fewer, closer lines. */
  .hero .sub{font-size:15px;line-height:1.4;max-width:none}
  /* the old two-line script hacks are gone: at .72em the script line holds
     one line at 390 (the design frame proves it) */
  /* Two CTAs in a strict two-up grid, grace-alt's treatment. flex-wrap was a
     lie here: with these labels each button wanted more than half the row, so
     they quietly stacked full-width, and those two tall rows were exactly the
     height that pushed the stats band's second row under the fold. */
  /* Every OTHER button pair rides one line as a spaced two-up grid. Found by
     audit at 390px: the home intro pair overflowed the viewport, and the
     buyers/sellers pairs stacked flush with zero gap between them. Labels wrap
     inside their button rather than breaking the pair. The hero pair is the
     one deliberate exception: it stays square and CONNECTED (below). */
  .cta-row:has(> .btn + .btn),
  .sec p:has(> .btn + .btn),
  .band p:has(> .btn + .btn){
    display:grid;grid-template-columns:1fr 1fr;gap:0;width:100%;max-width:100%;
  }
  /* .editorial .cta-row .btn included: the base's 480px editorial rule outranks
     the bare .cta-row .btn and kept 13.5px, which overflows at .16em tracking */
  .cta-row .btn,.editorial .cta-row .btn,.sec p > .btn + .btn,.sec p > .btn,.band p > .btn{
    min-width:0;max-width:100%;padding:12px 8px;font-size:10.5px;
    letter-spacing:.12em;text-align:center;white-space:normal;line-height:1.4;
  }
  /* stacked fallbacks (three or more, or engines without :has) never touch */
  .btn{max-width:100%}
  .btn + .btn{margin-top:0}
  p > .btn + .btn,.cta-row .btn + .btn{margin-left:0}

  /* the slab steps down on phones (Eric, 2026-08-13): on an iPhone the full
     20px/34px slab plus the design paddings pushed the stat band's second row
     ~30px under Safari's toolbar. Smaller slab + tighter vertical rhythm here
     buys the ~45px that puts all four stats back on the first screen. */
  .hero-ctas{gap:12px;margin-top:18px}
  .hero-ctas .btn.primary{padding:12px 22px;font-size:12px}
  .hero h1{margin-bottom:14px}
  /* The whole 2x2 stats band belongs on the FIRST screen. The base pins
     .hero{min-height:100svh}, which means the band always begins exactly at
     the fold on a phone: Grace saw two stats because the second row started
     where Safari's toolbar ends. Natural height instead, with a tighter
     column, puts headline, buttons and all four stats inside ~700px. */
  /* the hero fills the device exactly (svh accounts for Safari's chrome); the
     transparent one-line band rides inside it, so the first screen is all hero */
  .hero{min-height:100svh}
  .hero-in{padding-block:clamp(22px,3.4vh,36px) clamp(12px,1.8vh,18px)}
  /* all four stats on ONE line (the base drops to a 2x2 under 560px, and the
     2x2's second row is what kept hiding under the fold). Four across at 390
     is ~97px a cell: numbers hold one line, labels wrap to two. The base's
     nth-child(3) order swap and 56px right pad existed to dodge the chat
     bubble when the band ended at the viewport edge; one row ends well above
     the bubble, so both reset. */
  /* the 2x2 hairline grid from the mobile hero design (2026-08-10): every cell
     rules its own top, the right column rules its left, dividers continuous.
     The stacked CTA (one slab + a text link) is short enough that all four
     cells land on the first screen again. */
  .hero-stats .wrap{grid-template-columns:repeat(2,minmax(0,1fr));gap:0;padding:0 24px 10px!important}
  .hero-stats .stat{padding:11px 0 9px;border-top:1px solid rgba(242,239,232,.18)}
  .hero-stats .stat+.stat::before{display:none}
  .hero-stats .stat:nth-child(even){border-left:1px solid rgba(242,239,232,.18);padding-left:18px}
  /* natural order, as designed (the base's nth-child(3) fold swap resets);
     the Gracie bubble still sits on the bottom-right cell: clearance stays there */
  .hero-stats .stat:nth-child(3){order:0;padding-right:0}
  .hero-stats .stat:nth-child(4){padding-right:56px}
  .hero-stats .stat-v{font-size:24px}
  .hero-stats .stat-word{font-size:20px}
  .hero-stats .stat-l{font-size:9px;letter-spacing:.12em;margin-top:4px;line-height:1.3}
  .shead{padding-bottom:14px;margin-bottom:22px}
  .eyebrow::before{width:18px}
  .stat-v{font-size:30px}
  /* market/neighborhood stat cards: two per row on a phone, so the value has
     to fit half a 342px column. 30px tabular figures didn't ("$421,975" forced
     the grid past the viewport); ~25px at 390 does, easing down with the
     screen. Tighter cell padding buys the rest of the room. */
  .ms-v{font-size:clamp(20px,6.4vw,26px)}
}

/* ── the polaroid strip, ported ────────────────────────────────
   Structure lifted from grace-alt (this markup only exists there),
   restyled for this theme: a warmer, thinner frame, the caption in
   Ephesis rather than Caveat, and a softer lift when one is picked.
   `--script`, `--gold` and `--pad-x` are grace-alt tokens that do
   not exist in grace's base, so each is restated here. */
.pol-strip{
  display:flex;align-items:flex-start;gap:0;overflow-x:auto;overflow-y:hidden;
  margin-left:calc(50% - 50vw);margin-right:calc(50% - 50vw);
  padding:30px max(24px,calc(50vw - var(--wrap) / 2)) 40px;
  scroll-snap-type:x proximity;-webkit-overflow-scrolling:touch;
  scrollbar-width:none;overscroll-behavior-x:contain;
}
.pol-strip::-webkit-scrollbar{display:none}
.pol{
  flex:0 0 auto;width:clamp(184px,23vw,246px);margin:0 -34px 0 0;
  scroll-snap-align:center;background:#FFFDFA;padding:11px 11px 0;
  border:1px solid var(--rule);border-radius:var(--r-sm);
  /* grace-alt drops a heavy 30px shadow under each frame; a warm hairline and a
     whisper of depth is enough to read as a stack without the drama */
  box-shadow:0 10px 20px -16px rgba(58,47,39,.5);
  transform:rotate(var(--tilt,0deg));transform-origin:50% 92%;
  transition:transform .38s cubic-bezier(.2,.8,.2,1),box-shadow .38s ease,border-color .38s ease;
  z-index:calc(90 - var(--i,0));cursor:pointer;
}
.pol:last-child{margin-right:0}
.pol-img{position:relative;aspect-ratio:4/5;overflow:hidden;background:var(--cream);border-radius:calc(var(--r-sm) - 2px)}
.pol-m{width:100%;height:100%;object-fit:cover;display:block}
.pol.is-front{
  z-index:200;transform:rotate(0deg) translateY(-12px) scale(1.04);
  border-color:var(--accent-soft);
  box-shadow:0 22px 34px -22px rgba(58,47,39,.6);
}
@media(hover:hover){
  .pol:hover{transform:rotate(0deg) translateY(-5px)}
  .pol.is-front:hover{transform:rotate(0deg) translateY(-12px) scale(1.04)}
}
.pol:focus-visible{outline:2px solid var(--accent);outline-offset:3px}
.pol-play{
  position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);z-index:2;
  width:46px;height:46px;border-radius:50%;background:rgba(58,47,39,.46);color:#fff;
  display:flex;align-items:center;justify-content:center;font-size:15px;padding-left:3px;
  -webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);
  opacity:0;transition:opacity .2s;
}
.pol.stalled .pol-play{opacity:1}
.life-follow{text-align:left;margin-top:6px}
#lifestyle{scroll-margin-top:84px}
.lifestyle .life-intro{max-width:none;margin:0 0 22px}
@media(max-width:620px){
  .pol{width:clamp(158px,54vw,200px);margin-right:-26px}
  .pol figcaption{font-size:18px}
}

/* ── contrast corrections, measured not guessed ────────────────
   Audited with a WCAG pass over every visible text node against its
   real painted backdrop. These are the selectors that came back
   under AA and are not fixed by the --slate and --clay-ink tokens. */
.pop{color:var(--accent-deep)}          /* was 2.97:1 as the lighter accent at heading size */
.pnext-k,.gh-k,.l-kicker{color:var(--clay-ink)}
/* the nav is transparent over the hero and opaque once scrolled; the opaque
   state needs dark type, which the overlay state must not inherit */
.nav:not(.overlay) .brand-word,
.nav:not(.overlay) .links a{color:var(--ink)}
.nav:not(.overlay) .links a:hover{color:var(--accent-deep)}
.nav.overlay .brand-word,.nav.overlay .links a{color:#fff}

/* Same specificity as the base rules they replace (.shead h2 .pop is 0,3,0 and
   was beating a bare .pop). Measured, not assumed: the audit reported these three
   still failing after the token changes, with the exact colours below. */
.shead h2 .pop,h1 .pop,h2 .pop{color:var(--accent-deep)}   /* was #B07E3F, 2.76:1 at 44px */
.hero h1 .pop{color:#D9B36C;font-style:italic}             /* italic gold, the design's popped word */
.fbrokerage .bk{color:#C8CDD4}                             /* was #8A9099 on the dark footer */
.pnext .pnext-k{color:var(--clay-ink)}                     /* was --clay, 3.84:1 at 12px */

/* Second measured pass. Each of these came back under AA on the real page with
   her real copy, and each is a state or a container the first pass missed. */

/* The nav keeps .overlay when it sticks; .scrolled is the class that swaps the
   background to near-opaque linen. White links on linen measured 1.07:1. */
/* .overlay and .scrolled coexist on the home nav, and the overlay's transparent
   background was outliving the scroll: the wordmark sat naked on whatever passed
   under it. The combined state must win outright. */
.nav.scrolled,.nav.overlay.scrolled{background:rgba(246,242,236,.97);border-bottom:1px solid var(--rule)}
.nav.scrolled .links a,.nav.scrolled .brand-word,
.nav.overlay.scrolled .links a,.nav.overlay.scrolled .brand-word{color:var(--ink)}
.nav.overlay.scrolled .brand{color:var(--accent)}
.nav.scrolled .menu-btn span,.nav.overlay.scrolled .menu-btn span{background:var(--ink)}
.nav.scrolled .links a:hover,.nav.overlay.scrolled .links a:hover{color:var(--accent-deep)}

/* The closing band is dark; the script line and small print have to invert. */
.band h1 em,.band h2 em{color:var(--gold-soft)}
/* the footer element carries no class; select the tag */
footer .fh,footer .flogin,footer .legal,footer .bk,footer .ftag,footer p,
footer .fname,.fbrokerage .bk{color:#C8CDD4}
footer h3,footer strong,footer .fbrand{color:var(--paper)}
footer a{color:#E4E7EB}
footer a:hover{color:#fff}
/* the dark closing band, same problem as the footer */
.band p,.band .band-alt,.band .sub{color:rgba(255,255,255,.9)}
.band a{color:var(--gold-soft)}
.lclosed{color:var(--clay-ink)}
.areas-sub{color:var(--clay-ink)}
.sold-note{color:var(--clay-ink)}   /* was --clay, 4.12:1 at 13.5px */

/* ── the hero sentence stacks again (design 2026-08-10) ────────
   The "two voices share a line" pass is reversed by the Grace Hero Mobile
   design: the script sits UNDER the headline on its own line, clearly smaller
   (.72em, capped at 40px so the sentence holds one line in this column). */
.hero h1{font-size:clamp(42px,4.8vw,64px);line-height:1.06;max-width:23ch}
/* nowrap: the script sentence NEVER breaks — its size is set against the column
   at every width below, so forcing one line cannot overflow */
.hero h1 em{font-size:clamp(28px,.72em,40px);line-height:1.25;margin-left:0;position:relative;white-space:nowrap}

/* ── hero load: the text steps in (design 2026-08-10) ──────────
   One slide-up per voice — kicker, headline, script, subline, then the CTA
   stack — replacing the base's single-block entrance. The base's no-fx and
   reduced-motion kills strip these animations (and with them the backwards
   fill), so in both modes everything is simply visible. */
.hero-in{animation:none}
.hero-in .eyebrow,.hero-in h1,.hero-in h1 em,.hero-in .sub,.hero-in .hero-ctas{
  animation:heroin .85s cubic-bezier(.2,.6,.2,1) backwards}
.hero-in .eyebrow{animation-delay:.08s}
.hero-in h1{animation-delay:.22s}
.hero-in h1 em{animation-delay:.42s}
.hero-in .sub{animation-delay:.58s}
.hero-in .hero-ctas{animation-delay:.74s}
/* the mark hangs off the end of the script rather than the column edge */
.doodle{position:absolute;pointer-events:none;overflow:visible}
/* inline with the subline: flows after her last word (the nowrap .sub-tail
   keeps word + face together), tilted like something dashed off in a margin */
.sub-tail{white-space:nowrap}
.doodle-face{position:static;display:inline-block;vertical-align:-12%;
  padding-left:.35em;transform:rotate(-8deg);transform-origin:center}
@media(max-width:900px){.doodle-face{width:48px;height:41px}}
@media(max-width:620px){.doodle-face{width:41px;height:35px;padding-left:.28em}}

/* ── stat cards get room ───────────────────────────────────────
   The hero band's figures were sitting hard against their dividers.
   Desktop only: on phones this outranked (by source order) the mobile block's
   tight 2x2 padding and its 40px of block padding per row is what pushed the
   band's second row under Safari's toolbar. */
@media(min-width:761px){
.hero-stats .stat{padding:clamp(20px,2.6vw,30px) clamp(18px,2.4vw,32px)}
}
.hero-stats .wrap{padding-inline:0}
.mstats .mstat,.stats .stat,.tile{padding:clamp(20px,2.4vw,28px) clamp(18px,2.2vw,26px)}
.ed-badge{padding:14px 18px}
/* phones: two stat cards share a 342px column, so the cells give their extra
   room back and never refuse to shrink. AFTER the roomy rule above on purpose:
   it wins by source order (the hero band learned this the hard way). */
@media(max-width:760px){
  .mstats{gap:10px}
  .mstats .mstat{padding:16px 10px;min-width:0}
}

/* ── the nuance pass, 2026-08-09 ───────────────────────────────
   Small physical details, each cheap alone; together they are the
   difference between "styled" and "finished". */

/* selecting text answers in the brand, not browser blue */
::selection{background:var(--accent);color:#FCFBF8}

/* one focus language everywhere, instead of whatever each control inherited */
:where(a,button,summary,[tabindex]):focus-visible{
  outline:2px solid var(--accent);outline-offset:3px;border-radius:2px;
}

/* prose links: a hairline underline held slightly off the baseline, warming to
   green on hover, instead of the browser's heavy default strike-through-ish rule */
.sec p a,.prose a,.mqa a,.qa a{
  text-decoration-thickness:1px;
  text-underline-offset:3px;
  text-decoration-color:var(--rule-strong);
  transition:text-decoration-color .18s ease,color .18s ease;
}
.sec p a:hover,.prose a:hover{color:var(--accent-deep);text-decoration-color:var(--accent)}

/* buttons acknowledge the hand: a breath up on hover, settled back on press */
.btn{transition:background .18s ease,border-color .18s ease,color .18s ease,transform .16s ease}
@media(hover:hover){.btn:hover{transform:translateY(-1px)}}
.btn:active{transform:translateY(0)}

/* figures hold their column without rag: numbers align as a table wherever the
   face offers tabular forms, and paragraphs avoid one-word last lines */
.stat-v,.ms-v,.tile b,.ed-badge .stat-v{font-variant-numeric:tabular-nums}
.sec p,.prose p,.hero .sub,.psub{text-wrap:pretty}

/* Playfair's hairlines want real antialiasing on the dark hero band */
.hero h1,.band h2{-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility}

/* the popped word: in Playfair the colour is enough — no weight jump, so the
   word sits in the sentence instead of bulging out of it */
h1 .pop,h2 .pop{font-weight:inherit}

/* cards lift by border, not by shadow: hover deepens the hairline and the
   title, and the whole object stays flat on the page */
.lcard,.ghint,.mstat,.mqa{transition:border-color .2s ease}
.lcard:hover,.ghint:hover{border-color:var(--rule-strong)}

/* horizontal rules inside content match the theme's hairline */
.sec hr,.prose hr{border:0;border-top:1px solid var(--rule);margin:var(--sp-head) 0}

/* the back-to-top control inherits the theme's geometry */
.gotop{border-radius:var(--r-sm);box-shadow:none;border:1px solid var(--rule-strong)}

/* word-stats: set by mid.js on any stat value containing letters */
.stat-word{
  font-family:'Playfair Display','Besley',Georgia,serif;
  font-style:italic;font-weight:520;text-transform:none;
  letter-spacing:-.015em;font-size:clamp(26px,3.2vw,38px);
}

/* Chips are FACTS, not controls, and were reading as ghost buttons. grace-alt's
   treatment: one connected strip behind a single hairline, interior rules
   dividing the entries, square, on a light wash. No borders on the pieces, no
   fill per piece, nothing that says press me. */
.kw-chips{display:flex;flex-wrap:wrap;gap:0;width:fit-content;
  border:1px solid var(--rule);background:rgba(253,252,249,.6);margin-top:22px}
.kw-chips span{
  background:none;border:0;border-right:1px solid var(--rule);border-radius:0;
  color:var(--slate);font-size:12px;font-weight:500;letter-spacing:.01em;
  padding:8px 14px;
}
.kw-chips span:last-child{border-right:0}
@media(max-width:560px){
  /* ONE line, always: wrap used to strand the third chip on its own row.
     The font rides the viewport (clamp) so the row shrinks instead of breaking. */
  .kw-chips{width:100%;flex-wrap:nowrap}
  .kw-chips span{flex:1 1 auto;min-width:0;text-align:center;padding:8px 4px;
    white-space:nowrap;font-size:clamp(9px,2.9vw,12px);letter-spacing:0}
}

/* ── the open mobile menu ──────────────────────────────────────
   The overlay-nav's white wordmark was outliving the menu opening, sitting
   white on the paper panel. And the base sets the menu links in 21px uppercase
   Besley; here they go clean: Inter, sentence case. */
@media(max-width:820px){
  .nav.open .brand-word{color:var(--ink)}
  .nav.open .links a{
    font-family:'Inter',system-ui,sans-serif;font-size:17px;font-weight:600;
    letter-spacing:.01em;text-transform:none;
  }
  .nav.open .links a[aria-current="page"]{font-style:normal;color:var(--accent-deep)!important}
}

/* ── no horizontal scroll, ever ────────────────────────────────
   The polaroid strip's full-bleed margins are calc(50% - 50vw), and on Windows
   100vw includes the scrollbar, so Edge gets a few real pixels of horizontal
   scroll. clip, NEVER hidden: overflow-x:hidden on the root turns it into a
   scroll container and breaks position:fixed on iOS Safari (see the global
   law). clip clips without creating a scroller. */
html,body{overflow-x:clip}

/* ── the listings list (fewer than four actives) ───────────────
   A grid or carousel holding two cards looks broken; rows do not. */
.llist{display:flex;flex-direction:column;border:1px solid var(--rule);background:var(--field-2)}
.llist-row{display:flex;align-items:center;gap:16px;padding:14px 16px;text-decoration:none;
  color:var(--ink);transition:background .18s ease}
.llist-row + .llist-row{border-top:1px solid var(--rule)}
.llist-row:hover{background:#FBFAF6}
.llist-thumb{width:112px;height:84px;object-fit:cover;flex:none;border-radius:0;
  border:1px solid var(--rule)}
.llist-body{display:flex;flex-direction:column;gap:3px;min-width:0;flex:1}
.llist-title{font-family:'Besley',Georgia,serif;font-weight:600;font-size:16.5px;line-height:1.25}
.llist-row:hover .llist-title{color:var(--accent-deep)}
.llist-teaser{font-size:12.5px;color:var(--slate);overflow:hidden;display:-webkit-box;
  -webkit-line-clamp:1;-webkit-box-orient:vertical}
.llist-price{margin-left:auto;text-align:right;flex:none;display:flex;flex-direction:column;gap:2px;
  font-family:var(--bold);font-size:15px;letter-spacing:-.02em}
.llist-go{font-family:'Inter',sans-serif;font-size:10.5px;font-weight:700;letter-spacing:-.005em;
  text-transform:uppercase;color:var(--clay-ink)}
@media(max-width:560px){
  .llist-row{gap:12px;padding:12px}
  .llist-thumb{width:84px;height:63px}
  .llist-title{font-size:14.5px}
  .llist-price{font-size:13.5px}
}

/* the Instagram button: left aligned under the strip, glyph before the words */
.life-follow{text-align:left}
.btn-ig{display:inline-flex;align-items:center;gap:8px;
  /* ONE line, always: the label used to wrap to two on phones */
  white-space:nowrap;max-width:100%}
.btn-ig svg{width:15px;height:15px;flex:none}
@media(max-width:560px){
  .btn-ig{font-size:clamp(9px,3.2vw,13px);padding-left:10px;padding-right:10px;letter-spacing:.02em}
}

/* Stacking order. The polaroids climb to z 200 (front card) while the base
   theme's nav sits at 90, so scrolled cards painted OVER the header. The nav
   wins over all scrolling content; deliberate overlays (chat drawer, video
   modal, lightbox, skip link) win over the nav. */
.nav{z-index:300}
.nav .links{z-index:305}
#rchat-veil{z-index:415}
#rchat{z-index:420}
.vmodal{z-index:430}
#rgal-m{z-index:430}
.skip{z-index:440}
#rchat.page{z-index:auto}

/* ── the script line on phones ─────────────────────────────────
   Two things had to be true at once (Eric, 2026-08-09): the wrapped lines sit
   HALF as far apart as they did, and the line still clears the Playfair
   headline above it. line-height on an inline em cannot shrink a line box
   below the h1's own strut, so on phones the script becomes its own
   inline-block and sets its own leading, with the space above restored as a
   margin instead. It is also sized to land on ONE line at common phone
   widths; below that it wraps tight rather than overflowing, because a hero
   that scrolls sideways is worse than a hero on two lines.

   This block sits at the end of the file on purpose: the "hero sentence
   really does flow" rules above are not in a media query, so an earlier
   mobile block loses to them at equal specificity. That cost an hour. */
@media (max-width:760px){
  .hero h1 em{
    display:inline-block;
    /* 32 at the design's 390 frame; pure vw below that so the ONE-LINE
       sentence (nowrap above) shrinks with the column instead of clipping */
    font-size:clamp(18px,8vw,32px);
    line-height:1.15;
    margin-left:0;
    margin-top:clamp(6px,2vw,10px);
  }
  .doodle-face{width:38px;height:33px;padding-left:.24em;vertical-align:-14%}
}

/* ── connected button pairs: keep the seam ─────────────────────
   border-left:0 collapsed the double border between two GHOST buttons into one
   line, which was right for that case and wrong for every other one: a filled
   primary carries no border of its own, so stripping the ghost's left edge left
   the pair open on the seam and the outlined button read as unfinished. The
   ghost keeps its edge now, and the pair overlaps by a pixel so two outlined
   buttons still share a single line. */
.hero-ctas .btn + .btn,
.cta-row .btn + .btn,
.sec p > .btn + .btn,
.band p > .btn + .btn{
  border-left:1px solid var(--rule-strong);
  margin-left:-1px;
}
@media (max-width:760px){
  /* the pair is a two-up grid at this width; the overlap still collapses the seam */
  .cta-row .btn + .btn,
  .sec p > .btn + .btn,
  .band p > .btn + .btn{margin-left:-1px}
}

/* ── the strip's arrow lives in the Instagram row ──────────────
   One circular right arrow, vertically centered on the follow button and held
   to the container's right edge, half strength until approached. The strip
   loops, so a single direction is enough (mid.js wraps end back to start). */
.life-follow{position:relative;padding-right:58px}
.pol-next{
  position:absolute;right:0;top:50%;transform:translateY(-50%);
  width:46px;height:46px;border-radius:50%;
  border:1px solid var(--rule-strong);background:#FFFDFA;color:var(--ink);
  display:flex;align-items:center;justify-content:center;cursor:pointer;
  opacity:.5;transition:opacity .2s,border-color .2s;
  box-shadow:0 6px 18px -10px rgba(58,47,39,.6);
}
.pol-next:hover{opacity:1;border-color:var(--accent)}
.pol-next:focus-visible{opacity:1;outline:2px solid var(--accent);outline-offset:2px}
.pol-next svg{width:19px;height:19px}

/* ── desktop hero scale-up + motion (Eric, 2026-08-13) ─────────────────
   The hero text column grows with the device: 800px wide at full desktop,
   and every voice in it (headline, script line, its doodle, the sub) scales
   from the same fluid size. Mobile keeps the 2026-08-10 design untouched. */
@media (min-width:761px){
  .hero h1{font-size:min(clamp(46px,5.4vw,78px),calc((min(800px,92vw)) / (var(--hero-ch,24) * .375)));max-width:min(800px,92vw)}
  .hero h1 em{font-size:clamp(30px,.72em,54px)}
  .hero .sub{font-size:clamp(16px,1.35vw,20.5px);max-width:min(52ch,800px)}
  /* the face rides the script line's em box, so it scales with the sentence */
  .hero h1 em .doodle-face{width:1.42em;height:1.22em;vertical-align:-14%}
}

/* Two lines at every width (Eric, 2026-08-13). home.php picks the break and
   passes the longer half's length as --hero-ch; the type is capped at the size
   that half fits its column at, so the headline never spills to a third line.
   This sits in the end-of-file layer deliberately: the unscoped .hero h1 size
   further up outranks anything set in the max-width:760px block. */
@media (max-width:760px){
  .hero h1{font-size:min(clamp(34px,11.8vw,46px),calc((100vw - 52px) / (var(--hero-ch,24) * .375)));max-width:none}
}

/* Words flip in. JS wraps the roman headline words in .fw and arms .flip;
   without JS nothing is wrapped and the headline simply stands there,
   visible — the animation is decoration, never a gate. */
.flip{perspective:820px}
.fw{display:inline-block}
.flip .fw{opacity:0;transform:rotateX(86deg);transform-origin:50% 88%;
  animation:wordflip .62s cubic-bezier(.2,.65,.25,1) forwards;
  animation-delay:calc(.1s + var(--i,0) * .07s)}
.flip .fw-em{opacity:0;transform:none;animation:emin .7s ease forwards;animation-delay:var(--emd,1s)}
@keyframes wordflip{to{opacity:1;transform:none}}
@keyframes emin{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:none}}
@media (prefers-reduced-motion:reduce){
  .flip .fw,.flip .fw-em{animation:none;opacity:1;transform:none}
}
.no-fx .fw,.no-fx .fw-em{animation:none!important;opacity:1!important;transform:none!important}

/* Images ease in as they enter the frame: a quiet settle, applied by JS only
   to below-the-fold images, so nothing is ever hidden without a script. */
.img-ease{opacity:0;transform:scale(1.045);transition:opacity .75s ease,transform .95s cubic-bezier(.2,.6,.2,1)}
.img-ease.img-in{opacity:1;transform:none}
@media (prefers-reduced-motion:reduce){.img-ease{opacity:1;transform:none;transition:none}}
.no-fx .img-ease{opacity:1!important;transform:none!important}

/* the lifestyle polaroids stay out of the settle: a plain fade, nothing else */
.pol-strip.fade{transform:none}
/* the sold carousel clones cards to loop, so a clone can carry the class with
   no observer behind it — same guard the .fade system already needs there */
.sold-carousel .img-ease,.sold-band .img-ease{opacity:1!important;transform:none!important}

/* Page transitions: same-document cross-fade on browsers that support
   MPA view transitions; everywhere else navigation is just navigation. */
@view-transition{navigation:auto}
::view-transition-old(root){animation-duration:.22s}
::view-transition-new(root){animation-duration:.3s}

/* reviews: pages of three, the quiet leave/read line, the fading carousel
   (end-of-file design layer on purpose: it must outrank the base grid) */
.qgrid{grid-template-columns:1fr}
.qpage{display:grid;grid-template-columns:repeat(3,1fr);gap:20px}
@media(max-width:860px){.qpage{grid-template-columns:1fr;gap:16px}}
.qmore{text-align:center;margin-top:22px;font-size:13.5px;color:var(--slate)}
.qmore a{color:inherit;text-decoration:underline;text-underline-offset:3px}
.qmore a:hover{color:var(--walnut,#2B241B)}
/* phones: every card in one stack, one visible */
@media(max-width:860px){
  .qgrid.rotate .qpage{display:contents}
  .qgrid.rotate .qcard{grid-area:1/1;opacity:0;transform:none;transition:opacity .8s ease;pointer-events:none}
  .qgrid.rotate .qcard.on{opacity:1;pointer-events:auto}
}
/* desktop past three reviews: whole pages cross-fade */
.qgrid.rotate-pages .qpage{grid-area:1/1;opacity:0;transition:opacity .8s ease;pointer-events:none}
.qgrid.rotate-pages .qpage.on{opacity:1;pointer-events:auto}
.qgrid.rotate-pages .qcard{opacity:1;transform:none}
.qgrid.rotate,.qgrid.rotate-pages{touch-action:pan-y}
/* dots: 7px to the eye, 44px to the thumb */
.qdots{display:flex;justify-content:center;margin-top:6px}
.qdots button{width:44px;height:44px;margin:0 -6px;border:0;background:none;cursor:pointer;display:flex;align-items:center;justify-content:center;padding:0}
.qdots button::before{content:"";width:7px;height:7px;border-radius:50%;background:var(--rule);transition:background .3s,transform .3s}
.qdots button.on::before{background:var(--walnut,#2B241B);transform:scale(1.3)}
@media (prefers-reduced-motion: reduce){
  .qgrid.rotate .qcard,.qgrid.rotate-pages .qpage{transition:none}
}

/* listing gallery: one lead photo, thumbs in a 2-wide rail, one shared gap
   everywhere so the spacing reads even. Rows size from the thumbs; the lead
   stretches to meet them exactly. */
.rgal.ls .rgal-grid{display:grid;grid-template-columns:2.2fr 1fr 1fr;gap:12px}
.rgal.ls .rgal-t{position:relative}
.rgal.ls .rgal-t.lead{grid-column:1;grid-row:1 / span var(--rail-rows,4)}
.rgal.ls .rgal-t.lead .rgal-ph{height:100%;aspect-ratio:auto;min-height:340px}
.rgal.ls .rgal-t figcaption{display:none} /* captions live in the lightbox here */
.rgal.ls .rgal-more{position:absolute;right:8px;bottom:8px;z-index:2;background:rgba(34,30,24,.78);color:#fff;
  font-size:12px;font-weight:600;letter-spacing:.02em;padding:4px 9px;border-radius:99px;pointer-events:none}
@media(max-width:860px){
  .rgal.ls .rgal-grid{grid-template-columns:repeat(4,1fr);gap:8px}
  .rgal.ls .rgal-t.lead{grid-column:1 / -1;grid-row:auto}
  .rgal.ls .rgal-t.lead .rgal-ph{aspect-ratio:4/3;min-height:0;height:auto}
}
/* the jump link hangs off the price block absolutely, so the header keeps
   its exact height; it floats in the whitespace above the gallery */
.listing-head .lh-price{position:relative}
.lh-details{position:absolute;top:100%;right:0;margin-top:8px;font-size:13px;color:var(--slate);
  text-decoration:underline;text-underline-offset:3px;white-space:nowrap}
@media(max-width:700px){.lh-details{right:auto;left:0}}
#ldetails{scroll-margin-top:86px}
/* listing pages read as one continuous piece: no hairlines between sections */
.listing-head + .sec, .listing-head ~ .sec + .sec{border-top:0}
body:has(.listing-head) .phead, body:has(.listing-head) .sec+.sec{border-top:0;border-bottom:0}
/* This header opens on a breadcrumb, not an eyebrow, so the shared .phead block
   padding left most of a hundred pixels of nothing between the nav and a 12px
   line, and pushed the photographs down the page. It starts higher; the closing
   space below it is untouched. (Eric, 2026-08-21) */
.listing-head{padding-top:clamp(28px,3.2vw,44px)}
html{scroll-behavior:smooth}
@media (prefers-reduced-motion: reduce){html{scroll-behavior:auto}}
/* by-the-numbers rows in the listing sidebar */
.lnum{display:flex;justify-content:space-between;gap:14px;font-size:14px;padding:7px 0;border-bottom:1px solid var(--rule)}
.lnum:last-child{border-bottom:0}
.lnum b{font-weight:600;white-space:nowrap}
.lnum span{color:var(--slate)}

/* numbered process steps (buyers/sellers): serif italic numbers, dashed rules */
.psteps ol{list-style:none;margin:14px 0 0;padding:0}
.psteps li{display:flex;gap:22px;align-items:baseline;padding:17px 0;border-bottom:1px dashed var(--rule);font-size:15px;line-height:1.62;max-width:74ch}
.psteps li:last-child{border-bottom:0}
.pstep-n{font-family:'Besley',serif;font-style:italic;font-size:19px;color:var(--accent);flex:none;min-width:26px}
.psteps b{font-weight:600;color:var(--walnut,#2B241B)}
@media(max-width:560px){.psteps li{gap:14px;padding:14px 0}}

/* Guide teasers: a compact row, not a poster. The 16:9 card ran nearly full
   height of the viewport on a ZIP page with one guide, and a guide without a
   photo rendered as a different shape entirely. Now both are the same row and
   the thumb is simply present or absent. (End-of-file layer on purpose: it
   outranks the base .ghint card rules.) */
.ghints{grid-template-columns:1fr;gap:10px}
@media(min-width:900px){.ghints{grid-template-columns:1fr 1fr}}
.ghint{flex-direction:row;align-items:center;gap:14px;padding:12px 16px 12px 12px;background:var(--field-2,#F6F2EC)}
.ghint:hover,.nbcard:hover{transform:none;box-shadow:none}
.gh-img{flex:none;width:74px;height:74px;aspect-ratio:auto;border-radius:var(--r-sm,8px);overflow:hidden}
.gh-img img{width:100%;height:100%;object-fit:cover}
.ghint:hover .gh-img img{transform:none}
.gh-body{padding:0;gap:3px;min-width:0}
.gh-k{font-size:10px;letter-spacing:.16em}
.gh-t{font-size:17px;line-height:1.2}
/* both variants keep the same height: two lines of blurb, then the cue */
.gh-d{font-size:13px;line-height:1.5;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.gh-go{font-size:12.5px;margin-top:1px}
@media(max-width:560px){
  .ghint{gap:11px;padding:10px 12px 10px 10px}
  .gh-img{width:60px;height:60px}
  .gh-t{font-size:16px}
  .gh-d{-webkit-line-clamp:2;font-size:12.5px}
}

/* the see-all pill inherits grace/style.css; mid squares it and sets it in
   the uppercase, wide-tracked voice every button on this theme uses */
/* a bar across the foot of the last tile: the chip form outgrew a 160px
   thumb once the band replaced the old wide-cell grid */
.rgal.ed.sh .rgal-more{left:50%;transform:translateX(-50%);right:auto;bottom:8px;border-radius:99px;
  justify-content:center;max-width:calc(100% - 12px);
  font-size:9px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;
  padding:7px 11px;gap:5px}
@media(max-width:560px){.rgal.ed.sh .rgal-more{font-size:9px;padding:8px 10px;letter-spacing:.12em}}

/* Listing spec sheet ("By the numbers") in the content frame: no card chrome,
   a small sans heading sized to its own rows, and the same dotted hairline the
   features list uses. Lives here, not in the template's conditional style
   block, so a listing whose ZIP has no market row still gets the styles. */
.lspecs{margin-top:38px}
.lspecs-h{font-family:'Inter',system-ui,sans-serif;font-size:13.5px;font-weight:700;letter-spacing:0;text-transform:none;margin:0 0 14px}
.lspecs-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:0 40px}
.lspec{display:flex;justify-content:space-between;align-items:baseline;gap:14px;padding:11px 0;border-bottom:1px dashed var(--line);font-size:13.5px}
.lspec span{color:var(--slate)}
.lspec b{font-weight:600}
@media(max-width:560px){.lspecs-grid{grid-template-columns:1fr}}

/* the photo-less card (style.css): mid sets its addresses in Instrument Serif,
   the same face its neighborhood tiles use */
.lplate-addr{font-family:'Instrument Serif',Georgia,serif;font-weight:400;letter-spacing:0;
  font-size:clamp(18px,2.1vw,22px);line-height:1.14}
