/* ═══════════════════════════════════════════════════════════════════════
   Sections.
   The page is one journey in six movements:
     1  Hero        — the promise, the air, and the evidence at its floor
     2  Destinations— where the work is practised
     3  Process     — how the work is done
     4  The window  — one cinematic moment, carrying nothing but itself
     5  Voices      — what it was like
     6  Closing     — back to the opening air
   ═══════════════════════════════════════════════════════════════════════ */

/* ═══ Hero backdrop ═════════════════════════════════════════════════════
   The video's own frame is the hero background. This wrapper only holds the
   video and paints a still fallback colour behind it — the mean of the
   footage's first frame — so the instant before the video plays shows that
   flat colour, never anything cloud-like. */
.hero__media {
  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
  background: #909ca5;
}
/* ═══ Hero video ════════════════════════════════════════════════════════
   Fills the hero regardless of the footage's own aspect ratio — cover crops
   rather than letterboxes, and a letterbox bar here would read as a broken
   image on the first screen of the site.

   z-index 0 keeps it under .hero__media::after — the paper fade that sinks the
   footage into the page at the hero's floor. */
.hero__video {
  position: absolute;
  inset: 0;
  z-index: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Autoplay is not guaranteed — a data-saver setting or a low battery can
     refuse it, and Safari refuses it outright if the file is ever un-muted.
     When it does not play the element is a still frame, so it must still be
     something to look at rather than a black rectangle. */
  background: #909ca5;
  pointer-events: none;
}

/* Motion the reader did not ask for and cannot stop. Behind it the still
   fallback colour on .hero__media stands in. */
@media (prefers-reduced-motion: reduce) {
  .hero__video {
    display: none;
  }
}

/* The hero's floor is footage, and it has to sink into paper rather than be cut
   off at the section boundary. A longer smoothstep drain does it — t²(3−2t),
   zero slope at both ends, so neither where it starts nor where it lands is
   locatable. It opens at 58% (nearly flat there, 0.03 by 62%), keeping the
   weight in the last quarter. The proof band at 84% takes a partial veil, which
   is a gain — those figures are dark ink over the mid-toned footage. */
.hero__media::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  background: linear-gradient(
    180deg,
    rgba(247, 244, 237, 0) 58%,
    rgba(247, 244, 237, 0.028) 62%,
    rgba(247, 244, 237, 0.104) 66%,
    rgba(247, 244, 237, 0.216) 71%,
    rgba(247, 244, 237, 0.352) 75%,
    rgba(247, 244, 237, 0.5) 79%,
    rgba(247, 244, 237, 0.648) 83%,
    rgba(247, 244, 237, 0.784) 87%,
    rgba(247, 244, 237, 0.896) 92%,
    rgba(247, 244, 237, 0.972) 96%,
    var(--surface-page) 100%
  );
  pointer-events: none;
}

/* ═══ 1 · Hero ══════════════════════════════════════════════════════════ */
.hero {
  position: relative;
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  text-align: center;
  /* The generous floor is what lifts the figures. They used to sit hard on the
     bottom edge of the viewport, which reads as the band having fallen to the
     bottom rather than having been placed; the lockup's auto margins take the
     difference out of the space above it, so the whole composition rises
     together and the white space stays where it belongs. */
  padding: clamp(80px, 10vh, 128px) var(--gutter) clamp(48px, 7.5vh, 92px);
  overflow: hidden;
}

.hero__inner {
  position: relative;
  z-index: 1;
  flex: 1;
  display: flex;
  flex-direction: column;
  width: 100%;
  max-width: var(--maxw-wide);
  margin-inline: auto;
  will-change: transform, opacity;
}

/* `margin: auto 0` takes every spare pixel above and below, which centres the
   lockup in whatever the proof band leaves behind. */
.hero__lockup {
  margin: auto 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  max-width: 940px;
  margin-inline: auto;
}

/* +20% on the shared 13px kicker. It is the first line of the page and the
   only thing that says what the practice actually does, so it carries more
   than the labels further down. */
.hero__kicker {
  font-size: 15.6px;
  margin-bottom: clamp(14px, 2vh, 24px);
}

.hero__title {
  /* Capped against the viewport's *height* as well as its width: two lines of
     88px are fine on a tall screen and eat a third of a short laptop. */
  font-size: min(clamp(34px, 4.7vw, 60px), 9.4vh);
  /* Wide enough to hold the question on one line at desktop sizes. Capped at
     20ch it broke as "Where are you planning / to go?", which strands the verb
     and puts the weight on the wrong half of the question. */
  max-width: 30ch;
}

.hero__lede {
  margin-top: clamp(18px, 2.6vh, 32px);
  /* One sentence per line, so the measure has to hold the longer of the two
     unbroken — that is 85 characters. A step down in size buys the width to do
     it without the line growing overbearing: at 17.5px it lands around 740px
     inside a 940px lockup, comfortably clear of both edges.
     No `text-wrap: balance` here. Balance exists to even out a *wrapped*
     paragraph; with each sentence set as its own block there is nothing to
     balance, and it would only fight the break we have chosen. */
  font-size: clamp(15px, 1.42vw, 17.5px);
  max-width: min(100%, 92ch);
  /* .mrk-lede is muted grey (#6e6b7e), which was chosen to sit quietly under the
     headline on paper. Over the footage it measures 1.8:1 against the mix behind
     this band — under half the 4.5:1 minimum, and the reason the two lines read
     as absent rather than as secondary.
     Ink takes the same measurement to 6.35:1. The step down from the headline is
     carried by size and weight instead of by colour, which is where it should
     have been sitting on a background this variable anyway. */
  color: var(--text-body);
}

/* Each sentence is its own line. A <br> would leave both sentences inside one
   block, so the paragraph's width would be set by the pair and the shorter
   line could not centre independently of the longer one. */
.hero__lede-line {
  display: block;
}
.hero__lede-line + .hero__lede-line {
  margin-top: 0.28em;
}

.hero__actions {
  margin-top: clamp(26px, 3.6vh, 38px);
}

/* ── Practice at a glance ───────────────────────────────────────────────
   Anchored to the floor of the hero. No panel, no fill — the clouds drift
   straight through it, and a hairline that dissolves at both ends is the
   only thing separating it from the sky. */
.hero__proof {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  /* The lockup above centres itself with `margin: auto 0`, which means it will
     happily give away every last pixel between itself and this band when the
     viewport is short — the button ends up sitting on the hairline. This is the
     floor that cannot be given away. */
  margin: clamp(34px, 6vh, 72px) 0 0;
  padding-top: clamp(20px, 2.8vh, 30px);
  background-image: linear-gradient(
    90deg,
    rgba(20, 18, 43, 0) 0%,
    var(--border-default) 14%,
    var(--border-default) 86%,
    rgba(20, 18, 43, 0) 100%
  );
  background-size: 100% 1px;
  background-repeat: no-repeat;
  background-position: top center;
}

.hero__proof-item {
  position: relative;
  padding-inline: clamp(10px, 2vw, 30px);
}
.hero__proof-item + .hero__proof-item::before {
  content: "";
  position: absolute;
  left: 0;
  top: 12%;
  bottom: 12%;
  width: 1px;
  background: linear-gradient(
    180deg,
    rgba(20, 18, 43, 0) 0%,
    var(--border-default) 34%,
    var(--border-default) 66%,
    rgba(20, 18, 43, 0) 100%
  );
}

.hero__proof-value {
  font-family: var(--font-display);
  font-size: clamp(26px, 3vw, 38px);
  font-weight: var(--fw-medium);
  letter-spacing: var(--track-display);
  line-height: 1;
  color: var(--mrk-blue);
  /* These figures count up on load. Proportional digits are different widths,
     so a proportional "1" arriving where a "4" was shifts every character
     after it — the number appears to shiver for three seconds. Tabular figures
     cost nothing here and hold the line perfectly still. */
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
}

.hero__proof-body {
  margin: 8px 0 0;
  display: flex;
  flex-direction: column;
  gap: 3px;
}

.hero__proof-label {
  font-size: var(--text-sm);
  font-weight: var(--fw-semibold);
  color: var(--text-strong);
}

/* Below this the three columns stop being columns: each becomes a row with
   the figure leading, which keeps every line of copy intact. */
@media (max-width: 620px) {
  .hero__proof {
    grid-template-columns: minmax(0, 1fr);
    text-align: left;
  }
  .hero__proof-item {
    display: grid;
    grid-template-columns: 4.4rem minmax(0, 1fr);
    align-items: center;
    gap: 14px;
    padding: 14px 0;
  }
  .hero__proof-item + .hero__proof-item::before {
    top: 0;
    bottom: auto;
    left: 0;
    right: 0;
    width: auto;
    height: 1px;
    background: linear-gradient(
      90deg,
      var(--border-default) 0%,
      var(--border-default) 70%,
      rgba(20, 18, 43, 0) 100%
    );
  }
  .hero__proof-body {
    margin: 0;
  }
}

/* ═══ 2 · Destinations ══════════════════════════════════════════════════ */
.destinations {
  position: relative;
  background: var(--surface-page);
}

/* Narrower than the page's wide measure. The spread reads as an editorial
   page rather than a product grid, and that depends on the margin around it
   being wider than the gap inside it. */
.section__head {
  max-width: 1160px;
  margin-inline: auto;
  padding-inline: var(--gutter);
  margin-bottom: clamp(56px, 8vw, 104px);
}
/* ── The transition into the destinations ──────────────────────────────
   Three beats, and the spacing is what makes them read as one passage rather
   than three stacked blocks: the quote sets up, the question lands, the rule
   hands over to the grid. Everything shares the grid's own measure and gutter,
   so the whole section aligns to one column edge instead of the quote sitting
   in a container of its own — which is what made it feel like it was floating
   somewhere near the section rather than opening it. */
.dest__intro {
  max-width: 1160px;
  margin-inline: auto;
  padding-inline: var(--gutter);
  text-align: center;
}

/* The setup, not the headline. It still steps back from the question in scale,
   but it is set in full ink rather than muted — a quote this short reads as
   tentative when it is greyed, and it is a statement, not an aside. */
.dest__quote {
  margin: 0 auto;
  /* Wide enough for the longer second sentence to sit on a single line, so the
     two observations read as one clean centred stack above the question rather
     than one line over a wrapped one. On a phone the measure is the screen, so
     both lines wrap there — centred, which keeps the alignment. */
  max-width: 44ch;
  font-family: var(--font-display);
  font-style: italic;
  font-weight: var(--fw-regular);
  /* +10%. */
  font-size: clamp(21px, 2.26vw, 30px);
  line-height: 1.44;
  letter-spacing: var(--track-display);
  /* The site's black — Midnight. Pure #000 appears nowhere in this palette and
     would read colder than every other dark mark on the page. */
  color: var(--text-strong);
  text-wrap: balance;
}
.dest__quote p {
  margin: 0;
}
/* The opening line carries the observation; set 15% larger and bold so it leads
   the pair. em keeps the +15% relative to the quote's own fluid size. */
.dest__quote p:first-child {
  font-size: 1.15em;
  font-weight: var(--fw-bold);
}
/* The second line is the turn in the thought, so it gets the air. Both lines
   now carry the same ink, so the break alone does the separating. */
.dest__quote p + p {
  margin-top: 0.34em;
}

/* The headline of the section. Blue, and a full step up the display scale from
   the quote: this is the line the cards are an answer to, and it has to carry
   that much. */
.dest__question {
  margin: clamp(26px, 3vw, 42px) 0 0;
  font-size: var(--text-display-lg);
  color: var(--mrk-blue);
  text-wrap: balance;
}
/* On a phone the question is held to a single line — its size steps down just
   enough to fit the screen, which reads better than a two-word wrap. */
@media (max-width: 600px) {
  .dest__question {
    font-size: min(7.4vw, 30px);
    white-space: nowrap;
    text-wrap: nowrap;
  }
}

/* The hand-off. A hairline that dissolves at both ends — the same figure the
   hero uses under its proof band — drawn from the centre outwards as the
   section arrives. It is the one piece of movement here, and it does the job
   the white space used to be asked to do: it separates the question from the
   grid while tying them together, in a fraction of the height. */
.dest__rule {
  display: block;
  height: 1px;
  margin: clamp(20px, 2.1vw, 30px) auto clamp(30px, 3.2vw, 46px);
  background: linear-gradient(
    90deg,
    rgba(20, 18, 43, 0) 0%,
    var(--border-strong) 22%,
    var(--border-strong) 78%,
    rgba(20, 18, 43, 0) 100%
  );
  transform-origin: center;
}
.js-motion .dest__rule {
  transform: scaleX(0);
  transition: transform 1500ms var(--ease-drift);
  transition-delay: var(--reveal-delay, 0ms);
}
.js-motion .dest__rule.is-revealed {
  transform: scaleX(1);
}

.section__head-title {
  font-size: var(--text-display-md);
  margin-top: 22px;
  max-width: 18ch;
}
.section__head-note {
  margin-top: 26px;
  max-width: 46ch;
  font-size: var(--text-base);
  line-height: var(--lh-relaxed);
  color: var(--text-muted);
}

.dest__grid {
  max-width: 1160px;
  margin-inline: auto;
  padding-inline: var(--gutter);
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  /* The row gap is deliberately more than double the column gap. Even spacing
     in both directions reads as a table; a taller gap between rows is what
     lets each row settle as its own line of a spread. */
  column-gap: clamp(24px, 2.8vw, 44px);
  row-gap: clamp(64px, 7vw, 112px);
}

/* Cards stretch to the height of their row, and the body grows to fill
   whatever the figure leaves. That is what puts every closing rule on the
   same line across a row regardless of how long the description runs. */
.dest {
  position: relative;
  display: flex;
  flex-direction: column;
  height: 100%;
}

.dest__figure {
  position: relative;
  aspect-ratio: 4 / 5;
  overflow: hidden;
  border-radius: var(--radius-md);
  background: var(--mrk-blue-50);
  /* The lift lives here rather than on `.dest`: the reveal animation already
     owns the card's own transform, and the two would overwrite each other. */
  transition: transform 700ms var(--ease-out), box-shadow 700ms var(--ease-out);
}

.dest__image {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transform: scale(1.02);
  transition: transform 1200ms var(--ease-out), filter 900ms var(--ease-out);
}

/* A blue veil that lifts on hover — the image warms rather than moves much. */
.dest__figure::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(9, 20, 144, 0.16) 0%, rgba(8, 4, 43, 0.3) 100%);
  opacity: 1;
  transition: opacity 900ms var(--ease-out);
  pointer-events: none;
}

.dest__index {
  position: absolute;
  z-index: 1;
  top: 20px;
  left: 22px;
  font-family: var(--font-tagline);
  font-size: 12px;
  letter-spacing: var(--track-kicker);
  color: rgba(243, 236, 219, 0.78);
}

.dest__body {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 9px;
  margin-top: 20px;
  padding-bottom: 18px;
  border-bottom: 1px solid var(--border-default);
  transition: border-color 620ms var(--ease-out);
}

.dest__name {
  transition: color 520ms var(--ease-out);
  font-family: var(--font-display);
  font-size: clamp(21px, 2.2vw, 28px);
  font-weight: var(--fw-medium);
  letter-spacing: var(--track-display);
  color: var(--text-strong);
  line-height: var(--lh-snug);
}

.dest__category {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  font-family: var(--font-tagline);
  font-size: 12.5px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--mrk-blue);
  white-space: nowrap;
}
/* The pip is always there — it holds its space so the label keeps the same
   indent whether the row is hovered or not — and only earns its colour on
   hover. Green stays an event, not a decoration. */
.dest__category .dot {
  width: 6px;
  height: 6px;
  background: var(--mrk-line-strong);
  transition: background 420ms var(--ease-out), transform 420ms var(--ease-out);
}


/* Five things move, none of them far. The card should feel like it has been
   noticed rather than activated. */
@media (hover: hover) {
  .dest:hover .dest__figure {
    transform: translateY(-6px);
    box-shadow: var(--shadow-lg);
  }
  .dest:hover .dest__image {
    transform: scale(1.06);
  }
  .dest:hover .dest__figure::after {
    opacity: 0.42;
  }
  .dest:hover .dest__name {
    color: var(--mrk-blue);
  }
  .dest:hover .dest__body {
    border-bottom-color: var(--mrk-blue);
  }
  .dest:hover .dest__category .dot {
    background: var(--mrk-green);
    transform: scale(1.25);
  }
}

/* Three columns need the room; below that they step down rather than squeeze. */
@media (max-width: 1000px) {
  .dest__grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    column-gap: clamp(28px, 4vw, 56px);
  }
}

@media (max-width: 620px) {
  .dest__grid {
    grid-template-columns: minmax(0, 1fr);
    row-gap: clamp(52px, 12vw, 76px);
  }
}

/* ═══ 3 · Process ═══════════════════════════════════════════════════════ */
.process {
  position: relative;
  /* Sky rather than paint. A flat fill of one blue is what made this read as a
     coloured box dropped into the page; real air is never one value.
     Three layers do it: a wash that lightens toward the top left, a second
     bloom low and right, and a vertical gradient underneath running from a
     pale high-altitude blue down to the deeper tone at the floor. The two
     radial passes are what keep the corners from matching each other, which is
     the whole difference between a gradient and a sky.

     Every on-blue colour in this section resolves from the three tokens at the
     end, so recolouring the whole thing — titles, numbers, the drawn rules, the
     muted states — is done here and nowhere else. */
  background:
    radial-gradient(118% 86% at 18% 0%, rgba(255, 255, 255, 0.62) 0%, rgba(255, 255, 255, 0) 58%),
    radial-gradient(96% 72% at 88% 100%, rgba(96, 150, 196, 0.42) 0%, rgba(96, 150, 196, 0) 62%),
    linear-gradient(168deg, #dfeaf4 0%, #c4daec 34%, #a9c8e2 66%, #9dc0dd 100%);
  color: var(--mrk-midnight);
  --text-on-blue: var(--mrk-midnight);
  /* 0.68, not 0.6. The gradient's darkest corner is lighter than the flat fill
     it replaces, so a muted navy at 0.6 fell to 4.2:1 against it — under AA for
     the 13px step numbers. This clears 5:1 everywhere on the surface. */
  --text-on-blue-muted: rgba(8, 4, 43, 0.68);
  --border-on-blue: rgba(8, 4, 43, 0.16);
}

.process__inner {
  max-width: var(--maxw-wide);
  margin-inline: auto;
  /* Tighter than a full section. Four short lines do not fill a screen, and
     padded like every other section this one read as mostly empty — the reader
     arrives, takes all four in at once, and then keeps scrolling through
     nothing. Pulling the section in makes it a held moment rather than a
     stretch of travel. */
  padding: clamp(68px, 8vw, 116px) var(--gutter);
  display: grid;
  grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr);
  gap: clamp(40px, 5.5vw, 88px);
}

/* No longer sticky. Sticky earns its keep when there is a long column running
   past it; against four lines it simply never moves, and a position that never
   takes effect is a position that should not be declared. */
.process__aside {
  align-self: center;
}

.process__title {
  /* Was var(--mrk-ivory); now the on-blue text token so the whole section
     recolours from one place (see the .process overrides above). */
  color: var(--text-on-blue);
  font-size: var(--text-display-md);
  /* The kicker that used to sit above it is gone, so there is nothing to space
     down from — the title leads the column outright. */
  margin-top: 0;
  max-width: 12ch;
}
/* On a phone the 12ch measure is dropped and the size steps down so the title
   sits on one line across the full width rather than stacking to four words. */
@media (max-width: 600px) {
  .process__title {
    max-width: none;
    font-size: min(6.2vw, 25px);
    white-space: nowrap;
    text-wrap: nowrap;
  }
}

.process__list {
  display: flex;
  flex-direction: column;
}

.step {
  position: relative;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 6px clamp(24px, 4vw, 56px);
  padding: clamp(19px, 2.3vw, 30px) 0;
}

/* The rules are drawn, not printed.
   Each one is a pseudo-element scaled from its left edge, so as the section
   arrives the lines sweep out one after another and the list assembles itself
   rather than appearing whole. It is the quietest possible way to give a static
   block a sense of being made — no icons, no timeline spine, nothing that was
   not already in the design.
   The travel is long and the curve is slack: at this width a fast sweep reads
   as a swipe, and the point is that the reader should notice the section has
   settled without being able to say what moved. */
.step::before,
.step:last-child::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  height: 1px;
  background: var(--border-on-blue);
  transform-origin: left center;
  transition: transform 1400ms var(--ease-drift), background 620ms var(--ease-out);
  transition-delay: var(--reveal-delay, 0ms);
}
.step::before {
  top: 0;
}
.step:last-child::after {
  bottom: 0;
  /* The closing rule follows its own line in rather than arriving with it. */
  transition-delay: calc(var(--reveal-delay, 0ms) + 260ms);
}

/* Armed only once JS has confirmed it can un-arm them — same contract the
   reveal system uses, so without scripting the rules are simply drawn. */
.js-motion .step::before,
.js-motion .step:last-child::after {
  transform: scaleX(0);
}
.js-motion .step.is-revealed::before,
.js-motion .step.is-revealed:last-child::after {
  transform: scaleX(1);
}

.step__num {
  font-family: var(--font-tagline);
  font-size: 13px;
  letter-spacing: var(--track-kicker);
  color: var(--text-on-blue-muted);
  padding-top: 8px;
  transition: color 520ms var(--ease-out);
}

.step__title {
  font-family: var(--font-display);
  font-size: clamp(20px, 2.1vw, 27px);
  font-weight: var(--fw-medium);
  line-height: var(--lh-snug);
  letter-spacing: var(--track-display);
  color: var(--text-on-blue);
  /* No measure cap. These are whole sentences rather than the short labels
     that stood here before, and a 24ch limit broke them onto a new line
     two thirds of the way across an empty column — the text stopped for no
     reason the reader could see. The column edge is the only thing that should
     end a line. */
  text-wrap: pretty;
}

@media (hover: hover) {
  .step:hover .step__num {
    color: var(--mrk-green);
  }
  /* The line above the hovered step comes up with it, so the pair reads as one
     highlighted row rather than as a number that happened to change colour. */
  .step:hover::before {
    background: var(--text-on-blue-muted);
  }
}

@media (max-width: 900px) {
  .process__inner {
    grid-template-columns: minmax(0, 1fr);
    gap: clamp(40px, 8vw, 64px);
  }
  .process__aside {
    position: static;
  }
}

@media (max-width: 560px) {
  .step {
    grid-template-columns: minmax(0, 1fr);
    gap: 10px;
  }
}

/* ═══ 5b · The sequence ═════════════════════════════════════════════════
   Two viewport-heights of scroll spent on one held picture. The track supplies
   the distance, the stage stays put inside it, and the frame drawn is chosen
   from how far through the track the reader has come — so the picture advances
   at exactly their pace and stops dead when they do.

   Paper, because the sequence runs straight into the reviews below it and both
   sit on the page's own ground. */
.filmstrip {
  position: relative;
  background: var(--surface-page);
  /* The reviews section now sits between this and Begin, so the closing seam is
     anchored there rather than here — see .reviews. */
}

/* The distance. Two screens of it, so the sequence has room to read as motion
   rather than as a slideshow being clicked through. */
.filmstrip__track {
  position: relative;
  height: 200svh;
}

/* Held against the top of the viewport for as long as the track lasts. The
   sequence plays inside a frame that does not itself move, which is what makes
   the scroll feel like a playhead rather than like scrolling past a picture. */
.filmstrip__stage {
  position: sticky;
  top: 0;
  height: 100svh;
  overflow: hidden;
}

/* The canvas carries its own cover-fit in the draw call, so it only needs to be
   told how large it is on screen; the backing store follows this box. */
.frames__canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
}

/* The payoff line — the same gesture the window title had: one unbroken line,
   wider on screen than a resting word, tracking in from the right as the reader
   scrolls deeper into the sequence and coming to rest composed once the sky is
   open. Same treatment too — Spectral, brand blue, a soft light halo to lift it
   off cloud rather than a dark shadow that would muddy blue-on-sky.

   filmstrip.js owns both the horizontal position and the opacity, writing them
   from scroll progress; everything here is the resting appearance and the parked
   start. left:0 with a JS-driven translate keeps the maths in one place — the
   number written is the distance from the left edge. It begins parked a full
   viewport to the right (off screen, nothing showing) so there is no flash of it
   before the reveal starts. z-index sits it above the canvas that
   window-frames.js injects as a sibling. */
.filmstrip__title {
  position: absolute;
  top: 50%;
  left: 0;
  z-index: 2;
  margin: 0;
  width: max-content;
  white-space: nowrap;
  font-family: var(--font-display);
  font-weight: var(--fw-medium);
  font-size: clamp(32px, 7vw, 104px);
  line-height: 1;
  letter-spacing: var(--track-display);
  color: var(--mrk-blue);
  text-shadow: 0 0 28px rgba(255, 255, 255, 0.55);
  opacity: 0;
  /* Its own layer, so tracking it across the frames is a composite rather than
     a repaint of the text into the canvas on every step. */
  transform: translate3d(100vw, -50%, 0);
  will-change: transform, opacity;
  pointer-events: none;
}

/* Scroll-driven, so there is no animation to switch off — the picture only ever
   moves because the reader moved. What is dropped is the second screen of
   travel, which exists to pace the sequence and is dead height once the
   sequence is a single held frame. */
@media (prefers-reduced-motion: reduce) {
  .filmstrip__track {
    height: 100svh;
  }
}

/* ═══ 5c · Reviews ═══════════════════════════════════════════════════════
   An infinite rail of client accounts, drifting left on its own.
   z-index:1 clears the pinned sequence above; Begin sits at z-index:2 over it.
   The section is the anchor for the closing seam now: its trailing paper is what
   Begin's --seam ride-up dissolves into, so that band is kept clear of cards. */
/* The shared sky field: one continuous gradient behind both the reviews and the
   closing, so the weather carries unbroken from where the window sequence opens
   the sky down to the CTA. It rides up --seam into the sequence and its top band
   is masked to transparent, so the last sky frames show through and dissolve
   into the gradient — and because the gradient's top (#dfeaf4) is the same pale
   blue the sky opens to, the join reads as one continuous sky.
   The gradient itself is the Process section's, so the two blue surfaces on the
   page match. */
.skyfield {
  position: relative;
  z-index: 1;
  margin-top: calc(-1 * var(--seam));
  background:
    radial-gradient(118% 86% at 18% 0%, rgba(255, 255, 255, 0.62) 0%, rgba(255, 255, 255, 0) 58%),
    radial-gradient(96% 72% at 88% 100%, rgba(96, 150, 196, 0.42) 0%, rgba(96, 150, 196, 0) 62%),
    linear-gradient(168deg, #dfeaf4 0%, #c4daec 34%, #a9c8e2 66%, #9dc0dd 100%);
  -webkit-mask-image: linear-gradient(
    180deg,
    rgba(0, 0, 0, 0) 0,
    rgba(0, 0, 0, 0.085) calc(var(--seam) * 0.28),
    rgba(0, 0, 0, 0.5) calc(var(--seam) * 0.55),
    rgba(0, 0, 0, 0.915) calc(var(--seam) * 0.82),
    rgba(0, 0, 0, 1) var(--seam),
    rgba(0, 0, 0, 1) 100%
  );
  mask-image: linear-gradient(
    180deg,
    rgba(0, 0, 0, 0) 0,
    rgba(0, 0, 0, 0.085) calc(var(--seam) * 0.28),
    rgba(0, 0, 0, 0.5) calc(var(--seam) * 0.55),
    rgba(0, 0, 0, 0.915) calc(var(--seam) * 0.82),
    rgba(0, 0, 0, 1) var(--seam),
    rgba(0, 0, 0, 1) 100%
  );
}

.reviews {
  position: relative;
  z-index: 1;
  /* Transparent — the .skyfield gradient behind it is the surface now. */
  background: transparent;
  /* Content clears the masked top band: the kicker starts below the seam. */
  padding-top: calc(clamp(64px, 9vh, 120px) + var(--seam));
  padding-bottom: calc(clamp(56px, 8vh, 104px) + var(--seam));
  overflow: hidden;
}

.reviews__head {
  max-width: var(--maxw-content);
  margin: 0 auto clamp(30px, 4.4vw, 54px);
  padding-inline: var(--gutter);
  text-align: center;
}

/* The rail. The track is clipped by the section's overflow; the edges are faded
   to paper so cards arrive and leave rather than snap at a hard border — the
   same idea as the gradient mask in the reference, done with the page's colour. */
.marquee {
  position: relative;
}
.marquee::before,
.marquee::after {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  width: clamp(40px, 7vw, 120px);
  z-index: 2;
  pointer-events: none;
}
.marquee::before {
  left: 0;
  /* Fades to the sky field's own pale blue at the rail's edge, not paper. */
  background: linear-gradient(90deg, #dde7f2, rgba(221, 231, 242, 0));
}
.marquee::after {
  right: 0;
  background: linear-gradient(270deg, #dde7f2, rgba(221, 231, 242, 0));
}

/* One long row, wider than the page; marquee.js translates it and clones the set
   onto the end so the wrap has nothing to show. align-items: stretch (the flex
   default) gives every card the height of the tallest, so the rail is even. */
.marquee__track {
  display: flex;
  gap: clamp(16px, 1.6vw, 24px);
  width: max-content;
  padding-block: 6px;
  will-change: transform;
}

.review-card {
  flex: none;
  width: min(340px, calc(100vw - 4rem));
  display: flex;
  flex-direction: column;
  margin: 0;
  padding: clamp(22px, 2vw, 30px);
  background: var(--surface-card);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
}

/* The account sub-elements, carried over from the old carousel so the reviews
   read the same as they always did — visa label with the one earned green dot,
   blue five-star row, initials avatar, the quote in display italic. */
.review-card__visa {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  margin-bottom: 12px;
  font-family: var(--font-tagline);
  font-size: 12.5px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--mrk-blue);
}
.review-card__visa .dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--mrk-green);
  flex: none;
}
.review-card__stars {
  margin: 0 -0.34em 16px 0;
  font-size: 13px;
  letter-spacing: 0.34em;
  color: var(--mrk-blue);
}
.review-card__quote {
  margin: 0 0 auto;
  font-family: var(--font-display);
  font-style: italic;
  font-weight: var(--fw-regular);
  font-size: clamp(15px, 1.1vw, 17px);
  line-height: 1.55;
  letter-spacing: var(--track-display);
  color: var(--text-strong);
  /* Longer reviews are trimmed so the rail stays even and skimmable; the full
     account was always a summary of a longer note. */
  display: -webkit-box;
  -webkit-line-clamp: 7;
  line-clamp: 7;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.review-card__by {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-top: clamp(18px, 2vw, 24px);
}
.review-card__avatar {
  display: grid;
  place-items: center;
  width: 38px;
  height: 38px;
  border-radius: 50%;
  background: var(--mrk-blue-50);
  font-family: var(--font-tagline);
  font-size: 13px;
  letter-spacing: 0.08em;
  color: var(--mrk-blue);
  flex: none;
}
.review-card__name {
  font-size: var(--text-sm);
  font-weight: var(--fw-semibold);
  color: var(--text-strong);
}

/* ═══ 6 · Closing ═══════════════════════════════════════════════════════
   The final invitation. On the page's own paper, the same ground the reviews
   sit on, so the two read as one continuous surface. */
.closing {
  /* Transparent — the shared .skyfield gradient carries through from the reviews
     into this section, one continuous surface. */
  background: transparent;
  /* --seam is a global token: the reviews above and this section are written
     against the same number so they overlap cleanly. See tokens.css. */
  position: relative;
  overflow: hidden;
  /* Above the reviews, which set z-index: 1 to clear the pinned window. */
  z-index: 2;
  /* The overlap reaches back over the carousel's controls, so this section
     covers them. It must not take their clicks — .closing__inner takes pointer
     events back for the part that actually needs them. */
  pointer-events: none;

  margin-top: calc(-1 * var(--seam));
  /* Grown by the same amount it was pulled up by, so the content area is the
     viewport-height box it always was. Left at 100svh the seam would eat into
     it and push the lockup off centre. */
  min-height: calc(100svh + var(--seam));

  /* Where an anchor should actually land.
     This box begins --seam above where the section visually begins: that strip
     is the dissolve, and it reads as the end of the reviews rather than as the
     start of this. "Let's get started" scrolling to the box top therefore
     stopped mid-review with the closing content still below the fold.
     Negative because scroll-margin-top ordinarily holds a target *down* from
     the viewport edge, and what is wanted here is the reverse — skip the strip
     that is not visually mine. The anchor handler in js/main.js reads this off
     the element instead of hard-coding the seam a second time, so the two
     cannot fall out of step. */
  scroll-margin-top: calc(-1 * var(--seam));
  display: flex;
  flex-direction: column;
  /* Fills the viewport and centres its content. Arriving here from the CTA
     button used to land the reader at the top of a very tall section, with the
     heading pinned under the masthead and the buttons below the fold; centring
     the block means heading, description and both buttons are all in view at
     once the moment the scroll settles. */
  justify-content: center;
  padding: clamp(96px, 12vh, 156px) var(--gutter) clamp(72px, 9vh, 120px);
  padding-top: calc(clamp(96px, 12vh, 156px) + var(--seam));
  text-align: center;
}

.closing__inner {
  position: relative;
  z-index: 1;
  /* Taken back from the section, which gave them up so the reviews' controls
     stay clickable underneath the overlap. */
  pointer-events: auto;
  max-width: var(--maxw-content);
  margin-inline: auto;
  display: flex;
  flex-direction: column;
  align-items: center;
}

/* The invitation as a panel now — a glass card lifted off the closing sky, the
   text and the current CTA buttons on one side, an image on the other. The card
   is what carries the section; the sky behind it is unchanged, so the dissolve
   up out of the reviews is untouched. */
.begin-card {
  width: 100%;
  display: grid;
  grid-template-columns: 1.08fr 0.92fr;
  align-items: center;
  gap: clamp(28px, 4vw, 60px);
  padding: clamp(26px, 3.4vw, 52px);
  text-align: left;
  /* A white card lifted off the beige page — the box holds the invitation, the
     paper is only around it. The shadow is what separates the two: --shadow-lg
     (0 24px 50px -28px / 0.4) grown ~10% in reach and depth. */
  background: var(--surface-card);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-lg);
  box-shadow: 0 26px 55px -28px rgba(8, 4, 43, 0.44);
}

.begin-card__title {
  margin-top: 16px;
  font-size: var(--text-display-md);
  max-width: 15ch;
}

.begin-card__note {
  margin-top: clamp(16px, 2vw, 24px);
  max-width: 40ch;
}

.begin-card__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
  margin-top: clamp(26px, 3.4vw, 38px);
}

/* A quiet one-line fallback under the buttons — a muted lead-in and the address
   as a clean inline link, so it follows the card's own alignment (left on
   desktop, centred on a phone) rather than sitting as a big loose line. */
.begin-card__contact {
  margin-top: clamp(20px, 2.6vw, 28px);
  font-size: var(--text-sm);
  color: var(--text-muted);
}
.begin-card__email {
  font-weight: var(--fw-semibold);
  color: var(--text-strong);
  border-bottom: 1px solid var(--border-strong);
  padding-bottom: 1px;
  transition: color var(--dur-base) var(--ease-standard),
    border-color var(--dur-base) var(--ease-standard);
}
.begin-card__email:hover,
.begin-card__email:focus-visible {
  color: var(--mrk-blue);
  border-color: var(--mrk-blue);
}

/* The image, with a brand-blue plate rotated behind it — the reference's
   offset backdrop, in our colour and quieter. */
.begin-card__media {
  position: relative;
}
.begin-card__media-back {
  position: absolute;
  inset: 0;
  background: var(--mrk-blue);
  opacity: 0.14;
  border-radius: var(--radius-lg);
  transform: rotate(5deg) scale(1.015);
}
.begin-card__img {
  position: relative;
  display: block;
  width: 100%;
  height: 100%;
  max-height: 340px;
  object-fit: cover;
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-md);
}

@media (max-width: 860px) {
  .begin-card {
    grid-template-columns: 1fr;
    text-align: center;
  }
  .begin-card__actions {
    justify-content: center;
  }
  .begin-card__title,
  .begin-card__note {
    margin-inline: auto;
  }
  /* Image below the invitation on a narrow screen; capped so it does not
     dominate the fold. */
  .begin-card__img {
    max-height: 240px;
  }
}

