/* =========================================================================
   Erica Iriarte, Southern California real estate.
   The whole design system. Hand-written, no build step.

   Brand values come from PART 1 of Brett's build spec, which pulled them from
   The Rockwell Group, the site the client named as the aesthetic reference.

   Every rule tagged [CHECKLIST n.n] is an acceptance criterion from PART 2 of
   that spec. Each one is a defect a previous Appomark build shipped. Do not
   "simplify" them away.
   ========================================================================= */

/* [CHECKLIST 2.3] FIRST rule in the sheet, deliberately. Without it iOS Safari
   paints button text in system blue while desktop renders black, so the bug is
   invisible in desktop testing. */
button {
  color: inherit;
  font: inherit;
}

/* ------------------------------------------------------------------ tokens */
:root {
  --paper: #FFFFFF;             /* pure white */
  --cream: #FBF9F7;             /* page background, warm off white */
  --sand: #ECE7E1;              /* warm beige, alternating sections */
  --line: #DDDDDD;              /* hairline rules and borders */
  --ink: #000000;               /* body and heading text on light */
  --ink-soft: rgba(0, 0, 0, .66);
  --ink-faint: rgba(0, 0, 0, .42);
  /* ROUND 3 PART 1: the deep slate token is DELETED, deliberately, so it
     cannot come back. The site is a two colour world: white and beige with
     black text, and white only on photographs over the neutral scrim. */

  /* [CHECKLIST 2.4] Neutral near black RGB triplet for photo overlays. NEVER a
     brand colour: a tinted scrim colours every photograph on the site and costs
     a full revision round to trace back. */
  --scrim: 10, 9, 8;

  --display: 'Noto Serif Display', 'Times New Roman', serif;
  --body: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif;

  --nav-h: 92px;
  --wrap: 1240px;
  --ease: cubic-bezier(.22, .61, .36, 1);

  /* ROUND 3: the vertical rhythm is ONE scale, here and nowhere else. Every
     section pays the gap twice, once as its own bottom padding and once as
     the next section's top, so 56px a side is the 112px desktop budget the
     responsive check enforces. Never hard-code a fat literal padding on a
     section; if a section needs more air, raise this and re-run the check. */
  --gap-section: 56px;
  --gap-tight: 40px;
}

@media (max-width: 860px) {
  :root {
    --gap-section: 36px;
    --gap-tight: 28px;
  }
}

/* -------------------------------------------------------------------- base */
*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}

/* ROUND 3 PART 2: the readability lift. Body is 18px at 1.7, and EVERY
   font-size in this sheet is either a plain px value of 13px or more, or a
   clamp() whose floor is at least 13px. Bare vw font sizes are BANNED: they
   rendered the hero lede at 10px and the eyebrows at 8px on a 500px window,
   which is the single measured cause of the "hard to read" complaint. */
body {
  margin: 0;
  background: var(--cream);
  color: var(--ink);
  font-family: var(--body);
  font-size: 18px;
  font-weight: 400;
  line-height: 1.7;
  /* [CHECKLIST 2.5] Belt and braces against sideways scroll on a phone. */
  overflow-x: hidden;
}

/* `img { height: auto }` is load-bearing. Every <img> carries width/height
   attributes to reserve its box against layout shift. Without this the
   attribute becomes the used height and a 2400x1800 photo in a 580px column
   renders 580x1800, badly stretched. */
img {
  max-width: 100%;
  height: auto;
  display: block;
}

a {
  color: inherit;
}

h1, h2, h3, h4 {
  margin: 0;
  font-weight: 300;
}

p {
  margin: 0;
}

ul, ol {
  margin: 0;
  padding: 0;
}

:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 3px;
}

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 200;
  background: var(--ink);
  color: var(--paper);
  padding: 12px 18px;
  font-size: 13px;
}

.skip-link:focus {
  left: 12px;
  top: 12px;
}

.wrap {
  width: 100%;
  max-width: var(--wrap);
  margin: 0 auto;
  padding: 0 40px;
}

@media (max-width: 860px) {
  .wrap { padding: 0 24px; }
}

@media (max-width: 560px) {
  .wrap { padding: 0 20px; }
}

/* ---------------------------------------------------------------- type kit */
/* Display face: Noto Serif Display 300, uppercase, wide letterspacing. */
.display {
  font-family: var(--display);
  font-weight: 300;
  text-transform: uppercase;
  letter-spacing: .05em;
  line-height: 1.14;
  color: var(--ink);
}

/* ROUND 4 PART 2.2: .d1 appears only in page headers, one per interior
   page, so the header H1 scale lives here. Was clamp(44px, 5.5vw, 64px). */
.d1 { font-size: clamp(36px, 4vw, 54px); }
.d2 { font-size: clamp(30px, 3.4vw, 44px); }
.d3 { font-size: clamp(20px, 2.4vw, 26px); }

/* Eyebrows and nav share the small uppercase Inter setting. */
.eyebrow {
  font-size: 13.5px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 1.4px;
  color: var(--ink-soft);
  margin-bottom: 16px;
}

/* [CHECKLIST 1.2 note] Body paragraphs are SENTENCE CASE. The reference site
   sets some body copy uppercase at 12px; that is not copied here, it hurts
   readability on a consumer site.

   ROUND 3 PART 2: ledes are the style upgrade. Serif italic against the sans
   body, the editorial move. Needs the italic 400 axis in the Google Fonts link
   on every page. */
.lede {
  font-family: var(--display);
  font-style: italic;
  font-weight: 400;
  font-size: clamp(17px, 1.7vw, 20px);
  line-height: 1.65;
  color: var(--ink-soft);
  max-width: 62ch;
}

.prose p + p { margin-top: 18px; }

.prose {
  color: var(--ink-soft);
  max-width: 68ch;
}

.measure { max-width: 68ch; }

/* ----------------------------------------------------------------- buttons */
.btn {
  /* [CHECKLIST 2.1] inline-flex + nowrap, so a button never wraps to two lines
     however tight its column gets. */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  white-space: nowrap;
  gap: 10px;
  padding: 15px 30px;
  border: 1px solid var(--ink);
  border-radius: 0;
  background: none;
  font-family: var(--body);
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  text-decoration: none;
  cursor: pointer;
  transition: background-color .35s var(--ease), color .35s var(--ease),
              border-color .35s var(--ease), opacity .2s linear;
}

.btn-primary {
  background: var(--ink);
  color: var(--paper);
}

.btn-primary:hover {
  background: transparent;
  color: var(--ink);
}

.btn-ghost {
  background: transparent;
  color: var(--ink);
}

.btn-ghost:hover {
  background: var(--ink);
  color: var(--paper);
}

/* On a photograph the outline has to be white to be seen at all. */
.btn-on-photo {
  border-color: rgba(255, 255, 255, .85);
  color: #fff;
}

.btn-on-photo:hover {
  background: #fff;
  color: var(--ink);
}

.btn[disabled] {
  opacity: .4;
  cursor: not-allowed;
}

.btn-row {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
  margin-top: 32px;
}

/* A quiet text link with a rule under it, used for "more about" style links. */
.link-more {
  display: inline-block;
  margin-top: 26px;
  padding-bottom: 4px;
  border-bottom: 1px solid var(--ink);
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  text-decoration: none;
  transition: opacity .25s linear;
}

.link-more:hover { opacity: .6; }

/* -------------------------------------------------------------- navigation */
/* [CHECKLIST 2.1] Flex, never `1fr auto 1fr` with no gap: that collapses the
   bar into a squeezed cluster the moment the link set grows. */
.nav {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 100;
  background: transparent;
  border-bottom: 1px solid transparent;
  /* Background only. No shrink, no hide on scroll, no blur. */
  transition: background-color .35s var(--ease), border-color .35s var(--ease);
}

/* ROUND 3 PART 3: the bar runs the full viewport width. The lockup sits about
   24px from the left edge and the CTA about 24px from the right edge at
   desktop widths, with the links keeping a clear gap from the button. */
/* ROUND 5 PART 3: three zone grid, links genuinely centered in the viewport.
   THE RISE HOLLYWOOD HILLS TRAP LIVES HERE: below the burger breakpoint the
   links and the CTA are display:none, which removes them from the grid, so
   the burger falls into the middle column and renders dead centre. The mobile
   media query MUST redeclare the grid; it does, below. */
.nav-inner {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  width: 100%;
  min-height: var(--nav-h);
  margin: 0 auto;
  padding: 0 24px;
}
.nav-inner > .wordmark { justify-self: start; }
.nav-inner > .nav-links { justify-self: center; }
.nav-inner > .nav-cta { justify-self: end; }

/* [CHECKLIST 2.1] Solid cream with a hairline once scrolled past the hero. */
.nav.is-solid {
  background: var(--cream);
  border-bottom-color: var(--line);
}

/* [CHECKLIST 2.2] While the mobile menu is open the bar keeps a solid
   background whatever the scroll position, or the close X sits on a
   transparent bar over a light panel and disappears. */
body.menu-open .nav {
  background: var(--cream);
  border-bottom-color: var(--line);
}

/* The wordmark IS the brand: there is no logo file. Built as markup with one
   class so swapping in a real logo later is a single change. */
.wordmark {
  display: block;
  text-decoration: none;
  color: var(--ink);
  line-height: 1;
  /* ROUND 4 PART 1.3: the bar's flex gap is 32px; this margin adds to it, so
     the lockup never sits closer than 56px to ABOUT when the bar is tight. */
  margin-right: 24px;
}

/* ROUND 3 PART 3 grew the lockup to 24px. ROUND 4 PART 1.4 then took the
   subline to 9px/.24em: at 13px it alone was 272px wide and set the whole
   bar's width budget. The 24px wordmark stays. This is the ONE deliberate
   exception to the Round 3 "nothing below 13px" floor, ordered in Round 4. */
.wordmark-name {
  display: block;
  font-family: var(--display);
  font-weight: 300;
  font-size: 24px;
  letter-spacing: .18em;
  text-transform: uppercase;
  white-space: nowrap;
}

.wordmark-sub {
  display: block;
  margin-top: 5px;
  font-family: var(--body);
  font-size: 9px;
  font-weight: 400;
  letter-spacing: .24em;
  text-transform: uppercase;
  color: var(--ink-soft);
  white-space: nowrap;
}

/* Over the hero photograph, before the bar goes solid.

   [CHECKLIST 2.2] The `body:not(.menu-open)` guard is load-bearing, not tidiness.
   Opening the mobile menu at the TOP of the page makes the bar solid cream while
   the nav still has no `.is-solid` class, so without this guard the wordmark and
   the burger stayed white and vanished into the bar. It is the same defect the
   checklist calls out for the close X, one element over. */
body:not(.menu-open) .nav:not(.is-solid) .wordmark { color: #fff; }
body:not(.menu-open) .nav:not(.is-solid) .wordmark-sub { color: rgba(255, 255, 255, .8); }
body:not(.menu-open) .nav:not(.is-solid) .nav-link { color: #fff; }
body:not(.menu-open) .nav:not(.is-solid) .nav-link::after { background: #fff; }
body:not(.menu-open) .nav:not(.is-solid) .nav-cta .btn { border-color: rgba(255, 255, 255, .85); color: #fff; }
body:not(.menu-open) .nav:not(.is-solid) .nav-cta .btn:hover { background: #fff; color: var(--ink); }
body:not(.menu-open) .nav:not(.is-solid) .nav-burger { color: #fff; }

/* A page with no hero photograph behind the bar starts solid, so the bar is
   never white text on a cream page. Set on <body> per page. */
body.nav-solid .nav {
  background: var(--cream);
  border-bottom-color: var(--line);
}

.nav-links {
  display: flex;
  align-items: center;
  gap: 28px;
}

.nav-link {
  position: relative;
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 1.2px;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--ink);
  padding: 6px 0;
  /* ROUND 4 PART 1.2: a squeezed bar folds "HOME SEARCH" at the space instead
     of holding the line. No nav element ever renders on two lines. */
  white-space: nowrap;
}

.nav-link::after {
  content: '';
  position: absolute;
  left: 0;
  bottom: 0;
  width: 0;
  height: 1px;
  background: var(--ink);
  transition: width .3s var(--ease);
}

.nav-link:hover::after,
.nav-link.is-current::after { width: 100%; }

.nav-cta { margin-left: 0; }

.nav-cta .btn {
  padding: 13px 22px;
  font-size: 13px;
}

.nav-burger {
  display: none;
  margin-left: auto;
  padding: 8px;
  border: 0;
  background: none;
  color: var(--ink);
  cursor: pointer;
}

/* [CHECKLIST 2.1] Switch to the mobile menu at 1230px, per the Round 4
   PART 1.5 fallback. Measured after the Round 4 type reductions: the bar
   needs 1196px of viewport to hold one line, so a 1150px breakpoint left a
   1151-1196 band where the nowrap links could only collide. Any future nav
   change re-derives this number: sum the lockup, the links, the gaps and the
   CTA, add the bar padding, and keep the breakpoint above it. */
@media (max-width: 1230px) {
  .nav-links,
  .nav-cta { display: none; }
  .nav-burger { display: block; justify-self: end; }
  /* Redeclared, not inherited: with links and CTA out of the grid the burger
     would land in the centre column. minmax(0,1fr) + end pins it hard right. */
  .nav-inner { grid-template-columns: minmax(0, 1fr) auto; padding: 0 24px; }
}

@media (max-width: 560px) {
  :root { --nav-h: 78px; }
  .nav-inner { padding: 0 20px; }
  .wordmark-name { font-size: 20px; letter-spacing: .14em; }
}

/* ------------------------------------------------------------ mobile panel */
/* [CHECKLIST 2.2] No Home item: the wordmark is the home link. No scrolling,
   shrinking or zoom animations inside the panel. */
.mobile-panel {
  position: fixed;
  inset: 0;
  z-index: 99;
  display: none;
  flex-direction: column;
  gap: 6px;
  background: var(--cream);
  /* [CHECKLIST 2.2] Reserve the fixed bar's height so no item can sit behind
     it on a 667px tall phone. */
  padding: calc(var(--nav-h) + 40px) 28px 40px;
  overflow-y: auto;
}

.mobile-panel.is-open { display: flex; }

.mobile-panel a {
  padding: 14px 0;
  border-bottom: 1px solid var(--line);
  font-family: var(--display);
  font-size: 22px;
  font-weight: 300;
  letter-spacing: .05em;
  text-transform: uppercase;
  text-decoration: none;
}

/* ROUND 6 PART 2: the seller call to action, built to the note's end state.
   `.mobile-panel a` above matches EVERY anchor in the panel, the button
   included, so it was rendering as a 22px display-serif slab that ran past the
   panel's own padding. Every inherited property is restored to the site's
   button here, and the rule that separates it from the links is CONTACT's own
   bottom hairline, 20px above: a second border would read as a double line. */
.mobile-panel .btn {
  margin-top: 20px;
  align-self: stretch;
  min-height: 48px;
  /* The label is centred in a full-width box, so this padding is never SEEN: it
     is the minimum inset before a nowrap label would spill. 24px left only 10px
     of slack at 320px, which a failed webfont would eat. */
  padding: 14px 16px;
  border: 1px solid var(--ink);
  background: var(--ink);
  color: var(--cream);
  font-family: var(--body);
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 1.4px;
  text-align: center;
  white-space: nowrap;
}

/* [CHECKLIST 2.2] The burger swaps to a close X while the panel is open, and
   the guard above keeps it dark against the light panel. */
.nav-burger .i-close { display: none; }
body.menu-open .nav-burger .i-open { display: none; }
body.menu-open .nav-burger .i-close { display: block; }

/* ------------------------------------------------------------------- hero */
.hero {
  position: relative;
  display: flex;
  align-items: center;
  /* [CHECKLIST 2.4] 100dvh, NOT 100svh. svh leaves the next section bleeding
     in under the collapsed browser chrome on a phone. */
  min-height: 100dvh;
  padding: calc(var(--nav-h) + 40px) 0 var(--gap-section);
  overflow: hidden;
}

.hero-media {
  position: absolute;
  inset: 0;
}

/* ROUND 6 PART 1: <picture> is an inline wrapper with no box of its own, so it
   is given the media box explicitly. Without this the img sizes itself against
   the inline parent and the hero photograph collapses. */
.hero-media picture {
  display: block;
  width: 100%;
  height: 100%;
}

.hero-media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* [CHECKLIST 2.4] The site is light, so the scrim stays light: roughly .30 to
   .45, only as strong as the text needs. The middle stop sat at .22 in the
   first build and the sub-line disappeared into the sunlit wall of the hero
   photograph, so it is back inside the specified range. */
.hero-media::after {
  content: '';
  position: absolute;
  inset: 0;
  background:
    linear-gradient(to bottom,
      rgba(var(--scrim), .40) 0%,
      rgba(var(--scrim), .34) 45%,
      rgba(var(--scrim), .46) 100%);
}

.hero .wrap {
  position: relative;
  z-index: 1;
  text-align: center;
}

/* ROUND 5 PART 8.2: the timelapse loop. Injected by site.js ONLY on wide
   screens with motion allowed, so phones never download the file; the scrim
   (.hero-media::after) has z-index 0 context above siblings in source order,
   so the video is inserted BEFORE the img and covers the same box. */
.hero-video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* ROUND 6 PART 1.3: anchor the portrait's lower frame, so the home sits under
   the text and the sky stays clear above it. On a tall phone the portrait is
   proportionally WIDER than the viewport, so cover crops the sides and shows
   full height: this rule does its work in the 600 to 860px band, where the
   viewport is short enough for the crop to turn vertical. */
@media (max-width: 860px) {
  .hero-media img { object-position: center 62%; }
  /* ROUND 6 PART 1, acceptance 2: "the wordmark and subline sit in clean sky".
     The portrait is composed with the home in the lower two thirds, so the
     centred desktop placement drops the name onto the treeline. On a phone the
     block moves to the top of the frame, where the sky is. Desktop keeps the
     landscape photograph and its centred text, untouched. */
  .hero { align-items: flex-start; }
}

/* The hero name treatment: the same wordmark at display scale, spanning the
   hero. This is what makes a name work as a brand without a logo. */
.hero-name {
  font-family: var(--display);
  font-weight: 300;
  /* ROUND 5 PART 2.1: bigger again (supersedes Round 4's 42-66 clamp) and
     never wraps, at any width. The 44px floor is Brett's number; verify the
     name holds one line at 390 with the letterspacing below. */
  font-size: clamp(44px, 6vw, 76px);
  white-space: nowrap;
  letter-spacing: .12em;
  line-height: 1.05;
  text-transform: uppercase;
  color: #fff;
  margin: 0;
}

/* ROUND 5 PART 2.2: back to the letterspaced caps subline (supersedes Round
   4's serif italic lede, which lasted one day). Both axes are clamps because
   at a fixed wide letterspacing this 31 character line is the real wrap risk
   at 390px; nowrap makes any overshoot visible instead of folding. */
.hero-sub {
  margin-top: 22px;
  font-size: clamp(11px, 1.3vw, 16px);
  font-weight: 400;
  letter-spacing: clamp(2px, .28vw, 4px);
  text-transform: uppercase;
  white-space: nowrap;
  color: rgba(255, 255, 255, .9);
}

.hero .btn-row { justify-content: center; margin-top: 44px; }

/* [CHECKLIST 2.4] Any scroll cue hides at 860px. */
.scroll-cue {
  position: absolute;
  left: 50%;
  bottom: 34px;
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  z-index: 1;
  font-size: 13px;
  letter-spacing: .26em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, .85);
}

.scroll-cue .line {
  width: 1px;
  height: 46px;
  background: linear-gradient(to bottom, rgba(255, 255, 255, .9), rgba(255, 255, 255, 0));
}

@media (max-width: 860px) {
  .scroll-cue { display: none; }
}

/* ------------------------------------------------------------ page headers */
/* [CHECKLIST 2.4] 44svh with padding-top just clearing the nav and modest
   bottom padding. Never 60vh with flex-end plus 120px top padding: that leaves
   a dead band above the heading on a phone. */
.page-header {
  position: relative;
  display: flex;
  align-items: flex-end;
  min-height: 44svh;
  padding-top: 104px;
  padding-bottom: 52px;
  overflow: hidden;
}

.page-header .hero-media::after {
  background: linear-gradient(to bottom,
    rgba(var(--scrim), .34) 0%,
    rgba(var(--scrim), .26) 50%,
    rgba(var(--scrim), .44) 100%);
}

/* ROUND 3 PART 6.1: ONE shared inner block, so the header text sits at the
   same position on every page. Identical left padding (the .wrap), identical
   bottom padding (the section), and the eyebrow, H1 and lede in the same
   vertical rhythm. No per page overrides. */
.page-header .wrap,
.pagehead-inner {
  position: relative;
  z-index: 1;
}

.page-header .eyebrow {
  color: rgba(255, 255, 255, .82);
  /* ROUND 4 PART 2.4: hero eyebrows 13px. */
  font-size: 13px;
  letter-spacing: 2px;
  margin-bottom: 16px;
}

.page-header .display { color: #fff; }

.page-header .lede {
  color: rgba(255, 255, 255, .92);
  margin-top: 18px;
  /* ROUND 4 PART 2.3: header ledes are 18px flat, capped at 52ch. The body
     .lede clamp (17-20px) stays untouched everywhere else. */
  font-size: 18px;
  max-width: 52ch;
  /* ROUND 5 PART 7: contact's header text sat 30px lower than every other
     page. There was NO per page override; the header bottom-anchors its text,
     so a ONE line lede (contact) hangs the whole block one line lower than a
     two line one (about, buyers). Reserving two lines makes the eyebrow, the
     H1 and the lede land at the same Y on every page. */
  min-height: calc(2 * 1.65em);
}

/* ROUND 3 PART 6.3: the contact header keeps its image with the framing
   raised, so the subject sits higher in the crop. */
.page-header-raised .hero-media img { object-position: center 30%; }

/* ROUND 4 PART 3.1: the sellers header (the white oak kitchen) frames a touch
   above centre so the counters and the window sit well in the crop. */
.page-header-mid .hero-media img { object-position: center 45%; }

@media (max-width: 560px) {
  .page-header { padding-top: 96px; padding-bottom: 40px; }
}

/* ---------------------------------------------------------------- sections */
.section {
  padding: var(--gap-section) 0;
}

.section-tight { padding: var(--gap-tight) 0; }

.section-cream { background: var(--cream); }
.section-paper { background: var(--paper); }
.section-sand { background: var(--sand); }

/* ROUND 3 PART 1: the deep slate band is GONE. The county band now sits on
   .section-sand with ink text, same layout, warm instead of blue. The site has
   no dark section at all any more, and no .section-dark class either, so a new
   one cannot be reached for by habit. */

/* Two sand moments can now sit adjacent, the county band and the closing CTA.
   A hairline keeps them reading as two sections rather than one long band. */
/* ROUND 5 PART 4: the homepage county band went white, so no section-sand
   sits against the sand cta-band any more and the old hairline rule is gone. */


.section-head {
  max-width: 720px;
  margin-bottom: 48px;
}

/* ROUND 3 PART 4.1: centred section heads breathe at 880px. */
.section-head.is-centred {
  max-width: 880px;
  margin-left: auto;
  margin-right: auto;
  text-align: center;
}

.section-head .lede { margin-top: 18px; }

.section-head.is-centred .lede { margin-left: auto; margin-right: auto; }

.rule {
  height: 1px;
  background: var(--line);
  border: 0;
  margin: 0;
}

/* ROUND 3 PART 4.2: the standalone intro strip is REMOVED. Its sentence folded
   into the About preview lede on the homepage. */

/* ----------------------------------------------------------- numbers band */
.stats {
  display: grid;
  gap: 40px;
  grid-template-columns: repeat(4, 1fr);
  padding: var(--gap-section) 0;
}

.stats-3 { grid-template-columns: repeat(3, 1fr); }

.stat {
  position: relative;
  text-align: center;
  /* [CHECKLIST 2.5] A grid cell must be allowed to shrink. */
  min-width: 0;
}

/* Thin vertical hairlines between stats on desktop, hidden on mobile. */
.stat + .stat::before {
  content: '';
  position: absolute;
  left: -20px;
  top: 8%;
  bottom: 8%;
  width: 1px;
  background: var(--line);
}

.stat-value {
  font-family: var(--display);
  font-weight: 300;
  font-size: clamp(40px, 5.5vw, 76px);
  line-height: 1;
  color: var(--ink);
}

.stat-label {
  margin-top: 14px;
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 1.6px;
  text-transform: uppercase;
  color: var(--ink-soft);
}

@media (max-width: 860px) {
  .stats,
  .stats-3 {
    grid-template-columns: repeat(2, 1fr);
    gap: 44px 24px;
    padding: var(--gap-section) 0;
  }
  .stat + .stat::before { display: none; }
}

@media (max-width: 460px) {
  .stats,
  .stats-3 { grid-template-columns: 1fr; }
}

/* ----------------------------------------------------- split image + text */
.split {
  display: grid;
  grid-template-columns: 1fr 1fr;
  align-items: center;
  gap: 72px;
}

.split-body { min-width: 0; }

.split-media { min-width: 0; }

.split-media img {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
}

/* ROUND 4 PART 3.2: the home value form image (the curb appeal home) sits at
   plain centre. */
.value-split-media img { object-position: center; }

/* [CHECKLIST 2.6] No z-index:-1 decorative frames anywhere. They break inside
   any ancestor with a transform, and the reveal animation creates one. */

@media (max-width: 1024px) {
  .split { gap: 44px; }
}

/* [CHECKLIST 2.6] On mobile, text ALWAYS stacks above its photo. Set order
   explicitly on both children, including in reversed splits: DOM order puts
   the photo first there, and relying on the default would leave two photos
   touching where two splits meet. */
@media (max-width: 860px) {
  .split {
    grid-template-columns: 1fr;
    gap: 32px;
  }
  .split .split-body { order: 1; }
  .split .split-media { order: 2; }
}

/* ------------------------------------------------------------ listing grid */
.listing-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 32px;
}

@media (max-width: 1024px) {
  .listing-grid { grid-template-columns: repeat(2, 1fr); }
}

@media (max-width: 640px) {
  .listing-grid { grid-template-columns: 1fr; }
}

.listing-card {
  display: block;
  min-width: 0;
  background: var(--paper);
  border: 1px solid var(--line);
  text-decoration: none;
  color: var(--ink);
  transition: border-color .35s var(--ease);
}

.listing-card:hover { border-color: var(--ink); }

.listing-media {
  position: relative;
  aspect-ratio: 4 / 3;
  background: var(--sand);
  overflow: hidden;
}

.listing-media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform .6s var(--ease);
}

.listing-card:hover .listing-media img { transform: scale(1.04); }

.listing-status {
  position: absolute;
  left: 0;
  top: 0;
  padding: 8px 14px;
  background: rgba(var(--scrim), .72);
  color: #fff;
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 1.4px;
  text-transform: uppercase;
}

.listing-body { padding: 22px 24px 26px; }

.listing-price {
  font-family: var(--display);
  font-weight: 300;
  font-size: 24px;
  letter-spacing: .02em;
}

.listing-addr {
  margin-top: 8px;
  font-size: 15px;
  line-height: 1.45;
}

.listing-sub {
  margin-top: 4px;
  font-size: 13px;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--ink-soft);
}

.listing-specs {
  display: flex;
  flex-wrap: wrap;
  gap: 18px;
  margin-top: 18px;
  padding-top: 16px;
  border-top: 1px solid var(--line);
  font-size: 13px;
  letter-spacing: 1.1px;
  text-transform: uppercase;
  color: var(--ink-soft);
}

.listing-specs b {
  font-weight: 500;
  color: var(--ink);
}

.listing-empty,
.listing-loading {
  padding: 56px 0;
  text-align: center;
  color: var(--ink-soft);
}

.pager {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 18px;
  margin-top: 48px;
}

.pager-info {
  font-size: 13px;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: var(--ink-soft);
}

/* The IDX line the shared MLS pool requires. Small, but never hidden. */
.idx-note {
  margin-top: 36px;
  font-size: 13px;
  line-height: 1.7;
  color: var(--ink-faint);
  max-width: 90ch;
}

/* ------------------------------------------------------------ neighborhoods */
.hood-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 28px;
}

@media (max-width: 1024px) {
  .hood-grid { grid-template-columns: repeat(2, 1fr); }
}

@media (max-width: 560px) {
  .hood-grid { grid-template-columns: 1fr; }
}

.hood {
  min-width: 0;
}

.hood-media {
  aspect-ratio: 4 / 3;
  overflow: hidden;
}

.hood-media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Hover scales the photo. No grayscale, ever. */
  transition: transform .6s var(--ease);
}

.hood:hover .hood-media img { transform: scale(1.04); }

/* ROUND 3 PART 1.1: the band is warm now, so the cards read in ink. */
.hood-label {
  margin-top: 18px;
  font-family: var(--display);
  font-weight: 300;
  font-size: 18px;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--ink);
}

.hood-line {
  margin-top: 8px;
  font-size: 14px;
  line-height: 1.6;
  color: var(--ink-soft);
}

/* ROUND 2 PART 6.6: the band carries THREE county cards, not four neighborhood
   cards. Declared after the base rules above so the cascade resolves to three,
   then to two and one at the same breakpoints the four column grid uses. */
.hood-grid-3 { grid-template-columns: repeat(3, 1fr); }

@media (max-width: 1024px) {
  .hood-grid-3 { grid-template-columns: repeat(2, 1fr); }
}

@media (max-width: 560px) {
  .hood-grid-3 { grid-template-columns: 1fr; }
}

/* ROUND 2 PART 5. An in page anchor has to clear the fixed nav, or the heading
   it points at lands underneath the bar. This matters now that the persistent
   "What is my home worth" button in the nav is itself an anchor link. */
[id] { scroll-margin-top: calc(var(--nav-h) + 16px); }

/* The alias that keeps the old /sellers/#valuation link working after the
   section was renamed. It draws nothing and is only a scroll target. */
.anchor-alias {
  display: block;
  height: 0;
}

/* One quiet line under a form, PART 5.4. */
.form-note {
  margin-top: 22px;
  font-size: 15px;
  line-height: 1.65;
  color: var(--ink-soft);
}

/* ----------------------------------------------------------- who she helps */
/* ROUND 2 PART 7. NO BOXES, by instruction: three columns of type on cream.
   Each column is an Inter label over a hairline, then serif items with one
   quiet line under each. The columns collapse to a single stack in the same
   source order on a phone, so the reading order never changes. */
.helps-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 44px;
}

@media (max-width: 900px) {
  .helps-grid {
    grid-template-columns: 1fr;
    gap: 40px;
  }
}

.helps-col { min-width: 0; }

/* ROUND 3 PART 4.3: the full elevation treatment. Column labels carry a 40px
   accent rule above them, each item is a row over a hairline, and the hover
   animates the row's rule to full black while the name eases 6px right. The
   rows themselves carry data-reveal, so they stagger in on scroll. */
.helps-head {
  font-family: var(--body);
  font-size: 13.5px;
  font-weight: 500;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--ink-soft);
  padding-bottom: 14px;
}

.helps-head::before {
  content: '';
  display: block;
  width: 40px;
  height: 2px;
  background: var(--ink);
  margin-bottom: 16px;
}

.helps-list { list-style: none; }

.helps-list li {
  position: relative;
  padding: 20px 0 22px;
  border-bottom: 1px solid var(--line);
}

/* The animated rule sits on the hairline and grows to full width on hover. */
.helps-list li::after {
  content: '';
  position: absolute;
  left: 0;
  bottom: -1px;
  width: 0;
  height: 1px;
  background: var(--ink);
  transition: width .3s var(--ease);
}

.helps-list li:hover::after { width: 100%; }

.helps-item {
  display: block;
  font-family: var(--display);
  font-weight: 300;
  font-size: 24px;
  line-height: 1.3;
  color: var(--ink);
  transition: transform .3s var(--ease);
}

.helps-list li:hover .helps-item { transform: translateX(6px); }

.helps-note {
  display: block;
  margin-top: 7px;
  font-family: var(--display);
  font-style: italic;
  font-weight: 400;
  font-size: 17px;
  line-height: 1.55;
  color: var(--ink-soft);
}

/* ------------------------------------------------------------ testimonials */
.reviews {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 32px;
}

@media (max-width: 860px) {
  .reviews { grid-template-columns: 1fr; }
}

.review {
  min-width: 0;
  padding: 36px 34px;
  background: var(--paper);
  border: 1px solid var(--line);
}

.review-quote {
  font-size: 18px;
  line-height: 1.65;
  color: var(--ink);
}

.review-by {
  margin-top: 22px;
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: var(--ink-soft);
}

.review-source {
  margin-top: 14px;
  font-size: 13px;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: var(--ink-faint);
}

/* ------------------------------------------------------------- blog cards */
.post-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 32px;
}

@media (max-width: 1024px) {
  .post-grid { grid-template-columns: repeat(2, 1fr); }
}

@media (max-width: 640px) {
  .post-grid { grid-template-columns: 1fr; }
}

.post-card {
  display: block;
  min-width: 0;
  text-decoration: none;
  color: var(--ink);
}

.post-media {
  aspect-ratio: 3 / 2;
  background: var(--sand);
  overflow: hidden;
}

.post-media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform .6s var(--ease);
}

.post-card:hover .post-media img { transform: scale(1.04); }

.post-date {
  margin-top: 20px;
  font-size: 13px;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.post-title {
  margin-top: 10px;
  font-family: var(--display);
  font-weight: 300;
  font-size: 20px;
  letter-spacing: .04em;
  text-transform: uppercase;
  line-height: 1.3;
}

.post-excerpt {
  margin-top: 12px;
  font-size: 16px;
  line-height: 1.6;
  color: var(--ink-soft);
}

/* ------------------------------------------------------------ process steps */
.steps {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 28px;
}

@media (max-width: 1024px) {
  .steps { grid-template-columns: repeat(2, 1fr); }
}

@media (max-width: 640px) {
  .steps { grid-template-columns: 1fr; }
}

/* ROUND 3 PART 7.3: the process boxes get motion. Hover lifts the card 4px
   with a soft shadow and the step number eases from soft to full ink, all at
   250ms. Nothing spins, nothing bounces. The reveal stagger comes from
   data-reveal in site.js. */
.step {
  min-width: 0;
  padding: 34px 30px 36px;
  background: var(--paper);
  border: 1px solid var(--line);
  transition: border-color .25s var(--ease), transform .25s var(--ease),
              box-shadow .25s var(--ease);
}

.step:hover {
  border-color: var(--ink);
  transform: translateY(-4px);
  box-shadow: 0 14px 30px rgba(var(--scrim), .10);
}

.step-n {
  font-family: var(--display);
  font-weight: 300;
  font-size: 40px;
  line-height: 1;
  color: var(--ink-soft);
  transition: color .25s var(--ease);
}

.step:hover .step-n { color: var(--ink); }

.step-title {
  margin-top: 18px;
  font-family: var(--display);
  font-weight: 300;
  font-size: 19px;
  letter-spacing: .06em;
  text-transform: uppercase;
}

.step-body {
  margin-top: 12px;
  font-size: 16px;
  line-height: 1.65;
  color: var(--ink-soft);
}

/* ---------------------------------------------------------------- vendors */
.vendor-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 40px 32px;
}

@media (max-width: 1024px) {
  .vendor-grid { grid-template-columns: repeat(2, 1fr); }
}

@media (max-width: 640px) {
  .vendor-grid { grid-template-columns: 1fr; }
}

.vendor-trade { min-width: 0; }

.vendor-trade h3 {
  padding-bottom: 12px;
  border-bottom: 1px solid var(--line);
  font-family: var(--display);
  font-weight: 300;
  font-size: 15px;
  letter-spacing: .1em;
  text-transform: uppercase;
}

.vendor-list {
  list-style: none;
  margin-top: 16px;
}

.vendor-list li + li { margin-top: 14px; }

.vendor-name {
  font-size: 15px;
  font-weight: 500;
}

.vendor-meta {
  margin-top: 3px;
  font-size: 13px;
  color: var(--ink-soft);
}

.vendor-meta a { text-decoration: none; border-bottom: 1px solid var(--line); }

.vendor-note {
  margin-top: 44px;
  font-size: 13px;
  line-height: 1.7;
  color: var(--ink-faint);
  max-width: 80ch;
}

/* ------------------------------------------------------------------ forms */
/* [CHECKLIST 2.5] Every grid field gets min-width:0 and every control gets
   width:100%. Without both, the columns refuse to shrink and the form
   overflows the phone sideways. */
.form {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 22px;
  max-width: 900px;
}

.form-field {
  display: flex;
  flex-direction: column;
  gap: 8px;
  min-width: 0;
}

.form-field.is-wide { grid-column: 1 / -1; }

/* A form that sits inside a half-width split has about 580px to work with, and
   three columns of that leaves an email field 170px wide. Two columns is the
   right density there. */
.form.is-narrow { grid-template-columns: repeat(2, 1fr); }

.form-field label {
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: var(--ink-soft);
}

.form input,
.form select,
.form textarea {
  width: 100%;
  min-width: 0;
  padding: 14px 16px;
  border: 1px solid var(--line);
  border-radius: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--body);
  font-size: 15px;
  transition: border-color .3s var(--ease);
}

.form input:focus,
.form select:focus,
.form textarea:focus {
  border-color: var(--ink);
  outline: none;
}

.form textarea {
  min-height: 132px;
  resize: vertical;
}

/* [CHECKLIST 2.5] The submit gets its own auto-sized cell, never crammed into
   a field column. */
.form-actions {
  grid-column: 1 / -1;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 18px;
}

.form-consent {
  grid-column: 1 / -1;
  display: flex;
  gap: 12px;
  align-items: flex-start;
  font-size: 13px;
  line-height: 1.6;
  color: var(--ink-soft);
}

.form-consent input {
  width: 18px;
  height: 18px;
  flex: 0 0 auto;
  margin-top: 3px;
  padding: 0;
}

.form-check {
  grid-column: 1 / -1;
  display: flex;
  gap: 12px;
  align-items: center;
  font-size: 14px;
  color: var(--ink-soft);
}

.form-check input {
  width: 18px;
  height: 18px;
  flex: 0 0 auto;
  padding: 0;
}

/* The honeypot. Off screen rather than display:none, which some bots skip. */
.hp-field {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

.form-status {
  grid-column: 1 / -1;
  display: none;
  padding: 14px 16px;
  border: 1px solid var(--line);
  background: var(--paper);
  font-size: 14px;
}

.form-status.is-shown { display: block; }
.form-status.ok { border-color: var(--ink); }
.form-status.err { border-color: #B4402F; color: #B4402F; }

/* [CHECKLIST 2.5] 2 columns at 860px, 1 column at 560px. The .is-narrow
   variant is included EXPLICITLY at 560: its two-class selector outranks the
   plain .form rule, so without this line a narrow form stays two-column on a
   320px phone and overflows. */
@media (max-width: 860px) {
  .form { grid-template-columns: repeat(2, 1fr); }
}

@media (max-width: 560px) {
  .form,
  .form.is-narrow { grid-template-columns: 1fr; }
}

/* -------------------------------------------------------- search filters */
.filters {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 16px;
  align-items: end;
  margin-bottom: 44px;
}

.filters .form-field { min-width: 0; }

.filters input,
.filters select {
  width: 100%;
  min-width: 0;
  padding: 13px 14px;
  border: 1px solid var(--line);
  border-radius: 0;
  background: var(--paper);
  font-family: var(--body);
  font-size: 14px;
}

/* [CHECKLIST 2.5] The buttons get their own auto-sized row, never crammed into
   a field column where they would squeeze the selects beside them. */
.filters-actions {
  grid-column: 1 / -1;
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  min-width: 0;
}

@media (max-width: 1024px) {
  .filters { grid-template-columns: repeat(2, 1fr); }
}

@media (max-width: 560px) {
  .filters { grid-template-columns: 1fr; }
}

/* ------------------------------------------------------- mortgage calculator */
.calc {
  display: grid;
  grid-template-columns: 1.15fr 1fr;
  gap: 56px;
  align-items: start;
}

@media (max-width: 1024px) {
  .calc { grid-template-columns: 1fr; gap: 40px; }
}

.calc-inputs {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 20px;
}

@media (max-width: 560px) {
  .calc-inputs { grid-template-columns: 1fr; }
}

.calc-result {
  padding: 38px 34px;
  background: var(--paper);
  border: 1px solid var(--line);
}

.calc-total {
  font-family: var(--display);
  font-weight: 300;
  font-size: clamp(34px, 4.4vw, 52px);
  line-height: 1;
}

.calc-total-label {
  margin-top: 12px;
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 1.6px;
  text-transform: uppercase;
  color: var(--ink-soft);
}

.calc-rows {
  margin-top: 30px;
  padding-top: 22px;
  border-top: 1px solid var(--line);
}

.calc-row {
  display: flex;
  justify-content: space-between;
  gap: 16px;
  padding: 9px 0;
  font-size: 14px;
  color: var(--ink-soft);
}

.calc-row b {
  font-weight: 500;
  color: var(--ink);
}

.calc-note {
  margin-top: 28px;
  font-size: 13px;
  line-height: 1.7;
  color: var(--ink-faint);
  max-width: 80ch;
}

/* ---------------------------------------------------------------- homebot */
/* The embed is a third-party iframe. It is bounded here so it can never blow
   out the page width on a phone. */
.embed-frame {
  width: 100%;
  max-width: 100%;
  min-width: 0;
  overflow: hidden;
  background: var(--paper);
  border: 1px solid var(--line);
  padding: 28px;
}

.embed-frame iframe {
  width: 100%;
  max-width: 100%;
  border: 0;
  display: block;
}

.embed-placeholder {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 14px;
  padding: 52px 34px;
  text-align: left;
}

/* -------------------------------------------------------------- CTA band */
/* PART 6: the closing band carries NO photograph. One image per slot and no
   reuse, so on a light editorial site a flat beige band reads as more
   confident than a repeated photo. */
.cta-band {
  background: var(--sand);
  padding: var(--gap-section) 0;
  text-align: center;
}

.cta-band .btn-row { justify-content: center; }

/* ----------------------------------------------------------------- footer */
/* ROUND 3 PART 1.2: the footer is warm. Sand background, ink text, hairline
   rules, and the wordmark stays black. */
.footer {
  background: var(--sand);
  color: var(--ink-soft);
  padding: 76px 0 30px;
}

.footer-top {
  display: grid;
  grid-template-columns: 1.4fr 1fr 1fr;
  gap: 48px;
  padding-bottom: 44px;
  border-bottom: 1px solid var(--line);
}

@media (max-width: 860px) {
  .footer-top { grid-template-columns: 1fr; gap: 36px; }
}

.footer-col { min-width: 0; }

.footer .wordmark-name { color: var(--ink); font-size: 22px; }
.footer .wordmark-sub { color: var(--ink-soft); }

.footer-tag {
  margin-top: 16px;
  font-size: 14px;
  line-height: 1.7;
  color: var(--ink-soft);
  max-width: 42ch;
}

.footer-head {
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 1.6px;
  text-transform: uppercase;
  color: var(--ink);
  margin-bottom: 18px;
}

.footer-nav {
  display: flex;
  flex-direction: column;
  gap: 11px;
}

.footer-nav a {
  font-size: 14px;
  text-decoration: none;
  color: var(--ink-soft);
  transition: color .25s linear;
}

.footer-nav a:hover { color: var(--ink); }

.footer-contact {
  font-style: normal;
  font-size: 14px;
  line-height: 1.9;
  color: var(--ink-soft);
}

.footer-contact a {
  text-decoration: none;
  border-bottom: 1px solid rgba(0, 0, 0, .3);
}

.socials {
  display: flex;
  gap: 14px;
  margin-top: 20px;
}

.socials a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  border: 1px solid rgba(0, 0, 0, .28);
  color: var(--ink);
  transition: background-color .3s var(--ease), color .3s var(--ease);
}

.socials a:hover { background: var(--ink); color: var(--paper); }

.footer-legal {
  padding: 26px 0;
  border-bottom: 1px solid var(--line);
  font-size: 13px;
  line-height: 1.8;
  color: var(--ink-soft);
}

.footer-bottom {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px 22px;
  padding-top: 26px;
  font-size: 13px;
  color: var(--ink-soft);
}

.footer-bottom a {
  text-decoration: none;
  color: var(--ink-soft);
}

.footer-bottom a:hover { color: var(--ink); }

.footer-bottom .spacer { flex: 1 1 auto; }

.eho {
  display: inline-flex;
  align-items: center;
  gap: 7px;
}

/* ------------------------------------------------------- confirm markers */
/* Nothing the client has not supplied is invented. Every outstanding value
   from PART 8 renders as one of these instead of a plausible-looking number. */
.confirm {
  display: inline-block;
  padding: 2px 8px;
  border: 1px dashed currentColor;
  font-family: var(--body);
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: #8A6D1F;
  /* Deliberately NOT nowrap. That suits a two-word chip and is catastrophic
     for a sentence: one long inline chip pushed a previous build's document to
     691px on a 390px phone. Long text goes in .confirm-block. */
  white-space: normal;
}

.confirm-block {
  display: block;
  padding: 14px 16px;
  border: 1px dashed rgba(138, 109, 31, .55);
  background: rgba(138, 109, 31, .05);
  font-size: 13px;
  line-height: 1.65;
  color: #8A6D1F;
}

/* ----------------------------------------------- calculator tabs, ROUND 3 */
/* PART 7.2: one component pattern across the three calculators. The tabs are
   real buttons with aria-selected, keyboard reachable, and the active tab
   carries a 2px black underline. Zero third party chrome. */
.calc-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 28px;
  margin-bottom: 40px;
  border-bottom: 1px solid var(--line);
}

.calc-tab {
  position: relative;
  padding: 12px 2px 14px;
  border: 0;
  background: none;
  cursor: pointer;
  font-size: 13.5px;
  font-weight: 500;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: var(--ink-soft);
  transition: color .25s var(--ease);
}

.calc-tab::after {
  content: '';
  position: absolute;
  left: 0;
  bottom: -1px;
  width: 100%;
  height: 2px;
  background: transparent;
  transition: background-color .25s var(--ease);
}

.calc-tab[aria-selected="true"] {
  color: var(--ink);
}

.calc-tab[aria-selected="true"]::after { background: var(--ink); }

.calc-panel[hidden] { display: none; }

/* A helper note under an input, the "what counts as monthly debts" line. */
.field-help {
  font-size: 13px;
  line-height: 1.55;
  color: var(--ink-faint);
}

/* The one sentence answer a calculator leads with. */
.calc-sentence {
  margin-top: 26px;
  font-family: var(--display);
  font-style: italic;
  font-weight: 400;
  font-size: 17px;
  line-height: 1.6;
  color: var(--ink-soft);
}

/* A price RANGE is longer than one figure, so it steps down a size. */
.calc-total-sm { font-size: clamp(24px, 2.8vw, 40px); }

/* Rent vs buy leads with the two five year figures side by side. */
.rb-pair {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 24px;
}

.rb-pair > div { min-width: 0; }

.rb-total { font-size: clamp(24px, 2.6vw, 36px); }

@media (max-width: 460px) {
  .rb-pair { grid-template-columns: 1fr; }
}

/* -------------------------------------- sellers home value split, ROUND 3 */
/* PART 8.2: the kitchen the client loves on the left, the form on cream on
   the right. On mobile the IMAGE stacks above the form, by instruction, which
   is the one split on the site where the media leads. */
.value-split {
  display: grid;
  grid-template-columns: 1fr 1.1fr;
  gap: 64px;
  align-items: stretch;
}

.value-split-media { min-width: 0; }

.value-split-media img {
  width: 100%;
  height: 100%;
  min-height: 420px;
  object-fit: cover;
}

.value-split-body {
  min-width: 0;
  background: var(--cream);
  padding: 48px 44px;
}

@media (max-width: 1024px) {
  .value-split { gap: 40px; }
  .value-split-body { padding: 36px 30px; }
}

@media (max-width: 860px) {
  .value-split { grid-template-columns: 1fr; gap: 28px; }
  .value-split .value-split-media { order: 1; }
  .value-split .value-split-body { order: 2; }
  .value-split-media img { min-height: 0; aspect-ratio: 16 / 10; }
}

/* Floating labels, PART 8.2. The label sits in the field and eases up to 12px
   on focus or fill at 180ms. Present on the sellers form only; the label
   floats via :focus and :not(:placeholder-shown), so every input carries a
   single space placeholder. A select cannot be "placeholder shown", so its
   label holds the floated position permanently. */
.ff-float {
  position: relative;
  gap: 0;
}

.ff-float label {
  position: absolute;
  left: 17px;
  top: 17px;
  margin: 0;
  padding: 0 2px;
  background: transparent;
  font-size: 14px;
  font-weight: 400;
  letter-spacing: .04em;
  text-transform: none;
  color: var(--ink-faint);
  pointer-events: none;
  transform-origin: left top;
  transition: transform .18s var(--ease), color .18s var(--ease),
              background-color .18s var(--ease);
  /* One line, CLIPPED to the field. An absolutely positioned nowrap label
     otherwise runs past a tight column and gives the whole page a sideways
     scroll, which is how /sellers/ failed the sweep at 320px. */
  white-space: nowrap;
  max-width: calc(100% - 34px);
  overflow: hidden;
  text-overflow: ellipsis;
}

.ff-float input,
.ff-float select {
  padding-top: 22px;
  padding-bottom: 8px;
}

.ff-float input:focus + label,
.ff-float input:not(:placeholder-shown) + label,
.ff-float select + label {
  transform: translateY(-13px) scale(.86);
  color: var(--ink-soft);
}

/* PART 8.2: a 2px ink focus ring on the fields of this form. */
.ff-float input:focus,
.ff-float select:focus {
  border-color: var(--ink);
  box-shadow: inset 0 0 0 1px var(--ink);
}

/* PART 8.2: the submit runs the full width of the form column. */
.value-split .form-actions .btn { width: 100%; }

/* --------------------------------------------- About open columns, ROUND 3 */
/* PART 10.1: no boxes. Each item is an open column with a large serif numeral
   behind the title at 15 percent opacity, a 40px rule that extends to full
   width on hover, and the reveal brings the numeral in first. */
.open-steps {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 48px;
}

@media (max-width: 1024px) {
  .open-steps { grid-template-columns: 1fr; gap: 40px; }
}

.open-step {
  position: relative;
  min-width: 0;
}

/* ROUND 5 PART 6.2: the ghost numerals behind the titles are removed. The
   rules, serif titles, reveal and hover extension all stay. */

/* The content follows the numeral by 120ms. The rule keeps `width` in its
   transition list here, or the hover extension would snap instead of easing:
   this selector still matches after .is-in lands, so it owns the transition. */
.js [data-reveal] .open-step-rule,
.js [data-reveal] .open-step-title,
.js [data-reveal] .open-step-body {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity .6s var(--ease) .12s, transform .6s var(--ease) .12s,
              width .3s var(--ease);
}

.js [data-reveal].is-in .open-step-rule,
.js [data-reveal].is-in .open-step-title,
.js [data-reveal].is-in .open-step-body {
  opacity: 1;
  transform: none;
}

.open-step-rule {
  width: 40px;
  height: 2px;
  background: var(--ink);
  transition: width .3s var(--ease);
}

.open-step:hover .open-step-rule { width: 100%; }

.open-step-title {
  position: relative;
  margin-top: 26px;
  font-family: var(--display);
  font-weight: 300;
  font-size: 22px;
  letter-spacing: .06em;
  text-transform: uppercase;
}

.open-step-body {
  margin-top: 12px;
  font-size: 18px;
  line-height: 1.7;
  color: var(--ink-soft);
}

/* ------------------------------------------------------------------ reveal */
/* [CHECKLIST 2.8] Restrained: this is an elegant light site, not a showcase.
   Only armed once JS adds .js to <html>, so with scripts blocked every element
   stays at its default, which is fully visible. */
.js [data-reveal] {
  opacity: 0;
  transform: translateY(24px);
  transition: opacity .7s var(--ease), transform .7s var(--ease);
}

.js [data-reveal].is-in {
  opacity: 1;
  transform: none;
}

/* Photos scale from 1.04 to 1 on reveal. */
.js [data-reveal] .hood-media img,
.js [data-reveal].split-media img {
  transform: scale(1.04);
  transition: transform .9s var(--ease);
}

.js [data-reveal].is-in .hood-media img,
.js [data-reveal].is-in.split-media img {
  transform: none;
}

/* [CHECKLIST 2.8] The reduced motion guard wraps everything. Users who ask for
   less motion see final values immediately, including the stat counters. */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: .001ms !important;
    transition-duration: .001ms !important;
  }
  html { scroll-behavior: auto; }
  .js [data-reveal] {
    opacity: 1 !important;
    transform: none !important;
  }
}

/* ------------------------------------------------------------ legal pages */
.legal {
  padding: calc(var(--nav-h) + 72px) 0 96px;
}

.legal h2 {
  margin-top: 44px;
  font-family: var(--display);
  font-weight: 300;
  font-size: 20px;
  letter-spacing: .06em;
  text-transform: uppercase;
}

.legal h2:first-of-type { margin-top: 32px; }

.legal p,
.legal li {
  color: var(--ink-soft);
  font-size: 16px;
  line-height: 1.75;
}

.legal p { margin-top: 14px; }

.legal ul {
  margin-top: 14px;
  padding-left: 20px;
  list-style: disc;
}

.legal li + li { margin-top: 8px; }

.legal .measure { max-width: 72ch; }
