/* ===========================================================================
   REVISE · 26 September 2026
   Loaded last, on purpose. base -> desktop -> mobile -> revise.

   Four things Andy asked for, in the order he asked for them:
     1. the mobile hero must show the building and all four units, and stop
        being dark
     2. mobile generally: more appealing, better optimised
     3. a real location map, zoomed out, cleaner, eight to ten of the best
     4. a fact block that is simpler and more legible

   Plus the section that carries the builder's argument, and the traverse
   that replaced the ascent.
   =========================================================================== */

:root {
  --gv-line: color-mix(in oklab, var(--bone) 16%, transparent);
}

/* ===========================================================================
   1 · THE FACT BLOCK
   Was four soft facts in one row. Now six hard ones, each with its unit
   underneath so the numeral can be big without the label crowding it.
   Two up on a phone, three up from 700px, six across on a wide screen.
   =========================================================================== */
.statement__facts {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1px;
  background: var(--rule);
  border: 1px solid var(--rule);
  margin-top: clamp(2rem, 5vw, 3.5rem);
}
.statement__facts > div {
  background: var(--ground);
  padding: clamp(1rem, 3.2vw, 1.6rem) clamp(0.9rem, 3vw, 1.5rem);
  display: grid;
  align-content: start;
  gap: 0.15rem;
  min-height: 0;
}
.statement__facts dt {
  font-family: var(--sans);
  font-size: var(--t-label);
  letter-spacing: 0.17em;
  text-transform: uppercase;
  color: var(--ink-faint);
}
.statement__facts dd {
  margin: 0;
}
.statement__facts dd.display {
  font-family: var(--serif);
  font-weight: 300;
  font-size: clamp(2.1rem, 7.5vw, 3.1rem);
  line-height: 1;
  letter-spacing: -0.01em;
  color: var(--ink);
  margin-top: 0.3rem;
}
/* Specificity note: mobile.css carries a `.statement__facts dd` rule, which is
   (0,1,1). A bare `.fact__u` is (0,1,0) and loses, which is why the unit line
   was rendering at display size. Matched here at (0,2,1). */
.statement__facts dd.fact__u {
  font-family: var(--sans);
  font-size: clamp(0.66rem, 2.7vw, 0.74rem);
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--ink-faint);
  margin-top: 0.45rem;
  line-height: 1.45;
  letter-spacing: 0.1em;
}
@media (min-width: 700px)  { .statement__facts { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (min-width: 1100px) { .statement__facts { grid-template-columns: repeat(6, minmax(0, 1fr)); } }

/* ===========================================================================
   2 · THE ARGUMENT
   =========================================================================== */
.argument__grid {
  list-style: none;
  margin: clamp(2.2rem, 6vw, 3.6rem) 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: 1fr;
  gap: 0;
  border-top: 1px solid var(--rule);
}
.argument__grid li {
  display: grid;
  gap: 0.35rem;
  padding: clamp(1.1rem, 3.6vw, 1.5rem) 0;
  border-bottom: 1px solid var(--rule);
}
.argument__k {
  font-family: var(--sans);
  font-size: var(--t-label);
  letter-spacing: 0.17em;
  text-transform: uppercase;
  color: var(--amber-deep);
}
.argument__v {
  font-family: var(--serif);
  font-size: clamp(1.12rem, 4.3vw, 1.35rem);
  line-height: 1.45;
  color: var(--ink-soft);
  max-width: 46ch;
}
@media (min-width: 760px) {
  .argument__grid { grid-template-columns: 1fr 1fr; column-gap: clamp(2rem, 5vw, 4rem); }
}
@media (min-width: 1180px) {
  .argument__grid { grid-template-columns: repeat(3, 1fr); }
}

.argument__note {
  margin-top: clamp(2.4rem, 6vw, 4rem);
  padding: clamp(1.5rem, 5vw, 2.6rem);
  background: var(--shadow);
  color: var(--bone);
  max-width: 62ch;
}
.argument__nh {
  font-family: var(--serif);
  font-weight: 300;
  font-size: clamp(1.7rem, 6.4vw, 2.4rem);
  line-height: 1.1;
  margin: 0 0 0.9rem;
  color: var(--bone);
}
.argument__note p {
  font-size: clamp(1rem, 3.9vw, 1.08rem);
  line-height: 1.66;
  color: color-mix(in oklab, var(--bone) 82%, transparent);
  margin: 0 0 1rem;
}
.argument__attrib {
  font-family: var(--sans) !important;
  font-size: clamp(0.68rem, 2.8vw, 0.76rem) !important;
  line-height: 1.6 !important;
  letter-spacing: 0.06em;
  color: color-mix(in oklab, var(--bone) 52%, transparent) !important;
  padding-top: 1rem;
  border-top: 1px solid var(--gv-line);
  margin-bottom: 0 !important;
}

/* ===========================================================================
   3 · THE LOCATION DIAL
   The dial is a picture of the numbers beside it, so the two sit together and
   the list carries the names. On a phone the dial goes full width and the
   list runs under it; there is no point shrinking type into an SVG.
   =========================================================================== */
.locate {
  margin-top: clamp(2.4rem, 6vw, 4rem);
  display: grid;
  gap: clamp(1.8rem, 5vw, 3.5rem);
  align-items: start;
}
.locate__dial { margin: 0; }
.locate__dial img {
  width: 100%;
  height: auto;
  display: block;
}
.locate__cap {
  display: block;
  margin-top: 0.9rem;
  font-size: clamp(0.66rem, 2.7vw, 0.74rem);
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: color-mix(in oklab, var(--bone) 66%, transparent);  /* 48% measured 4.1:1 */
  max-width: 34ch;
}

.near { list-style: none; margin: 0; padding: 0; counter-reset: none; }
.near__i {
  display: grid;
  grid-template-columns: 2.1rem 1fr auto;
  align-items: baseline;
  gap: 0.75rem;
  padding: 0.72rem 0;
  border-bottom: 1px solid var(--gv-line);
}
.near__n {
  font-family: var(--sans);
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  color: color-mix(in oklab, var(--bone) 42%, transparent);
  font-variant-numeric: tabular-nums;
}
.near__i.is-key .near__n {
  color: var(--shadow);
  background: var(--amber);
  border-radius: 50%;
  width: 1.45rem; height: 1.45rem;
  display: grid; place-items: center;
  align-self: center;
}
.near__b { display: grid; gap: 0.18rem; min-width: 0; }
.near__name {
  font-family: var(--serif);
  font-size: clamp(1.15rem, 4.6vw, 1.42rem);
  line-height: 1.15;
  color: color-mix(in oklab, var(--bone) 72%, transparent);
}
.near__i.is-key .near__name { color: var(--bone); }
.near__note {
  font-size: 0.64rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: color-mix(in oklab, var(--bone) 42%, transparent);
}
.near__d {
  font-family: var(--sans);
  font-size: clamp(0.76rem, 3.1vw, 0.84rem);
  font-weight: 500;
  letter-spacing: 0.1em;
  color: var(--amber);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.drive {
  list-style: none; margin: 1.6rem 0 0; padding: 0;
  display: flex; flex-wrap: wrap; gap: 0.6rem 2.2rem;
}
.drive li { display: flex; gap: 0.6rem; align-items: baseline; }
.drive .label {
  font-size: 0.68rem; letter-spacing: 0.15em; text-transform: uppercase;
  color: color-mix(in oklab, var(--bone) 66%, transparent);  /* 50% measured 4.3:1 */
}
.drive .num { font-family: var(--sans); font-size: 0.82rem; color: var(--bone); }

.address__caveat {
  margin-top: 1.4rem;
  font-size: 0.64rem;
  line-height: 1.7;
  letter-spacing: 0.08em;
  color: color-mix(in oklab, var(--bone) 64%, transparent);  /* 40% measured 3.3:1 */
  max-width: 44ch;
}

@media (min-width: 900px) {
  .locate { grid-template-columns: minmax(0, 1fr) minmax(0, 0.92fr); gap: clamp(2.5rem, 5vw, 5rem); }
}

/* ===========================================================================
   4 · MOBILE
   Everything below is phone only.
   =========================================================================== */
@media (max-width: 899px) {

  /* -------------------------------------------------------------------------
     4.1 · THE HERO.
     The old one was a portrait cover-crop of the night elevation under a
     scrim that reached 90% at the foot. That is why you could not see the
     building, could not see four units, and why it read dark.

     Now: the three-quarter sunset plate held at its own aspect ratio, so
     nothing is cropped away, and the type sits BELOW it on the ink ground
     instead of on top of it. Once the type is off the picture, the picture
     does not need to be darkened to carry the type, so the scrim is a whisper
     at the foot purely to seat the plate on the ground.
     ------------------------------------------------------------------------- */
  /* CONTENT HEIGHT, not viewport height. Locking the hero to 100svh left a
     450px void under the price, because an uncropped 1.85:1 plate is only
     212px tall on a 393px phone and nothing was going to fill the rest that
     was worth a reader's time. A hero that is exactly as tall as what is in
     it reads composed; one padded out to the fold reads unfinished. It also
     gets the reader to the building in one scroll instead of two. */
  .hero {
    min-height: auto;
    display: grid;
    grid-template-rows: auto auto auto;
    align-content: start;
    overflow: hidden;
    background: var(--shadow);
    padding-top: calc(var(--safe-t, 0px) + 5.4rem);
    padding-bottom: clamp(2.6rem, 9vh, 4.4rem);
  }

  .hero__plate {
    position: relative;
    inset: auto;
    z-index: 0;
    grid-row: 1;
    width: 100%;
    aspect-ratio: 1280 / 691;
    overflow: hidden;
  }
  .hero__img { position: absolute; inset: 0; }
  .hero__img img {
    width: 100%; height: 100%;
    object-fit: cover;
    /* a hair off centre: keeps all four garage doors and the roofline in */
    object-position: 50% 46%;
  }
  /* the crossfade partner is desktop only now */
  .hero__img--sunset { display: none; }

  /* Seats the plate on the ground. It is not there to make the type legible,
     because the type is no longer on it. */
  .hero__scrim {
    background: linear-gradient(to bottom,
      color-mix(in oklab, var(--shadow) 30%, transparent) 0%,
      transparent 14%,
      transparent 74%,
      color-mix(in oklab, var(--shadow) 34%, transparent) 100%) !important;
  }

  .hero__type {
    grid-row: 2;
    align-self: start;
    text-align: left;
    padding-top: clamp(1.6rem, 6vw, 2.4rem);
    padding-bottom: 0;
  }
  .hero__eyebrow {
    color: var(--amber);
    font-size: 0.64rem;
    letter-spacing: 0.2em;
  }
  .hero__city { display: inline !important; }
  /* One line, and smaller than it was. The photograph is the hero; when the
     wordmark was 67px over two lines it was physically larger than the
     building and the plate read as a thumbnail. The <br> is a desktop line
     break, so it goes away here rather than leaving an empty line box
     between the two rows of the split-line rise animation. */
  .hero__word {
    font-size: clamp(2.4rem, 11.4vw, 3.6rem);
    line-height: 1.0;
    letter-spacing: -0.015em;
    margin-top: 0.55rem;
    text-wrap: nowrap;
  }
  .hero__word .line { padding-bottom: 0.1em; margin-bottom: -0.1em; }
  .hero__gloss { margin-top: 1rem; }
  .hero__gloss span:first-child {
    color: color-mix(in oklab, var(--bone) 76%, transparent);
  }
  /* The scroll cue comes back on the phone. It was hidden because the old
     hero had no room for it; this one has air below the type and an
     unfilled bottom third reads as a mistake rather than as composure. */
  /* Desktop pins this absolutely to the bottom of the hero, which on a phone
     put it underneath the fixed action bar. In the flow it goes. */
  .hero__cue {
    display: inline-flex !important;
    position: static;
    transform: none;
    left: auto; bottom: auto;
    grid-row: 3;
    justify-self: start;
    /* .hero has no inline padding of its own; .hero__type carries the gutter.
       Without this the cue hangs off the left edge of the screen. */
    margin-inline-start: max(var(--gutter), var(--safe-l, 0px));
    align-items: center;
    gap: 0.75rem;
    margin-top: clamp(1.8rem, 6vh, 3.4rem);
    padding: 0.6rem 0;
    min-height: 44px;
    color: color-mix(in oklab, var(--bone) 58%, transparent);
  }
  .hero__cue .label { font-size: 0.64rem; letter-spacing: 0.22em; }
  .hero__cue-arch { width: 34px; height: 22px; }
  .hero__cue-arch path { stroke: var(--amber); fill: none; stroke-width: 1.2; }

  .hero__gloss span:last-child {
    font-size: 1em !important;
    color: var(--amber);
    font-family: var(--sans);
    font-size: 0.8rem !important;
    letter-spacing: 0.12em;
    text-transform: uppercase;
  }

  /* -------------------------------------------------------------------------
     4.2 · THE TRAVERSE (was the ascent)
     A phone is good at travel. The old one travelled UP a crop of one bay,
     which is the thing Andy says does not show the building. This one travels
     ACROSS the four-bay elevation at full height, and the bay you are level
     with names itself and gives its own numbers.
     ------------------------------------------------------------------------- */
  .ascent--traverse .ascent__plate img {
    width: auto;
    height: 74svh;
    max-width: none;
    object-fit: cover;
    object-position: 50% 50%;
    /* travel = image width minus viewport width, expressed against its own box */
    transform: translate3d(calc((100vw - 100%) * var(--trav, 0)), 0, 0);
    will-change: transform;
  }
  .ascent--traverse .ascent__plate {
    position: absolute;
    top: calc(50% - 40svh);
    left: 0;
    display: block;
    width: auto;
  }
  .ascent--traverse .ascent__scrim {
    background: linear-gradient(to bottom,
      color-mix(in oklab, var(--shadow) 72%, transparent) 0%,
      transparent 22%, transparent 46%,
      color-mix(in oklab, var(--shadow) 78%, transparent) 76%,
      var(--shadow) 100%) !important;
  }
  .ascent--traverse .storey__n {
    color: var(--amber);
    font-size: 0.95rem;
    letter-spacing: 0.1em;
  }
  .ascent--traverse .storey__d { max-width: 30ch; }

  @supports (animation-timeline: view()) {
    /* the compositor keeps the pan smooth while the main thread decodes */
    .ascent--traverse .ascent__plate img {
      animation: traverse linear both;
      animation-timeline: --asc;
      animation-range: contain 0% contain 100%;
    }
    @keyframes traverse {
      from { transform: translate3d(0, 0, 0); }
      to   { transform: translate3d(calc(100vw - 100%), 0, 0); }
    }
  }
  @media (prefers-reduced-motion: reduce) {
    .ascent--traverse .ascent__plate img {
      animation: none;
      transform: translate3d(calc((100vw - 100%) * 0.5), 0, 0);
    }
  }

  /* -------------------------------------------------------------------------
     4.3 · GENERAL MOBILE POLISH
     ------------------------------------------------------------------------- */

  /* Section heads were running long and breaking badly at 360px. */
  .sec-head { text-wrap: balance; }
  .sec-lede { max-width: 34ch; }

  /* Every tappable thing clears 44px. */
  .thumbbar a, .thumbbar button { min-height: max(var(--bar-h), 48px); }
  .bay > button { min-height: 60px; }
  .near__i { min-height: 44px; }

  /* The dial gets the full gutter-to-gutter width; it is the content. */
  .locate { gap: 1.6rem; }
  .locate__dial { margin-inline: calc(var(--gutter) * -0.5); }

  /* iOS zooms any input under 16px on focus. Nothing here may be under 16px. */
  input, select, textarea { font-size: 16px !important; }
}

/* A phone in landscape has almost no height; the hero must not lock to 100svh
   and push the type under the fold. */
@media (max-width: 899px) and (orientation: landscape) and (max-height: 560px) {
  .hero { min-height: auto; padding-top: 5rem; padding-bottom: 5rem; }
  .hero__word { font-size: clamp(2.4rem, 9vw, 3.4rem); }
}

/* --------------------------------------------------------------------------
   The gloss was inheriting a centred justify-self from the desktop hero and
   sitting indented under the wordmark. It is a left-aligned stack on a phone.
   -------------------------------------------------------------------------- */
@media (max-width: 899px) {
  .hero__gloss {
    justify-self: start !important;
    justify-items: start !important;
    text-align: left !important;
    margin-inline: 0 !important;
  }
}

/* ===========================================================================
   5 · TAP TARGETS · found by measuring, not by eye
   The audit at 393px turned up three real ones. Inline links inside running
   text are exempt (WCAG 2.5.8 says so), so the note link in the bays caption
   is left alone; these three are not inline text, they are the things a
   buyer actually reaches for.
   =========================================================================== */
@media (max-width: 899px) {
  /* David's phone and email were 19px tall. They are the two most important
     targets on the page. */
  .enquire a[href^="tel:"], .enquire a[href^="mailto:"],
  .sheet a[href^="tel:"], .sheet a[href^="mailto:"],
  .sheet__call a {
    display: inline-block;
    min-height: 44px;
    padding-block: 0.7rem;
    line-height: 1.5;
  }

  /* Text fields were 24px tall. 48 gives a comfortable target and the 16px
     font size below keeps iOS from zooming the viewport on focus. */
  .enquire input, .enquire textarea, .enquire select,
  .sheet input, .sheet textarea, .sheet select,
  form input[type="text"], form input[type="email"], form input[type="tel"] {
    min-height: 48px;
    padding-block: 0.7rem;
  }
  form textarea { min-height: 96px; }
}

/* The plans note is a one-line caption that is almost entirely its own link,
   so it is a target rather than a link inside running text. */
@media (max-width: 899px) {
  .bays__note a {
    display: inline-block;
    min-height: 44px;
    padding-block: 0.65rem;
  }
}

/* ===========================================================================
   6 · SPLIT-LINE HEADINGS ON A PHONE
   The rise animation wraps each line in a block .line, and the source keeps a
   <br> between them. On a phone that left an empty line box between the two
   rows, so "Drawn by / gravity." was reading with a gap almost as tall as the
   type itself. Kill the break (the .line blocks already break) and tighten.
   =========================================================================== */
/* SUPERSEDED 26 Sep by authored breaks in typeset.css. Hiding every <br> in
   every section head destroyed breaks that were meant to be there, such as
   "820-826 / NE 26th Avenue", which then tore at "NE / 26th". */
