/* =========================================================
   Denny Rumah Sabah — DESIGN 3
   "KK waterfront / golden hour"

   HERO DIRECTION PREVIEW. Hero, credentials strip, header,
   footer and a small sample strip only.
   ========================================================= */
:root {
  /* --- the four given colours --- */
  --navy:   #0E1B2A;   /* dusk navy   */
  --gold:   #F2C879;   /* sunset gold */
  --orange: #C9552E;   /* burnt orange, used sparingly */
  --sand:   #E8E2D4;   /* sand        */

  /* --- derived, to make the four usable --- */
  --navy-deep: #071120;   /* top of the sky, footer */
  --navy-mid:  #17293C;   /* raised panels on dark  */
  --sand-pale: #F5F1E7;   /* page ground, lighter than sand */
  --sand-deep: #D8D0BD;   /* sand edges and rules   */

  --ink:       var(--navy);
  --ink-soft:  #2C3E4F;
  --muted:     #505F6E;   /* navy-tinted, never a neutral grey. Dark enough for 4.5:1 on sand. */
  --faint:     #8394A3;

  /* ── THE TWO ACCENTS HAVE SEPARATE JOBS ────────────────────────────
     GOLD   = interactive. Primary CTAs, nav active indicator, every link,
              hover states. Nothing non-clickable may be gold.
     ORANGE = decorative, never interactive. Logo wordmark, card accent
              bars, section dividers. Nothing orange may be clickable.

     Measured, because the palette constrains how each can be used:
              gold on navy      11.0:1   fine as text
              gold on sand       1.4:1   UNUSABLE as text — fill only
              orange on navy      4.0:1  fails as text, passes as a shape
              orange on sand      3.9:1  fails as text, passes as a shape

     So gold is TEXT only on navy, and a FILLED button anywhere else.
     Orange is only ever a SHAPE (rule, bar, wordmark) — never text.
     Neither is used for plain labels; those use the ink/sand/muted ramp. */

  --line-light: rgba(14, 27, 42, .13);
  --line-dark:  rgba(232, 226, 212, .16);  /* neutral hairline, not an accent */

  --display: "Fraunces", "Iowan Old Style", Georgia, serif;
  --font:    "Figtree", system-ui, -apple-system, sans-serif;

  --wrap:   1200px;
  --gutter: 28px;

  --ease: cubic-bezier(.16, 1, .3, 1);
  --fast: .18s;
  --mid:  .32s;
  --slow: .7s;

  --z-header: 60;
  --z-scrim:  65;
  --z-panel:  70;
  --z-float:  80;
  --z-skip:  100;
}

/* Fraunces is variable. SOFT rounds the terminals and WONK swaps in the
   friendlier alternates — this is what keeps it humanist rather than Didone. */
.display, h1, h2, h3, .logo, .price, .cred dd {
  font-family: var(--display);
  font-variation-settings: "SOFT" 45, "WONK" 1;
}

/* ---------------- base ---------------- */
*, *::before, *::after { box-sizing: border-box; }

html {
  scroll-behavior: smooth;
  scroll-padding-top: 86px;
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--sand-pale);
  color: var(--ink);
  font-family: var(--font);
  font-size: 16px;
  font-weight: 400;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: clip;   /* not hidden: hidden makes body a scroll container and breaks the sticky header */
}
body.is-locked { overflow: hidden; }

img { display: block; max-width: 100%; height: auto; }
a { color: inherit; text-decoration: none; }
h1, h2, h3 { margin: 0; font-weight: 400; }
p { margin: 0; text-wrap: pretty; }
ul, ol, dl, dd { margin: 0; padding: 0; }
li { list-style: none; }

/* Sentence case everywhere. Hierarchy is size and weight, never uppercase. */
h1 {
  font-size: clamp(33px, 6.4vw, 78px);
  font-weight: 400;
  line-height: 1.04;
  letter-spacing: -.018em;
  text-wrap: balance;
}
h2 {
  font-size: clamp(26px, 3.9vw, 46px);
  font-weight: 400;
  line-height: 1.12;
  letter-spacing: -.015em;
  text-wrap: balance;
}
h3 {
  font-size: 21px;
  font-weight: 500;
  line-height: 1.25;
  letter-spacing: -.01em;
  text-wrap: balance;
}
/* Emphasis is italic ONLY — not italic AND a colour change. Stacking both
   makes the phrase shout twice. On dark grounds it inherits the sand it sits
   in; on light grounds it inherits the ink. */
h1 em, h2 em { font-style: italic; color: inherit; }

.price { font-variant-numeric: tabular-nums; }
::selection { background: var(--gold); color: var(--navy); }

/* Interactive, so gold. The navy halo keeps it visible on sand, where gold
   alone measures 1.4:1. */
:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: 3px;
  box-shadow: 0 0 0 5px rgba(14, 27, 42, .55);
}
:focus:not(:focus-visible) { outline: none; }

.skip-link {
  position: absolute; top: 0; left: 50%;
  transform: translate(-50%, -120%);
  z-index: var(--z-skip);
  padding: 12px 24px;
  background: var(--navy); color: var(--gold);
  font-size: 14px; font-weight: 500;
  transition: transform var(--mid) var(--ease);
}
.skip-link:focus { transform: translate(-50%, 0); }

.wrap {
  width: 100%; max-width: var(--wrap);
  margin-inline: auto; padding-inline: var(--gutter);
}
.section { padding-block: 84px 92px; }

/* ═══════════════════════════════════════════════════════
   THE HORIZON MOTIF
   Replaces every plain hairline. A sea/sky line: bright at the
   centre, fading out at both ends, with a whisper of orange in it.
   ═══════════════════════════════════════════════════════ */
.horizon-rule {
  height: 2px; border: 0; margin: 0;
  background: linear-gradient(
    to right,
    transparent 0%,
    rgba(201, 85, 46, .35) 14%,
    var(--orange) 42%,
    var(--orange) 58%,
    rgba(201, 85, 46, .35) 86%,
    transparent 100%
  );
  opacity: .75;
}

/* ---------------- header ----------------
   Transparent over the hero sky, sand once scrolled past it. */
.site-header {
  position: sticky; top: 0; z-index: var(--z-header);
  background: transparent;
  border-bottom: 1px solid transparent;
  transition: background var(--mid) var(--ease), border-color var(--mid) var(--ease);
}
.site-header.is-stuck {
  background: rgba(14, 27, 42, .93);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border-bottom-color: rgba(201, 85, 46, .34);
}

.header-inner {
  height: 78px;
  display: flex; align-items: center; justify-content: space-between; gap: 26px;
}

.logo {
  font-size: 23px; font-weight: 500;
  letter-spacing: -.015em;
  white-space: nowrap;
  color: var(--sand-pale);
  transition: color var(--mid) var(--ease);
}
.logo span { color: var(--orange); }

.nav { display: flex; align-items: center; gap: 28px; font-size: 15px; }
.nav a {
  position: relative;
  color: rgba(232, 226, 212, .82);
  padding-block: 4px;
  transition: color var(--mid) var(--ease);
}
.nav a::after {
  content: ""; position: absolute; left: 0; bottom: 0;
  width: 100%; height: 1.5px; background: var(--gold);
  transform: scaleX(0); transform-origin: left;
  transition: transform var(--mid) var(--ease);
}
.nav a:hover { color: var(--sand-pale); }
/* The underline is reserved for the current section. Hover only brightens the
   text — otherwise a cursor left resting on a nav item after a click looks
   exactly like the active indicator, which is what it used to do. */
.nav a.is-current::after { transform: scaleX(1); }

.header-actions { display: flex; align-items: center; gap: 12px; }

.nav-toggle {
  display: none;
  width: 44px; height: 44px; padding: 0;
  background: transparent;
  border: 1px solid rgba(232, 226, 212, .35);
  border-radius: 4px;
  cursor: pointer; align-items: center; justify-content: center;
  transition: border-color var(--mid) var(--ease);
}
.nav-toggle:hover { border-color: var(--gold); }
.nav-toggle-bars { position: relative; width: 18px; height: 12px; display: block; }
.nav-toggle-bars span {
  position: absolute; left: 0; width: 100%; height: 1.5px;
  background: var(--sand-pale);
  transition: transform var(--mid) var(--ease), background var(--mid) var(--ease);
}
.nav-toggle-bars span:first-child { top: 1px; }
.nav-toggle-bars span:last-child { bottom: 1px; }
.nav-toggle[aria-expanded="true"] .nav-toggle-bars span:first-child { transform: translateY(4.5px) rotate(45deg); }
.nav-toggle[aria-expanded="true"] .nav-toggle-bars span:last-child { transform: translateY(-4.5px) rotate(-45deg); }

.nav-scrim {
  position: fixed; inset: 0; z-index: var(--z-scrim);
  background: rgba(7, 17, 32, .62);
  opacity: 0; transition: opacity var(--mid) var(--ease);
}
.nav-scrim.is-open { opacity: 1; }

.mobile-nav {
  position: fixed; top: 0; right: 0; z-index: var(--z-panel);
  width: min(350px, 86vw); height: 100dvh;
  padding: 92px 28px 32px;
  background: var(--navy);
  display: flex; flex-direction: column; gap: 2px;
  transform: translateX(100%);
  transition: transform var(--slow) var(--ease);
  overflow-y: auto;
}
.mobile-nav.is-open { transform: translateX(0); }
.mobile-nav a:not(.btn) {
  padding: 15px 4px;
  font-family: var(--display);
  font-variation-settings: "SOFT" 45, "WONK" 1;
  font-size: 27px;
  color: var(--sand);
  border-bottom: 1px solid var(--line-dark);
  transition: color var(--mid) var(--ease), padding-left var(--mid) var(--ease);
}
.mobile-nav a:not(.btn):hover { color: var(--gold); padding-left: 10px; }
.mobile-nav-cta { margin-top: 26px; }

/* ---------------- buttons ---------------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center;
  padding: 15px 28px;
  border: 1.5px solid transparent;
  border-radius: 3px;
  font-family: inherit;
  font-size: 15px; font-weight: 600;
  letter-spacing: -.005em; line-height: 1;
  cursor: pointer;
  transition: background var(--mid) var(--ease), color var(--mid) var(--ease),
              border-color var(--mid) var(--ease), transform var(--fast) var(--ease);
}
.btn-sm { padding: 10px 18px; font-size: 14px; }
.btn-block { width: 100%; }

.btn-solid { background: var(--gold); color: var(--navy); }
.btn-solid:hover { background: #F7D693; }
.btn-solid:active { transform: translateY(1px) scale(.99); }

.btn-ghost { border-color: rgba(232, 226, 212, .45); color: var(--sand-pale); }
.btn-ghost:hover { border-color: var(--gold); color: var(--gold); }
.btn-ghost:active { transform: translateY(1px) scale(.99); }

/* ═══════════════════════════════════════════════════════
   HERO — full bleed golden hour
   ═══════════════════════════════════════════════════════ */
.hero {
  position: relative;
  min-height: 94dvh;
  display: flex; align-items: flex-end;
  padding-block: 132px 76px;
  margin-top: -78px;          /* slide up under the transparent header */
  overflow: hidden;
  isolation: isolate;
}

/* The photograph. Positioned at 38% horizontally rather than centre so the
   palm trees and the near lamp post — the visually rich left edge — survive
   the crop when a phone squeezes a 16:9 image into a tall viewport.

   image-set lets modern browsers take the WebP (106 kB) while anything older
   falls back to the progressive JPEG (148 kB). The plain url() line above it
   is the fallback for browsers that do not understand image-set at all. */
.hero-photo {
  position: absolute; inset: 0; z-index: -1;
  background-color: var(--navy);
  background-image: url("images/hero-waterfront.jpg");
  background-image: image-set(
    url("images/hero-waterfront.webp") type("image/webp"),
    url("images/hero-waterfront.jpg")  type("image/jpeg")
  );
  background-size: cover;
  background-position: 38% center;
  background-repeat: no-repeat;
}

/* Overlay. Strongest on the left where the headline and paragraph sit,
   fading out to the right so the sunset, boats and lamp posts stay visible.
   Darker than the brief's starting values — measured against the photo, the
   original 0.75/0.45/0.15 left the body copy short of 4.5:1 where the sky is
   brightest. The vertical pass handles the gold band near the waterline. */
.hero-scrim {
  position: absolute; inset: 0;
  background:
    linear-gradient(to bottom,
      rgba(14, 27, 42, .55) 0%,
      rgba(14, 27, 42, .18) 34%,
      rgba(14, 27, 42, .30) 72%,
      rgba(14, 27, 42, .72) 100%),
    linear-gradient(to right,
      rgba(14, 27, 42, .91) 0%,
      rgba(14, 27, 42, .83) 26%,
      rgba(14, 27, 42, .58) 48%,
      rgba(14, 27, 42, .24) 72%,
      rgba(14, 27, 42, .10) 100%);
}

.hero-inner {
  position: relative; z-index: 1;
  display: flex; flex-direction: column;
  align-items: flex-start; gap: 24px;
}
.hero-inner h1 {
  max-width: 15ch;
  color: var(--sand-pale);
  text-shadow: 0 1px 18px rgba(7, 17, 32, .55);
}
.hero-inner .lead {
  max-width: 56ch;
  font-size: 17.5px;
  line-height: 1.7;
  color: rgba(232, 226, 212, .90);
  text-shadow: 0 1px 14px rgba(7, 17, 32, .6);
}

/* Credential line — a hairline rule instead of a middle dot */
.hero-cred {
  display: flex; align-items: center; flex-wrap: wrap; gap: 12px;
  font-size: 14px;
  color: rgba(245, 241, 231, .92);
}
.hero-cred-rule {
  width: 26px; height: 1px;
  background: currentColor; opacity: .55;
}

.btn-row { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 4px; }

/* ═══════════════════════════════════════════════════════
   CREDENTIALS STRIP
   Sits on sand, directly under the hero's sea. The horizon
   rule carries the motif across the seam.
   ═══════════════════════════════════════════════════════ */
.creds-band { background: var(--sand); position: relative; }
.creds-band::before {
  content: "";
  position: absolute; left: 0; right: 0; top: 0;
  height: 2px;
  background: linear-gradient(to right, transparent, var(--orange) 38%, var(--orange) 62%, transparent);
  opacity: .85;
}
.creds {
  display: grid; grid-template-columns: repeat(4, 1fr);
  gap: 1px;
  background: var(--sand-deep);
  border-inline: 1px solid var(--sand-deep);
}
.cred { background: var(--sand); padding: 30px 26px 32px; }
/* Label: small and quiet. No uppercase, no letter-spacing. */
.cred dt {
  font-size: 13.5px; font-weight: 500;
  color: var(--muted);
}
.cred dd {
  margin-top: 7px;
  font-size: clamp(21px, 2.2vw, 28px);
  font-weight: 500;
  line-height: 1.15;
  letter-spacing: -.015em;
  color: var(--ink);
}

/* Plain label. No number, no caps, no tracking. */
/* Not an accent. Orange fails as small text (3.9:1) and gold is reserved for
   things you can click, so labels sit in the normal text ramp instead. */
.section-label {
  font-size: 14px;
  font-weight: 600;
  color: var(--muted);
  margin-bottom: 12px;
}
.section-note {
  max-width: 58ch;
  margin-top: 16px;
  font-size: 16.5px;
  line-height: 1.7;
  color: var(--muted);
}

/* Links carry their own weight and underline. No trailing arrow. */
/* Every link is gold, because every link is an action. In-page links such as
   "Residential listings" are lower priority but still clickable, so they stay
   in the interactive colour. Orange was not an option regardless: as link
   text it measures 4.0:1 on navy and 3.9:1 on sand, both under the 4.5:1
   small-text minimum. */
.link {
  font-size: 16px;
  font-weight: 600;
  color: var(--gold);
  text-decoration: underline;
  text-decoration-color: rgba(242, 200, 121, .42);
  text-decoration-thickness: 1.5px;
  text-underline-offset: 5px;
  transition: text-decoration-color var(--mid) var(--ease), color var(--mid) var(--ease);
}
.link:hover { color: #F7D693; text-decoration-color: var(--gold); }

/* On a sand ground gold text is 1.4:1, so a link there becomes a filled gold
   pill instead: same colour, same meaning, legible. For the light sections
   still to be built. */
.link-pill {
  display: inline-flex; align-items: center;
  padding: 11px 20px;
  background: var(--gold); color: var(--navy);
  border-radius: 3px;
  font-size: 15px; font-weight: 600;
  text-decoration: none;
  transition: background var(--mid) var(--ease), transform var(--fast) var(--ease);
}
.link-pill:hover { background: #F7D693; }
.link-pill:active { transform: translateY(1px) scale(.99); }
/* Sized for a compact card footer, where the full .link-pill is too heavy. */
.link-pill-sm { padding: 7px 14px; font-size: 13px; }

/* These CTAs are real <button> elements now (their WhatsApp message is built
   from the page location at click time, so a static href cannot carry it) —
   strip the native button chrome that .link-pill and .price-tbd never had to
   account for when they were plain <a> tags. Background/colour stay owned by
   whichever of those two classes is paired with this one. */
.ask-price {
  appearance: none; -webkit-appearance: none;
  border: 0; font-family: inherit; cursor: pointer;
}
.price-tbd.ask-price { background: none; padding: 0; }

/* 1. Listing — photo-led, square, grounded by a gold price rule.
      Has an edge because it is a discrete object you can click. */

.listing-place { font-size: 14px; font-weight: 500; color: var(--muted); }

/* 2. Stat — not a card at all. No box, no shadow. Just a horizon
      rule above it, because a number is a fact, not an object. */

/* 3. Testimonial — an inset sand panel, no border, no shadow, with a
      big orange quote mark. Recessed rather than raised, so it reads
      as something quoted rather than something offered. */

.card-quote-cite strong { color: var(--ink); font-weight: 600; }

/* ═══════════════════════════════════════════════════════
   SECTION RHYTHM
   The ground colour alternates down the page so it does not
   read the same top to bottom. The horizon rule sits on every
   seam, which is what ties the alternation together rather
   than making it look like unrelated blocks.
   ═══════════════════════════════════════════════════════ */
.section { position: relative; }
.section::before {
  content: "";
  position: absolute; left: 0; right: 0; top: 0; height: 2px;
  background: linear-gradient(to right, transparent, var(--orange) 38%, var(--orange) 62%, transparent);
  opacity: .8;
}
.section-light { background: var(--sand-pale); }
.section-sand  { background: var(--sand); }
.section-dark  { background: var(--navy); color: var(--sand); }
.section-dark::before { opacity: .95; }

/* On navy, gold becomes the accent and body copy warms toward sand. */
.section-dark h2, .section-dark h3 { color: var(--sand-pale); }
.section-dark .section-label { color: rgba(232, 226, 212, .68); }
.section-dark .section-note { color: rgba(232, 226, 212, .74); }

.section-head {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: 48px; margin-bottom: 52px;
}
.section-head > div { display: flex; flex-direction: column; }
.section-head .section-note { margin-top: 0; }

/* ---------------- About ---------------- */
.about {
  display: grid; grid-template-columns: 1.05fr .95fr;
  gap: 74px; align-items: center;
}
.about-copy { display: flex; flex-direction: column; align-items: flex-start; gap: 18px; }
.about-copy h2 { max-width: 13ch; margin-bottom: 6px; }
.about-copy p { max-width: 60ch; font-size: 16.5px; line-height: 1.76; color: var(--muted); }

.tags { display: flex; flex-wrap: wrap; gap: 9px; margin-top: 12px; }
.tag {
  padding: 7px 15px;
  border: 1px solid var(--sand-deep);
  border-radius: 20px;
  font-size: 14px;
  color: var(--muted);
}

.about-media { position: relative; }
.about-frame {
  position: relative;
  margin: 0; overflow: hidden;
  aspect-ratio: 4 / 5.1;
  border-radius: 4px 4px 0 0;
  /* Matches the portrait studio backdrop exactly (sampled #252e3e on all four
     corners), so any sub-pixel edge blends instead of showing a seam. */
  background: #252e3e;
  /* The image rests on its horizon line rather than a plain edge. */
  border-bottom: 3px solid var(--orange);
  /* Navy-tinted and soft, so the panel is seated on the sand rather than
     stamped onto it. A neutral black shadow would look pasted. */
  box-shadow: 0 18px 44px rgba(37, 46, 62, .26), 0 2px 8px rgba(37, 46, 62, .14);
}
/* <picture> is inline with auto height, which would break the img height:100%. */
.about-frame picture { display: block; width: 100%; height: 100%; }
.about-frame img { width: 100%; height: 100%; object-fit: cover; }

/* An inner vignette in the photo own backdrop colour. The studio background is
   flat, so without this the navy meets the frame edge dead flat and reads as a
   cutout. Darkening the corners inward makes it read as lit depth instead.
   Feathering the panel into the cream was tried first and looked worse: fading
   a dark field into a light one produces a grey haze band, and his head sits
   too close to the top edge to fade there at all. */
.about-frame::after {
  content: ;
  position: absolute; inset: 0;
  pointer-events: none;
  background: radial-gradient(120% 92% at 50% 38%, rgba(37,46,62,0) 42%, rgba(23,30,42,.55) 100%);
}

/* ---------------- Projects ----------------
   Four equivalent categories, so an even grid is the honest layout.
   The differentiation is in the card treatment, not the sizing.
   Numbers are gone: these are a set, not a sequence. */
.pillars { display: grid; grid-template-columns: repeat(2, 1fr); gap: 24px; }
.pillar {
  display: flex; flex-direction: column;
  background: var(--navy-mid);
  border: 1px solid var(--line-dark);
  border-radius: 4px;
  overflow: hidden;
  transition: border-color var(--slow) var(--ease), transform var(--slow) var(--ease);
}
.pillar:hover { border-color: rgba(242, 200, 121, .48); transform: translateY(-4px); }

.pillar-media { position: relative; margin: 0; aspect-ratio: 16 / 10; overflow: hidden; }
/* <picture> is inline with auto height by default, so the img inside it would
   lose its height:100% and stop filling the 16:10 box. This keeps the card
   with a real photo cropping identically to the picsum placeholders. */
.pillar-media picture { display: block; width: 100%; height: 100%; }
.pillar-media img { width: 100%; height: 100%; object-fit: cover; transition: transform 1.1s var(--ease); }
.pillar:hover .pillar-media img { transform: scale(1.05); }
/* The horizon again, this time as the waterline between photo and text. */
.pillar-media::after {
  content: "";
  position: absolute; left: 0; right: 0; bottom: 0; height: 2px;
  background: linear-gradient(to right, var(--orange), rgba(201, 85, 46, .35) 78%, transparent);
}

.pillar-body {
  padding: 26px 26px 28px;
  display: flex; flex-direction: column; align-items: flex-start; gap: 6px;
  flex: 1;
}
.pillar-title {
  font-family: var(--display);
  font-variation-settings: "SOFT" 45, "WONK" 1;
  font-size: 27px; font-weight: 500; line-height: 1.12;
  letter-spacing: -.015em;
  color: var(--sand-pale);
}
.pillar-ms { font-size: 14px; color: rgba(232, 226, 212, .52); }
.pillar-desc {
  margin-top: 8px;
  font-size: 15.5px; line-height: 1.7;
  color: rgba(232, 226, 212, .78);
}
.pillar .link { margin-top: auto; padding-top: 18px; }

/* ---------------- preview note (not part of the design) ---------------- */
.preview-note {
  margin-bottom: 84px; padding: 24px 26px;
  border: 1px dashed var(--sand-deep);
  border-radius: 6px;
  display: flex; flex-direction: column; gap: 12px;
  max-width: 70ch;
  font-size: 15px; line-height: 1.7; color: var(--muted);
}
.preview-note strong { color: var(--ink); font-weight: 600; }

/* ---------------- footer ---------------- */
.site-footer { background: var(--navy); color: var(--sand); position: relative; }
.site-footer::before {
  content: "";
  position: absolute; left: 0; right: 0; top: 0; height: 2px;
  background: linear-gradient(to right, transparent, var(--orange) 38%, var(--orange) 62%, transparent);
  opacity: .85;
}
.footer-inner {
  padding-block: 46px 50px;
  display: flex; flex-wrap: wrap; gap: 24px 44px;
  align-items: center; justify-content: space-between;
}
.footer-brand { display: flex; flex-direction: column; gap: 6px; }
.site-footer .logo { color: var(--sand-pale); }
.site-footer .logo span { color: var(--orange); }
.footer-note { font-size: 14.5px; color: rgba(232, 226, 212, .72); }
.legal { font-size: 13.5px; color: rgba(232, 226, 212, .55); }
/* Navy ground, so gold is the correct interactive colour here — it only
   fails contrast on the light/sand sections. */
.legal a {
  color: var(--gold);
  text-decoration: underline;
  text-underline-offset: 3px;
}
.legal a:hover { color: var(--sand); }

/* ---------------- whatsapp float ---------------- */
.wa-float {
  position: fixed; right: 22px; bottom: 22px; z-index: var(--z-float);
  width: 56px; height: 56px;
  display: flex; align-items: center; justify-content: center;
  background: var(--gold); color: var(--navy);
  border-radius: 50%;
  box-shadow: 0 10px 28px rgba(14, 27, 42, .30);
  transition: transform var(--mid) var(--ease), background var(--mid) var(--ease);
}
.wa-float:hover { background: #F7D693; transform: translateY(-3px) scale(1.05); }
.wa-float:active { transform: translateY(0) scale(.96); }

/* ---------------- reveals ---------------- */
.js .reveal {
  opacity: 0; transform: translateY(20px);
  transition: opacity var(--slow) var(--ease), transform var(--slow) var(--ease);
  transition-delay: var(--d, 0ms);
}
.js .reveal.is-in { opacity: 1; transform: none; }

/* ---------------- responsive ----------------
   Mobile matters most here — that is where the buyers are. */
@media (max-width: 1024px) {
  .nav { display: none; }
  .nav-toggle { display: inline-flex; }
  .about { grid-template-columns: 1fr; gap: 44px; }
  .about-media { max-width: 520px; }
  .section-head { flex-direction: column; align-items: flex-start; gap: 18px; }
}

@media (max-width: 820px) {
  .creds { grid-template-columns: repeat(2, 1fr); }
}

@media (max-width: 680px) {
  :root { --gutter: 20px; }
  .hero { min-height: 88dvh; padding-block: 112px 56px; }
  /* Raise the horizon on a tall narrow screen so the copy is not
     sitting on top of the brightest part of the sky. */
  /* Hold the palm trees and near lamp post in frame on a narrow crop. */
  .hero-photo {
    background-position: 30% center;
    background-image: url("images/hero-waterfront-800.jpg");
    background-image: image-set(
      url("images/hero-waterfront-800.webp") type("image/webp"),
      url("images/hero-waterfront-800.jpg")  type("image/jpeg")
    );
  }
  /* Copy spans the full width here, so the overlay has to work top-to-bottom
     rather than left-to-right. */
  .hero-scrim {
    background:
      linear-gradient(to bottom,
        rgba(14, 27, 42, .40) 0%,
        rgba(14, 27, 42, .26) 24%,
        rgba(14, 27, 42, .66) 42%,
        rgba(14, 27, 42, .86) 56%,
        rgba(14, 27, 42, .93) 70%,
        rgba(14, 27, 42, .96) 100%);
  }
  .hero-inner { gap: 20px; }
  .hero-inner h1 { max-width: 100%; }
  .btn-row { width: 100%; }
  .btn-row .btn { flex: 1 1 100%; }
  .section { padding-block: 60px 66px; }
  .cred { padding: 22px 18px 24px; }
  .pillars { grid-template-columns: 1fr; gap: 18px; }
  .about-copy h2 { max-width: 100%; }
  .wa-float { right: 16px; bottom: 16px; }
}

@media (max-width: 520px) {
  /* Logo + CTA + hamburger overflows 390px. The same WhatsApp link is in the
     menu and on the floating button, so the header one is the right thing to
     drop rather than shrinking everything. */
  .header-actions .btn { display: none; }
  .logo { font-size: 20px; }
  .hero-inner .lead { font-size: 16.5px; }
  .hero-cred { font-size: 13px; gap: 9px; }
}

/* ═══════════════════════════════════════════════════════
   LISTINGS
   Two card treatments, deliberately unalike: the featured one
   is a wide split panel, the grid ones are compact and square.
   Both are grounded by an orange accent bar rather than a shadow.
   ═══════════════════════════════════════════════════════ */
.filters { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 16px; }
.filter {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 10px 18px;
  background: transparent;
  border: 1px solid var(--sand-deep);
  border-radius: 3px;
  font-family: inherit;
  font-size: 14.5px; font-weight: 500;
  color: var(--muted);
  cursor: pointer;
  transition: background var(--mid) var(--ease), color var(--mid) var(--ease),
              border-color var(--mid) var(--ease), transform var(--fast) var(--ease);
}
.filter:hover { border-color: var(--navy); color: var(--ink); }
.filter:active { transform: scale(.98); }
/* Selecting a filter is an action, so the active one takes the gold fill. */
.filter.is-active {
  background: var(--gold);
  border-color: var(--gold);
  color: var(--navy);
  font-weight: 600;
}
.filter-count { font-variant-numeric: tabular-nums; opacity: .65; }

.filter-status {
  min-height: 22px; margin-bottom: 22px;
  font-size: 14px; color: var(--muted);
}
.listing-empty { padding: 56px 0; text-align: center; font-size: 17px; color: var(--muted); }

.badge {
  align-self: flex-start;
  padding: 4px 12px;
  border: 1px solid var(--orange);
  border-radius: 20px;
  font-size: 12.5px; font-weight: 600;
  color: var(--orange);
}

.listing-featured {
  display: grid; grid-template-columns: 1.15fr .85fr;
  margin-bottom: 22px;
  background: #fff;
  border: 1px solid var(--sand-deep);
  border-radius: 4px;
  overflow: hidden;
}
.listing-featured-media { position: relative; margin: 0; min-height: 380px; overflow: hidden; }
.listing-featured-media img { width: 100%; height: 100%; object-fit: cover; transition: transform 1.1s var(--ease); }
.listing-featured:hover .listing-featured-media img { transform: scale(1.04); }
.listing-featured-body {
  display: flex; flex-direction: column; align-items: flex-start; gap: 13px;
  padding: 38px 38px 36px;
}
.listing-featured-body h3 {
  font-family: var(--display);
  font-variation-settings: "SOFT" 45, "WONK" 1;
  font-size: 30px; font-weight: 500; line-height: 1.14; letter-spacing: -.015em;
}
.listing-note { font-size: 15.5px; line-height: 1.7; color: var(--muted); }

.listing-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 22px; }
.listing {
  display: flex; flex-direction: column;
  background: #fff;
  border: 1px solid var(--sand-deep);
  border-radius: 4px;
  overflow: hidden;
  transition: transform var(--slow) var(--ease), border-color var(--slow) var(--ease);
}
/* Lift only. These cards are not links, and orange on a hover state would
   break the rule that orange is never interactive. Gold was not an option
   either: on a white card it measures 1.3:1 and would be invisible. */
.listing:hover { transform: translateY(-4px); }
.listing:hover .listing-media img { transform: scale(1.05); }
.is-hidden { display: none !important; }

.listing-media { position: relative; margin: 0; aspect-ratio: 3 / 2; overflow: hidden; }
.listing-media img { width: 100%; height: 100%; object-fit: cover; transition: transform 1.1s var(--ease); }
/* The horizon again, as the waterline between photo and text. Decorative. */
.listing-media::after {
  content: "";
  position: absolute; left: 0; right: 0; bottom: 0; height: 2px;
  background: linear-gradient(to right, var(--orange), rgba(201, 85, 46, .35) 78%, transparent);
}

/* Wrapper is a <figure>; the photo itself is now a <button> so the whole
   card image is a real, keyboard-reachable control that opens the lightbox
   rather than a div with a click handler bolted on. */
.listing-media-wrap, .listing-featured-media { margin: 0; }

.photo-trigger {
  appearance: none; -webkit-appearance: none;
  display: block; width: 100%; height: 100%;
  padding: 0; margin: 0; border: 0; background: none;
  font: inherit; text-align: left; cursor: pointer;
}
.photo-trigger picture { display: block; width: 100%; height: 100%; }
.photo-trigger:focus-visible { outline-offset: -3px; }

.photo-badge {
  position: absolute; right: 10px; bottom: 10px; z-index: 1;
  padding: 5px 11px;
  background: rgba(14, 27, 42, .74);
  backdrop-filter: blur(3px);
  border-radius: 20px;
  font-size: 12.5px; font-weight: 500;
  color: var(--gold);
}

/* No photos yet: an honest placeholder rather than a stock filler image,
   sized to match its siblings so the grid still lines up. */
.listing-media-pending {
  display: flex; align-items: center; justify-content: center;
  aspect-ratio: 3 / 2;
  border: 1.5px dashed var(--sand-deep);
  background: var(--sand);
}
.pending-label { font-size: 14px; color: var(--muted); }
.listing-pending:hover { transform: none; }

/* "Ask for price" is not a number, so it should not carry the same visual
   weight as one — it is a placeholder for data Denny has not confirmed.
   It is also now a real link (opens WhatsApp with the listing named), so it
   needs an interactive cue: an underline at rest, darkening on hover. Not
   gold — this section sits on light cards, and gold text measures 1.4:1
   there, the same reason grid cards get a filled pill instead of gold text. */
.price-tbd {
  font-style: italic; color: var(--muted); font-weight: 500;
  text-decoration: underline;
  text-decoration-color: rgba(80, 95, 110, .35);
  text-underline-offset: 4px;
  transition: color var(--mid) var(--ease), text-decoration-color var(--mid) var(--ease);
}
.price-tbd:hover, .price-tbd:focus-visible {
  color: var(--ink); text-decoration-color: var(--ink);
}



.listing-body {
  display: flex; flex-direction: column; align-items: flex-start; gap: 9px;
  padding: 22px 22px 24px; flex: 1;
}
.listing-body h3 {
  font-family: var(--display);
  font-variation-settings: "SOFT" 45, "WONK" 1;
  font-size: 23px; font-weight: 500; line-height: 1.16; letter-spacing: -.015em;
}
.listing-place { font-size: 14px; font-weight: 500; color: var(--muted); }

.specs { display: flex; flex-wrap: wrap; gap: 7px; font-size: 14px; color: var(--muted); }
.specs li { display: flex; align-items: center; gap: 7px; }
/* A dot between items, not a middle dot typed into the copy. */
.specs li + li::before {
  content: ""; width: 3px; height: 3px; border-radius: 50%;
  background: var(--sand-deep); flex: none;
}

.listing-tags { display: flex; flex-wrap: wrap; gap: 6px; }
.listing-tags li {
  padding: 4px 10px;
  border: 1px solid var(--sand-deep);
  border-radius: 20px;
  font-size: 12px; color: var(--muted);
}

.listing-foot {
  margin-top: auto; padding-top: 15px; width: 100%;
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 10px 14px;
  border-top: 2px solid var(--orange);
}
.price {
  font-family: var(--display);
  font-variation-settings: "SOFT" 45, "WONK" 1;
  font-size: 25px; font-weight: 600; letter-spacing: -.015em;
  font-variant-numeric: tabular-nums;
}
.price-unit { font-family: var(--font); font-size: 13px; font-weight: 400; color: var(--muted); }

.listing-more { margin-top: 40px; text-align: center; }

/* ═══════════════════════════════════════════════════════
   SERVICES — sand ground.
   Not cards at all: an editorial list separated by horizon
   rules. Six services in six boxes would have been the third
   identical grid on the page.
   ═══════════════════════════════════════════════════════ */
.services { border-top: 2px solid transparent;
  border-image: linear-gradient(to right, var(--orange), rgba(201, 85, 46, .3) 80%, transparent) 1; }
.service {
  display: grid; grid-template-columns: minmax(200px, .85fr) 1.4fr;
  gap: 30px; align-items: baseline;
  padding-block: 30px;
  border-bottom: 1px solid var(--sand-deep);
  transition: background var(--mid) var(--ease);
}
/* A neutral warm tint, not an accent — service rows are not clickable. */
.service:hover { background: rgba(216, 208, 189, .38); }
.service-title {
  font-family: var(--display);
  font-variation-settings: "SOFT" 45, "WONK" 1;
  font-size: 27px; font-weight: 500; line-height: 1.14; letter-spacing: -.015em;
}
.service-desc { max-width: 62ch; font-size: 15.5px; line-height: 1.74; color: var(--muted); }

/* ═══════════════════════════════════════════════════════
   TESTIMONIALS — navy ground.
   Two consented client photos, no quote attached: showing the
   photo is fine, inventing words for a real person is not. A
   plain 2-up grid rather than the old 3-column masonry, which
   was sized for a wall of variable-height text cards and would
   leave two empty columns with only two items in it.
   ═══════════════════════════════════════════════════════ */
.moments-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 22px; }
.quote-photo {
  border-radius: 14px 14px 14px 3px;
  overflow: hidden;
  background: var(--navy-mid);
}
.quote-photo .photo-trigger { cursor: pointer; }
.quote-photo picture { display: block; width: 100%; }
.quote-photo img {
  width: 100%; height: auto; display: block;
  transition: transform 1.1s var(--ease);
}
.quote-photo:hover img { transform: scale(1.04); }

/* ═══════════════════════════════════════════════════════
   FAQ — light ground. Rules, not boxes.
   ═══════════════════════════════════════════════════════ */
.faq { display: grid; grid-template-columns: .72fr 1.28fr; gap: 72px; align-items: start; }
.faq-intro {
  display: flex; flex-direction: column; align-items: flex-start; gap: 16px;
  position: sticky; top: 110px;
}
.faq-intro h2 { max-width: 13ch; }
.faq-intro p { max-width: 40ch; font-size: 15.5px; line-height: 1.72; color: var(--muted); }
.faq-intro .link-pill { margin-top: 6px; }

.faq-list { border-top: 2px solid transparent;
  border-image: linear-gradient(to right, var(--orange), rgba(201, 85, 46, .3) 80%, transparent) 1; }
.faq-list details { border-bottom: 1px solid var(--sand-deep); }
.faq-list summary {
  list-style: none; cursor: pointer;
  padding: 24px 0;
  display: flex; align-items: flex-start; justify-content: space-between; gap: 24px;
  font-family: var(--display);
  font-variation-settings: "SOFT" 45, "WONK" 1;
  font-size: 22px; font-weight: 500; line-height: 1.3; letter-spacing: -.012em;
  transition: color var(--mid) var(--ease);
}
.faq-list summary::-webkit-details-marker { display: none; }
/* Opening an answer is an action, so the affordance is gold. */
.faq-list summary:hover { color: var(--navy); }
.faq-list .sign { flex: none; position: relative; width: 16px; height: 16px; margin-top: 7px; }
.faq-list .sign::before, .faq-list .sign::after {
  content: ""; position: absolute; left: 50%; top: 50%;
  background: var(--navy);
  transition: transform var(--mid) var(--ease), opacity var(--mid) var(--ease);
}
.faq-list .sign::before { width: 15px; height: 2px; transform: translate(-50%, -50%); }
.faq-list .sign::after  { width: 2px; height: 15px; transform: translate(-50%, -50%); }
.faq-list details[open] .sign::after { transform: translate(-50%, -50%) rotate(90deg); opacity: 0; }

.faq-answer { overflow: hidden; }
.faq-answer p {
  max-width: 68ch; padding: 0 52px 26px 0;
  font-size: 15.5px; line-height: 1.78; color: var(--muted);
}
.faq-list details[open] .faq-answer { animation: faq-open var(--slow) var(--ease); }
@keyframes faq-open { from { opacity: 0; transform: translateY(-8px); } to { opacity: 1; transform: none; } }

/* ═══════════════════════════════════════════════════════
   CONTACT — navy ground
   ═══════════════════════════════════════════════════════ */
.contact { display: grid; grid-template-columns: 1fr .9fr; gap: 72px; align-items: start; }
.contact-copy { display: flex; flex-direction: column; align-items: flex-start; gap: 22px; }
.contact-copy h2 { max-width: 13ch; }
.contact-lead { max-width: 46ch; font-size: 16.5px; line-height: 1.72; color: rgba(232, 226, 212, .78); }

.contact-table { width: 100%; border-top: 1px solid var(--line-dark); }
.contact-table .row {
  display: grid; grid-template-columns: 130px 1fr; gap: 18px; align-items: baseline;
  padding: 16px 0;
  border-bottom: 1px solid var(--line-dark);
  font-size: 15.5px;
}
/* Sentence case, hierarchy from size and weight. Malay sits underneath. */
.row-label { display: flex; flex-direction: column; gap: 2px; font-size: 14px; font-weight: 500; color: rgba(232, 226, 212, .82); }
.row-label-ms { font-size: 12.5px; font-weight: 400; color: rgba(245, 241, 231, .62); }
.contact-table dd { margin: 0; color: rgba(232, 226, 212, .88); }
.row-value { color: rgba(232, 226, 212, .72); }
.row-alt { color: rgba(245, 241, 231, .62); font-size: 14px; }

.socials { display: flex; flex-wrap: wrap; gap: 9px; }
.socials a {
  display: inline-block; padding: 10px 18px;
  border: 1px solid var(--line-dark);
  border-radius: 3px;
  font-size: 14.5px; font-weight: 500;
  color: rgba(232, 226, 212, .85);
  transition: border-color var(--mid) var(--ease), color var(--mid) var(--ease);
}
.socials a:hover { border-color: var(--gold); color: var(--gold); }

.enquiry {
  display: flex; flex-direction: column; gap: 16px;
  padding: 34px;
  background: var(--navy-mid);
  border-radius: 4px;
  /* One orange edge instead of a shadow, so the panel is grounded without
     repeating the card treatment used in Listings. */
  border-top: 3px solid var(--orange);
}
.form-title {
  display: flex; flex-direction: column; gap: 3px;
  font-family: var(--display);
  font-variation-settings: "SOFT" 45, "WONK" 1;
  font-size: 27px; font-weight: 500; letter-spacing: -.015em;
  color: var(--sand-pale);
  margin-bottom: 2px;
}
.form-title-ms { font-family: var(--font); font-size: 13px; font-weight: 400; color: rgba(245, 241, 231, .64); }

.field { display: flex; flex-direction: column; gap: 7px; }
.field label {
  display: flex; align-items: baseline; flex-wrap: wrap; gap: 8px; row-gap: 2px;
  font-size: 14px; font-weight: 500;
  color: rgba(232, 226, 212, .82);
}
.label-ms { font-weight: 400; color: rgba(245, 241, 231, .64); }
.optional { font-size: 13px; font-weight: 400; color: rgba(245, 241, 231, .64); }

.enquiry input, .enquiry select, .enquiry textarea {
  width: 100%;
  padding: 13px 15px;
  background: var(--navy-deep);
  border: 1px solid var(--line-dark);
  border-radius: 3px;
  color: var(--sand-pale);
  font-family: var(--font); font-size: 15.5px; line-height: 1.5;
  color-scheme: dark;
  transition: border-color var(--mid) var(--ease), box-shadow var(--mid) var(--ease);
}
.enquiry textarea { resize: vertical; min-height: 100px; }
.enquiry input::placeholder, .enquiry textarea::placeholder { color: rgba(245, 241, 231, .60); }
.enquiry input:focus, .enquiry select:focus, .enquiry textarea:focus {
  outline: none;
  border-color: var(--gold);
  box-shadow: 0 0 0 3px rgba(242, 200, 121, .16);
}
.enquiry select { cursor: pointer; }

.field.has-error input, .field.has-error textarea { border-color: #E0906A; }
.field-error { font-size: 13.5px; color: #F0A585; }

.form-fineprint { font-size: 13px; line-height: 1.6; color: rgba(245, 241, 231, .64); }
.form-sent {
  padding: 14px 16px;
  background: rgba(242, 200, 121, .12);
  border-left: 3px solid var(--gold);
  border-radius: 3px;
  font-size: 14.5px; line-height: 1.6;
  color: var(--gold);
}
.form-sent a { color: var(--gold); font-weight: 600; text-decoration: underline; text-underline-offset: 3px; }

.btn-label { display: flex; flex-direction: column; align-items: center; gap: 3px; }
.btn-label-ms { font-size: 12px; font-weight: 400; opacity: .72; }

/* ═══════════════════════════════════════════════════════
   RESPONSIVE for the new sections
   ═══════════════════════════════════════════════════════ */
@media (max-width: 1024px) {
  .listing-grid { grid-template-columns: repeat(2, 1fr); }
  .listing-featured { grid-template-columns: 1fr; }
  .listing-featured-media { min-height: 0; aspect-ratio: 16 / 9; }
  .faq, .contact { grid-template-columns: 1fr; gap: 44px; }
  .faq-intro { position: static; }
}

@media (max-width: 680px) {
  .listing-grid { grid-template-columns: 1fr; }
  .moments-grid { grid-template-columns: 1fr; }
  .service { grid-template-columns: 1fr; gap: 10px; padding-block: 24px; }
  .listing-featured-body { padding: 26px 22px 28px; }
  .enquiry { padding: 24px 20px; }
  .contact-table .row { grid-template-columns: 1fr; gap: 5px; }
  .faq-answer p { padding-right: 0; }
  .filters { gap: 7px; }
  .filter { padding: 9px 14px; font-size: 14px; }
}

/* ---------------- reduced motion ---------------- */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
  .js .reveal { opacity: 1; transform: none; }
}

/* ══════════════════════════════════════════════════════
   LIGHTBOX — one shared instance, opened from any .photo-trigger button.
   ══════════════════════════════════════════════════════ */
.lightbox {
  position: fixed; inset: 0; z-index: var(--z-float, 80);
  /* Above the WhatsApp float button and everything else on the page. */
  z-index: 200;
}
.lightbox[hidden] { display: none; }

.lightbox-scrim {
  position: absolute; inset: 0;
  background: rgba(7, 17, 32, .94);
}

.lightbox-shell {
  position: relative; z-index: 1;
  height: 100%;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 18px;
  padding: 64px 64px 32px;
}

.lightbox-figure {
  margin: 0;
  max-width: min(1100px, 92vw);
  max-height: 72vh;
  display: flex;
}
.lightbox-figure picture { display: block; max-width: 100%; max-height: 72vh; }
.lightbox-figure img {
  display: block;
  max-width: 100%; max-height: 72vh;
  width: auto; height: auto;
  object-fit: contain;
  border-radius: 3px;
  box-shadow: 0 30px 80px rgba(0, 0, 0, .5);
}

.lightbox-caption {
  display: flex; align-items: center; gap: 14px;
  font-size: 15px;
  color: var(--sand-pale);
  text-align: center;
}
.lightbox-count { color: rgba(245, 241, 231, .55); }
.lightbox-count::before { content: "·"; margin-right: 14px; color: rgba(245, 241, 231, .35); }

.lightbox-btn {
  appearance: none; -webkit-appearance: none;
  display: flex; align-items: center; justify-content: center;
  width: 46px; height: 46px;
  padding: 0; border: 1px solid rgba(245, 241, 231, .22);
  border-radius: 50%;
  background: rgba(14, 27, 42, .55);
  color: var(--sand-pale);
  cursor: pointer;
  transition: border-color var(--mid) var(--ease), color var(--mid) var(--ease), background var(--mid) var(--ease);
}
.lightbox-btn:hover { border-color: var(--gold); color: var(--gold); }
.lightbox-btn:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; }

.lightbox-close { position: absolute; top: 20px; right: 20px; z-index: 2; }
.lightbox-nav { position: absolute; top: 50%; transform: translateY(-50%); z-index: 2; }
.lightbox-prev { left: 16px; }
.lightbox-next { right: 16px; }
/* Nothing to navigate: hide the arrows rather than leave them clickable
   against a single-photo gallery. */
.lightbox.is-single .lightbox-nav { display: none; }

@media (max-width: 680px) {
  .lightbox-shell { padding: 56px 16px 24px; }
  .lightbox-close { top: 12px; right: 12px; }
  .lightbox-prev { left: 8px; }
  .lightbox-next { right: 8px; }
  .lightbox-btn { width: 40px; height: 40px; }
}

@media (prefers-reduced-motion: reduce) {
  .lightbox-figure img { transition: none; }
}
