/* ============================================================================
   NEOPOLIS — bespoke stylesheet for One by MSN (sites/one-by-msn)
   ----------------------------------------------------------------------------
   Builder ............ msn-realty
   Palette source ..... builders/msn-realty/msn-realty.json → branding.colors
                        (9 canonical tokens, copied verbatim, nothing re-picked)
   Idiom .............. "Banded luxury", after sites/nambiar-kannamangala:
                        a serif display face, a paper ground, and full-width
                        bands that alternate paper / ink down the whole page,
                        with the ink band's ground set to --brand-secondary.

   WHAT MAKES THIS THEME ITS OWN (the palette is fixed, so identity lives here)
     · Display face is Playfair Display (self-hosted variable, 400–900) used
       ONLY for display sizes; body runs on a zero-byte system sans stack.
       One font file on the wire, not two.
     · Zero border-radius. Every corner is square except the two circular icon
       wells. Rules are 1px hairlines; the section marker is a 3px bar.
     · Section heads are marked three ways, never repeated in the same band:
       a tracked micro-label, a 3px bar (.gold-divider), and an h2 that carries
       its own 40px bar in ::before.
     · Measure is defended: .prose-inner.wide is a 1180px band, but running
       text inside it is capped at 68ch while tables, figures and galleries
       take the full width. Magazine rhythm, not a wall of 1180px lines.
     · Band rhythm is a single token (--band) so every band breathes alike.

   COLOUR CONTRACT
     The 9 tokens below plus --state-success / --state-error are the ONLY
     colours in this file. No aliases, no raw hex or rgba outside :root.
     Translucency is color-mix(... , transparent); tints and shades are
     color-mix over two of the nine.

   THE TWO DONOR TRAPS, AND HOW THIS SHEET AVOIDS THEM
     (a) The donor sets `.disc strong` to the dark ink token, and that shape
         lands inside a dark band at ~1.2:1. Here NO global rule ever gives
         `strong` or `em` a colour — they inherit from whatever band they are
         in. Where the surrounding copy is deliberately muted (hero sub,
         footer disclaimer) `strong` is brightened LOCALLY, on a ground that
         is known at that point. Search this file for "strong" — every hit is
         band-scoped.
     (b) The donor uses --brand-secondary both as the dark band's ground and
         as footer text on a light ground, so tuning it for one breaks the
         other. Here --brand-secondary has exactly ONE role: it is the ink
         band's ground (prose .bg-white, the page hero and the footer). It is
         never used as text anywhere. Headings and links on paper take
         --brand-primary instead, which has one role of its own: ink-on-paper
         and the filled-button ground. One token, one surface, no tug of war.

   CONTRAST (computed, sRGB, not eyeballed — see each rule's own comment)
     dark-primary    on the paper band (light-primary) .... 16.88:1
     dark-secondary  on the paper band .....................  8.34:1
     brand-primary   on the paper band ..................... 14.21:1
     light-secondary on the ink band (brand-secondary) ..... 17.58:1
     light-tertiary  on the ink band ....................... 15.15:1
     light-secondary at 72% composited on the ink band .....  9.32:1
     light-secondary on brand-primary (filled button) ...... 15.09:1
     Worst-case hero, scrim over a pure white photograph ...  7.94:1
   ========================================================================== */


/* ============================================================================
   1. FONTS — self-hosted only. No <link>, no @import, no preconnect.
   ========================================================================== */

/* Playfair Display, variable 400–900, from this site's own assets/fonts/.
   font-display:optional means: if it is not ready in the first ~100ms it is
   never swapped in, so the display face can never cause a layout shift or
   block the hero. The Georgia fallback is a real serif, so the page still
   reads as "serif display on paper" when the file never arrives. */
@font-face {
  font-family: "Playfair Display";
  src: url("../assets/fonts/playfair-var.woff2") format("woff2-variations"),
       url("../assets/fonts/playfair-var.woff2") format("woff2");
  font-weight: 400 900;
  font-style: normal;
  font-display: optional;
}


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

:root {
  /* ── The 9 canonical brand tokens (builders/msn-realty/msn-realty.json) ── */
  --brand-primary:   #04147B;  /* deep indigo — ink on paper, filled buttons  */
  --brand-secondary: #030E54;  /* near-black navy — THE INK BAND GROUND only  */
  --brand-tertiary:  #F0F1F7;  /* near-white lavender — washes, ink-band rule */
  --dark-primary:    #171717;  /* body copy on paper; hero scrim base         */
  --dark-secondary:  #4a4a4a;  /* meta, captions, muted copy on paper         */
  --dark-tertiary:   #d8d8d8;  /* hairlines and table borders on paper        */
  --light-primary:   #f8f8f8;  /* the paper band                              */
  --light-secondary: #ffffff;  /* cards, table stripes, ink-band text         */
  --light-tertiary:  #eeeeee;  /* deeper paper — FAQ band, ink-band body copy */

  /* ── The one allowed exception: form validation state ──
     Folded into the navy hue these stop reading as "wrong" / "done", which is
     an accessibility loss on a lead form. Both are AA on every light ground
     used here: error 10.17:1 on white, success 7.65:1 on white. */
  --state-error:   #7b1d33;
  --state-success: #1f5f34;

  /* ── Type ── */
  --display: "Playfair Display", ui-serif, Georgia, Cambria, "Times New Roman", Times, serif;
  --body: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Arial, sans-serif;
  --mono: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;

  /* ── Rhythm and measure ── */
  --wrap: 1180px;          /* full band width                                 */
  --wrap-narrow: 760px;    /* .prose-inner without .wide                      */
  --measure: 68ch;         /* running text inside a wide band                 */
  --band: clamp(3.25rem, 7.5vw, 6.5rem);  /* vertical band padding            */
  --gut: clamp(1.25rem, 4vw, 2.5rem);     /* horizontal gutter                */
  --navh: 62px;

  /* ── Elevation (full box-shadow values, built from the tokens above) ── */
  --lift: 0 10px 30px color-mix(in srgb, var(--dark-primary) 12%, transparent);
  --lift-lg: 0 22px 60px color-mix(in srgb, var(--dark-primary) 18%, transparent);


  /* Aliases for the generated related-projects block, which reads
     --font-body / --font-headline / --font-display. Without these it
     falls back to Georgia and breaks the page's type. */
  --font-body: var(--body);
  --font-display: var(--display);
  --font-headline: var(--display);
}


/* ============================================================================
   3. RESET
   ========================================================================== */

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

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

body {
  font-family: var(--body);
  font-size: 1.0625rem;         /* 17px — the base for the whole scale */
  line-height: 1.78;
  color: var(--dark-primary);   /* 16.88:1 on the paper band */
  background: var(--light-primary);
  -webkit-font-smoothing: antialiased;
  /* Nothing on this site may scroll the page sideways at 360px: wide content
     scrolls inside .table-wrap / .plan-grid / .gallery-grid instead. */
  overflow-x: hidden;
}

img { max-width: 100%; height: auto; display: block; }
a { color: inherit; text-decoration: none; }
ul, ol { list-style: none; }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }
input, textarea, select { font: inherit; color: inherit; }
table { border-collapse: collapse; }
svg { display: block; }

/* Motion is decoration here, never information. */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
  }
}


/* ============================================================================
   4. TYPE
   ========================================================================== */

h1, h2, h3, h4 {
  font-family: var(--display);
  font-weight: 500;
  line-height: 1.14;
  letter-spacing: -0.01em;
  color: var(--brand-primary);   /* 14.21:1 on paper — see §2 trap (b) */
  text-wrap: balance;
}

h1 { font-size: clamp(2.1rem, 5.2vw, 3.5rem); line-height: 1.06; }
h2 { font-size: clamp(1.55rem, 3.4vw, 2.4rem); }
h3 { font-size: clamp(1.12rem, 2.2vw, 1.45rem); font-weight: 600; }
h4 { font-size: 1.05rem; font-weight: 600; }

p { margin: 0 0 1.15rem; }
p:last-child { margin-bottom: 0; }

/* NO colour on strong / em — anywhere. They inherit the band they sit in,
   which is the whole defence against donor trap (a). Weight and slant carry
   the emphasis instead. */
strong, b { font-weight: 650; }
em, i { font-style: italic; }

small { font-size: .8125rem; }

code {
  font-family: var(--mono);
  font-size: .875em;
  padding: .12em .4em;
  background: color-mix(in srgb, var(--brand-primary) 8%, var(--light-secondary));
  border: 1px solid var(--dark-tertiary);
  /* 8% indigo over white; dark-primary on that chip is 15.23:1. A guard for
     RERA ids and stray markdown ticks, which is the only thing <code> holds. */
  color: var(--dark-primary);
  overflow-wrap: anywhere;
}

blockquote {
  margin: 1.75rem 0;
  padding: .25rem 0 .25rem 1.5rem;
  border-left: 3px solid var(--brand-primary);
  font-family: var(--display);
  font-size: 1.15rem;
  line-height: 1.5;
  font-style: italic;
  color: var(--dark-primary);
}

address { font-style: normal; }

hr {
  border: 0;
  height: 1px;
  background: var(--dark-tertiary);
  margin: 2.25rem 0;
}

/* Long RERA ids, survey numbers and URLs must not push a band sideways. */
p, li, td, th, figcaption, dd { overflow-wrap: break-word; }


/* ============================================================================
   5. FOCUS + SKIP LINK
   Every ground this site uses is either paper (light) or ink (navy), so the
   ring is declared twice: indigo on paper (14.21:1) and white on ink
   (17.58:1). Nothing here relies on the UA default.
   ========================================================================== */

:where(a, button, input, textarea, select, summary, [tabindex]):focus-visible {
  outline: 3px solid var(--brand-primary);
  outline-offset: 2px;
}

/* Ink grounds invert the ring. */
.bg-white :where(a, button, input, textarea, [tabindex]):focus-visible,
.page-hero :where(a, button, [tabindex]):focus-visible,
#hero :where(a, button, [tabindex]):focus-visible,
.closing-cta :where(a, button, [tabindex]):focus-visible,
#footer :where(a, button, [tabindex]):focus-visible,
#mobile-menu :where(a, button, [tabindex]):focus-visible,
.gallery-item:focus-visible {
  outline: 3px solid var(--light-secondary);
  outline-offset: 2px;
}

.skip-link {
  position: absolute;
  left: -9999px;
  top: auto;
  width: 1px;
  height: 1px;
  overflow: hidden;
  z-index: 2100;
}
.skip-link:focus {
  left: 1rem;
  top: 1rem;
  width: auto;
  height: auto;
  padding: .75rem 1.15rem;
  background: var(--brand-primary);
  color: var(--light-secondary);   /* 15.09:1 */
  font-size: .8rem;
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  outline: 3px solid var(--light-secondary);
  outline-offset: 2px;
}


/* ============================================================================
   6. LAYOUT — bands and wrappers
   The generator emits two band flavours whose names are inherited, not
   descriptive. In this theme:
       .bg-light  →  PAPER band  (--light-primary)
       .bg-white  →  INK band    (--brand-secondary)
   Every page alternates P I P I … perfectly (verified across all 12 pages),
   which is what makes the banding read as a rhythm rather than an accident.
   ========================================================================== */

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

.prose-section {
  padding: var(--band) var(--gut);
  /* Bands butt against each other with no gap; the colour step IS the join. */
}

.prose-inner {
  width: 100%;
  max-width: var(--wrap-narrow);
  margin-inline: auto;
}

/* Every generated .prose-inner also carries .wide. The band goes wide so
   tables and galleries can breathe; running text does not follow it. */
.prose-inner.wide { max-width: var(--wrap); }

.prose-inner.wide > p,
.prose-inner.wide > ul,
.prose-inner.wide > ol,
.prose-inner.wide > h3,
.prose-inner.wide > h4,
.prose-inner.wide > blockquote {
  max-width: var(--measure);
}

/* ── PAPER band ───────────────────────────────────────────────────────── */
.bg-light {
  background: var(--light-primary);
  color: var(--dark-primary);          /* 16.88:1 */
}

/* ── INK band ─────────────────────────────────────────────────────────────
   The ground is --brand-secondary, its single role in this sheet. Everything
   inside is inverted deliberately, one element at a time — headings, copy,
   links, rules, tables, captions, buttons. */
.bg-white {
  background: var(--brand-secondary);
  color: var(--light-tertiary);        /* 15.15:1 on ink */
}
.bg-white h2,
.bg-white h3,
.bg-white h4 { color: var(--light-secondary); }        /* 17.58:1 */
.bg-white hr { background: color-mix(in srgb, var(--light-secondary) 26%, transparent); }
.bg-white blockquote {
  border-left-color: var(--brand-tertiary);            /* 15.59:1 on ink */
  color: var(--light-secondary);
}
.bg-white code {
  background: color-mix(in srgb, var(--light-secondary) 12%, var(--brand-secondary));
  border-color: color-mix(in srgb, var(--light-secondary) 30%, transparent);
  color: var(--light-secondary);       /* white on the 12% mix → 13.01:1 */
}


/* ============================================================================
   7. PROSE INTERNALS
   ========================================================================== */

/* The h2 ornament: a 40px bar above the head, drawn in the band's own accent.
   It is the only repeated section marker inside a prose band. */
.prose-inner > h2 {
  position: relative;
  margin: 0 0 1.5rem;
  padding-top: 1.4rem;
}
.prose-inner > h2::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  width: 40px;
  height: 3px;
  background: var(--brand-primary);
}
.bg-white .prose-inner > h2::before { background: var(--brand-tertiary); }

.prose-inner > h2 + p,
.prose-inner > h3 + p { margin-top: 0; }

.prose-inner h3 { margin: 2.5rem 0 .85rem; }
.prose-inner h4 { margin: 1.9rem 0 .6rem; }
.prose-inner > *:first-child { margin-top: 0; }

/* Lists: a square marker drawn by ::before, so the bullet takes the band's
   accent instead of the UA's black disc. */
.prose-inner ul { margin: 0 0 1.25rem; padding: 0; }
.prose-inner ul > li {
  position: relative;
  padding-left: 1.4rem;
  margin-bottom: .55rem;
  max-width: var(--measure);
}
.prose-inner ul > li::before {
  content: "";
  position: absolute;
  left: 0;
  top: .72em;
  width: 6px;
  height: 6px;
  background: var(--brand-primary);
}
.bg-white .prose-inner ul > li::before { background: var(--brand-tertiary); }

.prose-inner ol {
  counter-reset: pn;
  margin: 0 0 1.25rem;
  padding: 0;
}
.prose-inner ol > li {
  counter-increment: pn;
  position: relative;
  padding-left: 2.2rem;
  margin-bottom: .7rem;
  max-width: var(--measure);
}
.prose-inner ol > li::before {
  content: counter(pn, decimal-leading-zero);
  position: absolute;
  left: 0;
  top: 0;
  font-family: var(--display);
  font-size: .95rem;
  font-weight: 600;
  color: var(--brand-primary);         /* 14.21:1 on paper */
  line-height: 1.9;
}
.bg-white .prose-inner ol > li::before { color: var(--brand-tertiary); }

/* ── In-content links ───────────────────────────────────────────────────
   EVERY selector here carries :not(.btn) and that is load-bearing, not tidy.
   The generator puts <a class="btn btn-gold"> inside .prose-inner, and a bare
   `.prose-inner a` rule (0,2,1) out-specifies `.bg-white .btn-gold` (0,2,0):
   it repainted the button LABEL while the button kept its own GROUND, giving
   indigo-on-indigo in a paper band and white-on-white in an ink band — 1:1,
   an invisible button, on all nine homepage CTA rows. Caught by a computed
   audit of the rendered page; no static check would have seen it.

   Underlined, so they are never colour-only. On paper: indigo 14.21:1.
   Hover deepens toward the body ink (that mix reads 15.66:1) AND thickens the
   underline, so the hover state is legible with colour vision off. */
.prose-inner a:not(.btn),
.footer-about-text a:not(.btn),
.footer-disclaimer a:not(.btn),
.faq-a a:not(.btn),
.contact-detail-text a:not(.btn),
.lead a:not(.btn),
figcaption a:not(.btn) {
  color: var(--brand-primary);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
  font-weight: 600;
  transition: color .2s ease, text-decoration-thickness .2s ease;
}
.prose-inner a:not(.btn):hover,
.footer-about-text a:not(.btn):hover,
.footer-disclaimer a:not(.btn):hover,
.faq-a a:not(.btn):hover,
.contact-detail-text a:not(.btn):hover,
.lead a:not(.btn):hover,
figcaption a:not(.btn):hover {
  color: color-mix(in srgb, var(--brand-primary) 65%, var(--dark-primary));
  text-decoration-thickness: 2px;
}

/* On every ink ground the same links go white (17.58:1) with a 60% underline
   that fills in on hover. */
.bg-white .prose-inner a:not(.btn),
.bg-white .faq-a a:not(.btn),
.page-hero a:not(.btn),
#footer a:not(.footer-logo):not(.btn),
.closing-cta a:not(.btn) {
  color: var(--light-secondary);
  text-decoration-color: color-mix(in srgb, var(--light-secondary) 60%, transparent);
}
.bg-white .prose-inner a:not(.btn):hover,
.bg-white .faq-a a:not(.btn):hover,
.page-hero a:not(.btn):hover,
#footer a:not(.footer-logo):not(.btn):hover,
.closing-cta a:not(.btn):hover {
  color: var(--light-secondary);
  text-decoration-color: var(--light-secondary);
  text-decoration-thickness: 2px;
}


/* ============================================================================
   8. NAV
   The bar is a light surface on every page, including over the cinematic
   hero, so there is exactly ONE nav contrast pair to keep honest. At 86%
   white over a pure-black backdrop the composite is a light grey on which the
   indigo wordmark still measures 10.9:1, the nav links 12.95:1, and the muted
   developer line 6.4:1. backdrop-filter is a nicety, never load-bearing.
   ========================================================================== */

#nav {
  position: fixed;
  inset: 0 0 auto 0;
  height: var(--navh);
  z-index: 1000;
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: 0 var(--gut);
  background: color-mix(in srgb, var(--light-secondary) 86%, transparent);
  border-bottom: 1px solid color-mix(in srgb, var(--dark-primary) 12%, transparent);
  -webkit-backdrop-filter: blur(14px);
  backdrop-filter: blur(14px);
  transition: background .3s ease, box-shadow .3s ease, border-color .3s ease;
}
#nav.scrolled {
  background: color-mix(in srgb, var(--light-secondary) 97%, transparent);
  border-bottom-color: var(--dark-tertiary);
  box-shadow: var(--lift);
}

/* The fixed bar is taken out of flow, so every page owes it clearance. */
body { padding-top: var(--navh); }

.nav-logo {
  display: flex;
  align-items: center;
  gap: .7rem;
  margin-right: auto;
  min-width: 0;
}
.brand-logo-img {
  width: 40px;
  height: 40px;
  object-fit: contain;
  flex: 0 0 auto;
}
.brand-text {
  display: flex;
  flex-direction: column;
  line-height: 1.1;
  min-width: 0;
}
.brand-developer {
  font-size: .625rem;
  font-weight: 700;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--dark-secondary);   /* 6.4:1 worst case on the translucent bar */
}
/* The two spans stack, and adjacent block boxes can concatenate with no
   separator in the accessibility tree ("MSN RealtyOne by MSN"). A trailing
   space keeps the accessible name readable; it collapses visually. */
.brand-developer::after { content: " "; }
.brand-project {
  font-family: var(--display);
  font-size: 1.05rem;
  font-weight: 600;
  letter-spacing: -0.005em;
  color: var(--brand-primary);    /* 10.9:1 worst case on the translucent bar */
  white-space: nowrap;
}

.nav-links {
  display: flex;
  align-items: center;
  gap: 1.35rem;
}
.nav-links a {
  font-size: .78rem;
  font-weight: 600;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--dark-primary);     /* 12.95:1 worst case on the translucent bar */
  padding: .35rem 0;
  white-space: nowrap;            /* see the 1024-1280 block in §20 */
  border-bottom: 2px solid transparent;
  transition: color .2s ease, border-color .2s ease;
}
/* Hover is a rule + an ink change, never colour alone. Indigo on the bar is
   10.9:1 worst case, so the hovered item is never the faint one. */
.nav-links a:hover {
  color: var(--brand-primary);
  border-bottom-color: var(--brand-primary);
}

.nav-cta {
  flex: 0 0 auto;
  padding: .62rem 1.35rem;
  background: var(--brand-primary);
  color: var(--light-secondary);  /* 15.09:1 */
  font-size: .73rem;
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  border: 1px solid var(--brand-primary);
  transition: background .25s ease, border-color .25s ease;
}
/* Hover inverts the fill rather than nudging the hue: white ground, indigo
   label (15.09:1), indigo border — the shape stays 10.9:1 against the bar, so
   it cannot go invisible the way a paler fill would. */
.nav-cta:hover {
  background: var(--light-secondary);
  color: var(--brand-primary);
}

/* ── Hamburger (shown under 1024 — see §20) ── */
.hamburger {
  display: none;
  flex: 0 0 auto;
  width: 42px;
  height: 42px;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  gap: 5px;
}
.hamburger span {
  display: block;
  width: 22px;
  height: 2px;
  background: var(--brand-primary);
  transition: transform .3s ease, opacity .2s ease;
}
.hamburger.open span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.hamburger.open span:nth-child(2) { opacity: 0; }
.hamburger.open span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

/* ── Mobile menu: a full-height ink panel ── */
#mobile-menu {
  position: fixed;
  inset: 0;
  z-index: 1500;
  background: var(--brand-secondary);
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: .15rem;
  padding: 5rem var(--gut) 3rem;
  overflow-y: auto;
  transform: translateX(100%);
  visibility: hidden;
  transition: transform .35s ease, visibility .35s ease;
}
#mobile-menu.open { transform: translateX(0); visibility: visible; }

#mobile-menu a {
  font-family: var(--display);
  font-size: 1.5rem;
  color: var(--light-secondary);   /* 17.58:1 on ink */
  padding: .5rem 0;
  border-bottom: 1px solid color-mix(in srgb, var(--light-secondary) 16%, transparent);
  transition: padding-left .2s ease, border-color .2s ease;
}
.menu-close {
  position: absolute;
  top: 1rem;
  right: var(--gut);
  width: 44px;
  height: 44px;
  font-size: 2rem;
  line-height: 1;
  color: var(--light-secondary);   /* 17.58:1 */
  border: 1px solid color-mix(in srgb, var(--light-secondary) 32%, transparent);
}
.menu-close:hover {
  background: var(--light-secondary);
  color: var(--brand-secondary);   /* inverted pair, 17.58:1 either way */
}
/* Not colour-only: the item slides in and its rule brightens. */
#mobile-menu a:hover {
  padding-left: .6rem;
  border-bottom-color: var(--brand-tertiary);
}
.menu-cta {
  margin-top: 1.5rem;
  text-align: center;
  background: var(--light-secondary);
  color: var(--brand-primary) !important;  /* 15.09:1 — beats the #mobile-menu a rule */
  font-family: var(--body) !important;
  font-size: .8rem !important;
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  padding: .95rem 1.5rem !important;
  border-bottom: 0 !important;
}
.menu-cta:hover {
  padding-left: 1.5rem !important;
  background: var(--brand-tertiary);       /* 13.39:1 against the indigo label */
}


/* ============================================================================
   9. BUTTONS
   Two roles, three grounds. .btn-gold is the filled one (the generator's
   name; there is no gold in this palette, so it is drawn in indigo).
   .btn-outline is the outline twin for DARK grounds, .btn-outline-dark the
   outline twin for PAPER — but the generator also drops .btn-outline-dark
   into .cta-row inside ink bands, so that case is overridden below. Missing
   that override is exactly how a fleet site once shipped an invisible button.
   ========================================================================== */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .5rem;
  padding: .9rem 1.75rem;
  border: 1px solid transparent;
  font-family: var(--body);
  font-size: .76rem;
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  line-height: 1.5;
  text-align: center;
  transition: background .25s ease, color .25s ease, border-color .25s ease, transform .25s ease;
}
.btn:hover { transform: translateY(-2px); }
.btn:active { transform: translateY(0); }

/* Filled — on paper. */
.btn-gold {
  background: var(--brand-primary);
  border-color: var(--brand-primary);
  color: var(--light-secondary);            /* 15.09:1 */
}
/* Hover darkens toward the ink band ground; white on that mix is 16.46:1.
   The lift plus a deeper fill, never a lighter one. */
.btn-gold:hover {
  background: color-mix(in srgb, var(--brand-primary) 45%, var(--brand-secondary));
  border-color: color-mix(in srgb, var(--brand-primary) 45%, var(--brand-secondary));
  color: var(--light-secondary);
}

/* Outline for DARK grounds (hero, page hero). */
.btn-outline {
  background: transparent;
  border-color: color-mix(in srgb, var(--light-secondary) 55%, transparent);
  color: var(--light-secondary);            /* 17.58:1 on ink */
}
.btn-outline:hover {
  background: var(--light-secondary);
  border-color: var(--light-secondary);
  color: var(--brand-primary);              /* 15.09:1 inverted */
}

/* Outline for PAPER grounds. */
.btn-outline-dark {
  background: transparent;
  border-color: var(--brand-primary);
  color: var(--brand-primary);              /* 14.21:1 on paper */
}
.btn-outline-dark:hover {
  background: var(--brand-primary);
  border-color: var(--brand-primary);
  color: var(--light-secondary);            /* 15.09:1 inverted */
}

/* ── Both button roles on an INK ground ──────────────────────────────────
   Indigo on navy is ~1.1:1 — a filled .btn-gold would vanish into the band.
   Inside an ink band (and inside .closing-cta, which is the indigo band) the
   filled button becomes a white block with an indigo label: the SHAPE reads
   at 17.58:1 against the ground and the LABEL at 15.09:1 against the shape. */
.bg-white .btn-gold,
.closing-cta .btn-gold,
.page-hero .btn-gold,
#footer .btn-gold {
  background: var(--light-secondary);
  border-color: var(--light-secondary);
  color: var(--brand-primary);
}
.bg-white .btn-gold:hover,
.closing-cta .btn-gold:hover,
.page-hero .btn-gold:hover,
#footer .btn-gold:hover {
  background: var(--brand-tertiary);        /* 15.59:1 shape, 13.39:1 label */
  border-color: var(--brand-tertiary);
  color: var(--brand-primary);
}

/* .btn-outline-dark inside an ink band: indigo on navy would be invisible. */
.bg-white .btn-outline-dark,
.closing-cta .btn-outline-dark {
  border-color: color-mix(in srgb, var(--light-secondary) 55%, transparent);
  color: var(--light-secondary);            /* 17.58:1 */
}
.bg-white .btn-outline-dark:hover,
.closing-cta .btn-outline-dark:hover {
  background: var(--light-secondary);
  border-color: var(--light-secondary);
  color: var(--brand-primary);              /* 15.09:1 */
}

.btn:disabled { opacity: .55; cursor: not-allowed; transform: none; }


/* ============================================================================
   10. HOMEPAGE HERO — cinematic, full viewport
   Stacking order is explicit and in this order for a reason: a peer clone in
   this fleet once painted the scrim UNDER the image because .hero-bg carried
   the higher z-index. bg 0 → overlay 1 → content 2, and nothing else in the
   hero is positioned.
   ========================================================================== */

#hero {
  position: relative;
  min-height: 100svh;
  display: flex;
  align-items: flex-end;
  overflow: hidden;
  padding: calc(var(--navh) + 2rem) var(--gut) clamp(2.5rem, 6vw, 4.5rem);
  margin-top: calc(var(--navh) * -1);   /* the hero starts under the glass bar */
  background: var(--brand-secondary);   /* the ground before the image decodes */
}

.hero-bg { position: absolute; inset: 0; z-index: 0; }
.hero-bg img,
.hero-bg picture { width: 100%; height: 100%; object-fit: cover; }

/* The scrim never drops below 75% ink, and that floor is not a taste call.
   Composited over a HYPOTHETICAL PURE WHITE photograph the top of the band
   still resolves to a mid grey where plain white text measures 7.94:1 and the
   90%-white hero paragraph 6.84:1 — so AA holds whatever image the asset
   pipeline ships, not merely for the night skyline that is there today. At a
   62% floor the same paragraph measured 4.33:1 and failed. */
.hero-overlay {
  position: absolute;
  inset: 0;
  z-index: 1;
  background: linear-gradient(
    180deg,
    color-mix(in srgb, var(--dark-primary) 75%, transparent) 0%,
    color-mix(in srgb, var(--dark-primary) 84%, transparent) 45%,
    color-mix(in srgb, var(--dark-primary) 94%, transparent) 100%
  );
}

.hero-content {
  position: relative;
  z-index: 2;
  width: 100%;
  max-width: var(--wrap);
  margin-inline: auto;
}

.hero-badge {
  display: inline-block;
  margin-bottom: 1.4rem;
  padding: .5rem 1rem;
  border: 1px solid color-mix(in srgb, var(--light-secondary) 55%, transparent);
  font-size: .66rem;
  font-weight: 700;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--light-secondary);       /* 7.94:1 worst case, see .hero-overlay */
}

.hero-title {
  font-size: clamp(2.75rem, 9vw, 6rem);
  font-weight: 500;
  line-height: 1.0;
  letter-spacing: -0.02em;
  color: var(--light-secondary);
  margin-bottom: .5rem;
}

.hero-sub {
  max-width: 62ch;
  margin: 1.25rem 0 2rem;
  font-size: .95rem;
  line-height: 1.85;
  /* 90% white on the scrim. Against the worst-case white-photo composite this
     still measures 6.84:1; against the real image, far more. */
  color: color-mix(in srgb, var(--light-secondary) 90%, transparent);
}
/* Band-scoped, per §2 trap (a): the hero's <strong> runs go to full white
   rather than inheriting any dark ink token. */
.hero-sub strong { color: var(--light-secondary); }

.hero-btns {
  display: flex;
  flex-wrap: wrap;
  gap: .75rem;
  margin-bottom: 2.25rem;
}

/* Five stats in a hairline-ruled row — the geometric signature of the theme. */
.hero-stats {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1px;
  background: color-mix(in srgb, var(--light-secondary) 22%, transparent);
  border: 1px solid color-mix(in srgb, var(--light-secondary) 22%, transparent);
  width: fit-content;
  max-width: 100%;
}
.hero-stat {
  padding: .85rem 1.15rem;
  background: color-mix(in srgb, var(--dark-primary) 55%, transparent);
  font-family: var(--display);
  font-size: .95rem;
  font-weight: 600;
  letter-spacing: .01em;
  color: var(--light-secondary);
  /* The cell carries its own 55% ink on top of the ≥75% scrim, so the worst
     possible ground here is a near-black and white reads above 12:1. */
}

/* .page-updated is only ever emitted inside a hero, so it is declared once
   for paper (defensive) and immediately inverted for both hero flavours. */
.page-updated {
  font-size: .68rem;
  font-weight: 600;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--dark-secondary);
  margin: 0 0 .5rem;
}
#hero .page-updated,
.page-hero .page-updated {
  color: color-mix(in srgb, var(--light-secondary) 88%, transparent);
  /* 13.62:1 composited on the ink band; 6.60:1 against the worst-case hero
     scrim. 80% was the first draft and failed the hero case at 3.88:1. */
}


/* ============================================================================
   11. PAGE HERO (every page except the homepage) — an ink band
   Ink here means the first prose band below it (.bg-light, paper) always
   steps away from it, which keeps the P/I alternation unbroken from the top
   of every subpage.
   ========================================================================== */

.page-hero {
  background: var(--brand-secondary);
  color: var(--light-tertiary);          /* 15.15:1 */
  padding: clamp(3rem, 7vw, 5.5rem) var(--gut);
  border-bottom: 3px solid var(--brand-primary);
}
.page-hero-inner {
  width: 100%;
  max-width: var(--wrap);
  margin-inline: auto;
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(2rem, 5vw, 3.5rem);
  align-items: center;
}
.page-hero h1 { color: var(--light-secondary); margin-bottom: .6rem; }
.page-hero strong { color: var(--light-secondary); }   /* band-scoped, §2 (a) */

.lead {
  max-width: 62ch;
  margin: 1.1rem 0 1.9rem;
  font-size: 1.05rem;
  line-height: 1.8;
  color: color-mix(in srgb, var(--light-secondary) 88%, var(--brand-secondary));
  /* composites to a near-white → 13.62:1 on the ink ground */
}

.page-hero-ctas { display: flex; flex-wrap: wrap; gap: .75rem; }

.page-hero-stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 1px;
  margin-top: 2.25rem;
  background: color-mix(in srgb, var(--light-secondary) 20%, transparent);
  border: 1px solid color-mix(in srgb, var(--light-secondary) 20%, transparent);
}
.page-hero-stat {
  padding: 1.1rem 1.15rem;
  background: var(--brand-secondary);
  display: flex;
  flex-direction: column;
  gap: .3rem;
}
.num {
  font-family: var(--display);
  /* Capped at 1.7rem, not 2.2rem, and allowed to wrap: .num is NOT always a
     numeral on this site — it also carries "Under Construction",
     "5,08,494.17 sq m" and "₹13,300 – 16,100". At 2.2rem the longest of those
     ran straight out of its cell. break-word wraps at the space first and
     splits a word only when nothing else will fit. */
  font-size: clamp(1.3rem, 2.6vw, 1.7rem);
  font-weight: 600;
  line-height: 1.14;
  overflow-wrap: break-word;
  hyphens: none;
  color: var(--light-secondary);         /* 17.58:1 */
  font-variant-numeric: lining-nums tabular-nums;
}
.lbl {
  font-size: .64rem;
  font-weight: 700;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: color-mix(in srgb, var(--light-secondary) 78%, var(--brand-secondary));
  /* 10.80:1 on the ink ground */
}

.page-hero-image {
  position: relative;
  max-width: 560px;
  width: 100%;
  justify-self: center;
}
/* A 1px offset frame rather than a shadow — square, architectural, and it
   survives on a dark ground where a shadow would not. */
.page-hero-image::after {
  content: "";
  position: absolute;
  inset: 14px -14px -14px 14px;
  border: 1px solid color-mix(in srgb, var(--light-secondary) 35%, transparent);
  z-index: 0;
  pointer-events: none;
}
.page-hero-image img {
  position: relative;
  z-index: 1;
  width: 100%;
  height: auto;
  object-fit: cover;
}


/* ============================================================================
   12. TABLES — the heaviest content on this site (1,149 <td> across 12 pages)
   ========================================================================== */

.table-wrap {
  width: 100%;
  max-width: 100%;
  margin: 1.75rem 0 2rem;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  /* The scroll container, not the page, absorbs a wide table at 360px. */
  border: 1px solid var(--dark-tertiary);
}
.bg-white .table-wrap { border-color: color-mix(in srgb, var(--light-secondary) 24%, transparent); }

.data-table {
  width: 100%;
  min-width: 520px;              /* below this a 2-col table becomes unreadable */
  font-size: .9rem;
  line-height: 1.65;
  background: var(--light-secondary);
}
.data-table th,
.data-table td {
  padding: .8rem 1rem;
  text-align: left;
  vertical-align: top;
  border-bottom: 1px solid var(--dark-tertiary);
}
.data-table thead th {
  background: var(--brand-primary);
  color: var(--light-secondary);         /* 15.09:1 */
  font-family: var(--body);
  font-size: .68rem;
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  border-bottom: 0;
  white-space: nowrap;
}
.data-table tbody th {
  font-weight: 650;
  color: var(--dark-primary);            /* 17.93:1 on white */
}
.data-table tbody td { color: var(--dark-primary); }
.data-table tbody tr:nth-child(even) { background: var(--light-primary); }
.data-table tbody tr:last-child th,
.data-table tbody tr:last-child td { border-bottom: 0; }
.data-table tbody tr:hover { background: color-mix(in srgb, var(--brand-primary) 6%, var(--light-secondary)); }

/* ── The same table inside an INK band ───────────────────────────────────
   Ground, stripes, borders and copy all invert. Without this the table keeps
   a white ground and an indigo head inside a navy band, which reads as a
   pasted-in rectangle rather than part of the band. */
.bg-white .data-table { background: var(--brand-secondary); }
.bg-white .data-table thead th {
  background: color-mix(in srgb, var(--light-secondary) 16%, var(--brand-secondary));
  color: var(--light-secondary);         /* white on the 16% mix → 11.40:1 */
}
.bg-white .data-table th,
.bg-white .data-table td {
  border-bottom-color: color-mix(in srgb, var(--light-secondary) 22%, transparent);
  color: var(--light-tertiary);          /* 15.15:1; 13.37:1 on the zebra row */
}
.bg-white .data-table tbody th { color: var(--light-secondary); }
.bg-white .data-table tbody tr:nth-child(even) {
  background: color-mix(in srgb, var(--light-secondary) 6%, var(--brand-secondary));
}
.bg-white .data-table tbody tr:hover {
  background: color-mix(in srgb, var(--light-secondary) 12%, var(--brand-secondary));
}
/* §2 trap (a) again — in an ink band the emphasised cell goes white, it does
   not inherit a dark ink token from anywhere. */
.bg-white .data-table strong { color: var(--light-secondary); }
.bg-white .data-table a:not(.btn) { color: var(--light-secondary); }


/* ============================================================================
   13. FIGURES — floor plans, master plan, location map
   Source plates are 720px square. Capping the figure at 720px is deliberate:
   upscaled into a 1180px band they go soft.
   ========================================================================== */

.plan-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(1.25rem, 3vw, 2rem);
  margin: 2rem 0;
}

.plan-figure,
.content-figure {
  margin: 0 0 1.5rem;
  max-width: 720px;
  background: var(--light-secondary);
  border: 1px solid var(--dark-tertiary);
  padding: .75rem;
}
.plan-figure { margin-bottom: 0; }
.content-figure { margin-inline: auto; }

.plan-figure img,
.content-figure img {
  width: 100%;
  height: auto;
  background: var(--light-primary);
}

.plan-figure figcaption,
.content-figure figcaption {
  margin-top: .7rem;
  padding-top: .7rem;
  border-top: 1px solid var(--dark-tertiary);
  font-size: .78rem;
  line-height: 1.65;
  color: var(--dark-secondary);          /* 8.86:1 on white */
}

/* Inside an ink band the plate keeps a light mount — a 720px render needs a
   light surround to stay legible — but the caption follows the band. */
.bg-white .plan-figure,
.bg-white .content-figure {
  background: color-mix(in srgb, var(--light-secondary) 10%, var(--brand-secondary));
  border-color: color-mix(in srgb, var(--light-secondary) 26%, transparent);
}
.bg-white .plan-figure figcaption,
.bg-white .content-figure figcaption {
  border-top-color: color-mix(in srgb, var(--light-secondary) 26%, transparent);
  color: color-mix(in srgb, var(--light-secondary) 82%, var(--brand-secondary));
  /* 9.40:1 on the 10% mount */
}
.bg-white .plan-figure strong,
.bg-white .content-figure strong { color: var(--light-secondary); }


/* ============================================================================
   14. GALLERY + LIGHTBOX
   ========================================================================== */

.gallery-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 4px;
  margin: 2rem 0;
}

.gallery-item {
  position: relative;
  overflow: hidden;
  background: var(--brand-secondary);
  cursor: pointer;
  aspect-ratio: 1 / 1;
}
.gallery-item img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform .6s ease;
}
.gallery-item:hover img,
.gallery-item:focus-visible img { transform: scale(1.05); }

.gallery-item-overlay {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: color-mix(in srgb, var(--brand-secondary) 55%, transparent);
  opacity: 0;
  transition: opacity .3s ease;
}
.gallery-item:hover .gallery-item-overlay,
.gallery-item:focus-visible .gallery-item-overlay { opacity: 1; }

/* The zoom glyph: a white ring on a 55% navy wash. Even over a white photo
   that wash composites to a mid indigo-grey where white reads 4.17:1 — clear
   of the 3:1 bar for a graphic, and the glyph carries a 2px stroke. */
.gallery-zoom-icon {
  width: 54px;
  height: 54px;
  border-radius: 50%;
  border: 1px solid color-mix(in srgb, var(--light-secondary) 70%, transparent);
  display: flex;
  align-items: center;
  justify-content: center;
}
.gallery-zoom-icon svg {
  width: 24px;
  height: 24px;
  fill: none;
  stroke: var(--light-secondary);
  stroke-width: 2;
  stroke-linecap: round;
}

/* Lightbox — markup is injected by js/script.js, so it never appears in the
   page source; without these rules it would ship as an unstyled block. */
#lightbox {
  position: fixed;
  inset: 0;
  z-index: 2000;
  display: flex;
  align-items: center;
  justify-content: center;
  background: color-mix(in srgb, var(--brand-secondary) 95%, transparent);
  opacity: 0;
  pointer-events: none;
  transition: opacity .3s ease;
}
#lightbox.open { opacity: 1; pointer-events: auto; }
.lightbox-img { max-width: 92vw; max-height: 82vh; object-fit: contain; }
.lightbox-close,
.lightbox-prev,
.lightbox-next {
  position: absolute;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--light-secondary);         /* ≥16:1 on the 95% navy scrim */
  border: 1px solid color-mix(in srgb, var(--light-secondary) 35%, transparent);
  transition: background .2s ease, color .2s ease;
}
.lightbox-close { top: 1.25rem; right: 1.25rem; width: 44px; height: 44px; font-size: 1.7rem; line-height: 1; }
.lightbox-prev { left: 1rem; top: 50%; transform: translateY(-50%); width: 48px; height: 48px; font-size: 1.6rem; }
.lightbox-next { right: 1rem; top: 50%; transform: translateY(-50%); width: 48px; height: 48px; font-size: 1.6rem; }
.lightbox-close:hover,
.lightbox-prev:hover,
.lightbox-next:hover {
  background: var(--light-secondary);
  color: var(--brand-secondary);         /* inverted, 17.58:1 either way */
}
.lightbox-caption {
  position: absolute;
  bottom: 1.5rem;
  left: 50%;
  transform: translateX(-50%);
  max-width: 90vw;
  text-align: center;
  font-size: .8rem;
  line-height: 1.6;
  color: color-mix(in srgb, var(--light-secondary) 86%, transparent);
  /* 13.19:1 over the 95% navy scrim */
}


/* ============================================================================
   15. CTA ROW + CLOSING CTA
   ========================================================================== */

.cta-row {
  display: flex;
  flex-wrap: wrap;
  gap: .75rem;
  align-items: center;
  margin-top: 2.5rem;
  padding-top: 2rem;
  border-top: 1px solid var(--dark-tertiary);
}
.bg-white .cta-row,
#faq .cta-row { border-top-color: color-mix(in srgb, var(--light-secondary) 24%, transparent); }
#faq .cta-row { border-top-color: var(--dark-tertiary); }

/* The closing band. It follows a paper band on some pages and an ink band on
   others, so it is drawn in --brand-primary rather than --brand-secondary:
   against an ink band the two navies are close (~1.1:1), and the 3px
   brand-tertiary rule on top is what actually declares the new band. */
.closing-cta {
  background: var(--brand-primary);
  border-top: 3px solid var(--brand-tertiary);
  padding: var(--band) var(--gut);
  text-align: center;
}
.closing-cta-inner {
  max-width: 720px;
  margin-inline: auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1.75rem;
}
.closing-cta h2 {
  color: var(--light-secondary);         /* 15.09:1 on indigo */
  font-size: clamp(1.7rem, 3.8vw, 2.6rem);
}
.closing-cta p { color: var(--brand-tertiary); }   /* 13.39:1 on indigo */
.closing-cta strong { color: var(--light-secondary); }   /* band-scoped, §2 (a) */


/* ============================================================================
   16. FAQ — a paper band, the quietest one on the page
   ========================================================================== */

#faq {
  background: var(--light-tertiary);
  padding: var(--band) var(--gut);
}
.faq-inner {
  width: 100%;
  max-width: 880px;
  margin-inline: auto;
}
.faq-header { margin-bottom: 2.5rem; }

.section-label {
  font-size: .66rem;
  font-weight: 700;
  letter-spacing: .24em;
  text-transform: uppercase;
  color: var(--brand-primary);           /* 13.01:1 on the FAQ band */
  margin: 0 0 .6rem;
}
.section-title { margin: 0; }

/* The generator's "gold" divider, drawn in indigo — this palette has no gold,
   and inventing one would mean a tenth colour. */
.gold-divider {
  width: 56px;
  height: 3px;
  background: var(--brand-primary);
  margin-top: 1.1rem;
}

.faq-list {
  border-top: 1px solid var(--dark-tertiary);
}
.faq-item { border-bottom: 1px solid var(--dark-tertiary); }

.faq-q {
  width: 100%;
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1.25rem;
  padding: 1.25rem 0;
  text-align: left;
  font-family: var(--display);
  font-size: 1.08rem;
  font-weight: 600;
  line-height: 1.4;
  color: var(--brand-primary);           /* 13.01:1 on the FAQ band */
  transition: color .2s ease;
}
.faq-q svg {
  flex: 0 0 auto;
  width: 22px;
  height: 22px;
  margin-top: .2rem;
  fill: none;
  stroke: currentColor;                  /* inherits the 13.01:1 head colour */
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
  transition: transform .3s ease;
}
/* Hover is a colour step PLUS an underline, so it is never colour-only. */
.faq-q:hover {
  color: var(--dark-primary);            /* 15.45:1 on the FAQ band */
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 4px;
}
.faq-item.open .faq-q svg { transform: rotate(180deg); }

/* 0fr → 1fr animates in current browsers and simply sizes correctly in older
   ones, so the accordion degrades to an instant open rather than breaking. */
.faq-a {
  display: grid;
  grid-template-rows: 0fr;
  overflow: hidden;
  transition: grid-template-rows .3s ease;
}
.faq-a > * { min-height: 0; }
.faq-item.open .faq-a { grid-template-rows: 1fr; }
.faq-a p,
.faq-a ul,
.faq-a ol {
  font-size: .95rem;
  line-height: 1.8;
  color: var(--dark-primary);            /* 15.45:1 on the FAQ band */
}
.faq-item.open .faq-a > :last-child { padding-bottom: 1.4rem; }


/* ============================================================================
   17. CONTACT + FORMS
   ========================================================================== */

#contact {
  /* A third light value so #contact and #faq, which sit next to each other on
     the contact page, still read as two bands. */
  background: color-mix(in srgb, var(--brand-tertiary) 60%, var(--light-secondary));
  padding: var(--band) var(--gut);
}
.contact-inner {
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(2rem, 5vw, 3.5rem);
  align-items: start;
}
.contact-info .section-title { margin-bottom: 0; }
.contact-info p {
  max-width: var(--measure);
  color: var(--dark-primary);            /* 16.74:1 on the wash */
}

.contact-detail {
  margin-top: 2rem;
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
}
.contact-detail-item {
  display: flex;
  align-items: flex-start;
  gap: 1rem;
}
.contact-detail-icon {
  flex: 0 0 auto;
  width: 46px;
  height: 46px;
  border-radius: 50%;
  background: var(--brand-primary);
  display: flex;
  align-items: center;
  justify-content: center;
}
.contact-detail-icon svg {
  width: 21px;
  height: 21px;
  fill: none;
  stroke: var(--light-secondary);        /* 15.09:1 on the indigo well */
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.contact-detail-text {
  font-size: .9rem;
  line-height: 1.7;
  color: var(--dark-secondary);          /* 8.27:1 on the wash */
}
.contact-detail-text strong {
  display: block;
  font-family: var(--display);
  font-size: 1.02rem;
  font-weight: 600;
  color: var(--brand-primary);           /* 14.09:1 on the wash */
  margin-bottom: .15rem;
}

.form-card {
  background: var(--light-secondary);
  border: 1px solid var(--dark-tertiary);
  border-top: 3px solid var(--brand-primary);
  padding: clamp(1.5rem, 4vw, 2.25rem);
  box-shadow: var(--lift);
}

.form-row {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0 1rem;
}

.form-group { margin-bottom: 1.1rem; }
.form-group label {
  display: block;
  margin-bottom: .4rem;
  font-size: .7rem;
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--dark-primary);            /* 17.93:1 on the white card */
}
.form-group input,
.form-group textarea {
  width: 100%;
  padding: .8rem .9rem;
  background: var(--light-primary);
  border: 1px solid var(--dark-tertiary);
  color: var(--dark-primary);            /* 16.88:1 */
  font-size: .95rem;
  transition: border-color .2s ease, background .2s ease;
}
.form-group textarea { min-height: 7rem; resize: vertical; }
.form-group input::placeholder,
.form-group textarea::placeholder {
  color: var(--dark-secondary);          /* 8.34:1 — placeholders are AA here */
  opacity: 1;
}
.form-group input:hover,
.form-group textarea:hover { border-color: var(--brand-primary); }
.form-group input:focus,
.form-group textarea:focus {
  background: var(--light-secondary);
  border-color: var(--brand-primary);
  outline: 3px solid var(--brand-primary);
  outline-offset: 1px;
}
.form-group input.error,
.form-group textarea.error { border-color: var(--state-error); border-width: 2px; }

/* Emitted on every load and revealed by js/contact-form.js. Without the
   display rule the card would ship four permanent error messages. */
.field-error {
  display: none;
  margin-top: .35rem;
  font-size: .78rem;
  font-weight: 600;
  color: var(--state-error);             /* 10.17:1 on white */
}
.field-error.show { display: block; }

.form-submit {
  width: 100%;
  padding: 1rem 1.5rem;
  background: var(--brand-primary);
  color: var(--light-secondary);         /* 15.09:1 */
  border: 1px solid var(--brand-primary);
  font-size: .78rem;
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  transition: background .25s ease, border-color .25s ease;
}
.form-submit:hover {
  background: color-mix(in srgb, var(--brand-primary) 45%, var(--brand-secondary));
  border-color: color-mix(in srgb, var(--brand-primary) 45%, var(--brand-secondary));
  /* the same deepened navy as .btn-gold:hover — white label 16.46:1 */
}
.form-submit:disabled { opacity: .55; cursor: not-allowed; }

/* The status block carries the `hidden` attribute until the worker replies —
   this must not out-specify it. */
.form-status {
  display: block;
  margin-top: 1rem;
  padding: .85rem 1rem;
  font-size: .88rem;
  font-weight: 600;
  border-left: 3px solid var(--dark-tertiary);
  background: var(--light-primary);
  color: var(--dark-primary);
}
.form-status[hidden] { display: none; }
.form-status.success {
  border-left-color: var(--state-success);
  background: color-mix(in srgb, var(--state-success) 8%, var(--light-secondary));
  color: var(--state-success);           /* on its own 8% tint → 6.76:1 */
}
.form-status.error {
  border-left-color: var(--state-error);
  background: color-mix(in srgb, var(--state-error) 8%, var(--light-secondary));
  color: var(--state-error);             /* on its own 8% tint → 8.81:1 */
}

/* ── Contact modal (injected by js/script.js on every non-contact page) ── */
.cm-modal {
  margin: auto;                          /* re-assert UA dialog centring */
  width: min(100%, 29rem);
  padding: 1rem;
  border: 0;
  background: transparent;
  overscroll-behavior: contain;
}
.cm-modal:not([open]) { display: none; }
/* ::backdrop inherits custom properties in current engines; the filter is the
   belt-and-braces so the scrim is visible even where it does not. */
.cm-modal::backdrop {
  background: color-mix(in srgb, var(--brand-secondary) 72%, transparent);
  -webkit-backdrop-filter: blur(3px) brightness(.55);
  backdrop-filter: blur(3px) brightness(.55);
}
.cm-modal__panel {
  position: relative;
  padding: clamp(1.35rem, 4vw, 2rem);
  background: var(--light-secondary);
  border-top: 3px solid var(--brand-primary);
  color: var(--dark-primary);
  box-shadow: var(--lift-lg);
}
.cm-modal__title {
  font-family: var(--display);
  font-size: 1.35rem;
  font-weight: 600;
  line-height: 1.25;
  color: var(--brand-primary);           /* 15.09:1 on white */
  margin: 0 0 1.25rem;
  padding-right: 2.75rem;
}
.cm-modal__close {
  position: absolute;
  top: .6rem;
  right: .6rem;
  width: 42px;
  height: 42px;
  font-size: 1.6rem;
  line-height: 1;
  color: var(--dark-primary);            /* 17.93:1 on white */
  transition: background .2s ease, color .2s ease;
}
.cm-modal__close:hover {
  background: var(--brand-primary);
  color: var(--light-secondary);         /* 15.09:1 inverted */
}
.cm-form { display: grid; gap: .9rem; }
.cm-form__field { display: flex; flex-direction: column; gap: .35rem; text-align: left; }
.cm-form__field label {
  font-size: .7rem;
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--dark-primary);
}
.cm-form input,
.cm-form textarea {
  width: 100%;
  min-width: 0;
  font: inherit;
  font-size: .95rem;
  padding: .7rem .85rem;
  background: var(--light-primary);
  border: 1px solid var(--dark-tertiary);
  color: var(--dark-primary);
}
.cm-form input::placeholder,
.cm-form textarea::placeholder { color: var(--dark-secondary); opacity: 1; }
.cm-form input:focus-visible,
.cm-form textarea:focus-visible {
  outline: 3px solid var(--brand-primary);
  outline-offset: 1px;
  border-color: var(--brand-primary);
  background: var(--light-secondary);
}
.cm-form textarea { min-height: 5.5rem; resize: vertical; }
.cm-form__submit {
  padding: .9rem 1.5rem;
  background: var(--brand-primary);
  color: var(--light-secondary);         /* 15.09:1 */
  border: 1px solid var(--brand-primary);
  font-size: .78rem;
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  transition: background .25s ease, border-color .25s ease;
}
.cm-form__submit:hover {
  background: color-mix(in srgb, var(--brand-primary) 45%, var(--brand-secondary));
  border-color: color-mix(in srgb, var(--brand-primary) 45%, var(--brand-secondary));
}
.cm-form__status {
  padding: .75rem .9rem;
  font-size: .85rem;
  font-weight: 600;
  border-left: 3px solid var(--dark-tertiary);
  background: var(--light-primary);
  color: var(--dark-primary);
}
.cm-form__status[hidden] { display: none; }
.cm-form__status.success {
  border-left-color: var(--state-success);
  background: color-mix(in srgb, var(--state-success) 8%, var(--light-secondary));
  color: var(--state-success);
}
.cm-form__status.error {
  border-left-color: var(--state-error);
  background: color-mix(in srgb, var(--state-error) 8%, var(--light-secondary));
  color: var(--state-error);
}
.cm-form__hint {
  margin: 0;
  font-size: .76rem;
  line-height: 1.6;
  color: var(--dark-secondary);          /* 8.86:1 on the white panel */
}
.cm-form__hint a { color: var(--brand-primary); text-decoration: underline; font-weight: 600; }
.cm-form__hint a:hover { color: color-mix(in srgb, var(--brand-primary) 65%, var(--dark-primary)); }

/* Class-based so it cannot fight an inline body.style.overflow. */
body.has-modal-open { overflow: hidden; }


/* ============================================================================
   18. FOOTER — the closing ink band
   Deliberately ink, not paper: it is the clean resolution of donor trap (b).
   With --brand-secondary as a ground here there is no second surface to tune
   it against, and every footer element is inverted below.
   ========================================================================== */

#footer {
  background: var(--brand-secondary);
  color: var(--light-tertiary);          /* 15.15:1 */
  padding: clamp(3rem, 6vw, 4.5rem) var(--gut) 2rem;
  border-top: 3px solid var(--brand-primary);
}

.footer-inner {
  width: 100%;
  max-width: var(--wrap);
  margin-inline: auto;
  display: grid;
  grid-template-columns: 1fr;
  gap: 2.5rem;
  padding-bottom: 2.5rem;
  border-bottom: 1px solid color-mix(in srgb, var(--light-secondary) 20%, transparent);
}

.footer-brand { max-width: 46ch; }
.footer-logo {
  display: flex;
  align-items: center;
  gap: .7rem;
  margin-bottom: 1.1rem;
}
/* The lockup inverts inside the ink footer. */
#footer .brand-developer { color: color-mix(in srgb, var(--light-secondary) 78%, var(--brand-secondary)); } /* 10.80:1 */
#footer .brand-project { color: var(--light-secondary); }   /* 17.58:1 */

.footer-tagline {
  font-family: var(--display);
  font-size: 1.05rem;
  line-height: 1.5;
  color: var(--light-secondary);         /* 17.58:1 */
  margin-bottom: .85rem;
}
.footer-about-text {
  font-size: .84rem;
  line-height: 1.75;
  color: color-mix(in srgb, var(--light-secondary) 76%, var(--brand-secondary));
  /* 10.28:1 on the ink footer */
}

.footer-col-title {
  font-size: .64rem;
  font-weight: 700;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--brand-tertiary);          /* 15.59:1 on ink */
  margin: 0 0 1rem;
  padding-bottom: .6rem;
  border-bottom: 1px solid color-mix(in srgb, var(--light-secondary) 22%, transparent);
}
.footer-col ul { display: flex; flex-direction: column; gap: .1rem; }
.footer-col a,
.footer-col address {
  display: block;
  font-size: .84rem;
  line-height: 1.7;
  padding: .28rem 0;
  color: color-mix(in srgb, var(--light-secondary) 80%, var(--brand-secondary));
  /* 11.35:1 on the ink footer */
}
/* Not colour-only: the link shifts right and gains an underline. */
.footer-col a:hover {
  color: var(--light-secondary);         /* 17.58:1 */
  padding-left: .35rem;
  text-decoration: underline;
  text-underline-offset: 3px;
}

.footer-disclaimer {
  max-width: 90ch;
  margin: 2rem auto 1.25rem;
  font-size: .72rem;
  line-height: 1.7;
  text-align: center;
  color: color-mix(in srgb, var(--light-secondary) 70%, var(--brand-secondary));
  /* 8.84:1 on the ink footer — small text, checked at the 4.5:1 bar */
}
/* §2 trap (a), the exact shape the donor got wrong: the disclaimer's <strong>
   sits in a DARK band, so it brightens toward white. It must never pick up a
   dark ink token. */
.footer-disclaimer strong { color: var(--light-secondary); }

.footer-copy {
  text-align: center;
  font-size: .72rem;
  letter-spacing: .06em;
  color: color-mix(in srgb, var(--light-secondary) 66%, var(--brand-secondary));
  /* 7.93:1 on the ink footer */
}


/* ============================================================================
   19. UTILITIES + JS STATE
   ========================================================================== */

/* js/script.js adds .visible to any .reveal it observes. No page currently
   emits .reveal, but the rules are declared so a future one is not invisible. */
.reveal { opacity: 0; transform: translateY(18px); transition: opacity .6s ease, transform .6s ease; }
.reveal.visible { opacity: 1; transform: none; }

::selection { background: var(--brand-primary); color: var(--light-secondary); }

/* Print: drop the chrome, flatten the ink bands to paper so a printed page is
   not a solid navy rectangle. */
@media print {
  #nav, #mobile-menu, .hamburger, #lightbox, .cm-modal, .cta-row, .closing-cta { display: none !important; }
  body { padding-top: 0; }
  .bg-white, .page-hero, #footer {
    background: var(--light-secondary) !important;
    color: var(--dark-primary) !important;
  }
  .bg-white h2, .bg-white h3, .page-hero h1, #footer .brand-project {
    color: var(--brand-primary) !important;
  }
}


/* ============================================================================
   20. RESPONSIVE — mobile-first, breakpoints 520 / 600 / 768 / 900 / 1024
   Nothing above this point assumes a wide viewport.
   ========================================================================== */

@media (min-width: 520px) {
  .plan-figure,
  .content-figure { padding: 1rem; }

  .form-row { grid-template-columns: 1fr 1fr; }

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

@media (min-width: 600px) {
  .gallery-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }

  .footer-inner { grid-template-columns: repeat(2, minmax(0, 1fr)); }

  .btn { padding: .95rem 2rem; }
}

@media (min-width: 768px) {
  body { font-size: 1.09375rem; }   /* 17.5px */

  .plan-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }

  .gallery-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 6px; }

  .hero-stats {
    display: flex;
    flex-wrap: wrap;
  }
  .hero-stat { flex: 0 0 auto; }

  .cta-row { flex-wrap: nowrap; }
}

@media (min-width: 900px) {
  .page-hero-inner { grid-template-columns: 1.25fr 1fr; }

  .contact-inner { grid-template-columns: 1fr 1fr; }

  .footer-inner { grid-template-columns: 2fr 1fr 1fr 1fr; }
  .footer-brand { grid-column: span 1; }

  .faq-q { font-size: 1.15rem; }
}

@media (min-width: 1024px) {
  :root { --navh: 76px; }

  .gallery-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  /* The lead plate takes a 2×2 cell; the remaining seven fill around it. */
  .gallery-item:first-child { grid-column: span 2; grid-row: span 2; aspect-ratio: auto; }

  .data-table { font-size: .92rem; }
  .data-table th,
  .data-table td { padding: .95rem 1.15rem; }
}

/* ── 1024-1280: the desktop nav is on, but nine links at full size do not
   fit. Measured: at 1280 the list is 851px and exactly fills the bar; below
   that "Master Plan" and "Floor Plans" wrapped to a second line inside a 76px
   bar (the list grew to 62px tall). Everything in the bar steps down one
   notch through this range instead of collapsing early — the fleet standard
   puts the hamburger at 1024 and that is not negotiable here. ── */
@media (min-width: 1024px) and (max-width: 1279.98px) {
  #nav { gap: .55rem; padding: 0 1.4rem; }
  .brand-logo-img { width: 34px; height: 34px; }
  .brand-project { font-size: .92rem; }
  .brand-developer { font-size: .58rem; letter-spacing: .16em; }
  .nav-links { gap: .78rem; }
  .nav-links a { font-size: .67rem; letter-spacing: .05em; }
  .nav-cta { padding: .55rem 1rem; font-size: .67rem; letter-spacing: .08em; }
}

/* ── Nav collapses to the hamburger at 1024, per the fleet standard ── */
@media (max-width: 1023.98px) {
  .nav-links { display: none; }
  .nav-cta { display: none; }
  .hamburger { display: flex; }
  .brand-project { font-size: .98rem; }
}
@media (min-width: 1024px) {
  #mobile-menu { display: none; }
}

/* ── 360px safety: nothing may push the body sideways ── */
@media (max-width: 400px) {
  .brand-logo-img { width: 34px; height: 34px; }
  .brand-project { font-size: .9rem; white-space: normal; }
  .hero-btns .btn,
  .page-hero-ctas .btn,
  .cta-row .btn { width: 100%; }
  .hero-stats { grid-template-columns: repeat(2, minmax(0, 1fr)); width: 100%; }
  .page-hero-image::after { inset: 8px -8px -8px 8px; }
}
