/* ==========================================================================
   1839 15th Street, Unit 364 — design tokens (Modernist system, Roboto/navy override)
   ========================================================================== */
:root {
  --color-bg: #f3f2f2;
  --color-surface: #ffffff;
  --color-text: #201e1d;
  --color-neutral-300: #e2e0de;
  --color-neutral-500: #b9b7b5;
  --color-neutral-700: #6b6864;
  --color-neutral-800: #3d3b39;

  --color-accent: #3457a6;
  --color-accent-100: #e2e8f6;
  --color-accent-600: #2c4a8f;
  --color-accent-700: #24406e;

  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-6: 24px;
  --space-8: 32px;

  --font-display: 'Roboto', sans-serif;

  /* Bootstrap variable overrides */
  --bs-body-bg: var(--color-bg);
  --bs-body-color: var(--color-text);
  --bs-link-color: var(--color-accent);
  --bs-link-hover-color: var(--color-accent-700);
  --bs-primary: var(--color-accent);
  --bs-border-radius: 0;
  --bs-border-radius-lg: 0;
  --bs-border-radius-sm: 0;
}

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

html {
  scroll-behavior: smooth;
}

body {
  background-color: var(--color-bg);
  color: var(--color-text);
  font-family: 'Roboto', sans-serif;
  font-weight: 300;
}

h1, h2, h3 {
  font-family: var(--font-display);
  font-weight: 100;
  color: var(--color-text);
}

a {
  color: var(--color-accent);
}
a:hover {
  color: var(--color-accent-700);
}

/* Skip link */
.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 2000;
  background: var(--color-accent);
  color: #fff;
  padding: var(--space-3) var(--space-6);
  font-weight: 400;
}
.skip-link:focus {
  left: var(--space-4);
  top: var(--space-4);
}

/* Focus visibility */
a:focus-visible,
button:focus-visible,
input:focus-visible,
textarea:focus-visible {
  outline: 3px solid var(--color-accent-600);
  outline-offset: 2px;
}

/* ==========================================================================
   Navigation
   ========================================================================== */
.site-nav {
  background-color: transparent;
  padding: 27.6px 0;
  transition: background-color 0.6s ease, padding 0.6s ease, box-shadow 0.6s ease;
}
.site-nav.is-scrolled {
  background-color: var(--color-bg);
  padding: var(--space-4) 0;
  box-shadow: 0 1px 0 var(--color-neutral-300);
}
.site-nav .navbar-brand {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 15px;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  white-space: nowrap;
  color: var(--color-text);
}
.site-nav .navbar-brand img {
  display: block;
  /* Fluid: full 40px on tablets/desktops, easing down to 34px on phones
     (9vw hits the 34px floor at ~375px wide). Any smaller and the two-line
     logo's lettering gets too small to read. */
  height: clamp(34px, 9vw, 40px);
  width: auto;
  /* Same duration as the nav's background fade, so the two change together. */
  transition: filter 0.6s ease;
}
/* The PNG is dark. While the nav is transparent over the hero photo it is
   turned white (brightness(0) -> black, invert(1) -> white); once .is-scrolled
   gives the nav a solid light background, the original dark artwork shows. */
.site-nav:not(.is-scrolled) .navbar-brand img {
  filter: brightness(0) invert(1);
}
.site-nav .nav-link {
  font-size: 14px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--color-text) !important;
  position: relative;
  padding-bottom: 4px;
}
.site-nav .nav-link::after {
  content: '';
  position: absolute;
  left: 0;
  bottom: 0;
  width: 0;
  height: 2px;
  background-color: var(--color-accent);
  transition: width 0.3s ease;
}
.site-nav .nav-link:hover::after,
.site-nav .nav-link:focus-visible::after {
  width: 100%;
}
.site-nav .navbar-toggler {
  border: none;
  box-shadow: none;
}

/* ==========================================================================
   Hero
   ========================================================================== */
.hero {
  position: relative;
  height: 100vh;
  /* On phones 100vh is the height with the browser toolbars hidden, so while the
     toolbar is showing the bottom of the hero (where the logo sits) is pushed off
     screen. svh = the "small" viewport, i.e. always what's actually visible. */
  height: 100svh;
  min-height: 560px;
  overflow: hidden;
}
.hero-image-wrap {
  position: absolute;
  left: 0;
  right: 0;
  /* Only 25% taller than the hero, split evenly above and below (top: -12.5%) so
     the photo's center sits exactly on the hero's center at rest. A taller wrapper
     makes object-fit: cover scale the photo up to fill it — at 200% the 1950px
     photo rendered at ~150-180% of native size and looked pixelated. Keep in sync
     with PARALLAX in js/site.js (buffer above/below = PARALLAX = half the extra). */
  top: -12.5%;
  height: 125%;
  will-change: transform;
}
.hero-image-wrap img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  animation: hero-zoom 14s cubic-bezier(0.16, 1, 0.3, 1) forwards;
}
@keyframes hero-zoom {
  from { transform: scale(1); }
  to { transform: scale(1.03); }
}
.hero-overlay {
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(20, 19, 18, 0.05) 0%, rgba(20, 19, 18, 0.55) 100%);
}
.hero-content {
  position: absolute;
  left: var(--space-6);
  right: var(--space-6);
  bottom: var(--space-8);
  color: #fff;
  text-align: center;
  will-change: transform, opacity; /* parallax + scroll fade, both driven by js/site.js */
}
.hero-tag {
  display: inline-block;
  background-color: var(--color-accent);
  color: #fff;
  font-size: 13px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  padding: 6px 14px;
  margin-bottom: var(--space-4);
  opacity: 0;
  transform: translateY(28px);
  animation: reveal-up 0.9s cubic-bezier(0.16, 1, 0.3, 1) forwards;
}
.hero-title {
  font-family: var(--font-display);
  font-weight: 100;
  color: #fff;
  font-size: clamp(48px, 8vw, 108px);
  line-height: 0.95;
  margin-bottom: var(--space-4);
  opacity: 0;
  transform: translateY(28px);
  animation: reveal-up 0.9s cubic-bezier(0.16, 1, 0.3, 1) forwards;
  animation-delay: 0.08s;
}
/* Title is a white logo lockup (PNG) rather than text; the <h1> stays for SEO/a11y. */
.hero-title img {
  display: block;
  width: clamp(240px, 42vw, 480px);
  height: auto;
  margin: 0 auto;
}
.hero-location {
  font-size: 20px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  margin-bottom: 0;
  opacity: 0;
  transform: translateY(28px);
  animation: reveal-up 0.9s cubic-bezier(0.16, 1, 0.3, 1) forwards;
  animation-delay: 0.16s;
}
@keyframes reveal-up {
  to { opacity: 1; transform: translateY(0); }
}

/* ==========================================================================
   Scroll reveal (generic, used by stat row / description / gallery heading)
   ========================================================================== */
.reveal {
  opacity: 0;
  transform: translateY(28px);
  transition: opacity 0.7s cubic-bezier(0.16, 1, 0.3, 1), transform 0.7s cubic-bezier(0.16, 1, 0.3, 1);
}
.reveal.reveal--delay {
  transition-delay: 0.08s;
}
.reveal.reveal--delay-2 {
  transition-delay: 0.16s;
}
.reveal.is-visible {
  opacity: 1;
  transform: translateY(0);
}

/* ==========================================================================
   Stat row
   ========================================================================== */
.stat-row {
  padding: var(--space-8) 0;
}
.stat-col {
  text-align: center;
  padding: var(--space-6);
  /* Lets .stat-value size itself from this column's width (cqw) — see below. */
  container-type: inline-size;
}
@media (max-width: 575.98px) {
  .stat-col {
    padding: var(--space-3);
  }
}
.stat-value {
  font-family: var(--font-display);
  font-weight: 100;
  display: block;
  /* "$1,800,000" is ~4.75x its font size wide and can't wrap, so a fixed 40px
     pokes out of a narrow column (phones with 2 across, tablets with 4 across)
     and makes the whole page scroll sideways. Cap at 40px but shrink with the
     column: 19cqw keeps even the price inside it. The first line is the fallback
     for browsers without container query units (safe everywhere, just smaller). */
  font-size: 28px;
  font-size: min(40px, 19cqw);
}
.stat-label {
  font-size: 13px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--color-neutral-700);
}
.stat-col--price .stat-label {
  display: block;
  margin-bottom: var(--space-1);
}
.stat-col--price .stat-value {
  color: var(--color-accent-700);
}

/* ==========================================================================
   Description
   ========================================================================== */
.description {
  padding: var(--space-8) 0;
}
.description-kicker {
  text-align: center;
  font-size: 13px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--color-accent-700);
  font-weight: 500;
  margin-bottom: var(--space-2);
}
.description-tagline {
  text-align: center;
  font-style: italic;
  font-size: 16px;
  color: var(--color-neutral-700);
  margin-bottom: var(--space-8);
}
/* Lead photo above the description, in the same column as the copy. */
.description-image {
  max-width: 1000px;
  margin: 0 auto var(--space-8);
}
.description-image img {
  display: block;
  width: 100%;
  height: auto;
}
/* A photo that follows a block's copy: space above it, none below (the next
   block supplies its own top margin). */
.description-copy + .description-image {
  margin: var(--space-8) auto 0;
}
/* Copy that resumes after an in-between photo. */
.description-image + .description-copy {
  margin-top: var(--space-8);
}
/* The address lockup above the description. Same white-on-transparent PNG as the
   hero; the filter turns it near-black (~the page text color) for the light
   background. brightness(0) -> black, invert(.12) -> rgb(31,31,31). */
.description-logo {
  margin-bottom: var(--space-4);
}
.description-logo img {
  display: block;
  width: clamp(170px, 32vw, 280px);
  height: auto;
  margin: 0 auto;
  filter: brightness(0) invert(0.12);
}
.description-heading {
  text-align: center;
  font-size: clamp(24px, 3vw, 32px);
  margin-bottom: var(--space-6);
}
/* The description is a run of headline + copy blocks, all with the same headline size. */
.description-block + .description-block {
  margin-top: calc(var(--space-8) * 2);
}
.description-copy {
  max-width: 1000px;
  margin: 0 auto;
  font-size: 17px;
  line-height: 1.6;
  text-align: left;
}
.description-copy p + p {
  margin-top: var(--space-4);
}

/* ==========================================================================
   Gallery / infinite carousel
   ========================================================================== */
.gallery {
  padding: var(--space-8) 0;
}
.gallery-heading-row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  margin-bottom: var(--space-6);
}
.gallery-count {
  margin-left: auto;
  font-size: 13px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--color-neutral-700);
}
.gallery-viewport {
  position: relative;
  /* Capped at 720px: past that, 62vh would make each (3:2-ratio) slide wide
     enough to approach the container's own width, squeezing the previous/
     next slide peek down to a sliver on tall viewports. (720px splits the
     difference between the uncapped sliver and an earlier, too-generous
     580px cap.) */
  height: min(62vh, 720px);
  min-height: 380px;
  overflow: hidden;
  touch-action: pan-y;
}
.gallery-track {
  display: flex;
  height: 100%;
  will-change: transform;
}
.gallery-slide {
  flex: 0 0 auto;
  height: 100%;
  opacity: 0.45;
  transition: opacity 0.4s ease;
  cursor: pointer;
  background-color: var(--color-bg);
}
.gallery-slide.is-active {
  opacity: 1;
}
.gallery-slide img {
  width: 100%;
  height: 100%;
  /* contain (not cover): every photo shows at its full width, uncropped —
     the slide's own width is sized to the image's aspect ratio in JS, so
     this only ever letterboxes on the rare/narrow viewport where the slide
     width gets capped to fit the screen. */
  object-fit: contain;
  display: block;
  user-select: none;
  -webkit-user-drag: none;
}
.gallery-arrow {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 56px;
  height: 56px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: rgba(243, 242, 242, 0.92);
  border: 2px solid transparent;
  color: var(--color-text);
  z-index: 2;
  transition: border-color 0.2s ease, color 0.2s ease;
}
.gallery-arrow:hover {
  border-color: var(--color-accent);
  color: var(--color-accent);
}
.gallery-arrow--dark {
  background-color: rgba(255, 255, 255, 0.1);
  color: #fff;
}
.gallery-arrow--prev { left: 16px; }
.gallery-arrow--next { right: 16px; }
.gallery-counter {
  position: absolute;
  right: 16px;
  bottom: 16px;
  background-color: rgba(20, 19, 18, 0.7);
  color: #fff;
  font-size: 13px;
  padding: 4px 10px;
  z-index: 2;
}

/* Lightbox modal */
.lightbox-modal .modal-content {
  background-color: rgba(20, 19, 18, 0.96);
  border: none;
}
.lightbox-body {
  position: relative;
  height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
}
.lightbox-body img {
  max-width: min(85vw, 1100px);
  max-height: 85vh;
  object-fit: contain;
}
.lightbox-close {
  position: absolute;
  top: 16px;
  right: 16px;
  width: 44px;
  height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: rgba(255, 255, 255, 0.1);
  border: none;
  color: #fff;
  z-index: 2;
  transition: background-color 0.2s ease;
}
.lightbox-close:hover {
  background-color: rgba(255, 255, 255, 0.2);
}
.lightbox-counter {
  position: absolute;
  bottom: 16px;
  left: 50%;
  transform: translateX(-50%);
  background-color: rgba(20, 19, 18, 0.7);
  color: #fff;
  font-size: 13px;
  padding: 4px 10px;
}

/* ==========================================================================
   Agent bio
   ========================================================================== */
.agent {
  padding: var(--space-8) 0;
}
.agent-inner {
  max-width: 560px;
  margin: 0 auto;
  text-align: center;
  /* Lets .agent-contact size its text from this column's width (cqw). */
  container-type: inline-size;
}
.agent-photo {
  width: 88px;
  height: 88px;
  border-radius: 50%;
  object-fit: cover;
  margin: 0 auto var(--space-4);
}
.agent-name {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: 28px;
  margin-bottom: var(--space-1);
}
.agent-title {
  text-transform: uppercase;
  font-size: 21px;
  color: var(--color-neutral-700);
  margin-bottom: var(--space-4);
}
.agent-contact {
  /* The email address is ~14x its font size wide and can't wrap, so a fixed 24px
     overflows phones narrower than ~360px and makes the page scroll sideways.
     Cap at 24px and shrink with the column (6.9cqw keeps it inside). The first
     line is the fallback for browsers without container query units. */
  font-size: 20px;
  font-size: min(24px, 6.9cqw);
  /* Last item in the agent block (the disclaimer moved under the floor plan). */
  margin-bottom: 0;
}
.agent-contact a {
  display: block;
  color: var(--color-text);
  overflow-wrap: anywhere; /* last resort on very narrow screens */
}
.agent-contact a:hover {
  color: var(--color-accent);
}
.agent-bio {
  font-size: 17px;
  line-height: 1.6;
  text-align: left;
  margin-bottom: var(--space-6);
}
.agent-bio p + p {
  margin-top: var(--space-4);
}

/* ==========================================================================
   Contact
   ========================================================================== */
.contact {
  padding: var(--space-8) 0 calc(var(--space-8) * 2);
}
.contact-inner {
  max-width: 840px;
  margin: 0 auto;
}
.contact-heading {
  text-align: center;
  margin-bottom: var(--space-6);
}
.contact-form {
  display: flex;
  flex-direction: column;
  gap: calc(var(--space-6) + 1em);
}
.field-underline {
  border: none;
  border-bottom: 1px solid var(--color-neutral-500);
  background: transparent;
  border-radius: 0;
  font-size: 16px;
  padding: var(--space-2) 0;
  color: var(--color-text);
}
.field-underline:focus {
  border-bottom-color: var(--color-accent);
  box-shadow: none;
}
.field-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
}
.field-row > .field-group {
  flex: 1 1 220px;
}
.field-label {
  font-size: 13px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--color-neutral-700);
  margin-bottom: var(--space-1);
  display: block;
}
.contact-submit {
  align-self: flex-end;
  padding: 12px 28px;
  background-color: var(--color-accent);
  color: #fff;
  text-transform: uppercase;
  font-size: 14px;
  font-weight: 500;
  border: none;
}
.contact-submit:hover {
  background-color: color-mix(in srgb, var(--color-accent) 60%, white) !important;
}
.contact-submit:active {
  background-color: color-mix(in srgb, var(--color-accent) 45%, white) !important;
}
.honeypot-field {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}
.contact-success {
  border: none;
  background-color: var(--color-accent-100);
  color: var(--color-accent-700);
}

/* ==========================================================================
   Floor plan
   ========================================================================== */
.floorplan {
  padding: var(--space-8) 0;
}
.floorplan-heading {
  text-align: center;
  font-size: clamp(24px, 3vw, 32px);
  margin-bottom: var(--space-6);
}
/* The plan is a 4:3 JPG on white; a white panel keeps its edges from showing
   against the page's off-white. */
.floorplan-image {
  max-width: 1000px;
  margin: 0 auto var(--space-6);
  background-color: var(--color-surface);
}
.floorplan-image img {
  display: block;
  width: 100%;
  height: auto;
}
.floorplan-disclaimer {
  max-width: 700px;
  margin: 0 auto var(--space-6);
  text-align: center;
  font-size: 0.75em;
  color: var(--color-neutral-700);
  line-height: 1.6;
}
.floorplan-actions {
  text-align: center;
}
/* Same look as the contact form's submit button. */
.floorplan-download {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: 12px 28px;
  background-color: var(--color-accent);
  color: #fff;
  text-transform: uppercase;
  font-size: 14px;
  font-weight: 500;
  text-decoration: none;
}
.floorplan-download:hover,
.floorplan-download:focus-visible {
  color: #fff;
  background-color: color-mix(in srgb, var(--color-accent) 60%, white);
}

/* ==========================================================================
   Map
   ========================================================================== */
.map {
  height: 400px;
  width: 100%;
  filter: grayscale(0.2);
}

/* ==========================================================================
   Footer
   ========================================================================== */
.site-footer {
  padding: var(--space-6) 0;
  border-top: 1px solid var(--color-neutral-300);
  font-size: 13px;
  text-transform: uppercase;
}
.site-footer .footer-brand img {
  max-height: 24px;
}
.footer-disclaimer {
  font-size: 12px;
  text-transform: none;
  color: var(--color-neutral-700);
  line-height: 1.6;
  margin-top: var(--space-4);
}
