/* Dyer Real Estate — shared styles */

/* Palette: Alexandria Tigers maroon and gold, matched to the school's own
   site. Every color here flows through these variables — change one and it
   updates everywhere. (A few files keep their own copies, because SVG fills
   can't read CSS variables: images/logo.svg, images/favicon.svg and
   images/placeholders/*.svg. images/castle-intro.png is flat artwork matched
   to the building sign, so its colours are baked in and can't follow these
   at all — it has to be re-exported by hand if the palette ever moves.) */
:root {
  --color-bg: #ffffff;
  --color-bg-alt: #f8f6f4;
  --color-text: #20262e;
  --color-text-muted: #625d5b;
  --color-primary: #8b2332;
  --color-primary-dark: #6d1a26;
  --color-accent: #f9c132;
  /* A dark bronze rather than a darker gold: this is used as text on white
     (agent job titles, the "Price Reduced" badge), and real gold is far too
     light to read there. */
  --color-accent-dark: #8a6608;
  --color-border: #e6e2df;
  --color-success: #2e7d4f;
  --color-success-bg: #eaf6ef;
  /* A brighter, more orange red than the maroon, so error text reads as an
     error rather than as ordinary branding. */
  --color-danger: #9e3327;
  --color-danger-bg: #fbeae7;
  --font-heading: Georgia, 'Times New Roman', serif;
  --font-body: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
  --radius: 6px;
  --header-height: 72px;
  --max-width: 1180px;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
}

body {
  font-family: var(--font-body);
  color: var(--color-text);
  background: var(--color-bg);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4 {
  font-family: var(--font-heading);
  color: var(--color-primary-dark);
  margin: 0 0 0.5em;
  line-height: 1.2;
}

p { margin: 0 0 1em; }

a { color: var(--color-primary); text-decoration: none; }
a:hover { text-decoration: underline; }

img { max-width: 100%; display: block; }

.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0,0,0,0);
  white-space: nowrap;
  border: 0;
}

.container {
  max-width: var(--max-width);
  margin: 0 auto;
  padding: 0 24px;
}

/* Vertical breathing room for a page whose content is one plain container
   (listing detail, 404). Use this instead of an inline `padding: 40px 0 64px`
   -- the shorthand resets left/right to 0 and the page ends up flush against
   the screen edge on a phone. These are longhand on purpose. */
.page-body {
  padding-top: 40px;
  padding-bottom: 64px;
}
@media (max-width: 700px) {
  .container { padding: 0 20px; }
  .page-body { padding-top: 24px; padding-bottom: 40px; }
}

/* Buttons */
.btn {
  display: inline-block;
  font-family: var(--font-body);
  font-size: 0.95rem;
  font-weight: 600;
  padding: 10px 20px;
  border-radius: var(--radius);
  border: 1px solid transparent;
  cursor: pointer;
  text-decoration: none;
  transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}
.btn:hover { text-decoration: none; }
.btn-primary { background: var(--color-primary); color: #fff; }
.btn-primary:hover { background: var(--color-primary-dark); }
/* Gold can't carry white text — near-black on gold, the same pairing the
   school's own gold nav bar uses. On hover the fill darkens to bronze, so
   the text flips to white. */
.btn-accent { background: var(--color-accent); color: #20262e; }
.btn-accent:hover { background: var(--color-accent-dark); color: #fff; }
.btn-outline { background: transparent; color: var(--color-primary); border-color: var(--color-primary); }
.btn-outline:hover { background: var(--color-primary); color: #fff; }
.btn-danger { background: transparent; color: var(--color-danger); border-color: var(--color-danger); }
.btn-danger:hover { background: var(--color-danger); color: #fff; }
.btn-sm { padding: 6px 14px; font-size: 0.85rem; }
.btn-block { display: block; width: 100%; text-align: center; }
.btn[disabled] { opacity: 0.6; cursor: not-allowed; }

/* Site header — two tiers, after the Alexandria-Monroe school site:
   a maroon brand bar with a gold nav bar beneath it.

   There's no hamburger menu. With only three links, they shrink to fit
   even a narrow phone, which is simpler and steadier than a menu that has
   to open and close. */
.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  background: var(--color-primary);
}
.header-top {
  background: var(--color-primary);
}
.header-top .container {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding-top: 13px;
  padding-bottom: 13px;
}
.brand {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-shrink: 1;
  min-width: 0;
}
.brand:hover { text-decoration: none; }
/* Sized by height only: the castle artwork is landscape, and a fixed square
   would squash it. 44px rather than 38px because the brickwork and the lit
   windows stop reading much below that. */
.brand img, .brand svg { height: 44px; width: auto; flex-shrink: 0; }
.brand-text {
  font-family: var(--font-heading);
  font-size: 1.25rem;
  color: #fff;
  font-weight: bold;
  white-space: nowrap;
}
.brand-text small {
  display: block;
  font-family: var(--font-body);
  font-size: 0.6rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  color: rgba(255,255,255,0.8);
  text-transform: uppercase;
}
.header-phone {
  color: #fff;
  font-size: 0.82rem;
  font-weight: 600;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  white-space: nowrap;
  flex-shrink: 0;
}
.header-phone:hover { text-decoration: underline; }

.header-nav {
  background: var(--color-accent);
}
.main-nav {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 36px;
  flex-wrap: wrap;
}
.main-nav a {
  color: #20262e;
  font-weight: 600;
  font-size: 0.82rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 11px 2px;
  border-bottom: 3px solid transparent;
}
.main-nav a:hover, .main-nav a.active {
  color: var(--color-primary-dark);
  border-bottom-color: var(--color-primary-dark);
  text-decoration: none;
}

@media (max-width: 700px) {
  .brand-text { font-size: 1.05rem; }
  .brand-text small { font-size: 0.55rem; }
  .header-phone { font-size: 0.72rem; letter-spacing: 0.04em; }
  .main-nav { gap: 18px; }
  .main-nav a { font-size: 0.72rem; letter-spacing: 0.04em; }
}
@media (max-width: 420px) {
  /* The phone number moves to its own line rather than squeezing the name. */
  .header-top .container { flex-wrap: wrap; justify-content: center; gap: 8px; }
  .main-nav { gap: 12px; }
  .main-nav a { font-size: 0.68rem; letter-spacing: 0.02em; }
}

/* Footer */
.site-footer {
  background: var(--color-primary-dark);
  color: #e6bcc3;
  padding: 40px 0 24px;
  margin-top: 60px;
}
.site-footer a { color: #fff; }
.footer-grid {
  display: grid;
  grid-template-columns: 1.3fr 1fr 1fr;
  gap: 32px;
  margin-bottom: 24px;
}
.footer-grid h4 {
  color: #fff;
  font-size: 0.95rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  margin-bottom: 10px;
}
.footer-grid p, .footer-grid a {
  font-size: 0.9rem;
  color: #e6bcc3;
}
/* Office address in the footer. <address> is italic by default everywhere;
   this is a postal address, so that's reset. */
.footer-address {
  font-style: normal;
  font-size: 0.9rem;
  color: #e6bcc3;
  line-height: 1.6;
  margin: 0 0 10px;
}
.footer-grid ul { list-style: none; padding: 0; margin: 0; }
.footer-grid li { margin-bottom: 6px; }
.footer-bottom {
  border-top: 1px solid rgba(255,255,255,0.15);
  padding-top: 16px;
  font-size: 0.8rem;
  color: #eec9cf;
  display: flex;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 8px;
}
.staff-link { font-size: 0.8rem; color: #eec9cf; }
@media (max-width: 700px) {
  /* Once the three columns stack into one, left-aligned text reads as ragged
     against the centered content above it, so the whole footer centers. */
  .footer-grid { grid-template-columns: 1fr; text-align: center; }
  .footer-bottom { justify-content: center; text-align: center; }
}

/* Hero — split panel + bright carousel */
.hero {
  display: grid;
  grid-template-columns: minmax(380px, 460px) 1fr;
  min-height: min(72vh, 580px);
  background: var(--color-primary-dark);
}
.hero-panel {
  color: #fff;
  padding: 56px 48px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  background:
    radial-gradient(ellipse at top left, rgba(249,193,50,0.12), transparent 55%),
    var(--color-primary-dark);
}
.hero-badge {
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: #fbd166;
  border: 1px solid rgba(251,209,102,0.55);
  padding: 5px 12px;
  border-radius: 3px;
  margin-bottom: 22px;
  align-self: flex-start;
}
.hero-carousel {
  position: relative;
  overflow: hidden;
  background: #5c1520;
  min-height: 320px;
  contain: layout paint;
}
.hero-slides { position: absolute; inset: 0; }
.hero-slide {
  position: absolute;
  inset: 0;
  background-size: cover;
  background-position: center;
  opacity: 0;
  visibility: hidden;
  transform: scale(1.06);
  transition: opacity 1.2s ease, visibility 0s linear 1.2s;
}
/* Ken Burns zoom runs only while a slide is visible; "leaving" keeps the
   outgoing slide's zoom going during the crossfade so it doesn't snap. */
.hero-slide.active,
.hero-slide.leaving {
  visibility: visible;
  animation: heroZoom 7s linear forwards;
  will-change: transform, opacity;
}
.hero-slide.active {
  opacity: 1;
  transition: opacity 1.2s ease;
}
@keyframes heroZoom {
  from { transform: scale(1.06); }
  to { transform: scale(1); }
}
@media (prefers-reduced-motion: reduce) {
  .hero-slide,
  .hero-slide.active,
  .hero-slide.leaving {
    animation: none;
    transform: none;
    transition: opacity 0.4s ease, visibility 0s linear 0.4s;
  }
}
.hero-title {
  font-size: clamp(1.9rem, 3.2vw, 2.5rem);
  font-weight: 400;
  color: #fff;
  line-height: 1.15;
  margin-bottom: 16px;
}
.hero-title em {
  font-style: italic;
  color: var(--color-accent);
}
.hero-sub {
  color: rgba(255,255,255,0.8);
  max-width: 420px;
  margin-bottom: 28px;
}
.hero-ctas {
  display: flex;
  flex-direction: column;
  gap: 12px;
  max-width: 340px;
}
.hero-ctas .btn { text-align: center; }
.hero-caption {
  position: absolute;
  left: 24px;
  bottom: 24px;
  z-index: 2;
  display: block;
  background: rgba(92,21,32,0.85);
  color: #fff;
  padding: 10px 16px;
  border-radius: 5px;
  border-left: 3px solid var(--color-accent);
  text-decoration: none;
}
.hero-caption:hover { background: rgba(92,21,32,0.97); text-decoration: none; }
.hero-caption-price {
  display: block;
  font-family: var(--font-heading);
  font-size: 1.25rem;
}
.hero-caption-addr {
  display: block;
  font-size: 0.85rem;
  color: rgba(255,255,255,0.85);
}
.btn-lg { padding: 13px 28px; font-size: 1rem; }
.btn-ghost {
  background: rgba(255,255,255,0.08);
  color: #fff;
  border-color: rgba(255,255,255,0.55);
}
.btn-ghost:hover { background: #fff; color: var(--color-primary-dark); }
@media (max-width: 860px) {
  .hero { grid-template-columns: 1fr; }
  .hero-panel { padding: 40px 24px; }
  .hero-carousel { min-height: 300px; }
}
.hero-empty {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #e6bcc3;
  font-size: 1rem;
}

/* Community bar under hero */
.hero-bar { background: var(--color-primary-dark); color: #fff; }
.hero-bar-inner {
  max-width: var(--max-width);
  margin: 0 auto;
  padding: 0 24px;
  display: grid;
  /* auto-fit rather than a fixed four: the bar is built from whatever towns
     have listings (see buildTownBar in js/home.js), so it has to sit evenly
     whether that comes out as three names or five. */
  grid-template-columns: repeat(auto-fit, minmax(min(160px, 100%), 1fr));
  text-align: center;
}
.hero-bar-inner a {
  display: block;
  padding: 18px 10px;
  border-right: 1px solid rgba(255,255,255,0.12);
  color: #fff;
  text-decoration: none;
  transition: background 0.15s ease;
}
.hero-bar-inner a:last-child { border-right: none; }
.hero-bar-inner a:hover { background: rgba(255,255,255,0.06); text-decoration: none; }
.hero-bar .town {
  display: block;
  font-family: var(--font-heading);
  font-size: 1.05rem;
  color: var(--color-accent);
}
.hero-bar .count {
  display: block;
  font-size: 0.78rem;
  color: rgba(255,255,255,0.65);
}
@media (max-width: 700px) {
  .hero-bar-inner { grid-template-columns: 1fr 1fr; }
  .hero-bar-inner a:nth-child(2) { border-right: none; }
  .hero-bar-inner a:nth-child(1),
  .hero-bar-inner a:nth-child(2) { border-bottom: 1px solid rgba(255,255,255,0.12); }
}

/* Tabs / listings browser */
.listings-section { padding: 56px 0; }
.section-heading {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  margin-bottom: 20px;
  flex-wrap: wrap;
  gap: 12px;
}
.tabs {
  display: flex;
  gap: 6px;
  border-bottom: 1px solid var(--color-border);
  margin-bottom: 28px;
  flex-wrap: wrap;
}
.tab-btn {
  background: none;
  border: none;
  padding: 10px 18px;
  font-size: 0.95rem;
  font-weight: 600;
  color: var(--color-text-muted);
  cursor: pointer;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
}
.tab-btn:hover { color: var(--color-primary); }
.tab-btn.active {
  color: var(--color-primary);
  border-bottom-color: var(--color-accent);
}

/* min(260px, 100%) rather than a bare 260px: on a screen narrower than the
   track minimum, a plain minmax() refuses to shrink and the whole grid
   spills off the side, giving the page a horizontal scrollbar. This matters
   below ~310px (a folded Galaxy Fold is 280px). */
.listing-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(260px, 100%), 1fr));
  gap: 22px;
}
.listing-card {
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  overflow: hidden;
  background: #fff;
  transition: box-shadow 0.15s ease, transform 0.15s ease;
  display: flex;
  flex-direction: column;
  cursor: pointer;
}
.listing-card:hover { box-shadow: 0 4px 18px rgba(62,18,28,0.12); transform: translateY(-2px); }
.listing-photo {
  height: 170px;
  background: var(--color-bg-alt);
  background-size: cover;
  background-position: center;
  position: relative;
}
.listing-photo .save-btn {
  position: absolute;
  top: 10px; right: 10px;
  background: rgba(255,255,255,0.92);
  border: none;
  border-radius: 50%;
  width: 34px; height: 34px;
  cursor: pointer;
  font-size: 1rem;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--color-text-muted);
}
.listing-photo .save-btn.saved { color: var(--color-accent); }
.listing-photo .placeholder-icon {
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  color: var(--color-border);
}
.listing-photo .placeholder-icon svg { width: 48px; height: 48px; }

/* Skeleton "shimmer" shown while a photo is loading (see img-skeleton.js).
   Works two ways: as an overlay on background-image tiles (listing cards,
   hero slides, agent avatars — paired with data-bg-src), and as an opacity
   fade on real <img> tags (gallery main photo, floor plan — paired with
   class="img-fade"). Neither makes the photo download faster; it just keeps
   the layout from sitting on a blank box while it does. */
/* No "position" here on purpose — every element this is used on already
   establishes its own positioning context (relative/absolute) for other
   layout reasons except .agent-avatar, which gets position:relative added
   directly on its own rule below, so this never clobbers .hero-slide's
   position:absolute stacking. */
.img-skeleton { background-color: var(--color-bg-alt); overflow: hidden; }
.img-skeleton::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg, transparent, rgba(255,255,255,0.6), transparent);
  background-size: 200% 100%;
  animation: dyer-shimmer 1.3s ease-in-out infinite;
  opacity: 1;
  transition: opacity 0.25s ease;
  pointer-events: none;
}
.img-skeleton.is-loaded::after { opacity: 0; }
@keyframes dyer-shimmer {
  0% { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}
img.img-skeleton.img-fade { opacity: 0; transition: opacity 0.25s ease; background: none; }
img.img-skeleton.img-fade.is-loaded { opacity: 1; }
img.img-skeleton.img-fade.is-loaded::after { display: none; }

.listing-body { padding: 14px 16px 16px; flex: 1; display: flex; flex-direction: column; }
.listing-price {
  font-family: var(--font-heading);
  font-size: 1.3rem;
  color: var(--color-primary-dark);
}
.listing-address { color: var(--color-text); font-size: 0.95rem; }
.listing-city { color: var(--color-text-muted); font-size: 0.85rem; margin-bottom: 10px; }
.listing-badge {
  display: inline-block;
  font-size: 0.7rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  padding: 3px 8px;
  border-radius: 4px;
  background: var(--color-bg-alt);
  color: var(--color-text-muted);
  margin-bottom: 8px;
  align-self: flex-start;
}
/* "Price Reduced" used to be a red badge, which no longer stands out now
   that red is the brand color — it reads as ordinary Dyer chrome. Tan keeps
   it noticeable against a red header and a photo. */
.listing-badge.reduced { background: #fdf4d9; color: #8a6608; }
.listing-badge.open { background: var(--color-success-bg); color: var(--color-success); }
/* Pending replaces the category badge on homes that are under contract.
   A pale tint of the brand red (--color-primary #8b2332) so it reads as
   Dyer's own palette rather than a fifth unrelated badge color. */
.listing-badge.pending { background: #f9e0e3; color: #8b2332; }
.listing-card .card-actions { margin-top: auto; padding-top: 10px; }

.empty-state {
  text-align: center;
  padding: 40px 20px;
  color: var(--color-text-muted);
}
/* The "no listings" message is a grid child like any card. Left alone it
   sizes to one column and sits off to the left, which looks like a broken
   card — more visibly so now that the MIBOR card shares the row with it. */
.listing-grid > .empty-state { grid-column: 1 / -1; }

/* MIBOR hand-off card — the last cell of every listing grid, on the home
   page tabs and the Homes for Sale filters alike (see miborCardHtml() in
   js/listing-cards.js). It borrows the listing card's shape and hover so it
   sits in the grid naturally, but takes a dashed border and the tinted
   ground so nobody mistakes it for a home that's for sale. */
.mibor-card {
  position: relative;
  border: 1px dashed var(--color-primary);
  border-radius: var(--radius);
  background: var(--color-bg-alt);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  color: var(--color-text);
  cursor: pointer;
  transition: box-shadow 0.15s ease, transform 0.15s ease, background 0.15s ease;
}
/* Same lift and shadow as .listing-card, plus the dashes firming up into a
   solid border, so the card answers to the cursor like every home beside it.
   :focus-within covers keyboard users tabbing onto either link inside. */
.mibor-card:hover,
.mibor-card:focus-within {
  background: #fff;
  border-style: solid;
  box-shadow: 0 4px 18px rgba(62,18,28,0.12);
  transform: translateY(-2px);
}
/* Same 170px as .listing-photo, so the card's text starts on the same line
   as the price on the listing cards beside it. */
.mibor-card-logo {
  height: 170px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px 24px;
  background: #fff;
  border-bottom: 1px solid var(--color-border);
}
.mibor-card-logo img { width: 100%; max-width: 208px; height: auto; }
.mibor-card-body {
  padding: 14px 16px 16px;
  flex: 1;
  display: flex;
  flex-direction: column;
}
.mibor-card-body h3 {
  font-size: 1.05rem;
  line-height: 1.25;
  margin: 0 0 6px;
}
.mibor-card-body p {
  font-size: 0.85rem;
  line-height: 1.45;
  color: var(--color-text-muted);
  margin: 0 0 10px;
}
/* The "call us" line is the point of the card, so it gets full-strength body
   text while the MIBOR sentence above it stays muted. */
.mibor-card-call {
  color: var(--color-text) !important;
  margin-bottom: 14px !important;
}
/* Rides above the stretched overlay below, so tapping the number dials the
   office instead of opening the MIBOR search. */
.mibor-card-call a { font-weight: 700; white-space: nowrap; position: relative; z-index: 2; }
/* margin-top:auto pins the link to the bottom of the card the way
   .card-actions does on a listing, so it lines up however tall the card
   ends up in its row. */
.mibor-card-cta {
  margin-top: auto;
  align-self: flex-start;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-weight: 700;
  font-size: 0.9rem;
  color: var(--color-primary);
}
/* Stretched link: this pseudo-element covers the whole card, so a click
   anywhere on it opens the MIBOR search. It's done this way rather than
   wrapping the card in one big <a> because the card also holds the office
   phone link, and an anchor can't legally contain another anchor. */
.mibor-card-cta::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 1;
}
.mibor-card-cta svg { width: 16px; height: 16px; transition: transform 0.15s ease; }
.mibor-card:hover .mibor-card-cta { text-decoration: underline; }
.mibor-card:hover .mibor-card-cta svg { transform: translateX(3px); }
@media (prefers-reduced-motion: reduce) {
  .mibor-card, .mibor-card-cta svg { transition: none; }
  .mibor-card:hover, .mibor-card:focus-within { transform: none; }
  .mibor-card:hover .mibor-card-cta svg { transform: none; }
}

/* Generic page sections */
.page-hero {
  background: var(--color-bg-alt);
  padding: 48px 0;
  text-align: center;
  border-bottom: 1px solid var(--color-border);
}
.page-hero p { color: var(--color-text-muted); max-width: 640px; margin: 0 auto; }

/* Flex rather than grid, so that a last row holding fewer agents than a full
   row is centered instead of pinned to the left. CSS grid centers the whole
   block but still starts each row in column one, which left the fourth agent
   hanging under the first with empty space beside them. Flex wrapping centers
   every row on its own, so any leftover card sits in the middle.

   The card sizing carries over from the grid version: 320px is the cap, so a
   small team doesn't stretch into oversized cards, and the 260px floor makes
   a card wrap to the next row rather than squeeze. min(260px, 100%) keeps a
   single card from overflowing a narrow phone. Works for any number of
   agents. */
.agents-grid {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 24px;
  padding: 48px 0 64px;
}
/* The "Loading agents…" / "no agents" message is a flex child too, so give it
   the full row rather than letting it size itself like a card. */
.agents-grid > .empty-state { flex: 1 1 100%; }
.agent-card {
  flex: 0 1 320px;
  min-width: min(260px, 100%);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  padding: 24px;
  text-align: center;
}
/* Sized for real headshots — the initials fallback fills the same circle. */
.agent-avatar {
  width: 116px; height: 116px;
  border-radius: 50%;
  background: var(--color-primary);
  color: #fff;
  font-family: var(--font-heading);
  font-size: 1.6rem;
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 0 auto 14px;
  position: relative;
}
.agent-card h3 { margin-bottom: 2px; }
.agent-title { color: var(--color-accent-dark); font-weight: 600; font-size: 0.9rem; margin-bottom: 10px; }
.agent-contact { font-size: 0.9rem; color: var(--color-text-muted); }
.agent-contact a { color: var(--color-text-muted); }
.agent-contact div { margin-bottom: 3px; }
.agent-contact .phone-label {
  display: inline-block;
  min-width: 46px;
  font-size: 0.72rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--color-accent-dark);
}
.agent-avatar-photo {
  background-size: cover;
  background-position: center;
  font-size: 0; /* hide initials fallback text when a photo is set */
}
.agent-initials { line-height: 1; }
/* The promise carried over from the old dyerre.net, now heading the Agents
   page. Serif italic under a short gold rule, so it reads as the brokerage
   speaking rather than as ordinary page copy.

   The selector is `p.brand-statement`, not `.brand-statement`: it has to
   outrank `.page-hero p` above, which would otherwise force the muted grey
   back on. Keep this rule below that one. */
p.brand-statement {
  position: relative;
  max-width: 660px;
  margin: 22px auto 0;
  padding-top: 24px;
  font-family: var(--font-heading);
  font-style: italic;
  font-size: 1.08rem;
  line-height: 1.65;
  color: var(--color-primary-dark);
}
p.brand-statement::before {
  content: "";
  position: absolute;
  top: 0;
  left: 50%;
  transform: translateX(-50%);
  width: 56px;
  height: 3px;
  border-radius: 2px;
  background: var(--color-accent);
}
/* On a phone this runs to six or seven lines of italic serif before the
   first agent is visible. Easing the size and the surrounding padding buys
   back roughly a third of that height without shrinking it into fine print. */
@media (max-width: 560px) {
  .page-hero { padding: 32px 0; }
  p.brand-statement {
    font-size: 0.98rem;
    margin-top: 18px;
    padding-top: 20px;
  }
}

.muted { color: var(--color-text-muted); }

/* Forms */
.form-card {
  max-width: 420px;
  margin: 56px auto;
  padding: 32px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
}
.form-card h1 { font-size: 1.5rem; text-align: center; }
.form-subtext { text-align: center; color: var(--color-text-muted); margin-bottom: 24px; font-size: 0.9rem; }
.field { margin-bottom: 16px; }
.field label { display: block; font-size: 0.85rem; font-weight: 600; margin-bottom: 6px; color: var(--color-text); }
.label-optional { font-weight: 400; color: var(--color-text-muted); }
.field input, .field select, .field textarea {
  width: 100%;
  padding: 10px 12px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  font-size: 0.95rem;
  font-family: var(--font-body);
}
.field input:focus, .field select:focus, .field textarea:focus {
  outline: none;
  border-color: var(--color-primary);
}
.field-hint { font-size: 0.8rem; color: var(--color-text-muted); margin-top: 4px; }
.form-msg {
  padding: 10px 12px;
  border-radius: var(--radius);
  font-size: 0.88rem;
  margin-bottom: 16px;
  display: none;
}
.form-msg.error { display: block; background: var(--color-danger-bg); color: var(--color-danger); }
.form-msg.success { display: block; background: var(--color-success-bg); color: var(--color-success); }
.form-switch { text-align: center; margin-top: 16px; font-size: 0.9rem; color: var(--color-text-muted); }

/* Filter bar (full listings page) */
.filter-bar {
  display: flex;
  gap: 14px;
  flex-wrap: wrap;
  align-items: flex-end;
  padding: 24px 0;
  border-bottom: 1px solid var(--color-border);
  margin-bottom: 28px;
}
/* flex-basis 150px with grow: the four filters sit side by side on a laptop,
   then wrap and stretch to fill the row on a phone instead of leaving each
   dropdown stranded at 150px against a wide empty gap. */
.filter-bar .field { margin-bottom: 0; flex: 1 1 150px; min-width: 150px; }

/* Staff dashboard */
.dash-shell { display: flex; min-height: calc(100vh - var(--header-height)); }
.dash-sidebar {
  width: 220px;
  background: var(--color-bg-alt);
  border-right: 1px solid var(--color-border);
  padding: 24px 0;
  flex-shrink: 0;
}
.dash-sidebar a {
  display: block;
  padding: 10px 24px;
  color: var(--color-text);
  font-weight: 600;
  font-size: 0.92rem;
}
.dash-sidebar a.active { color: var(--color-primary); background: #fff; border-right: 3px solid var(--color-accent); }
.dash-main { flex: 1; padding: 32px; max-width: 980px; }
.dash-table { width: 100%; border-collapse: collapse; font-size: 0.92rem; }
.dash-table th, .dash-table td {
  text-align: left;
  padding: 10px 12px;
  border-bottom: 1px solid var(--color-border);
}
.dash-table th { color: var(--color-text-muted); font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.04em; }
.dash-table .thumb { width: 48px; height: 36px; border-radius: 4px; background: var(--color-bg-alt); }
.dash-table img.thumb { object-fit: cover; }
.status-pill {
  display: inline-block;
  font-size: 0.72rem;
  font-weight: 700;
  text-transform: uppercase;
  padding: 3px 9px;
  border-radius: 10px;
  background: var(--color-bg-alt);
  color: var(--color-text-muted);
}
.status-pill.active { background: var(--color-success-bg); color: var(--color-success); }
.status-pill.sold { background: var(--color-danger-bg); color: var(--color-danger); }
.dash-toolbar { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; flex-wrap: wrap; gap: 12px; }
.modal-overlay {
  position: fixed; inset: 0;
  background: rgba(40,12,14,0.5);
  display: none;
  align-items: center;
  justify-content: center;
  z-index: 100;
  padding: 20px;
}
.modal-overlay.open { display: flex; }
.modal-card {
  background: #fff;
  border-radius: var(--radius);
  padding: 28px;
  max-width: 480px;
  width: 100%;
  max-height: 90vh;
  overflow-y: auto;
}
.modal-card h2 { font-size: 1.2rem; }
.photo-preview {
  width: 100%;
  height: 140px;
  background: var(--color-bg-alt);
  border-radius: var(--radius);
  margin-bottom: 10px;
  background-size: cover;
  background-position: center;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--color-text-muted);
  font-size: 0.85rem;
  overflow: hidden;
}

/* Focal-point picker — wraps .photo-preview in the photo upload modals */
.focal-wrap { position: relative; }
.focal-wrap.has-photo .photo-preview { cursor: crosshair; }
.focal-dot {
  display: none;
  position: absolute;
  width: 14px;
  height: 14px;
  border-radius: 50%;
  border: 2px solid #fff;
  background: var(--color-accent);
  box-shadow: 0 0 0 1px rgba(0,0,0,0.35);
  transform: translate(-50%, -50%);
  pointer-events: none;
}
.focal-hint {
  display: none;
  color: var(--color-text-muted);
  font-size: 0.78rem;
  margin-top: 6px;
}

/* First-visit intro — castle rises out of the moat, windows warm up, flash
   into the site. The artwork is images/castle-intro.png, matched to the
   building sign; it replaced a brick-by-brick SVG build in Aug 2026. */
html.intro-lock, html.intro-lock body { overflow: hidden; }
.intro-overlay {
  position: fixed;
  inset: 0;
  z-index: 300;
  background: #fcf9f2;
  display: flex;
  align-items: center;
  justify-content: center;
  animation: introFadeOut 0.45s ease 2.75s forwards;
}
.intro-overlay[hidden] { display: none; }
/* Every animated part of the intro is held at its first frame until
   index.html adds .intro-ready, which it does once the castle artwork has
   decoded. A paused animation does not advance through its delay either, so
   the whole timeline shifts intact rather than starting half-run. */
.intro-overlay:not(.intro-ready),
.intro-overlay:not(.intro-ready) .intro-castle img,
.intro-overlay:not(.intro-ready) .intro-glow,
.intro-overlay:not(.intro-ready) .intro-name,
.intro-overlay:not(.intro-ready) .intro-tagline,
.intro-overlay:not(.intro-ready) .intro-flash { animation-play-state: paused; }
.intro-inner { text-align: center; }
/* The window the castle slides up through. Height is pinned to the
   artwork's 800x623 aspect so the image can be positioned by percentage.
   Re-measure this if castle-intro.png is ever replaced at a new aspect,
   or the artwork gets clipped by the overflow below. */
.intro-castle {
  position: relative;
  width: 240px;
  height: 187px;
  max-width: 72vw;
  overflow: hidden;
  /* This is a block, so the parent's text-align:center does NOT centre it the
     way it centred the inline <svg> this replaced. The auto margins do. */
  margin-left: auto;
  margin-right: auto;
}
.intro-castle img {
  display: block;
  width: 100%;
  height: auto;
  transform: translateY(102%);
  animation: introRise 1.15s cubic-bezier(0.16, 0.9, 0.28, 1) 0.15s forwards;
}
/* Lit windows. Each sits at the centre of a window in the artwork, given as
   a percentage of the image box — if the artwork is ever replaced these four
   need re-measuring. The gradient is kept soft so it warms the brick around
   each window rather than sitting on it as a visible disc. */
.intro-glow {
  position: absolute;
  border-radius: 50%;
  opacity: 0;
  pointer-events: none;
  background: radial-gradient(closest-side, rgba(249,193,50,0.55), rgba(249,193,50,0) 72%);
  animation: introWindowGlow 0.75s ease 1.25s forwards;
}
.intro-glow-tower    { left: 74.8%; top: 37.0%; width: 26%; height: 33%; transform: translate(-50%, -50%); }
.intro-glow-main     { left: 37.3%; top: 75.4%; width: 34%; height: 44%; transform: translate(-50%, -50%); animation-delay: 1.35s; }
.intro-glow-turret-a { left: 15.1%; top: 68.6%; width: 18%; height: 23%; transform: translate(-50%, -50%); animation-delay: 1.45s; }
.intro-glow-turret-b { left: 22.0%; top: 68.6%; width: 18%; height: 23%; transform: translate(-50%, -50%); animation-delay: 1.45s; }
.intro-name {
  margin-top: 14px;
  font-family: var(--font-heading);
  color: var(--color-primary-dark);
  font-size: 1.35rem;
  letter-spacing: 0.04em;
  opacity: 0;
  animation: introName 0.5s ease 0.95s forwards;
}
/* Tamra's line, arriving after the name so it reads as the payoff to the
   castle rising. The tagline fades in at 1.3s and the flash comes at 2.6s,
   leaving it fully visible for about 0.8s. To give it longer, push the flash
   and fade-out delays back and raise the matching setTimeout in index.html
   by the same amount — all three move together. */
.intro-tagline {
  margin-top: 6px;
  font-family: var(--font-heading);
  font-style: italic;
  color: var(--color-accent-dark);
  font-size: 0.95rem;
  max-width: 20em;
  margin-left: auto;
  margin-right: auto;
  padding: 0 16px;
  opacity: 0;
  animation: introName 0.5s ease 1.3s forwards;
}
.intro-flash {
  position: absolute;
  inset: 0;
  background: #fff;
  opacity: 0;
  pointer-events: none;
  animation: introFlash 0.3s ease-in 2.6s forwards;
}
@keyframes introRise { to { transform: translateY(0); } }
@keyframes introName { to { opacity: 1; } }
@keyframes introWindowGlow {
  0% { opacity: 0; }
  65% { opacity: 1; }
  100% { opacity: 0.82; }
}
@keyframes introFlash { to { opacity: 1; } }
@keyframes introFadeOut { to { opacity: 0; visibility: hidden; } }
@media (prefers-reduced-motion: reduce) {
  .intro-overlay { display: none; }
}
/* ============================================================
   Professional listing cards — stats row, chips, photo overlays
   ============================================================ */
.listing-price-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
}
.neighborhood-chip {
  font-size: 0.72rem;
  font-weight: 600;
  color: var(--color-primary);
  background: var(--color-bg-alt);
  border: 1px solid var(--color-border);
  border-radius: 999px;
  padding: 2px 10px;
  white-space: nowrap;
  /* 45% clipped ordinary subdivision names ("Timberlake Estates") mid-word.
     58% fits them while still leaving room for a seven-figure price. */
  max-width: 58%;
  overflow: hidden;
  text-overflow: ellipsis;
}
.listing-stats {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 6px 0 8px;
  color: var(--color-text);
  font-size: 0.88rem;
}
.listing-stats .stat { display: inline-flex; align-items: center; gap: 5px; }
.listing-stats .stat b { font-weight: 700; }
.listing-stats .stat svg { width: 17px; height: 17px; color: var(--color-primary); flex-shrink: 0; }
.listing-stats .stat-sep { width: 1px; height: 14px; background: var(--color-border); }
.listing-badge.on-photo {
  position: absolute;
  top: 10px; left: 10px;
  margin: 0;
  background: rgba(255,255,255,0.94);
  box-shadow: 0 1px 4px rgba(62,18,28,0.18);
  z-index: 1;
}
.listing-badge.on-photo.reduced { background: #fdf4d9; }
.listing-badge.on-photo.open { background: var(--color-success-bg); }
.listing-badge.on-photo.pending { background: #f9e0e3; }
.photo-count {
  position: absolute;
  bottom: 8px; right: 8px;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  background: rgba(58,14,24,0.72);
  color: #fff;
  font-size: 0.75rem;
  font-weight: 600;
  border-radius: 4px;
  padding: 2px 7px;
}
.photo-count svg { width: 13px; height: 13px; }
.listing-agent-line {
  margin-top: auto;
  padding-top: 8px;
  font-size: 0.8rem;
  color: var(--color-text-muted);
}
.listing-agent-line a { font-weight: 600; }

/* Admin: "+ Add Listing" card at the end of the grid */
.add-listing-card {
  border: 2px dashed var(--color-border);
  border-radius: var(--radius);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: 240px;
  color: var(--color-text-muted);
  cursor: pointer;
  transition: border-color 0.15s ease, color 0.15s ease;
  background: transparent;
  font: inherit;
}
.add-listing-card:hover { border-color: var(--color-accent); color: var(--color-accent-dark); }
.add-listing-card .plus { font-size: 2.2rem; line-height: 1; font-family: var(--font-heading); }

/* ============================================================
   Inline editing (admin view)
   ============================================================ */
.ie-editable { position: relative; cursor: pointer; border-radius: 4px; }
.ie-editable:hover { outline: 2px dashed var(--color-accent); outline-offset: 3px; }
.ie-editable .ie-pencil {
  display: none;
  position: absolute;
  top: -10px; right: -10px;
  width: 22px; height: 22px;
  background: var(--color-accent);
  color: #fff;
  border-radius: 50%;
  align-items: center;
  justify-content: center;
  box-shadow: 0 1px 4px rgba(62,18,28,0.3);
  z-index: 2;
}
.ie-editable:hover .ie-pencil { display: inline-flex; }
.ie-pencil-svg { width: 12px; height: 12px; }
.ie-editing { cursor: auto; }
.ie-editing:hover { outline: none; }
.ie-editing .ie-pencil { display: none !important; }
.ie-input {
  font: inherit;
  color: inherit;
  width: 100%;
  max-width: 100%;
  border: 2px solid var(--color-accent);
  border-radius: 4px;
  padding: 2px 6px;
  background: #fff;
}
.ie-error { color: var(--color-danger); font-size: 0.78rem; margin-top: 4px; }
.ie-hint {
  font-size: 0.78rem;
  color: var(--color-accent-dark);
  background: #fdf8ee;
  border: 1px solid #eadfc9;
  border-radius: 4px;
  padding: 6px 10px;
  margin-bottom: 14px;
}

/* ============================================================
   Listing detail page — gallery, facts, sections, agent panel
   ============================================================ */
.detail-layout {
  display: grid;
  grid-template-columns: 1.5fr 1fr;
  gap: 32px;
  margin-top: 16px;
  align-items: start;
}
/* Grid items default to min-width:auto, so a wide child (the thumbnail strip
   on a listing with many photos) stretches its column and pushes the details
   column off-screen. min-width:0 lets the column shrink so the strip's own
   overflow-x:auto scrolling takes over instead. */
.detail-layout > * { min-width: 0; }
@media (max-width: 820px) {
  .detail-layout { grid-template-columns: 1fr; }
}

.gallery-main {
  position: relative;
  height: 380px;
  border-radius: 8px;
  overflow: hidden;
  background: var(--color-bg-alt);
  background-size: cover;
  background-position: center;
  cursor: zoom-in;
}
@media (max-width: 820px) { .gallery-main { height: 260px; } }
.gallery-main .placeholder-icon {
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  color: var(--color-border);
}
.gallery-main .placeholder-icon svg { width: 96px; height: 96px; }
.gallery-nav {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  background: rgba(255,255,255,0.92);
  border: none;
  border-radius: 50%;
  width: 40px; height: 40px;
  font-size: 1.2rem;
  cursor: pointer;
  color: var(--color-primary-dark);
  box-shadow: 0 1px 6px rgba(62,18,28,0.25);
  display: flex; align-items: center; justify-content: center;
}
.gallery-nav:hover { background: #fff; }
.gallery-nav.prev { left: 12px; }
.gallery-nav.next { right: 12px; }
.gallery-counter {
  position: absolute;
  bottom: 10px; right: 10px;
  background: rgba(58,14,24,0.72);
  color: #fff;
  font-size: 0.78rem;
  font-weight: 600;
  border-radius: 4px;
  padding: 2px 8px;
}
.gallery-thumbs {
  display: flex;
  gap: 8px;
  margin-top: 10px;
  overflow-x: auto;
  padding-bottom: 4px;
}
.gallery-thumb {
  position: relative;
  width: 84px; height: 60px;
  flex-shrink: 0;
  border-radius: 4px;
  background-size: cover;
  background-position: center;
  background-color: var(--color-bg-alt);
  cursor: pointer;
  border: 2px solid transparent;
}
.gallery-thumb.active { border-color: var(--color-accent); }
.gallery-thumb .thumb-x {
  position: absolute;
  top: -6px; right: -6px;
  width: 18px; height: 18px;
  border: none;
  border-radius: 50%;
  background: var(--color-danger);
  color: #fff;
  font-size: 0.7rem;
  line-height: 1;
  cursor: pointer;
  display: flex; align-items: center; justify-content: center;
}
.gallery-add-btn {
  width: 84px; height: 60px;
  flex-shrink: 0;
  border: 2px dashed var(--color-border);
  border-radius: 4px;
  background: transparent;
  color: var(--color-text-muted);
  font-size: 1.3rem;
  cursor: pointer;
}
.gallery-add-btn:hover { border-color: var(--color-accent); color: var(--color-accent-dark); }

/* Full-screen lightbox */
.lightbox {
  position: fixed;
  inset: 0;
  z-index: 400;
  background: rgba(30,12,14,0.94);
  display: none;
  align-items: center;
  justify-content: center;
}
.lightbox.open { display: flex; }
.lightbox img {
  max-width: 92vw;
  max-height: 88vh;
  object-fit: contain;
  border-radius: 4px;
}
.lightbox .gallery-nav { background: rgba(255,255,255,0.85); }
.lightbox-close {
  position: absolute;
  top: 16px; right: 20px;
  background: none;
  border: none;
  color: #fff;
  font-size: 2rem;
  cursor: pointer;
  line-height: 1;
}
.lightbox-caption {
  position: absolute;
  bottom: 18px; left: 50%;
  transform: translateX(-50%);
  color: #fff;
  font-size: 0.9rem;
  background: rgba(0,0,0,0.45);
  padding: 4px 14px;
  border-radius: 999px;
}

/* Key facts grid */
.facts-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(150px, 100%), 1fr));
  gap: 10px;
  margin: 18px 0;
}
.fact-tile {
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  padding: 10px 12px;
  background: #fff;
}
.fact-tile .fact-label {
  font-size: 0.72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--color-text-muted);
  margin-bottom: 2px;
}
.fact-tile .fact-value { font-size: 0.95rem; font-weight: 600; color: var(--color-text); }
.fact-tile .fact-value .muted { color: var(--color-text-muted); font-weight: 400; }

.detail-stats { font-size: 1.05rem; margin: 10px 0 4px; }
.detail-stats .stat svg { width: 20px; height: 20px; }

/* Detail page content sections */
.detail-section { margin-top: 36px; }
.detail-section > h2 {
  font-size: 1.25rem;
  border-bottom: 2px solid var(--color-border);
  padding-bottom: 8px;
}
.tour-frame {
  width: 100%;
  aspect-ratio: 16 / 9;
  border: none;
  border-radius: 8px;
  background: var(--color-bg-alt);
}
.floor-plan-img {
  max-height: 480px;
  border: 1px solid var(--color-border);
  border-radius: 8px;
  cursor: zoom-in;
  background: #fff;
}

/* Agent panel */
.agent-panel {
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  padding: 18px;
  margin-top: 20px;
  background: var(--color-bg-alt);
  display: flex;
  gap: 14px;
  align-items: flex-start;
}
.agent-panel .agent-avatar {
  width: 52px; height: 52px;
  border-radius: 50%;
  background: var(--color-primary);
  color: #fff;
  display: flex; align-items: center; justify-content: center;
  font-family: var(--font-heading);
  font-size: 1.1rem;
  flex-shrink: 0;
}
.agent-panel h3 { margin-bottom: 2px; font-size: 1.05rem; }
.agent-panel .agent-title { color: var(--color-text-muted); font-size: 0.82rem; margin-bottom: 6px; }
.agent-panel .agent-contact { font-size: 0.85rem; }
.agent-panel .agent-links { margin-top: 8px; font-size: 0.85rem; }

/* Never break a nav label across two lines — "Homes for Sale" stays whole
   and the row tightens instead. The narrow-screen sizes live with the rest
   of the header rules above; this only guards the wrapping. */
.main-nav a { white-space: nowrap; }

/* Detail-page gallery: show the whole photo, box fits the image (no crop).
   These override the fixed-height rules above. */
.gallery-main {
  height: auto;
  min-height: 220px;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden; /* contains the crop overlay's grey mask */
}
@media (max-width: 820px) { .gallery-main { height: auto; } }
.gallery-img {
  display: block;
  width: 100%;
  height: auto;
  max-height: 540px;
  object-fit: contain;
}

/* Card-crop overlay: draggable card-shaped window, outside area greyed out */
.crop-layer { position: absolute; inset: 0; z-index: 3; }
.crop-box {
  position: absolute;
  border: 2px solid #fff;
  border-radius: 2px;
  box-shadow: 0 0 0 9999px rgba(36, 16, 18, 0.62);
  cursor: grab;
  touch-action: none;
}
.crop-box:active { cursor: grabbing; }
.crop-bar {
  position: absolute;
  bottom: 12px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 4;
  display: flex;
  align-items: center;
  gap: 10px;
  background: rgba(255, 255, 255, 0.96);
  border-radius: 6px;
  padding: 6px 12px;
  box-shadow: 0 2px 10px rgba(62, 18, 28, 0.3);
  font-size: 0.8rem;
  color: var(--color-text-muted);
  white-space: nowrap;
  max-width: calc(100% - 24px);
}

/* Circular variant of the crop box, used for agent photo cropping — same
   drag mechanics as the card-crop tool above, just round. */
.crop-box-circle { border-radius: 50%; }

/* Agent photo crop popup: shows the full photo with the draggable circle
   sized to hug the image exactly (no letterboxing math needed) since the
   inner wrapper shrinks to the rendered <img> size. */
.photo-crop-stage {
  display: flex;
  justify-content: center;
  align-items: center;
  background: var(--color-bg-alt);
  border-radius: var(--radius);
  padding: 12px;
}
.photo-crop-inner {
  position: relative;
  display: inline-block;
  line-height: 0;
}
.photo-crop-inner img {
  display: block;
  max-width: 100%;
  max-height: 55vh;
  border-radius: 4px;
}

/* ---------------------------------------------------------------------------
   "Stop by our office" section at the bottom of the Agents page.

   The photo and the map sit side by side and stack on narrow screens at the
   same 860px breakpoint the hero uses. Both panes are locked to the photo's
   native 600x385 proportions so the two never disagree in height, and the
   map gets that shape via aspect-ratio rather than a fixed pixel height —
   otherwise the iframe reflows the footer as it loads.
   --------------------------------------------------------------------------- */
.office-section {
  /* The site header is sticky, so without this an /agents.html#office jump
     parks the headline underneath it. */
  scroll-margin-top: calc(var(--header-height) + 24px);
  background: var(--color-bg-alt);
  border-top: 1px solid var(--color-border);
  padding: 56px 0 64px;
  text-align: center;
}
.office-section h2 { margin: 0 0 12px; }

/* The Dyer team's invitation line. Capped and auto-centered so it breaks into
   comfortable lines instead of running the full width of the container. */
.office-invite {
  max-width: 470px;
  margin: 0 auto 20px;
  color: var(--color-text-muted);
  line-height: 1.6;
}

/* <address> italicizes by default in every browser; this is a postal address,
   not an aside, so it's reset to normal and laid out as stacked lines. */
.office-address {
  font-style: normal;
  display: flex;
  flex-direction: column;
  gap: 2px;
  margin: 0 0 28px;
  color: var(--color-text-muted);
  font-size: 1.05rem;
}
.office-address .office-street { font-weight: 600; color: var(--color-text); }
.office-address a { font-weight: 600; }
/* "Main line:" sits a touch quieter than the number it introduces. */
.office-address .office-phone { margin-top: 6px; }

.office-media {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 24px;
  align-items: stretch;
}
.office-photo,
.office-map {
  margin: 0;
  aspect-ratio: 600 / 385;
  border-radius: var(--radius);
  overflow: hidden;
  border: 1px solid var(--color-border);
  background: #fff;
}
/* The photo is only 600px wide, so it fills the column and is cropped
   rather than letterboxed. object-fit keeps it from stretching out of
   proportion on columns that aren't exactly 600x385. */
.office-photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 60%;
}
.office-map iframe {
  display: block;
  width: 100%;
  height: 100%;
  border: 0;
}
.office-cta { margin-top: 24px; }

@media (max-width: 860px) {
  /* Stacked, a full-width pane would blow the 600px photo up past its native
     size and leave the pair looking edge-to-edge. Capping at the photo's real
     width keeps it sharp, and the auto margins center the column. */
  .office-media {
    grid-template-columns: 1fr;
    max-width: 600px;
    margin-left: auto;
    margin-right: auto;
  }
}
@media (max-width: 700px) {
  .office-section { padding: 40px 0 48px; }
}
