/* ==========================================================================
   Northwind Realty — design tokens, layout and components
   A single stylesheet, no build step. Sections:
   1 tokens & base   2 header   3 buttons & forms   4 hero   5 property cards
   6 content blocks  7 filters  8 property detail  9 contact   10 overlays
   ========================================================================== */

/* 1. tokens & base -------------------------------------------------------- */
:root {
  color-scheme: light;

  --canvas: #f6f7f8;
  --surface: #ffffff;
  --surface-subtle: #fafbfb;
  --ink: #1c2026;
  --ink-soft: #3a4149;
  --muted: #878d96;
  --muted-strong: #626a74;
  --line: #e8eaed;
  --line-strong: #dcdfe4;
  --brand: #17594f;
  --brand-dark: #0f423a;
  --brand-soft: #e8f1ef;
  --accent: #b9713f;
  --accent-soft: #f7ece2;
  --accent-ink: #8a4f22;
  /* Ink for anything sitting ON a solid --brand fill. In dark mode --brand is a
     light teal, so white on it would be about 2:1 and unreadable. */
  --on-solid: #ffffff;
  --danger: #a5443a;
  --danger-soft: #f7e9e7;
  --danger-line: #f3c9c9;
  /* A promotion has to read as urgent without reading as an error, so it gets its
     own hue: warmer and brighter than --accent, and clearly not --danger. */
  --hot: #c2451f;
  --hot-soft: #fdeee7;
  --shadow: 0 1px 2px rgb(24 30 38 / 3%), 0 6px 18px rgb(24 30 38 / 4%);
  --shadow-lg: 0 2px 6px rgb(24 30 38 / 4%), 0 18px 40px rgb(24 30 38 / 8%);
  --radius: 14px;
  --radius-sm: 10px;
  --radius-lg: 20px;
  --container: 1200px;

  /* Text and lines that sit ON the dark brand surfaces - the hero, the quote
     cards, the CTA panel, .section--dark. These four values were written out by
     hand in six separate rules, which meant every theme change meant finding all
     six. They are tokens now. */
  --on-brand: #eaf2f0;
  --on-brand-muted: #c3d6d1;
  --on-brand-faint: #9dbab3;
  --on-brand-eyebrow: #8fc0b4;
  --on-brand-hairline: color-mix(in srgb, #fff 12%, transparent);
  --on-brand-fill: rgb(255 255 255 / 7%);
  --on-brand-chip: rgb(255 255 255 / 16%);
  --on-brand-hover: rgb(255 255 255 / 24%);

  /* The near-white fills used for hover and for pressed states on light
     surfaces. Tokens so they can be inverted rather than restated. */
  --surface-hover: #fbfbfc;
  --surface-sunk: #f2f3f4;
  --line-hover: #c8ccd3;

  /* Tints of the brand for focus rings and for translucent surfaces. Written as
     mixes rather than as baked rgb() so that recolouring --brand once moves
     every ring and every wash with it. */
  --brand-wash: color-mix(in srgb, var(--brand) 10%, transparent);
  --brand-wash-strong: color-mix(in srgb, var(--brand) 24%, transparent);
  --canvas-glass: color-mix(in srgb, var(--canvas) 92%, transparent);
  --header-glass: color-mix(in srgb, var(--surface) 82%, transparent);
  --badge-float: color-mix(in srgb, var(--surface) 88%, transparent);

  /* A placeholder tone for the grey boxes behind images that have not loaded,
     and for the empty state in the gallery. */
  --image-placeholder: #e7eaec;

  font-family: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  color: var(--ink);
  background: var(--canvas);
  font-synthesis: none;
  text-rendering: optimizeLegibility;

  /* Headings should not end on a stray single word; body copy should not leave
     rivers of white space. Both are honoured where supported and ignored
     quietly where not. */
  --stack-section: 84px;
}

/* ---- dark palette ---------------------------------------------------------
   Applied when the reader's system asks for it, or when they choose it from the
   header. An explicit choice wins: :root[data-theme="light"] is deliberately not
   matched by the media query below, which is what lets a light preference hold
   on a dark system.

   The palette is written out twice - once for the system preference, once for
   the explicit choice - because a media query and an attribute selector cannot
   share one rule. The inline script in each page head resolves the preference to
   a concrete data-theme before first paint, so in practice only the explicit
   branch runs and there is no flash of the wrong theme. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;
    --canvas: #0d1113;
    --surface: #151b1e;
    --surface-subtle: #11171a;
    --ink: #e7edee;
    --ink-soft: #c2cbcd;
    --muted: #8a9497;
    --muted-strong: #a6b1b4;
    --line: #232d31;
    --line-strong: #323e43;
    --brand: #4fb3a2;
    --brand-dark: #0a2b26;
    --brand-soft: #16302c;
    --accent: #dda06e;
    --accent-soft: #2d2319;
    --accent-ink: #e8b98d;
    --on-solid: #06231f;
    --danger: #e0766c;
    --danger-soft: #2e1c1a;
    --danger-line: #5a2f2a;
    --hot: #ff8f66;
    --hot-soft: #35201a;
    --shadow: 0 1px 2px rgb(0 0 0 / 30%), 0 6px 18px rgb(0 0 0 / 34%);
    --shadow-lg: 0 2px 6px rgb(0 0 0 / 34%), 0 18px 40px rgb(0 0 0 / 44%);
    --surface-hover: #1c2428;
    --surface-sunk: #1a2226;
    --line-hover: #46545a;
    --image-placeholder: #1a2226;
    --header-glass: color-mix(in srgb, #151b1e / 82%, transparent);
    --badge-float: color-mix(in srgb, #151b1e / 88%, transparent);
  }
}
:root[data-theme="dark"] {
  color-scheme: dark;
  --canvas: #0d1113;
  --surface: #151b1e;
  --surface-subtle: #11171a;
  --ink: #e7edee;
  --ink-soft: #c2cbcd;
  --muted: #8a9497;
  --muted-strong: #a6b1b4;
  --line: #232d31;
  --line-strong: #323e43;
  --brand: #4fb3a2;
  --brand-dark: #0a2b26;
  --brand-soft: #16302c;
  --accent: #dda06e;
  --accent-soft: #2d2319;
  --accent-ink: #e8b98d;
  --on-solid: #06231f;
  --danger: #e0766c;
  --danger-soft: #2e1c1a;
  --danger-line: #5a2f2a;
  --hot: #ff8f66;
  --hot-soft: #35201a;
  --shadow: 0 1px 2px rgb(0 0 0 / 30%), 0 6px 18px rgb(0 0 0 / 34%);
  --shadow-lg: 0 2px 6px rgb(0 0 0 / 34%), 0 18px 40px rgb(0 0 0 / 44%);
  --surface-hover: #1c2428;
  --surface-sunk: #1a2226;
  --line-hover: #46545a;
  --image-placeholder: #1a2226;
  --header-glass: color-mix(in srgb, #151b1e / 82%, transparent);
  --badge-float: color-mix(in srgb, #151b1e / 88%, transparent);
}
* { box-sizing: border-box; }
html { scroll-behavior: smooth; overflow-x: clip; scrollbar-gutter: stable; }
/* The header is sticky at 74px and the results page adds a second sticky bar on
   top of it, so anything jumped to by an anchor used to land underneath. */
[id] { scroll-margin-top: 104px; }
@supports not (overflow: clip) {
  html { overflow-x: hidden; }
}
body { margin: 0; min-width: 320px; background: var(--canvas); }
body.nav-open, body.dialog-open { overflow: hidden; }
button, input, select, textarea { font: inherit; color: inherit; }
button, a { -webkit-tap-highlight-color: transparent; }
button { cursor: pointer; }
a { color: inherit; text-decoration: none; }
img { display: block; max-width: 100%; }
svg { display: block; }
h1, h2, h3, h4, p, figure, ul, ol { margin: 0; }
ul, ol { padding: 0; list-style: none; }
.icon { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; flex: 0 0 auto; }
.icon--sm { width: 16px; height: 16px; }
.icon--lg { width: 24px; height: 24px; }
.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0; }
.skip-link { position: fixed; z-index: 100; top: 12px; left: 12px; padding: 10px 16px; border-radius: 8px; color: white; background: var(--brand-dark); transform: translateY(-160%); transition: transform .2s; }
.skip-link:focus { transform: translateY(0); }
:focus-visible { outline: 3px solid #7fb3a5; outline-offset: 3px; }

/* These five used to be inline style attributes, which forced
   style-src 'unsafe-inline' into the pages' Content-Security-Policy. An inline
   attribute is script-adjacent in the ways that matter, so they are ordinary
   rules here and the policy can be strict. Keep it that way: a style="" in a
   template below this line will silently weaken the CSP on every page. */
.gone-note { max-width: 420px; margin: 12px auto 24px; color: var(--muted); }
.prose--spaced { margin-top: 14px; }
.detail-subhead { margin-top: 14px; }
.detail-ask { margin-top: 8px; }
/* The bot-check field: present in the DOM so a script fills it, never shown and
   never focusable. This is what .sr-only already does. */
input[name="botcheck"] { position: absolute; left: -9999px; width: 1px; height: 1px; opacity: 0; }

/* The SVG sprite: in the document, so <use href="#icon-..."> resolves, but off
   the page entirely. It used to carry these four declarations inline. */
.icon-sprite { position: absolute; width: 0; height: 0; overflow: hidden; }

.newsletter-note { color: var(--muted-strong); font-size: 14px; }
.filter-tools--wide { gap: 16px; }
.field--inline { flex-direction: row; align-items: center; gap: 8px; }
.select--compact { padding-block: 8px; }
.section-title--small { font-size: 26px; }
.form--spaced { margin-top: 26px; }
.office-list--spaced { margin-top: 22px; }
.eyebrow--spaced { margin-top: 44px; }

.container { width: min(100% - 48px, var(--container)); margin-inline: auto; }
.section { padding: 84px 0; }
.section--tight { padding: 56px 0; }
.section--surface { background: var(--surface); border-block: 1px solid var(--line); }
.section--dark { background: var(--brand-dark); color: var(--on-brand); }
.section--dark .eyebrow { color: var(--on-brand-eyebrow); }
.section--dark .section-title { color: #fff; }
.section--dark .section-lead { color: var(--on-brand-muted); }
.eyebrow { margin: 0 0 12px; color: var(--brand); font-size: 11px; font-weight: 700; letter-spacing: 1.4px; text-transform: uppercase; }
.section-head { max-width: 620px; margin-bottom: 40px; }
.section-head--split { display: flex; align-items: flex-end; justify-content: space-between; gap: 28px; max-width: none; }
.section-title { font-size: clamp(26px, 3.2vw, 38px); font-weight: 700; letter-spacing: -1.1px; line-height: 1.12; }
.section-lead { margin-top: 14px; color: var(--muted-strong); font-size: 16px; line-height: 1.65; }
.section-link { display: inline-flex; align-items: center; gap: 7px; color: var(--brand); font-size: 14px; font-weight: 600; white-space: nowrap; }
.section-link:hover { gap: 11px; }
.section-link .icon { transition: transform .18s; }

/* 2. header --------------------------------------------------------------- */
.site-header { position: sticky; z-index: 40; top: 0; background: var(--header-glass); border-bottom: 1px solid transparent; backdrop-filter: blur(14px); transition: border-color .2s, box-shadow .2s; }
.site-header.is-stuck { border-bottom-color: var(--line); box-shadow: 0 1px 20px rgb(24 30 38 / 4%); }
.header-inner { display: flex; align-items: center; gap: 34px; height: 74px; }
.brand { display: flex; align-items: center; gap: 11px; font-size: 19px; font-weight: 700; letter-spacing: -.6px; }
.brand-mark { position: relative; width: 28px; height: 28px; flex: 0 0 auto; }
.brand-mark i { position: absolute; bottom: 0; width: 11px; background: var(--brand); border-radius: 2px; }
.brand-mark i:nth-child(1) { left: 0; height: 14px; }
.brand-mark i:nth-child(2) { left: 9px; height: 22px; }
.brand-mark i:nth-child(3) { right: 0; height: 10px; background: var(--accent); }
.brand-mark::after { content: ""; position: absolute; left: 9px; top: 0; width: 11px; height: 11px; background: var(--brand-dark); clip-path: polygon(50% 0, 100% 100%, 0 100%); }
.main-nav { display: flex; align-items: center; gap: 6px; margin-right: auto; }
.main-nav a { padding: 9px 13px; border-radius: 9px; color: var(--muted-strong); font-size: 14.5px; font-weight: 500; transition: color .15s, background .15s; }
.main-nav a:hover { color: var(--ink); background: var(--surface-sunk); }
.main-nav a[aria-current="page"] { color: var(--brand); background: var(--brand-soft); font-weight: 600; }
.header-actions { display: flex; align-items: center; gap: 10px; }

/* Currency picker. The label is .sr-only, so the select and the note stack in
   a column and the whole thing lines up with the button beside it. */
.currency-picker { position: relative; display: flex; flex-direction: column; align-items: flex-end; gap: 3px; }
.currency-picker[hidden] { display: none; }
.currency-picker select { max-width: 190px; padding: 9px 30px 9px 11px; border: 1px solid var(--line-strong); border-radius: 10px; background: var(--surface); color: var(--ink-soft); font-size: 13.5px; font-weight: 500; cursor: pointer; transition: border-color .15s, box-shadow .15s; }
.currency-picker select:hover { border-color: var(--brand); }
.currency-picker select:focus { border-color: var(--brand); box-shadow: 0 0 0 3px var(--brand-wash); outline: none; }
.currency-picker select:disabled { color: var(--muted); cursor: progress; }
.currency-note { color: var(--muted); font-size: 12.5px; font-weight: 500; white-space: nowrap; }
.currency-note[hidden] { display: none; }
.icon-button { display: inline-flex; align-items: center; justify-content: center; width: 38px; height: 38px; padding: 0; border: 1px solid var(--line-strong); border-radius: 10px; color: var(--ink-soft); background: var(--surface); transition: border-color .15s, background .15s; }
.icon-button:hover { border-color: var(--line-hover); background: var(--surface-hover); }
.menu-button { display: none; }
.nav-scrim { display: none; }

/* 3. buttons & forms ------------------------------------------------------ */
.button { display: inline-flex; align-items: center; justify-content: center; gap: 8px; padding: 12px 20px; border: 1px solid transparent; border-radius: 10px; font-size: 14.5px; font-weight: 600; white-space: nowrap; transition: background .15s, border-color .15s, color .15s, transform .15s; }
.button:active { transform: translateY(1px); }
.button--primary { color: var(--on-solid); background: var(--brand); }
.button--primary:hover { background: var(--brand-dark); }
.button--secondary { color: var(--ink-soft); background: var(--surface); border-color: var(--line-strong); }
.button--secondary:hover { border-color: var(--line-hover); background: var(--surface-hover); }
.button--ghost { color: var(--brand); background: transparent; }
.button--ghost:hover { background: var(--brand-soft); }
.button--light { color: var(--brand-dark); background: #fff; }
.button--light:hover { background: #eef4f2; }
.button--block { width: 100%; }
.field { display: flex; flex-direction: column; gap: 7px; min-width: 0; }
.field > span { color: var(--muted-strong); font-size: 13px; font-weight: 600; }
.field small { color: var(--muted); font-weight: 500; }
.field input, .field select, .field textarea { width: 100%; padding: 11px 13px; border: 1px solid var(--line-strong); border-radius: 10px; background: var(--surface); font-size: 14.5px; transition: border-color .15s, box-shadow .15s; }
.field textarea { min-height: 118px; resize: vertical; }
.field input:focus, .field select:focus, .field textarea:focus { border-color: var(--brand); box-shadow: 0 0 0 3px var(--brand-wash); outline: none; }
.field input::placeholder, .field textarea::placeholder { color: #a8adb5; }
.field-error { color: var(--danger); font-size: 13px; }
.checkbox { display: flex; align-items: center; gap: 10px; color: var(--muted-strong); font-size: 14px; }
.checkbox input { width: 17px; height: 17px; accent-color: var(--brand); }
.badge { display: inline-flex; align-items: center; gap: 6px; padding: 5px 10px; border-radius: 999px; font-size: 12px; font-weight: 700; letter-spacing: .3px; }
.badge--brand { color: var(--brand); background: var(--brand-soft); }
.badge--accent { color: var(--accent-ink); background: var(--accent-soft); }
.badge--solid { color: var(--on-solid); background: var(--brand); }
.badge--muted { color: var(--muted-strong); background: var(--badge-float); }
/* Hot deals. The badge is deliberately the loudest thing on a card, because the
   whole point of the flag is that it gets noticed. It is still a badge and not a
   ribbon so it sits in the same row as the rest rather than fighting them. */
.badge--hot { color: #fff; background: var(--hot); letter-spacing: .6px; }
.badge--hot::before {
  content: "";
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
  animation: hot-pulse 2.4s ease-in-out infinite;
}
@keyframes hot-pulse { 0%, 100% { opacity: 1; } 50% { opacity: .35; } }
/* The pulse is the one thing on the page that moves without being asked to, so it
   is switched off with the rest of the motion for anybody who asked for that. */
@media (prefers-reduced-motion: reduce) {
  .badge--hot::before { animation: none; }
}

/* A hot card gets a warm edge rather than a bigger one: the card grid is
   auto-fill, so a card that grew would change the number of columns. */
.card--hot { border-color: var(--hot); box-shadow: 0 0 0 1px var(--hot), var(--shadow); }
.card--hot:hover { box-shadow: 0 0 0 1px var(--hot), var(--shadow-lg); }

/* Short stays. The night rate leads because it is the one a weekend is compared
   on; the week and month sit beside it in the quieter ink. */
.card-price--stay { display: flex; align-items: baseline; flex-wrap: wrap; gap: 4px 12px; }
.card-price--stay strong { font-weight: 700; }
.card-price--stay span { color: var(--muted); font-size: 14px; font-weight: 500; }
.card-stay {
  display: flex;
  align-items: center;
  gap: 7px;
  margin-top: 12px;
  color: var(--muted);
  font-size: 13px;
  font-weight: 500;
}
.card-stay .icon { color: var(--hot); }

/* The rates table on a detail page. */
.rates { margin: 26px 0 0; border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden; }
.rates-row { display: flex; align-items: center; justify-content: space-between; gap: 16px; padding: 14px 18px; background: var(--surface); }
.rates-row + .rates-row { border-top: 1px solid var(--line); }
.rates-row dt { color: var(--muted-strong); font-size: 13.5px; font-weight: 600; }
.rates-row dd { margin: 0; font-size: 16px; font-weight: 700; letter-spacing: -.3px; }
.rates-note { display: flex; align-items: center; gap: 8px; padding: 12px 18px; border-top: 1px solid var(--line); color: var(--muted); background: var(--surface-subtle); font-size: 13px; }

/* Charges around the stay. Set apart from the rates because they are not part of
   what the guest sleeps in: the deposit comes back, the cleaning fee happens once
   however long the stay is. Same weight as a rate would read as a charge every
   night, and the note beside each label is what stops that. */
.rates-row--term { background: var(--surface-subtle); }
.rates-row--term dt { color: var(--muted); font-weight: 500; }
.rates-row--term dt small { display: block; color: var(--muted); font-weight: 400; font-size: 12.5px; }
.rates-row--term dd { font-size: 14.5px; font-weight: 600; color: var(--muted-strong); letter-spacing: 0; }

/* What a longer term works out at per night.
   Printed under the rate rather than beside it, because it is a derivation of that
   rate rather than a second rate - and putting it at the same weight invites the
   reader to compare the two numbers directly, which is the mistake. */
.rates-equivalent {
  display: block;
  margin-top: 4px;
  color: var(--muted);
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0;
}
.rates-saving { color: var(--brand); font-weight: 600; }

/* The call to action under the rates. A rates table with nothing to press is a
   price list; this is where "can I have those dates" gets answered. */
.rates-cta {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 12px 18px;
  margin-top: 18px;
}
.rates-cta-note {
  display: flex;
  align-items: center;
  gap: 7px;
  margin: 0;
  color: var(--muted);
  font-size: 13.5px;
}
.rates-cta-note .icon { color: var(--brand); }

/* The hot banner on a detail page, and the strip on the home page. */
.hot-banner {
  display: flex;
  align-items: center;
  gap: 11px;
  margin-bottom: 20px;
  padding: 13px 18px;
  border: 1px solid var(--hot);
  border-radius: var(--radius-sm);
  color: var(--hot);
  background: var(--hot-soft);
  font-size: 14px;
  font-weight: 600;
}

/* A priced promotion. The badge alone said "reduced" without saying by how much,
   which is the one half of the information a reader needs to decide anything. The
   was-figure is struck through and quiet so it cannot be mistaken for the price. */
.hot-banner--priced { display: block; }
.hot-banner-line { display: flex; align-items: center; gap: 11px; margin: 0; }
.hot-deal {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 4px 14px;
  margin: 8px 0 0 30px;
  color: var(--muted-strong);
  font-size: 15px;
}
.hot-deal-was { text-decoration: line-through; opacity: .7; font-weight: 500; }
.hot-deal-now { color: var(--hot); font-weight: 700; }
.hot-deal-now small { color: var(--muted); font-size: 12.5px; font-weight: 500; letter-spacing: 0; }
.hot-deal-save { font-size: 13.5px; font-weight: 600; }

/* The same promotion on a card. Sits under the price rather than inside it, so the
   struck-through figure is never adjacent to the one number being charged. */
.card-deal {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 4px 10px;
  margin: -6px 0 10px;
  font-size: 13px;
  font-weight: 600;
}
.card-deal-was { color: var(--muted); text-decoration: line-through; font-weight: 500; }
.card-deal-save { color: var(--hot); }
.card-rate-equiv { color: var(--muted); font-size: 13px; font-weight: 500; }

.hot-strip { display: grid; grid-template-columns: repeat(auto-fill, minmax(310px, 1fr)); gap: 26px; }
.hot-empty { color: var(--muted); font-size: 15px; }
/* The shortcut into just the promotions, sitting where the sort control is so it
   reads as a way of arranging the results rather than a separate page. */
.hot-link {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 7px 14px;
  border: 1px solid var(--hot);
  border-radius: 999px;
  color: var(--hot);
  background: var(--hot-soft);
  font-size: 13.5px;
  font-weight: 600;
  white-space: nowrap;
  transition: background .15s, border-color .15s;
}
.hot-link:hover { background: color-mix(in srgb, var(--hot) 14%, var(--hot-soft)); }
.hot-link::before { content: ""; width: 7px; height: 7px; border-radius: 50%; background: currentColor; }

/* The short-stay panel on the agent upload form. A fieldset because the boxes
   and the rates belong together as one question, and the legend is what a screen
   reader announces when focus lands in there. */
.short-stay { margin: 18px 0 0; padding: 16px; border: 1px solid var(--line); border-radius: 12px; }
.short-stay[hidden] { display: none; }
.short-stay legend { padding: 0 6px; color: var(--muted-strong); font-size: 12.5px; font-weight: 700; letter-spacing: .3px; }
.short-stay .field-hint { margin: 0 0 14px; }
/* A row of checkboxes that reads as one question. Used by the agent form's short
   stays and by the same panel in the admin editor, so it lives here rather than
   in either stylesheet. */
.check-row { display: flex; flex-wrap: wrap; gap: 12px 20px; align-items: center; }
.check-row .field--check { display: inline-flex; align-items: center; gap: 7px; font-size: 14px; white-space: nowrap; }
[data-stay-only][hidden] { display: none; }
.grid-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; margin-bottom: 12px; }
@media (max-width: 560px) { .grid-3 { grid-template-columns: 1fr; } }

/* 4. hero & search -------------------------------------------------------- */
/* The hero background used to be a flat green wash. The property slideshow now
   fills it, so ::before becomes the scrim that keeps the headline legible over a
   photograph: heaviest at the left, where the copy sits, clearing toward the
   right so the picture is not simply blacked out. The flat green stays on .hero
   itself as the paint underneath, for the frame before the first image decodes
   and for anyone the script never reaches. */
.hero { position: relative; overflow: hidden; padding: 96px 0 108px; background: var(--brand-dark); color: #eef4f2; }
.hero::before { content: ""; position: absolute; inset: 0; z-index: 1; background: linear-gradient(96deg, var(--brand-dark) 4%, rgb(15 66 58 / 84%) 38%, rgb(15 66 58 / 52%) 72%, rgb(15 66 58 / 34%) 100%), radial-gradient(1000px 420px at 78% -10%, rgb(185 113 63 / 26%), transparent 60%); }
.hero::after { content: ""; position: absolute; inset: auto 0 0; z-index: 1; height: 120px; background: linear-gradient(to top, var(--canvas), transparent); }
.hero-inner { position: relative; z-index: 2; max-width: 720px; }
.hero .eyebrow { color: var(--on-brand-eyebrow); }
.hero h1 { font-size: clamp(34px, 5.2vw, 60px); font-weight: 700; letter-spacing: -2px; line-height: 1.05; color: #fff; }
.hero h1 em { font-style: normal; color: #e3b98d; }
.hero-lead { max-width: 560px; margin-top: 20px; color: var(--on-brand-muted); font-size: 17px; line-height: 1.65; }
.hero-actions { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 30px; }
.hero-meta { display: flex; flex-wrap: wrap; gap: 28px; margin-top: 46px; }
.hero-meta div { display: flex; flex-direction: column; gap: 3px; }
.hero-meta strong { color: #fff; font-size: 24px; font-weight: 700; letter-spacing: -.8px; }
.hero-meta span { color: var(--on-brand-faint); font-size: clamp(13px, 1vw, 14px); }

/* hero slideshow ---------------------------------------------------------- */
.hero-slides { position: absolute; inset: 0; z-index: 0; }
.hero-slide { position: absolute; inset: 0; opacity: 0; transition: opacity 1.1s ease; }
.hero-slide.is-active { opacity: 1; }
.hero-slide img { width: 100%; height: 100%; object-fit: cover; }

/* A slow push-in, so a frame that is held for several seconds still reads as film
   rather than as a still. Runs only on the active slide, and so only for the
   length of its own dwell. */
.hero-slide.is-active img { animation: hero-drift 14s ease-out both; }
@keyframes hero-drift { from { transform: scale(1.03); } to { transform: scale(1.13); } }

.hero-slider { position: relative; z-index: 2; display: flex; align-items: center; flex-wrap: wrap; gap: 16px 22px; margin-top: 42px; }
.hero-slider[hidden] { display: none; }

.hero-slide-caption { display: flex; align-items: center; gap: 10px; flex: 1; min-width: 0; color: var(--on-brand-muted); font-size: clamp(13.5px, 1vw, 15px); }
.hero-slide-label { flex: 0 0 auto; padding: 3px 9px; border-radius: 999px; color: #fff; background: var(--on-brand-chip); font-size: 11px; font-weight: 700; letter-spacing: 1.1px; text-transform: uppercase; }
.hero-slide-caption a { min-width: 0; overflow: hidden; color: #fff; font-weight: 600; text-overflow: ellipsis; white-space: nowrap; }
.hero-slide-caption a:hover { text-decoration: underline; }

.hero-slide-controls { display: flex; align-items: center; gap: 8px; }
.hero-slide-btn { display: inline-flex; align-items: center; justify-content: center; width: 34px; height: 34px; padding: 0; border: 1px solid color-mix(in srgb, #fff 32%, transparent); border-radius: 9px; color: #fff; background: color-mix(in srgb, #fff 12%, transparent); backdrop-filter: blur(6px); transition: background .15s, border-color .15s; }
.hero-slide-btn:hover { border-color: color-mix(in srgb, #fff 58%, transparent); background: var(--on-brand-hover); }
.hero-slide-btn .icon { width: 17px; height: 17px; }
/* One arrow glyph serves both directions; mirrored rather than drawn twice. */
.hero-slide-btn .icon--flip { transform: scaleX(-1); }
/* The play triangle is a filled shape, and the rest of the sprite is stroked. */
.hero-slide-btn .icon--fill { fill: currentColor; stroke: none; }

/* The dots are 9px of ink, which is well under the 24px minimum target size in
   WCAG 2.2. The button keeps a 9px circle drawn by ::before and takes the full
   24px, so the visible dot is unchanged and the thing you have to hit is not. */
.hero-dots { display: flex; align-items: center; gap: 2px; padding-inline: 2px; }
.hero-dot { position: relative; width: 24px; height: 24px; padding: 0; border: 0; border-radius: 50%; background: none; }
.hero-dot::before { content: ""; position: absolute; left: 50%; top: 50%; width: 9px; height: 9px; border-radius: 50%; background: color-mix(in srgb, #fff 38%, transparent); transition: background .15s, transform .15s; }
.hero-dot:hover::before { background: color-mix(in srgb, #fff 68%, transparent); }
.hero-dot[aria-current="true"]::before { background: #fff; transform: translate(-50%, -50%) scale(1.28); }

.search-panel { position: relative; z-index: 2; margin-top: -62px; padding: 10px; border: 1px solid var(--line); border-radius: var(--radius-lg); background: var(--surface); box-shadow: var(--shadow-lg); }
.search-tabs { display: flex; gap: 4px; padding: 4px; }
.search-tab { padding: 9px 18px; border: 0; border-radius: 9px; color: var(--muted-strong); background: transparent; font-size: 14px; font-weight: 600; }
.search-tab.is-active { color: var(--brand); background: var(--brand-soft); }
.search-form { display: grid; grid-template-columns: 1.6fr 1fr 1fr auto; gap: 12px; align-items: end; padding: 12px 6px 6px; border-top: 1px solid var(--line); }
.search-form .button { height: 44px; }

/* 5. property cards ------------------------------------------------------- */
.card-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(310px, 1fr)); gap: 26px; }
.property-card { position: relative; display: flex; flex-direction: column; overflow: hidden; border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface); box-shadow: var(--shadow); transition: transform .2s, box-shadow .2s, border-color .2s; }
.property-card:hover { transform: translateY(-4px); border-color: var(--line-strong); box-shadow: var(--shadow-lg); }
.card-media { position: relative; aspect-ratio: 4 / 3; overflow: hidden; background: var(--image-placeholder); }
.card-media img { width: 100%; height: 100%; object-fit: cover; transition: transform .45s ease; }
.property-card:hover .card-media img { transform: scale(1.045); }
.card-badges { position: absolute; inset: 12px 12px auto; display: flex; gap: 6px; }
.favorite-button { position: absolute; z-index: 2; top: 12px; right: 12px; display: inline-flex; align-items: center; justify-content: center; width: 34px; height: 34px; padding: 0; border: 1px solid color-mix(in srgb, #fff 65%, transparent); border-radius: 50%; color: var(--ink-soft); background: rgb(255 255 255 / 88%); backdrop-filter: blur(6px); transition: color .15s, background .15s, transform .15s; }
.favorite-button:hover { transform: scale(1.07); background: #fff; }
.favorite-button .icon { fill: none; }
.favorite-button[aria-pressed="true"] { color: #fff; background: var(--danger); border-color: var(--danger); }
.favorite-button[aria-pressed="true"] .icon { fill: currentColor; }
.card-body { display: flex; flex-direction: column; flex: 1; padding: 18px 18px 20px; }
.card-price { font-size: 21px; font-weight: 700; letter-spacing: -.7px; }
.card-price small { margin-left: 6px; color: var(--muted); font-size: clamp(13px, .95vw, 14px); font-weight: 500; letter-spacing: 0; }
.card-title { margin-top: 7px; font-size: 16px; font-weight: 600; }
.card-address { display: flex; align-items: baseline; gap: 6px; margin-top: 6px; color: var(--muted); font-size: clamp(14px, 1.05vw, 15.5px); line-height: 1.45; }
.card-specs { display: flex; flex-wrap: wrap; gap: 6px 16px; margin-top: 16px; padding-top: 15px; border-top: 1px solid var(--line); color: var(--muted-strong); font-size: clamp(14px, 1.02vw, 15px); line-height: 1.5; }
.card-specs span { display: inline-flex; align-items: center; gap: 6px; }
.card-footer { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-top: 16px; }
.card-agent { display: flex; align-items: center; gap: 8px; color: var(--muted); font-size: clamp(13px, 1vw, 14.5px); }
.avatar { display: inline-flex; align-items: center; justify-content: center; width: 28px; height: 28px; border-radius: 9px; font-size: 11px; font-weight: 700; letter-spacing: -.2px; }
.avatar--teal { color: #eaf2f0; background: #2c6156; }
.avatar--sand { color: #6b4425; background: #ecd9c2; }
.avatar--lilac { color: #4b3f63; background: #ded5ea; }
.avatar--slate { color: #eef1f3; background: #4a5560; }
.avatar--lg { width: 46px; height: 46px; border-radius: 13px; font-size: 15px; }
.card--sold { opacity: .72; }

/* list view */
.card-grid.is-list { grid-template-columns: 1fr; }
.card-grid.is-list .property-card { display: grid; grid-template-columns: 320px 1fr; }
.card-grid.is-list .card-media { aspect-ratio: auto; height: 100%; min-height: 210px; }
.card-grid.is-list .card-body { padding: 22px 24px; }
.card-grid.is-list .card-title { font-size: 19px; }
.card-grid.is-list .card-description { display: -webkit-box; -webkit-line-clamp: 2; line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; margin-top: 12px; color: var(--muted-strong); font-size: 14px; line-height: 1.6; }
.empty-state { padding: 70px 24px; border: 1px dashed var(--line-strong); border-radius: var(--radius); background: var(--surface); text-align: center; }
.empty-state h3 { font-size: 19px; }
.empty-state p { margin: 10px auto 22px; max-width: 380px; color: var(--muted); line-height: 1.6; }

/* 6. content blocks ------------------------------------------------------- */
.stat-band { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1px; overflow: hidden; border: 1px solid var(--line); border-radius: var(--radius); background: var(--line); }
.stat-band div { display: flex; flex-direction: column; gap: 6px; padding: 30px 26px; background: var(--surface); }
.stat-band strong { font-size: 30px; font-weight: 700; letter-spacing: -1px; }
.stat-band span { color: var(--muted); font-size: clamp(13.5px, 1vw, 15px); }

.value-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 26px; }
.value-card { padding: 28px; border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface); box-shadow: var(--shadow); }
.value-icon { display: inline-flex; align-items: center; justify-content: center; width: 46px; height: 46px; margin-bottom: 18px; border-radius: 13px; color: var(--brand); background: var(--brand-soft); }
.value-card h3 { font-size: 17.5px; font-weight: 650; letter-spacing: -.3px; }
.value-card p { margin-top: 10px; color: var(--muted-strong); font-size: 14.5px; line-height: 1.65; }

.split { display: grid; grid-template-columns: 1fr 1fr; gap: 64px; align-items: center; }
.split--reverse .split-media { order: 2; }
.split-media { position: relative; }
.split-media img { width: 100%; border-radius: var(--radius-lg); box-shadow: var(--shadow-lg); }
.split-media .badge { position: absolute; right: 18px; bottom: 18px; }
.check-list { display: grid; gap: 13px; margin-top: 24px; }
.check-list li { display: flex; align-items: flex-start; gap: 11px; color: var(--ink-soft); font-size: 15px; line-height: 1.55; }
.check-list .icon { margin-top: 2px; color: var(--brand); }

.agent-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 22px; }
.agent-card { padding: 26px 22px; border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface); text-align: center; box-shadow: var(--shadow); transition: transform .2s, box-shadow .2s; }
.agent-card:hover { transform: translateY(-3px); box-shadow: var(--shadow-lg); }
.agent-card h3 { margin-top: 14px; font-size: 16px; font-weight: 650; }
.agent-card .agent-role { color: var(--muted); font-size: 13px; }
.agent-card .agent-stat { margin-top: 14px; padding-top: 14px; border-top: 1px solid var(--line); color: var(--muted-strong); font-size: 13px; }
.agent-card .agent-links { display: flex; justify-content: center; gap: 8px; margin-top: 14px; }

.quote-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 24px; }
.quote-card { display: flex; flex-direction: column; gap: 18px; padding: 28px; border-radius: var(--radius); background: var(--on-brand-fill); border: 1px solid var(--on-brand-hairline); }
.quote-card blockquote { margin: 0; color: var(--on-brand); font-size: 15.5px; line-height: 1.7; }
.quote-card figcaption { display: flex; align-items: center; gap: 11px; margin-top: auto; color: var(--on-brand-faint); font-size: 13.5px; }
.quote-card figcaption strong { color: #fff; font-weight: 600; }

.cta-panel { display: grid; grid-template-columns: 1.2fr auto; gap: 32px; align-items: center; padding: 46px 50px; border-radius: var(--radius-lg); background: var(--brand); color: var(--on-solid); }
.cta-panel h2 { color: var(--on-solid); font-size: clamp(22px, 2.6vw, 30px); font-weight: 700; letter-spacing: -.9px; }
.cta-panel p { margin-top: 12px; color: var(--on-brand-muted); font-size: 15px; line-height: 1.6; }
.cta-panel .button--light { padding: 13px 24px; }
.cta-panel .button--secondary { color: #eaf2f0; background: transparent; border-color: color-mix(in srgb, #fff 32%, transparent); }
.cta-panel .button--secondary:hover { background: rgb(255 255 255 / 10%); }
.cta-actions { display: flex; flex-wrap: wrap; gap: 12px; }

/* footer */
.site-footer { padding: 62px 0 30px; border-top: 1px solid var(--line); background: var(--surface); }
.footer-grid { display: grid; grid-template-columns: 1.6fr repeat(3, 1fr); gap: 40px; }
.footer-brand p { max-width: 300px; margin-top: 16px; color: var(--muted); font-size: 14px; line-height: 1.65; }
.footer-social { display: flex; gap: 9px; margin-top: 20px; }
.footer-col h3 { margin-bottom: 16px; color: var(--ink); font-size: 13px; font-weight: 700; letter-spacing: .6px; text-transform: uppercase; }
.footer-col li + li { margin-top: 11px; }
.footer-col a, .footer-col span { color: var(--muted-strong); font-size: 14px; }
.footer-col a:hover { color: var(--brand); }
.newsletter { display: flex; gap: 8px; margin-top: 16px; }
.newsletter input { flex: 1; min-width: 0; padding: 11px 13px; border: 1px solid var(--line-strong); border-radius: 10px; font-size: 14px; }
.newsletter input:focus { border-color: var(--brand); outline: none; box-shadow: 0 0 0 3px var(--brand-wash); }
.footer-bottom { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 14px; margin-top: 48px; padding-top: 24px; border-top: 1px solid var(--line); color: var(--muted); font-size: 13.5px; }
.footer-bottom nav { display: flex; gap: 20px; }

/* 7. page header & filters ------------------------------------------------ */
.page-header { padding: 54px 0 40px; border-bottom: 1px solid var(--line); background: var(--surface); }
.page-header h1 { font-size: clamp(27px, 3.6vw, 40px); font-weight: 700; letter-spacing: -1.3px; }
.page-header p { max-width: 620px; margin-top: 12px; color: var(--muted-strong); line-height: 1.65; }
.breadcrumbs { display: flex; align-items: center; gap: 8px; margin-bottom: 16px; color: var(--muted); font-size: 13.5px; }
.breadcrumbs a:hover { color: var(--brand); }
.filter-bar { position: sticky; z-index: 20; top: 74px; padding: 16px 0; background: var(--canvas-glass); border-bottom: 1px solid var(--line); backdrop-filter: blur(10px); }
.filter-form { display: grid; grid-template-columns: minmax(200px, 1.6fr) repeat(4, minmax(118px, 1fr)) auto; gap: 11px; align-items: end; }
.filter-form .field input, .filter-form .field select { height: 44px; padding-block: 0; }
.filter-tools { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 14px; margin-top: 16px; }
.result-count { color: var(--muted-strong); font-size: 14px; }
.result-count strong { color: var(--ink); }
.chip-row { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 14px; }
.chip { display: inline-flex; align-items: center; gap: 7px; padding: 7px 9px 7px 13px; border: 1px solid var(--line-strong); border-radius: 999px; color: var(--ink-soft); background: var(--surface); font-size: 13.5px; }
.chip button { display: inline-flex; padding: 0; border: 0; color: var(--muted); background: transparent; }
.chip button:hover { color: var(--danger); }
.view-toggle { display: inline-flex; padding: 3px; border: 1px solid var(--line-strong); border-radius: 10px; background: var(--surface); }
.view-toggle button { display: inline-flex; padding: 7px 11px; border: 0; border-radius: 7px; color: var(--muted); background: transparent; }
.view-toggle button.is-active { color: var(--brand); background: var(--brand-soft); }
.load-more { display: flex; justify-content: center; margin-top: 40px; }

/* 8. property detail ------------------------------------------------------ */
.detail-layout { display: grid; grid-template-columns: minmax(0, 1fr) 336px; gap: 40px; align-items: start; }
.gallery { display: grid; gap: 12px; }
.gallery-main { position: relative; overflow: hidden; border-radius: var(--radius-lg); background: var(--image-placeholder); aspect-ratio: 16 / 10; }
.gallery-main img { width: 100%; height: 100%; object-fit: cover; }
.gallery-thumbs { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; }
.gallery-thumbs button { padding: 0; overflow: hidden; border: 1px solid var(--line); border-radius: var(--radius-sm); background: var(--image-placeholder); aspect-ratio: 4 / 3; transition: border-color .15s, opacity .15s; }
.gallery-thumbs button img { width: 100%; height: 100%; object-fit: cover; }
.gallery-thumbs button:hover { opacity: .85; }
.gallery-thumbs button[aria-current="true"] { border-color: var(--brand); box-shadow: 0 0 0 2px var(--brand-soft); }
.detail-title { display: flex; align-items: flex-start; justify-content: space-between; gap: 20px; margin-top: 30px; }
.detail-title h1 { font-size: clamp(25px, 3vw, 34px); font-weight: 700; letter-spacing: -1.1px; }
.detail-price { margin-top: 8px; font-size: 26px; font-weight: 700; letter-spacing: -.9px; }
.detail-price small { margin-left: 7px; color: var(--muted); font-size: 13.5px; font-weight: 500; }
.detail-actions { display: flex; gap: 10px; flex: 0 0 auto; }
.detail-actions .favorite-button { position: static; border-color: var(--line-strong); color: var(--ink-soft); }
/* The dividers are drawn by each cell casting a 1px shadow right and down over
   a surface-coloured container, NOT by the old `gap: 1px` + grey background
   trick. That trick paints the whole unfilled remainder of the last row grey,
   which reads as an empty card rather than as space - visible on any grid whose
   item count is not a multiple of its column count (the terms panel has five
   fields in three columns). Shadows clip against `overflow: hidden`, so the
   outermost ones are cut by the container's own border and no edge doubles. */
.spec-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 0; margin: 30px 0; overflow: hidden; border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface); }
.spec-grid > div { display: flex; flex-direction: column; gap: 5px; padding: 20px 18px; background: var(--surface); box-shadow: 1px 0 0 var(--line), 0 1px 0 var(--line); }
.spec-grid dt { color: var(--muted); font-size: clamp(13px, .95vw, 14px); }
.spec-grid dd { margin: 0; font-size: 16px; font-weight: 650; }
.prose { color: var(--muted-strong); font-size: 15.5px; line-height: 1.75; }
.prose + .prose { margin-top: 14px; }
.detail-section { margin-top: 40px; }
.detail-section h2 { font-size: 19px; font-weight: 650; letter-spacing: -.4px; }
.feature-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 12px 24px; margin-top: 20px; }
.feature-grid li { display: flex; align-items: center; gap: 10px; color: var(--ink-soft); font-size: 14.5px; }
.feature-grid .icon { color: var(--brand); }
.agent-card--sticky { position: sticky; top: 96px; padding: 26px; border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface); box-shadow: var(--shadow); }
.agent-card--sticky h2 { font-size: 17px; font-weight: 650; }
.agent-card--sticky .agent-role { margin-top: 3px; color: var(--muted); font-size: 13.5px; }
.agent-card--sticky p { margin: 18px 0; color: var(--muted-strong); font-size: 14px; line-height: 1.6; }
.agent-meta { display: flex; flex-direction: column; gap: 11px; padding: 16px 0; margin-bottom: 18px; border-block: 1px solid var(--line); }
.agent-meta a { display: flex; align-items: center; gap: 10px; color: var(--ink-soft); font-size: 14px; }
.agent-meta a:hover { color: var(--brand); }
.agent-meta .icon { color: var(--muted); }
.not-found { padding: 90px 24px; text-align: center; }

/* ---- listing truth ---------------------------------------------------------
   The freshness line on a card, and the panel that backs it up on the detail
   page. The colour is doing real work: a confirmation that is eight weeks old
   has to look different from one made this morning, or the whole feature is
   just words. */
.card-truth { display: flex; align-items: center; gap: 7px; margin-top: 10px; font-size: 12.5px; font-weight: 500; }
.card-truth .icon { flex: none; }
.card-truth--fresh { color: var(--brand); }
.card-truth--aging { color: var(--accent-ink); }
.card-truth--old, .card-truth--none { color: var(--danger); }
/* The score is separated from the sentence by a hairline rather than a bullet:
   it is a different kind of statement, and running them together reads as one
   vague claim. */
.card-truth-score { margin-left: auto; padding-left: 10px; border-left: 1px solid var(--line); color: var(--muted); font-size: 12px; white-space: nowrap; }

.truth-panel { padding: 26px; border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface); }
.truth-stamp { display: inline-flex; align-items: center; gap: 8px; padding: 8px 14px; border-radius: 999px; font-size: 13px; font-weight: 650; white-space: nowrap; }
.truth-stamp--fresh { color: var(--brand); background: var(--brand-soft); }
.truth-stamp--aging { color: var(--accent-ink); background: var(--accent-soft); }
.truth-stamp--old, .truth-stamp--none { color: var(--danger); background: var(--danger-soft); }

/* A definition list rather than a grid of boxes: these are long sentences, and a
   fixed column would either clip them or waste half the width on the label. */
.truth-rows { display: grid; gap: 0; margin: 22px 0 0; }
.truth-rows > div { display: grid; grid-template-columns: 190px 1fr; gap: 16px; padding: 13px 0; border-top: 1px solid var(--line); }
.truth-rows dt { color: var(--muted); font-size: 13.5px; font-weight: 600; }
.truth-rows dd { margin: 0; font-size: 14.5px; line-height: 1.55; }
.truth-gap { display: flex; align-items: flex-start; gap: 9px; margin: 18px 0 0; padding: 13px 15px; border: 1px solid var(--line); border-radius: var(--radius-sm); color: var(--accent-ink); background: var(--accent-soft); font-size: 13.5px; line-height: 1.55; }
.truth-gap .icon { flex: none; margin-top: 2px; }
.truth-foot { display: flex; align-items: center; gap: 16px; margin-top: 20px; padding-top: 18px; border-top: 1px solid var(--line); }
.truth-foot-note { margin: 0; color: var(--muted); font-size: 13px; line-height: 1.5; }

/* ---- valuation -------------------------------------------------------------
   The range is the headline and the reasoning sits under it. Colour is used
   only for the confidence chip, so the eye lands on the number first. */
.valuation-range { display: flex; flex-wrap: wrap; align-items: baseline; gap: 10px; margin: 16px 0 0; font-size: clamp(22px, 2.6vw, 29px); font-weight: 700; letter-spacing: -.8px; }
.valuation-dash { color: var(--muted); font-size: 15px; font-weight: 500; letter-spacing: 0; }
.valuation-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 16px; margin-top: 12px; color: var(--muted); font-size: 13.5px; }
.valuation-confidence { padding: 4px 11px; border-radius: 999px; font-size: 12px; font-weight: 700; letter-spacing: .3px; }
.valuation-confidence--high { color: var(--brand); background: var(--brand-soft); }
.valuation-confidence--medium { color: var(--accent-ink); background: var(--accent-soft); }
.valuation-confidence--low { color: var(--danger); background: var(--danger-soft); }
.valuation-block { margin-top: 26px; }
.valuation-block h3 { font-size: 14px; font-weight: 650; }
.valuation-list { display: grid; gap: 9px; margin: 12px 0 0; padding: 0; list-style: none; }
.valuation-list li { display: flex; align-items: flex-start; gap: 10px; color: var(--ink-soft); font-size: 14px; line-height: 1.55; }
.valuation-list .icon { flex: none; margin-top: 3px; color: var(--brand); }
.valuation-list--assumes .icon { color: var(--muted); }
/* The disclaimer is the most important sentence in the panel, so it is boxed and
   not styled as a footnote. "Not a formal appraisal" buried in small print is
   exactly the kind of claim this feature exists to stop. */
.valuation-disclaimer { display: flex; align-items: flex-start; gap: 10px; margin: 26px 0 18px; padding: 15px 17px; border: 1px solid var(--line); border-radius: var(--radius-sm); color: var(--muted-strong); background: var(--surface-subtle); font-size: 13.5px; line-height: 1.6; }
.valuation-disclaimer .icon { flex: none; margin-top: 2px; color: var(--muted); }

/* ---- tenancy --------------------------------------------------------------- */
.tenancy .spec-grid { grid-template-columns: repeat(3, 1fr); }
.tenancy-note { display: flex; align-items: flex-start; gap: 10px; color: var(--muted); font-size: 13px; line-height: 1.6; }
.tenancy-note .icon { flex: none; margin-top: 2px; }

/* ---- promotion transparency ------------------------------------------------ */
.promotion-note { padding: 16px 18px; margin-bottom: 20px; border: 1px solid color-mix(in srgb, var(--hot) 28%, var(--line)); border-radius: var(--radius); background: var(--hot-soft); }
.promotion-note p { display: flex; align-items: flex-start; gap: 10px; margin: 0; font-size: 13.5px; line-height: 1.55; }
.promotion-note .icon { flex: none; margin-top: 2px; }
.promotion-reason { color: var(--ink-soft); }
.promotion-reason .icon { color: var(--hot); }
/* The exclusions are the line that stops the promotion being read as a bigger
   discount than it is, so they get the stronger weight. */
.promotion-excludes { margin-top: 9px !important; padding-top: 9px; border-top: 1px solid color-mix(in srgb, var(--hot) 22%, transparent); color: var(--accent-ink); font-weight: 500; }

/* ---- honest ranking -------------------------------------------------------- */
.sort-explain { display: flex; align-items: flex-start; gap: 9px; margin: 16px 0 0; color: var(--muted); font-size: 13px; line-height: 1.55; }
.sort-explain .icon { flex: none; margin-top: 2px; color: var(--brand); }
.sort-explain strong { color: var(--ink-soft); font-weight: 650; }
/* Paid placement. Deliberately quiet and obviously a disclosure rather than a
   badge of honour - it must not read as a second "verified". */
.badge--sponsored { color: var(--muted-strong); background: var(--badge-float); border: 1px solid var(--line-strong); letter-spacing: .3px; }
.badge--reduced { color: var(--brand); background: var(--brand-soft); }
/* The disclosure on the listing's own page. Quiet on purpose - it is a legal
   note, and styling it like a promotion would be the exact confusion it exists
   to prevent. */
.placement-note { display: flex; align-items: baseline; gap: 12px; margin: 0 0 20px; padding: 11px 14px; border: 1px dashed var(--line-strong); border-radius: var(--radius-sm); color: var(--muted); font-size: 13px; line-height: 1.55; }
.placement-note .badge { flex: none; }

/* ---- viewing desk ---------------------------------------------------------- */
.desk-assurance { display: flex; align-items: flex-start; gap: 9px; margin: 16px 0 0; color: var(--muted); font-size: 12.5px; line-height: 1.55; }
.desk-assurance .icon { flex: none; margin-top: 2px; color: var(--brand); }
.desk-assurance a { color: var(--brand); font-weight: 600; }
.desk-recipient { display: flex; align-items: center; gap: 12px; margin-top: 20px; padding: 13px 15px; border: 1px solid var(--line); border-radius: var(--radius-sm); background: var(--surface-subtle); }
.desk-recipient-name { margin: 0; font-size: 14px; font-weight: 650; }
.desk-recipient-role { margin: 2px 0 0; color: var(--muted); font-size: 12.5px; }

.desk-slots { margin-top: 22px; padding: 0; border: 0; }
.desk-slots legend { padding: 0 0 12px; font-size: 14px; font-weight: 650; }
.desk-slots legend small { color: var(--muted); font-weight: 400; }
.slot-days { display: grid; gap: 10px; max-height: 232px; overflow-y: auto; padding: 2px; }
.slot-day { display: grid; grid-template-columns: 96px 1fr; gap: 10px; align-items: center; padding: 9px 11px; border: 1px solid var(--line); border-radius: var(--radius-sm); background: var(--surface); }
.slot-day-label { margin: 0; color: var(--ink-soft); font-size: 13px; font-weight: 650; }
.slot-times { display: flex; flex-wrap: wrap; gap: 6px; }
.slot { position: relative; display: inline-flex; }
/* The checkbox itself is hidden but not removed - it keeps the field focusable
   and keeps native form semantics, so the browser's own keyboard order and
   assistive handling still work. */
.slot input { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; opacity: 0; cursor: pointer; }
.slot span { padding: 6px 11px; border: 1px solid var(--line-strong); border-radius: 999px; color: var(--muted-strong); background: var(--surface); font-size: 12.5px; font-weight: 500; transition: border-color .15s, color .15s, background .15s; }
.slot:hover span { border-color: var(--brand); color: var(--brand); }
.slot input:checked + span { border-color: var(--brand); color: var(--on-solid); background: var(--brand); }
/* The focus ring is drawn on the label, because the element that actually took
   focus is the invisible input. Suppressing it here would make this unusable by
   keyboard. */
.slot input:focus-visible + span { outline: 2px solid var(--brand); outline-offset: 2px; }
.slot-error { margin: 10px 0 0; color: var(--danger); font-size: 13px; line-height: 1.5; }

.desk-receipt .receipt-ref { margin: 20px 0 0; padding: 13px 15px; border-radius: var(--radius-sm); background: var(--brand-soft); font-size: 14px; }
.receipt-steps { margin: 20px 0 0; padding: 0; list-style: none; counter-reset: step; }
.receipt-steps li { position: relative; padding: 0 0 16px 30px; font-size: 13.5px; line-height: 1.5; }
.receipt-steps li::before { counter-increment: step; content: counter(step); position: absolute; top: 0; left: 0; display: grid; place-items: center; width: 21px; height: 21px; border: 1px solid var(--line-strong); border-radius: 50%; color: var(--muted); font-size: 11px; font-weight: 700; }
.receipt-steps li.is-done::before { border-color: var(--brand); color: var(--on-solid); background: var(--brand); }
.receipt-steps strong { display: block; font-size: 13.5px; font-weight: 650; }
.receipt-steps span { color: var(--muted-strong); }
.receipt-escalate { display: flex; align-items: flex-start; gap: 10px; margin: 8px 0 0; padding: 13px 15px; border-radius: var(--radius-sm); color: var(--muted-strong); background: var(--surface-subtle); font-size: 13px; line-height: 1.55; }
.receipt-escalate .icon { flex: none; margin-top: 2px; color: var(--accent-ink); }
.receipt-escalate a { color: var(--brand); font-weight: 600; }
.receipt-actions { display: flex; flex-wrap: wrap; gap: 10px; margin: 20px 0 0; }
.report-intro { margin: 18px 0 0; color: var(--muted-strong); font-size: 13.5px; line-height: 1.6; }

@media (max-width: 640px) {
  .truth-rows > div { grid-template-columns: 1fr; gap: 3px; }
  .tenancy .spec-grid { grid-template-columns: 1fr; }
  .slot-day { grid-template-columns: 1fr; }
  .truth-foot { flex-direction: column; align-items: flex-start; }
}

/* 9. contact -------------------------------------------------------------- */
.contact-layout { display: grid; grid-template-columns: 1.25fr 1fr; gap: 48px; align-items: start; }
.form-card { padding: 32px; border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface); box-shadow: var(--shadow); }
.form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 18px; }
.form-grid .field--full { grid-column: 1 / -1; }
.form-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 14px; margin-top: 24px; }
.form-note { color: var(--muted); font-size: 13px; }
.office-list { display: grid; gap: 14px; }
.office-card { display: flex; gap: 14px; padding: 20px; border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface); }
.office-card h3 { font-size: 15.5px; font-weight: 650; }
.office-card p { margin-top: 6px; color: var(--muted-strong); font-size: 14px; line-height: 1.55; }
.office-card .icon { margin-top: 2px; color: var(--brand); }
.faq { display: grid; gap: 10px; margin-top: 22px; }
.faq details { border: 1px solid var(--line); border-radius: var(--radius-sm); background: var(--surface); }
.faq summary { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 16px 18px; cursor: pointer; font-size: 15px; font-weight: 600; list-style: none; }
.faq summary::-webkit-details-marker { display: none; }
.faq summary .icon { color: var(--muted); transition: transform .18s; }
.faq details[open] summary .icon { transform: rotate(45deg); }
.faq p { padding: 0 18px 18px; color: var(--muted-strong); font-size: 14.5px; line-height: 1.65; }

/* 10. overlays ------------------------------------------------------------ */
.toast { position: fixed; z-index: 60; bottom: 26px; left: 50%; padding: 13px 20px; border-radius: 12px; color: #fff; background: #1f2a2b; box-shadow: var(--shadow-lg); font-size: 14px; opacity: 0; transform: translate(-50%, 16px); pointer-events: none; transition: opacity .2s, transform .2s; }
.toast.is-visible { opacity: 1; transform: translate(-50%, 0); }
dialog { padding: 0; border: 0; background: transparent; }
dialog::backdrop { background: rgb(18 24 28 / 45%); backdrop-filter: blur(2px); }
.dialog-shell { width: min(100% - 32px, 520px); padding: 28px; border-radius: var(--radius-lg); background: var(--surface); box-shadow: var(--shadow-lg); }
.dialog-header { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; }
.dialog-header h2 { font-size: 20px; font-weight: 700; letter-spacing: -.6px; }
.dialog-header p { margin-top: 7px; color: var(--muted-strong); font-size: 14px; line-height: 1.55; }
.dialog-shell .form-grid { margin-top: 22px; }
.dialog-actions { display: flex; justify-content: flex-end; gap: 10px; margin-top: 24px; }

/* 11. progressive enhancement ---------------------------------------------
   Everything below is something the page gets better by if the browser knows
   how to do it, and the same page without, if it does not. None of it is load
   bearing, so none of it is wrapped in a feature query except where getting it
   wrong would look broken. */

/* Balance the last line of a heading, and loosen the rivers that justify-ish
   body copy otherwise leaves behind. */
.section-title, .page-header h1, .detail-title h1, .hero h1, .cta-panel h2,
.dialog-header h2, .agent-card h3, .card-title {
  text-wrap: balance;
}
.hero-lead, .section-lead, .page-header p, .quote-card blockquote, .faq p,
.detail-description, .field-error, .chip {
  text-wrap: pretty;
}

/* Below the fold, a section's layout and paint can be skipped until it is close
   enough to matter. The intrinsic size is a guess at the finished height, and
   is only used to hold the scrollbar steady before the real one is measured. */
.section--deferred {
  content-visibility: auto;
  contain-intrinsic-size: auto 640px;
}

/* Dialogs fade and lift into place. @starting-style is what lets the first frame
   be styled differently from the resting state; browsers without it simply
   show the dialog, which is what it did before. */
@starting-style {
  dialog[open] .dialog-shell { opacity: 0; transform: translateY(10px) scale(.98); }
}
dialog[open] .dialog-shell { transition: opacity .22s ease, transform .22s ease; }

/* Frosted surfaces are decoration. Where the reader has asked the system not to
   blur what is behind them, they get an opaque surface instead. */
@media (prefers-reduced-transparency: reduce) {
  .site-header, .filter-bar, .hero-slide-btn, .favorite-button {
    backdrop-filter: none;
  }
  .site-header { background: var(--surface); }
  .filter-bar { background: var(--canvas); }
  .hero-slide-btn, .favorite-button { background: #20282c; }
  .quote-card { background: color-mix(in srgb, var(--brand-dark) 92%, #000); }
}

/* Where backdrop-filter is not implemented the glass tints would sit on an
   opaque fallback anyway; this makes that deliberate rather than accidental. */
@supports not (backdrop-filter: blur(2px)) {
  .site-header { background: var(--surface); }
  .filter-bar { background: var(--canvas); }
}

/* ---- theme toggle ---------------------------------------------------------
   Injected into .header-actions by app.js. The icon is drawn inline rather than
   pulled from the sprite so that no page has to be edited to add it. Both glyphs
   are in the DOM and CSS picks one, so the control never re-renders. */
.theme-toggle { position: relative; color: var(--ink-soft); }
.theme-toggle .icon { transition: transform .25s ease, opacity .15s ease; }
.theme-toggle .icon--moon { opacity: 1; }
.theme-toggle .icon--sun { position: absolute; opacity: 0; transform: rotate(-70deg) scale(.6); }
:root[data-theme="dark"] .theme-toggle .icon--moon { opacity: 0; transform: rotate(70deg) scale(.6); }
:root[data-theme="dark"] .theme-toggle .icon--sun { opacity: 1; transform: rotate(0) scale(1); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .theme-toggle .icon--moon { opacity: 0; transform: rotate(70deg) scale(.6); }
  :root:not([data-theme="light"]) .theme-toggle .icon--sun { opacity: 1; transform: rotate(0) scale(1); }
}
@media (prefers-reduced-motion: reduce) {
  .theme-toggle .icon { transition: none; }
}

/* 12. responsive ---------------------------------------------------------- */
@media (max-width: 1080px) {
  .value-grid, .quote-grid, .agent-grid { grid-template-columns: repeat(2, 1fr); }
  .detail-layout { grid-template-columns: 1fr; }
  .agent-card--sticky { position: static; }
  .contact-layout { grid-template-columns: 1fr; gap: 36px; }
  .footer-grid { grid-template-columns: 1fr 1fr; gap: 32px; }
  .stat-band { grid-template-columns: repeat(2, 1fr); }
  .filter-form { grid-template-columns: 1fr 1fr; }
  .filter-form .button { grid-column: 1 / -1; }
  .split { gap: 40px; }
}
@media (max-width: 860px) {
  .container { width: min(100% - 36px, var(--container)); }
  .header-inner { height: 66px; gap: 16px; }
  .menu-button { display: inline-flex; margin-left: auto; }
  .main-nav { position: fixed; z-index: 45; top: 0; right: 0; bottom: 0; width: min(300px, 82vw); flex-direction: column; align-items: stretch; gap: 4px; margin: 0; padding: 82px 20px 24px; background: var(--surface); box-shadow: -12px 0 40px rgb(24 30 38 / 12%); transform: translateX(100%); transition: transform .22s ease; }
  .main-nav a { padding: 13px 14px; font-size: 16px; }
  .nav-open .main-nav { transform: translateX(0); }
  .nav-scrim { position: fixed; z-index: 44; inset: 0; display: block; background: rgb(20 26 30 / 30%); opacity: 0; pointer-events: none; transition: opacity .22s; }
  .nav-open .nav-scrim { opacity: 1; pointer-events: auto; }
  .header-actions .button--primary { display: none; }
  .filter-bar { top: 66px; }
  .section { padding: 64px 0; }
  .split { grid-template-columns: 1fr; gap: 30px; }
  .split--reverse .split-media { order: 0; }
  .cta-panel { grid-template-columns: 1fr; padding: 34px 28px; }
  .card-grid.is-list .property-card { grid-template-columns: 1fr; }
  .card-grid.is-list .card-media { aspect-ratio: 16 / 9; }
  .section-head--split { align-items: flex-start; flex-direction: column; }
}
@media (max-width: 640px) {
  .container { width: min(100% - 32px, var(--container)); }
  .hero { padding: 66px 0 88px; }
  .hero-slider { margin-top: 32px; }
  /* The caption takes the full width and the controls sit under it, rather than
     leaving a short caption sharing a row with three buttons and a row of dots. */
  .hero-slide-caption { flex: 1 0 100%; }
  .search-panel { margin-top: -46px; }
  .search-form { grid-template-columns: 1fr; }
  .value-grid, .quote-grid, .agent-grid, .stat-band, .feature-grid, .form-grid { grid-template-columns: 1fr; }
  .form-grid .field--full { grid-column: auto; }
  .spec-grid { grid-template-columns: 1fr 1fr; }
  .detail-title { flex-direction: column; }
  .gallery-thumbs { grid-template-columns: repeat(3, 1fr); gap: 8px; }
  .card-grid { grid-template-columns: 1fr; gap: 20px; }
  .footer-grid { grid-template-columns: 1fr; }
  .footer-bottom { flex-direction: column; align-items: flex-start; }
  .form-card, .dialog-shell { padding: 22px; }
  .filter-form { grid-template-columns: 1fr; }
  .filter-tools { flex-direction: column; align-items: flex-start; }
  .hero-meta { gap: 20px; }
}
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { scroll-behavior: auto !important; transition-duration: .01ms !important; animation-duration: .01ms !important; animation-iteration-count: 1 !important; }
  /* The slideshow is the only thing on the page that moves on its own. The blanket
     rules above already collapse it, but the push-in would still snap the picture
     to its scaled end state, so it is switched off outright. app.js also never
     starts the timer for a reader who has asked for reduced motion. */
  .hero-slide { transition: none; }
  .hero-slide.is-active img { animation: none; }
}
