/* ═══════════════════════════════════════════════════════════════════════════
   Purple Real Estate — the whole design layer.

   Direction A's layout on the Purple Group design system (Direction B).
   Tokens below are transcribed from HANDOFF.md §4, which is the agreed source.

   THE SYSTEM IS CLOSED. No colour, weight, radius or spacing value exists here
   that is not in the token block. Adding one is a design decision, not a CSS
   change — see CLAUDE.md § The design system is closed.

   No gradients. No shadows. No emoji. No unicode icon characters. Icons are
   inline Lucide SVG at stroke-width 1.5.
   ═══════════════════════════════════════════════════════════════════════════ */

:root {
  /* ── Palette. Blue Violet is the SINGLE accent; there is no second. ── */
  --ink:      #021B2A;   /* Ink Black — the ground */
  --cloud:    #F5FDFF;   /* Cloudy White — body and heading ink */
  --violet:   #7C3AED;   /* Blue Violet — actions, tags, eyebrow rule */
  --teal:     #053A4D;   /* Dark Teal — hairlines, ghost-button border */
  --frost:    #A6E1FA;   /* Frosted Blue — eyebrows, cadastral line */
  --dim:      #8FA7B4;   /* dimmed body on the dark ground */
  --dim-light:#4A6270;   /* dimmed body on a LIGHT band. --dim cannot do this job:
                            #8FA7B4 on Cloudy White is ~2.2:1. Same teal bias,
                            darkened until it clears AA — measures 6.2:1. */
  --ink-82:   rgba(2, 27, 42, 0.82);  /* flat panel over photography, never a gradient */

  /* ── Type. One sans throughout. Hanken Grotesk stands in for Greycliff CF
        until the licensed files land — see HANDOFF.md §3. ── */
  --sans: 'Hanken Grotesk', 'Avenir Next', Avenir, ui-sans-serif, system-ui, sans-serif;
  --mono: 'IBM Plex Mono', ui-monospace, SFMono-Regular, Menlo, monospace;

  /* ── Radii. Photography 16px and always rectangular; UI chrome 4px. ── */
  --r-photo: 16px;
  --r-ui: 4px;

  /* ── Spacing scale ── */
  --gut: clamp(20px, 5vw, 64px);   /* page side gutter */
  --sec: clamp(64px, 9vw, 128px);  /* section rhythm */

  /* ── Motion ── */
  --ease: cubic-bezier(0.22, 0.61, 0.36, 1);
  --t-fast: 120ms;
  --t-mid: 220ms;
  --t-slow: 480ms;

  color-scheme: dark;
}

/* The site commits to one look: a dark ground is the brand, not a theme. */

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

html { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  background: var(--ink);
  color: var(--cloud);
  font-family: var(--sans);
  font-weight: 400;
  font-size: 17px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

img { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; }

/* Focus is never removed. 2px Blue Violet at 2px offset. */
:focus-visible {
  outline: 2px solid var(--violet);
  outline-offset: 2px;
  border-radius: 2px;
}

h1, h2, h3, h4, h5 {
  margin: 0;
  font-weight: 500;
  letter-spacing: -0.025em;
  line-height: 0.98;   /* headlines only; sentence case, never Title Case */
}
p { margin: 0; }
ul { margin: 0; padding: 0; list-style: none; }

.wrap { max-width: 1320px; margin: 0 auto; padding-inline: var(--gut); }

/* The eyebrow signature: 700, 0.18em, ALL CAPS, Frosted Blue.
   Non-negotiable per brand.md. */
.eyebrow {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--frost);
  line-height: 1.5;
  margin: 0;
}
.eyebrow--rule {
  padding-left: 16px;
  border-left: 2px solid var(--violet);
}

.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* Skip link — visible only on focus, lands on the main content. */
.skip {
  position: absolute; left: -9999px; top: 0; z-index: 100;
  background: var(--violet); color: var(--cloud);
  padding: 12px 20px; border-radius: var(--r-ui);
  font-size: 13px; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase;
}
.skip:focus { left: var(--gut); top: 12px; }

/* ── Buttons ─────────────────────────────────────────────────────────────── */
.btn {
  display: inline-block;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  border-radius: var(--r-ui);
  transition: background var(--t-mid) var(--ease), border-color var(--t-mid) var(--ease),
              color var(--t-mid) var(--ease);
  white-space: nowrap;
}
.btn--solid {
  color: var(--cloud);
  background: var(--violet);
  padding: 16px 28px;
  border: 1px solid var(--violet);
}
.btn--solid:hover { background: #6D28D9; border-color: #6D28D9; }
.btn--ghost {
  color: var(--cloud);
  border: 1px solid var(--teal);
  padding: 16px 28px;
}
.btn--ghost:hover { border-color: var(--frost); }
.btn--sm { padding: 13px 20px; font-size: 11px; }

/* ═══ NAV ═══════════════════════════════════════════════════════════════════
   A LIGHT masthead band above the dark page, which is what lets the supplied
   brand logo be used as drawn. Purple #55307F on Ink Black measures about 1.6:1
   — nowhere near legible — so the original artwork needs a light ground. The
   derived white knockout existed only to work around that.

   Proportions measured off purple.group at 1440px: 94px tall, and nav links set
   in caps at 700 rather than sentence case — which is also this brand's own
   eyebrow signature. Its width is NOT purple.group's: the logo sits on the body
   grid (.wrap) so it lines up with the hero type and every section below.
   ═══════════════════════════════════════════════════════════════════════════ */
.nav {
  position: sticky; top: 0; z-index: 50;
  background: var(--cloud);
  /* No bottom hairline: the step down to the Ink Black hero is the edge. */
}
/* Width and gutters come from .wrap — do not override them here. */
.nav__inner {
  display: flex; align-items: center; gap: 32px;
  min-height: 94px;
}
.nav__logo { height: 38px; width: auto; }

.nav__links { display: flex; gap: 30px; margin-left: auto; align-items: center; }
.nav__links a {
  font-size: 13px; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--ink);
  transition: color var(--t-fast) var(--ease);
  padding-block: 4px;
}
.nav__links a:hover { color: var(--violet); }
/* The menu carries its own CTA for the mobile panel, where .nav__cta is hidden.
   Above the breakpoint that copy is a DUPLICATE of .nav__cta and must not paint. */
.nav__links .btn { display: none; }

.nav__toggle {
  display: none; margin-left: auto;
  background: none; border: 1px solid var(--teal); border-radius: var(--r-ui);
  color: var(--ink); padding: 9px; cursor: pointer;
}

@media (max-width: 960px) {
  .nav__inner { min-height: 72px; }
  .nav__logo { height: 30px; }
  .nav__toggle { display: inline-flex; }
  .nav__cta { display: none; }
  .nav__links {
    display: none;
    position: absolute; left: 0; right: 0; top: 100%;
    flex-direction: column; gap: 0; align-items: stretch;
    background: var(--cloud);
    padding: 8px var(--gut) 24px;
  }
  .nav__links[data-open='true'] { display: flex; }
  .nav__links .btn { display: block; }
  .nav__links a { padding-block: 15px; border-bottom: 1px solid rgba(5, 58, 77, 0.14); }
  .nav__links .btn { margin-top: 18px; text-align: center; border-bottom: 0; }
}

/* ═══ HERO ═════════════════════════════════════════════════════════════════
   Type on a flat ground BESIDE the photograph, never over it. This is the
   structural fix for the live site's white-on-light failure — see HANDOFF §6.1.
   ═════════════════════════════════════════════════════════════════════════ */
/* HEIGHT IS A FEATURE HERE. The cities strip sits at the bottom edge of the
   photograph, so the whole hero has to clear the fold on a laptop or that line is
   never seen. A 14in MacBook Pro leaves roughly 800px of viewport after browser
   chrome; minus the 94px masthead that is ~700px, so the hero targets ~610px and
   the strip lands well inside it. Adding vertical space back here pushes it off
   screen again — check a short viewport before growing any value below. */
/* Capped at the .wrap width, so on a wide screen the photograph stops at the
   content box instead of bleeding to the viewport edge, and the type's --gut
   padding lands on the same left line as the logo and every section below. */
.hero {
  display: grid; grid-template-columns: 1fr 0.92fr; align-items: stretch;
  max-width: 1320px; margin-inline: auto;
}
.hero__type {
  display: flex; flex-direction: column;
  padding: clamp(36px, 4.4vw, 64px) clamp(28px, 4vw, 64px) clamp(30px, 3vw, 44px) var(--gut);
}
.hero h1 {
  font-size: clamp(32px, 4.6vw, 62px);
  margin-top: 22px;
  max-width: 20ch;
  text-wrap: balance;
}
.hero__sub {
  margin-top: 20px; font-size: clamp(15.5px, 1.2vw, 18px);
  line-height: 1.5; color: var(--dim); max-width: 44ch;
}
.hero__actions { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 28px; }
.hero__img {
  position: relative; overflow: hidden; background: #08283A;
  /* WHAT ACTUALLY SETS THE HERO'S HEIGHT. Without an explicit height the <img>
     resolves height:100% against an indefinite track and falls back to its own
     aspect ratio at the column width — a near-square crop then dictated a 740px
     hero and pushed the cities strip below the fold on a 14in laptop.
     Capped so nav (94px) + hero always clears a short viewport. svh, not vh, so
     mobile browser chrome is counted. */
  height: clamp(340px, calc(100svh - 150px), 620px);
}
@supports not (height: 100svh) {
  .hero__img { height: clamp(340px, calc(100vh - 150px), 620px); }
}
/* `picture` is display:contents so the <img> still lays out as the direct child
   the cover sizing below assumes — the selector would otherwise miss it. */
.hero__img picture { display: contents; }
.hero__img img { width: 100%; height: 100%; object-fit: cover; }
.hero__cities {
  position: absolute; left: 0; right: 0; bottom: 0;
  padding: 16px clamp(18px, 2vw, 28px);
  background: var(--ink-82);        /* flat panel, not a gradient scrim */
  display: flex; flex-wrap: wrap; gap: 6px 18px;
}
.hero__cities span {
  font-size: 11px; font-weight: 700; letter-spacing: 0.17em; text-transform: uppercase;
}
.hero__cities span:first-child { color: var(--frost); }

@media (max-width: 900px) {
  .hero { grid-template-columns: 1fr; }
  .hero__type { padding-inline: var(--gut); }
  /* Stacked: the photograph is a band under the type, not a full column. */
  .hero__img { height: clamp(260px, 42svh, 360px); }
}

/* ═══ SECTION SCAFFOLD ═════════════════════════════════════════════════════ */
.section { padding-block: var(--sec); border-top: 1px solid var(--teal); }
.section__head { max-width: 62ch; }
.section__head h2 { font-size: clamp(28px, 3.4vw, 46px); margin-top: 20px; text-wrap: balance; }
.section__head p { margin-top: 20px; color: var(--dim); font-size: 17px; line-height: 1.6; }

/* ═══ LISTINGS ═════════════════════════════════════════════════════════════
   Catalogue items, not boxed cards: image → hairline rule → price.
   No border, no shadow, so nothing competes with the photograph.

   EVERY LISTING LINKS OUT TO sreality.cz. That is the system of record; this
   site owns no listing data and has no detail pages. See ADR 0001.
   ═════════════════════════════════════════════════════════════════════════ */
.offers__head {
  display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between;
  gap: 12px 24px; padding-bottom: 20px; border-bottom: 1px solid var(--teal);
}
.offers__head a { font-size: 14px; color: var(--dim); border-bottom: 1px solid var(--teal); padding-bottom: 2px; }
.offers__head a:hover { color: var(--cloud); border-color: var(--frost); }

/* ── The three strips ───────────────────────────────────────────────────────
   Listings, references and partner logos each lay out as ONE horizontal row
   that scrolls sideways rather than wrapping into a stack. Shared here is only
   the scrolling and the drag affordance; each section keeps its own column
   width and gap, since a listing card, a quotation and a logo want different
   room. The strips never move on their own — the reader drags them.

   In every one of them the reveal sits on the container, not on each item
   (index.html): an item scrolled out of this overflow box never intersects the
   viewport, so a per-item reveal would leave the far ones permanently invisible.

   site.js sets the three attributes below, and only on these containers.
   [data-drag] appears only while the row actually overflows, so the grab cursor
   never promises a movement that cannot happen. */
.grid, .refs, .partners {
  grid-auto-flow: column;
  overflow-x: auto; overscroll-behavior-x: contain;
  scroll-snap-type: x proximity;
  scrollbar-width: thin; scrollbar-color: var(--teal) transparent;
}
[data-drag] { cursor: grab; }
[data-press] { -webkit-user-select: none; user-select: none; }
[data-dragging] { cursor: grabbing; scroll-snap-type: none; }
.item, .ref, .partner { scroll-snap-align: start; }

/* Cards hold 260px, so all four fit the 1320px wrap exactly and the listings
   only start scrolling on a narrower screen. */
.grid {
  display: grid; grid-auto-columns: minmax(260px, 1fr);
  gap: clamp(24px, 3vw, 40px); margin-top: 36px;
}

.item { display: flex; flex-direction: column; }
.item__media {
  position: relative; border-radius: var(--r-photo); overflow: hidden;
  aspect-ratio: 4 / 3; max-width: 100%; background: #08283A;
}
.item__media img {
  width: 100%; height: 100%; object-fit: cover;
  transition: transform var(--t-slow) var(--ease);
}
.item:hover .item__media img { transform: scale(1.03); }
@media (prefers-reduced-motion: reduce) { .item:hover .item__media img { transform: none; } }

/* Empty state for a listing that has no photograph yet. KEPT ON PURPOSE even
   though all four current cards carry one: listings are refreshed from Sreality,
   whose image CDN returns 401, so every new listing arrives photo-less until Petr
   supplies the original. This is the recurring case, not a one-off.
   (This overrides an earlier note here that said to delete it once real photos
   landed — that was written before the refresh cycle was understood.)
   A flat panel with a label reads as deliberate rather than broken. */
.item__media--empty {
  display: flex; align-items: center; justify-content: center;
  border: 1px solid var(--teal);
}
.item__soon {
  font-size: 10.5px; font-weight: 700; letter-spacing: 0.18em;
  text-transform: uppercase; color: var(--frost); opacity: 0.75;
}

.item__tag {
  position: absolute; left: 12px; top: 12px;
  font-size: 10px; font-weight: 700; letter-spacing: 0.15em; text-transform: uppercase;
  color: var(--cloud); background: var(--violet);
  padding: 7px 11px; border-radius: var(--r-ui);
}
.item__body { padding-top: 18px; }
.item__body h3 { font-size: 19px; line-height: 1.26; letter-spacing: -0.015em; }
.item__loc { margin-top: 8px; font-size: 14px; color: var(--dim); }
.item__cad { margin-top: 4px; font-family: var(--mono); font-size: 12px; color: var(--frost); }
.item__price {
  margin-top: 18px; padding-top: 14px; border-top: 1px solid var(--teal);
  display: flex; align-items: baseline; justify-content: space-between; gap: 12px;
}
/* Prices are numbers again: tabular figures, non-breaking thousands separator
   in the markup, and no zero-width characters. See HANDOFF §6.3. */
.item__price b {
  font-size: 20px; font-weight: 600; letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
}
.item__price span {
  font-size: 12.5px; color: var(--dim);
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
.item__out {
  margin-top: 12px; font-size: 12px; color: var(--dim);
  display: inline-flex; align-items: center; gap: 6px;
}
.item:hover .item__out { color: var(--frost); }
.item__out svg { width: 14px; height: 14px; }

/* ═══ SERVICES ═════════════════════════════════════════════════════════════ */
.svc { display: grid; grid-template-columns: repeat(2, 1fr); gap: clamp(28px, 3vw, 48px); margin-top: 48px; }
@media (max-width: 820px) { .svc { grid-template-columns: 1fr; } }
.svc__card { padding-top: 26px; border-top: 1px solid var(--teal); }
.svc__card h3 { font-size: 21px; margin-top: 18px; line-height: 1.2; }
.svc__icon { color: var(--frost); }
.svc__card ul { margin-top: 18px; display: flex; flex-direction: column; gap: 11px; }
.svc__card li {
  position: relative; padding-left: 20px; font-size: 15.5px; line-height: 1.5; color: var(--dim);
}
.svc__card li::before {
  content: ''; position: absolute; left: 0; top: 10px;
  width: 7px; height: 1px; background: var(--violet);
}

/* ═══ FAQ ══════════════════════════════════════════════════════════════════ */
.faq { margin-top: 44px; max-width: 900px; }
.faq__item { border-top: 1px solid var(--teal); }
.faq__item:last-child { border-bottom: 1px solid var(--teal); }
.faq__q {
  width: 100%; display: flex; align-items: flex-start; justify-content: space-between; gap: 24px;
  background: none; border: 0; color: var(--cloud);
  font-family: var(--sans); font-size: clamp(17px, 1.6vw, 20px); font-weight: 500;
  letter-spacing: -0.015em; line-height: 1.3; text-align: left;
  padding: 26px 0; cursor: pointer;
}
.faq__q:hover { color: var(--frost); }
.faq__sign { flex: none; width: 20px; height: 20px; margin-top: 3px; color: var(--violet);
  transition: transform var(--t-mid) var(--ease); }
.faq__q[aria-expanded='true'] .faq__sign { transform: rotate(45deg); }
/* Visible BY DEFAULT and collapsed by JS, never the reverse: without this file's
   script every answer must still be readable. Inverting these two rules is what
   turns the accordion into six dead buttons for a reader with no JS. */
.faq__a { display: block; padding-bottom: 28px; max-width: 72ch; color: var(--dim); line-height: 1.65; }
.faq__a[data-open='false'] { display: none; }
.faq__a strong { color: var(--cloud); font-weight: 600; }
.faq__a ul { margin-top: 12px; display: flex; flex-direction: column; gap: 8px; }
.faq__a li { position: relative; padding-left: 20px; }
.faq__a li::before {
  content: ''; position: absolute; left: 0; top: 13px; width: 7px; height: 1px; background: var(--violet);
}

/* ═══ REFERENCES ═══════════════════════════════════════════════════════════ */
/* 320px keeps a quotation readable — narrower and the short ones break into a
   column of two-word lines. */
.refs { display: grid; grid-auto-columns: minmax(320px, 1fr); gap: clamp(24px, 3vw, 44px); margin-top: 48px; }
.ref { padding-top: 26px; border-top: 1px solid var(--teal); }
.ref blockquote { margin: 0; font-size: 18px; line-height: 1.55; letter-spacing: -0.01em; }
.ref figcaption { margin-top: 18px; font-size: 12px; font-weight: 700;
  letter-spacing: 0.16em; text-transform: uppercase; color: var(--frost); }

/* ═══ CERTIFICATES + MAP ═══════════════════════════════════════════════════ */
.two { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(32px, 4vw, 64px); }
@media (max-width: 820px) { .two { grid-template-columns: 1fr; } }
.two--center { align-items: center; }

/* O nás: the photograph the hero used to carry, now beside the text that explains
   the business rather than above the fold. Photography stays a 16px rectangle. */
.onas__img img {
  display: block; width: 100%; height: auto;
  border-radius: var(--r-photo);
}
.docs { margin-top: 30px; display: flex; flex-direction: column; gap: 2px; }
.doc {
  display: flex; align-items: center; gap: 14px;
  padding: 18px 0; border-top: 1px solid var(--teal);
  font-size: 15.5px; color: var(--dim);
  transition: color var(--t-fast) var(--ease);
}
.doc:last-child { border-bottom: 1px solid var(--teal); }
.doc:hover { color: var(--cloud); }
.doc svg { flex: none; color: var(--frost); }
.doc span { margin-left: auto; font-family: var(--mono); font-size: 11px; color: var(--frost); }

/* ═══ LIGHT BAND ════════════════════════════════════════════════════════════
   A Cloudy White section on the Ink Black page. Introduced for Partneři, whose
   logos are other companies' marks supplied as white-background JPEGs — on the
   dark ground each needed its own white tile, which read as seven patches. On a
   light band they simply sit there.

   NO NEW COLOURS. The band re-roles existing tokens: Cloudy White becomes the
   ground, Ink Black the heading ink, Dark Teal the eyebrow and the dimmed body.
   Frosted Blue cannot carry the eyebrow here — #A6E1FA on #F5FDFF is about
   1.2:1 — so Dark Teal takes that job, the same swap the hairlines already make.
   ═══════════════════════════════════════════════════════════════════════════ */
.section--light {
  background: var(--cloud);
  color: var(--ink);
  border-top: 0;
}
.section--light .section__head .eyebrow { color: var(--teal); }
.section--light .section__head p { color: var(--dim-light); }

/* ═══ PARTNERS ══════════════════════════════════════════════════════════════ */
/* Columns size to the logo, not to a fixed width: the marks range from a square
   symbol to a long wordmark, and a uniform column would centre each one in its
   own box, so the visible gap between two narrow logos came out twice the gap
   between two wide ones. max-content puts the same air between every pair. */
.partners {
  margin-top: 44px;
  display: grid; grid-auto-columns: max-content;
  gap: clamp(20px, 3vw, 40px);
  align-items: center;
}
/* The band loops. site.js moves the logos onto a track and rides a second,
   aria-hidden copy behind them; this is the enhanced state, and the rules above
   are the fallback — the same logos, dragged by hand.
   The set carries its own TRAILING gap, so translating the track exactly -50%
   puts the copy where the original stood and the seam cannot be seen. Uniform
   gaps on one flat track would land half a gap out and visibly jump.
   It pauses on hover and on keyboard focus: these logos are links, and a link
   that moves under the cursor cannot be clicked. */
.partners[data-marquee] { display: block; overflow: hidden; scroll-snap-type: none; }
.partners__track {
  display: flex; width: max-content;
  animation: partners-run 36s linear infinite;
}
.partners[data-marquee]:hover .partners__track,
.partners[data-marquee]:focus-within .partners__track { animation-play-state: paused; }
.partners__set {
  display: grid; grid-auto-flow: column; grid-auto-columns: max-content;
  gap: clamp(20px, 3vw, 40px); padding-right: clamp(20px, 3vw, 40px);
  align-items: center;
}
@keyframes partners-run {
  from { transform: translateX(0); }
  to { transform: translateX(-50%); }
}
@media (prefers-reduced-motion: reduce) { .partners__track { animation: none; } }

.partner {
  display: flex; align-items: center; justify-content: center;
  min-height: 84px;
  transition: opacity var(--t-mid) var(--ease);
}
.partner:hover { opacity: 0.6; }
.partner img {
  max-height: 52px; width: auto; object-fit: contain;
  /* The supplied marks are JPEGs, so each carries a baked-in #FFFFFF box that
     still reads as a faint rectangle against Cloudy White (#F5FDFF). Multiply
     maps white onto the band exactly (white x bg = bg), so the box disappears
     while the mark itself is untouched. Logos whose own ground is coloured
     (ILO, Asociace, Zvládneme, Ubytovna) are near-unchanged, because the band
     is near-white. Not a gradient and not a shadow — the system bans those. */
  mix-blend-mode: multiply;
}

/* ═══ CONTACT ══════════════════════════════════════════════════════════════ */
.contact { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(32px, 4vw, 72px); align-items: start; }
@media (max-width: 820px) { .contact { grid-template-columns: 1fr; } }
/* Moved here from the hero, and materially bigger: 168px wide against the 64px
   thumbnail it replaced. A one-person brokerage competing on a human approach
   should show the person at a size you can actually read a face in, and the
   contact block is where that decision gets made. Photography stays a 16px
   rectangle — never masked into a circle. */
.contact__broker {
  display: flex; align-items: center; gap: 22px;
  margin-top: 34px;
}
.contact__broker img {
  width: 168px; height: 181px; flex: none;
  border-radius: var(--r-photo);
  object-fit: cover;
}
.contact__broker b {
  display: block; font-size: 20px; font-weight: 600;
  letter-spacing: -0.01em; line-height: 1.2;
}
.contact__broker span {
  /* No max-width: at 11px with 0.16em tracking the full title is ~230px and the
     column has ~410px beside the portrait, so it sits on one line. Constraining it
     broke it across three. */
  display: block; margin-top: 9px;
  font-size: 11px; font-weight: 700; letter-spacing: 0.16em;
  text-transform: uppercase; color: var(--frost); line-height: 1.5;
}
@media (max-width: 480px) {
  .contact__broker { gap: 16px; }
  .contact__broker img { width: 124px; height: 134px; }
  .contact__broker b { font-size: 18px; }
}

.contact__lines { margin-top: 30px; display: flex; flex-direction: column; gap: 2px; }
.cline {
  display: flex; align-items: center; gap: 14px;
  padding: 18px 0; border-top: 1px solid var(--teal); font-size: 16px;
  transition: color var(--t-fast) var(--ease);
}
.cline:last-of-type { border-bottom: 1px solid var(--teal); }
a.cline:hover { color: var(--frost); }
.cline svg { flex: none; color: var(--frost); }
.contact__card { padding-top: 30px; border-top: 1px solid var(--teal); }
.contact__card dl { margin: 22px 0 0; display: grid; grid-template-columns: auto 1fr; gap: 10px 20px; }
.contact__card dt {
  font-size: 10.5px; font-weight: 700; letter-spacing: 0.16em;
  text-transform: uppercase; color: var(--frost); padding-top: 3px;
}
.contact__card dd { margin: 0; font-size: 15.5px; color: var(--dim); line-height: 1.5; }

/* The map is a photographic rectangle, not UI chrome, so it takes --r-photo like
   every other image on the page. The panel colour behind it is what the listing
   media already uses, so an unloaded map reads as a deliberate empty frame
   rather than a hole. */
.contact__map {
  margin-top: 32px; aspect-ratio: 3 / 2;
  border-radius: var(--r-photo); overflow: hidden; background: #08283A;
}
.contact__map iframe { display: block; width: 100%; height: 100%; border: 0; }

/* ═══ FOOTER ════════════════════════════════════════════════════════════════
   Dark again, and carrying no logo. The masthead is sticky, so the mark never
   leaves the screen; repeating it at the bottom earned nothing, and hosting it was
   the only reason this band was ever light. Ink Black ground, Dark Teal hairline.
   ═══════════════════════════════════════════════════════════════════════════ */
.foot {
  border-top: 1px solid var(--teal);
  padding-block: 44px 52px;
}
.foot__inner {
  display: flex; flex-wrap: wrap; align-items: baseline;
  gap: 14px 48px;
}
.foot__group { font-size: 14.5px; line-height: 1.6; color: var(--dim); max-width: 46ch; }
.foot__group a {
  color: var(--cloud); font-weight: 600;
  border-bottom: 1px solid var(--violet); padding-bottom: 1px;
  transition: color var(--t-fast) var(--ease);
}
.foot__group a:hover { color: var(--frost); }

.foot__meta { margin-left: auto; font-size: 13.5px; color: var(--dim); }
.foot__meta a { border-bottom: 1px solid var(--teal); }
.foot__meta a:hover { color: var(--cloud); border-color: var(--frost); }

@media (max-width: 680px) {
  .foot__inner { flex-direction: column; align-items: flex-start; }
  .foot__meta { margin-left: 0; }
}

/* ═══ REVEAL ═══════════════════════════════════════════════════════════════
   Enhancement only. Without JS every section is visible — .reveal gets its
   visible state from JS adding [data-ready], never the reverse.
   ═════════════════════════════════════════════════════════════════════════ */
[data-ready] .reveal { opacity: 0; transform: translateY(14px); }
[data-ready] .reveal[data-seen='true'] {
  opacity: 1; transform: none;
  transition: opacity var(--t-slow) var(--ease), transform var(--t-slow) var(--ease);
}
@media (prefers-reduced-motion: reduce) {
  [data-ready] .reveal { opacity: 1; transform: none; }
}
