@charset "UTF-8";
/* ==========================================================================
   KAANI100 — MOBILE-FIRST STYLESHEET
   --------------------------------------------------------------------------
   Written mobile-first: base styles target the smallest screen, and every
   media query is min-width. Nothing here relies on !important to win a
   cascade fight, and nothing relies on overflow-x:hidden to hide a layout bug.

   Layer order
     1. Reset
     2. Design tokens
     3. Base / typography
     4. Layout primitives
     5. Components
     6. Page-specific
     7. Utilities

   Breakpoints (min-width):  sm 640px · lg 1024px · xl 1280px
   ========================================================================== */


/* ==========================================================================
   1. RESET
   ========================================================================== */

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

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

body,
h1, h2, h3, h4, h5, h6,
p, figure, blockquote, dl, dd, ol, ul {
  margin: 0;
  padding: 0;
}

/* Unconditional, not ul[class]/ol[class] — this design system never wants a
   native bullet or number, and a bare <ul>/<ol> (e.g. the footer nav lists,
   the breadcrumb) was slipping through the old class-gated version with
   default browser bullets and indent, throwing off alignment. */
ul, ol { list-style: none; padding-left: 0; }

img, picture, video, iframe, svg {
  display: block;
  max-width: 100%;
}

img { height: auto; }

input, button, textarea, select {
  font: inherit;
  color: inherit;
}

button { background: none; border: none; }

/* Flex/grid children refuse to shrink below content width by default, which
   is the single most common cause of horizontal overflow. Opt out globally. */
.container > *,
.p-grid > *,
.feature-grid > *,
.two-col > *,
.steps > *,
.field__row > * { min-width: 0; }


/* ==========================================================================
   2. DESIGN TOKENS
   ========================================================================== */

:root {
  /* ------------------------------------------------------------------
     COLOUR — navy + gold, two hues only.
     Every value below is contrast-verified. The previous palette carried
     six competing hues (coral/amber/green/sky/violet on top of navy+blue)
     which encoded nothing and made each page look like a different site.

     RULE, one meaning per colour:
       navy  = structure (header, footer, CTA bands, headings)
       gold  = the single accent (price, verified, active, decoration)
       green = functional success only          red = functional error only
     ------------------------------------------------------------------ */

  /* Navy — one family. Header/footer/gradient now have a stated
     relationship instead of being two unrelated navies. */
  --navy-950: #071426;   /* footer, deepest                          */
  --navy-900: #0e2647;   /* hero / CTA gradient start                */
  --navy-800: #14365f;   /* THE brand navy: header, gradient end     */
  --navy-700: #1d4675;   /* hover on navy                            */

  /* Gold — the only accent.
     gold-700 for TEXT on light (5.3:1)   gold-400 for text ON navy (7.0:1)
     gold-500 is decoration only — it is 4.4:1 on navy, fine for borders
     and icons, NOT for body copy. */
  --gold-700: #8a6508;
  --gold-600: #a87c0d;
  --gold-500: #c89211;
  --gold-400: #dca828;
  --gold-100: #f5e9cc;
  --gold-50:  #fbf5e8;

  /* --- Warm neutral surfaces ---
     Separation widened from 5%/7% to 10%/12% luminance so the bands read
     as deliberate hierarchy rather than three almost-identical whites. */
  /* NOTE: there is deliberately NO pure white anywhere on this site.
     Cards use a warm off-white and the page canvas a slightly deeper ivory,
     so nothing reads as a stark white block interrupting the page. */
  --surface:        #fdfbf6;   /* cards / raised surfaces */
  --surface-alt:    #f5f0e4;   /* the page canvas          */
  --surface-sunken: #eae2d2;   /* image wells, pills       */
  --border:         #e6dfd0;
  --border-strong:  #d2c8b4;

  /* --- Text --- */
  --text:          #1a1f2e;
  --text-muted:    #4e5666;
  --text-subtle:   #5a6270;   /* was 4.51:1 on alt — now 5.6:1 */
  --text-inverse:  #ffffff;
  --text-on-dark:       rgba(255, 255, 255, 0.92);
  --text-on-dark-muted: rgba(255, 255, 255, 0.76);

  /* --- Feedback: functional states ONLY, never decoration --- */
  --success-bg:     #edf7f0;
  --success-fg:     #1f5c3d;
  --success-border: #b9dcc7;
  --error-bg:       #fdf1f0;
  --error-fg:       #a3271b;
  --error-border:   #eab5ae;
  --info-bg:        var(--gold-50);
  --info-fg:        var(--gold-700);

  /* Third-party brand mark — the only place this green may appear. */
  --whatsapp:       #25d366;
  --whatsapp-hover: #1eb857;
  --whatsapp-fg:    #04310f;

  /* --- Type --- */
  --font-sans:  "Manrope", system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-serif: "Merriweather", Georgia, serif;

  /* Fluid scale. Minimums are never below 14px, and nothing shrinks as the
     viewport grows (the old sheet had rules that did exactly that). */
  --fs-xs:   0.8125rem;                              /* 13px — badges only */
  --fs-sm:   0.875rem;                               /* 14px floor for body */
  --fs-base: 1rem;
  --fs-md:   1.0625rem;
  --fs-lg:   clamp(1.125rem, 1.05rem + 0.35vw, 1.3125rem);
  --fs-xl:   clamp(1.375rem, 1.2rem + 0.8vw,  1.75rem);
  --fs-2xl:  clamp(1.625rem, 1.35rem + 1.3vw, 2.25rem);
  --fs-3xl:  clamp(1.875rem, 1.4rem + 2.2vw,  3rem);
  --fs-hero: clamp(2rem,     1.4rem + 3.2vw,  3.75rem);

  /* --- Spacing --- */
  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-5: 1.5rem;
  --space-6: 2rem;
  --space-7: 2.5rem;
  --space-8: 3rem;
  --space-9: 4rem;
  --space-10: 5rem;

  --section-y:    var(--space-8);
  --gutter:       var(--space-4);

  /* --- Shape --- */
  --radius-sm:   8px;
  --radius:      12px;
  --radius-lg:   18px;
  --radius-full: 999px;

  --shadow-sm: 0 1px 2px rgba(15, 23, 42, 0.06);
  --shadow:    0 4px 16px rgba(15, 23, 42, 0.08);
  --shadow-lg: 0 16px 40px rgba(15, 23, 42, 0.12);

  /* --- Layout --- */
  --container:        1200px;
  --container-narrow: 760px;

  /* --- Interaction --- */
  --tap-min: 44px;                 /* WCAG-friendly minimum touch target */
  --header-h: 64px;

  /* --- Motion ---
     One curve cannot do every job. This site used to have exactly one, and
     applying a snappy 180ms UI curve to a 700ms content reveal is what made
     the whole thing read as machine-made: it arrives at full speed and stops
     dead, with none of the long deceleration that reads as weight.

     Pick by intent:
       --ease          existing UI (drawer, filter sheet) — deliberately unchanged
       --ease-entrance expo-out. Things arriving from nothing: reveals, the hero
       --ease-settle   quint-out. Things responding to a pointer: hover-in
       --ease-exit     quad-in. Things relaxing back: hover-out

     Enter and exit are NOT the same length on purpose. A real object answers
     the hand quickly and relaxes slowly; matching the two is the single most
     reliable tell of motion nobody designed. */
  --ease:          cubic-bezier(0.2, 0.9, 0.3, 1);
  --ease-entrance: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-settle:   cubic-bezier(0.22, 1, 0.36, 1);
  --ease-exit:     cubic-bezier(0.4, 0, 1, 1);

  --dur-micro:  160ms;
  --dur-exit:   180ms;
  --dur-hover:  280ms;
  --dur-hero:   700ms;
  --dur-reveal: 720ms;

  /* --- Depth --- */
  --z-sticky-cta: 60;
  --z-header:     100;
  --z-scrim:      110;
  --z-drawer:     120;
  --z-skip:       200;
}

@media (min-width: 640px) {
  :root { --section-y: var(--space-9); --gutter: var(--space-5); }
}

@media (min-width: 1024px) {
  :root { --section-y: var(--space-10); --gutter: var(--space-6); --header-h: 76px; }
}


/* ==========================================================================
   3. BASE / TYPOGRAPHY
   ========================================================================== */

body {
  font-family: var(--font-sans);
  font-size: var(--fs-base);
  line-height: 1.65;
  color: var(--text);
  background: var(--surface-alt);
  -webkit-font-smoothing: antialiased;
  /* Room for the sticky mobile CTA bar so it never covers the footer. */
  padding-bottom: env(safe-area-inset-bottom);
}

h1, h2, h3, h4 {
  font-family: var(--font-serif);
  line-height: 1.2;
  color: var(--navy-800);
  text-wrap: balance;
}

h1 { font-size: var(--fs-3xl); }
h2 { font-size: var(--fs-2xl); }
h3 { font-size: var(--fs-lg); }
h4 { font-size: var(--fs-md); }

p { text-wrap: pretty; }

a { color: var(--gold-700); }
a:hover { color: var(--navy-800); }

:focus-visible {
  outline: 3px solid var(--gold-500);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

.skip-link {
  position: absolute;
  left: var(--space-4);
  top: -100px;
  z-index: var(--z-skip);
  padding: var(--space-3) var(--space-4);
  background: var(--navy-800);
  color: var(--text-inverse);
  border-radius: 0 0 var(--radius) var(--radius);
  text-decoration: none;
  transition: top 150ms var(--ease);
}
.skip-link:focus { top: 0; color: var(--text-inverse); }


/* ==========================================================================
   4. LAYOUT PRIMITIVES
   ========================================================================== */

.container {
  width: 100%;
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.container--narrow { max-width: var(--container-narrow); }

/* No alternating bands. Every content section sits on the same warm
   canvas; separation comes from spacing and from white cards, not from
   stripes of slightly-different white. `.section--alt` is kept as a
   no-op so templates need no churn. */
.section { padding-block: var(--section-y); }
.section--alt { background: transparent; }

/* Navy "chapter" band. Breaks the long light stretch with a deliberate dark
   section rather than a near-invisible off-white stripe. Cards inside stay
   light so they lift off the navy. Only the section HEADER text is recoloured
   here — card internals keep their own styling, so this never leaks. */
.section--dark {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  background: linear-gradient(160deg, var(--navy-900) 0%, var(--navy-800) 100%);
  color: var(--text-on-dark);
}

.section--dark::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background-image:
    radial-gradient(circle, rgba(255, 255, 255, 0.05) 1px, transparent 1px),
    radial-gradient(ellipse 60% 55% at 80% 15%, rgba(200, 146, 17, 0.18) 0%, transparent 60%);
  background-size: 26px 26px, 100% 100%;
}

.section--dark .section__head .section__title { color: var(--text-inverse); }
.section--dark .section__head .section__lead  { color: var(--text-on-dark-muted); }
.section--dark .section__head .eyebrow        { color: var(--gold-400); }

/* Primary CTA gains punch on navy: solid gold with dark text. */
.section--dark .btn--primary {
  background: var(--gold-500);
  color: var(--navy-950);
}
.section--dark .btn--primary:hover {
  background: var(--gold-400);
  color: var(--navy-950);
}

/* Dashed empty-state border needs to be visible against navy. */
.section--dark .empty-state { border-color: rgba(255, 255, 255, 0.28); }

.section__head {
  text-align: center;
  max-width: 46rem;
  margin-inline: auto;
  margin-bottom: var(--space-6);
}
.section__head--left { text-align: left; margin-inline: 0; }

.section__title { margin-bottom: var(--space-3); }

.section__lead {
  color: var(--text-muted);
  font-size: var(--fs-md);
}

.section__cta {
  margin-top: var(--space-6);
  text-align: center;
}

.eyebrow {
  display: inline-block;
  font-family: var(--font-sans);
  font-size: var(--fs-sm);
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--gold-700);
  margin-bottom: var(--space-2);
}
.eyebrow--on-dark { color: var(--gold-400); }

.stack > * + * { margin-top: var(--space-4); }

.two-col {
  display: grid;
  gap: var(--space-5);
}

.prose { color: var(--text-muted); }
.prose > * + * { margin-top: var(--space-4); }
.prose--center { text-align: center; }
.prose__lead {
  font-family: var(--font-serif);
  font-size: var(--fs-lg);
  font-weight: 700;
  color: var(--navy-800);
}

@media (min-width: 768px) {
  .two-col { grid-template-columns: 1fr 1fr; gap: var(--space-6); }
}


/* ==========================================================================
   5. COMPONENTS
   ========================================================================== */

/* --- 5.1 Buttons ---------------------------------------------------------
   Every variant clears the 44px minimum target at every screen size. */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  min-height: var(--tap-min);
  padding: var(--space-3) var(--space-5);
  border-radius: var(--radius-full);
  font-weight: 700;
  font-size: var(--fs-sm);
  line-height: 1.2;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  /* The base state is the LEAVING state. The :hover rule below overrides the
     duration and curve on the way in, so a button answers the pointer quickly
     and relaxes slowly. */
  transition: background-color var(--dur-exit) var(--ease-exit),
              color           var(--dur-exit) var(--ease-exit),
              border-color    var(--dur-exit) var(--ease-exit),
              transform       var(--dur-exit) var(--ease-exit),
              box-shadow      var(--dur-exit) var(--ease-exit);
}

/* Every button lifts. `transform` was already listed in the transition above,
   but not one of the .btn--* hover rules ever set one — so the most-touched
   element on a property site changed colour and did nothing else. */
.btn:hover {
  transform: translateY(-2px);
  box-shadow: var(--shadow);
  transition-duration: var(--dur-hover);
  transition-timing-function: var(--ease-settle);
}

/* Both values in one transform on purpose: a press should push the already
   lifted button down, not cancel the lift and jump. */
.btn:active {
  transform: translateY(-1px) scale(0.97);
  transition-duration: var(--dur-micro);
}

/* Optional trailing arrow that leans toward where the button is taking you.
   Same idea as .link-arrow further down, which was the one piece of genuine
   micro-interaction the sheet already had. */
.btn__arrow { transition: translate var(--dur-exit) var(--ease-exit); }
.btn:hover .btn__arrow {
  translate: 3px 0;
  transition-duration: var(--dur-hover);
  transition-timing-function: var(--ease-settle);
}

.btn--lg { font-size: var(--fs-base); padding: var(--space-4) var(--space-6); }
.btn--sm { min-height: var(--tap-min); padding: var(--space-2) var(--space-4); }
.btn--block { display: flex; width: 100%; }

.btn--primary { background: var(--gold-700); color: var(--text-inverse); }
.btn--primary:hover { background: var(--navy-800); color: var(--text-inverse); box-shadow: var(--shadow); }

.btn--ghost {
  background: var(--surface);
  color: var(--navy-800);
  border: 1px solid var(--border-strong);
}
.btn--ghost:hover { background: var(--gold-50); color: var(--navy-800); border-color: var(--gold-500); }

.btn--on-dark { background: var(--surface); color: var(--navy-800); }
.btn--on-dark:hover { background: var(--gold-50); color: var(--navy-800); }

.btn--outline-light {
  background: transparent;
  color: var(--text-inverse);
  border: 2px solid rgba(255, 255, 255, 0.6);
}
.btn--outline-light:hover { background: rgba(255, 255, 255, 0.14); color: var(--text-inverse); border-color: var(--text-inverse); }

.btn--solid-dark { background: var(--navy-800); color: var(--text-inverse); }
.btn--solid-dark:hover { background: var(--navy-900); color: var(--text-inverse); }

.btn--whatsapp { background: var(--whatsapp); color: var(--whatsapp-fg); }
.btn--whatsapp:hover { background: var(--whatsapp-hover); color: var(--whatsapp-fg); }


/* --- 5.2 Header + navigation --------------------------------------------
   Mobile: off-canvas drawer. Desktop: inline row. One set of markup. */

.site-header {
  position: sticky;
  top: 0;
  z-index: var(--z-header);
  background: var(--navy-800);
  border-bottom: 1px solid rgba(255, 255, 255, 0.12);
}

.site-header__bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  min-height: var(--header-h);
}

.site-header__logo {
  display: flex;
  align-items: center;
  flex-shrink: 0;
}
/* The asset is trimmed to the artwork, so this height IS the visible mark. */
.site-header__logo img {
  height: 34px;
  width: auto;
}

.nav-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--tap-min);
  height: var(--tap-min);
  margin-right: calc(var(--space-2) * -1);
  color: var(--text-inverse);
  font-size: 1.5rem;
  cursor: pointer;
  border-radius: var(--radius-sm);
}

.nav-close {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--tap-min);
  height: var(--tap-min);
  color: var(--text-inverse);
  font-size: 1.25rem;
  cursor: pointer;
  border-radius: var(--radius-sm);
}

/* Drawer, closed by default on small screens */
.primary-nav {
  position: fixed;
  inset: 0 0 0 auto;
  width: min(20rem, 85vw);
  transform: translateX(100%);
  transition: transform 260ms var(--ease);
  z-index: var(--z-drawer);
  visibility: hidden;
}
.primary-nav.is-open { transform: translateX(0); visibility: visible; }

.primary-nav__panel {
  display: flex;
  flex-direction: column;
  height: 100%;
  background: var(--surface);
  overflow-y: auto;
  box-shadow: var(--shadow-lg);
}

/* Navy header bar so the drawer reads as part of the site's identity
   instead of a generic white overlay disconnected from the navy header. */
.primary-nav__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-shrink: 0;
  padding: var(--space-4);
  min-height: var(--header-h);
  background: var(--navy-800);
}

.primary-nav__title {
  font-family: var(--font-serif);
  font-weight: 700;
  color: var(--text-inverse);
}

.primary-nav__list,
.primary-nav__cta { padding-inline: var(--space-4); }
.primary-nav__cta { padding-bottom: var(--space-4); }

.primary-nav__list {
  display: flex;
  flex-direction: column;
  margin-top: var(--space-2);
}

.primary-nav__list a {
  display: flex;
  align-items: center;
  min-height: var(--tap-min);
  padding: var(--space-3) var(--space-2);
  color: var(--text);
  font-weight: 600;
  text-decoration: none;
  border-bottom: 1px solid var(--border);
  /* There was no transition here at all: the hover state snapped on instantly,
     which is a large part of why the header felt abrupt. */
  transition: color            var(--dur-exit) var(--ease-exit),
              background-color var(--dur-exit) var(--ease-exit);
}
.primary-nav__list a:hover {
  color: var(--gold-700);
  transition-duration: var(--dur-hover);
  transition-timing-function: var(--ease-settle);
}
.primary-nav__list a[aria-current="page"] { color: var(--gold-700); }

.primary-nav__cta {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  margin-top: var(--space-5);
}

.nav-scrim {
  position: fixed;
  inset: 0;
  background: rgba(10, 22, 40, 0.5);
  z-index: var(--z-scrim);
}
.nav-scrim[hidden] { display: none; }

@media (min-width: 1024px) {
  .nav-toggle,
  .nav-close,
  .primary-nav__head,
  .nav-scrim { display: none; }

  .primary-nav {
    position: static;
    width: auto;
    transform: none;
    visibility: visible;
    z-index: auto;
    /* Take the rest of the bar so the account cluster's margin-left:auto has
       room to push against; min-width:0 lets the name below truncate instead
       of forcing the row wider than the header. */
    flex: 1 1 auto;
    min-width: 0;
  }
  .primary-nav__panel {
    flex-direction: row;
    align-items: center;
    gap: var(--space-4);
    height: auto;
    padding: 0;
    background: transparent;
    overflow: visible;
    box-shadow: none;
  }
  /* The drawer pads these; in the bar that padding is dead space that pushed
     the labels into wrapping. */
  .primary-nav__list,
  .primary-nav__cta { padding-inline: 0; padding-bottom: 0; }

  .primary-nav__list { flex-direction: row; gap: var(--space-1); margin-top: 0; }
  .primary-nav__list a {
    position: relative;              /* anchors the underline below */
    color: rgba(255, 255, 255, 0.9);
    border-bottom: none;
    padding-inline: var(--space-3);
    border-radius: var(--radius-sm);
    font-size: var(--fs-sm);
    /* Two-word labels ("Buy Land", "Buyers Corner") must stay on one line —
       wrapping them is what made the bar look ragged. */
    white-space: nowrap;
  }
  .primary-nav__list a:hover { color: var(--text-inverse); background: rgba(255, 255, 255, 0.12); }
  .primary-nav__list a[aria-current="page"] { color: var(--text-inverse); background: rgba(255, 255, 255, 0.18); }

  /* Gold rule wipes in from the left under the label. Desktop only: in the
     mobile drawer these links already carry a border-bottom separator and the
     two would sit on top of each other. */
  .primary-nav__list a::after {
    content: "";
    position: absolute;
    left: var(--space-3);
    right: var(--space-3);
    bottom: 5px;
    height: 2px;
    border-radius: 2px;
    background: var(--gold-400);
    scale: 0 1;
    transform-origin: 0 50%;
    transition: scale var(--dur-exit) var(--ease-exit);
  }
  .primary-nav__list a:hover::after,
  .primary-nav__list a[aria-current="page"]::after {
    scale: 1 1;
    transition-duration: var(--dur-hover);
    transition-timing-function: var(--ease-settle);
  }
  .primary-nav__cta { flex-direction: row; margin-top: 0; flex-shrink: 0; }
  .primary-nav__cta .btn--block { width: auto; }
  .primary-nav__cta .btn { white-space: nowrap; }
  .site-header__logo img { height: 42px; }
}


/* --- 5.3 Footer ---------------------------------------------------------- */

.site-footer {
  background: var(--navy-900);
  color: var(--text-on-dark-muted);
  margin-top: var(--space-8);
}

.site-footer__grid {
  display: grid;
  gap: var(--space-6);
  padding-block: var(--space-8);
}

.site-footer__logo {
  height: 46px;
  width: auto;
  margin-bottom: var(--space-3);
}

.site-footer__brand p { font-size: var(--fs-sm); max-width: 32ch; }

.site-footer__heading {
  font-family: var(--font-sans);
  font-size: var(--fs-sm);
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-inverse);
  margin-bottom: var(--space-3);
}

.site-footer__col ul { display: flex; flex-direction: column; }

/* :not(.btn) so real buttons (e.g. the footer's "Send us a message" ghost
   button) keep their own navy-on-white styling instead of inheriting the
   near-white link color meant for plain text links on the dark footer. */
.site-footer__col a:not(.btn),
.site-footer__contact span {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  min-height: var(--tap-min);
  color: var(--text-on-dark-muted);
  text-decoration: none;
  font-size: var(--fs-sm);
}
.site-footer__col a:not(.btn):hover { color: var(--text-inverse); }
.site-footer__contact .btn { margin-top: var(--space-1); }

.site-footer__contact li { display: flex; }

.site-footer__social {
  display: flex;
  gap: var(--space-2);
  margin-top: var(--space-3);
}
.site-footer__social a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--tap-min);
  height: var(--tap-min);
  border-radius: var(--radius-full);
  background: rgba(255, 255, 255, 0.1);
  font-size: 1.125rem;
}

.site-footer__bottom {
  border-top: 1px solid rgba(255, 255, 255, 0.12);
  padding-block: var(--space-4);
  font-size: var(--fs-sm);
  text-align: center;
}

@media (min-width: 640px) {
  .site-footer__grid { grid-template-columns: repeat(2, 1fr); }
}
@media (min-width: 1024px) {
  .site-footer__grid { grid-template-columns: 2fr 1fr 1fr 1.4fr; }
}


/* --- 5.4 Hero + page hero ------------------------------------------------ */

.hero,
.page-hero,
.cta-band {
  position: relative;
  overflow: hidden;
  background: linear-gradient(135deg, var(--navy-900) 0%, var(--navy-800) 100%);
  color: var(--text-inverse);
  isolation: isolate;
}

/* Layered CSS-only depth: a fine dot grid plus a warm gold glow.
   The glow was previously blue, which read as a fifth blue on top of the
   four already in play. Gold ties the dark bands to the accent system.
   .cta-band is included here so the closing band matches the opening hero
   instead of rendering as a flat gradient. */
.hero__bg,
.page-hero__bg,
.cta-band__bg {
  position: absolute;
  inset: 0;
  z-index: -1;
  background-image:
    radial-gradient(circle, rgba(255, 255, 255, 0.06) 1px, transparent 1px),
    radial-gradient(ellipse 70% 60% at 75% 20%, rgba(200, 146, 17, 0.20) 0%, transparent 62%);
  background-size: 26px 26px, 100% 100%;
}

.hero__inner,
.page-hero__inner {
  padding-block: var(--space-8);
  text-align: center;
}

.hero__title,
.page-hero__title {
  color: var(--text-inverse);
  font-size: var(--fs-hero);
  font-weight: 900;
  margin-bottom: var(--space-4);
}

.page-hero__title { font-size: var(--fs-3xl); }

.hero__lead,
.page-hero__subtitle {
  color: var(--text-on-dark-muted);
  font-size: var(--fs-md);
  max-width: 44ch;
  margin-inline: auto;
}

.hero__actions {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  margin-top: var(--space-6);
}

@media (min-width: 640px) {
  .hero__inner { padding-block: var(--space-10); }
  .page-hero__inner { padding-block: var(--space-9); }
  /* Wrap, never nowrap — this is what forced 358px of minimum width before. */
  .hero__actions { flex-direction: row; flex-wrap: wrap; justify-content: center; }
}


/* --- 5.5 Trust strip ----------------------------------------------------- */

.trust-strip {
  background: transparent;
  border-bottom: 1px solid var(--border);
}

.trust-strip__inner {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--space-3) var(--space-4);
  padding-block: var(--space-5);
}

.trust-strip__item {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--navy-800);
}
.trust-strip__item i { color: var(--gold-700); font-size: 1.125rem; flex-shrink: 0; }

@media (min-width: 900px) {
  .trust-strip__inner { grid-template-columns: repeat(4, 1fr); }
}


/* --- 5.6 Property card + grid -------------------------------------------- */

.p-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-5);
}

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

.p-card {
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  overflow: hidden;
  /* Base = leaving; the hover rule speeds up the way in. See the motion tokens. */
  transition: transform  var(--dur-exit) var(--ease-exit),
              box-shadow var(--dur-exit) var(--ease-exit);
}
.p-card:hover {
  transform: translateY(-6px);
  box-shadow: var(--shadow-lg);
  transition-duration: var(--dur-hover);
  transition-timing-function: var(--ease-settle);
}

.p-card__media { position: relative; aspect-ratio: 4 / 3; background: var(--surface-sunken); }
.p-card__media img { width: 100%; height: 100%; object-fit: cover; }

.p-card__media-fallback,
.gallery__fallback {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  color: var(--text-subtle);
  font-size: 2rem;
  background: var(--surface-sunken);
}

.p-card__badge {
  position: absolute;
  top: var(--space-3);
  left: var(--space-3);
  padding: var(--space-1) var(--space-3);
  border-radius: var(--radius-full);
  background: var(--gold-700);
  color: var(--text-inverse);
  font-size: var(--fs-xs);
  font-weight: 700;
  letter-spacing: 0.04em;
}
.property-badge--sell { background: var(--navy-800); color: var(--text-inverse); }

.p-card__body {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: var(--space-4);
  flex: 1;
}

.p-card__title { font-size: var(--fs-lg); }
.p-card__title a { color: var(--navy-800); text-decoration: none; }
.p-card__title a:hover { color: var(--gold-700); }

.p-card__location {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  color: var(--text-muted);
  font-size: var(--fs-sm);
}

.p-card__facts {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}
.p-card__facts li {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding: var(--space-1) var(--space-3);
  border-radius: var(--radius-full);
  background: var(--surface-sunken);
  color: var(--text-muted);
  font-size: var(--fs-sm);
}

.p-card__approvals { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.p-card__approvals li {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  color: var(--success-fg);
  font-size: var(--fs-sm);
  font-weight: 600;
}

.p-card__foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  margin-top: auto;
  padding-top: var(--space-3);
  border-top: 1px solid var(--border);
}

.p-card__price {
  font-family: var(--font-serif);
  font-size: var(--fs-lg);
  font-weight: 900;
  color: var(--navy-800);
}


/* --- 5.7 Listing layout + filters ---------------------------------------- */

.listing-toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  margin-bottom: var(--space-5);
}

.listing-toolbar__count { color: var(--text-muted); font-size: var(--fs-sm); }
.listing-toolbar__count strong { color: var(--navy-800); font-size: var(--fs-md); }
.listing-toolbar__actions { display: flex; flex-wrap: wrap; gap: var(--space-3); }

.filters-trigger__count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 1.5rem;
  height: 1.5rem;
  padding-inline: var(--space-1);
  border-radius: var(--radius-full);
  background: var(--gold-700);
  color: var(--text-inverse);
  font-size: var(--fs-xs);
}

.listing-layout { display: grid; gap: var(--space-6); }

.filters {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: var(--space-4);
}

.filters__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: var(--space-4);
}
.filters__title { font-size: var(--fs-md); margin: 0; }

/* The close button only makes sense while the sheet is open. */
.filters__close { display: none; }

.filters__body { display: grid; gap: var(--space-4); }
.filters__actions { display: grid; gap: var(--space-3); margin-top: var(--space-5); }

/* Bottom-sheet presentation, applied by JS on small screens only.
   Without JS the form simply stays inline and fully usable. */
.filters.is-sheet {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  max-height: 85vh;
  overflow-y: auto;
  border-radius: var(--radius-lg) var(--radius-lg) 0 0;
  padding-bottom: calc(var(--space-5) + env(safe-area-inset-bottom));
  transform: translateY(100%);
  transition: transform 260ms var(--ease);
  z-index: var(--z-drawer);
  box-shadow: var(--shadow-lg);
}
.filters.is-sheet.is-open { transform: translateY(0); }
.filters.is-sheet .filters__close { display: inline-flex; align-items: center; justify-content: center; width: var(--tap-min); height: var(--tap-min); }

@media (min-width: 1024px) {
  .listing-layout { grid-template-columns: 18rem 1fr; align-items: start; }
  .listing-layout--no-filters { grid-template-columns: 1fr; }
  .listing-layout__filters { position: sticky; top: calc(var(--header-h) + var(--space-4)); }
}


/* --- 5.8 Forms ----------------------------------------------------------- */

.field { display: flex; flex-direction: column; gap: var(--space-2); }

.field__label {
  font-size: var(--fs-sm);
  font-weight: 700;
  color: var(--navy-800);
}
.field__required { color: var(--gold-500); }

.input {
  width: 100%;
  min-height: var(--tap-min);
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  background: var(--surface);
  /* 16px prevents iOS Safari from zooming the viewport on focus. */
  font-size: 1rem;
  color: var(--text);
  transition: border-color 160ms var(--ease), box-shadow 160ms var(--ease);
}
.input:focus {
  outline: none;
  border-color: var(--gold-500);
  box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.25);
}
.input::placeholder { color: var(--text-subtle); }

.input--textarea { min-height: 7rem; resize: vertical; }

.input--select {
  appearance: none;
  padding-right: var(--space-8);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%23475569' d='M6 8L1 3h10z'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right var(--space-4) center;
}

.input--file { padding: var(--space-2); }

.field__help { font-size: var(--fs-sm); color: var(--text-subtle); }
/* Django hands some help text over as a <ul> — the password rules on signup
   are four separate items. The global reset strips list markers, so restore
   them here; four unmarked lines read as one run-on paragraph. */
.field__help ul {
  list-style: disc;
  padding-left: 1.1em;
  margin: 0;
}
.field__help li { margin-block: 0.15em; }

.field__errors { color: var(--error-fg); font-size: var(--fs-sm); }
.field--invalid .input { border-color: var(--error-border); }

.field--group { border: none; padding: 0; margin: 0; }
.field__row { display: flex; align-items: center; gap: var(--space-2); }
.field__sep { color: var(--text-subtle); flex-shrink: 0; }

.field-pair { display: grid; gap: var(--space-4); }

.fieldset { border: none; padding: 0; margin: 0; }
.fieldset + .fieldset { margin-top: var(--space-6); }
.fieldset__legend {
  font-family: var(--font-serif);
  font-size: var(--fs-md);
  font-weight: 700;
  color: var(--navy-800);
  margin-bottom: var(--space-4);
  padding: 0;
}
.fieldset > .field + .field,
.fieldset > .field + .field-pair,
.fieldset > .field-pair + .field { margin-top: var(--space-4); }

.form-errors {
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius);
  background: var(--error-bg);
  color: var(--error-fg);
  font-size: var(--fs-sm);
}

@media (min-width: 640px) {
  .field-pair { grid-template-columns: 1fr 1fr; }
}


/* --- 5.9 Flash messages -------------------------------------------------- */

.flash-list { display: grid; gap: var(--space-3); margin-top: var(--space-5); }

.flash {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  padding: var(--space-4);
  border-radius: var(--radius);
  font-size: var(--fs-sm);
}
.flash i { flex-shrink: 0; font-size: 1.125rem; }
.flash--success { background: var(--success-bg); color: var(--success-fg); }
.flash--error   { background: var(--error-bg);   color: var(--error-fg); }
.flash--info,
.flash--warning { background: var(--info-bg);    color: var(--info-fg); }


/* --- 5.10 Cards, features, steps ----------------------------------------- */

.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: var(--space-5);
}
.card--flush { padding: 0; overflow: hidden; }
.card__title {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--fs-lg);
  margin-bottom: var(--space-4);
}
/* The Vision/Mission pair. Gold beside navy is the palette expressing
   itself, unlike the old max-chroma yellow beside navy. */
.card--accent-gold { border-top: 4px solid var(--gold-500); }
.card--accent-navy { border-top: 4px solid var(--navy-800); }

.feature-grid { display: grid; grid-template-columns: 1fr; gap: var(--space-4); }

.feature-card {
  position: relative;
  background: var(--surface);
  border: 1px solid var(--border);
  border-top: 4px solid var(--gold-500);
  border-radius: var(--radius-lg);
  padding: var(--space-5);
  transition: transform  var(--dur-exit) var(--ease-exit),
              box-shadow var(--dur-exit) var(--ease-exit);
}
.feature-card:hover {
  transform: translateY(-6px);
  box-shadow: var(--shadow);
  transition-duration: var(--dur-hover);
  transition-timing-function: var(--ease-settle);
}
.feature-card h3 { margin-bottom: var(--space-2); }
.feature-card p { color: var(--text-muted); font-size: var(--fs-sm); }

.feature-card__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 3rem;
  height: 3rem;
  border-radius: var(--radius);
  background: var(--gold-50);
  color: var(--gold-700);
  font-size: 1.375rem;
  margin-bottom: var(--space-4);
}

.feature-card__num {
  display: block;
  font-family: var(--font-serif);
  font-size: var(--fs-2xl);
  font-weight: 900;
  /* gold-600, not gold-500: 3.78:1 on white clears the large-text bar,
     where gold-500 sits at 2.77:1. (The original was 1.48:1 - invisible.) */
  color: var(--gold-600);
  line-height: 1;
  margin-bottom: var(--space-3);
}

@media (min-width: 640px) {
  .feature-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (min-width: 1024px) {
  .feature-grid { grid-template-columns: repeat(3, 1fr); }
  .feature-grid--four { grid-template-columns: repeat(4, 1fr); }
}

/* Steps — stacked on mobile, never a squeezed 5-column row. */
.steps { display: grid; grid-template-columns: 1fr; gap: var(--space-4); counter-reset: step; }

.step {
  position: relative;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: var(--space-5);
}
.step__num {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.5rem;
  height: 2.5rem;
  border-radius: var(--radius-full);
  background: var(--navy-800);
  color: var(--text-inverse);
  font-weight: 800;
  margin-bottom: var(--space-3);
}
.step h3 { margin-bottom: var(--space-2); }
.step p { color: var(--text-muted); font-size: var(--fs-sm); }
.step__link {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  min-height: var(--tap-min);
  font-weight: 700;
  font-size: var(--fs-sm);
  text-decoration: none;
}

@media (min-width: 640px) { .steps { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1024px) {
  .steps { grid-template-columns: repeat(4, 1fr); }
  .steps--five { grid-template-columns: repeat(5, 1fr); }
}


/* --- 5.11 Pillars, chips, lists ------------------------------------------ */

.pillars {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-3);
  margin-top: var(--space-6);
}
.pillar {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-4);
  border-radius: var(--radius);
  background: var(--surface);
  border: 1px solid var(--border);
}
.pillar i { font-size: 1.5rem; color: var(--gold-700); flex-shrink: 0; }
.pillar__num {
  font-family: var(--font-serif);
  font-size: var(--fs-xl);
  font-weight: 900;
  color: var(--navy-800);
  flex-shrink: 0;
}
.pillar__label { font-size: var(--fs-sm); font-weight: 600; color: var(--text-muted); }

@media (min-width: 768px) { .pillars { grid-template-columns: repeat(3, 1fr); } }

.chip-list { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.chip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-4);
  border-radius: var(--radius-full);
  background: var(--gold-50);
  color: var(--navy-800);
  font-size: var(--fs-sm);
  font-weight: 600;
}

.tick-list { display: grid; gap: var(--space-3); }
.tick-list li {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  color: var(--text-muted);
  font-size: var(--fs-sm);
}
.tick-list i { color: var(--gold-700); flex-shrink: 0; margin-top: 0.2em; }

.link-arrow {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  min-height: var(--tap-min);
  font-weight: 700;
  text-decoration: none;
  transition: gap 180ms var(--ease);
}
.link-arrow:hover { gap: var(--space-3); }

.pullquote {
  margin-block: var(--space-4);
  padding-left: var(--space-4);
  border-left: 4px solid var(--gold-500);
  font-family: var(--font-serif);
  font-style: italic;
  color: var(--navy-800);
}

.notice {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  padding: var(--space-4);
  margin-bottom: var(--space-5);
  border-radius: var(--radius);
  background: var(--info-bg);
  color: var(--info-fg);
  font-size: var(--fs-sm);
}
.notice i { flex-shrink: 0; font-size: 1.125rem; }


/* --- 5.12 Empty state ---------------------------------------------------- */

.empty-state {
  text-align: center;
  padding: var(--space-8) var(--space-5);
  border: 1px dashed var(--border-strong);
  border-radius: var(--radius-lg);
  background: var(--surface);
}
.empty-state__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 4rem;
  height: 4rem;
  border-radius: var(--radius-full);
  background: var(--gold-50);
  color: var(--gold-700);
  font-size: 1.75rem;
  margin-bottom: var(--space-4);
}
.empty-state h2, .empty-state h3 { margin-bottom: var(--space-2); }
.empty-state p {
  color: var(--text-muted);
  font-size: var(--fs-sm);
  max-width: 44ch;
  margin: 0 auto var(--space-5);
}


/* --- 5.13 Carousel ------------------------------------------------------- */

.carousel { position: relative; }

.carousel__viewport { overflow: hidden; border-radius: var(--radius-lg); }

.carousel__track {
  display: flex;
  transition: transform 400ms var(--ease);
}

.carousel__slide { flex: 0 0 100%; min-width: 0; }

.hotspot { position: relative; }
.hotspot img {
  width: 100%;
  aspect-ratio: 16 / 10;
  object-fit: cover;
}
.hotspot__caption {
  position: absolute;
  inset: auto 0 0 0;
  padding: var(--space-6) var(--space-4) var(--space-4);
  background: linear-gradient(to top, rgba(10, 22, 40, 0.9), transparent);
  color: var(--text-inverse);
}
.hotspot__caption h3 { color: var(--text-inverse); margin-bottom: var(--space-1); }
.hotspot__caption p { font-size: var(--fs-sm); color: var(--text-on-dark-muted); }

/* Arrows sit below the image on mobile so they never cover the caption,
   and never shrink below the 44px target. */
.carousel__arrow {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--tap-min);
  height: var(--tap-min);
  border-radius: var(--radius-full);
  background: var(--surface);
  border: 1px solid var(--border-strong);
  color: var(--navy-800);
  font-size: 1.125rem;
  cursor: pointer;
  transition: background-color 180ms var(--ease), color 180ms var(--ease);
}
.carousel__arrow:hover { background: var(--gold-700); color: var(--text-inverse); border-color: var(--gold-700); }

.carousel__arrow--prev,
.carousel__arrow--next { position: absolute; top: calc(50% - var(--tap-min) / 2); }
.carousel__arrow--prev { left: var(--space-2); }
.carousel__arrow--next { right: var(--space-2); }

.carousel__dots {
  display: flex;
  justify-content: center;
  gap: var(--space-1);
  margin-top: var(--space-4);
}
.carousel__dot {
  /* 44px hit area with a small visible dot drawn inside it. */
  width: var(--tap-min);
  height: var(--tap-min);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  border-radius: var(--radius-full);
}
.carousel__dot::before {
  content: "";
  width: 10px;
  height: 10px;
  border-radius: var(--radius-full);
  background: var(--border-strong);
  transition: background-color 180ms var(--ease), transform 180ms var(--ease);
}
.carousel__dot.is-active::before { background: var(--gold-700); transform: scale(1.3); }


/* --- 5.14 Property detail ------------------------------------------------ */

.breadcrumb { padding-block: var(--space-4); }
.breadcrumb ol { display: flex; flex-wrap: wrap; gap: var(--space-2); font-size: var(--fs-sm); }
.breadcrumb li { display: flex; align-items: center; gap: var(--space-2); color: var(--text-subtle); }
.breadcrumb li + li::before { content: "/"; color: var(--border-strong); }
.breadcrumb a { color: var(--text-muted); text-decoration: none; }
.breadcrumb a:hover { color: var(--gold-700); }

.detail__layout { display: grid; gap: var(--space-6); padding-bottom: var(--space-8); }
.detail__main { display: grid; gap: var(--space-6); }

.gallery__stage { border-radius: var(--radius-lg); overflow: hidden; background: var(--surface-sunken); }
.gallery__stage img { width: 100%; aspect-ratio: 3 / 2; object-fit: cover; }
.gallery__fallback { aspect-ratio: 3 / 2; }

.gallery__thumbs {
  display: flex;
  gap: var(--space-2);
  margin-top: var(--space-3);
  overflow-x: auto;
  padding-bottom: var(--space-2);
  scroll-snap-type: x mandatory;
}
.gallery__thumb {
  flex: 0 0 auto;
  width: 5rem;
  border-radius: var(--radius-sm);
  overflow: hidden;
  border: 2px solid transparent;
  cursor: pointer;
  scroll-snap-align: start;
}
.gallery__thumb img { width: 100%; aspect-ratio: 4 / 3; object-fit: cover; }
.gallery__thumb.is-active { border-color: var(--gold-700); }

.detail__title { margin-bottom: var(--space-2); }
.detail__location {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  color: var(--text-muted);
  margin-bottom: var(--space-3);
}
.detail__price {
  font-family: var(--font-serif);
  font-size: var(--fs-2xl);
  font-weight: 900;
  color: var(--navy-800);
}
.detail__price-note {
  display: inline-block;
  margin-left: var(--space-2);
  padding: var(--space-1) var(--space-3);
  border-radius: var(--radius-full);
  background: var(--success-bg);
  color: var(--success-fg);
  font-family: var(--font-sans);
  font-size: var(--fs-sm);
  font-weight: 700;
  vertical-align: middle;
}

.approvals {
  padding: var(--space-4);
  border-radius: var(--radius-lg);
  background: var(--success-bg);
  border: 1px solid var(--success-border);
}
.approvals__title {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--fs-md);
  color: var(--success-fg);
  margin-bottom: var(--space-3);
}
.approvals__list { display: grid; gap: var(--space-2); }
.approvals__list li {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  color: var(--success-fg);
  font-size: var(--fs-sm);
  font-weight: 600;
}

.detail__section h2 { font-size: var(--fs-xl); margin-bottom: var(--space-4); }

.spec-grid { display: grid; grid-template-columns: 1fr; gap: var(--space-3); }
.spec {
  display: flex;
  justify-content: space-between;
  gap: var(--space-4);
  padding: var(--space-3) 0;
  border-bottom: 1px solid var(--border);
}
.spec dt { color: var(--text-subtle); font-size: var(--fs-sm); }
.spec dd { font-weight: 700; color: var(--navy-800); text-align: right; font-size: var(--fs-sm); }

.map-embed {
  position: relative;
  border-radius: var(--radius-lg);
  overflow: hidden;
  background: var(--surface-sunken);
  aspect-ratio: 4 / 3;
}
.map-embed iframe { width: 100%; height: 100%; border: 0; }

.enquiry-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-top: 4px solid var(--gold-700);
  border-radius: var(--radius-lg);
  padding: var(--space-5);
  scroll-margin-top: calc(var(--header-h) + var(--space-4));
}
.enquiry-card__title { font-size: var(--fs-lg); margin-bottom: var(--space-2); }
.enquiry-card__lead { color: var(--text-muted); font-size: var(--fs-sm); margin-bottom: var(--space-4); }
.enquiry-form { display: grid; gap: var(--space-4); }
.enquiry-card__or {
  text-align: center;
  color: var(--text-subtle);
  font-size: var(--fs-sm);
  margin-block: var(--space-4) var(--space-3);
}
.enquiry-card__direct { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-3); }

@media (min-width: 640px) {
  .spec-grid { grid-template-columns: repeat(2, 1fr); gap: var(--space-3) var(--space-6); }
  .map-embed { aspect-ratio: 16 / 9; }
  .gallery__thumb { width: 6.5rem; }
}

@media (min-width: 1024px) {
  .detail__layout { grid-template-columns: 1fr 22rem; align-items: start; }
  /* Clears the section nav, which now sticks above it. Without the extra
     offset the enquiry card slides underneath the nav bar as you scroll. */
  .detail__aside { position: sticky; top: calc(var(--header-h) + 4rem); }
}


/* --- 5.15 Sticky mobile CTA ---------------------------------------------- */

.sticky-cta {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: var(--z-sticky-cta);
  display: flex;
  gap: var(--space-2);
  padding: var(--space-3) var(--gutter);
  padding-bottom: calc(var(--space-3) + env(safe-area-inset-bottom));
  background: var(--surface);
  border-top: 1px solid var(--border);
  box-shadow: 0 -4px 16px rgba(15, 23, 42, 0.08);
}
.sticky-cta .btn { flex-shrink: 0; }
.sticky-cta .btn--block { flex: 1; }
.sticky-cta .btn:not(.btn--block) { width: var(--tap-min); padding-inline: 0; }

/* Only the detail page gets the bar, and only below the desktop breakpoint. */
.page-detail { padding-bottom: 5.5rem; }

@media (min-width: 1024px) {
  .sticky-cta { display: none; }
  .page-detail { padding-bottom: 0; }
}


/* --- 5.16 Contact + founder layouts -------------------------------------- */

.contact-layout { display: grid; gap: var(--space-6); }
.contact-layout__aside { display: grid; gap: var(--space-5); align-content: start; }

.contact-list { display: grid; gap: var(--space-4); }
.contact-list li { display: flex; align-items: flex-start; gap: var(--space-3); }
.contact-list i { color: var(--gold-700); font-size: 1.125rem; flex-shrink: 0; margin-top: 0.15em; }
.contact-list__label {
  display: block;
  font-size: var(--fs-sm);
  font-weight: 700;
  color: var(--navy-800);
}
.contact-list a { text-decoration: none; }
.contact-list a:hover { text-decoration: underline; }

.founder { display: grid; gap: var(--space-5); align-items: center; }
.founder__portrait { border-radius: var(--radius-lg); overflow: hidden; background: var(--surface-sunken); }
/* Source photo is a tall 900x1355 portrait: centre-cropping cuts the head off,
   so anchor the crop to the top of the frame. */
.founder__portrait img {
  width: 100%;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  object-position: 50% top;
}
.founder__portrait--round {
  width: min(12rem, 60%);
  margin-inline: auto;
  border-radius: var(--radius-full);
  border: 4px solid var(--surface);
  box-shadow: var(--shadow);
}
.founder__portrait--round img { aspect-ratio: 1 / 1; }
.founder__name { margin-bottom: var(--space-1); }
.founder__credential {
  color: var(--gold-700);
  font-weight: 700;
  font-size: var(--fs-sm);
  margin-bottom: var(--space-4);
}
.founder__body > p { color: var(--text-muted); margin-bottom: var(--space-4); }

@media (min-width: 768px) {
  .contact-layout { grid-template-columns: 1.4fr 1fr; align-items: start; }
  .founder { grid-template-columns: 20rem 1fr; gap: var(--space-8); }
  .founder--teaser { grid-template-columns: 14rem 1fr; }
  .founder__portrait--round { width: 100%; }
}


/* --- 5.17 CTA band ------------------------------------------------------- */

.cta-band__inner {
  text-align: center;
  padding-block: var(--space-8);
}
.cta-band__title { color: var(--text-inverse); margin-bottom: var(--space-3); }
.cta-band__lead { color: var(--text-on-dark-muted); margin-bottom: var(--space-6); }
.cta-band__actions {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  align-items: stretch;
}

@media (min-width: 640px) {
  .cta-band__actions { flex-direction: row; flex-wrap: wrap; justify-content: center; }
}


/* --- 5.18 Login gate ------------------------------------------------------ */
/* Stands in for an enquiry / contact / buyer-interest form when nobody is
   signed in. Sized to sit inside the same card the form occupied, so the page
   layout does not jump between the two states. */

.login-gate {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: var(--space-2);
  padding: var(--space-5) var(--space-4);
  background: var(--surface-sunken);
  border-radius: var(--radius-lg);
}

.login-gate .bi {
  font-size: 1.5rem;
  color: var(--navy-800);
}

.login-gate__title {
  font-size: var(--fs-lg);
  margin: 0;
}

.login-gate__text {
  color: var(--text-muted);
  font-size: var(--fs-sm);
  max-width: 34ch;
  margin: 0;
}

.login-gate__actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--space-2);
  margin-top: var(--space-2);
  width: 100%;
}
.login-gate__actions .btn { flex: 1 1 9rem; }


/* --- 5.19 Account pages --------------------------------------------------- */
/* Login, signup, password reset and email confirmation. Those pages are
   rendered by django-allauth through main/templates/allauth/, which reuses
   .card, .field, .input and .btn — only the few classes below are new. */

/* Navy backdrop, matching .hero / .cta-band exactly (see 5.x above) so the
   account pages sit in the same visual world as the rest of the site. The
   header is navy too, so the two meet with no seam. */
.auth-page {
  position: relative;
  overflow: hidden;
  isolation: isolate;
  background: linear-gradient(135deg, var(--navy-900) 0%, var(--navy-800) 100%);
  /* Fill the viewport below the header even when the form is short, so no
     strip of page background shows beneath a compact login box. */
  min-height: calc(100vh - var(--header-h));
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding-block: var(--space-7);
}

.auth-page__bg {
  position: absolute;
  inset: 0;
  z-index: -1;
  background-image:
    radial-gradient(circle, rgba(255, 255, 255, 0.06) 1px, transparent 1px),
    radial-gradient(ellipse 70% 60% at 75% 20%, rgba(200, 146, 17, 0.20) 0%, transparent 62%);
  background-size: 26px 26px, 100% 100%;
}

/* The logo above the card. On a page whose whole job is asking for a
   password, showing whose site it is carries real weight. */
.auth-page__brand {
  display: flex;
  justify-content: center;
  margin-bottom: var(--space-5);
}
.auth-page__brand img {
  height: 46px;
  width: auto;
}

.auth-card {
  max-width: 26rem;
  margin-inline: auto;
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  box-shadow: var(--shadow-lg);
}

.auth-card__title {
  font-size: var(--fs-xl);
  margin: 0;
}

.auth-card__text {
  color: var(--text-muted);
  font-size: var(--fs-sm);
  margin: 0;
}

/* The "or" between the password form and the social buttons. The rule is
   drawn with a flex row rather than an <hr> so the label sits in the gap. */
.auth-divider {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  color: var(--text-subtle);
  font-size: var(--fs-sm);
}
.auth-divider::before,
.auth-divider::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--border);
}

.auth-providers {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}
.auth-provider {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
}

/* Account links in the mobile drawer, separated from the main nav above. */
.primary-nav__list--account {
  border-top: 1px solid rgba(255, 255, 255, 0.15);
  padding-top: var(--space-2);
}
.primary-nav__account {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) 0;
  color: rgba(255, 255, 255, 0.75);
  font-size: var(--fs-sm);
}
/* "Log out" is a submit button so it can POST, but it has to read as a nav
   link — this strips the button chrome without losing the button semantics. */
.primary-nav__linkbutton {
  background: none;
  border: none;
  padding: 0;
  font: inherit;
  color: inherit;
  cursor: pointer;
  text-align: left;
}

/* Matches the breakpoint at which the drawer becomes a horizontal bar (5.2). */
@media (min-width: 1024px) {
  /* margin-left:auto is the single thing separating the left-hand nav links
     from the right-hand account + Contact Us cluster. */
  .primary-nav__list--account {
    flex-direction: row;
    align-items: center;
    gap: var(--space-1);
    border-top: none;
    padding-top: 0;
    margin-left: auto;
    min-width: 0;
  }
  .primary-nav__account {
    /* A signed-in address is context, not navigation — dimmer and capped so
       admin@kaani100.com cannot squeeze the links beside it. */
    max-width: 11rem;
    min-width: 0;
    padding: 0 var(--space-2);
    border-right: 1px solid rgba(255, 255, 255, 0.18);
    color: rgba(255, 255, 255, 0.65);
    font-size: var(--fs-xs);
  }
  .primary-nav__account span {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .primary-nav__linkbutton {
    display: flex;
    align-items: center;
    min-height: 0;
    white-space: nowrap;
    color: rgba(255, 255, 255, 0.9);
    padding: var(--space-2) var(--space-3);
    border-radius: var(--radius-sm);
    font-size: var(--fs-sm);
    font-weight: 600;
  }
  .primary-nav__linkbutton:hover {
    color: var(--text-inverse);
    background: rgba(255, 255, 255, 0.12);
  }
}


/* --- 5.20 Motion ----------------------------------------------------------
   Four rules govern everything in this section.

   1. Decoration lives inside `prefers-reduced-motion: no-preference`, so it is
      structurally impossible for it to reach someone who asked for less
      movement. Only genuine function — the lightbox, the back-to-top button —
      sits outside, where section 7 strips its transitions instead.
   2. Anything that STARTS an element invisible is additionally gated on
      `html.js`, set inline in partials/_head.html. With JavaScript off or
      broken that hidden state never exists, so no content can be stranded.
   3. Reveal offsets use the standalone `translate` property rather than
      `transform`, so they compose with the hover lifts already declared on
      .p-card and .feature-card instead of fighting them for one declaration.
   4. Scroll-linked effects are wrapped in @supports. Where the browser can
      drive them off the scroller they cost no JavaScript and never jitter;
      where it cannot, they are simply absent.
   -------------------------------------------------------------------------- */


/* Same-origin navigations cross-fade instead of flashing the page background.
   Unsupported browsers just navigate the old way — there is no fallback to
   write. The header is named so it holds still while the content beneath it
   changes, rather than fading out and back in along with everything else. */

@view-transition { navigation: auto; }

.site-header { view-transition-name: site-header; }

/* Anchor targets stop below the sticky header instead of behind it.
   scroll-padding has to sit on the scrolling element itself — putting it on
   body does nothing — hence :has() to vary it per page rather than a body
   class. The detail page needs extra room because its section nav sticks
   below the header, and the nav's own links are anchors into the page. */
html { scroll-padding-top: calc(var(--header-h) + var(--space-4)); }
html:has(.page-detail) { scroll-padding-top: calc(var(--header-h) + 4.5rem); }


/* --- Header on scroll ---------------------------------------------------- */
/* Function, not decoration: it tells you the header is a layer above the page
   rather than part of it, which is worth keeping under reduced motion. */

.site-header {
  transition: background-color 260ms var(--ease), box-shadow 260ms var(--ease);
}
.site-header.is-scrolled {
  background: var(--navy-900);
  box-shadow: 0 8px 28px rgba(7, 20, 38, 0.32);
}
.site-header__logo img { transition: height 260ms var(--ease); }
.site-header.is-scrolled .site-header__logo img { height: 28px; }


/* --- Back to top --------------------------------------------------------- */

.to-top {
  position: fixed;
  right: var(--gutter);
  bottom: calc(var(--space-5) + env(safe-area-inset-bottom));
  z-index: var(--z-sticky-cta);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--tap-min);
  height: var(--tap-min);
  border-radius: var(--radius-full);
  background: var(--navy-800);
  color: var(--text-inverse);
  font-size: 1.125rem;
  cursor: pointer;
  box-shadow: var(--shadow-lg);
  opacity: 0;
  visibility: hidden;          /* keeps it out of the tab order while hidden */
  translate: 0 14px;
  transition: opacity 260ms var(--ease),
              translate 260ms var(--ease),
              visibility 260ms,
              background-color 180ms var(--ease);
}
.to-top.is-visible { opacity: 1; visibility: visible; translate: none; }
.to-top:hover { background: var(--navy-700); }

/* Clear of the sticky enquiry bar that only the property page carries. */
.page-detail .to-top { bottom: calc(5.5rem + env(safe-area-inset-bottom)); }
@media (min-width: 1024px) {
  .page-detail .to-top { bottom: calc(var(--space-5) + env(safe-area-inset-bottom)); }
}


/* --- Photo lightbox ------------------------------------------------------ */

.gallery__stage img { cursor: zoom-in; }

.lightbox {
  position: fixed;
  inset: 0;
  z-index: var(--z-drawer);
  display: grid;
  grid-template-rows: auto minmax(0, 1fr) auto;
  gap: var(--space-3);
  padding: var(--space-4);
  padding-block-end: calc(var(--space-4) + env(safe-area-inset-bottom));
  background: rgba(7, 20, 38, 0.94);
  opacity: 0;
  visibility: hidden;
  transition: opacity 240ms var(--ease), visibility 240ms;
}
.lightbox.is-open { opacity: 1; visibility: visible; }

.lightbox__bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  color: var(--text-on-dark);
}
.lightbox__count { font-size: var(--fs-sm); font-weight: 600; }

.lightbox__figure { display: grid; place-items: center; min-height: 0; }

.lightbox__img {
  max-width: 100%;
  max-height: 100%;
  width: auto;
  object-fit: contain;
  border-radius: var(--radius);
  opacity: 0;
  scale: 0.94;
  transition: opacity 320ms var(--ease), scale 320ms var(--ease);
}
.lightbox.is-open .lightbox__img { opacity: 1; scale: 1; }

.lightbox__nav { display: flex; justify-content: center; gap: var(--space-4); }

.lightbox__btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--tap-min);
  height: var(--tap-min);
  border-radius: var(--radius-full);
  background: rgba(255, 255, 255, 0.12);
  color: var(--text-inverse);
  font-size: 1.125rem;
  cursor: pointer;
  transition: background-color 180ms var(--ease);
}
.lightbox__btn:hover { background: rgba(255, 255, 255, 0.24); }

/* Digits stop jostling their neighbours while a number counts up. */
.pillar__num { font-variant-numeric: tabular-nums; }


/* --- Everything below is decoration, and opts out for reduced motion ------ */

@media (prefers-reduced-motion: no-preference) {

  /* Page transitions: content lifts away, the next page settles in under it. */
  ::view-transition-old(root) { animation: kaani-page-out 160ms var(--ease-exit) both; }
  ::view-transition-new(root) { animation: kaani-page-in 320ms var(--ease-entrance) 60ms both; }

  @keyframes kaani-page-out { to   { opacity: 0; translate: 0 -8px; } }
  @keyframes kaani-page-in  { from { opacity: 0; translate: 0 14px; } }

  /* In-page anchors glide rather than jump. */
  html { scroll-behavior: smooth; }

  /* --- Entrance engine -------------------------------------------------
     Choreography lives in the TEMPLATES as data-anim attributes; this file only
     defines what each named effect looks like. That split is the point: it is
     what lets Buyers Corner move differently from the property list, instead of
     every page sharing one global reveal.

     WHY KEYFRAMES AND NOT TRANSITIONS: the previous version set `transition` on
     .p-card, which replaced the shorthand the card already carried and silently
     killed its hover lift until that was restated by hand. Keyframes touch only
     the properties they name, so a card can arrive and lift under the pointer
     with neither effect aware of the other.

     PROPERTY OWNERSHIP — do not break this split:
         entrance owns  opacity, translate, scale, filter
         hover    owns  transform
     Both are independent properties and compose freely.

     Note the base state sets opacity:0 and `.is-in` sets opacity:1. That is
     load-bearing, not redundant: these keyframes declare only a `from`, so the
     browser reads the `to` off the element's own computed style. Leave the base
     0 in place and every animation would run 0 → 0. */

  .js [data-anim],
  .js [data-anim-stagger] > * { opacity: 0; }

  .js [data-anim].is-in,
  .js [data-anim-stagger] > .is-in {
    opacity: 1;
    animation-duration: var(--dur-reveal);
    animation-timing-function: var(--ease-entrance);
    animation-delay: var(--anim-delay, 0ms);
    animation-fill-mode: both;
  }

  /* Default for anything inside a staggered container. Declared BEFORE the
     explicit effects, so a child carrying its own data-anim still wins. */
  .js [data-anim-stagger] > .is-in { animation-name: anim-settle; }

  .js [data-anim="rise"].is-in   { animation-name: anim-rise; }
  .js [data-anim="fade"].is-in   { animation-name: anim-fade; }
  .js [data-anim="settle"].is-in { animation-name: anim-settle; }
  .js [data-anim="left"].is-in   { animation-name: anim-left; }
  .js [data-anim="right"].is-in  { animation-name: anim-right; }
  .js [data-anim="zoom"].is-in   { animation-name: anim-zoom; }
  .js [data-anim="count"].is-in  { animation-name: anim-rise; }

  /* `draw` is the odd one out: never hidden, just collapsed to nothing and then
     wiped open. Used for rules, underlines and the timeline. */
  .js [data-anim="draw"] {
    opacity: 1;
    scale: 0 1;
    transform-origin: 0 50%;
  }
  .js [data-anim="draw"].is-in {
    scale: 1 1;
    animation-name: anim-draw;
  }

  /* Headings that assemble a word at a time. The heading itself must stay
     opaque or the words would fade in twice over. */
  .js [data-anim="words"] { opacity: 1; }
  .js [data-anim="words"] .word {
    display: inline-block;
    opacity: 0;
  }
  .js [data-anim="words"].is-in .word {
    opacity: 1;
    animation: anim-word 640ms var(--ease-entrance) var(--anim-delay, 0ms) both;
  }

  @keyframes anim-rise   { from { opacity: 0; translate: 0 22px; } }
  @keyframes anim-fade   { from { opacity: 0; } }
  @keyframes anim-settle { from { opacity: 0; translate: 0 26px; scale: 0.96; } }
  @keyframes anim-left   { from { opacity: 0; translate: -32px 0; } }
  @keyframes anim-right  { from { opacity: 0; translate:  32px 0; } }
  @keyframes anim-zoom   { from { opacity: 0; scale: 0.92; } }
  @keyframes anim-draw   { from { scale: 0 1; } }
  @keyframes anim-word   { from { opacity: 0; translate: 0 18px; filter: blur(4px); } }

  /* --- Hero entrance ---
     Everything down by ~950ms. The :not([data-anim]) is required, not tidiness:
     a hero child that opts into the engine (the home headline, which arrives a
     word at a time) must not ALSO get the block fade, and these rules match the
     engine's specificity exactly — so without the exclusion, source order would
     hand the element this animation-delay and wreck the word timing. */
  .js .hero__inner > *:not([data-anim]),
  .js .page-hero__inner > *:not([data-anim]) {
    animation: kaani-hero-in var(--dur-hero) var(--ease-entrance) both;
  }
  .js .hero__inner > :nth-child(1):not([data-anim]),
  .js .page-hero__inner > :nth-child(1):not([data-anim]) { animation-delay:  40ms; }
  .js .hero__inner > :nth-child(2):not([data-anim]),
  .js .page-hero__inner > :nth-child(2):not([data-anim]) { animation-delay: 110ms; }
  .js .hero__inner > :nth-child(3):not([data-anim]),
  .js .page-hero__inner > :nth-child(3):not([data-anim]) { animation-delay: 180ms; }
  .js .hero__inner > :nth-child(4):not([data-anim]),
  .js .page-hero__inner > :nth-child(4):not([data-anim]) { animation-delay: 250ms; }

  @keyframes kaani-hero-in {
    from { opacity: 0; translate: 0 26px; filter: blur(5px); }
    to   { opacity: 1; translate: none;   filter: none; }
  }

  /* --- Ambient glow ---
     A second, wandering pool of gold over the static one already in the
     gradient. Only translate and scale move, so it composites on the GPU.

     Was a 26s cycle, which is below the threshold at which movement registers
     as movement — it spent frames and delivered nothing anyone could see. 14s
     with wider travel and a little more alpha actually reads. */
  .hero__bg::after,
  .cta-band__bg::after {
    content: "";
    position: absolute;
    inset: -25%;
    background: radial-gradient(circle at 50% 50%, rgba(220, 168, 40, 0.2), transparent 62%);
    animation: kaani-float 14s ease-in-out infinite alternate;
    pointer-events: none;
  }

  @keyframes kaani-float {
    from { translate: -12% -8%; scale: 1; }
    to   { translate:  14%  9%; scale: 1.22; }
  }

  /* --- Property photo zoom ---
     Slow in, quick out. A photo that takes its time settling and then snaps
     back is the same fast-in/slow-out principle inverted: here the LEAVING is
     the cheap move, so it is the one that should be over quickly. */
  .p-card__media img { transition: scale var(--dur-exit) var(--ease-exit); }
  .p-card:hover .p-card__media img,
  .p-card:focus-within .p-card__media img {
    scale: 1.07;
    transition-duration: 620ms;
    transition-timing-function: var(--ease-settle);
  }

  /* --- Scroll-linked, where the browser can drive it itself --- */
  @supports (animation-timeline: scroll()) {

    /* Reading progress along the bottom edge of the header. */
    .site-header::after {
      content: "";
      position: absolute;
      left: 0;
      bottom: -1px;
      width: 100%;
      height: 2px;
      background: linear-gradient(90deg, var(--gold-600), var(--gold-400));
      transform-origin: 0 50%;
      scale: 0 1;
      animation: kaani-progress linear both;
      animation-timeline: scroll(root block);
    }

    @keyframes kaani-progress { to { scale: 1 1; } }

    /* The hero backdrop drifts slower than the page scrolling over it. The
       scale covers the gap the translate would otherwise open at the top. */
    .hero__bg {
      animation: kaani-parallax linear both;
      animation-timeline: scroll(root block);
      animation-range: 0 100vh;
    }

    @keyframes kaani-parallax { to { translate: 0 12%; scale: 1.15; } }
  }
}


/* --- 5.21 Scroll-story components ----------------------------------------
   Page-specific furniture that only exists to tell a story as you scroll.
   Each of these degrades to something readable with JavaScript off — the rail
   shows as a solid line, steps sit at full opacity, nav links are plain
   anchors — so nothing here is load-bearing for comprehension.
   -------------------------------------------------------------------------- */

/* A parallaxed image is scaled up so the drift never exposes the frame behind
   it — its container clips to a fixed aspect ratio, so an unscaled image would
   show a sliver of background at one edge or the other for the whole scroll. */
.js [data-scroll="parallax"] { scale: 1.12; }


/* Buyers Corner: the four steps as a timeline that draws itself. */

.timeline { position: relative; }

.timeline__rail {
  position: absolute;
  left: 1.25rem;                 /* centre line of the 2.5rem numeral */
  top: 1.25rem;
  bottom: 1.25rem;
  width: 2px;
  border-radius: 2px;
  background: var(--border-strong);
}

/* The steps sit on a dark band, where the light tan rail reads as a drawn line
   rather than an undrawn one and steals attention from the gold fill. */
.section--dark .timeline__rail { background: rgba(255, 255, 255, 0.2); }

.timeline__fill {
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: linear-gradient(180deg, var(--gold-500), var(--gold-700));
  transform-origin: 50% 0;
  /* Default full: with no JavaScript the line is simply drawn already. The
     .js rule below is what collapses it so scrolling can fill it in. */
  scale: 1 1;
}
.js .timeline__fill { scale: 1 0; }

/* Vertical at every width — a timeline that reflows into four columns on
   desktop is no longer a timeline. This deliberately overrides the .steps
   grid from section 5.10. */
.steps--timeline {
  grid-template-columns: 1fr;
  gap: var(--space-5);
  padding-left: 3.75rem;
}

.steps--timeline .step__num {
  position: absolute;
  left: -3.75rem;
  top: var(--space-5);
  margin-bottom: 0;
  background: var(--surface);
  color: var(--text-muted);
  border: 2px solid var(--border-strong);
  transition: background-color var(--dur-hover) var(--ease-settle),
              border-color    var(--dur-hover) var(--ease-settle),
              color           var(--dur-hover) var(--ease-settle),
              scale           var(--dur-hover) var(--ease-settle);
}

/* Dimming is gated on .js: without it, nothing would ever brighten these
   back up and the whole section would read as permanently disabled. */
.js .steps--timeline .step {
  opacity: 0.5;
  transition: opacity    var(--dur-hover) var(--ease-settle),
              transform  var(--dur-hover) var(--ease-settle),
              box-shadow var(--dur-hover) var(--ease-settle);
}
.js .steps--timeline .step.is-active {
  opacity: 1;
  transform: translateX(4px);
  box-shadow: var(--shadow);
}
.steps--timeline .step.is-active .step__num {
  background: var(--gold-700);
  border-color: var(--gold-700);
  color: var(--text-inverse);
  scale: 1.08;
}

@media (min-width: 640px) {
  .steps--timeline { grid-template-columns: 1fr; padding-left: 4.5rem; }
  .steps--timeline .step__num { left: -4.5rem; }
  .timeline__rail { left: 1.5rem; }
}
@media (min-width: 1024px) {
  .steps--timeline { grid-template-columns: 1fr; }
}


/* Property detail: nav that tracks the section you are reading. */

.section-nav {
  position: sticky;
  top: var(--header-h);
  z-index: var(--z-sticky-cta);
  margin-bottom: var(--space-5);
  background: var(--surface-alt);
  border-bottom: 1px solid var(--border);
}

/* The scroll container is the inner row, not the sticky element itself —
   overflow on a sticky element is legal but makes it its own scroll container,
   which is a needless complication when a child can carry it instead. */
.section-nav__inner {
  display: flex;
  gap: var(--space-1);
  padding-block: var(--space-2);
  overflow-x: auto;
  scrollbar-width: none;
}
.section-nav__inner::-webkit-scrollbar { display: none; }

.section-nav a {
  flex-shrink: 0;
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-full);
  color: var(--text-muted);
  font-size: var(--fs-sm);
  font-weight: 600;
  text-decoration: none;
  white-space: nowrap;
  transition: background-color var(--dur-exit) var(--ease-exit),
              color            var(--dur-exit) var(--ease-exit);
}
.section-nav a:hover { color: var(--navy-800); background: var(--surface-sunken); }
.section-nav a.is-current {
  background: var(--navy-800);
  color: var(--text-inverse);
  transition-duration: var(--dur-hover);
  transition-timing-function: var(--ease-settle);
}


/* Listing: the result count and filter controls stay reachable while you
   scroll a long grid. */

.listing-toolbar {
  position: sticky;
  top: var(--header-h);
  z-index: var(--z-sticky-cta);
  padding-block: var(--space-3);
  background: var(--surface-alt);
}


/* List-your-land: how much of the form is left. */

.form-progress {
  position: sticky;
  top: calc(var(--header-h) + var(--space-2));
  z-index: 1;
  height: 4px;
  margin-bottom: var(--space-5);
  border-radius: var(--radius-full);
  overflow: hidden;
  background: var(--surface-sunken);
}

.form-progress__fill {
  display: block;
  height: 100%;
  background: linear-gradient(90deg, var(--gold-600), var(--gold-400));
  transform-origin: 0 50%;
  scale: 0 1;
  transition: scale var(--dur-hover) var(--ease-settle);
}


/* ==========================================================================
   6. UTILITIES
   ========================================================================== */

.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;
}

/* Locks background scrolling while the drawer or filter sheet is open. */
.is-scroll-locked { overflow: hidden; }


/* ==========================================================================
   7. MOTION PREFERENCES
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}
