/* Skycrest Homes interior pages.

   Loaded after v2.css on every page except the homepage, so it inherits the
   whole V2 base (reset, grain, header chrome, containers) and only adds the
   section types the homepage never needed. Everything is namespaced .ix-* so
   an interior rule can never reach the homepage or v1.

   The two motion rules from v2.css still hold:
   1. Scroll-driven endpoints resolve neutral once their token collapses,
      because reduced motion forces animation-duration to 1ms and a progress
      timeline then parks on its 100% keyframe forever.
   2. Animations never touch a property a hover or reveal transitions. */

:root {
  /* The homepage runs its hero at 100svh and its cinema panels near full
     frame. Interior heroes stay one notch below that so a sub-page never
     pretends to be the front door, but they sit much closer to it than a
     conventional 400px banner would. */
  --ix-hero-h: clamp(560px, 84svh, 920px);
  --ix-hero-h-short: clamp(420px, 58svh, 640px);
  --ix-display-hero: clamp(2.75rem, 6.4vw, 6rem);
  --ix-display-lg: clamp(2rem, 3.8vw, 3.5rem);
  --ix-display-md: clamp(1.5rem, 2.4vw, 2.25rem);
  --ix-numeral: clamp(2.5rem, 5vw, 4.5rem);
  --ix-gutter: clamp(var(--sk-space-4), 6vw, var(--sk-space-12));
  --ix-band: clamp(var(--sk-space-10), 11vw, var(--sk-space-20));
  --ix-parallax: 4svh;
  --ix-settle: 1.05;
}

@media (prefers-reduced-motion: reduce) {
  :root {
    --ix-parallax: 0svh;
    --ix-settle: 1;
  }
}

/* ── Section shells ─────────────────────────────────────────────────────── */

.ix-section {
  position: relative;
  padding-block: var(--ix-band);
  background: var(--sk-white);
}
.ix-section--bone {
  background: var(--sk-paper-bone);
}
.ix-section--limestone {
  background: var(--sk-paper-limestone);
}
.ix-section--dark {
  background: var(--sk-paper-dark);
  color: var(--sk-bone);
}
.ix-section--tight {
  padding-block: clamp(var(--sk-space-8), 7vw, var(--sk-space-12));
}

/* A drawn hairline between two same-coloured bands, so the page still has
   joints when consecutive sections share a background. */
.ix-rule {
  display: block;
  height: 1px;
  border: 0;
  margin: 0;
  background: var(--sk-line);
}
.ix-section--dark .ix-rule {
  background: rgba(239, 235, 228, 0.18);
}

/* ── Interior hero ──────────────────────────────────────────────────────── */

/* Same cinema as the homepage hero, one chapter in: shorter, and the headline
   sits on a baseline rather than centred, so interior pages never pretend to
   be the front door. */
.ix-hero {
  position: relative;
  display: flex;
  align-items: flex-end;
  min-height: var(--ix-hero-h);
  padding-block: clamp(var(--sk-space-12), 14vh, var(--sk-space-20))
    clamp(var(--sk-space-6), 7vh, var(--sk-space-10));
  overflow: clip;
  background: var(--sk-ink-deep);
  color: var(--sk-white);
  isolation: isolate;
}
.ix-hero--short {
  min-height: var(--ix-hero-h-short);
}

.ix-hero__media {
  position: absolute;
  /* Oversized by the parallax travel on both edges so the drift never shows
     a seam at either end of the range. */
  inset: calc(var(--ix-parallax) * -1.6) 0;
  z-index: -2;
}

.ix-hero__img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  scale: var(--ix-settle);
}

/* Three stacked scrims: a horizontal one over the type column, a vertical one
   that anchors the type to the lower edge, and a flat one beneath both.

   The vertical layer's trough is the stop that matters. It exists to let the
   middle of the photo stay light, so it has to sit ABOVE where the copy starts:
   the eyebrow lands around 32% of the band, and with the trough also at 32% it
   was reading its own weakest pixel at 4.37:1. The trough sits at 18% and
   climbs back by 34%, so the whole stack stands on rising scrim.

   The floor is deliberately well clear of 4.5 rather than just over it. One
   hero template serves every interior page and each gets a different photo, so
   a margin of a few hundredths is decided by whichever photo happens to land
   there. Worst run on the darkest-to-light photo in the set, at 1440:
   crumbs 5.65:1, eyebrow 5.70:1, h1 8.15:1, lede 8.81:1.

   Changing these stops, or the hero height — which is what moves the copy
   across them — means re-measuring every hero photo, not just one. */
.ix-hero::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background:
    linear-gradient(
      90deg,
      rgba(11, 20, 26, 0.52) 0%,
      rgba(11, 20, 26, 0) 76%
    ),
    linear-gradient(
      180deg,
      rgba(11, 20, 26, 0.74) 0%,
      rgba(11, 20, 26, 0.40) 18%,
      rgba(11, 20, 26, 0.62) 34%,
      rgba(11, 20, 26, 0.70) 72%,
      rgba(11, 20, 26, 0.86) 100%
    ),
    rgba(11, 20, 26, 0.20);
}

/* Narrow viewports: the type runs the full width, so the horizontal scrim has
   to as well rather than fading out before the end of a line. */
@media (max-width: 900px) {
  .ix-hero::before {
    background:
      linear-gradient(
        90deg,
        rgba(11, 20, 26, 0.52) 0%,
        rgba(11, 20, 26, 0.36) 100%
      ),
      linear-gradient(
        180deg,
        rgba(11, 20, 26, 0.74) 0%,
        rgba(11, 20, 26, 0.40) 18%,
        rgba(11, 20, 26, 0.62) 34%,
        rgba(11, 20, 26, 0.70) 72%,
        rgba(11, 20, 26, 0.86) 100%
      ),
      rgba(11, 20, 26, 0.20);
  }
}

/* Wide, not the standard container. The header and footer already run at
   --sk-container-wide, so content on the narrower measure left the page
   visibly pinched between its own chrome. Every interior band below sits on
   this same edge. */
.ix-hero__inner {
  position: relative;
  width: 100%;
  max-width: var(--sk-container-wide);
  margin-inline: auto;
  padding-inline: var(--sk-space-4);
}

.ix-hero__eyebrow {
  margin: 0 0 var(--sk-space-3);
  font-size: var(--sk-text-xs);
  font-weight: 600;
  letter-spacing: var(--sk-tracking-widest);
  text-transform: uppercase;
  color: var(--sk-sky);
}

.ix-hero__title {
  margin: 0;
  max-width: 16ch;
  font-family: var(--sk-font-display);
  font-size: var(--ix-display-hero);
  font-weight: 400;
  /* A little more than the display default so descenders (p, g, y) never
     touch the ascenders on the next line. */
  line-height: 1.04;
  letter-spacing: var(--sk-tracking-display);
  color: var(--sk-white);
  text-wrap: balance;
}

.ix-hero__lede {
  margin: var(--sk-space-4) 0 0;
  max-width: 54ch;
  font-size: var(--sk-text-lg);
  line-height: var(--sk-leading-relaxed);
  color: rgba(250, 248, 245, 0.88);
}

.ix-hero__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sk-space-2);
  margin-top: var(--sk-space-5);
}

/* ── Breadcrumbs ────────────────────────────────────────────────────────── */

.ix-crumbs {
  /* Negative top margin cancels the padding the links carry for target size,
     so the crumb trail still sits where the design puts it. */
  margin: -5px 0 calc(var(--sk-space-5) - 5px);
  font-size: var(--sk-text-xs);
  letter-spacing: var(--sk-tracking-wide);
  text-transform: uppercase;
}
.ix-crumbs__list {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sk-space-1);
  margin: 0;
  padding: 0;
  list-style: none;
}
.ix-crumbs__list li::after {
  content: '/';
  margin-left: var(--sk-space-1);
  color: rgba(250, 248, 245, 0.42);
}
.ix-crumbs__list li:last-child::after {
  content: none;
}
/* 5px block padding takes the link from 15px to 25px, clearing the 24px
   WCAG 2.5.8 minimum without changing how the trail reads. */
.ix-crumbs a,
.ix-crumbs [aria-current='page'] {
  display: inline-block;
  padding-block: 5px;
}
.ix-crumbs a {
  color: rgba(250, 248, 245, 0.72);
  text-decoration: none;
  transition: color var(--sk-duration-fast) var(--sk-ease-standard);
}
.ix-crumbs a:hover {
  color: var(--sk-white);
}
.ix-crumbs [aria-current='page'] {
  color: var(--sk-sky);
}

/* ── Lede band ──────────────────────────────────────────────────────────── */

/* The opening statement. Display-sized prose against a wide right margin,
   with an optional aside column that carries the first proof point. */
.ix-lede__inner {
  display: grid;
  grid-template-columns: minmax(0, 1.55fr) minmax(0, 1fr);
  gap: var(--ix-gutter);
  align-items: start;
  width: 100%;
  max-width: var(--sk-container-wide);
  margin-inline: auto;
  padding-inline: var(--sk-space-4);
}
.ix-lede--solo .ix-lede__inner {
  grid-template-columns: minmax(0, 1fr);
  max-width: 1040px;
}

.ix-lede__text {
  margin: 0;
  font-family: var(--sk-font-display);
  font-size: var(--ix-display-md);
  font-weight: 400;
  line-height: var(--sk-leading-snug);
  letter-spacing: var(--sk-tracking-tight);
  color: var(--sk-ink);
  text-wrap: pretty;
}
.ix-lede__text + .ix-lede__text {
  margin-top: var(--sk-space-4);
  font-family: var(--sk-font-body);
  font-size: var(--sk-text-base);
  line-height: var(--sk-leading-relaxed);
  letter-spacing: 0;
  color: var(--sk-slate);
}

/* When the band opens with a heading, the heading carries the display size and
   every paragraph under it is body copy. Without one, the first paragraph is
   the display line instead. */
.ix-lede__heading {
  margin: 0 0 var(--sk-space-4);
  font-family: var(--sk-font-display);
  font-size: var(--ix-display-md);
  font-weight: 400;
  line-height: var(--sk-leading-snug);
  letter-spacing: var(--sk-tracking-tight);
  color: var(--sk-ink);
  text-wrap: balance;
}
.ix-lede__heading ~ .ix-lede__text {
  font-family: var(--sk-font-body);
  font-size: var(--sk-text-base);
  line-height: var(--sk-leading-relaxed);
  letter-spacing: 0;
  color: var(--sk-slate);
}

.ix-lede__aside {
  padding-top: var(--sk-space-2);
  border-top: 1px solid var(--sk-line-strong);
}
.ix-lede__aside p {
  margin: 0 0 var(--sk-space-3);
  font-size: var(--sk-text-sm);
  line-height: var(--sk-leading-relaxed);
  color: var(--sk-slate);
}
.ix-lede__aside p:last-child {
  margin-bottom: 0;
}
.ix-lede__asideTitle {
  margin: 0 0 var(--sk-space-2);
  font-size: var(--sk-text-xs);
  font-weight: 600;
  letter-spacing: var(--sk-tracking-widest);
  text-transform: uppercase;
  color: var(--sk-primary);
}

@media (max-width: 900px) {
  .ix-lede__inner {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* ── Split band ─────────────────────────────────────────────────────────── */

/* Image-dominant, like the homepage's plan rows: the photo takes the larger
   track and the copy sits against it. An even 50/50 reads as a diagram; this
   reads as a spread. */
.ix-split__inner {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.42fr);
  gap: var(--ix-gutter);
  align-items: center;
  width: 100%;
  max-width: var(--sk-container-wide);
  margin-inline: auto;
  padding-inline: var(--sk-space-4);
}
/* Flip reverses the visual order only; the DOM keeps media after copy so the
   reading order is identical on every band at 900px and below. The track
   widths have to reverse with it, or the photo would land in the narrow
   column and shrink on exactly the rows meant to alternate. */
.ix-split--flip .ix-split__inner {
  grid-template-columns: minmax(0, 1.42fr) minmax(0, 1fr);
}
.ix-split--flip .ix-split__media {
  order: -1;
}

/* The media box carries the reveal, the image inside it carries the drift.
   Keeping them on separate elements is what lets the wipe transition own
   transform while the scroll timeline owns the image's. */
/* 3/2 and flat, matching .v2-frame. The homepage never puts a radius or a
   drop shadow on photography — it lets the image be a rectangle of the page —
   and a rounded, floating panel here would read as a different site. */
.ix-split__media {
  position: relative;
  aspect-ratio: 3 / 2;
  overflow: clip;
  background: var(--sk-limestone);
}
.ix-split__img {
  position: absolute;
  inset-inline: 0;
  top: calc(var(--ix-parallax) * -1.6);
  display: block;
  width: 100%;
  height: calc(100% + var(--ix-parallax) * 3.2);
  object-fit: cover;
}

.ix-split__eyebrow {
  margin: 0 0 var(--sk-space-2);
  font-size: var(--sk-text-xs);
  font-weight: 600;
  letter-spacing: var(--sk-tracking-widest);
  text-transform: uppercase;
  color: var(--sk-primary);
}
.ix-section--dark .ix-split__eyebrow {
  color: var(--sk-sky);
}

.ix-split__title {
  margin: 0 0 var(--sk-space-3);
  font-family: var(--sk-font-display);
  font-size: var(--ix-display-lg);
  font-weight: 400;
  line-height: var(--sk-leading-tight);
  letter-spacing: var(--sk-tracking-tightest);
  text-wrap: balance;
}

.ix-split__body p {
  margin: 0 0 var(--sk-space-3);
  color: var(--sk-slate);
  line-height: var(--sk-leading-relaxed);
}
.ix-section--dark .ix-split__body p {
  color: rgba(250, 248, 245, 0.78);
}
.ix-split__body p:last-child {
  margin-bottom: 0;
}
.ix-split__actions {
  margin-top: var(--sk-space-5);
}

/* A short list of plain claims under the copy. Markers are drawn so they
   inherit the brand rather than the UA bullet. */
.ix-split__points {
  margin: 0 0 var(--sk-space-4);
  padding: 0;
  list-style: none;
}
.ix-split__points li {
  position: relative;
  padding-left: var(--sk-space-4);
  margin-bottom: var(--sk-space-2);
  color: var(--sk-slate);
  line-height: var(--sk-leading-normal);
}
.ix-split__points li::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0.65em;
  width: 10px;
  height: 1px;
  background: var(--sk-primary);
}
.ix-section--dark .ix-split__points li {
  color: rgba(250, 248, 245, 0.78);
}
.ix-section--dark .ix-split__points li::before {
  background: var(--sk-sky);
}

@media (max-width: 900px) {
  /* The flip variant is listed again because its two-column rule above is
     (0,2,0); a media query adds no specificity, so a bare .ix-split__inner
     here would lose to it and the flipped bands would never stack. */
  .ix-split__inner,
  .ix-split--flip .ix-split__inner {
    grid-template-columns: minmax(0, 1fr);
  }
  .ix-split--flip .ix-split__media {
    order: 0;
  }
}

/* ── Card grid ──────────────────────────────────────────────────────────── */

/* Unlike the __inner blocks above, the card grid does not contain itself: it
   sits inside a .sk-container so a section header can share the same gutter. */
.ix-cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(290px, 1fr));
  gap: var(--sk-space-4);
}
.ix-cards--spaced {
  margin-top: var(--sk-space-8);
}

/* On the wide measure auto-fit packs four 290px tracks, which leaves a set of
   six cards sitting 4 + 2 with an orphan row. These pin the count for the two
   grids that have a fixed number of items; below the breakpoint auto-fit takes
   over again. */
@media (min-width: 1040px) {
  .ix-cards--3 {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}
@media (min-width: 1180px) {
  .ix-cards--4 {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}

.ix-card {
  position: relative;
  display: flex;
  flex-direction: column;
  overflow: clip;
  background: var(--sk-white);
  border: 1px solid var(--sk-line);
  border-radius: var(--sk-radius-md);
  text-decoration: none;
  color: inherit;
  /* box-shadow and border-color only. The lift is done with translate so it
     never fights the reveal transform, which uses transform. */
  transition:
    box-shadow var(--sk-duration-base) var(--sk-ease-standard),
    border-color var(--sk-duration-base) var(--sk-ease-standard),
    translate var(--sk-duration-base) var(--sk-ease-standard);
}
.ix-card:hover,
.ix-card:focus-visible {
  border-color: var(--sk-line-strong);
  box-shadow: var(--sk-shadow-lg);
  translate: 0 -4px;
}

/* A card that is not a link gets no lift, because nothing happens when you
   click it and an affordance that leads nowhere is worse than none. */
.ix-card--static:hover,
.ix-card--static:focus-visible {
  border-color: var(--sk-line);
  box-shadow: none;
  translate: none;
}

.ix-card__media {
  overflow: clip;
  background: var(--sk-limestone);
}
.ix-card__img {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 10;
  object-fit: cover;
  transition: scale var(--sk-duration-slow) var(--sk-ease-standard);
}
.ix-card:hover .ix-card__img {
  scale: 1.04;
}

.ix-card__body {
  display: flex;
  flex-direction: column;
  flex: 1;
  padding: var(--sk-space-4);
}
.ix-card__title {
  margin: 0 0 var(--sk-space-2);
  font-family: var(--sk-font-display);
  font-size: var(--sk-text-2xl);
  font-weight: 400;
  line-height: var(--sk-leading-snug);
  letter-spacing: var(--sk-tracking-tight);
  color: var(--sk-ink);
}
.ix-card__text {
  margin: 0;
  font-size: var(--sk-text-sm);
  line-height: var(--sk-leading-relaxed);
  color: var(--sk-slate);
}
.ix-card__more {
  margin-top: auto;
  padding-top: var(--sk-space-4);
  font-size: var(--sk-text-xs);
  font-weight: 600;
  letter-spacing: var(--sk-tracking-wide);
  text-transform: uppercase;
  color: var(--sk-primary);
}
.ix-card__more::after {
  content: '\2192';
  display: inline-block;
  margin-left: var(--sk-space-1);
  transition: translate var(--sk-duration-fast) var(--sk-ease-standard);
}
.ix-card:hover .ix-card__more::after {
  translate: 4px 0;
}

/* ── Numbered steps ─────────────────────────────────────────────────────── */

/* The long-form process list. .sk-process covers the four-up homepage grid;
   this is the vertical seven-step read, with a spine the rows hang off. */
.ix-steps {
  position: relative;
  width: 100%;
  max-width: 1180px;
  margin: 0 auto;
  padding-inline: var(--sk-space-4);
  list-style: none;
}

/* Three columns, like the homepage's manifest rows: numeral, name, then the
   explanation in its own track. On one wide measure the body would run past
   100ch; split this way the full width is used and every column still reads. */
.ix-step {
  position: relative;
  display: grid;
  grid-template-columns: clamp(3rem, 8vw, 7rem) minmax(0, 1fr) minmax(0, 1.35fr);
  column-gap: var(--ix-gutter);
  align-items: baseline;
  padding-block: clamp(var(--sk-space-5), 4vw, var(--sk-space-8));
  border-top: 1px solid var(--sk-line);
}
.ix-step:last-child {
  border-bottom: 1px solid var(--sk-line);
}

.ix-step__num {
  font-family: var(--sk-font-display);
  font-size: var(--ix-numeral);
  font-weight: 400;
  line-height: 0.85;
  letter-spacing: var(--sk-tracking-display);
  color: var(--sk-line-strong);
  font-variant-numeric: tabular-nums;
  transition: color var(--sk-duration-slow) var(--sk-ease-standard);
}
.ix-step.is-revealed .ix-step__num {
  color: var(--sk-primary);
}

.ix-step__title {
  margin: 0 0 var(--sk-space-2);
  font-family: var(--sk-font-display);
  font-size: var(--sk-text-2xl);
  font-weight: 400;
  line-height: var(--sk-leading-snug);
  letter-spacing: var(--sk-tracking-tight);
  color: var(--sk-ink);
}
.ix-step__text {
  margin: 0;
  color: var(--sk-slate);
  line-height: var(--sk-leading-relaxed);
}

/* Two columns first — the body drops under the title but keeps the numeral
   beside it — then one, so the row never collapses in a single jump. */
@media (max-width: 1000px) {
  .ix-step {
    grid-template-columns: clamp(3rem, 8vw, 7rem) minmax(0, 1fr);
  }
  .ix-step__text {
    grid-column: 2;
    margin-top: var(--sk-space-2);
  }
}
@media (max-width: 680px) {
  .ix-step {
    grid-template-columns: minmax(0, 1fr);
    row-gap: var(--sk-space-2);
  }
  .ix-step__text {
    grid-column: 1;
    margin-top: 0;
  }
  .ix-step__num {
    font-size: var(--sk-text-3xl);
  }
}

/* ── Pull quote ─────────────────────────────────────────────────────────── */

.ix-quote__inner {
  width: 100%;
  max-width: 960px;
  margin-inline: auto;
  padding-inline: var(--sk-space-4);
  text-align: center;
}
.ix-quote__text {
  margin: 0;
  font-family: var(--sk-font-display);
  font-size: var(--ix-display-lg);
  font-weight: 400;
  line-height: var(--sk-leading-tight);
  letter-spacing: var(--sk-tracking-tightest);
  color: var(--sk-bone);
  text-wrap: balance;
}
.ix-quote__cite {
  display: block;
  margin-top: var(--sk-space-4);
  font-family: var(--sk-font-body);
  font-size: var(--sk-text-xs);
  font-style: normal;
  font-weight: 600;
  letter-spacing: var(--sk-tracking-widest);
  text-transform: uppercase;
  color: var(--sk-sky);
}

/* ── Contact ────────────────────────────────────────────────────────────── */

.ix-contact__inner {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr);
  gap: var(--ix-gutter);
  align-items: start;
  width: 100%;
  max-width: var(--sk-container-wide);
  margin-inline: auto;
  padding-inline: var(--sk-space-4);
}

.ix-contact__title {
  margin: 0 0 var(--sk-space-3);
  font-family: var(--sk-font-display);
  font-size: var(--ix-display-lg);
  font-weight: 400;
  line-height: var(--sk-leading-tight);
  letter-spacing: var(--sk-tracking-tightest);
}
.ix-contact__text {
  margin: 0 0 var(--sk-space-6);
  color: var(--sk-slate);
  line-height: var(--sk-leading-relaxed);
}

.ix-contact__rows {
  margin: 0;
}
.ix-contact__row {
  padding-block: var(--sk-space-3);
  border-top: 1px solid var(--sk-line);
}
.ix-contact__row:last-child {
  border-bottom: 1px solid var(--sk-line);
}
.ix-contact__label {
  margin: 0 0 var(--sk-space-1);
  font-size: var(--sk-text-xs);
  font-weight: 600;
  letter-spacing: var(--sk-tracking-widest);
  text-transform: uppercase;
  color: var(--sk-slate-muted);
}
.ix-contact__value {
  margin: 0;
  font-size: var(--sk-text-lg);
  color: var(--sk-ink);
}
.ix-contact__value a {
  color: var(--sk-deep);
  text-decoration: none;
  border-bottom: 1px solid var(--sk-line-strong);
  transition:
    color var(--sk-duration-fast) var(--sk-ease-standard),
    border-color var(--sk-duration-fast) var(--sk-ease-standard);
}
.ix-contact__value a:hover {
  color: var(--sk-primary);
  border-color: var(--sk-primary);
}

/* The about page reuses these rows inside .ix-split__body, whose `p` rule is
   one element-selector more specific and would otherwise recolour the label and
   push the value a paragraph gap away from it. */
/* Same shape as the blog author block, so the man introducing himself on the
   about page and the man signing the posts read as one person. */
.ix-builder {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sk-space-4);
  align-items: flex-start;
  margin-top: var(--sk-space-5);
  padding-top: var(--sk-space-5);
  border-top: 1px solid var(--sk-line-strong);
}
/* The email is a 224px string with no useful break point, and this block sits in
   the narrow half of a 1fr/1.42fr split, so the room beside the photo runs out
   twice: below 480px, and again from 900px where the split has just gone
   two-column. Wrapping on an explicit min-width handles both without guessing
   at breakpoints — the text drops under the photo whenever 96px + gap + 240px
   will not fit, and returns to its side when it will. */
.ix-builder__text {
  flex: 1 1 15rem;
  min-width: 15rem;
}
.ix-builder__text .ix-contact__value {
  overflow-wrap: anywhere;
}
.ix-split__body .ix-contact__label {
  margin-bottom: var(--sk-space-1);
  color: var(--sk-slate-muted);
}
.ix-split__body .ix-contact__value {
  margin-bottom: 0;
  color: var(--sk-ink);
}

/* ── Form ───────────────────────────────────────────────────────────────── */

/* Semantic HTML only. The action is a placeholder until the GoHighLevel
   endpoint lands, so the markup has to survive being swapped for a GHL embed
   without any style here depending on this exact DOM. */
.ix-form {
  padding: clamp(var(--sk-space-4), 3vw, var(--sk-space-6));
  background: var(--sk-white);
  border: 1px solid var(--sk-line);
  border-radius: var(--sk-radius-md);
  box-shadow: var(--sk-shadow-md);
}
.ix-form__grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--sk-space-3);
}
.ix-form__field--full {
  grid-column: 1 / -1;
}

.ix-form__label {
  display: block;
  margin-bottom: var(--sk-space-1);
  font-size: var(--sk-text-xs);
  font-weight: 600;
  letter-spacing: var(--sk-tracking-wide);
  text-transform: uppercase;
  color: var(--sk-slate);
}

.ix-form__input,
.ix-form__select,
.ix-form__textarea {
  width: 100%;
  /* 12px block padding puts a single-line control at 48px, clear of the 44px
     target floor without a min-height that would break the textarea. */
  padding: 12px var(--sk-space-2);
  font-family: inherit;
  font-size: var(--sk-text-base);
  line-height: var(--sk-leading-normal);
  color: var(--sk-ink);
  background: var(--sk-bone);
  border: 1px solid var(--sk-line-strong);
  border-radius: var(--sk-radius-sm);
  transition:
    border-color var(--sk-duration-fast) var(--sk-ease-standard),
    background var(--sk-duration-fast) var(--sk-ease-standard);
}
.ix-form__textarea {
  min-height: 150px;
  resize: vertical;
}
.ix-form__input:focus,
.ix-form__select:focus,
.ix-form__textarea:focus {
  background: var(--sk-white);
  border-color: var(--sk-primary);
}

/* The label wraps the box so the whole line is the hit area, which is what
   gets a 16px checkbox over the 44px target floor without scaling the box
   itself up to something that no longer looks like a checkbox. */
.ix-form__check {
  display: flex;
  gap: var(--sk-space-2);
  align-items: flex-start;
  min-height: 44px;
  padding-block: var(--sk-space-1);
  font-size: var(--sk-text-sm);
  line-height: var(--sk-leading-normal);
  color: var(--sk-slate);
  cursor: pointer;
}
.ix-form__check input {
  flex: none;
  width: 1.125rem;
  height: 1.125rem;
  /* Nudged down to sit on the first line's baseline rather than its box top. */
  margin-top: 0.1875rem;
  accent-color: var(--sk-primary);
}

.ix-form__actions {
  margin-top: var(--sk-space-4);
}
.ix-form__note {
  margin: var(--sk-space-3) 0 0;
  font-size: var(--sk-text-xs);
  line-height: var(--sk-leading-normal);
  color: var(--sk-slate-muted);
}

@media (max-width: 820px) {
  .ix-contact__inner {
    grid-template-columns: minmax(0, 1fr);
  }
}
@media (max-width: 520px) {
  .ix-form__grid {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* ── Closing CTA ────────────────────────────────────────────────────────── */

/* .sk-cta is shared with v1, where it is a short padded strip. interior.css
   only ever loads on interior pages, so raising it here reaches those and
   nothing else. The homepage closes on a 92svh photograph; a 200px strip
   after it would read as the end of a different page. */
.sk-cta {
  display: grid;
  place-items: center;
  min-height: clamp(520px, 78svh, 860px);
}
.sk-cta__inner {
  max-width: 64rem;
}

/* v1 darkens this band by running the photo at 32% over ink, which cannot hold
   a contrast floor: dimming a photo scales its bright pixels but never bounds
   them, so a blown-out sky stays the brightest thing on the page no matter how
   far the opacity drops. The homepage instead shows the photo at full strength
   under a gradient, which does bound it. Same approach here, and it is also the
   only version the contrast sampler can model, since it composites a ::before
   over the image and has no way to see opacity on the <img> itself.

   Stops follow .v2-cta, re-expressed top-to-bottom: the stack sits mid-frame,
   so the scrim has to hold through the middle rather than only at the floor.
   Worst-case white pixel under each run, measured across every interior CTA
   photo: headline 7.85:1, body 10.39:1. The body reads higher than the headline
   because it sits lower in the frame, where the scrim is at its strongest.
   Changing these stops means re-measuring. */
.sk-cta .sk-cta__bg {
  z-index: -2;
  opacity: 1;
}
.sk-cta::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background: linear-gradient(
    180deg,
    rgba(11, 20, 26, 0.62) 0%,
    rgba(11, 20, 26, 0.84) 45%,
    rgba(11, 20, 26, 0.94) 100%
  );
}

/* ── Spec grid ──────────────────────────────────────────────────────────── */

/* The "what's included" ledger. No media, so it reads as a specification
   rather than a third row of cards on a page that already has two. */
.ix-spec {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(258px, 1fr));
  column-gap: var(--ix-gutter);
  row-gap: clamp(var(--sk-space-5), 3vw, var(--sk-space-8));
  margin: var(--sk-space-8) 0 0;
  padding: 0;
  list-style: none;
}
/* Six is the common count, and auto-fit lands it as a ragged four plus two.
   Flooring the track at a third of the row stops it reaching four columns;
   max() still lets it collapse to two and then one on narrow screens. */
.ix-spec:has(> :nth-child(6):last-child) {
  grid-template-columns: repeat(
    auto-fit,
    minmax(max(258px, (100% - 2 * var(--ix-gutter)) / 3), 1fr)
  );
}
.ix-spec__item {
  position: relative;
  padding-top: var(--sk-space-4);
  border-top: 1px solid var(--sk-line-strong);
}
/* A sky rule that draws across the top of its own row on reveal. Width is the
   animated property, never transform, so it cannot fight the reveal itself. */
.ix-spec__item::before {
  content: '';
  position: absolute;
  inset: -1px auto auto 0;
  width: 0;
  height: 1px;
  background: var(--sk-primary);
  transition: width var(--sk-duration-slow) var(--sk-ease-standard);
}
.ix-spec__item.is-revealed::before {
  width: 2.75rem;
}
.ix-spec__title {
  margin: 0 0 var(--sk-space-2);
  font-family: var(--sk-font-display);
  font-size: var(--sk-text-xl);
  font-weight: 400;
  line-height: var(--sk-leading-snug);
  letter-spacing: var(--sk-tracking-tight);
  color: var(--sk-ink);
}
.ix-spec__text {
  margin: 0;
  font-size: var(--sk-text-sm);
  line-height: var(--sk-leading-relaxed);
  color: var(--sk-slate);
}

/* ── Place ledger ───────────────────────────────────────────────────────── */

/* Towns, each with the pages we have for it. A card grid would make 23 towns
   look like 23 products; a ledger makes it look like coverage. */
.ix-places {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(238px, 1fr));
  column-gap: var(--ix-gutter);
  row-gap: clamp(var(--sk-space-5), 3vw, var(--sk-space-6));
  margin: var(--sk-space-8) 0 0;
  padding: 0;
  list-style: none;
}
.ix-place {
  padding-top: var(--sk-space-3);
  border-top: 1px solid var(--sk-line-strong);
}
.ix-place__name {
  margin: 0;
  font-family: var(--sk-font-display);
  font-size: var(--sk-text-xl);
  font-weight: 400;
  line-height: var(--sk-leading-snug);
  letter-spacing: var(--sk-tracking-tight);
}
.ix-place__name a {
  color: var(--sk-ink);
  text-decoration: none;
  transition: color var(--sk-duration-fast) var(--sk-ease-standard);
}
.ix-place__links {
  margin: var(--sk-space-2) 0 0;
  padding: 0;
  list-style: none;
}
.ix-place__links a {
  display: block;
  padding-block: 2px;
  font-size: var(--sk-text-sm);
  line-height: var(--sk-leading-relaxed);
  color: var(--sk-slate);
  text-decoration: none;
  transition: color var(--sk-duration-fast) var(--sk-ease-standard);
}
.ix-place__name a:hover,
.ix-place__name a:focus-visible,
.ix-place__links a:hover,
.ix-place__links a:focus-visible {
  color: var(--sk-primary);
}

/* Same rule as the footer: set as dense inline text these sit far under the
   44px minimum, and padding the anchor is what enlarges the target. */
@media (max-width: 1200px) {
  .ix-place__links a {
    display: flex;
    align-items: center;
    min-height: 44px;
    padding-block: 0;
  }
}

/* ── FAQ band ───────────────────────────────────────────────────────────── */

/* The heading column is sticky so the question you are reading always has the
   section's own call to action beside it, rather than scrolled off the top. */
.ix-faqs__inner {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.5fr);
  gap: var(--ix-gutter);
  align-items: start;
  width: 100%;
  max-width: var(--sk-container-wide);
  margin-inline: auto;
  padding-inline: var(--sk-space-4);
}
.ix-faqs__head {
  position: sticky;
  top: clamp(5.5rem, 14vh, 9rem);
}
/* The top margin matches .sk-section-header__intro, because this note sits
   where that intro would and the header's title carries margin: 0. */
.ix-faqs__note {
  margin: var(--sk-space-4) 0;
  font-size: var(--sk-text-sm);
  line-height: var(--sk-leading-relaxed);
  color: var(--sk-slate);
}

@media (max-width: 900px) {
  .ix-faqs__inner {
    grid-template-columns: minmax(0, 1fr);
  }
  /* Sticky in one column would pin the heading over the answers it introduces. */
  .ix-faqs__head {
    position: static;
  }
}

/* The steps list carries its own measure, so it needs the gap the section
   header's container would otherwise have given it. */
.ix-steps--after-head {
  margin-top: var(--sk-space-8);
}

/* ── Reviews ────────────────────────────────────────────────────────────── */

/* Three long unattributed reviews. Each leads with its own pulled sentence at
   display size so the stack can be skimmed, then carries the full text at
   reading size underneath. Two columns would break the quotes mid-paragraph
   at every width, so this stays a single measured column. */
.ix-reviews {
  display: grid;
  gap: clamp(var(--sk-space-8), 5vw, var(--sk-space-12));
  width: 100%;
  max-width: 880px;
  margin: var(--sk-space-10) auto 0;
  padding: 0;
  list-style: none;
  counter-reset: ix-review;
}
.ix-review {
  position: relative;
  counter-increment: ix-review;
  padding-top: var(--sk-space-6);
  border-top: 1px solid var(--sk-line);
}
.ix-review::before {
  content: counter(ix-review, decimal-leading-zero);
  position: absolute;
  top: var(--sk-space-6);
  left: 0;
  font-family: var(--sk-font-body);
  font-size: var(--sk-text-xs);
  font-weight: 600;
  letter-spacing: var(--sk-tracking-widest);
  color: var(--sk-sky);
}
.ix-review__pull {
  margin: 0 0 var(--sk-space-5);
  padding-left: var(--sk-space-10);
  font-family: var(--sk-font-display);
  font-size: var(--ix-display-md);
  font-weight: 400;
  line-height: var(--sk-leading-tight);
  letter-spacing: var(--sk-tracking-tight);
  color: var(--sk-primary);
  text-wrap: pretty;
}
.ix-review__quote {
  margin: 0;
  padding-left: var(--sk-space-10);
}
.ix-review__quote p {
  margin: 0;
  font-size: var(--sk-text-base);
  line-height: var(--sk-leading-relaxed);
  color: var(--sk-slate);
}
.ix-review__meta {
  margin: var(--sk-space-4) 0 0;
  padding-left: var(--sk-space-10);
  font-size: var(--sk-text-xs);
  font-weight: 600;
  letter-spacing: var(--sk-tracking-widest);
  text-transform: uppercase;
  color: var(--sk-slate-muted);
}

@media (max-width: 640px) {
  /* The number moves above the quote rather than beside it, so the text can
     use the full width instead of being indented past a two-character mark. */
  .ix-review::before {
    position: static;
    display: block;
    margin-bottom: var(--sk-space-3);
  }
  .ix-review__pull,
  .ix-review__quote,
  .ix-review__meta {
    padding-left: 0;
  }
}

/* ── Legal document ─────────────────────────────────────────────────────── */

/* No hero: a policy's only job is to be legible, and a photograph over a
   liability clause is decoration. The contents rail is sticky because these
   are read by hunting for one clause, not from the top. */
.ix-legal__inner {
  display: grid;
  grid-template-columns: minmax(0, 15rem) minmax(0, 1fr);
  column-gap: var(--ix-gutter);
  align-items: start;
  width: 100%;
  max-width: var(--sk-container);
  margin-inline: auto;
  padding-inline: var(--sk-space-4);
}
.ix-legal__head {
  grid-column: 1 / -1;
  max-width: 48rem;
  margin-bottom: clamp(var(--sk-space-8), 5vw, var(--sk-space-12));
}
.ix-legal__eyebrow {
  margin: 0 0 var(--sk-space-3);
  font-size: var(--sk-text-xs);
  font-weight: 600;
  letter-spacing: var(--sk-tracking-widest);
  text-transform: uppercase;
  color: var(--sk-sky);
}
.ix-legal__title {
  margin: 0;
  font-family: var(--sk-font-display);
  font-size: var(--ix-display-lg);
  font-weight: 400;
  line-height: var(--sk-leading-tight);
  letter-spacing: var(--sk-tracking-tightest);
  color: var(--sk-primary);
}
.ix-legal__lede {
  margin: var(--sk-space-5) 0 0;
  font-size: var(--sk-text-lg);
  line-height: var(--sk-leading-relaxed);
  color: var(--sk-slate);
}
.ix-legal__updated {
  margin: var(--sk-space-4) 0 0;
  font-size: var(--sk-text-xs);
  letter-spacing: var(--sk-tracking-wide);
  text-transform: uppercase;
  color: var(--sk-slate-muted);
}

/* The privacy policy runs to 21 clauses, which is taller than the slot a sticky
   rail has under the fixed header. Capping it to that slot and letting it
   scroll on its own keeps the last clauses clickable; without the cap the end
   of the list sits permanently below the fold and cannot be reached at all. */
.ix-legal__toc {
  position: sticky;
  top: clamp(5.5rem, 14vh, 9rem);
  max-height: calc(100svh - clamp(5.5rem, 14vh, 9rem) - var(--sk-space-8));
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-width: thin;
}
.ix-legal__tocTitle {
  margin: 0 0 var(--sk-space-3);
  font-size: var(--sk-text-xs);
  font-weight: 600;
  letter-spacing: var(--sk-tracking-widest);
  text-transform: uppercase;
  color: var(--sk-slate-muted);
}
.ix-legal__tocList {
  margin: 0;
  padding: 0 0 0 var(--sk-space-5);
  font-size: var(--sk-text-sm);
  line-height: var(--sk-leading-snug);
  color: var(--sk-slate);
}
.ix-legal__tocList li {
  margin-bottom: var(--sk-space-2);
}
.ix-legal__tocList a {
  color: inherit;
  text-decoration: none;
  transition: color var(--sk-duration-fast) var(--sk-ease-standard);
}
.ix-legal__tocList a:hover {
  color: var(--sk-primary);
}

.ix-legal__body {
  max-width: 44rem;
}
.ix-legal__section + .ix-legal__section {
  margin-top: clamp(var(--sk-space-6), 4vw, var(--sk-space-10));
}
/* Anchor targets clear the fixed header when a contents link jumps to them. */
.ix-legal__section {
  scroll-margin-top: clamp(5rem, 13vh, 8rem);
}
.ix-legal__heading {
  margin: 0 0 var(--sk-space-4);
  font-family: var(--sk-font-display);
  font-size: var(--sk-text-2xl);
  font-weight: 400;
  line-height: var(--sk-leading-snug);
  letter-spacing: var(--sk-tracking-tight);
  color: var(--sk-primary);
}
.ix-legal__body p {
  margin: 0 0 var(--sk-space-4);
  font-size: var(--sk-text-base);
  line-height: var(--sk-leading-relaxed);
  color: var(--sk-slate);
}
.ix-legal__body p:last-child {
  margin-bottom: 0;
}
.ix-legal__list {
  margin: 0 0 var(--sk-space-4);
  padding-left: var(--sk-space-5);
  font-size: var(--sk-text-base);
  line-height: var(--sk-leading-relaxed);
  color: var(--sk-slate);
}
.ix-legal__list li {
  margin-bottom: var(--sk-space-2);
}
.ix-legal__body a {
  color: var(--sk-primary);
  text-underline-offset: 0.2em;
}
.ix-legal__section--contact {
  margin-top: clamp(var(--sk-space-8), 5vw, var(--sk-space-12));
  padding-top: var(--sk-space-6);
  border-top: 1px solid var(--sk-line);
}
.ix-legal__sibling {
  color: var(--sk-slate-muted);
}

@media (max-width: 900px) {
  .ix-legal__inner {
    grid-template-columns: minmax(0, 1fr);
    row-gap: var(--sk-space-8);
  }
  /* Sticky in one column would pin the contents over the clause it links to.
     The height cap goes with it: a nested scroller inside the page scroller is
     a trap on touch, and in one column the list has the room to run full. */
  .ix-legal__toc {
    position: static;
    max-height: none;
    overflow: visible;
    padding-bottom: var(--sk-space-6);
    border-bottom: 1px solid var(--sk-line);
  }
}

/* ── Project grid and filter ────────────────────────────────────────────── */

/* Column count is written out rather than left to auto-fill so it matches the
   sizes attribute every card in this grid carries. An auto-fill track that
   lands on four columns while the image says 31vw makes the browser fetch a
   rung wider than it will ever paint. */
.ix-work {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: clamp(var(--sk-space-6), 3vw, var(--sk-space-10)) var(--sk-space-5);
  margin: var(--sk-space-8) 0 0;
  padding: 0;
  list-style: none;
}
.ix-work__item[hidden] {
  display: none;
}
/* Row sweep. The shared [data-sk-stagger] groups cap their index at 4, which
   across 36 cards would release everything past the fifth together. Keying the
   delay to the column instead makes each row sweep left to right as it arrives,
   and each card is its own observer target so the rows stay independent. The
   reset is what stops the two-column pattern leaking into the three-column one. */
@media (min-width: 701px) {
  .ix-work {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
  .ix-work > :nth-child(2n) {
    --sk-reveal-index: 1;
  }
}
@media (min-width: 1101px) {
  .ix-work {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
  .ix-work > :nth-child(3n + 1) {
    --sk-reveal-index: 0;
  }
  .ix-work > :nth-child(3n + 2) {
    --sk-reveal-index: 1;
  }
  .ix-work > :nth-child(3n) {
    --sk-reveal-index: 2;
  }
}
/* Re-entry after a filter change. The grid has already reflowed by the time
   this plays, so the card fades in where it has landed rather than sliding
   across; both endpoints collapse to neutral through the distance token. */
.ix-work__item.is-entering {
  animation: ix-filter-in var(--sk-duration-base) var(--sk-ease-entrance) both;
}
@keyframes ix-filter-in {
  from {
    opacity: 0;
    transform: translateY(var(--sk-distance-sm));
  }
  to {
    opacity: 1;
    transform: none;
  }
}
.ix-work .sk-project__frame {
  aspect-ratio: 16 / 10;
}
/* Action row that closes a full-width section, where there is no lede or split
   to hang the button off. */
.ix-more {
  margin: var(--sk-space-8) 0 0;
}
.ix-work__scope {
  margin: 0.35rem 0 0;
  font-family: var(--sk-font-body);
  font-size: var(--sk-text-sm);
  line-height: var(--sk-leading-relaxed);
  color: var(--sk-slate-muted);
}

/* The grid is complete and correct before any script runs, so the bar stays
   out of the page until the hook has actually wired itself up. Keying this on
   .sk-js instead would show a dead row of buttons whenever the script throws. */
.ix-filter {
  display: none;
}
.ix-filter.is-ready {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sk-space-2);
  margin-top: var(--sk-space-6);
}
.ix-filter__btn {
  min-height: 44px;
  padding: 0.6rem 1.1rem;
  border: 1px solid var(--sk-line-strong);
  border-radius: 999px;
  background: transparent;
  font-family: var(--sk-font-body);
  font-size: var(--sk-text-sm);
  font-weight: 600;
  letter-spacing: var(--sk-tracking-wide);
  color: var(--sk-slate);
  cursor: pointer;
  transition:
    color var(--sk-duration-fast) var(--sk-ease-standard),
    border-color var(--sk-duration-fast) var(--sk-ease-standard),
    background-color var(--sk-duration-fast) var(--sk-ease-standard);
}
.ix-filter__btn:hover {
  border-color: var(--sk-primary);
  color: var(--sk-primary);
}
.ix-filter__btn[aria-pressed='true'] {
  border-color: var(--sk-primary);
  background: var(--sk-primary);
  color: #fff;
}
.ix-filter__count {
  margin: 0;
  font-family: var(--sk-font-body);
  font-size: var(--sk-text-sm);
  color: var(--sk-slate-muted);
}
.ix-filter__count:not(.is-ready) {
  display: none;
}

/* Town list on /our-work/ */
.ix-towns {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sk-space-2) var(--sk-space-3);
  margin: var(--sk-space-6) 0 0;
  padding: 0;
  list-style: none;
}
.ix-towns__item {
  display: flex;
  align-items: baseline;
  gap: 0.4rem;
  padding: 0.55rem 1rem;
  border: 1px solid var(--sk-line);
  border-radius: 999px;
  font-family: var(--sk-font-body);
  font-size: var(--sk-text-sm);
  color: var(--sk-slate);
}
.ix-towns__n {
  font-weight: 700;
  color: var(--sk-primary);
}

/* ── Map embed ──────────────────────────────────────────────────────────── */

/* Flat rectangle, no radius, matching .ix-split__media and .v2-frame. The
   limestone fill is what the reader looks at while the iframe is still
   lazy-loading, so the band does not collapse and then jump.
   The ratio widens with the container rather than holding at one value: 16/9
   across a 1360px band is 760px of map, taller than the viewport it sits in,
   while 4/3 on a phone is what keeps streets either side of the pin. */
.ix-map {
  position: relative;
  aspect-ratio: 4 / 3;
  overflow: clip;
  margin: var(--sk-space-8) 0 0;
  background: var(--sk-paper-limestone);
  border: 1px solid var(--sk-line);
}
@media (min-width: 701px) {
  .ix-map {
    aspect-ratio: 16 / 9;
  }
}
@media (min-width: 1101px) {
  .ix-map {
    aspect-ratio: 21 / 9;
  }
}
.ix-map__frame {
  display: block;
  width: 100%;
  height: 100%;
  border: 0;
}

/* ── Scroll-driven motion ───────────────────────────────────────────────── */

/* Positive condition on purpose: a browser that cannot parse
   animation-timeline drops the block and keeps the complete page. Both
   endpoints resolve neutral once --ix-parallax and --ix-settle collapse. */
@supports (animation-timeline: view()) {
  .ix-hero__img {
    animation: ix-hero-settle linear both;
    animation-timeline: view();
    animation-range: exit 0% exit 100%;
  }
  @keyframes ix-hero-settle {
    from {
      scale: var(--ix-settle);
    }
    to {
      scale: 1;
    }
  }

  .ix-hero__media,
  .ix-split__img {
    animation: ix-drift linear both;
    animation-timeline: view();
    animation-range: cover 0% cover 100%;
  }
  @keyframes ix-drift {
    from {
      transform: translateY(calc(var(--ix-parallax) * -1));
    }
    to {
      transform: translateY(var(--ix-parallax));
    }
  }
}

/* ── Project gallery ────────────────────────────────────────────────────── */

/* Up to 47 photographs on one page, so the grid has to stay cheap. Every tile
   is a fixed 4/3 crop, which means the browser knows the full page height
   before a single image decodes and nothing reflows as they arrive. */
.ix-gal {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 260px), 1fr));
  gap: var(--sk-space-3);
  margin: var(--sk-space-8) 0 0;
  padding: 0;
  list-style: none;
}
.ix-gal__link {
  display: block;
  position: relative;
  aspect-ratio: 4 / 3;
  overflow: hidden;
  background: var(--sk-limestone);
}
.ix-gal__img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: scale var(--sk-duration-base) var(--sk-ease-standard);
}
.ix-gal__link:hover .ix-gal__img,
.ix-gal__link:focus-visible .ix-gal__img {
  scale: var(--ix-settle);
}
.ix-gal__link:focus-visible {
  outline: 2px solid var(--sk-sky);
  outline-offset: 3px;
}
/* The zoom cue is drawn rather than iconographic, and only appears once the
   lightbox hook has claimed the grid. Without the script the tile is still a
   link to the full image, which is a perfectly good fallback, but it opens a
   page rather than an overlay so it must not promise an overlay. */
[data-sk-lightbox].is-ready .ix-gal__link::after {
  content: '';
  position: absolute;
  inset: auto var(--sk-space-2) var(--sk-space-2) auto;
  width: 28px;
  height: 28px;
  border: 1px solid rgba(255, 255, 255, 0.85);
  border-radius: var(--sk-radius-pill);
  background: rgba(22, 35, 43, 0.45);
  opacity: 0;
  transition: opacity var(--sk-duration-fast) var(--sk-ease-standard);
}
[data-sk-lightbox].is-ready .ix-gal__link:hover::after,
[data-sk-lightbox].is-ready .ix-gal__link:focus-visible::after {
  opacity: 1;
}
.ix-gal__more {
  margin: var(--sk-space-8) 0 0;
  font-family: var(--sk-font-body);
  font-size: var(--sk-text-sm);
}

/* ── Listings ───────────────────────────────────────────────────────────── */

/* Beds, baths, size and price. Ruled top and bottom rather than boxed, so it
   reads as part of the copy column it sits in and not as a widget dropped on
   top of it. Two-up on a phone: four cells across 343px would wrap "5,045 sq
   ft" mid-number. */
.ix-amen {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--sk-space-3) var(--sk-space-4);
  margin: var(--sk-space-4) 0 var(--sk-space-5);
  padding: var(--sk-space-4) 0;
  border-top: 1px solid var(--sk-line);
  border-bottom: 1px solid var(--sk-line);
}
/* The first three cells are a digit under a word, so they are sized by their
   label and nothing else. Four even tracks would leave "Under contract" to wrap
   while 60px of whitespace sat beside the bed count. */
@media (min-width: 560px) {
  .ix-amen {
    grid-template-columns: auto auto auto minmax(0, 1fr);
  }
}
.ix-amen__cell {
  min-width: 0;
}
.ix-amen__label {
  margin: 0 0 var(--sk-space-1);
  font-family: var(--sk-font-body);
  font-size: var(--sk-text-xs);
  font-weight: 600;
  letter-spacing: var(--sk-tracking-widest);
  text-transform: uppercase;
  color: var(--sk-slate-muted);
}
.ix-amen__value {
  margin: 0;
  font-family: var(--sk-font-display);
  font-size: var(--sk-text-lg);
  line-height: 1.2;
  color: var(--sk-ink);
}
/* The price is the cell people scan for first, so it takes the brand colour.
   A house that is gone drops back to body grey: "Under contract" must not be
   dressed to look like it is still for sale. */
.ix-amen__cell--status .ix-amen__value {
  color: var(--sk-primary);
}
.ix-amen__cell--status.is-taken .ix-amen__value {
  color: var(--sk-slate);
}

/* Inside a plan card the strip stays two-up at every width, because the card is
   never wider than about 300px and four cells in it would be unreadable. */
.ix-amen--compact {
  gap: var(--sk-space-2) var(--sk-space-3);
  margin: var(--sk-space-3) 0 var(--sk-space-4);
  padding: var(--sk-space-3) 0;
}
@media (min-width: 560px) {
  .ix-amen--compact {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}
.ix-amen--compact .ix-amen__value {
  font-size: var(--sk-text-base);
}
/* "$2,100,000 + lot" needs the full width of the card, and it is the line the
   reader came to the card for, so it gets its own row rather than half of one. */
.ix-amen--compact .ix-amen__cell--status {
  grid-column: 1 / -1;
}

/* The thumbnails sit outside .ix-split__inner so they can run the full width of
   the band instead of being trapped in the narrow copy column, which means they
   have to restate the container themselves. */
.ix-strip {
  width: 100%;
  max-width: var(--sk-container-wide);
  margin-inline: auto;
  padding-inline: var(--sk-space-4);
}

/* auto-fill rather than auto-fit: a listing with three images gets three tiles
   the same size as the listing below it with six, because the empty tracks hold
   their width. auto-fit would collapse them and stretch three photographs across
   the whole band. */
.ix-gal--strip {
  grid-template-columns: repeat(auto-fill, minmax(132px, 1fr));
  gap: var(--sk-space-2);
  margin: var(--sk-space-5) 0 0;
}
@media (min-width: 700px) {
  .ix-gal--strip {
    grid-template-columns: repeat(auto-fill, minmax(176px, 1fr));
    gap: var(--sk-space-3);
  }
}
.ix-gal--strip > li {
  min-width: 0;
}

/* A plan card is about 290px wide, so the 176px track above fits exactly one
   column and stacks the set into a tower that doubles the card's height. Fixed
   two-up instead: an explicit track count rather than auto-fill, so the card
   with one spare image sizes its tile like the cards with two. */
.ix-card .ix-gal--strip {
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--sk-space-2);
  /* Pushed to the foot of the card the way .ix-card__more is, so the four
     strips line up with each other instead of floating wherever each card's
     prose happens to stop. */
  margin-top: auto;
  padding-top: var(--sk-space-4);
}

/* The plan card's lead is a 3:2 crop shown in a 16:10 frame, matching
   .ix-card__img so the plan cards align with every other card grid on the site. */
.ix-gal__link--wide {
  aspect-ratio: 16 / 10;
}

/* A drawing is letterboxed to fill its tile exactly, so the hover zoom would
   push the garage back off the edge. Photographs carry spare pixels on all four
   sides; floor plans carry none. */
.ix-gal__link:hover .ix-gal__img--plan,
.ix-gal__link:focus-visible .ix-gal__img--plan {
  scale: 1;
}

/* ── Lightbox ───────────────────────────────────────────────────────────── */

/* Built on <dialog>, so the browser owns the focus trap, the Escape key and
   the inert backdrop rather than this file reimplementing all three badly. */
.ix-lb {
  width: 100vw;
  max-width: 100vw;
  height: 100dvh;
  max-height: 100dvh;
  margin: 0;
  padding: 0;
  border: 0;
  background: transparent;
  overflow: hidden;
}
.ix-lb::backdrop {
  background: rgba(16, 26, 32, 0.93);
}
.ix-lb__figure {
  display: grid;
  grid-template-rows: 1fr auto;
  gap: var(--sk-space-3);
  width: 100%;
  height: 100%;
  margin: 0;
  padding: var(--sk-space-10) var(--sk-space-4) var(--sk-space-4);
  box-sizing: border-box;
}
.ix-lb__img {
  justify-self: center;
  align-self: center;
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
}
.ix-lb__caption {
  font-family: var(--sk-font-body);
  font-size: var(--sk-text-sm);
  text-align: center;
  color: rgba(255, 255, 255, 0.78);
}
.ix-lb__btn {
  position: absolute;
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  padding: 0;
  border: 1px solid rgba(255, 255, 255, 0.4);
  border-radius: var(--sk-radius-pill);
  background: rgba(16, 26, 32, 0.6);
  color: var(--sk-white);
  font-family: var(--sk-font-body);
  font-size: 1.1rem;
  line-height: 1;
  cursor: pointer;
  transition: background var(--sk-duration-fast) var(--sk-ease-standard);
}
.ix-lb__btn:hover,
.ix-lb__btn:focus-visible {
  background: rgba(16, 26, 32, 0.95);
}
.ix-lb__btn--close {
  top: var(--sk-space-3);
  right: var(--sk-space-3);
}
.ix-lb__btn--prev {
  top: 50%;
  left: var(--sk-space-3);
  translate: 0 -50%;
}
.ix-lb__btn--next {
  top: 50%;
  right: var(--sk-space-3);
  translate: 0 -50%;
}

/* ── Facts list ─────────────────────────────────────────────────────────── */

/* The aside on a project page carries data rather than a paragraph, so it is a
   definition list. Rows rather than a two-column grid, because "Ground-up home
   with a finished lower level" wraps and a grid row would drag the term with it. */
.ix-facts {
  margin: 0 0 var(--sk-space-5);
}
.ix-facts__row {
  display: flex;
  flex-wrap: wrap;
  gap: 0 var(--sk-space-2);
  padding: 0.55rem 0;
  border-top: 1px solid var(--sk-hairline);
}
.ix-facts__row:first-child {
  border-top: 0;
  padding-top: 0;
}
.ix-facts dt {
  flex: 0 0 5.5rem;
  font-family: var(--sk-font-body);
  font-size: var(--sk-text-xs);
  letter-spacing: var(--sk-tracking-wide);
  text-transform: uppercase;
  color: var(--sk-slate-muted);
}
.ix-facts dd {
  flex: 1 1 10rem;
  margin: 0;
  font-family: var(--sk-font-body);
  font-size: var(--sk-text-sm);
  line-height: var(--sk-leading-snug);
  color: var(--sk-ink);
}

/* ── Before / after ─────────────────────────────────────────────────────── */

/* .sk-ba in components.css draws the frame, the labels and the handle. These
   rules place it on an interior page and wire the split, which the hook writes
   to --sk-ba-split so the clip and the handle can never disagree. */
.ix-ba {
  margin: var(--sk-space-8) 0 0;
}
.ix-ba__caption {
  margin: var(--sk-space-3) 0 0;
  max-width: 62ch;
  font-family: var(--sk-font-body);
  font-size: var(--sk-text-sm);
  line-height: var(--sk-leading-relaxed);
  color: var(--sk-slate-muted);
}
/* Without the script both frames are stacked and only the finished room shows,
   which is the right thing for a page about a finished room. The hook adds
   .is-ready and the clip takes over from there. */
[data-sk-ba].is-ready .sk-ba__after {
  clip-path: inset(0 0 0 var(--sk-ba-split));
}
[data-sk-ba].is-ready .sk-ba__handle {
  left: var(--sk-ba-split);
}
[data-sk-ba]:not(.is-ready) .sk-ba__handle,
[data-sk-ba]:not(.is-ready) .sk-ba__range,
[data-sk-ba]:not(.is-ready) .sk-ba__label {
  display: none;
}
.sk-ba__range:focus-visible {
  outline: 2px solid var(--sk-sky);
  outline-offset: 2px;
}

/* Two neighbours rather than three, so the pair sits wider than a grid row. */
@media (min-width: 701px) {
  .ix-work--pair {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}
@media (min-width: 1101px) {
  .ix-work--pair {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
  .ix-work--pair > :nth-child(2n) {
    --sk-reveal-index: 1;
  }
  .ix-work--pair > :nth-child(2n + 1) {
    --sk-reveal-index: 0;
  }
}

/* ── Blog ───────────────────────────────────────────────────────────────── */

/* The post hero carries a byline under the title, which the other heroes do
   not, so it runs a little taller than --ix-hero-h-short to keep the stack off
   the lower edge. */
.ix-hero--post {
  min-height: calc(var(--ix-hero-h-short) + 3rem);
}
.ix-post__byline {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sk-space-2);
  margin: var(--sk-space-4) 0 0;
  font-size: var(--sk-text-sm);
  letter-spacing: var(--sk-tracking-wide);
  color: rgba(255, 255, 255, 0.88);
}
.ix-post__author {
  font-weight: 600;
  color: var(--sk-white);
}

.ix-post__inner {
  display: grid;
  grid-template-columns: minmax(0, 15rem) minmax(0, 1fr);
  column-gap: var(--ix-gutter);
  align-items: start;
  width: 100%;
  max-width: var(--sk-container);
  margin-inline: auto;
  padding-inline: var(--sk-space-4);
}

/* Same sticky rail as the legal pages, with the same height cap: the longest
   post runs to nine sections, which is taller than the slot under the fixed
   header. */
.ix-post__toc {
  position: sticky;
  top: clamp(5.5rem, 14vh, 9rem);
  max-height: calc(100svh - clamp(5.5rem, 14vh, 9rem) - var(--sk-space-8));
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-width: thin;
}
.ix-post__tocTitle {
  margin: 0 0 var(--sk-space-3);
  font-size: var(--sk-text-xs);
  font-weight: 600;
  letter-spacing: var(--sk-tracking-widest);
  text-transform: uppercase;
  color: var(--sk-slate-muted);
}
.ix-post__tocList {
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: var(--sk-text-sm);
  line-height: var(--sk-leading-snug);
}
.ix-post__tocList li {
  margin-bottom: var(--sk-space-1);
}
.ix-post__tocList a {
  display: block;
  padding: var(--sk-space-2) 0 var(--sk-space-2) var(--sk-space-4);
  border-left: 2px solid var(--sk-line);
  color: var(--sk-slate);
  text-decoration: none;
  transition:
    color var(--sk-duration-fast) var(--sk-ease-standard),
    border-color var(--sk-duration-fast) var(--sk-ease-standard);
}
.ix-post__tocList a:hover {
  color: var(--sk-primary);
  border-left-color: var(--sk-line-strong);
}
/* Set by data-sk-toc. The attribute is the hook rather than a class so the
   no-JS page carries no state it cannot clear. */
.ix-post__tocList a[aria-current='true'] {
  color: var(--sk-primary);
  font-weight: 600;
  border-left-color: var(--sk-sky);
}

.ix-post__body {
  max-width: 44rem;
}
.ix-post__lede {
  margin: 0 0 clamp(var(--sk-space-6), 4vw, var(--sk-space-10));
  font-size: var(--sk-text-xl);
  line-height: var(--sk-leading-relaxed);
  color: var(--sk-ink);
}
.ix-post__section + .ix-post__section {
  margin-top: clamp(var(--sk-space-6), 4vw, var(--sk-space-12));
}
/* Anchor targets clear the fixed header when a contents link jumps to them. */
.ix-post__section {
  scroll-margin-top: clamp(5rem, 13vh, 8rem);
}
.ix-post__heading {
  margin: 0 0 var(--sk-space-4);
  font-family: var(--sk-font-display);
  font-size: var(--ix-display-md);
  font-weight: 400;
  line-height: var(--sk-leading-snug);
  letter-spacing: var(--sk-tracking-tight);
  color: var(--sk-primary);
}
.ix-post__body p {
  margin: 0 0 var(--sk-space-4);
  font-size: var(--sk-text-base);
  line-height: var(--sk-leading-relaxed);
  color: var(--sk-slate);
}
.ix-post__body p:last-child {
  margin-bottom: 0;
}
.ix-post__list {
  margin: 0 0 var(--sk-space-4);
  padding-left: var(--sk-space-5);
  font-size: var(--sk-text-base);
  line-height: var(--sk-leading-relaxed);
  color: var(--sk-slate);
}
.ix-post__list li {
  margin-bottom: var(--sk-space-2);
}
.ix-post__list li::marker {
  color: var(--sk-sky);
}
.ix-post__body a {
  color: var(--sk-primary);
  text-underline-offset: 3px;
}

.ix-post__pull {
  margin: clamp(var(--sk-space-5), 3vw, var(--sk-space-6)) 0 !important;
  padding-left: var(--sk-space-5);
  border-left: 3px solid var(--sk-sky);
  font-family: var(--sk-font-display);
  font-size: var(--sk-text-xl) !important;
  line-height: var(--sk-leading-snug) !important;
  letter-spacing: var(--sk-tracking-tight);
  color: var(--sk-ink) !important;
}

.ix-post__takeaway {
  margin-top: clamp(var(--sk-space-8), 5vw, var(--sk-space-12));
  padding: clamp(var(--sk-space-5), 3vw, var(--sk-space-6));
  background: var(--sk-limestone);
  border-radius: var(--sk-radius-md);
}
.ix-post__takeawayTitle {
  margin: 0 0 var(--sk-space-2) !important;
  font-size: var(--sk-text-xs);
  font-weight: 600;
  letter-spacing: var(--sk-tracking-widest);
  text-transform: uppercase;
  color: var(--sk-sky);
}
.ix-post__takeaway .sk-btn {
  margin-top: var(--sk-space-5);
}

.ix-post__links {
  margin-top: clamp(var(--sk-space-6), 4vw, var(--sk-space-10));
  padding-top: var(--sk-space-6);
  border-top: 1px solid var(--sk-line);
}
.ix-post__linksTitle {
  margin: 0 0 var(--sk-space-3) !important;
  font-size: var(--sk-text-xs);
  font-weight: 600;
  letter-spacing: var(--sk-tracking-widest);
  text-transform: uppercase;
  color: var(--sk-slate-muted);
}
.ix-post__links ul {
  margin: 0;
  padding-left: var(--sk-space-5);
  font-size: var(--sk-text-base);
  line-height: var(--sk-leading-relaxed);
}
.ix-post__links li {
  margin-bottom: var(--sk-space-2);
}
/* These are standalone destinations in a list, not prose links, so they are tap
   targets. A touch user needs the full 44px whatever the screen width is. */
@media (pointer: coarse) {
  .ix-post__links a {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
  }
}

.ix-author {
  display: flex;
  gap: var(--sk-space-4);
  align-items: flex-start;
  margin-top: clamp(var(--sk-space-6), 4vw, var(--sk-space-10));
  padding-top: var(--sk-space-6);
  border-top: 1px solid var(--sk-line);
}
.ix-author__photo {
  flex: none;
  width: 96px;
  height: 96px;
  border-radius: 50%;
  object-fit: cover;
  background: var(--sk-limestone);
}
.ix-author__name {
  margin: 0 !important;
  font-family: var(--sk-font-display);
  font-size: var(--sk-text-lg);
  color: var(--sk-ink) !important;
}
.ix-author__role {
  margin: 0 0 var(--sk-space-2) !important;
  font-size: var(--sk-text-xs) !important;
  letter-spacing: var(--sk-tracking-wide);
  text-transform: uppercase;
  color: var(--sk-slate-muted) !important;
}
.ix-author__bio {
  margin: 0 !important;
  font-size: var(--sk-text-sm) !important;
}

/* .ix-card declares display:flex, which outranks the UA rule for [hidden], so
   the blog filter needs this or a filtered-out card stays on the page. */
.ix-card[hidden] {
  display: none;
}
.ix-card.is-entering {
  animation: ix-filter-in var(--sk-duration-base) var(--sk-ease-entrance) both;
}

.ix-card__meta {
  margin: 0 0 var(--sk-space-2);
  font-size: var(--sk-text-xs);
  font-weight: 600;
  letter-spacing: var(--sk-tracking-wide);
  text-transform: uppercase;
  color: var(--sk-slate-muted);
}
/* The blog cards carry a meta line above the title, so the title drops a step
   to keep the card from reading as two headings. */
.ix-card__meta + .ix-card__title {
  font-size: var(--sk-text-xl);
}

/* The rail is a left column at desktop and a plain list above the article
   below it. Sticky at 860px would pin a 9-item list over a single-column
   read and leave almost no room for the prose. */
@media (max-width: 1000px) {
  .ix-post__inner {
    grid-template-columns: minmax(0, 1fr);
    row-gap: var(--sk-space-6);
  }
  .ix-post__toc {
    position: static;
    max-height: none;
    padding: var(--sk-space-5);
    background: var(--sk-limestone);
    border-radius: var(--sk-radius-md);
  }
  .ix-post__body {
    max-width: none;
  }
  .ix-author {
    flex-direction: column;
  }
}

/* ── Service-area map (Areas We Cover, Markup #33) ────────────────────────
   Inline SVG drawn from real coordinates: no map service, no tracking. */
.ix-map2 {
  margin: var(--sk-space-6) 0 var(--sk-space-8);
}
.ix-map2__svg {
  display: block;
  width: 100%;
  height: auto;
  border: 1px solid var(--sk-line);
  border-radius: var(--sk-radius-lg);
  background: var(--sk-white);
  box-shadow: var(--sk-shadow-md);
}
.ix-map2__land {
  fill: #f6f3ee;
}
.ix-map2__lake {
  fill: #dbe9f1;
}
.ix-map2__shore {
  fill: none;
  stroke: #b9d2e0;
  stroke-width: 2;
}
.ix-map2__water {
  font-family: var(--sk-font-display);
  font-size: 22px;
  font-style: italic;
  letter-spacing: 0.08em;
  fill: #6f97ad;
}
.ix-map2__city rect {
  fill: var(--sk-ink);
}
.ix-map2__label {
  font-family: var(--sk-font-body);
  font-size: 15px;
  font-weight: 500;
  fill: var(--sk-ink);
  paint-order: stroke;
  stroke: #f6f3ee;
  stroke-width: 4px;
  stroke-linejoin: round;
}
.ix-map2__label--city {
  font-family: var(--sk-font-display);
  font-size: 20px;
  font-weight: 400;
}
.ix-map2__town .ix-map2__pin {
  fill: var(--sk-white);
  stroke: var(--sk-primary);
  stroke-width: 2.5;
  transition: fill var(--sk-duration-fast), r var(--sk-duration-fast);
}
.ix-map2__town.is-project .ix-map2__pin {
  fill: var(--sk-primary);
  stroke: var(--sk-white);
}
.ix-map2__town.is-project .ix-map2__label {
  font-weight: 700;
}
.ix-map2__count {
  font-family: var(--sk-font-body);
  font-size: 11px;
  font-weight: 700;
  fill: var(--sk-white);
  text-anchor: middle;
  pointer-events: none;
}
.ix-map2__town:hover .ix-map2__pin,
.ix-map2__town:focus-visible .ix-map2__pin {
  fill: var(--sk-deep);
  stroke: var(--sk-white);
}
.ix-map2__town:hover .ix-map2__label,
.ix-map2__town:focus-visible .ix-map2__label {
  fill: var(--sk-primary);
  text-decoration: underline;
}
.ix-map2__town:focus-visible {
  outline: none;
}
.ix-map2__scale line {
  stroke: var(--sk-slate);
  stroke-width: 2;
}
.ix-map2__scale text {
  font-family: var(--sk-font-body);
  font-size: 13px;
  fill: var(--sk-slate);
}
.ix-map2__legend {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sk-space-1) var(--sk-space-4);
  margin-top: var(--sk-space-2);
  font-size: var(--sk-text-sm);
  color: var(--sk-slate);
}
.ix-map2__legend > span {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
}
.ix-map2__key {
  display: inline-block;
  width: 14px;
  height: 14px;
  border: 2.5px solid var(--sk-primary);
  border-radius: 50%;
  background: var(--sk-white);
}
.ix-map2__key.is-project {
  border-color: var(--sk-primary);
  background: var(--sk-primary);
}
@media (max-width: 720px) {
  .ix-map2 {
    margin-inline: calc(var(--sk-space-4) * -1);
  }
  .ix-map2__svg {
    border-radius: 0;
    border-inline: 0;
  }
}

/* Phones: keep the map readable (labels ~12px) and let it pan sideways
   instead of shrinking it to the screen width. */
.ix-map2__hint {
  display: none;
}
@media (max-width: 720px) {
  .ix-map2__scroller {
    overflow-x: auto;
    overscroll-behavior-x: contain;
    -webkit-overflow-scrolling: touch;
  }
  .ix-map2__scroller .ix-map2__svg {
    width: 780px;
    max-width: none;
  }
  .ix-map2__hint {
    display: block;
    margin: var(--sk-space-1) var(--sk-space-4) 0;
    font-size: var(--sk-text-xs);
    color: var(--sk-slate-muted);
  }
  .ix-map2__legend {
    padding-inline: var(--sk-space-4);
  }
}

/* ── Build timeline (Our Process, Markup #32) ─────────────────────────────
   Four stages on a line on desktop; stacked with a vertical line on phones. */
.ix-timeline__list {
  position: relative;
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--sk-space-4);
  margin: var(--sk-space-8) 0 0;
  padding: 0;
  list-style: none;
}
.ix-timeline__list::before {
  content: '';
  position: absolute;
  top: 22px;
  left: 22px;
  right: 22px;
  height: 2px;
  background: var(--sk-line-strong);
}
.ix-timeline__item {
  position: relative;
}
.ix-timeline__dot {
  position: relative;
  display: grid;
  place-items: center;
  width: 46px;
  height: 46px;
  border: 2px solid var(--sk-primary);
  border-radius: var(--sk-radius-pill);
  background: var(--sk-white);
  font-family: var(--sk-font-display);
  font-size: 1.25rem;
  color: var(--sk-primary);
}
.ix-timeline__item:last-child .ix-timeline__dot {
  background: var(--sk-primary);
  color: var(--sk-white);
}
.ix-timeline__title {
  margin: var(--sk-space-3) 0 var(--sk-space-1);
  font-family: var(--sk-font-display);
  font-weight: 400;
  font-size: var(--sk-text-xl);
  line-height: var(--sk-leading-snug);
  color: var(--sk-ink-deep);
}
.ix-timeline__text {
  margin: 0;
  max-width: 32ch;
  font-size: var(--sk-text-base);
  line-height: var(--sk-leading-relaxed);
  color: var(--sk-slate);
}
@media (max-width: 900px) {
  .ix-timeline__list {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--sk-space-5);
  }
  .ix-timeline__list::before {
    top: 22px;
    bottom: 22px;
    left: 22px;
    right: auto;
    width: 2px;
    height: auto;
  }
  .ix-timeline__item {
    padding-left: 72px;
  }
  .ix-timeline__dot {
    position: absolute;
    left: 0;
    top: 0;
  }
  .ix-timeline__title {
    margin-top: 0.4rem;
  }
}

/* Map window: shorter, and the map pans inside it (mouse drag on desktop,
   swipe on phones). The frame moves from the SVG to the window. */
.ix-map2__scroller {
  height: clamp(420px, 62vh, 600px);
  overflow: auto;
  overscroll-behavior: contain;
  scrollbar-width: none;
  border: 1px solid var(--sk-line);
  border-radius: var(--sk-radius-lg);
  background: #f6f3ee;
  box-shadow: var(--sk-shadow-md);
  cursor: grab;
  -webkit-user-select: none;
  user-select: none;
}
.ix-map2__scroller::-webkit-scrollbar {
  display: none;
}
.ix-map2__scroller.is-dragging {
  cursor: grabbing;
}
.ix-map2__scroller .ix-map2__svg {
  border: 0;
  border-radius: 0;
  box-shadow: none;
}
.ix-map2__hint {
  display: block;
  margin: 0 0 var(--sk-space-1);
  font-size: var(--sk-text-xs);
  letter-spacing: var(--sk-tracking-wide);
  color: var(--sk-slate-muted);
}
@media (max-width: 720px) {
  .ix-map2__scroller {
    height: 440px;
    border-radius: 0;
    border-inline: 0;
  }
  .ix-map2__hint {
    margin: 0 var(--sk-space-4) var(--sk-space-1);
  }
}

/* Compact timeline under the process steps (replaces the separate
   "How long it takes" section). */
.ix-steps__timeline {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--sk-space-2) var(--sk-space-4);
  margin-top: var(--sk-space-6);
  padding: var(--sk-space-3) var(--sk-space-4);
  border: 1px solid var(--sk-line);
  border-left: 3px solid var(--sk-primary);
  border-radius: var(--sk-radius-md);
  background: var(--sk-white);
}
.ix-steps__timelineText {
  margin: 0;
  font-size: var(--sk-text-base);
  line-height: var(--sk-leading-normal);
  color: var(--sk-slate);
}
.ix-steps__timelineText strong {
  font-weight: 600;
  color: var(--sk-ink-deep);
}
.ix-steps__phases {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem;
  margin: 0;
  padding: 0;
  list-style: none;
  counter-reset: phase;
}
.ix-steps__phases li {
  counter-increment: phase;
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  font-size: var(--sk-text-sm);
  font-weight: 500;
  color: var(--sk-ink);
}
.ix-steps__phases li::before {
  content: counter(phase);
  display: inline-grid;
  place-items: center;
  width: 1.5rem;
  height: 1.5rem;
  border-radius: var(--sk-radius-pill);
  background: var(--sk-primary);
  font-size: 0.75rem;
  font-weight: 700;
  color: var(--sk-white);
}
.ix-steps__phases li + li::after {
  content: none;
}
.ix-steps__phases li:not(:last-child)::after {
  content: '\2192';
  margin-left: 0.2rem;
  color: var(--sk-line-strong);
}

/* Map zoom controls (top-right of the map window) */
.ix-map2__frame {
  position: relative;
}
.ix-map2__zoom {
  position: absolute;
  top: 12px;
  right: 12px;
  z-index: 2;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.ix-map2__zoomBtn {
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  padding: 0;
  border: 1px solid var(--sk-line-strong);
  border-radius: var(--sk-radius-md);
  background: var(--sk-white);
  box-shadow: var(--sk-shadow-sm);
  font: 500 1.375rem/1 var(--sk-font-body);
  color: var(--sk-ink);
  cursor: pointer;
  transition: background-color var(--sk-duration-fast), color var(--sk-duration-fast), opacity var(--sk-duration-fast);
}
.ix-map2__zoomBtn--reset {
  font-size: 1.125rem;
}
.ix-map2__zoomBtn:hover:not(:disabled),
.ix-map2__zoomBtn:focus-visible {
  background: var(--sk-primary);
  border-color: var(--sk-primary);
  color: var(--sk-white);
}
.ix-map2__zoomBtn:disabled {
  opacity: 0.4;
  cursor: default;
}
@media (max-width: 720px) {
  .ix-map2__zoom {
    right: var(--sk-space-2);
  }
}

/* Timeline note under the process steps: plain heading and paragraph on the
   section background, on the same measure as the steps above it. */
.ix-steps__note {
  max-width: 1180px;
  margin: var(--sk-space-4) auto 0;
  padding-inline: var(--sk-space-4);
}
.ix-steps__noteTitle {
  margin: 0 0 var(--sk-space-1);
  font-family: var(--sk-font-display);
  font-size: var(--sk-text-2xl);
  font-weight: 400;
  line-height: var(--sk-leading-snug);
  letter-spacing: var(--sk-tracking-tight);
  color: var(--sk-ink);
}
.ix-steps__noteText {
  margin: 0;
  max-width: 70ch;
  font-size: var(--sk-text-base);
  line-height: var(--sk-leading-relaxed);
  color: var(--sk-slate);
}
.ix-steps__noteText + .ix-steps__noteText {
  margin-top: var(--sk-space-2);
}

/* Timeline note: centred, on a wider measure */
.ix-steps__note {
  text-align: center;
}
.ix-steps__note .ix-steps__noteText {
  max-width: 92ch;
  margin-inline: auto;
}
