/* ==========================================================================
   Ahmad Atalla - off-plan property advisor
   Built to the Agentwise structural language. All motion values measured
   from the live template; see the spec for what was measured vs chosen.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Tokens
   -------------------------------------------------------------------------- */

:root {
  /* Palette - read from the Agentwise live CSS */
  --paper:       #fffdf1;
  --ink:         #070707;
  --panel:       #141414;
  --accent:      #ff2244;
  --accent-warm: #d94e1a;
  --muted:       #5c5c5c;
  --rule:        #eaeaea;
  --rule-input:  rgba(7, 7, 7, 0.28);
  --rule-dark:   rgba(255, 255, 255, 0.12);
  --paper-dim:   rgba(255, 253, 241, 0.55);

  /* The template uses exactly one easing curve, everywhere. */
  --ease: cubic-bezier(0.65, 0, 0.35, 1);

  /* Measured durations */
  --t-reveal:    600ms;
  --t-panel:     900ms;
  --t-accordion: 900ms;
  --t-roll:      500ms;   /* chosen, not measured */
  --t-press:     140ms;

  /* Rhythm */
  --gutter: 40px;
  --shell:  1440px;
  --nav-h:  84px;

  --step-0: 1rem;
  --step-1: 1.125rem;
  --step-2: 1.5rem;
  --step-3: clamp(2rem, 4vw, 3.25rem);
  --step-4: clamp(3rem, 9vw, 8.5rem);
  --step-5: clamp(4rem, 15vw, 15rem);
}

/* --------------------------------------------------------------------------
   2. Reset
   -------------------------------------------------------------------------- */

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

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

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  font-size: var(--step-1);
  line-height: 1.33;
  letter-spacing: -0.02em;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

body.is-locked { overflow: hidden; }

h1, h2, h3, h4, p, figure, blockquote { margin: 0; }
ul, ol { margin: 0; padding: 0; list-style: none; }
img { display: block; max-width: 100%; height: auto; }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }
a { color: inherit; text-decoration: none; }

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
}

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

/* --------------------------------------------------------------------------
   3. Layout shell + the hairline grid
   -------------------------------------------------------------------------- */

.shell {
  width: 100%;
  max-width: var(--shell);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.grid-lines {
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  max-width: var(--shell);
  margin-inline: auto;
  padding-inline: var(--gutter);
  display: grid;
  grid-template-columns: repeat(4, 1fr);
}
.grid-lines span { border-left: 1px solid var(--rule); }
.grid-lines span:first-child { border-left: 0; }

.section {
  position: relative;
  z-index: 1;
  border-bottom: 1px solid var(--rule);
  padding-block: clamp(2.75rem, 5.6vw, 5rem);
}

.section--dark {
  background: var(--ink);
  color: var(--paper);
  border-bottom-color: var(--rule-dark);
}
.section--dark .eyebrow { color: var(--paper-dim); }

.section__head {
  display: grid;
  gap: 1.25rem;
  margin-bottom: clamp(1.75rem, 3.2vw, 2.75rem);
}

.eyebrow {
  font-size: 0.6875rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--muted);
  display: flex;
  align-items: center;
  gap: 0.6rem;
}
.eyebrow::before {
  content: '';
  width: 6px; height: 6px;
  background: var(--accent);
}
/* Removed on request 1 Sep 2026, mobile and desktop both. */
#questions .eyebrow { display: none; }

.section__title {
  /* 6 Sep 2026, Phil: every section title at the about headline's size,
     not step-3. The same two clamps live on .about__text p:first-child. */
  font-size: clamp(2rem, 3.2vw, 2.75rem);
  line-height: 1.02;
  letter-spacing: -0.04em;
  text-transform: uppercase;
  font-weight: 600;
  max-width: 18ch;
}
/* A title that says a whole sentence: the author sets the line break, so a
   single word can never be left on its own. */
/* 6 Sep 2026, Phil: "How I can help" sits 30px lower to close the dead
   space above its cards. Desktop only; the phone spacing is already tight. */
@media (min-width: 641px) {
  #services .section__head { padding-top: 30px; margin-bottom: calc(clamp(1.75rem, 3.2vw, 2.75rem) - 30px); }
}
.section__title--lines { max-width: none; }
.section__title--lines span { display: block; }

.lede {
  color: var(--muted);
  max-width: 58ch;
  line-height: 1.5;
}
.section--dark .lede { color: var(--paper-dim); }

/* --------------------------------------------------------------------------
   4. Loading screen
   Measured: content fades and rises 13.3vh over 600ms; six panels collapse
   height 100% to 0% over 900ms, starting 80ms apart.
   -------------------------------------------------------------------------- */

.loader {
  position: fixed;
  inset: 0;
  z-index: 100;
  background: transparent;
  pointer-events: none;
}

.loader__panels {
  position: absolute;
  inset: 0;
  display: grid;
  grid-template-columns: repeat(6, 1fr);
}

.loader__panel {
  background: var(--ink);
  height: 100%;
  transition: height var(--t-panel) var(--ease);
}

.loader__panel:nth-child(1) { transition-delay: 0ms; }
.loader__panel:nth-child(2) { transition-delay: 80ms; }
.loader__panel:nth-child(3) { transition-delay: 160ms; }
.loader__panel:nth-child(4) { transition-delay: 240ms; }
.loader__panel:nth-child(5) { transition-delay: 320ms; }
.loader__panel:nth-child(6) { transition-delay: 400ms; }

.loader.is-done .loader__panel { height: 0%; }
.loader.is-done, .loader[hidden] { display: none !important; }

.loader__inner {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  align-content: center;
  gap: clamp(3rem, 12vh, 9rem);
  color: var(--paper);
  text-align: center;
  transition: opacity var(--t-reveal) var(--ease),
              transform var(--t-reveal) var(--ease);
}

.loader.is-done .loader__inner {
  opacity: 0;
  transform: translateY(-13.3vh);
}

.loader__mark {
  font-size: 0.75rem;
  letter-spacing: 0.34em;
  text-transform: uppercase;
}

.loader__count {
  font-size: clamp(2.5rem, 7vw, 4.5rem);
  font-weight: 500;
  letter-spacing: -0.05em;
  font-variant-numeric: tabular-nums;
}

.loader__tag {
  font-size: 0.8125rem;
  color: var(--paper-dim);
  letter-spacing: 0.02em;
}

/* --------------------------------------------------------------------------
   5. Navigation - mix-blend-mode difference, so it inverts over dark imagery
   -------------------------------------------------------------------------- */

.nav {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 40;
  height: var(--nav-h);
  mix-blend-mode: difference;
  color: #fff;
}

.nav__inner {
  height: 100%;
  max-width: var(--shell);
  margin-inline: auto;
  padding-inline: var(--gutter);
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.nav__brand {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  font-size: 1rem;
  font-weight: 600;
  letter-spacing: 0.01em;
  text-transform: uppercase;
  visibility: hidden;
  opacity: 0;
  transform: translateY(-0.5rem);
  pointer-events: none;
  transition: opacity 360ms var(--ease), transform 360ms var(--ease), visibility 0s linear 360ms;
}
.nav.is-scrolled .nav__brand {
  visibility: visible;
  opacity: 1;
  transform: none;
  pointer-events: auto;
  transition: opacity 360ms var(--ease), transform 360ms var(--ease), visibility 0s;
}
/* On desktop the nav brand waits until the hero name has scrolled away, so the
   small nav name never cross-fades over the large hero name. */
@media (min-width: 1025px) {
  .nav.is-scrolled .nav__brand {
    visibility: hidden;
    opacity: 0;
    transform: translateY(-0.5rem);
    pointer-events: none;
  }
  .nav.is-past-hero .nav__brand {
    visibility: visible;
    opacity: 1;
    transform: none;
    pointer-events: auto;
  }
}

/* Driven from the scroll job: the brand hides while any large left-aligned
   heading is inside the navigation band, which is where it used to collide. */
.nav.is-brand-hidden .nav__brand {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity 260ms var(--ease), visibility 0s linear 260ms;
}

.nav__brand::before {
  content: '';
  width: 9px; height: 9px;
  background: currentColor;
}

.nav__toggle {
  display: flex;
  align-items: center;
  gap: 0.85rem;
  font-size: 0.75rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  padding: 0.6rem 0;
}

.nav__bars {
  display: grid;
  gap: 4px;
  width: 22px;
}
.nav__bars span {
  height: 1.5px;
  background: currentColor;
  transition: transform 300ms var(--ease), opacity 200ms var(--ease);
}

.nav.is-open .nav__bars span:nth-child(1) { transform: translateY(5.5px) rotate(45deg); }
.nav.is-open .nav__bars span:nth-child(2) { opacity: 0; }
.nav.is-open .nav__bars span:nth-child(3) { transform: translateY(-5.5px) rotate(-45deg); }

/* Menu panel - drops from the navigation column, like the live template. */
.menu {
  position: fixed;
  top: calc(var(--nav-h) + 16px);
  right: max(var(--gutter), calc((100vw - var(--shell)) / 2 + var(--gutter)));
  z-index: 39;
  width: min(320px, calc(100vw - (var(--gutter) * 2)));
  background: var(--paper);
  color: var(--ink);
  border: 1px solid var(--rule);
  display: block;
  opacity: 0;
  transform: translateY(-1rem) scaleY(0.92);
  transform-origin: top right;
  transition: opacity var(--t-reveal) var(--ease),
              transform var(--t-reveal) var(--ease),
              visibility var(--t-reveal) var(--ease);
  visibility: hidden;
}

.menu.is-open {
  opacity: 1;
  transform: none;
  visibility: visible;
}

.menu__list {
  padding: 0;
  display: grid;
  gap: 0;
}

.menu__list a {
  display: block;
  padding: 1rem 1.25rem;
  border-bottom: 1px solid var(--rule);
  font-size: 0.8125rem;
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  line-height: 1.2;
  opacity: 1;
  transition: color 300ms var(--ease), background 300ms var(--ease), transform 300ms var(--ease);
}

@media (hover: hover) and (pointer: fine) {
  .menu__list a:hover { color: var(--paper); background: var(--ink); transform: translateX(0.35rem); }
}

.menu__meta {
  display: none;
}

/* --------------------------------------------------------------------------
   6. Buttons - the live template rolls the duplicate label vertically.
   -------------------------------------------------------------------------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: space-between;
  gap: 2.5rem;
  min-height: 56px;
  padding: 0 1.5rem;
  background: var(--ink);
  color: var(--paper);
  font-size: 0.8125rem;
  font-weight: 500;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  white-space: nowrap;
  transition: background 260ms var(--ease), transform var(--t-press) var(--ease);
}

.btn--ghost {
  background: transparent;
  color: var(--ink);
  border: 1px solid var(--ink);
}
.section--dark .btn--ghost,
.cta .btn--ghost { color: var(--paper); border-color: var(--rule-dark); }

.btn--accent { background: var(--accent); color: var(--ink); }

.btn:active { transform: scale(0.98); }

.roll {
  position: relative;
  display: block;
  overflow: clip;
  height: 1.2em;
  line-height: 1.2;
}
.roll span {
  display: block;
  white-space: nowrap;
  transition: transform var(--t-roll) var(--ease);
}
.roll span:last-child {
  position: absolute;
  top: 1.2em;
  left: 0;
}

@media (hover: hover) and (pointer: fine) {
  .btn:hover .roll span:first-child,
  .btn:hover .roll span:last-child  { transform: translateY(-1.2em); }
  .btn:hover { background: var(--accent); color: #fff; }
  .btn--accent:hover { background: var(--ink); color: var(--paper); }
}

.btn__arrow {
  flex: none;
  width: 16px; height: 16px;
  transition: transform var(--t-roll) var(--ease);
}
@media (hover: hover) and (pointer: fine) {
  .btn:hover .btn__arrow { transform: translateY(-4px); }
}

/* --------------------------------------------------------------------------
   7. Hero - one screen. Copy and a full-height column of photograph.
   Markup is flat and in phone order; the wide layout lifts the photograph out
   of flow rather than reordering anything. See HERO-REDESIGN-SPEC.md.
   -------------------------------------------------------------------------- */

/* No background here on purpose. The page's fixed hairline grid sits at z-index
   0 and shows through every section below, which have no background either. An
   opaque hero would be the only part of the page the grid does not run through. */
.hero {
  position: relative;
  z-index: 1;
  border-bottom: 1px solid var(--rule);
  min-height: 100vh;    /* first, for anything without dvh */
  min-height: 100dvh;   /* second, so current browsers take it */
  display: flex;
  flex-direction: column;
  padding: calc(var(--nav-h) + 12px) var(--gutter) 0;
}

/* -- the photograph ------------------------------------------------------ */

.hero__photo {
  position: relative;
  overflow: hidden;
  /* flex-basis 0 with min-height 0 makes this the element that absorbs
     whatever height is left, and gives it back when there is none. With
     `1 1 auto` plus a 300px floor it grew to its max and pushed the button
     off the bottom of every phone: 950px of hero inside an 844px screen. */
  flex: 1 1 0;
  min-height: 0;
  max-height: min(70vh, 110vw);
  margin: 24px calc(var(--gutter) * -1) 0;
}

/* Each level has to be told to fill the panel. <picture> is display:inline with
   no height of its own, so an img{height:100%} inside it would resolve against
   an auto-height parent and fall back to the intrinsic ratio. */
.hero__photo-inner { display: block; width: 100%; height: 100%; }
.hero__photo picture {
  /* Scroll offset target: no transition, and 7% of overscan top and bottom so
     the 6% scroll movement never drags an empty edge into the panel. */
  display: block;
  width: 100%;
  height: 114%;
  margin-top: -7%;
}
.hero__photo img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 22%;
  filter: saturate(0.86) contrast(1.04);
  /* Pointer offset target. 12px of overscan on every side covers the 8px of
     pointer movement, for the same reason as the picture's 7% above.
     max-width:none is required: the base reset caps every img at 100%, which
     silently clipped the horizontal overscan to zero and left a bare strip
     down the panel's right edge as the pointer moved. */
  width: calc(100% + 24px);
  height: calc(100% + 24px);
  max-width: none;
  margin: -12px;
  transition: transform 600ms var(--spring);
}

/* -- the copy ------------------------------------------------------------ */

/* The claim is the H1 now, so it is sentence case: eight words of uppercase
   at display size is a shout, not a headline. The name below carries the
   page's uppercase signature instead, which keeps the family intact. */
.hero__headline {
  font-size: clamp(1.875rem, 7.6vw, 3rem);
  font-weight: 600;
  line-height: 1.04;
  letter-spacing: -0.035em;
}
.hero__headline > span { display: block; overflow: hidden; }
.hero__headline > span > i { display: block; font-style: normal; }
.hero__headline > span:nth-child(2) { color: rgba(7, 7, 7, 0.4); }

.hero__name {
  margin-top: 20px;
  font-size: 1.625rem;
  font-weight: 600;
  letter-spacing: 0.28em;
  text-transform: uppercase;
}

.hero__role {
  margin-top: 0px;
  font-size: 0.6875rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--muted);
}

.hero__rule {
  height: 1px;
  margin-top: 30px;
  background: rgba(7, 7, 7, 0.16);
  transform-origin: left;
}

.hero__claim {
  margin-top: 18px;
  font-size: 1rem;
  line-height: 1.6;
  letter-spacing: -0.01em;
  max-width: 60ch;
  text-wrap: pretty;
}

.hero__actions {
  display: flex;
  flex-direction: column;
  margin: 26px calc(var(--gutter) * -1) 0;
}
.hero__actions .btn {
  min-height: 62px;
  justify-content: space-between;
  gap: 1rem;
}
.hero__actions .btn + .btn { border-top: 1px solid rgba(255, 253, 241, 0.22); }

/* A stacked layout on something wider than a phone. Full bleed stops working
   here: at 781 x 1024 it crops the portrait to a 1.34 landscape band and fills
   the width with his face. A centred plate keeps a portrait-ish aspect. The
   aspect clause keeps this away from the two-column case below. */
@media (min-width: 481px) and (max-aspect-ratio: 6/5) {
  .hero__photo {
    /* The plate's HEIGHT is whatever the copy leaves over, roughly the viewport
       less about 470px. Tying the width to that keeps the plate square-ish
       instead of a letterbox: a fixed 520px at 900 tall gave a 1.55 band. The
       max() is a floor so a very short viewport cannot drive the width to nothing. */
    width: min(100%, 520px, max(240px, calc(100vh - 470px)));
    /* Flush left, not centred. The name, role, rule, sentence and button all
       share this left edge; a centred plate was the one element floating free
       of it, and it read as unresolved rather than deliberate. */
    align-self: flex-start;
    margin-inline: 0;
  }
}

/* -- short viewports. The problem is height, so the query is height. ------ */

@media (max-height: 720px) {
  .hero__headline { font-size: clamp(1.5rem, 4.6vw, 2.125rem); }
  .hero__name  { margin-top: 14px; font-size: 0.75rem; }
  .hero__role  { margin-top: 7px; }
  .hero__rule  { margin-top: 16px; }
  .hero__claim { margin-top: 14px; font-size: 0.875rem; line-height: 1.55; }
  .hero__actions { margin-top: 18px; }
  .hero__photo { min-height: 180px; margin-top: 16px; }
}

/* A phone held sideways is about 390px tall with a navigation bar in it. */
@media (max-height: 480px) {
  .hero { padding-top: calc(var(--nav-h) * 0.6); }
  .hero__headline { font-size: clamp(1.25rem, 3.4vw, 1.625rem); }
  .hero__name  { margin-top: 10px; font-size: 0.6875rem; }
  .hero__role  { margin-top: 6px; }
  .hero__rule  { margin-top: 10px; }
  .hero__claim { margin-top: 10px; font-size: 0.8125rem; line-height: 1.45; }
  .hero__actions { margin-top: 12px; }
  .hero__actions .btn { min-height: 46px; }
  .hero__photo { min-height: 140px; max-height: 260px; margin-top: 12px; }
}

/* -- phone width: photo as backdrop, on request 26 Aug 2026 (Option 2 from
   the Hero Height Options comparison, picked over a tightened-spacing
   alternative). The photo fills the whole hero box; the copy sits on top of
   it at the bottom over a dark scrim, the same ink used everywhere else on
   the page (.cta__bg::after carries the same technique). .hero is a flex
   column with the default stretch, so pulling .hero's own padding to zero
   and letting .hero__photo bleed inset:0 is what makes it full-bleed; the
   text elements then carry their own padding-inline to hold the page's
   gutter, and .hero__actions keeps stretching edge to edge exactly as it does
   at every other size. */
@media (max-width: 640px) {
  /* Option A, picked from the mobile-landing comparison: the photo leads as
     a fixed-height plate, name/role caption its bottom edge, then the page
     drops onto plain paper for the headline and actions. Every color and
     the button styling below are the same tokens/classes the rest of the
     site already uses at this width - only the hero's internal order and
     the photo's height are new. */
  .hero {
    padding: 0;
    overflow: hidden;
  }

  .hero__photo {
    order: 1;
    position: relative;
    flex: none;
    min-height: 0;
    max-height: none;
    height: 58vh;
    margin: 0 calc(var(--gutter) * -1);
  }
  .hero__photo::after {
    content: "";
    position: absolute;
    inset: auto 0 0 0;
    height: 55%;
    background: linear-gradient(180deg,
      rgba(7, 7, 7, 0) 0%,
      rgba(7, 7, 7, .62) 62%,
      rgba(7, 7, 7, .88) 100%);
    pointer-events: none;
  }

  /* name and role used to sit in normal flex flow with a negative margin
     pulling them up onto the photo - which meant editing either one's size
     shifted where the NEXT element started too, and that shift then carried
     into the headline below it, and so on down the card. Taking both out of
     flow and anchoring each to the photo's own fixed height (58vh, set
     above) breaks that chain: every element below the photo now measures
     from the photo, never from its sibling's rendered box. */
  .hero__name {
    position: absolute;
    top: calc(58vh - 78px);
    left: 0;
    right: 0;
    z-index: 1;
    margin: 0;
    padding-inline: var(--gutter);
    font-size: 1.625rem;
    color: var(--paper);
  }
  .hero__role {
    position: absolute;
    top: calc(58vh - 33px);
    left: 0;
    right: 0;
    z-index: 1;
    margin: 0;
    padding-inline: var(--gutter);
    color: var(--paper-dim);
  }

  .hero__headline {
    order: 4;
    margin-top: 48px;
    padding-inline: var(--gutter);
    font-size: clamp(1.5rem, 7.4vw, 2.125rem);
    /* 1.08 rounded to a line box 1px shorter than the glyphs' own scroll
       height (descenders on g/p/y), so the overflow:hidden reveal mask
       clipped a hairline off every line. 1.16 gives that headroom back. */
    line-height: 1.09; /* 1.16 until 7 Sep 2026; Phil asked for two points tighter on the phone */
    text-transform: uppercase;
  }

  .hero__rule {
    order: 5;
    margin: 18px var(--gutter) 0;
  }

  .hero__actions {
    order: 6;
    margin: 20px var(--gutter) 28px;
  }
  /* The divider between the two stacked buttons was tuned for sitting on
     the dark photo scrim; the block now sits on paper, so it needs the
     same dark, low-opacity rule the rest of the light-background page uses. */
  .hero__actions .btn + .btn { border-top-color: rgba(7, 7, 7, 0.14); }

  /* The -5px nudge on the first headline line (pinned at desktop, 31 Aug) sits
     inside an overflow:hidden reveal span. At mobile's smaller font size that
     shift clips the cap-height off the top of the letters. The base rule is
     unconditional and comes later in the file, so the extra .hero__headline
     here is specificity, not decoration - it's what makes this win. */
  .is-ready .hero__headline.hero__headline > span:nth-child(1) > i { transform: translateY(0); }
}
@media (max-width: 640px) and (prefers-reduced-motion: reduce) {
  .hero__headline.hero__headline > span:nth-child(1) > i { transform: none; }
}

/* -- two columns: only when the viewport is wide AND landscape enough ------
   The gate is an aspect ratio, not a width. At 781 x 1024 a 50% column is 391
   wide and 1024 tall, an aspect of 0.38 against a 0.75 photograph: cover crops
   it to a claustrophobic vertical slice of his face. Below 6/5 the panel would
   be narrower than 0.6 and the stacked layout is simply better. */
@media (min-width: 781px) and (min-aspect-ratio: 6/5) {
  .hero {
    /* The shared edge the copy column's own left padding computes from.
       Untouched by the 1 Sep rebuild below - still the anchor for the LEFT
       side only now that the right side is full-bleed, not gutter-offset. */
    --hero-col-edge: max(var(--gutter), calc(50vw - (var(--shell) / 2) + var(--gutter)));
    /* Rebuilt 1 Sep 2026 (Option A of three, Phil's pick): the plate becomes
       a full-height, full-bleed photograph at roughly half the screen,
       capped so it doesn't dominate a very wide monitor. */
    --hero-photo-w: min(50vw, 720px);
    justify-content: center;
    /* Just above true centre. The navigation carries visual weight at the top,
       so a geometrically centred block reads as sitting low. The right pad
       clears the full-bleed photo plus a fixed gap, not a proportional one -
       the photo's own width no longer scales with the gutter system. */
    padding: calc(var(--nav-h) * 0.8)
             calc(var(--hero-photo-w) + 64px) 0
             calc(var(--hero-col-edge) + 20px);
  }
  /* Full-bleed and full-height: right:0/top:0/bottom:0 rather than a sized,
     inset, vertically-centred plate. Name and role move onto it as a photo
     caption (below), the way they already do on mobile - this is that same
     pattern reaching desktop for the first time, not a new one. */
  .hero__photo {
    position: absolute;
    inset: 0 0 0 auto;
    width: var(--hero-photo-w);
    flex: none;
    min-height: 0;
    max-height: none;
    margin: 0;
  }
  .hero__photo img { object-position: 50% 18%; }
  /* Same scrim technique as the mobile hero and the CTA band - a dark ink
     wash under the caption text, not a filter over the whole photo. */
  .hero__photo::after {
    content: "";
    position: absolute;
    inset: auto 0 0 0;
    height: 40%;
    background: linear-gradient(180deg,
      rgba(7, 7, 7, 0) 0%,
      rgba(7, 7, 7, .55) 60%,
      rgba(7, 7, 7, .82) 100%);
    pointer-events: none;
  }

  /* Name and role caption the photo's bottom edge, on the photo itself now
     rather than on paper beneath it - paper colours would be unreadable on
     the scrim, hence the explicit paper/paper-dim here. */
  .hero__name,
  .hero__role {
    position: absolute;
    left: auto;
    right: 0;
    width: var(--hero-photo-w);
    text-align: center;
    z-index: 1;
    margin: 0;
  }
  .hero__name { bottom: 64px; color: var(--paper); }
  .hero__role { bottom: 34px; color: var(--paper-dim); }

  .hero__headline { font-size: clamp(2.125rem, 3.9vw, 3.5rem); line-height: 1.02; letter-spacing: -0.04em; }
  .hero__rule  { margin-top: 26px; width: min(560px, 100%); }
  .hero__claim { margin-top: 20px; font-size: 1.0625rem; line-height: 1.5; max-width: 500px; }
  .hero__actions {
    flex-direction: row;
    flex-wrap: wrap;
    gap: 12px;
    margin: 32px 0 0;
    align-self: start;
  }
  .hero__actions .btn { min-height: 56px; gap: 2rem; }
  /* Side by side on desktop, so the WhatsApp button keeps all four edges
     (the stacked layouts drop the top edge on purpose). Phil, 7 Sep 2026. */
  .hero__actions .btn + .btn { border-top: 1px solid var(--ink); }

  /* The CTA's two buttons on request 1 Sep 2026: same size and layout as
     the hero's - .doors's own gap (0.75rem) already matched, the label-to-
     arrow gap (1.5rem base) and the centred group didn't. The repeated
     class is specificity, not decoration: the unscoped base rule
     (.cta .doors { justify-content: center }) sits later in the file and
     would otherwise win the tie regardless of this media query. */
  .cta.cta .doors { justify-content: flex-start; }
  .cta .doors .btn { gap: 2rem; }
}

/* The photo is full-bleed/full-height now (inset:0 0 0 auto), so it no
   longer needs a height override on a short viewport - it was only ever
   sized here because the old plate was fixed-height and vertically
   centred. Name/role are bottom-anchored to the photo itself for the same
   reason: a margin-top here would still shift them (position:absolute with
   bottom set still resolves through margin-top), so it's left alone rather
   than carried forward unused. Only the LEFT column's own flow spacing
   still needs compressing on a short window. */
@media (min-width: 781px) and (min-aspect-ratio: 6/5) and (max-height: 720px) {
  .hero        { padding-top: calc(var(--nav-h) * 0.6); }
  .hero__headline { font-size: clamp(1.625rem, 3.1vw, 2.375rem); }
  .hero__rule  { margin-top: 16px; }
  .hero__claim { margin-top: 16px; font-size: 0.9375rem; }
  .hero__actions { margin-top: 24px; }
}
@media (min-width: 781px) and (min-aspect-ratio: 6/5) and (max-height: 480px) {
  .hero        { padding-top: calc(var(--nav-h) * 0.45); }
  .hero__headline { font-size: clamp(1.25rem, 2.5vw, 1.75rem); }
  .hero__rule  { margin-top: 11px; }
  .hero__claim { margin-top: 11px; font-size: 0.8125rem; line-height: 1.45; }
  .hero__actions { margin-top: 16px; }
  .hero__actions .btn { min-height: 46px; }
}

/* -- entrance ------------------------------------------------------------ */

/* The wipe starts from a visible sliver, not from nothing: a clip to zero area
   can delay the Largest Contentful Paint until it is revealed, and nothing in
   the world appears from nothing. */
.hero__photo       { clip-path: inset(0 0 92% 0); }
.hero__photo-inner { transform: scale(1.10); }
.hero__headline > span > i { transform: translateY(106%); }
.hero__rule  { transform: scaleX(0); }
.hero__name,
.hero__role,
.hero__claim,
.hero__actions { opacity: 0; transform: translateY(18px); }

.is-ready .hero__photo {
  clip-path: inset(0 0 0 0);
  /* height is here so the phone-width photo box (its cap is dropped, see
     the mobile block above) eases when iOS Safari's address bar collapses
     or expands mid-scroll, instead of jumping. A no-op on desktop, where
     the box is absolutely positioned and dvh never moves. */
  transition: clip-path 1000ms var(--spring), height 500ms var(--ease);
}
.is-ready .hero__photo-inner {
  transform: scale(1);
  transition: transform 1600ms var(--spring);
}
.is-ready .hero__headline > span > i {
  transform: translateY(0);
  transition: transform 820ms var(--spring);
}
.is-ready .hero__headline > span:nth-child(1) > i { transition-delay: 60ms; transform: translateY(-5px); }
.is-ready .hero__headline > span:nth-child(2) > i { transition-delay: 140ms; transform: translateY(1px); }
.is-ready .hero__rule {
  transform: scaleX(1);
  transition: transform 700ms var(--spring) 340ms;
}
.is-ready .hero__name,
.is-ready .hero__role,
.is-ready .hero__claim,
.is-ready .hero__actions {
  opacity: 1;
  transform: none;
  transition: opacity 600ms var(--spring), transform 600ms var(--spring);
}
.is-ready .hero__name    { transition-delay: 240ms; }
.is-ready .hero__role    { transition-delay: 300ms; }
.is-ready .hero__claim   { transition-delay: 380ms; }
.is-ready .hero__actions { transition-delay: 450ms; }

@media (prefers-reduced-motion: reduce) {
  .hero__photo       { clip-path: none; }
  .hero__photo-inner { transform: none; }
  .hero__headline > span > i { transform: none; }
  .hero__headline > span:nth-child(1) > i { transform: translateY(-5px); }
  .hero__headline > span:nth-child(2) > i { transform: translateY(1px); }
  .hero__rule  { transform: scaleX(1); }
  .hero__name,
  .hero__role,
  .hero__claim,
  .hero__actions { opacity: 1; transform: none; }
  .hero__photo img { transition: none; }
}

/* --------------------------------------------------------------------------
   8. About + the stat band
   -------------------------------------------------------------------------- */

.about__body {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 2rem;
  align-items: start;
}

.about__text {
  grid-column: 1 / 3;
  display: grid;
  gap: 1.5rem;
}

.about__text p {
  font-size: var(--step-2);
  line-height: 1.35;
  letter-spacing: -0.025em;
}
.about__text p:first-child span { display: block; }
.about__text p:first-child {
  /* Raised from step-2 + 1pt on request 6 Sep 2026 ("increase this headline"). */
  font-size: clamp(2rem, 3.2vw, 2.75rem);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: -0.04em;
  line-height: 1.05;
}
.about__text p + p {
  font-size: var(--step-0);
  line-height: 1.6;
  color: var(--muted);
  max-width: 46ch;
}

.about__figure {
  grid-column: 3 / 5;
  aspect-ratio: 4 / 5;
  overflow: hidden;
  background: var(--rule);
}
.about__figure img { width: 100%; height: 100%; object-fit: cover; }

.stats {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  border-top: 1px solid var(--rule);
  margin-top: clamp(2rem, 3.6vw, 3rem);
  width: min(100%, 1100px);
  margin-inline: auto;
}

.stat {
  padding: 2rem 1.5rem 0 0;
  border-left: 1px solid var(--rule);
  padding-left: 1.5rem;
}
.stat:first-child { border-left: 0; padding-left: 0; }

.stat__value {
  font-size: clamp(2rem, 4vw, 3.25rem);
  font-weight: 600;
  letter-spacing: -0.05em;
  line-height: 1;
}
.stat__value [data-stat-count] { display: inline-block; min-width: 1.25ch; font-variant-numeric: tabular-nums; }
.stat:nth-child(3) .stat__value { font-size: clamp(1.65rem, 3vw, 3rem); white-space: nowrap; }

.stat__label {
  margin-top: 0.75rem;
  font-size: 0.6875rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--muted);
}

/* --------------------------------------------------------------------------
   9. Featured property carousel - pure opacity cross-fade, measured
   -------------------------------------------------------------------------- */

.carousel {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 2rem;
  align-items: end;
}

.carousel__stage {
  grid-column: 1 / 4;
  position: relative;
  aspect-ratio: 16 / 10;
  background: var(--panel);
  overflow: hidden;
}

.carousel__slide {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity var(--t-reveal) var(--ease);
}
.carousel__slide.is-active { opacity: 1; }
.carousel__slide img { width: 100%; height: 100%; object-fit: cover; }

.carousel__side {
  grid-column: 4 / 5;
  display: grid;
  gap: 1.75rem;
}

.carousel__count {
  display: flex;
  align-items: baseline;
  gap: 0.35rem;
  font-size: 0.8125rem;
  letter-spacing: 0.1em;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}
.carousel__count b {
  font-size: 1.5rem;
  font-weight: 600;
  color: var(--ink);
  letter-spacing: -0.03em;
}

.listing { display: grid; gap: 1rem; }

.listing__flag {
  justify-self: start;
  font-size: 0.625rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  background: var(--accent);
  color: var(--ink);
  padding: 0.35rem 0.6rem;
}

.listing__name {
  font-size: 1.375rem;
  font-weight: 600;
  letter-spacing: -0.03em;
  text-transform: uppercase;
  line-height: 1.12;
}

.listing__where { font-size: 0.875rem; color: var(--muted); }

.listing__price {
  font-size: 1.75rem;
  font-weight: 600;
  letter-spacing: -0.04em;
  font-variant-numeric: tabular-nums;
}

.listing__specs {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  border-top: 1px solid var(--rule);
  padding-top: 1rem;
  gap: 0.75rem;
}
.listing__specs div { display: grid; gap: 0.3rem; }
.listing__specs dt {
  font-size: 0.625rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
}
.listing__specs dd {
  margin: 0;
  font-size: 0.9375rem;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
}

.listing__ref {
  font-size: 0.6875rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted);
}

.carousel__nav { display: flex; gap: 0.5rem; }
.listing[hidden] { display: none; }

.carousel__btn {
  width: 48px; height: 48px;
  border: 1px solid var(--rule);
  display: grid;
  place-items: center;
  transition: background 240ms var(--ease), color 240ms var(--ease),
              border-color 240ms var(--ease), transform var(--t-press) var(--ease);
}
.carousel__btn:active { transform: scale(0.96); }
@media (hover: hover) and (pointer: fine) {
  .carousel__btn:hover { background: var(--ink); color: var(--paper); border-color: var(--ink); }
}

/* --------------------------------------------------------------------------
   10. Services
   -------------------------------------------------------------------------- */

.services {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  border-top: 1px solid var(--rule);
}

.service {
  position: relative;
  overflow: hidden;
  padding: clamp(2rem, 4vw, 3.5rem) clamp(1.5rem, 3vw, 3rem) clamp(2rem, 4vw, 3.5rem) 0;
  border-left: 1px solid var(--rule);
  padding-left: clamp(1.5rem, 3vw, 3rem);
  display: grid;
  gap: 1.25rem;
  align-content: start;
}
.service:first-child { border-left: 0; padding-left: clamp(1.5rem, 3vw, 3rem); }
.service::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 0;
  background: var(--ink);
  transform: scaleY(0);
  transform-origin: bottom;
  transition: transform var(--t-panel) var(--ease);
}
.service > * { position: relative; z-index: 1; transition: color var(--t-reveal) var(--ease), border-color var(--t-reveal) var(--ease); }

.service__label {
  font-size: 0.6875rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--accent);
}

.service__title {
  font-size: clamp(1.5rem, 2.6vw, 2.25rem);
  font-weight: 600;
  letter-spacing: -0.035em;
  text-transform: uppercase;
  line-height: 1.06;
  max-width: 14ch;
}

.service p { color: var(--muted); line-height: 1.55; font-size: var(--step-0); max-width: 40ch; }

.service .btn { justify-self: start; margin-top: 0.75rem; }

@media (hover: hover) and (pointer: fine) {
  .service:hover::before { transform: scaleY(1); }
  .service:hover .service__title { color: var(--paper); }
  .service:hover p { color: var(--paper-dim); }
  .service:hover .btn--ghost { color: var(--paper); border-color: var(--rule-dark); }
}

/* --------------------------------------------------------------------------
   11. Process - a pinned card, four scroll-driven steps
   -------------------------------------------------------------------------- */

.process { position: relative; }

.process__pin {
  position: sticky;
  top: calc(var(--nav-h) + 36px);
  height: 660px;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 2rem;
  border: 1px solid var(--rule-dark);
  padding: clamp(2rem, 4vw, 3.5rem);
  overflow: hidden;
}

/* The template lets the pinned process card settle into place as it enters. */
html.has-motion [data-scroll-reveal] .process__pin {
  opacity: 0;
  transform: translateY(2.25rem);
  transition: opacity var(--t-reveal) var(--ease), transform var(--t-panel) var(--ease);
}
html.has-motion [data-scroll-reveal].is-in .process__pin {
  opacity: 1;
  transform: none;
}

.process__left { grid-column: 1 / 3; display: grid; grid-template-columns: auto 1fr; align-content: space-between; }

.process__index {
  grid-column: 1;
  grid-row: 1;
  display: flex;
  align-items: baseline;
  gap: 0.4rem;
  font-size: 0.9375rem;
  color: var(--paper-dim);
  font-variant-numeric: tabular-nums;
}
.process__index .roll { display: inline-block; height: 1em; }
.process__index b {
  font-size: clamp(3rem, 7vw, 6rem);
  font-weight: 600;
  letter-spacing: -0.05em;
  color: var(--paper);
  line-height: 1;
}

.process__steps { grid-column: 1 / -1; grid-row: 2; position: relative; }

.process__step {
  position: absolute;
  inset: auto 0 0 0;
  display: grid;
  gap: 1rem;
  opacity: 0;
  transform: translateY(20px);
  transition: opacity var(--t-reveal) var(--ease),
              transform var(--t-reveal) var(--ease);
  pointer-events: none;
}
.process__step.is-active { opacity: 1; transform: none; pointer-events: auto; }

.process__step h3 {
  font-size: clamp(1.75rem, 3.3vw, 3rem);
  font-weight: 600;
  letter-spacing: -0.04em;
  text-transform: uppercase;
  line-height: 1.04;
  max-width: 20ch;
}
.process__step p { color: rgba(255, 253, 241, 0.72); line-height: 1.55; font-size: calc(var(--step-0) + 1pt); max-width: 42ch; }

.process__right {
  grid-column: 3 / 5;
  position: relative;
  overflow: hidden;
  background: var(--panel);
}
.process__art {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity var(--t-reveal) var(--ease);
}
.process__art.is-active { opacity: 1; }
.process__art img { width: 100%; height: 100%; object-fit: cover; }

.process__bar {
  position: absolute;
  left: 0; bottom: 0;
  height: 2px;
  width: 100%;
  background: var(--rule-dark);
}
.process__bar i {
  display: block;
  height: 100%;
  width: 0%;
  background: var(--accent);
}

.process__spacers > div { height: 100vh; }

/* --------------------------------------------------------------------------
   12. CTA band
   -------------------------------------------------------------------------- */

.cta {
  position: relative;
  min-height: 620px;
  display: grid;
  align-items: center;
  overflow: hidden;
  border-bottom: 1px solid var(--rule);
}

.cta__bg {
  position: absolute;
  inset: 0;
  transform: scale(var(--cta-bg-scale, 1));
  transform-origin: center;
  will-change: transform;
}
.cta__bg img { width: 100%; height: 100%; object-fit: cover; }
.cta__bg::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg, rgba(7,7,7,0.88) 0%, rgba(7,7,7,0.55) 60%, rgba(7,7,7,0.3) 100%);
}

.cta__inner {
  position: relative;
  z-index: 1;
  color: var(--paper);
  display: grid;
  gap: 2rem;
  max-width: 46ch;
  opacity: var(--cta-copy-opacity, 1);
  transform: translateY(var(--cta-copy-y, 0));
  will-change: opacity, transform;
}

.cta__title {
  font-size: clamp(2rem, 3.2vw, 2.75rem);
  font-weight: 600;
  letter-spacing: -0.04em;
  text-transform: uppercase;
  line-height: 1.02;
}

.cta__inner p { color: var(--paper-dim); line-height: 1.55; }
.cta .btn { justify-self: start; }

/* --------------------------------------------------------------------------
   13. Insights
   -------------------------------------------------------------------------- */

.insights {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 2rem;
}

.insight { display: grid; gap: 1.25rem; align-content: start; }

.insight__thumb {
  aspect-ratio: 4 / 3;
  overflow: hidden;
  background: var(--rule);
}
.insight__thumb img {
  width: 100%; height: 100%; object-fit: cover;
  transition: transform 700ms var(--ease);
}
@media (hover: hover) and (pointer: fine) {
  .insight:hover .insight__thumb img { transform: scale(1.04); }
}

.insight__meta {
  display: flex;
  gap: 1rem;
  font-size: 0.625rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--muted);
}

.insight__title {
  font-size: 1.25rem;
  font-weight: 600;
  letter-spacing: -0.03em;
  text-transform: uppercase;
  line-height: 1.15;
}

.insight p { font-size: 0.9375rem; color: var(--muted); line-height: 1.55; }

/* --------------------------------------------------------------------------
   14. FAQ accordion - height transition over 900ms, measured
   -------------------------------------------------------------------------- */

.faq__layout {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 2rem;
}
.faq__aside { grid-column: 1 / 2; display: grid; gap: 1.5rem; align-content: start; }
.faq__list  { grid-column: 2 / 5; border-top: 1px solid var(--rule); }

.faq__item { border-bottom: 1px solid var(--rule); }

.faq__q {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 2rem;
  text-align: left;
  padding: 1.5rem 0;
  font-size: clamp(1rem, 1.6vw, 1.25rem);
  font-weight: 500;
  letter-spacing: -0.02em;
  text-transform: uppercase;
  transition: color 240ms var(--ease);
}
@media (hover: hover) and (pointer: fine) {
  .faq__q:hover { color: var(--accent); }
}

.faq__sign {
  flex: none;
  position: relative;
  width: 16px; height: 16px;
  transition: transform 420ms var(--ease);
}
.faq__sign::before, .faq__sign::after {
  content: '';
  position: absolute;
  inset: 50% 0 auto 0;
  height: 1.5px;
  background: currentColor;
}
.faq__sign::after { transform: rotate(90deg); }
.faq__item.is-open .faq__sign { transform: rotate(45deg); }

.faq__a {
  height: 0;
  overflow: hidden;
  transition: height var(--t-accordion) var(--ease);
}
.faq__a > div { padding-bottom: 1.75rem; }
.faq__a p { color: var(--muted); line-height: 1.6; max-width: 62ch; }

/* --------------------------------------------------------------------------
   15. Footer
   -------------------------------------------------------------------------- */

.footer { position: relative; z-index: 1; background: var(--ink); color: var(--paper); padding-block: clamp(3rem, 6vw, 5rem); }

html.has-motion [data-scroll-reveal] .footer__word,
html.has-motion [data-scroll-reveal] .footer__top > :not(.footer__word),
html.has-motion [data-scroll-reveal] .footer__base {
  opacity: 0;
  transform: translateY(2.5rem);
  transition: opacity var(--t-reveal) var(--ease), transform var(--t-panel) var(--ease);
}
html.has-motion [data-scroll-reveal] .footer__word { transform: translateY(4.5rem); }
html.has-motion [data-scroll-reveal].is-in .footer__word,
html.has-motion [data-scroll-reveal].is-in .footer__top > :not(.footer__word),
html.has-motion [data-scroll-reveal].is-in .footer__base {
  opacity: 1;
  transform: none;
}
html.has-motion [data-scroll-reveal] .footer__top > :nth-child(2) { transition-delay: 80ms; }
html.has-motion [data-scroll-reveal] .footer__top > :nth-child(3) { transition-delay: 160ms; }
html.has-motion [data-scroll-reveal] .footer__base { transition-delay: 240ms; }

.footer__top {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, max-content));
  justify-content: start;
  column-gap: clamp(3rem, 8vw, 7rem);
  row-gap: 2rem;
  padding-bottom: 3rem;
  border-bottom: 1px solid var(--rule-dark);
}

.footer__word {
  grid-column: 1 / 3;
  font-size: clamp(2.5rem, 7vw, 5.5rem);
  font-weight: 600;
  letter-spacing: -0.05em;
  text-transform: uppercase;
  line-height: 0.92;
}

.footer__col { display: grid; gap: 0.6rem; align-content: start; font-size: 0.9375rem; }
.footer__heading {
  font-size: 0.625rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--paper-dim);
  margin-bottom: 0.4rem;
}
.footer__col a { color: var(--paper); transition: color 240ms var(--ease); }
@media (hover: hover) and (pointer: fine) {
  .footer__col a:hover { color: var(--accent); }
}

.footer__base {
  padding-top: 2rem;
  display: flex;
  flex-wrap: wrap;
  gap: 1.5rem;
  justify-content: space-between;
  font-size: 0.75rem;
  color: var(--paper-dim);
}

/* --------------------------------------------------------------------------
   16. Guide capture
   -------------------------------------------------------------------------- */

.guide {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: grid;
  place-items: center;
  padding: var(--gutter);
  background: rgba(7, 7, 7, 0.62);
  opacity: 0;
  visibility: hidden;
  transition: opacity 320ms var(--ease), visibility 320ms var(--ease);
}
.guide.is-open { opacity: 1; visibility: visible; }

.guide__card {
  width: min(560px, 100%);
  background: var(--paper);
  padding: clamp(1.75rem, 4vw, 2.75rem);
  display: grid;
  gap: 1.25rem;
  transform: scale(0.96);
  transition: transform 320ms var(--ease);
}
.guide.is-open .guide__card { transform: scale(1); }

.guide__title {
  font-size: clamp(1.5rem, 3vw, 2rem);
  font-weight: 600;
  letter-spacing: -0.04em;
  text-transform: uppercase;
  line-height: 1.05;
}

.guide p { color: var(--muted); font-size: 0.9375rem; line-height: 1.55; }

.guide__form { display: grid; gap: 0.75rem; }

.guide__field { display: grid; gap: 0.4rem; }
.guide__field label {
  font-size: 0.625rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--muted);
}
.guide__field input {
  font: inherit;
  font-size: 1rem;
  padding: 0.85rem 1rem;
  border: 1px solid var(--ink);
  background: #fff;
  color: var(--ink);
}
.guide__field input::placeholder { color: #8a8a8a; }
.guide__field input:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }

.guide__close {
  justify-self: end;
  font-size: 0.6875rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--muted);
}

.guide__note { font-size: 0.75rem; }

/* --------------------------------------------------------------------------
   17. Responsive
   -------------------------------------------------------------------------- */

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


  .about__body, .carousel, .faq__layout { grid-template-columns: repeat(2, 1fr); }
  .about__text, .about__figure, .carousel__stage, .carousel__side,
  .faq__aside, .faq__list { grid-column: 1 / 3; }

  .stats { grid-template-columns: repeat(2, 1fr); }
  .stat:nth-child(3) { border-left: 0; padding-left: 0; }
  .stat { padding-top: 1.5rem; }

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

  .process__pin {
    grid-template-columns: 1fr;
    top: calc(var(--nav-h) + 24px);
    height: min(660px, calc(100vh - var(--nav-h) - 36px));
    min-height: 0;
  }
  .process__left { grid-column: 1; }
  .process__right { display: none; }

  .footer__top { grid-template-columns: repeat(2, 1fr); }
  .footer__word { grid-column: 1 / 3; margin-bottom: 1.5rem; }
}

@media (max-width: 640px) {
  :root { --gutter: 20px; }

  body { font-size: 1rem; }

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


  .about__body, .carousel, .faq__layout, .services,
  .insights, .footer__top, .stats { grid-template-columns: 1fr; }

  .about__text, .about__figure, .carousel__stage, .carousel__side,
  .faq__aside, .faq__list, .footer__word { grid-column: 1; }

  .service, .stat { border-left: 0; padding-left: 0; }
  .service + .service, .stat + .stat { border-top: 1px solid var(--rule); padding-top: 2rem; }

  .process__pin { padding: 1.5rem; }
  .process__spacers > div { height: 60vh; }

  .listing__specs { grid-template-columns: repeat(3, 1fr); gap: 0.5rem; }
}

/* --------------------------------------------------------------------------
   18. Animation-spec v2 motion layer
   -------------------------------------------------------------------------- */

/* Native implementation: the spec's Lenis dependency remains deliberately
   absent until Phil approves the local third-party file. */
:root {
  --spring: cubic-bezier(0.22, 0.7, 0.25, 1);
  --spring-soft: cubic-bezier(0.28, 0.8, 0.32, 1);
}

.loader__panels { grid-template-columns: repeat(4, 1fr); }
.loader__panel { border-inline: 0; }
.loader__panel:nth-child(5), .loader__panel:nth-child(6) { display: none; }

.nav.is-light { mix-blend-mode: normal; color: var(--paper); background: var(--ink); }
.menu__list a { display: flex; align-items: center; gap: .65rem; }
.menu__list a i { width: 6px; height: 6px; border-radius: 50%; background: currentColor; flex: none; }
@media (hover: hover) and (pointer: fine) {
  /* The left/right padding here was being cancelled out exactly by the
     matching negative margin-inline (kept, so the hover box's outer edge
     still lines up with the rest of the menu) - net zero, so the bullet
     and label sat flush against the box edge. The extra 30px on the left
     is real, visible indent on top of that. */
  .menu__list a { color: #7b7b7b; padding: .7rem .8rem .7rem calc(.8rem + 30px); margin-inline: -.8rem; border: 1px solid transparent; transition: color 300ms var(--ease), background 300ms var(--ease), border-color 300ms var(--ease), letter-spacing 300ms var(--ease); }
  .menu__list a:hover { color: var(--ink); background: #fff; border-color: var(--rule); letter-spacing: .03em; }
}


/* Four reveal directions, fired once when an element first enters view. */
html.has-motion [data-reveal] { opacity: 0; transition: opacity 700ms var(--spring), transform 700ms var(--spring); transition-delay: var(--reveal-delay, 0ms); }
html.has-motion [data-reveal="rise"] { transform: translateY(100px); }
html.has-motion [data-reveal="small-rise"] { transform: translateY(20px); }
html.has-motion [data-reveal="drop"] { transform: translateY(-20px); transition-timing-function: var(--spring-soft); }
html.has-motion [data-reveal="left"] { transform: translateX(-100px); }
html.has-motion [data-reveal="right"] { transform: translateX(100px); }
html.has-motion [data-reveal].is-in { opacity: 1; transform: none; }
.section:not(#process) { contain: paint; }

.carousel__stage { position: relative; }
.carousel__stage img { transition: transform 600ms var(--ease); }
@media (hover: hover) and (pointer: fine) { .carousel__stage:hover img { transform: scale(1.1); } }
.follow-cursor { position: fixed; z-index: 50; display: grid; grid-template-columns: 1fr auto; align-items: center; gap: .65rem; padding: .7rem .9rem; border-radius: 999px; background: var(--ink); color: var(--paper); font-size: .625rem; letter-spacing: .12em; text-transform: uppercase; pointer-events: none; opacity: 0; transform: translate3d(-50%, -50%, 0) scale(.9); transition: opacity 200ms var(--ease), transform 200ms var(--ease); }
.follow-cursor.is-visible { opacity: 1; transform: translate3d(-50%, -50%, 0) scale(1); }
.follow-cursor span { font-size: 1rem; line-height: 1; }

.service::before { background: rgba(7,7,7,.88); }
.service::after { content: ''; position: absolute; inset: 0; z-index: 0; background: rgba(0,0,0,.5); opacity: 0; transition: opacity 300ms var(--ease); }
@media (hover: hover) and (pointer: fine) { .service:hover::after { opacity: 1; } }

.process__pin { top: 180px; }
.process__steps { opacity: 0; transform: translateY(-20px); transition: opacity 700ms var(--spring-soft) 200ms, transform 700ms var(--spring-soft) 200ms; }
[data-scroll-reveal].is-in .process__steps { opacity: 1; transform: translateY(0); }

/* The stat band stays compact, with labels centred under their figures. */
.stats { column-gap: clamp(1rem, 2vw, 2rem); align-items: start; }
.stat { min-height: 9rem; display: grid; align-content: start; justify-items: center; text-align: center; }
@media (max-width: 640px) { .stat { min-height: 0; } }
/* On request 1 Sep 2026: centred between the band's own top rule and the
   section's bottom rule. 99px matches the section's own bottom padding at
   the width this was checked against - a fluid match isn't possible
   without duplicating #about's own layout, and this is a one-section fix. */
@media (min-width: 1025px) { .stat { padding-top: 99px; } }

/* The CTA now has its own slow timed entrance, rather than tracking scroll. */
.cta__bg { transform: scale(.4); opacity: 1; transition: transform 4000ms var(--spring), filter 4000ms var(--spring); filter: brightness(.8); }
.cta.is-in .cta__bg { transform: scale(1); filter: brightness(1); }
.cta__inner { opacity: 1; transform: none; }

@media (hover: hover) and (pointer: fine) { .insight:hover .insight__thumb img { transform: scale(1.1); } }
.card-link { display: inline-flex; align-items: center; gap: .55rem; align-self: start; font-size: .6875rem; letter-spacing: .15em; text-transform: uppercase; }
.roll--x { min-width: 9rem; }
.roll--x span { display: inline-block; }
.roll--x span:last-child { top: 0; left: calc(100% + .8rem); }
@media (hover: hover) and (pointer: fine) { .card-link:hover .roll--x span { transform: translateX(calc(-100% - .8rem)); } }

.footer__word { will-change: transform; transform: translateY(var(--footer-drift, 0)); }
.nav-scheme-marker { height: 1px; background: transparent; }

@media (max-width: 1024px) {
  .process__pin { top: calc(var(--nav-h) + 108px); }
}
@media (max-width: 640px) {
  .process__pin { top: calc(var(--nav-h) + 54px); }
}

/* --------------------------------------------------------------------------
   Mobile-only V1.1 — desktop V1 is intentionally locked.
   -------------------------------------------------------------------------- */
@media (max-width: 640px) {
  /* Keep navigation text readable when it crosses a property image. */
  .nav.is-scrolled {
    mix-blend-mode: normal;
    color: var(--paper);
    background: rgba(7, 7, 7, .94);
  }
  .nav__brand,
  .nav__toggle { min-height: 44px; }
  .menu__list a,
  .card-link,
  .footer__col a {
    min-height: 44px;
    display: flex;
    align-items: center;
  }
  /* 7 Sep 2026: Phil nudged the second link in each footer column 17 to 21px
     closer to the first on the phone. Written as the column's own spacing:
     no grid gap, and a 36px row instead of 44, so both columns tighten alike. */
  .footer__col { gap: 0; }
  .footer__col a { min-height: 36px; }
  /* One rhythm, measured: 16px from heading to first link, 16px between the
     two links (text edge to text edge), in both columns. */
  .footer__heading { margin-bottom: 0.5rem; }
  /* And the dead space either side of the rule, and under the copyright line
     (his pins 5 and 6): 24px above the rule, 24px below, 28px under the
     copyright line. */
  .footer__top { padding-bottom: 1rem; }
  .footer__base { padding-top: 1.5rem; gap: 1rem; }
  .footer { padding-bottom: 1.75rem; }


  /* Match the desktop reveal: a full-bleed portrait sits behind the copy and
     the cream mask opens a growing circular window over it, so scrolling
     reveals more of Ahmad rather than zooming a fixed crop. */

  /* Keep the introduction as one responsive sentence so it settles to two
     lines, rather than retaining the desktop's forced three-line split. */
  .about__text p:first-child {
    /* Raised from clamp(1rem, 5vw, 1.3rem) on request 6 Sep 2026; both lines
       stay nowrap, and the longer one still fits at 320px. */
    font-size: clamp(1.4rem, 7.2vw, 1.75rem);
    line-height: 1.05;
    letter-spacing: -0.04em;
  }
  .about__text p:first-child span { display: block; white-space: nowrap; }
  .about__text p:first-child span + span { margin-left: 0; }

  .stat:nth-child(3) .stat__value { font-size: 2rem; }
  /* Centre each stat on the true vertical axis: drop the desktop right-padding
     and shrink-wrap value + label so neither sits off-centre. */
  .stat { padding-right: 0; }
  .stat__value,
  .stat__label { width: max-content; max-width: 100%; margin-inline: auto; text-align: center; }

  /* Listings retain their hierarchy without the desktop-size gaps. */
  .carousel__side { gap: 1.25rem; position: relative; }
  /* Sit the prev/next arrows in the empty right-hand space beside the price,
     rather than top-right by the counter, so the listing reads as one block. */
  .carousel__nav { position: absolute; top: 8.6rem; right: 0; }
  .carousel__btn { width: 44px; height: 44px; }
  .listing { gap: .65rem; }
  .listing__name { font-size: 1.25rem; line-height: 1.1; }
  .listing__price { font-size: 1.625rem; }
  .listing__specs { margin-block: .25rem; padding-top: .75rem; }
  .listing__ref { margin-top: .25rem; }

  /* A narrow viewport is touch-first. Hide pointer-only affordances and use
     the same panel-fill motion when a service card is touched. */
  .follow-cursor { display: none !important; }
  .service:hover::before { transform: scaleY(0); }
  .service:hover::after { opacity: 0; }
  .service:hover .service__title { color: var(--ink); }
  .service:hover p { color: var(--muted); }
  .service:hover .btn--ghost { color: var(--ink); border-color: var(--ink); }
  .service.is-touch-active::before { transform: scaleY(1); }
  .service.is-touch-active .service__title { color: var(--paper); }
  .service.is-touch-active p { color: var(--paper-dim); }
  .service.is-touch-active .btn--ghost { color: var(--paper); border-color: var(--rule-dark); }
  .service.is-mobile-scroll-wipe::before { transform: scaleY(1); }
  .service.is-mobile-scroll-wipe .service__title { color: var(--paper); }
  .service.is-mobile-scroll-wipe p { color: var(--paper-dim); }
  .service.is-mobile-scroll-wipe .btn--ghost { color: var(--paper); border-color: var(--rule-dark); }
  .service,
  .service:first-child { padding-inline: 1.5rem; }
  .btn:active .roll span:first-child,
  .btn:active .roll span:last-child { transform: translateY(-1.2em); }
  .card-link:active .roll--x span { transform: translateX(calc(-100% - .8rem)); }
  .insight__thumb:active img { transform: scale(1.06); }

  /* The desktop process artwork crossfades beneath its copy on mobile instead
     of disappearing at the tablet breakpoint. */
  .process__pin {
    grid-template-rows: minmax(0, 1fr) 11rem;
    gap: 1rem;
  }
  /* grid-column:1 left both panels sitting inside a single track of the
     desktop 4-column grid (25%/50% of the card) instead of the card's full
     width - the image in particular read as a narrow strip. 1/-1 spans every
     track regardless of how many the desktop rule declares. */
  .process__left { grid-column: 1 / -1; grid-row: 1; min-height: 0; }
  .process__right {
    display: block;
    grid-column: 1 / -1;
    grid-row: 2;
    min-height: 11rem;
  }

  /* On a phone each active process step begins beside its number, with the
     artwork and progress line still visible below rather than under the fold. */
  .process__pin {
    --process-art-size: min(calc(100vw - 6.5rem), 18.4375rem);
    grid-template-rows: minmax(0, 1fr) var(--process-art-size);
    /* The step text is absolutely positioned and now sits 40px lower (see
       .process__step below) without its own row growing to match, so it was
       overflowing into the image row beneath it. The extra 40px here is that
       same shift, added back as clearance. */
    gap: calc(.5rem + 40px);
  }
  /* On request 1 Sep 2026: the jump row moved off the "01 / 04" line onto
     its own line beneath it, sized down so it reads as a secondary control
     rather than repeating the index at the same weight. The repeated class
     is specificity, not decoration: the base rule sits later in the file
     and would otherwise win the tie. */
  .process__left { grid-template-rows: auto auto 1fr; row-gap: 10px; }
  .process__jump.process__jump {
    grid-column: 1 / -1;
    grid-row: 2;
    justify-self: start;
    align-self: start;
    margin: 0;
  }
  /* Same specificity problem as .process__jump.process__jump above: the
     unscoped base button rule (width:46px) sits later in the file and would
     win the tie against an equal-specificity mobile rule. */
  .process__jump.process__jump button { width: 37px; height: 37px; font-size: 0.55rem; }
  .process__jump.process__jump { gap: 0.4rem; }
  .process__steps { grid-row: 3; min-height: 11rem; }
  /* Phil nudged step 4's heading and copy down 40px to close the gap under
     the 01-04 jump row; applied to every step here, not just the one he
     happened to be looking at, since the gap is the same on all four. */
  .process__step { inset: 40px 0 auto 0; }
  /* Let the longest step heading settle to three lines rather than four:
     drop the tablet font a step and give the copy the column's full width. */
  .process__step h3 { font-size: 1.5rem; max-width: none; }
  .process__right {
    min-height: 0;
    height: var(--process-art-size);
    transform: translateY(var(--process-art-shift, 0px));
    transition: transform var(--t-reveal) var(--ease);
  }
  .process__bar {
    left: 0;
    right: 0;
    bottom: 0;
    width: auto;
    height: 3px;
  }

  /* Preserve readable CTA copy throughout the existing slow image zoom. The
     dark section backdrop means the image can build in from scale .4 without
     exposing cream behind it, so the copy stays on ink the whole way. */
  .cta { background: var(--ink); }
  .cta__bg { filter: brightness(.66); }
  .cta.is-in .cta__bg { filter: brightness(.66); }
  /* --step-3's clamp floor (2rem) still ran to three lines on a phone;
     1.625rem is the largest size this container's width still settles onto
     two lines at, checked against the current copy. */
  .cta__title { font-size: 1.625rem; }
  .section__title { font-size: clamp(1.4rem, 7.2vw, 1.75rem); }
  .cta__bg::after {
    /* Lightened 26 Aug 2026 (Option A from the fix comparison) - the .82/.72
       version buried the photo under the scrim almost entirely. */
    background: linear-gradient(180deg, rgba(7,7,7,.50) 0%, rgba(7,7,7,.35) 100%);
  }
}

/* --------------------------------------------------------------------------
   19. Reduced motion
   -------------------------------------------------------------------------- */



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

  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    transition-delay: 0ms !important;
  }

  [data-reveal] { opacity: 1 !important; transform: none !important; }
  .cta__bg { transform: scale(1); filter: none; }

  /* The pinned card becomes four stacked static blocks. */
  .process__pin { position: relative; top: auto; height: auto; }
  .process__steps { position: static; display: grid; gap: 2.5rem; }
  .process__step { position: relative; inset: auto; opacity: 1; transform: none; }
  .process__spacers { display: none; }
  .process__right { display: none; }
}

/* Reduce Motion still shows the two signature mobile effects, as gentle colour /
   opacity changes (no large movement), rather than suppressing them entirely. */
@media (max-width: 640px) and (prefers-reduced-motion: reduce) {
  .service::before { transform: scaleY(1); opacity: 0; transition: opacity 300ms var(--ease) !important; }
  .service.is-mobile-scroll-wipe::before,
  .service.is-touch-active::before { opacity: 1; }

  .cta__bg { transform: none; opacity: 0; transition: opacity 900ms var(--ease) !important; }
  .cta.is-in .cta__bg { transform: none; opacity: 1; }
}


/* --------------------------------------------------------------------------
   14. Round two - film, photography plates, fee, consultation, step jump
   Added 26 Aug 2026. Same language as the rest of the page: hairlines, sharp
   corners, uppercase micro-labels, one accent.
   -------------------------------------------------------------------------- */

/* -- doors: WhatsApp and the booking link always travel together ---------- */
.doors { display: flex; flex-wrap: wrap; gap: 0.75rem; }
.doors .btn { gap: 1.5rem; }
.service .doors { margin-top: 0.75rem; }
.cta .doors { justify-content: center; }

/* -- the film ------------------------------------------------------------ */
.film { display: grid; gap: clamp(1.5rem, 3vw, 2.25rem); }
.film__copy { display: grid; gap: 0.9rem; max-width: 60ch; }
.film__note {
  font-size: 0.6875rem; letter-spacing: 0.16em;
  text-transform: uppercase; color: var(--accent);
}

.film__stage {
  position: relative;
  /* Full-bleed: breaks out of .shell's max-width and side padding to run
     edge to edge, rather than sitting at the content column's own width
     (which is what "100%" here actually meant before - the shell was
     already capping it). Safe against the body's overflow-x: hidden. */
  width: 100vw;
  margin-inline: calc(-50vw + 50%);
  aspect-ratio: 16 / 9;
  background: var(--ink);
  overflow: hidden;
}
.film__poster {
  position: absolute; inset: 0;
  display: block; width: 100%; height: 100%; padding: 0;
}
.film__poster img {
  width: 100%; height: 100%; object-fit: cover;
  filter: saturate(0.86) brightness(0.7);
  transition: transform 900ms var(--ease), filter 600ms var(--ease);
}
.film__play {
  position: absolute; left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  width: 84px; height: 84px;
  display: grid; place-items: center;
  border: 1px solid rgba(255, 253, 241, 0.65);
  color: var(--paper);
  transition: background 300ms var(--ease), color 300ms var(--ease),
              border-color 300ms var(--ease), transform var(--t-press) var(--ease);
}
.film__play svg { width: 26px; height: 26px; }
.film__label {
  position: absolute; left: 1.5rem; bottom: 1.25rem;
  color: var(--paper);
  font-size: 0.6875rem; letter-spacing: 0.18em; text-transform: uppercase;
}
@media (hover: hover) and (pointer: fine) {
  .film__poster:hover img { transform: scale(1.04); filter: saturate(0.9) brightness(0.78); }
  .film__poster:hover .film__play { background: var(--accent); color: var(--ink); border-color: var(--accent); }
}
.film__poster:active .film__play { transform: translate(-50%, -50%) scale(0.96); }
.film__stage iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }
.film__fallback { display: none; }

/* -- photography plates. No names, no prices, no specs. ------------------- */
.plates {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-template-rows: 1fr 1fr;
  gap: 1.25rem;
  height: clamp(360px, 44vw, 600px);
}
.plate { display: grid; grid-template-rows: minmax(0, 1fr) auto; min-height: 0; }
.plate img,
.plate__placeholder { width: 100%; height: 100%; min-height: 0; }
.plate img { object-fit: cover; }
.plate__placeholder {
  display: grid;
  place-items: center;
  padding: 1.5rem;
  background-color: var(--ink);
  background-image:
    linear-gradient(135deg, transparent 49.8%, var(--rule-dark) 50%, transparent 50.2%),
    linear-gradient(45deg, transparent 49.8%, var(--rule-dark) 50%, transparent 50.2%);
  color: var(--paper-dim);
  text-align: center;
  font-size: 0.6875rem;
  letter-spacing: 0.16em;
  line-height: 1.5;
  text-transform: uppercase;
}
.plate figcaption {
  padding-top: 0.7rem;
  font-size: 0.6875rem; letter-spacing: 0.16em;
  text-transform: uppercase; color: var(--muted);
}
.plate--tall   { grid-column: 1 / 2; grid-row: 1 / 3; }
.plate--wide   { grid-column: 2 / 5; grid-row: 1 / 2; }
.plate--square { grid-column: 2 / 5; grid-row: 2 / 3; }
.plates__note {
  margin-top: 1.25rem;
  font-size: 0.6875rem; letter-spacing: 0.16em;
  text-transform: uppercase; color: var(--accent);
}
.developer-line {
  max-width: 62ch;
  margin-top: 1rem;
  color: var(--muted);
  font-size: var(--step-0);
  line-height: 1.6;
}
.developer-line span {
  margin-right: 0.6rem;
  color: var(--ink);
  font-size: 0.6875rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

/* -- how I get paid ------------------------------------------------------ */
.fee__head { display: grid; gap: 0.85rem; margin-bottom: clamp(1.5rem, 3vw, 2.25rem); }
.fee__lead {
  font-size: var(--step-3);
  font-weight: 600; letter-spacing: -0.04em; line-height: 1;
  text-transform: uppercase;
  color: var(--accent);
}
/* The commission line as a sentence, a quarter smaller than the display
   lead, on request 6 Sep 2026. Same face, weight, tracking and colour. */
.fee__lead--sentence { font-size: calc(var(--step-3) * 0.75); line-height: 1.08; }
.fee__lead--sentence span { display: block; }
/* 6 Sep 2026: "The developer." in ink; the bracketed price line smaller, still red. */
.fee__lead--sentence span:first-child { color: var(--ink); }
.fee__lead--sentence span + span { font-size: calc(var(--step-3) * 0.55); margin-top: 0.35rem; }
.faq__a p + p { margin-top: 0.9rem; }

/* 7 Sep 2026, option A: the question becomes the small marked label, the
   answer is the one big line, the price line a short footnote with a red
   dash. "The developer." set five sizes below the mock, on request. */
.fee__head--a,
.section__head--lead { gap: 1.5rem; }
.fee__q,
.head__label {
  font-size: 0.6875rem; letter-spacing: 0.18em; text-transform: uppercase;
  font-weight: 500; color: var(--muted);
  display: flex; align-items: center; gap: 0.6rem; max-width: none;
}
.fee__q::before,
.head__label::before { content: ''; width: 6px; height: 6px; background: var(--accent); flex: none; }
.fee__answer,
.head__big {
  max-width: 16ch;
  font-size: clamp(2.25rem, 4.6vw, 4rem);
  line-height: 0.95; letter-spacing: -0.05em; font-weight: 600; text-transform: uppercase;
}
.fee__note,
.head__note { display: grid; grid-template-columns: 56px 1fr; gap: 1rem; align-items: start; max-width: 52ch; }
.fee__note i,
.head__note i { display: block; height: 2px; background: var(--accent); margin-top: 0.72em; }
.fee__note p,
.head__note p { color: var(--ink); font-size: 1.0625rem; line-height: 1.45; letter-spacing: -0.01em; }
@media (max-width: 640px) {
  .fee__head--a { gap: 1.1rem; }
  .fee__note,
  .head__note { grid-template-columns: 36px 1fr; gap: 0.75rem; }
}

.fee__body {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(1.5rem, 3vw, 2.5rem);
  border-top: 1px solid var(--rule);
  padding-top: clamp(1.5rem, 3vw, 2.25rem);
}
.fee__body p { color: var(--muted); line-height: 1.6; font-size: var(--step-0); max-width: 48ch; }

/* -- the four steps, clickable as well as scrollable ---------------------- */
/* align-self: end used to sit this level with the "/ 04" caption at the
   BOTTOM of the index row - correct in theory, but "01" is set so much
   taller than "/ 04" that bottom-aligning read as sitting well below both,
   not beside them. center puts the buttons on the same line as the whole
   "01 / 04" group instead (on request 1 Sep 2026). Mobile overrides this
   via the higher-specificity .process__jump.process__jump rule below and
   is unaffected. */
.process__jump { grid-column: 2; grid-row: 1; justify-self: end; align-self: center; display: flex; gap: 0.5rem; margin: 0 -7px 0 0; }
.process__jump button {
  width: 46px; height: 46px;
  border: 1px solid var(--rule-dark);
  color: var(--paper-dim);
  font-size: 0.6875rem; letter-spacing: 0.1em;
  font-variant-numeric: tabular-nums;
  transition: color 260ms var(--ease), border-color 260ms var(--ease),
              background 260ms var(--ease), transform var(--t-press) var(--ease);
}
.process__jump button[aria-current="step"] {
  color: var(--ink); background: var(--paper); border-color: var(--paper);
}
.process__jump button:active { transform: scale(0.96); }
@media (hover: hover) and (pointer: fine) {
  .process__jump button:hover { color: var(--paper); border-color: var(--paper); }
  .process__jump button[aria-current="step"]:hover { color: var(--ink); }
}
/* Reduced motion shows all four steps at once, so jumping has nothing to do. */
@media (prefers-reduced-motion: reduce) { .process__jump { display: none; } }

/* -- the private consultation -------------------------------------------- */
.consult {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: clamp(2rem, 4vw, 3.5rem);
  align-items: start;
}
.consult__aside { grid-column: 1 / 3; display: grid; gap: 1.4rem; align-content: start; }
.consult__alt { font-size: var(--step-0); color: var(--muted); line-height: 1.5; }
.consult__alt a { border-bottom: 1px solid var(--accent); }

.consult__form {
  grid-column: 3 / 5;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1.4rem 1.5rem;
}
.field { display: grid; gap: 0.5rem; min-width: 0; }
.field label {
  font-size: 0.6875rem; letter-spacing: 0.16em;
  text-transform: uppercase; color: var(--muted);
}
.field input[type="text"],
.field input[type="email"],
.field select {
  font: inherit;
  font-size: var(--step-0);
  letter-spacing: -0.01em;
  color: var(--ink);
  background: transparent;
  border: 0;
  border-bottom: 1px solid var(--rule-input);
  border-radius: 0;
  padding: 0.55rem 0;
  min-height: 48px;
  width: 100%;
  appearance: none;
  transition: border-color 260ms var(--ease);
}
.field input::placeholder { color: var(--muted); opacity: 1; }
.field input:focus,
.field select:focus { border-bottom-color: var(--ink); }
.field select {
  padding-right: 1.5rem;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none'%3E%3Cpath d='M3 6l5 5 5-5' stroke='%235c5c5c' stroke-width='1.5'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 0 center;
  background-size: 16px 16px;
}
.field--check {
  grid-column: 1 / -1;
  display: flex; align-items: flex-start; gap: 0.75rem;
  font-size: 0.875rem; line-height: 1.5; color: var(--muted);
  cursor: pointer;
}
.field--check input { flex: none; width: 18px; height: 18px; margin-top: 2px; accent-color: var(--accent); }
.consult__submit { grid-column: 1 / -1; justify-self: start; }
.field__note {
  grid-column: 1 / -1;
  font-size: 0.875rem; line-height: 1.5; color: var(--ink);
  border-left: 2px solid var(--accent); padding-left: 0.9rem;
}

/* -- tablet and phone ----------------------------------------------------- */
@media (max-width: 900px) {
  .plates {
    grid-template-columns: repeat(2, 1fr);
    grid-template-rows: auto;
    height: auto;
  }
  .plate--tall   { grid-column: 1 / 2; grid-row: auto; aspect-ratio: 3 / 4; }
  .plate--wide   { grid-column: 2 / 3; grid-row: auto; aspect-ratio: 3 / 4; }
  .plate--square { grid-column: 1 / -1; grid-row: auto; aspect-ratio: 16 / 9; }
  .plate { grid-template-rows: auto auto; }
  .plate img,
  .plate__placeholder { aspect-ratio: inherit; }

  .fee__body { grid-template-columns: 1fr; }
  .consult { grid-template-columns: 1fr; }
  .consult__aside, .consult__form { grid-column: 1 / -1; }
}

@media (max-width: 640px) {
  .plates { grid-template-columns: 1fr; }
  .plate--tall, .plate--wide { grid-column: 1 / -1; aspect-ratio: 1 / 1; }
  .plate--square { aspect-ratio: 1 / 1; }

  .consult__form { grid-template-columns: 1fr; }
  /* Stacked and touching, no gap - the same format the hero actions use.
     .service .btn's own margin-top (for a grid context elsewhere) was the
     actual gap between the two buttons; .doors's margin-top already spaces
     the block from the copy above, so the per-button one just resets here. */
  .doors { flex-direction: column; align-items: stretch; gap: 0; }
  .service .btn { margin-top: 0; }
  .doors .btn { width: 100%; justify-content: space-between; }
  .film__play { width: 64px; height: 64px; }
  .film__play svg { width: 20px; height: 20px; }
  .film__label { display: none; }
  .consult__submit { justify-self: stretch; width: 100%; }
  /* .section's own clamp resolves to 44px at this width; 20px off each side. */
  #questions { padding-block: 24px; }
  /* 7 Sep 2026, Phil's pin: "Questions" sits 30px lower on the phone, the
     list stays where it was (the layout gap gives the 30px back). */
  #questions .faq__aside { padding-top: 30px; }
  #questions .faq__layout { gap: 2px; }
}
