/* ==========================================================================
   TASMONT HOMES — Design System
   Dark architectural luxury. Palette drawn from the Tasmont mark:
   charcoal roofline, brass battens, ivory render, Tasmanian foliage.
   ========================================================================== */

/* Two weights per family, and only the italic the brass headings use.
   The sheet previously pulled seven faces to render four, which is payload
   spent on weights no rule ever asks for. */
@import url('https://fonts.googleapis.com/css2?family=Playfair+Display:ital,wght@0,400;0,500;1,400&family=Inter:wght@400;500&display=swap');

:root {
  /* Surfaces — cool charcoal, matching the roof of the mark */
  --ink-900: #08090b;
  --ink-850: #0b0d10;
  --ink-800: #101318;
  --ink-750: #151920;
  --ink-700: #1b2028;
  --ink-600: #242a34;

  /* Brass — lifted straight from the logo battens */
  --gold: #c9a24c;
  --gold-light: #e6c67f;
  --gold-bright: #f2dda6;
  --gold-deep: #8f6f2c;
  --gold-glow: rgba(201, 162, 76, 0.38);
  --gold-veil: rgba(201, 162, 76, 0.10);

  /* Foliage accent, used sparingly for "verified / live" states */
  --sage: #86977a;

  /* Type */
  --ivory: #f6f1e8;
  --ivory-dim: #b3ab9c;
  --ivory-faint: #7b7466;

  --line: rgba(201, 162, 76, 0.20);
  --line-soft: rgba(255, 255, 255, 0.08);
  --line-hair: rgba(255, 255, 255, 0.045);

  --glass: rgba(255, 255, 255, 0.045);
  --glass-strong: rgba(255, 255, 255, 0.075);
  --glass-line: rgba(255, 255, 255, 0.11);
  --blur: 22px;

  --font-display: 'Playfair Display', 'Times New Roman', Georgia, serif;
  --font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;

  --shadow-sm: 0 4px 16px rgba(0, 0, 0, 0.35);
  --shadow-md: 0 14px 38px rgba(0, 0, 0, 0.48);
  --shadow-lg: 0 30px 70px rgba(0, 0, 0, 0.62);
  --shadow-brass: 0 0 44px rgba(201, 162, 76, 0.22);

  --ease: cubic-bezier(0.4, 0, 0.2, 1);
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-spring: cubic-bezier(0.34, 1.4, 0.5, 1);
  --t-fast: 0.22s var(--ease);
  --t: 0.36s var(--ease);
  --t-slow: 0.7s var(--ease-out);

  --r-xs: 6px;
  --r-sm: 10px;
  --r-md: 16px;
  --r-lg: 24px;
  --r-xl: 34px;
  --r-pill: 999px;

  /* Spacing scale, 8px base. Every gap, pad and margin added or corrected
     in this pass comes from here rather than from a hand-picked rem value,
     so vertical rhythm stays consistent between sections. */
  --space-1: 0.25rem;   /*  4px */
  --space-2: 0.5rem;    /*  8px */
  --space-3: 0.75rem;   /* 12px */
  --space-4: 1rem;      /* 16px */
  --space-5: 1.5rem;    /* 24px */
  --space-6: 2rem;      /* 32px */
  --space-8: 3rem;      /* 48px */
  --space-10: 4rem;     /* 64px */
  --space-12: 6rem;     /* 96px */

  --wrap: 1240px;
  --wrap-lg: 1440px;
  --gutter: clamp(1.15rem, 4vw, 2.5rem);
  --nav-h: 84px;
}

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

html {
  font-size: 16px;
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--nav-h) + 1rem);
  background: var(--ink-900);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-size-adjust: 100%;
}

body {
  font-family: var(--font-sans);
  background: var(--ink-900);
  color: var(--ivory);
  line-height: 1.7;
  /* 300 on a dark background reads as grey mush at body size; 400 is the
     lightest weight that holds its shape here. */
  font-weight: 400;
  overflow-x: hidden;
  min-height: 100vh;
}

/* Two soft brass washes so large flat panels never read as dead black. */
body::before {
  content: '';
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background:
    radial-gradient(1100px 620px at 82% -8%, rgba(201, 162, 76, 0.055), transparent 62%),
    radial-gradient(860px 520px at 8% 102%, rgba(201, 162, 76, 0.035), transparent 66%);
}
body > * { position: relative; z-index: 1; }

a { color: inherit; text-decoration: none; transition: color var(--t-fast); }
img, video { max-width: 100%; height: auto; display: block; }
button { font: inherit; color: inherit; cursor: pointer; border: none; background: none; }
input, select, textarea { font: inherit; color: inherit; }
ul, ol { list-style: none; }
svg { flex-shrink: 0; }

::selection { background: var(--gold); color: var(--ink-900); }

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

::-webkit-scrollbar { width: 11px; }
::-webkit-scrollbar-track { background: var(--ink-900); }
::-webkit-scrollbar-thumb { background: var(--ink-700); border-radius: 99px; border: 3px solid var(--ink-900); }
::-webkit-scrollbar-thumb:hover { background: var(--gold-deep); }

/* --- Typography --- */
/* A single scale, each step roughly 1.25x the one below it. The old top end
   ran to 4.9rem, which on a laptop pushed everything under an h1 below the
   fold; headings here are sized to sit calmly rather than to shout. */
h1, h2, h3, h4, h5, h6 {
  font-family: var(--font-display);
  font-weight: 400;
  line-height: 1.18;
  letter-spacing: -0.015em;
  color: var(--ivory);
  text-wrap: balance;
}

h1, .display-1 { font-size: clamp(2.25rem, 4.6vw, 3.5rem); line-height: 1.12; letter-spacing: -0.025em; }
.display-2,
h2          { font-size: clamp(1.75rem, 3.2vw, 2.5rem); letter-spacing: -0.02em; }
h3          { font-size: clamp(1.15rem, 1.7vw, 1.4rem); line-height: 1.3; letter-spacing: -0.01em; }
h4          { font-size: clamp(1rem, 1.3vw, 1.125rem); line-height: 1.35; }

.display-2 { font-family: var(--font-display); line-height: 1.18; }

/* Measure is capped so body copy never runs the full width of a 1440px
   container, which is the single biggest thing making long text hard to
   read on a wide screen. */
p { color: var(--ivory-dim); max-width: 70ch; text-wrap: pretty; }
strong { color: var(--ivory); font-weight: 500; }

.text-gold {
  background: linear-gradient(100deg, var(--gold-deep) 0%, var(--gold-light) 32%, var(--gold-bright) 50%, var(--gold-light) 68%, var(--gold-deep) 100%);
  background-size: 220% 100%;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  font-style: italic;
  animation: brass-sweep 9s var(--ease) infinite;
}
@keyframes brass-sweep {
  0%, 100% { background-position: 0% 50%; }
  50%      { background-position: 100% 50%; }
}

.text-gradient {
  background: linear-gradient(120deg, var(--ivory), var(--gold-light));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

/* Eyebrow — a brass hairline, then small caps */
.section-label, .eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 0.7rem;
  font-family: var(--font-sans);
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--gold);
  margin-bottom: var(--space-4);
}
.section-label::before, .eyebrow::before {
  content: '';
  width: clamp(24px, 4vw, 46px);
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--gold));
}

/* --- Layout --- */
.container { width: 100%; max-width: var(--wrap); margin-inline: auto; padding-inline: var(--gutter); }
.container-lg { max-width: var(--wrap-lg); }

.section { padding: clamp(4.5rem, 9vw, 8rem) 0; position: relative; }
.section-sm { padding: clamp(3rem, 5vw, 4.5rem) 0; position: relative; }
.section--tight { padding: clamp(3.25rem, 6vw, 5.25rem) 0; }
.section--alt { background: var(--ink-850); }

/* A lead-in section hands straight over to the section below it. Left to
   stack, a tight section's 84px bottom padding plus a full section's 128px
   top padding opened a 212px hole in the page with nothing in it. */
.section--lead { padding-bottom: 0; }

.section-header { max-width: 720px; margin: 0 auto clamp(2.75rem, 5vw, 4.25rem); text-align: center; }
.section-header .section-label, .section-header .eyebrow { justify-content: center; }
.section-header .section-label::after, .section-header .eyebrow::after {
  content: '';
  width: clamp(24px, 4vw, 46px);
  height: 1px;
  background: linear-gradient(90deg, var(--gold), transparent);
}
.section-title { margin-bottom: 1rem; }
.section-desc { color: var(--ivory-dim); font-size: 1.02rem; max-width: 62ch; margin-inline: auto; }

.visually-hidden {
  position: absolute !important;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* --- Glass surface --- */
.glass-card {
  position: relative;
  background: linear-gradient(160deg, rgba(255, 255, 255, 0.062), rgba(255, 255, 255, 0.018));
  border: 1px solid var(--glass-line);
  border-radius: var(--r-lg);
  backdrop-filter: blur(var(--blur));
  -webkit-backdrop-filter: blur(var(--blur));
  transition: transform var(--t), border-color var(--t), box-shadow var(--t);
}
/* A brass hairline catching the top edge, like light on a batten. */
.glass-card::after {
  content: '';
  position: absolute;
  inset: 0 0 auto 0;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--gold-glow) 45%, transparent);
  opacity: 0.7;
  pointer-events: none;
}
.glass-card:hover {
  transform: translateY(-6px);
  border-color: var(--line);
  box-shadow: var(--shadow-lg), var(--shadow-brass);
}

/* --- Buttons --- */
.btn {
  --btn-pad: 0.95rem 2rem;
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.6rem;
  padding: var(--btn-pad);
  font-family: var(--font-sans);
  font-size: 0.82rem;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  border-radius: var(--r-pill);
  border: 1px solid transparent;
  white-space: nowrap;
  overflow: hidden;
  isolation: isolate;
  transition: transform var(--t), box-shadow var(--t), color var(--t), border-color var(--t), background var(--t);
}
.btn:hover { transform: translateY(-2px); }
.btn:active { transform: translateY(0); }
.btn svg { transition: transform var(--t); }
.btn:hover svg { transform: translateX(4px); }

/* Sheen that wipes across on hover */
.btn::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background: linear-gradient(105deg, transparent 30%, rgba(255, 255, 255, 0.4) 50%, transparent 70%);
  transform: translateX(-120%);
  transition: transform 0.75s var(--ease-out);
}
.btn:hover::before { transform: translateX(120%); }
.btn-solid {
  background: linear-gradient(135deg, var(--gold-light), var(--gold) 52%, var(--gold-deep));
  color: #17130a;
  box-shadow: 0 10px 30px rgba(201, 162, 76, 0.26);
}
.btn-solid:hover {
  box-shadow: 0 16px 44px rgba(201, 162, 76, 0.42);
  color: #17130a;
}

.btn-outline {
  border-color: var(--line);
  color: var(--gold-light);
  background: rgba(201, 162, 76, 0.05);
}
.btn-outline:hover {
  border-color: var(--gold);
  background: rgba(201, 162, 76, 0.12);
  color: var(--gold-bright);
}

/* Thin-line secondary. Neutral rather than brass, so it sits behind the
   primary CTA instead of competing with it. */
.btn-line {
  border-color: var(--glass-line);
  color: var(--ivory);
  background: transparent;
}
.btn-line:hover {
  border-color: var(--gold);
  color: var(--gold-bright);
  background: rgba(201, 162, 76, 0.07);
}

.btn-glass {
  background: rgba(10, 12, 15, 0.42);
  border-color: rgba(255, 255, 255, 0.28);
  color: var(--ivory);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
}
.btn-glass:hover { background: rgba(10, 12, 15, 0.62); border-color: var(--gold); color: var(--gold-bright); }

.btn-block { display: flex; width: 100%; }
.btn-sm { --btn-pad: 0.6rem 1.25rem; font-size: 0.72rem; }

/* --- Scroll reveal ---
   `.reveal`, `.fade-in` and `.stagger-children` are markup hooks, not styles.
   The scroll engine claims them alongside the structural selectors listed at
   the foot of this sheet (see SCROLL CHOREOGRAPHY) and drives them from the
   scroll position, so the start states, the travel and the stagger all live
   there. Nothing is declared here on purpose: an element with no `.fx`
   ancestor — scripting off — simply renders in place. */
/* ==========================================================================
   NAVIGATION
   One header, one drawer, one active state, shared by every page.
   ========================================================================== */
.main-header {
  /* First thing on the page, and barely a move: the frame arrives, then the
     content arrives inside it. Settles down from above rather than up from
     below, which is the direction a fixed header reads as belonging to. */
  animation: header-in 0.8s var(--ease-out) both;
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 900;
  height: var(--nav-h);
  display: flex;
  align-items: center;
  transition: height var(--t), border-color var(--t);
  border-bottom: 1px solid transparent;
}

/* The glass plate lives on a pseudo-element, not on the header itself.
   backdrop-filter turns whatever carries it into a containing block for
   fixed-position descendants, and the mobile drawer is a descendant — put
   the blur on the header and the open drawer collapses into the 70px header
   band the moment .scrolled lands. Keeping it here leaves the drawer
   anchored to the viewport at every scroll position. */
.main-header::before {
  content: '';
  position: absolute;
  /* -1px so the plate reaches under the bottom border, the way the
     header's own background used to. */
  inset: 0 0 -1px 0;
  z-index: -1;
  background: linear-gradient(180deg, rgba(8, 9, 11, 0.82), rgba(8, 9, 11, 0.28) 70%, transparent);
  transition: background var(--t), backdrop-filter var(--t);
}
.main-header.scrolled {
  height: 70px;
  border-bottom-color: var(--line-soft);
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.45);
}

.main-header.scrolled::before {
  background: rgba(9, 11, 14, 0.86);
  backdrop-filter: blur(20px) saturate(150%);
  -webkit-backdrop-filter: blur(20px) saturate(150%);
}
.nav-wrapper {
  width: 100%;
  max-width: var(--wrap-lg);
  margin-inline: auto;
  padding-inline: var(--gutter);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
}

/* --- Brand: the Tasmont house on an ivory plate, then the wordmark --- */
.brand-logo {
  display: inline-flex;
  align-items: center;
  gap: 0.85rem;
  flex-shrink: 0;
}
.brand-mark {
  display: grid;
  place-items: center;
  width: 74px;
  height: 42px;
  padding: 3px 6px;
  border-radius: 11px;
  background: linear-gradient(157deg, #fdfcf9, #efe9dd);
  border: 1px solid rgba(201, 162, 76, 0.42);
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.45), inset 0 1px 0 rgba(255, 255, 255, 0.9);
  transition: transform var(--t), box-shadow var(--t);
}
.brand-mark img {
  width: 100%;
  height: 100%;
  object-fit: contain;
}
.brand-logo:hover .brand-mark {
  transform: translateY(-2px);
  box-shadow: 0 10px 26px rgba(0, 0, 0, 0.5), 0 0 24px var(--gold-glow), inset 0 1px 0 rgba(255, 255, 255, 0.9);
}
.brand-name {
  font-family: var(--font-display);
  font-size: 1.28rem;
  font-weight: 600;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  line-height: 1.05;
  color: var(--ivory);
  white-space: nowrap;
}
.brand-name span {
  color: var(--gold);
  font-weight: 500;
}
/* .brand-name ships as one flat string, so split it onto its own baseline */
.brand-name { font-size: 1.18rem; }

/* --- Links --- */
.navbar-links {
  display: flex;
  align-items: center;
  gap: clamp(1rem, 2.2vw, 2.1rem);
  margin-inline: auto;
}
.nav-item {
  position: relative;
  font-size: 0.79rem;
  font-weight: 500;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--ivory-dim);
  padding: 0.5rem 0;
  white-space: nowrap;
}
.nav-item::after {
  content: '';
  position: absolute;
  left: 0;
  bottom: 0;
  width: 100%;
  height: 1px;
  background: linear-gradient(90deg, var(--gold), var(--gold-light));
  transform: scaleX(0);
  transform-origin: right;
  transition: transform 0.4s var(--ease-out);
}
.nav-item:hover, .nav-item.active { color: var(--ivory); }
.nav-item:hover::after, .nav-item.active::after { transform: scaleX(1); transform-origin: left; }
.nav-item.active { color: var(--gold-light); }

.nav-actions { display: flex; align-items: center; gap: 0.85rem; flex-shrink: 0; }


.nav-cta { --btn-pad: 0.7rem 1.5rem; font-size: 0.73rem; }

/* --- Burger --- */
.nav-toggle {
  display: none;
  flex-direction: column;
  justify-content: center;
  gap: 5px;
  width: 42px;
  height: 42px;
  padding: 0 9px;
  border-radius: 10px;
  border: 1px solid var(--line-soft);
  background: var(--glass);
  color: var(--ivory);
  font-size: 1.15rem;
}
.nav-toggle span {
  display: block;
  height: 1.5px;
  width: 100%;
  background: var(--ivory);
  border-radius: 2px;
  transition: transform var(--t), opacity var(--t-fast);
}
.nav-toggle.active span:nth-child(1) { transform: translateY(6.5px) rotate(45deg); }
.nav-toggle.active span:nth-child(2) { opacity: 0; }
.nav-toggle.active span:nth-child(3) { transform: translateY(-6.5px) rotate(-45deg); }

/* ==========================================================================
   HERO
   An editorial split. A dark specification panel holds every word; a
   full-bleed architectural plate holds the photograph, and nothing is
   allowed to float across it but one small project label. The seam between
   the two is bridged by a gradient rather than a hard edge, and the plate
   fades into the stats bar below so the section ends without a cut.

   The whole composition is one grid, so the two halves stay in proportion at
   every width and collapse — image above, panel below — rather than shrink.
   ========================================================================== */

.hero {
  position: relative;
  min-height: 100svh;
  display: grid;
  /* 43 / 57. Type gets the smaller half deliberately: the photograph is the
     first thing the eye is supposed to land on. */
  grid-template-columns: minmax(0, 43fr) minmax(0, 57fr);
  isolation: isolate;
  overflow: hidden;
  background: var(--ink-900);
}

/* --- Left: the specification panel --- */
.hero-panel {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: calc(var(--nav-h) + clamp(2rem, 5vh, 3.25rem))
           clamp(1.75rem, 4.2vw, 4.5rem)
           clamp(5.5rem, 9vh, 7rem);
  background: linear-gradient(180deg, var(--ink-850) 0%, var(--ink-900) 46%, var(--ink-850) 100%);
}

/* Drafting grid. Deliberately at the edge of perception — it should read as
   paper texture, not as a pattern anyone notices. */
.hero-blueprint {
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background-image:
    linear-gradient(to right, rgba(201, 162, 76, 0.028) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(201, 162, 76, 0.028) 1px, transparent 1px);
  background-size: 68px 68px;
  -webkit-mask-image: radial-gradient(88% 74% at 18% 26%, #000 0%, transparent 72%);
          mask-image: radial-gradient(88% 74% at 18% 26%, #000 0%, transparent 72%);
}

.hero-panel-body {
  position: relative;
  width: 100%;
  max-width: 34rem;
  margin-left: auto;
}

/* --- Slug line: eyebrow, measurement rule, annotation --- */
.hero-slug {
  display: flex;
  align-items: center;
  gap: 0.9rem;
  margin-bottom: clamp(1.4rem, 3vh, 2rem);
  animation: hero-rise 0.9s var(--ease-out) 0.1s both;
}
.hero-eyebrow {
  flex-shrink: 0;
  font-size: 0.66rem;
  font-weight: 500;
  letter-spacing: 0.34em;
  text-transform: uppercase;
  color: var(--gold);
}
/* The rule carries drafting ticks along its length. */
.hero-rule {
  flex: 1 1 auto;
  min-width: 1.5rem;
  height: 5px;
  background-image:
    linear-gradient(to right, rgba(201, 162, 76, 0.42) 0 100%),
    repeating-linear-gradient(to right, rgba(201, 162, 76, 0.42) 0 1px, transparent 1px 9px);
  background-size: 100% 1px, 100% 5px;
  background-position: 0 0, 0 0;
  background-repeat: no-repeat, repeat-x;
}
.hero-note {
  flex-shrink: 0;
  font-size: 0.6rem;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--ivory-faint);
  white-space: nowrap;
}

/* --- Headline: each line rises out of its own mask --- */
.hero-title {
  font-size: clamp(2.4rem, 3.65vw, 3.85rem);
  line-height: 1.07;
  letter-spacing: -0.028em;
  margin-bottom: clamp(1.1rem, 2.4vh, 1.6rem);
}
.hero-line {
  display: block;
  overflow: hidden;
  padding-bottom: 0.09em;
}
.hero-line > span, .hero-line > em {
  display: inline-block;
  animation: hero-word 1.05s var(--ease-out) both;
}
.hero-line:nth-child(1) > * { animation-delay: 0.24s; }
.hero-line:nth-child(2) > * { animation-delay: 0.38s; }
@keyframes hero-word {
  from { transform: translateY(105%) rotate(2deg); opacity: 0; }
  to   { transform: none; opacity: 1; }
}

.hero-lede {
  max-width: 46ch;
  font-size: clamp(0.94rem, 1.05vw, 1.04rem);
  line-height: 1.72;
  color: rgba(246, 241, 232, 0.74);
  margin-bottom: clamp(1.9rem, 4vh, 2.6rem);
  animation: hero-rise 1s var(--ease-out) 0.62s both;
}

.hero-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.85rem;
  margin-bottom: clamp(2.25rem, 5vh, 3.25rem);
}
/* The pair arrives together but not in lockstep: the primary leads by a
   beat, which is enough to read as a sequence rather than a block move. */
.hero-actions .btn {
  --btn-pad: 0.92rem 1.85rem;
  font-size: 0.75rem;
  animation: hero-rise 0.95s var(--ease-out) both;
}
.hero-actions .btn:nth-child(1) { animation-delay: 0.76s; }
.hero-actions .btn:nth-child(2) { animation-delay: 0.87s; }

@keyframes header-in {
  from { opacity: 0; transform: translateY(-8px); }
  to   { opacity: 1; transform: none; }
}

@keyframes hero-rise {
  from { opacity: 0; transform: translateY(20px); }
  to   { opacity: 1; transform: none; }
}

/* --- Specification bar ---
   Drawing-sheet labels: hairline rules, tracked-out caps, brass glyphs.
   Nothing here is a badge or a pill.

   Three equal columns rather than an inline row. Set inline, the three labels
   want 684px and the panel is a 43% column — under 500px at most desktop
   widths — so the row would wrap and strand a separator against nothing.
   Columns let each label take two lines and hold the rules upright, which is
   how the labels sit on a real specification sheet anyway. */
.hero-spec {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  padding-top: clamp(1rem, 2.4vh, 1.35rem);
  border-top: 1px solid var(--line-hair);
}
.hero-spec li {
  display: flex;
  align-items: flex-start;
  gap: 0.5rem;
  padding-right: clamp(0.7rem, 1.4vw, 1.15rem);
  border-right: 1px solid var(--line-hair);
  font-size: 0.62rem;
  font-weight: 500;
  line-height: 1.65;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ivory-dim);
  text-wrap: balance;
  animation: hero-rise 0.85s var(--ease-out) both;
}
.hero-spec li + li { padding-left: clamp(0.7rem, 1.4vw, 1.15rem); }
.hero-spec li:last-child { border-right: 0; padding-right: 0; }
.hero-spec li:nth-child(1) { animation-delay: 0.9s; }
.hero-spec li:nth-child(2) { animation-delay: 0.99s; }
.hero-spec li:nth-child(3) { animation-delay: 1.08s; }

/* --- Scroll cue --- */
.hero-scroll {
  position: absolute;
  left: clamp(1.75rem, 4.2vw, 4.5rem);
  bottom: clamp(1.9rem, 4.5vh, 3rem);
  display: flex;
  align-items: center;
  gap: 0.75rem;
  font-size: 0.6rem;
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: var(--ivory-faint);
  animation: hero-rise 0.75s var(--ease-out) 1.97s both;
  transition: color var(--t);
}
.hero-scroll:hover { color: var(--ivory-dim); }
.hero-scroll-index {
  font-family: var(--font-display);
  font-size: 0.78rem;
  letter-spacing: 0.1em;
  color: var(--gold);
}
.hero-scroll-rail {
  position: relative;
  width: clamp(38px, 5vw, 62px);
  height: 1px;
  overflow: hidden;
  background: var(--line-soft);
}
.hero-scroll-rail::after {
  content: '';
  position: absolute;
  inset: 0 auto 0 0;
  width: 42%;
  background: linear-gradient(90deg, transparent, var(--gold));
  animation: hero-travel 2.3s var(--ease) infinite;
}
@keyframes hero-travel {
  0%   { transform: translateX(-100%); }
  100% { transform: translateX(260%); }
}
.hero-scroll-arrow {
  color: var(--gold);
  transition: transform var(--t);
}
.hero-scroll:hover .hero-scroll-arrow { transform: translateY(3px); }

/* --- Right: the architectural plate --- */
.hero-plate {
  position: relative;
  z-index: 0;
  overflow: hidden;
  background: var(--ink-900);
}

/* --sy is written by the scroll engine, --mx / --my by the pointer handler,
   both in app.js. They live on the stage rather than on .hero because a
   custom property set on the section would invalidate the computed style of
   every node inside it on every frame; scoped here it touches two.
   The stage over-extends so there is somewhere for the drift to go. */
.hero-stage {
  position: absolute;
  left: 0;
  right: 0;
  top: -16%;
  height: 132%;
  --sy: 0;
  --mx: 0;
  --my: 0;
  transform: translate3d(calc(var(--mx) * 1px), calc((var(--sy) + var(--my)) * 1px), 0);
  will-change: transform;
}
.hero-stage img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Two animations, one property between them. The entrance settles on the
     scale the ken-burns crawl starts from, and the crawl is delayed past the
     entrance so the handover is invisible. Both use `scale` / `translate`
     rather than `transform`, which the parallax above owns. */
  animation:
    hero-plate-in 1.6s var(--ease-out) both,
    hero-kenburns 42s var(--ease) 1.6s infinite alternate;
}
@keyframes hero-plate-in {
  from { scale: 1.11; opacity: 0; }
  to   { scale: 1.06; opacity: 1; }
}
@keyframes hero-kenburns {
  0%   { scale: 1.06; translate: 0 0; }
  100% { scale: 1.15; translate: -1.8% -1.3%; }
}

/* Bridges the plate to the panel on the left and to the stats bar below, so
   neither edge reads as a cut. Kept light — the photograph is the point. */
.hero-veil {
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  background:
    linear-gradient(90deg, var(--ink-900) 0%, rgba(8, 9, 11, 0.62) 6%, rgba(8, 9, 11, 0.12) 20%, transparent 34%),
    linear-gradient(180deg, rgba(8, 9, 11, 0.52) 0%, transparent 22%),
    linear-gradient(0deg, var(--ink-850) 0%, rgba(11, 13, 16, 0.55) 9%, transparent 26%);
}

.hero-grain {
  position: absolute;
  inset: -60px;
  z-index: 3;
  pointer-events: none;
  opacity: 0.11;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='220' height='220'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.82' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  animation: hero-grain-shift 0.9s steps(4) infinite;
}
@keyframes hero-grain-shift {
  0%   { transform: translate(0, 0); }
  25%  { transform: translate(-3%, 2%); }
  50%  { transform: translate(2%, -3%); }
  75%  { transform: translate(-2%, -2%); }
  100% { transform: translate(0, 0); }
}

/* --- The one thing allowed to sit on the photograph --- */


.hero-note--coord {
  position: absolute;
  z-index: 4;
  left: clamp(1.5rem, 3vw, 2.75rem);
  bottom: clamp(2.75rem, 6vh, 4rem);
  font-size: 0.585rem;
  color: rgba(246, 241, 232, 0.52);
  /* After the curtain has cleared the photograph, not over it. */
  animation: hero-rise 0.8s var(--ease-out) 1.78s both;
}

/* Annotation running up the seam between the two halves.

   Set with writing-mode rather than a rotation, so the entrance below is free
   to own `transform` — an animation outranks a static declaration on the same
   property, and a shared `hero-rise` would quietly flatten the label back to
   horizontal.

   Held entirely on the panel side of the seam rather than straddling it: at
   0.3 opacity the lower half of a straddling label vanished into the lit part
   of the photograph, and the annotation read as a fragment. */
.hero-seam {
  position: absolute;
  z-index: 5;
  top: 50%;
  left: 43%;
  writing-mode: vertical-rl;
  font-size: 0.55rem;
  letter-spacing: 0.42em;
  text-transform: uppercase;
  color: rgba(246, 241, 232, 0.3);
  white-space: nowrap;
  pointer-events: none;
  animation: hero-seam-in 0.85s var(--ease-out) 1.86s both;
}
@keyframes hero-seam-in {
  from { opacity: 0; transform: translate(calc(-100% - 0.8rem), calc(-50% + 18px)); }
  to   { opacity: 1; transform: translate(calc(-100% - 0.8rem), -50%); }
}

/* While a scroll is in flight, park the plate's ambient loops. Both keep the
   backdrop under the tag's blur panel changing, so that blur cannot be cached
   and re-samples every frame. A pause of a few hundred milliseconds is not
   perceptible and hands the frame budget back. Class toggled in app.js. */
.hero.is-scrolling .hero-stage img,
.hero.is-scrolling .hero-grain,
.hero.is-scrolling .hero-scroll-rail::after {
  animation-play-state: paused;
}

/* Below roughly a 1280px viewport the 43% column drops under the ~440px that
   three columns need to keep each label to two lines, and the labels start
   breaking to three. They stack into a single specification list instead —
   still upright rules, still drawing-sheet caps, just one per row. */
@media (max-width: 1279px) {
  .hero-spec {
    grid-template-columns: 1fr;
    gap: 0.6rem;
  }
  .hero-spec li,
  .hero-spec li + li {
    border-right: 0;
    padding-right: 0;
    padding-left: 0;
  }
}

/* --- Tablet: even halves, tighter type --- */
@media (max-width: 1080px) {
  .hero { grid-template-columns: 1fr 1fr; }
  .hero-seam { left: 50%; }
  .hero-panel-body { max-width: none; }
  .hero-title { font-size: clamp(2rem, 4.4vw, 2.9rem); }
  .hero-lede { font-size: 0.92rem; }
  .hero-actions .btn { --btn-pad: 0.85rem 1.4rem; font-size: 0.685rem; }
  .hero-spec li { font-size: 0.585rem; }
}

/* --- Phone: the plate on top, the panel beneath it ---
   Stacked rather than squeezed: the photograph keeps a generous, deliberately
   cinematic band and the panel gets the full width for its type. */
@media (max-width: 820px) {
  .hero {
    min-height: 0;
    grid-template-columns: 1fr;
    grid-template-rows: auto auto;
  }
  .hero-plate {
    order: 1;
    height: clamp(300px, 46svh, 460px);
  }
  .hero-panel {
    order: 2;
    padding: clamp(2.25rem, 7vw, 3.25rem) var(--gutter) clamp(4.5rem, 9vh, 5.5rem);
  }
  .hero-stage { top: -8%; height: 116%; }
  .hero-veil {
    background:
      linear-gradient(180deg, rgba(8, 9, 11, 0.62) 0%, transparent 34%),
      linear-gradient(0deg, var(--ink-850) 0%, rgba(11, 13, 16, 0.5) 12%, transparent 34%);
  }
  .hero-seam { display: none; }

  .hero-note--coord { bottom: clamp(1.1rem, 3vh, 1.75rem); }
  .hero-title { font-size: clamp(2.15rem, 8.4vw, 3rem); }
  .hero-lede { max-width: 54ch; }
  .hero-scroll {
    left: var(--gutter);
    bottom: clamp(1.5rem, 4vh, 2.25rem);
  }
}

@media (max-width: 520px) {
  .hero-actions { width: 100%; }
  .hero-actions .btn { flex: 1 1 auto; }
  .hero-spec { gap: 0.75rem; }
  .hero-spec li { font-size: 0.6rem; }
  .hero-slug { gap: 0.7rem; }
  .hero-note { display: none; }
}

/* --- Inner-page hero --- */
.page-hero {
  position: relative;
  display: flex;
  align-items: flex-end;
  min-height: clamp(320px, 48vh, 460px);
  padding: calc(var(--nav-h) + 3rem) 0 clamp(2.5rem, 5vw, 4rem);
  overflow: hidden;
  isolation: isolate;
}
.page-hero-bg {
  position: absolute;
  inset: 0;
  z-index: -2;
  width: 100%;
  height: 100%;
  object-fit: cover;
  animation: hero-kenburns 40s var(--ease) infinite alternate;
}
.page-hero::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background:
    linear-gradient(180deg, rgba(8, 9, 11, 0.86) 0%, rgba(8, 9, 11, 0.42) 40%, var(--ink-900) 98%),
    radial-gradient(90% 70% at 30% 60%, transparent 20%, rgba(8, 9, 11, 0.6) 100%);
}
.page-hero-inner { position: relative; }
.page-hero-title { margin-bottom: 0.9rem; }

.page-hero-crumb, .breadcrumb {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.5rem;
  font-size: 0.78rem;
  letter-spacing: 0.08em;
  color: var(--ivory-faint);
}
.page-hero-crumb a, .breadcrumb a { color: var(--ivory-dim); }
.page-hero-crumb a:hover, .breadcrumb a:hover { color: var(--gold-light); }
.page-hero-crumb i, .breadcrumb i { color: var(--gold-deep); font-size: 0.7rem; }

/* Slim head used by the project detail page */
.page-head {
  padding: calc(var(--nav-h) + 2.5rem) 0 1.75rem;
  border-bottom: 1px solid var(--line-hair);
  background: linear-gradient(180deg, var(--ink-850), var(--ink-900));
}
.page-head .display-2 { margin: 1rem 0 0.6rem; }

@media (prefers-reduced-motion: reduce) {
  .hero-stage img, .page-hero-bg, .hero-grain,
  .hero-scroll-rail::after, .text-gold {
    animation: none !important;
  }
  .hero-slug, .hero-line > span, .hero-line > em,
  .hero-lede, .hero-actions, .hero-actions .btn, .hero-spec li,
  .hero-scroll, .hero-note--coord, .hero-seam,
  .main-header {
    animation: none !important;
    opacity: 1;
    transform: none;
  }
  /* The seam label still has to sit against its side of the seam. */
  .hero-seam { transform: translate(calc(-100% - 0.8rem), -50%); }
  .hero-stage img { scale: 1.06; opacity: 1; }
}
/* ==========================================================================
   STATS BAR
   ========================================================================== */
.stats-bar {
  padding: clamp(2.5rem, 5vw, 3.75rem) 0;
  background: var(--ink-850);
  border-block: 1px solid var(--line-hair);
}
.stats-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 1.5rem;
}
.stat-item { position: relative; text-align: center; }
.stat-item:not(:last-child)::after {
  content: '';
  position: absolute;
  right: 0;
  top: 12%;
  height: 76%;
  width: 1px;
  background: linear-gradient(180deg, transparent, var(--line), transparent);
}
.stat-number {
  display: block;
  font-family: var(--font-display);
  font-size: clamp(2rem, 4vw, 3.1rem);
  font-weight: 500;
  line-height: 1;
  letter-spacing: -0.02em;
  margin-bottom: 0.6rem;
  background: linear-gradient(135deg, var(--ivory), var(--gold-light) 70%, var(--gold));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
.stat-label {
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ivory-faint);
}

/* ==========================================================================
   VALUE CARDS
   ========================================================================== */
.value-cards-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(255px, 1fr));
  gap: var(--space-5);
}

/* These cards are read, not clicked. They previously inherited the glass
   card's hover lift and brass bloom, which invited a click that does
   nothing — so the surface here is flat and static, and the only thing
   that moves on the page is something you can actually act on. */
.value-card {
  position: relative;
  padding: var(--space-6) var(--space-5);
  border: 1px solid var(--line-hair);
  border-radius: var(--r-lg);
  background: linear-gradient(160deg, rgba(255, 255, 255, 0.04), rgba(255, 255, 255, 0.012));
}
.value-card h3 { margin-bottom: var(--space-3); }
.value-card p { font-size: 0.93rem; max-width: none; }

/* ==========================================================================
   STORY SPLIT
   ========================================================================== */
.story-section { background: var(--ink-850); }
.story-split {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(2.5rem, 6vw, 5rem);
  align-items: center;
}
.story-image-wrap { position: relative; }
.story-image {
  position: relative;
  border-radius: var(--r-lg);
  overflow: hidden;
  box-shadow: var(--shadow-lg);
}
.story-image::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  border: 1px solid var(--glass-line);
  pointer-events: none;
}
.story-image img {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  transition: transform 1s var(--ease-out);
}
.story-image:hover img { transform: scale(1.06); }


.story-text h2 { margin-bottom: 1.25rem; }
.story-text p { margin-bottom: 1.1rem; }

/* ==========================================================================
   PROCESS TIMELINE
   ========================================================================== */
.timeline-grid {
  position: relative;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: 2rem;
}
.timeline-grid::before {
  content: '';
  position: absolute;
  top: 27px;
  left: 8%;
  right: 8%;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--line) 15%, var(--line) 85%, transparent);
}
.timeline-card { position: relative; text-align: center; padding-top: 0.25rem; }
.timeline-dot {
  position: relative;
  display: grid;
  place-items: center;
  width: 54px;
  height: 54px;
  margin: 0 auto 1.5rem;
  border-radius: 50%;
  font-family: var(--font-display);
  font-size: 1.05rem;
  color: var(--gold-light);
  background: var(--ink-800);
  border: 1px solid var(--line);
  transition: background var(--t), color var(--t), box-shadow var(--t), transform var(--t);
}
.timeline-card:hover .timeline-dot {
  background: var(--gold);
  color: var(--ink-900);
  transform: translateY(-4px);
  box-shadow: 0 12px 30px rgba(201, 162, 76, 0.38);
}
.timeline-card h4 { margin-bottom: 0.6rem; }
.timeline-card p { font-size: 0.9rem; }

/* ==========================================================================
   PROJECT CARDS
   One component. The projects index carries it as static markup; the home
   page renders the same shape from PROJECTS in app.js.
   ========================================================================== */
.project-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
  gap: 1.75rem;
}

.project-card {
  position: relative;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  border-radius: var(--r-lg);
  background: linear-gradient(165deg, rgba(255, 255, 255, 0.055), rgba(255, 255, 255, 0.015));
  border: 1px solid var(--glass-line);
  transition: transform var(--t), border-color var(--t), box-shadow var(--t);
}
.project-card:hover {
  transform: translateY(-6px);
  border-color: var(--line);
  box-shadow: var(--shadow-lg), var(--shadow-brass);
}
.project-shot {
  position: relative;
  display: block;
  overflow: hidden;
  aspect-ratio: 3 / 2;
}
.project-shot img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.9s var(--ease-out);
}

/* A settle rather than a zoom: past a few percent the crop visibly
   changes and the photograph stops being the subject. */
.project-card:hover .project-shot img { transform: scale(1.03); }

/* Gradient foot on the photo so the labels always sit on tone */
.project-shot::after {
  content: '';
  position: absolute;
  inset: auto 0 0 0;
  height: 55%;
  background: linear-gradient(180deg, transparent, rgba(8, 9, 11, 0.78));
  pointer-events: none;
}
.project-tag {
  position: absolute;
  top: 0.9rem;
  left: 0.9rem;
  z-index: 2;
  padding: 0.35rem 0.85rem;
  border-radius: var(--r-pill);
  font-size: 0.65rem;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--gold-bright);
  background: rgba(8, 9, 11, 0.7);
  border: 1px solid var(--line);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
}
.project-count {
  position: absolute;
  right: 0.9rem;
  bottom: 0.9rem;
  z-index: 2;
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.32rem 0.75rem;
  border-radius: var(--r-pill);
  font-size: 0.7rem;
  color: var(--ivory);
  background: rgba(8, 9, 11, 0.66);
  border: 1px solid var(--glass-line);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
}
.project-body {
  display: flex;
  flex-direction: column;
  flex: 1;
  padding: 1.5rem 1.6rem 1.6rem;
}
.project-name {
  font-size: 1.22rem;
  letter-spacing: 0.02em;
  margin-bottom: 0.45rem;
}
.project-meta {
  display: flex;
  align-items: center;
  gap: 0.45rem;
  font-size: 0.82rem;
  color: var(--gold);
  letter-spacing: 0.04em;
  margin-bottom: 0.9rem;
}


.project-specs {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  padding: 0.9rem 0;
  margin-bottom: 1.1rem;
  border-block: 1px solid var(--line-hair);
}


/* Smaller cards used in the "other projects" rail on the detail page */
.project-mini-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
  gap: 1rem;
}
.project-mini-grid a {
  display: block;
  border-radius: var(--r-md);
  overflow: hidden;
  border: 1px solid var(--line-hair);
  transition: border-color var(--t), transform var(--t);
}
.project-mini-grid a:hover { border-color: var(--line); transform: translateY(-4px); }
.project-mini-grid img { aspect-ratio: 3 / 2; object-fit: cover; width: 100%; }
.project-mini-grid span {
  display: block;
  padding: 0.7rem 0.9rem;
  font-size: 0.76rem;
  line-height: 1.55;
  letter-spacing: 0.05em;
  color: var(--gold);
}
.project-mini-grid strong {
  font-family: var(--font-display);
  font-size: 0.95rem;
  letter-spacing: 0.06em;
  color: var(--ivory);
}

/* Filter chips */
.homes-filters { display: flex; flex-wrap: wrap; gap: 0.6rem; }
.homes-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.55rem 1.15rem;
  border-radius: var(--r-pill);
  font-size: 0.76rem;
  font-weight: 500;
  letter-spacing: 0.1em;
  color: var(--ivory-dim);
  background: var(--glass);
  border: 1px solid var(--line-soft);
  transition: color var(--t-fast), border-color var(--t-fast), background var(--t-fast), transform var(--t-fast);
}
.homes-chip:hover, .homes-chip.is-active {
  color: var(--gold-bright);
  border-color: var(--line);
  background: rgba(201, 162, 76, 0.12);
  transform: translateY(-2px);
}
.homes-chip span { color: var(--ivory-faint); font-size: 0.7rem; }

/* ==========================================================================
   CLOSING CTA
   ========================================================================== */
.cta-section {
  position: relative;
  padding: clamp(5rem, 11vw, 9rem) var(--gutter);
  text-align: center;
  overflow: hidden;
  isolation: isolate;
}
.cta-bg { position: absolute; inset: 0; z-index: -2; }
.cta-bg img { width: 100%; height: 100%; object-fit: cover; }
.cta-section::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background:
    linear-gradient(180deg, var(--ink-900) 0%, rgba(8, 9, 11, 0.72) 45%, var(--ink-900) 100%),
    radial-gradient(70% 70% at 50% 50%, rgba(201, 162, 76, 0.16), transparent 70%);
}
.cta-content { max-width: 760px; margin-inline: auto; }
.cta-content .section-label { justify-content: center; }
.cta-content h2 { margin-bottom: var(--space-4); }
.cta-content p { margin-bottom: var(--space-6); margin-inline: auto; font-size: 1.02rem; }
.cta-content .cta-actions { margin-inline: auto; }

/* About-page CTA panel */
.about-cta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 2rem;
  padding: clamp(1.75rem, 4vw, 2.75rem);
  border-radius: var(--r-xl);
  background: radial-gradient(110% 130% at 100% 0%, rgba(201, 162, 76, 0.14), transparent 60%), var(--ink-800);
  border: 1px solid var(--line);
}
.about-cta-title { margin-bottom: 0.6rem; }
.about-cta-actions { display: flex; flex-wrap: wrap; gap: 0.85rem; }

/* ==========================================================================
   FOOTER
   ========================================================================== */
.footer, .main-footer {
  padding: clamp(3.5rem, 7vw, 5.5rem) 0 0;
  background: var(--ink-850);
  border-top: 1px solid var(--line-hair);
}
.footer-grid {
  display: grid;
  grid-template-columns: 1.6fr repeat(3, 1fr);
  gap: clamp(2rem, 4vw, 3.5rem);
  padding-bottom: 3rem;
}
.footer-brand .brand-logo {
  display: inline-flex;
  align-items: center;
  gap: 0.85rem;
  margin-bottom: 1.15rem;
}
.footer-logo-img { width: 190px; height: auto; margin-bottom: 1.15rem; }
.footer-brand h3 {
  font-size: 1.25rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  margin-bottom: 0.75rem;
}
.footer-brand p { font-size: 0.9rem; max-width: 42ch; }
.footer-col h4 {
  position: relative;
  font-family: var(--font-sans);
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ivory);
  margin-bottom: 1.5rem;
  padding-bottom: 0.7rem;
}
.footer-col h4::after {
  content: '';
  position: absolute;
  left: 0;
  bottom: 0;
  width: 32px;
  height: 1px;
  background: var(--gold);
}
.footer-links { display: flex; flex-direction: column; gap: 0.7rem; }
.footer-links a, .footer-links span { font-size: 0.88rem; color: var(--ivory-dim); }
.footer-links a:hover { color: var(--gold-light); padding-left: 5px; }
.footer-links a { transition: color var(--t-fast), padding-left var(--t-fast); }

.footer-social { display: flex; gap: 0.65rem; margin-top: 1.5rem; }
.footer-social a {
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  color: var(--ivory-dim);
  border: 1px solid var(--line-soft);
  transition: color var(--t), border-color var(--t), background var(--t), transform var(--t);
}
.footer-social a:hover {
  color: var(--gold-bright);
  border-color: var(--line);
  background: rgba(201, 162, 76, 0.11);
  transform: translateY(-3px);
}

.footer-bottom {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 1.6rem 0;
  border-top: 1px solid var(--line-hair);
  font-size: 0.8rem;
  color: var(--ivory-faint);
}


/* Sticky mobile action bar on the contact page */


/* ==========================================================================
   PROJECT DETAIL
   ========================================================================== */
.detail-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 370px;
  gap: clamp(2rem, 4vw, 3.25rem);
  align-items: start;
}

.gallery-main {
  position: relative;
  border-radius: var(--r-lg);
  overflow: hidden;
  background: var(--ink-800);
  border: 1px solid var(--line-soft);
  aspect-ratio: 3 / 2;
}
.gallery-main img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: opacity 0.35s var(--ease), transform 0.9s var(--ease-out);
}


.gallery-nav {
  position: absolute;
  top: 50%;
  z-index: 2;
  display: grid;
  place-items: center;
  width: 46px;
  height: 46px;
  transform: translateY(-50%);
  border-radius: 50%;
  font-size: 1.15rem;
  color: var(--ivory);
  background: rgba(8, 9, 11, 0.62);
  border: 1px solid var(--glass-line);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  transition: background var(--t-fast), color var(--t-fast), transform var(--t-fast);
}
.gallery-nav:hover { background: var(--gold); color: var(--ink-900); }
.gallery-nav--prev { left: 0.9rem; }
.gallery-nav--next { right: 0.9rem; }
.gallery-nav--prev:hover { transform: translateY(-50%) translateX(-3px); }
.gallery-nav--next:hover { transform: translateY(-50%) translateX(3px); }


.gallery-counter {
  position: absolute;
  right: 0.9rem;
  bottom: 0.9rem;
  z-index: 2;
  padding: 0.35rem 0.85rem;
  border-radius: var(--r-pill);
  font-size: 0.74rem;
  letter-spacing: 0.08em;
  color: var(--ivory);
  background: rgba(8, 9, 11, 0.66);
  border: 1px solid var(--glass-line);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
}

.gallery-thumbs {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(88px, 1fr));
  gap: 0.6rem;
  margin-top: 0.85rem;
}
.gallery-thumbs--strip {
  display: flex;
  overflow-x: auto;
  scrollbar-width: thin;
  padding-bottom: 0.5rem;
}
.gallery-thumbs--strip .gallery-thumb { flex: 0 0 96px; }
.gallery-thumb {
  border-radius: var(--r-sm);
  overflow: hidden;
  cursor: pointer;
  opacity: 0.5;
  border: 1px solid transparent;
  transition: opacity var(--t-fast), border-color var(--t-fast), transform var(--t-fast);
}
.gallery-thumb:hover { opacity: 0.85; transform: translateY(-2px); }
.gallery-thumb.active { opacity: 1; border-color: var(--gold); }
.gallery-thumb img { width: 100%; aspect-ratio: 3 / 2; object-fit: cover; }

.detail-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1rem;
  margin: 2.25rem 0 0.6rem;
}
.detail-status {
  padding: 0.35rem 0.9rem;
  border-radius: var(--r-pill);
  font-size: 0.66rem;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--sage);
  background: rgba(134, 151, 122, 0.12);
  border: 1px solid rgba(134, 151, 122, 0.32);
}
.detail-location {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.95rem;
  color: var(--ivory-dim);
  margin-bottom: 2rem;
}
.detail-location i { color: var(--gold); }

.detail-specs-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 0.85rem;
  margin-bottom: 2.75rem;
}
.spec-box {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  padding: 1rem 1.15rem;
  border-radius: var(--r-md);
  background: rgba(255, 255, 255, 0.035);
  border: 1px solid var(--line-hair);
  transition: border-color var(--t), background var(--t);
}
.spec-box:hover { border-color: var(--line); background: rgba(201, 162, 76, 0.06); }
.spec-box-label {
  font-size: 0.66rem;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--gold);
}
.spec-box-value { font-size: 0.98rem; color: var(--ivory); }

.detail-block { margin-bottom: 2.75rem; }
.detail-block h3 {
  padding-bottom: 0.85rem;
  margin-bottom: 1.35rem;
  border-bottom: 1px solid var(--line-hair);
}
.detail-block > p { margin-bottom: 1.25rem; }

.plan-summary {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: 0.75rem;
  margin: 1.5rem 0;
}
.plan-summary > div {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.75rem 1rem;
  border-radius: var(--r-sm);
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid var(--line-hair);
}
.plan-summary dt { font-size: 0.82rem; color: var(--ivory-faint); }
.plan-summary dd { font-size: 0.88rem; color: var(--ivory); font-variant-numeric: tabular-nums; }

.detail-note {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.84rem;
  color: var(--ivory-faint);
}
.detail-note i { color: var(--gold); }

.amenity-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(255px, 1fr));
  gap: 0.65rem 1.5rem;
}
.amenity-grid > span, .amenity-grid > li {
  position: relative;
  display: block;
  padding-left: 1.6rem;
  font-size: 0.92rem;
  color: var(--ivory-dim);
}
.amenity-grid > span::before, .amenity-grid > li::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0.72em;
  width: 7px;
  height: 7px;
  border-radius: 2px;
  transform: rotate(45deg);
  background: var(--gold);
}

.plan-sheet {
  display: block;
  position: relative;
  border-radius: var(--r-lg);
  overflow: hidden;
  background: #f6f4ef;
  border: 1px solid var(--line-soft);
  transition: border-color var(--t), transform var(--t);
}
.plan-sheet:hover { border-color: var(--gold); transform: translateY(-3px); }
/* The plan sheet loads lazily and its dimensions are not known until it
   arrives, so the box reserves its own height. Without this the block below
   jumps when the sheet lands. */
.plan-sheet img { width: 100%; aspect-ratio: 4 / 3; object-fit: contain; }
.plan-sheet-hint {
  position: absolute;
  right: 0.9rem;
  bottom: 0.9rem;
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.4rem 0.9rem;
  border-radius: var(--r-pill);
  font-size: 0.72rem;
  color: var(--ivory);
  background: rgba(8, 9, 11, 0.75);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
}

/* --- Sticky enquiry card --- */
.sticky-contact-card {
  position: sticky;
  top: calc(var(--nav-h) + 1.25rem);
  padding: 1.75rem;
  border-radius: var(--r-lg);
  background: linear-gradient(160deg, rgba(255, 255, 255, 0.06), rgba(255, 255, 255, 0.018));
  border: 1px solid var(--glass-line);
  backdrop-filter: blur(var(--blur));
  -webkit-backdrop-filter: blur(var(--blur));
  box-shadow: var(--shadow-md);
}


.enquiry-lede { font-size: 0.88rem; margin-bottom: 1.35rem; }


/* ==========================================================================
   HOMES GALLERY
   ========================================================================== */
.homes-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding-bottom: 1.5rem;
  margin-bottom: 2rem;
  border-bottom: 1px solid var(--line-hair);
}
.homes-count { font-size: 0.82rem; letter-spacing: 0.1em; color: var(--ivory-faint); }

.homes-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
  grid-auto-rows: 210px;
  gap: 0.85rem;
}
.homes-tile {
  position: relative;
  display: block;
  border-radius: var(--r-md);
  overflow: hidden;
  cursor: zoom-in;
  border: 1px solid var(--line-hair);
  transition: border-color var(--t), transform var(--t), box-shadow var(--t);
}
.homes-tile:hover { border-color: var(--line); transform: translateY(-4px); box-shadow: var(--shadow-md); }
.homes-tile.is-wide { grid-column: span 2; }
.homes-tile img { width: 100%; height: 100%; object-fit: cover; transition: transform 0.9s var(--ease-out); }
.homes-tile:hover img { transform: scale(1.07); }
.homes-tile-cap {
  position: absolute;
  inset: auto 0 0 0;
  padding: 1.4rem 1rem 0.85rem;
  font-size: 0.78rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ivory);
  background: linear-gradient(180deg, transparent, rgba(8, 9, 11, 0.85));
  opacity: 0;
  transform: translateY(8px);
  transition: opacity var(--t), transform var(--t);
}
.homes-tile:hover .homes-tile-cap { opacity: 1; transform: none; }

/* ==========================================================================
   LIGHTBOX VIEWER
   ========================================================================== */
.viewer {
  position: fixed;
  inset: 0;
  z-index: 1200;
  display: flex;
  flex-direction: column;
  background: rgba(5, 6, 8, 0.96);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--t), visibility var(--t);
}
.viewer.active{ opacity: 1; visibility: visible; }

.viewer-bar {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: 1rem clamp(1rem, 3vw, 2rem);
  border-bottom: 1px solid var(--line-hair);
}
.viewer-title { font-family: var(--font-display); font-size: 1.05rem; letter-spacing: 0.06em; }
.viewer-counter { font-size: 0.8rem; color: var(--ivory-faint); font-variant-numeric: tabular-nums; }
.viewer-link {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  font-size: 0.76rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--gold-light);
}
.viewer-close {
  display: grid;
  place-items: center;
  width: 42px;
  height: 42px;
  border-radius: 50%;
  font-size: 1.15rem;
  color: var(--ivory-dim);
  border: 1px solid var(--line-soft);
  transition: color var(--t), border-color var(--t), transform var(--t);
}
.viewer-close:hover { color: var(--gold-light); border-color: var(--line); transform: rotate(90deg); }

.viewer-stage {
  position: relative;
  flex: 1;
  display: grid;
  place-items: center;
  min-height: 0;
  padding: clamp(1rem, 3vw, 2.5rem);
}
.viewer-img {
  max-width: 100%;
  max-height: 100%;
  width: auto;
  height: auto;
  object-fit: contain;
  border-radius: var(--r-sm);
  box-shadow: var(--shadow-lg);
}
.viewer-nav {
  position: absolute;
  top: 50%;
  display: grid;
  place-items: center;
  width: 52px;
  height: 52px;
  transform: translateY(-50%);
  border-radius: 50%;
  font-size: 1.25rem;
  color: var(--ivory);
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid var(--glass-line);
  transition: background var(--t-fast), color var(--t-fast);
}
.viewer-nav:hover { background: var(--gold); color: var(--ink-900); }
.viewer-nav--prev { left: clamp(0.75rem, 2vw, 1.75rem); }
.viewer-nav--next { right: clamp(0.75rem, 2vw, 1.75rem); }

/* ==========================================================================
   FORMS
   ========================================================================== */
.form-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: 1.15rem;
}
.form-group { display: flex; flex-direction: column; gap: 0.45rem; margin-bottom: 1.15rem; }
.form-group.full-width { grid-column: 1 / -1; }
.form-label {
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ivory-dim);
}
.form-control {
  width: 100%;
  padding: 0.85rem 1.1rem;
  border-radius: var(--r-sm);
  font-size: 0.94rem;
  color: var(--ivory);
  background: rgba(255, 255, 255, 0.035);
  border: 1px solid var(--line-soft);
  outline: none;
  transition: border-color var(--t-fast), background var(--t-fast), box-shadow var(--t-fast);
}
.form-control::placeholder { color: var(--ivory-faint); }
.form-control:focus {
  border-color: var(--gold);
  background: rgba(201, 162, 76, 0.06);
  box-shadow: 0 0 0 3px var(--gold-veil);
}
textarea.form-control { min-height: 130px; resize: vertical; }
select.form-control {
  appearance: none;
  cursor: pointer;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8' fill='none' stroke='%23c9a24c' stroke-width='1.8'%3E%3Cpath d='M1 1.5L6 6.5L11 1.5'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 1.1rem center;
  padding-right: 2.5rem;
}
select.form-control option { background: var(--ink-800); color: var(--ivory); }

.form-hint { font-size: 0.76rem; color: var(--ivory-faint); }
.form-status {
  margin-top: 0.9rem;
  font-size: 0.85rem;
  color: var(--sage);
  min-height: 1.2em;
}


/* ==========================================================================
   CONTACT
   ========================================================================== */
.contact-methods {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  gap: 1.15rem;
  margin-bottom: 3rem;
}
.contact-method {
  position: relative;
  display: grid;
  /* The icon column went with the icon. `minmax(0, …)` on the text column is
     what stops a long address — enquiries@tasmonthomes.com.au is wider than
     a 320px screen — from forcing the grid past the viewport. */
  grid-template-columns: minmax(0, 1fr) auto;
  grid-template-areas:
    'label go'
    'value go'
    'note go';
  align-items: center;
  gap: 0.1rem 1.1rem;
  padding: 1.35rem 1.5rem;
  border-radius: var(--r-lg);
  background: linear-gradient(160deg, rgba(255, 255, 255, 0.055), rgba(255, 255, 255, 0.015));
  border: 1px solid var(--glass-line);
  transition: transform var(--t), border-color var(--t), box-shadow var(--t);
}
.contact-method:hover { transform: translateY(-5px); border-color: var(--line); box-shadow: var(--shadow-md); }


.contact-method-value { overflow-wrap: anywhere; }

.contact-method-label {
  grid-area: label;
  font-size: 0.66rem;
  font-weight: 500;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--gold);
}
.contact-method-value { grid-area: value; font-size: 1rem; color: var(--ivory); }
.contact-method-note { grid-area: note; font-size: 0.76rem; color: var(--ivory-faint); }
.contact-method-go { grid-area: go; color: var(--ivory-faint); transition: color var(--t), transform var(--t); }
.contact-method:hover .contact-method-go { color: var(--gold-light); transform: translate(3px, -3px); }

.contact-layout {
  display: grid;
  grid-template-columns: minmax(0, 1.5fr) minmax(0, 1fr);
  gap: clamp(1.75rem, 4vw, 3rem);
  align-items: start;
}
.contact-panel {
  padding: clamp(1.75rem, 4vw, 2.75rem);
  border-radius: var(--r-xl);
  background: linear-gradient(160deg, rgba(255, 255, 255, 0.055), rgba(255, 255, 255, 0.015));
  border: 1px solid var(--glass-line);
}
.contact-panel .section-title { text-align: left; }
.contact-panel .section-desc { margin: 0 0 2rem; text-align: left; }

.contact-rail { display: flex; flex-direction: column; gap: 1.15rem; }
.contact-card {
  padding: 1.6rem;
  border-radius: var(--r-lg);
  background: var(--ink-800);
  border: 1px solid var(--line-hair);
}
.contact-card-title {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  font-size: 1.05rem;
  margin-bottom: 1.15rem;
  padding-bottom: 0.85rem;
  border-bottom: 1px solid var(--line-hair);
}
.contact-card-title i { color: var(--gold); }

.contact-hours { display: flex; flex-direction: column; gap: 0.6rem; }
.contact-hours > div { display: flex; align-items: baseline; justify-content: space-between; gap: 1rem; }
.contact-hours dt { font-size: 0.86rem; color: var(--ivory-dim); }
.contact-hours dd { font-size: 0.86rem; color: var(--ivory); font-variant-numeric: tabular-nums; }

/* The steps carry their own numbers in the markup, so style those rather
   than generating a second set with a counter. */
.contact-next { display: flex; flex-direction: column; gap: 0.9rem; }
.contact-next li {
  position: relative;
  padding-left: 2.25rem;
  font-size: 0.89rem;
  color: var(--ivory-dim);
}
.contact-next li > span {
  position: absolute;
  left: 0;
  top: 0.05em;
  display: grid;
  place-items: center;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  font-family: var(--font-display);
  font-size: 0.82rem;
  color: var(--gold);
  background: rgba(201, 162, 76, 0.1);
  border: 1px solid var(--line);
}

.contact-map {
  margin-top: 3rem;
  border-radius: var(--r-lg);
  overflow: hidden;
  border: 1px solid var(--line-soft);
  filter: grayscale(1) invert(0.9) contrast(0.85) hue-rotate(180deg);
  opacity: 0.85;
  transition: filter var(--t), opacity var(--t);
}
.contact-map:hover { opacity: 1; }
.contact-map iframe { display: block; width: 100%; height: 380px; border: 0; }

/* ==========================================================================
   LEGACY TOKEN ALIASES
   Older markup still references the previous variable names inline; map them
   onto the current palette so nothing falls back to an unstyled default.
   ========================================================================== */
:root {
  --color-bg: var(--ink-900);
  --color-bg-alt: var(--ink-850);
  --color-bg-card: var(--ink-800);
  --color-surface: var(--ink-800);
  --color-surface-hover: var(--ink-700);
  --color-gold: var(--gold);
  --color-gold-light: var(--gold-light);
  --color-gold-dark: var(--gold-deep);
  --color-gold-glow: var(--gold-glow);
  --color-gold-subtle: var(--gold-veil);
  --color-text: var(--ivory);
  --color-text-muted: var(--ivory-dim);
  --color-text-dim: var(--ivory-faint);
  --color-white: #ffffff;
  --color-border: var(--line);
  --color-border-light: var(--line-soft);
  --glass-bg: var(--glass);
  --glass-bg-card: var(--glass);
  --glass-bg-strong: var(--glass-strong);
  --glass-border: var(--glass-line);
  --glass-border-gold: var(--line);
  --glass-blur: var(--blur);
  --font-heading: var(--font-display);
  --font-body: var(--font-sans);
  --shadow-gold: var(--shadow-brass);
  --shadow-card: var(--shadow-md);
  --shadow-card-hover: var(--shadow-lg);
  --transition-fast: var(--t-fast);
  --transition-base: var(--t);
  --transition-slow: var(--t-slow);
  --radius-sm: var(--r-sm);
  --radius-md: var(--r-md);
  --radius-lg: var(--r-lg);
  --radius-xl: var(--r-xl);
  --radius-full: var(--r-pill);
  --max-width: var(--wrap);
  --max-width-lg: var(--wrap-lg);
}

/* ==========================================================================
   RESPONSIVE
   ========================================================================== */
@media (max-width: 1180px) {
  /* minmax(0, 1fr), not 1fr — the desktop rule uses it for the same reason.
     A bare 1fr track cannot shrink below its content's min-content width, and
     the thumbnail strip's min-content is every thumbnail laid end to end, so
     the column stretched to ~2,400px and the whole page scrolled sideways on
     every tablet and phone. */
  .detail-layout { grid-template-columns: minmax(0, 1fr); }
  .sticky-contact-card { position: static; }
  .footer-grid { grid-template-columns: 1fr 1fr; }
}

@media (max-width: 1024px) {
  :root { --nav-h: 74px; }

  .story-split,
  .contact-layout { grid-template-columns: 1fr; }


  .timeline-grid::before { display: none; }
}

/* --- Mobile drawer --- */
@media (max-width: 980px) {
  /* The drawer is a sibling that paints at z-index 950, and it slides in over
     the right edge of the header — exactly where this button sits. Without a
     stacking position of its own the burger ends up buried under the panel,
     so the X state is never visible and there is nothing left to tap to
     close. Lift it above the drawer. */
  .nav-toggle {
    display: flex;
    position: relative;
    z-index: 960;
  }
.navbar-links {
    position: fixed;
    inset: 0 0 0 auto;
    z-index: 950;
    width: min(340px, 84vw);
    margin: 0;
    padding: calc(var(--nav-h) + 2rem) 2rem 2rem;
    flex-direction: column;
    align-items: flex-start;
    gap: 0.35rem;
    background: rgba(11, 13, 16, 0.97);
    backdrop-filter: blur(24px);
    -webkit-backdrop-filter: blur(24px);
    border-left: 1px solid var(--line-soft);
    box-shadow: -30px 0 70px rgba(0, 0, 0, 0.6);
    transform: translateX(100%);
    visibility: hidden;
    transition: transform 0.45s var(--ease-out), visibility 0.45s;
  }
.navbar-links.active { transform: none; visibility: visible; }
.nav-item {
    width: 100%;
    padding: 0.95rem 0;
    font-size: 0.88rem;
    border-bottom: 1px solid var(--line-hair);
  }
.nav-item::after { display: none; }

  .nav-cta { display: none; }

  .stats-grid { grid-template-columns: 1fr 1fr; gap: 2rem 1rem; }
  .stat-item:nth-child(2)::after { display: none; }

  .contact-panel .section-title,
  .section-header { text-align: left; }
  .section-header { margin-inline: 0; }
  .section-header .section-label, .section-header .eyebrow { justify-content: flex-start; }
  .section-header .section-label::after, .section-header .eyebrow::after { display: none; }
  .section-desc { margin-inline: 0; }

  body { padding-bottom: 0; }
  .main-footer, .footer { padding-bottom: 4.5rem; }
}

@media (max-width: 768px) {
  /* The hero carries its own stacked layout — see the HERO block. */
  .footer-grid { grid-template-columns: 1fr; }
  .footer-bottom { flex-direction: column; align-items: flex-start; }

  /* Keep the four value cards in a compact 2x2 layout on mobile. */
  .value-cards-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0.75rem;
  }
  .value-card { padding: 1.35rem 1rem 1.25rem; }


  .value-card h4 { font-size: 1rem; line-height: 1.2; }
  .value-card p { font-size: 0.82rem; line-height: 1.55; }

  /* Picture grids go two-up on a phone rather than one long column. */
.project-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 1rem;
  }
  .project-mini-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0.85rem;
  }
  .homes-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    grid-auto-rows: 170px;
    gap: 0.6rem;
  }
  /* Every seventh tile runs the full width. At two columns that packs without
     a hole — one wide, six in three pairs, wide again — so the wall keeps its
     rhythm instead of going uniform. */
  .homes-tile.is-wide { grid-column: span 2; }

  .about-cta { flex-direction: column; align-items: flex-start; }


  .gallery-thumbs { grid-template-columns: repeat(auto-fill, minmax(70px, 1fr)); }
  .contact-map iframe { height: 300px; }
}

/* --- Two-up picture cards on a phone ---
   At two columns a card is roughly 160px wide, which cannot hold everything
   the desktop card carries without wrapping into a tall, cramped strip. Each
   card keeps what identifies the home — the photograph, its name, where it
   is, the headline specs and the way in — and sheds the design label over the
   photo, the summary paragraph and the "Custom Build" tag. All three are
   repeated on the detail page the card leads to. */
@media (max-width: 600px) {
.project-grid { gap: 0.75rem; }

  /* Photo overlays */
  .project-grid .project-tag {
    top: 0.5rem;
    left: 0.5rem;
    padding: 0.2rem 0.5rem;
    font-size: 0.52rem;
    letter-spacing: 0.12em;
  }
.project-count {
    right: 0.5rem;
    bottom: 0.5rem;
    gap: 0.25rem;
    padding: 0.2rem 0.5rem;
    font-size: 0.6rem;
  }


  /* Body */
.project-body { padding: 0.85rem 0.8rem 0.95rem; }
.project-name {
    font-size: 0.94rem;
    line-height: 1.2;
    letter-spacing: 0.01em;
    margin-bottom: 0.3rem;
  }

  .project-grid .project-meta { font-size: 0.66rem; line-height: 1.4; margin-bottom: 0.7rem; }


  .project-specs {
    gap: 0.3rem 0.65rem;
    padding: 0.55rem 0;
    margin-bottom: 0.7rem;
  }


  /* At this size the link text is too small to aim at, and it is the card's
     only way in — so its hit area is stretched over the whole card, and a tap
     anywhere on the photograph opens the build. */

  /* Two buttons will not sit side by side in 160px. Stacked, each keeps a
     full-width tap target. */


  /* Detail page: other projects */
  .project-mini-grid span { padding: 0.55rem 0.65rem; font-size: 0.64rem; line-height: 1.45; }
  .project-mini-grid strong { font-size: 0.8rem; }

  /* Homes wall */
  .homes-grid { grid-auto-rows: 140px; }
  .homes-tile-cap { padding: 1rem 0.6rem 0.55rem; font-size: 0.6rem; letter-spacing: 0.06em; }
}

@media (max-width: 520px) {
  /* At 320px the brand plus the menu button ran 11px past the viewport and
     pushed the whole page sideways. The wrapper's 1.5rem gap is the slack
     that buys it back, and the brand is allowed to shrink rather than
     forcing the row wider than the screen. */
  .nav-wrapper { gap: 0.6rem; }
  .brand-logo { min-width: 0; gap: 0.55rem; }
  .brand-name { font-size: 1.02rem; }
  .brand-mark { width: 60px; height: 35px; flex-shrink: 0; }

  .stats-grid { grid-template-columns: 1fr; }
  .stat-item::after { display: none !important; }

  .detail-specs-grid { grid-template-columns: 1fr 1fr; }

  .btn { --btn-pad: 0.85rem 1.5rem; font-size: 0.75rem; }
}

@media (max-width: 360px) {
  .brand-mark { width: 48px; height: 28px; }
  .brand-name { font-size: 0.92rem; }
}

/* --- Print --- */
@media print {
.main-header, .hero-scroll, .hero-seam, .footer, .main-footer, .nav-toggle{ display: none !important; }
  body { background: #fff; color: #111; }
  body::before { display: none; }
}

/* ==========================================================================
   SCROLL CHOREOGRAPHY
   Starting states for the engine in app.js §10. Three rules hold across the
   whole block:

   1. Nothing is hidden unless something can bring it back. Every start state
      is gated on `.fx` — set by the inline head script, so it is only ever
      present when scripting is alive — and qualified with
      `:not([data-fx-done])`, the attribute the engine writes the moment an
      element has finished (or has been waved through). A failsafe in app.js
      stamps that attribute on everything if the engine ever fails to report.
   2. The selector inventory below is mirrored verbatim by FX_GROUPS and
      FX_ITEMS in app.js. Add to one, add to the other.
   3. Only `opacity` and `transform` are ever animated, and the engine writes
      both inline, so a reveal costs a composite and never a reflow. When an
      element finishes the engine clears its inline styles rather than pinning
      them, which is what lets the hover states underneath (a project card's
      lift, an award item's 0.72 resting opacity) survive intact.
   ========================================================================== */

/* The engine owns the scroll position while smooth scrolling is running, so
   the browser's own smooth behaviour has to stand down — otherwise the two
   animate the same value against each other and the result stutters. */
html.fx-smooth { scroll-behavior: auto; }

/* --- Start states --- */

/* Promoted only while an element is actually mid-reveal. Leaving will-change
   on permanently would hold a compositor layer for every card on the page. */
[data-fx-live] { will-change: transform, opacity; }

/* Nested copy is hidden only once the engine has registered it. Text remains
   a whole semantic block, including its inline emphasis and links. */
.fx [data-fx="text"]:not([data-fx-done]) { opacity: 0; }
.fx [data-fx-inline] { display: inline-block; }

/* --- Parallax headroom ---
   The two full-bleed plates are `inset: 0`, which leaves nothing to drift
   into. Both are absolutely positioned, so over-extending them costs no
   layout; `bottom` is simply ignored once `top` and `height` are set. */
.fx .cta-bg { inset: -11% 0; }
.fx .page-hero-bg { top: -11%; height: 122%; }

/* --- Reduced motion ---
   The engine keeps running but drops to opacity alone: no travel, no scale,
   no parallax, no scroll hijack. Content still arrives rather than snapping,
   which reads as calm instead of inert. */
.fx-reduced [data-fx] { transition: opacity 0.45s linear; }

@media (prefers-reduced-motion: reduce) {
  .fx [data-fx="text"] {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
  }

  .fx .cta-bg { inset: 0; }
  .fx .page-hero-bg { top: 0; height: 100%; }
}

/* Paper has no scroll position, so nothing may be part-way through a reveal. */
@media print {
  .fx [data-fx="text"] {
    opacity: 1 !important;
    transform: none !important;
  }

}

/* ==========================================================================
   COMPONENTS ADDED IN THE REFINEMENT PASS
   New markup introduced when the six pages were brought onto one header,
   one footer and one card. Sits after the sections above so it can settle
   a few inherited rules without raising specificity.
   ========================================================================== */

/* --- Skip link ------------------------------------------------------------
   First thing in the tab order on every page, and the only way a keyboard
   user gets past the navigation without walking it on each page. */
.skip-link {
  position: absolute;
  top: 0;
  left: 50%;
  z-index: 200;
  transform: translate(-50%, -120%);
  padding: 0.75rem 1.5rem;
  border-radius: 0 0 var(--r-sm) var(--r-sm);
  background: var(--gold);
  color: var(--ink-900);
  font-size: 0.8rem;
  font-weight: 500;
  letter-spacing: 0.04em;
  transition: transform var(--t-fast);
}
.skip-link:focus-visible { transform: translate(-50%, 0); }

/* Body lock while the mobile drawer is open. A class rather than an inline
   style so the state is visible in the DOM and cannot be half-cleared. */
body.nav-open { overflow: hidden; }

/* --- Editorial lead -------------------------------------------------------
   Opens a page with one statement set large, so the site does not begin
   every section with the same eyebrow-heading-cards shape. */
.lead-statement {
  font-family: var(--font-display);
  font-size: clamp(1.3rem, 2.4vw, 1.9rem);
  line-height: 1.5;
  letter-spacing: -0.012em;
  color: var(--ivory);
  max-width: 34ch;
  text-wrap: pretty;
}

/* --- Section furniture ---------------------------------------------------- */
.section-header--left {
  max-width: 44ch;
  margin-inline: 0;
  text-align: left;
}
.section-header--left .eyebrow,
.section-header--left .section-label { justify-content: flex-start; }
.section-header--left .eyebrow::after,
.section-header--left .section-label::after { display: none; }
.section-header--left .section-desc { margin-inline: 0; }

.section-foot {
  display: flex;
  justify-content: center;
  margin-top: clamp(2.5rem, 5vw, 3.5rem);
}

/* A hairline band, used where a section needs separating without a fill. */
.band-rule { border-block: 1px solid var(--line-hair); }

.cta-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  justify-content: center;
}

/* --- Project card --------------------------------------------------------- */
.project-link {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  margin-top: auto;
  padding-top: var(--space-3);
  font-size: 0.78rem;
  font-weight: 500;
  letter-spacing: 0.06em;
  color: var(--gold-light);
}
.project-link span { transition: transform var(--t); }
.project-card:hover .project-link { color: var(--gold-bright); }
.project-card:hover .project-link span { transform: translateX(4px); }

/* The specs line is one sentence now, not a row of icon chips. */
.project-specs {
  display: block;
  padding: var(--space-3) 0 0;
  margin: 0;
  border-block: 0;
  border-top: 1px solid var(--line-hair);
  font-size: 0.82rem;
  color: var(--ivory-dim);
}

/* --- Credentials ----------------------------------------------------------
   Only rendered when SITE.credentials holds something the business can
   evidence; the band removes itself while that list is empty. */
.credentials-strip {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--space-5) var(--space-8);
}
.credential {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  text-align: center;
}
.credential-label {
  font-size: 0.78rem;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ivory);
}
.credential-detail { font-size: 0.78rem; color: var(--ivory-faint); }

/* --- Testimonials --------------------------------------------------------- */
.testimonial-list {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: var(--space-5);
}
.testimonial {
  padding: var(--space-6);
  border: 1px solid var(--line-hair);
  border-radius: var(--r-lg);
  background: var(--ink-850);
}
.testimonial blockquote {
  font-family: var(--font-display);
  font-size: 1.1rem;
  line-height: 1.6;
  color: var(--ivory);
}
.testimonial figcaption {
  margin-top: var(--space-4);
  font-size: 0.8rem;
  color: var(--gold-light);
}
.testimonial figcaption span {
  display: block;
  color: var(--ivory-faint);
}

/* --- Footer --------------------------------------------------------------- */
.footer-heading {
  margin-bottom: 1.15rem;
  font-family: var(--font-sans);
  font-size: 0.74rem;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ivory);
}

/* --- Project detail ------------------------------------------------------- */
.detail-main { min-width: 0; }

.detail-address {
  margin-top: 0.35rem;
  font-size: 0.88rem;
  color: var(--ivory-faint);
}

.detail-lede {
  font-size: 1.02rem;
  line-height: 1.75;
  color: var(--ivory-dim);
  max-width: 68ch;
}

.detail-missing {
  max-width: 48ch;
  margin-inline: auto;
  padding: var(--space-10) 0;
  text-align: center;
}
.detail-missing p { margin: var(--space-4) 0 var(--space-6); color: var(--ivory-dim); }

.enquiry-title {
  font-size: 1.15rem;
  margin-bottom: 0.4rem;
}
.enquiry-alt {
  margin-top: var(--space-4);
  font-size: 0.82rem;
  color: var(--ivory-faint);
}
.enquiry-alt a { color: var(--gold-light); }
.enquiry-alt a:hover { color: var(--gold-bright); }

/* --- Forms ---------------------------------------------------------------- */
.form-optional {
  font-weight: 400;
  letter-spacing: 0.04em;
  text-transform: none;
  color: var(--ivory-faint);
}

/* Spam trap. Removed from the layout and from the tab order, but not with
   `display: none`, which some bots read as a signal to skip the field. */
.form-trap {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
.form-trap input { width: 1px; }

.form-control.is-invalid {
  border-color: #c2695c;
  background: rgba(194, 105, 92, 0.07);
}
.form-control.is-invalid:focus {
  border-color: #d88274;
  box-shadow: 0 0 0 1px rgba(216, 130, 116, 0.4);
}

.form-status {
  margin-top: var(--space-4);
  font-size: 0.86rem;
  line-height: 1.6;
}
.form-status.is-ok { color: var(--sage); }
.form-status.is-error { color: #d88274; }

/* --- Story split ---------------------------------------------------------- */
/* Alternates the image to the other side, so two splits on one page do not
   read as the same section twice. */
.story-split--reverse .story-image-wrap { order: 2; }

@media (max-width: 900px) {
  .story-split--reverse .story-image-wrap { order: 0; }
}

/* --- Contact -------------------------------------------------------------- */
.contact-card-text {
  font-size: 0.88rem;
  line-height: 1.7;
  color: var(--ivory-dim);
}

/* --- Page hero ------------------------------------------------------------ */
.page-hero-eyebrow { margin-bottom: 1rem; }

/* ==========================================================================
   MOTION PRIMITIVES
   A small set of entrance behaviours the scrubbed engine above does not
   cover: type revealed from behind a mask, photography wiped open, hairlines
   drawn on. Each one is declarative — the markup carries `data-motion`, the
   observer in app.js adds `.is-in` once, and the transition below does the
   work. No frame loop, no library.

   Two rules hold throughout, the same two the scroll engine works to:

   1. A start state is gated on `.fx`, which the head script only sets when
      scripting is alive. With JavaScript off nothing is hidden, so nothing
      can be stranded.
   2. Only transform, opacity and clip-path are animated. The one exception
      is the eyebrow's letter-spacing, which is a layout property — it is
      allowed because the element is a handful of small-caps characters and
      the tracking settling in is the whole effect.
   ========================================================================== */

/* --- Masked line reveal ---------------------------------------------------
   Headings arrive from behind their own baseline rather than fading upward.
   The mask is a block wrapper with overflow hidden; the inner span starts one
   line-height down and slides to nothing. Lines are measured at runtime, so
   the stagger follows however the type actually breaks at this width. */
.ln {
  display: block;
  overflow: hidden;
  /* The descender of a serif cap would otherwise be clipped by the mask. */
  padding-bottom: 0.08em;
  margin-bottom: -0.08em;
}
.ln-i {
  display: block;
  will-change: transform;
}
.fx [data-motion="lines"]:not(.is-in) .ln-i {
  transform: translateY(105%);
}
[data-motion="lines"] .ln-i {
  transition: transform 1.15s var(--ease-out);
  transition-delay: calc(var(--ln) * 0.09s);
}
/* Once the reveal is over the promotion is no longer worth a layer. */
[data-motion="lines"].is-in .ln-i { will-change: auto; }

/* --- Photographic wipe ----------------------------------------------------
   The frame opens left to right while the photograph inside settles out of a
   slight over-scale. The two run at different lengths on purpose: the image
   is still moving after the frame has finished, which is what stops it
   reading as a shutter. */
.fx [data-motion="image"]:not(.is-in) {
  clip-path: inset(0 100% 0 0);
}
[data-motion="image"] {
  clip-path: inset(0 0 0 0);
  transition: clip-path 1.45s var(--ease-out);
}
.fx [data-motion="image"]:not(.is-in) img {
  transform: scale(1.06);
}
[data-motion="image"] img {
  transition: transform 1.7s var(--ease-out);
}

/* --- Drawn hairline -------------------------------------------------------
   Rules arrive the way they would be drawn on a sheet, from their origin
   outward. Used on the eyebrow dash and the process rail, nowhere else. */
.fx [data-motion="rule"]:not(.is-in)::before,
.fx .eyebrow[data-fx]:not([data-fx-done])::before {
  transform: scaleX(0);
}
.eyebrow::before {
  transform-origin: left;
  transition: transform 1s var(--ease-out) 0.1s;
}

/* Tracking settles in as the label arrives. */
.eyebrow, .section-label {
  transition: letter-spacing 1.1s var(--ease-out);
}
.fx :is(.eyebrow, .section-label)[data-fx]:not([data-fx-done]) {
  letter-spacing: 0.34em;
}

/* --- Process rail ---------------------------------------------------------
   The line through the five stages draws across as the section arrives, and
   each stage's marker lifts out of its resting state behind it. */
.timeline-grid::before {
  transform-origin: left;
  transition: transform 1.5s var(--ease-out);
}
.fx [data-motion="rail"]:not(.is-in)::before {
  transform: scaleX(0);
}
.timeline-dot {
  /* Resting state is a step not yet reached; arriving brings it up to full. */
  opacity: 0.55;
  transition: background var(--t), color var(--t), box-shadow var(--t),
              transform var(--t), opacity 0.8s var(--ease-out);
}
[data-motion="rail"].is-in .timeline-dot { opacity: 1; }
[data-motion="rail"] .timeline-card:nth-child(1) .timeline-dot { transition-delay: 0.35s; }
[data-motion="rail"] .timeline-card:nth-child(2) .timeline-dot { transition-delay: 0.52s; }
[data-motion="rail"] .timeline-card:nth-child(3) .timeline-dot { transition-delay: 0.69s; }
[data-motion="rail"] .timeline-card:nth-child(4) .timeline-dot { transition-delay: 0.86s; }
[data-motion="rail"] .timeline-card:nth-child(5) .timeline-dot { transition-delay: 1.03s; }

/* --- Closing plate --------------------------------------------------------
   The container, not the photograph: the image itself is a parallax plate and
   its transform already has an owner in the frame loop. */
.cta-bg {
  transition: transform 2s var(--ease-out);
}
.fx [data-motion="plate"]:not(.is-in) .cta-bg {
  transform: scale(1.045);
}

/* --- Magnetic buttons -----------------------------------------------------
   The pull is written to a custom property so the class's own hover lift and
   this offset compose instead of overwriting one another. Desktop pointers
   only; the script never attaches on touch. */
.btn {
  --mag-x: 0px;
  --mag-y: 0px;
}
.btn[data-magnetic] {
  transform: translate3d(var(--mag-x), var(--mag-y), 0);
  transition: transform 0.45s var(--ease-out), background var(--t),
              border-color var(--t), color var(--t), box-shadow var(--t);
}
.btn[data-magnetic]:hover {
  transform: translate3d(var(--mag-x), calc(var(--mag-y) - 2px), 0);
}
/* While the pointer is inside, the offset tracks it closely rather than
   easing, or the button lags behind the cursor and feels loose. */
.btn[data-magnetic][data-mag-live] {
  transition: transform 0.12s linear, background var(--t),
              border-color var(--t), color var(--t), box-shadow var(--t);
}

/* --- Hero curtain ---------------------------------------------------------
   Retracts off the photograph on load. The image underneath is untouched:
   its own entrance, its scale and its ken-burns drift are all as they were,
   because the plate's over-scale is the headroom the parallax spends and
   taking it away would pull the photograph off its frame. */
.hero-curtain {
  position: absolute;
  inset: 0;
  z-index: 3;
  background: var(--ink-900);
  transform-origin: right;
  pointer-events: none;
  animation: hero-curtain 1.5s var(--ease-out) 0.35s both;
}
@keyframes hero-curtain {
  from { transform: scaleX(1); }
  to   { transform: scaleX(0); }
}

/* --- Reduced motion -------------------------------------------------------
   Everything arrives, nothing travels. Content is never withheld: each start
   state is released rather than animated, so a visitor who has asked for less
   motion gets the finished page immediately. */
@media (prefers-reduced-motion: reduce) {
  .ln-i,
  [data-motion="lines"] .ln-i,
  [data-motion="image"],
  [data-motion="image"] img,
  .eyebrow::before,
  .eyebrow, .section-label,
  .timeline-grid::before,
  .timeline-dot,
  .cta-bg,
  .btn[data-magnetic] {
    transition: none !important;
    animation: none !important;
  }
  .fx [data-motion="lines"]:not(.is-in) .ln-i { transform: none; }
  .fx [data-motion="image"]:not(.is-in) { clip-path: none; }
  .fx [data-motion="image"]:not(.is-in) img { transform: none; }
  .fx [data-motion="rule"]:not(.is-in)::before,
  .fx .eyebrow[data-fx]:not([data-fx-done])::before { transform: none; }
  .fx :is(.eyebrow, .section-label)[data-fx]:not([data-fx-done]) { letter-spacing: 0.2em; }
  .fx [data-motion="rail"]:not(.is-in)::before { transform: none; }
  .timeline-dot { opacity: 1; }
  .fx [data-motion="plate"]:not(.is-in) .cta-bg { transform: none; }
  .hero-curtain { display: none; }
}
