/* ==========================================================================
   Practice Websites
   Loaded only by src/pages/practice-websites.njk (front matter:
   pageCss: practice-websites).

   Shared furniture (.mf-h2, .mf-lead, .mf-btn*, .mf-eyebrow*, .mf-reveal,
   .mf-horizon, .mf-chip-icon, .mf-badge) comes from framework/components.css.
   Colour, type, radius and shadow all come from tokens — see
   theme-mediflare.css and framework/tokens.css. No raw hex below except
   inside multi-stop gradient ramps, where the stops are the design itself.
   ========================================================================== */

/* ==========================================================================
   Hero
   ========================================================================== */

.mf-pw-hero {
  position: relative;
  display: flex;
  align-items: center;
  /* Clipped on the inline axis only. The mock deliberately overhangs the
     block end, so that axis has to stay visible; clip on the other keeps the
     glow and the frame's shadow from ever widening the page. */
  overflow-x: clip;
  overflow-y: visible;
  /* No bottom padding: the mock's own negative margin below carries the
     spacing, by design — it hangs past the hero's edge into the arch. */
  padding: 132px 48px 0;

  /* The colour the benefits pane below opens on. The hero itself has no
     background — it shows the fixed --page-wash — so without this the flat
     pane butts against a wash that is a different tone at that scroll
     position, and the seam reads as a drawn line. Overridden to coal at the
     breakpoints where the pane falls back to the dark grid; see --pw-pin. */
}

/* On :root rather than on .mf-pw-hero: the wave divider below the hero fills
   its dome with this colour, and a sibling cannot read a custom property
   scoped to the hero. Declared once here, the hero's seam and the wave's fill
   can never disagree — including at the breakpoints below that flip it. */
:root {
  --pw-seam: var(--paper-100);

  /* The nav pill sticks at top:16 and stands 84px tall, so it permanently
     covers this much of any pinned pane. Every section that pins measures
     against the strip underneath it — centring on the raw viewport puts the
     top of the pinned content behind the nav. Two sections pin, so this is
     declared once here rather than twice. */
  --pw-nav-clear: 116px;
}

/* Resolves the last stretch of the hero to exactly --pw-seam, so the two
   surfaces meet on the same colour and the join disappears. It runs 230px
   past the hero's edge — the height of the divider below — because that
   divider's own flat base has to come off for it to paint over the mock, and
   this takes the base's place. Behind the mock (z-index -1) rather than over
   it, which is the whole point of moving it here.

   Flat fill plus a mask rather than a gradient of transparent stops: the
   seam colour is a variable, so shaping the ramp in the colour itself would
   need per-stop alpha of that variable. Masking a solid fill keeps the one
   token doing the work and puts the ramp shape where it can be read. The
   stops are weighted late — the eye catches the start of a linear paper
   fade as a band, so most of the travel happens in the last third. */
.mf-pw-hero::after {
  content: "";
  position: absolute;
  z-index: 0;
  inset-inline: 0;
  z-index: -1;
  inset-block-end: -230px;
  block-size: 490px;
  pointer-events: none;
  background: var(--pw-seam);
  -webkit-mask-image: linear-gradient(
    180deg, transparent 0%, rgb(0 0 0 / 0.3) 20%,
    rgb(0 0 0 / 0.72) 36%, rgb(0 0 0 / 0.94) 46%, #000 53%, #000 100%
  );
  mask-image: linear-gradient(
    180deg, transparent 0%, rgb(0 0 0 / 0.3) 20%,
    rgb(0 0 0 / 0.72) 36%, rgb(0 0 0 / 0.94) 46%, #000 53%, #000 100%
  );
}

/* The wave's dome has to be the colour the benefits pane opens on, not the
   framework default, or it shows as a band of its own against it. */
/* The hero resolves its last stretch to a flat --pw-seam, so the arch has to
   start on exactly that colour rather than on the page wash showing through.
   Both the glow's base and the dome below it take the same token. */
.mf-wave {
  --wave-fill: var(--pw-seam);
  --wave-base: var(--pw-seam);
}

/* The hero's own arch is a lid, not a floor: the browser mock runs off the
   bottom of the hero and this paints over it, so the frame reads as carrying
   on behind the curve instead of stopping short above it.

   Its flat base has to go transparent for that — an opaque band would cut the
   mock on a straight line instead of the curve — so .mf-pw-hero::after carries
   the flat colour behind the band instead. z-index 2 clears the hero's
   contents, which sit at auto; the phone and the score badge take 3 to stay in
   front of the curve. */
.mf-pw-hero + .mf-wave {
  z-index: 2;
  --wave-base: transparent;
}

.mf-pw-hero__wrap {
  position: relative;
  inline-size: 100%;
  max-inline-size: var(--content-max);
  margin-inline: auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: clamp(44px, 5vw, 72px);
  text-align: center;
}

.mf-pw-hero__text {
  inline-size: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
}

.mf-pw-hero__title {
  font-family: var(--font-display);
  font-weight: var(--weight-semibold);
  font-size: clamp(34px, 3.6vw, 56px);
  line-height: 1.1;
  letter-spacing: -0.015em;
  color: var(--ink);
  margin: 20px 0 0;
  text-wrap: balance;
}

.mf-pw-hero__lead {
  font-family: var(--font-body);
  font-size: 18px;
  line-height: 1.7;
  letter-spacing: 0.01em;
  color: var(--ink-muted);
  max-inline-size: 620px;
  margin: 24px auto 0;
}

.mf-pw-hero__ctas {
  display: flex;
  justify-content: center;
  gap: 14px;
  flex-wrap: wrap;
  margin-block-start: 32px;
}

.mf-pw-hero__trust {
  list-style: none;
  margin: 30px 0 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 10px 22px;
  font-family: var(--font-ui);
  font-size: 13px;
  font-weight: var(--weight-medium);
  color: var(--ink-soft);
}

.mf-pw-hero__trust li {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  white-space: nowrap;
}

/* --- The mock -----------------------------------------------------------
   One browser frame, centred under the copy and running close to the full
   width of the content column. It is the only thing in the lower half of the
   hero: no phone, no tablet, nothing flanking it, so the reader lands on the
   screenshot and stays there.
   ------------------------------------------------------------------------ */

.mf-pw-hero__art {
  position: relative;
  display: flex;
  justify-content: center;
  inline-size: 100%;
  /* The arch in the divider below peaks 60px under the hero's edge, and the
     gap between a floating mock and that peak read as dead space. This drops
     the mock past the edge so its bottom crosses the peak instead — it sits
     into the curve, and the arch runs out from behind it either side.

     Deep enough that the curve visibly crosses the frame rather than kissing
     its edge. The arch peaks 60px under the hero's edge at every width, so the
     cut depth is this figure minus 60 — about 80px on a wide screen. It scales
     down with the viewport because the mock does: a fixed 140px would swallow
     a third of the frame on a phone. */
  margin-block-end: clamp(-140px, -9.7vw, -95px);
}

/* Browser and phone stand side by side on one baseline, so the arch below
   crosses both at the depth its curve happens to be at that point — deepest
   through the middle of the browser, shallowest out at the phone.

   Wider than the browser alone used to be: the phone takes its width out of
   the row, and the browser has to stay the dominant thing in the hero. */
.mf-pw-hero__mock {
  position: relative;
  /* The end column's share of the row, and the phone's share of that column.
     Both live here so a breakpoint moves the whole arrangement with one
     number each. */
  --pw-side: 22%;
  /* Full column width, so the phone and the card above it share an edge on
     both sides rather than the phone sitting inset under a wider card. */
  --pw-phone: 100%;
  --pw-gap: clamp(14px, 1.9vw, 32px);

  inline-size: min(100%, 1400px);
  display: flex;
  align-items: flex-end;
  gap: var(--pw-gap);
}

/* Below the frame rather than beside it in the paint order. The mock is not a
   stacking context — it must not be, or the phone and badge inside it could
   not rise above the arch — so its screenshot paints with the ordinary in-flow
   content, which any z-index 0 sibling would cover. */
.mf-pw-hero__glow {
  position: absolute;
  z-index: -1;
  inline-size: min(880px, 100%);
  aspect-ratio: 1;
  inset-inline-start: 50%;
  inset-block-start: 50%;
  translate: -50% -50%;
  border-radius: 50%;
  background: radial-gradient(
    circle at 50% 50%,
    rgb(232 84 10 / 0.32) 0%,
    rgb(240 120 40 / 0.18) 36%,
    rgb(248 178 112 / 0.07) 60%,
    rgb(248 178 112 / 0) 76%
  );
  filter: blur(80px);
  pointer-events: none;
}

.mf-pw-frame {
  position: relative;
  /* Takes whatever the end column leaves. A zero basis rather than auto: with
     auto the frame asks for the capture's own 1500px, which is fine while the
     row cannot wrap and forces a line break of its own once it can.
     min-inline-size clears the default `auto` floor, or it refuses to shrink
     under its content either way. */
  flex: 1 1 0;
  min-inline-size: 0;
  background: var(--ink-on-dark);
  /* No border. The shadow and the dark chrome bar carry the separation on
     their own, and an outline round the whole frame boxed it in. */
  border-radius: var(--radius-tile);
  overflow: hidden;
  /* Deeper than the trio's, because the frame is now much larger — the same
     shadow scaled up with it would read as a smudge under a small card. */
  box-shadow: 0 46px 90px -32px rgb(80 50 15 / 0.38);
}

/* The one part of the frame that is chrome rather than content, so it cannot
   scale with the image. Tied to the viewport instead: the mock tracks the
   viewport up to its 1240px cap, which keeps the bar in proportion without a
   container query. */
.mf-pw-frame__bar {
  block-size: clamp(24px, 2.4vw, 38px);
  display: flex;
  align-items: center;
  gap: 7px;
  padding-inline: 14px;
  /* Dark-mode browser chrome. The same coal the score badge uses, so the two
     dark marks on the mock are the same tone. */
  background: var(--coal-720);
  border-block-end: 1px solid var(--coal-400);
}

.mf-pw-frame__dot {
  inline-size: 8px;
  block-size: 8px;
  border-radius: 50%;
  background: var(--grad-icon);
  flex: none;
}

.mf-pw-frame__url {
  margin-inline-start: 10px;
  font-family: var(--font-ui);
  font-size: clamp(9px, 0.85vw, 12px);
  letter-spacing: 0.02em;
  color: var(--ink-on-dark);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.mf-pw-frame__screen {
  /* The window's shape, not the image's — a browser window's ordinary 8:5,
     which is what this was before it was stretched to fit the practice's
     illustration in one screen. Nothing is stretched to fit any more: the
     page inside is over twice this tall and is clipped to it, exactly as a
     real window clips a page, and the scroll below is what reveals the rest. */
  aspect-ratio: 8 / 5;
  overflow: hidden;
  background: var(--paper-100);
}

/* The page itself — 1500x2699, a little over two screenfuls — sized to the
   window's width and left at its own height, so the window clips it. It then
   scrolls itself: slow enough to read as ambient rather than as something
   demanding attention, and only ever transform, so it stays on the compositor
   and costs no layout.

   -65.3% is the whole overhang, worked out from the two ratios above and
   fixed at every viewport because both the window and the page scale with the
   same width: the window is w/1.6 = 0.625w tall, the page is w*(2699/1500) =
   1.799w, so the travel is 1.174w — 65.3% of the page's own height. Re-derive
   it if either the crop or the window's ratio changes. */
.mf-pw-frame__screen img {
  display: block;
  inline-size: 100%;
  block-size: auto;
  animation: pwPageScroll 39s ease-in-out infinite;
  will-change: transform;
}

/* Hovering the window holds the page still, so anything worth a second look
   can have one. */
.mf-pw-frame:hover .mf-pw-frame__screen img { animation-play-state: paused; }

/* --- The end column ----------------------------------------------------
   One proof card sitting directly on top of the phone. Both hug the foot of
   the column, so the card is always just above the phone's top edge no matter
   how much taller the browser beside them happens to be.
   ------------------------------------------------------------------------ */

.mf-pw-hero__side {
  flex: 0 0 var(--pw-side);
  inline-size: var(--pw-side);
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  align-items: flex-end;
  gap: clamp(12px, 1.6vw, 24px);
}

/* --- The proof cards --- */

.mf-pw-hero__proof {
  list-style: none;
  margin: 0;
  padding: 0;
  inline-size: 100%;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: clamp(8px, 0.9vw, 14px);
  text-align: start;
}

/* Paper, not coal: it sits clear of the screenshot out in the column, so it
   has the page wash behind it rather than a practice's pale homepage, and the
   light card reads as part of this page rather than as a sticker on theirs.
   Armed by practice-websites.js, which adds .is-in to [data-mf-fcard]; --i
   comes off the loop index in the markup. */
.mf-pw-hero__proof-item {
  padding: clamp(12px, 1.1vw, 16px) clamp(13px, 1.2vw, 18px);
  border-radius: var(--radius-tile);
  background: var(--ink-on-dark);
  border: 1px solid var(--border-light);
  box-shadow: var(--shadow-card-sm);
  opacity: 0;
  transform: translateY(10px);
  transition:
    opacity 0.6s ease,
    transform 0.6s ease;
  transition-delay: calc(var(--i) * 90ms + 150ms);
}

.mf-pw-hero__proof-item.is-in { opacity: 1; transform: none; }

.mf-pw-hero__proof-icon {
  display: block;
  line-height: 0;
  margin-block-end: 9px;
}

.mf-pw-hero__proof-label {
  font-family: var(--font-ui);
  font-size: 13px;
  font-weight: var(--weight-semibold);
  line-height: 1.25;
  color: var(--ink);
  margin: 0;
}

/* Counted up from zero by JS on first view. Fixed width and tabular figures
   so the label does not reflow as the number gains digits. */
.mf-pw-hero__proof-num {
  display: inline-block;
  min-inline-size: 2.6ch;
  text-align: end;
  font-family: var(--font-display);
  font-weight: var(--weight-semibold);
  font-variant-numeric: tabular-nums;
}

.mf-pw-hero__proof-note {
  font-family: var(--font-body);
  font-size: 11px;
  line-height: 1.45;
  color: var(--ink-muted);
  margin: 6px 0 0;
}

/* --- The phone ----------------------------------------------------------
   A capture with its own device frame baked in, so there is no bezel, notch
   or screen mask here — just an image at the foot of the column. The shadow
   is a drop-shadow rather than a box-shadow so it follows the phone's rounded
   silhouette instead of boxing it.
   ------------------------------------------------------------------------ */

.mf-pw-hero__phone {
  inline-size: var(--pw-phone);
  block-size: auto;
  /* Dropped below the browser's baseline. The arch is a good deal lower out
     at the edges than it is through the middle, so matching baselines would
     leave the phone barely grazing it while the browser is cut deep. */
  margin-block-end: clamp(-38px, -2.6vw, -16px);
  filter: drop-shadow(0 34px 46px rgb(80 50 15 / 0.34));
}


/* ==========================================================================
   Benefits — the scroll-pinned ring

   The track is tall, the pane inside it sticks: the browser does the pinning
   natively, exactly as the homepage services scrub does. JS only reports how
   far through the track the reader is, by setting data-idx on the section
   and toggling .is-dark on the pane.

   --pw-scrub is the only place the scroll length is set. --pw-ring is the
   ring's diameter; every orbit measurement is derived from it, so the ring
   can be resized from one value.
   ========================================================================== */

.mf-pw-benefits {
  --pw-scrub: 480vh;

  --pw-band: calc(100vh - var(--pw-nav-clear));

  /* Radius of a benefit's node, and the clear space left between the node
     circles and the nearest edge of a card. */
  --pw-node-r: 24px;
  --pw-card-gap: 32px;
  --pw-card-w: 275px;
  --pw-card-min: 215px;

  /* The visual panel that pops beside a card. Zero here: it is only shown
     once the viewport is wide enough to hold it without squeezing the ring
     (see the min-width: 1440px block in Responsive), and while it is hidden
     it must cost the ring nothing — every expression below subtracts it, so
     a width of 0 leaves the geometry exactly as it was before the panel
     existed. --pw-viz-delay is the beat between the card landing and its
     visual following it. */
  --pw-viz-w: 0px;

  /* The beat between the card landing and each panel following it. Two
     values rather than one plus an offset, because a custom property cannot
     be defined in terms of itself: .mf-pw-bviz-b re-points --pw-viz-delay at
     the -b value, and everything downstream — including each visual's own
     internal stagger — keys off that. */
  --pw-viz-delay-a: 0.2s;
  --pw-viz-delay-b: 0.34s;
  --pw-viz-delay: var(--pw-viz-delay-a);

  /* Height of the tallest benefit card. Only a rough default — the stylesheet
     cannot measure wrapped text, so practice-websites.js overwrites this with
     the real measurement. Everything below sizes off it. */
  --pw-card-h: 190px;

  /* The largest ring whose outermost cards still fit the strip on both axes.

     Vertically the outermost card reaches (0.556 x ring) for the node, plus
     its own half height, plus the 37.5px fan, past the centre; 72px covers
     the fan and leaves a little breathing room, and 1.8 is 1/0.556 solved
     back for the ring. Horizontally the ring must leave a card beside it.

     Deriving the ring rather than fixing it at 54vh is what keeps the top
     nodes and cards clear of the sticky nav on short screens, and clear of
     the viewport edges on narrow ones. */
  --pw-ring: min(
    600px,
    calc((var(--pw-band) / 2 - var(--pw-card-h) * 0.964 - 16px) * 1.8),
    calc(
      (50vw - var(--pw-node-r) - var(--pw-card-gap) - var(--pw-card-min) - 24px) / 0.6
    ),
    /* And room for a visual panel, which sits where the ring's own curve was
       leaving space rather than beside the card — so it asks for the widest
       stand-off the ring ever demands plus its own width, not for anything
       off the card's share. 72px covers the nudge and step the panels take
       past the card and each other, and the margin at the viewport edge. */
    calc(
      (50vw - var(--pw-node-r) - var(--pw-card-gap) - var(--pw-viz-w) - 72px) / 0.6
    )
  );
  --pw-ring-radius: 60%;

  /* The card's own width, hoisted out of .mf-pw-bcard so the visual panel
     beside it can offset itself by exactly the same value. Two copies of
     this min() would be two things to keep in step; one is a fact. */
  --pw-card-real: min(
    var(--pw-card-w),
    calc(
      50vw - 0.6 * var(--pw-ring) - var(--pw-node-r) - var(--pw-card-gap) - 24px
    )
  );

  /* The width of the panel that sits beside the card, as opposed to the one
     above or below it. Derived from what is left over once the ring and the
     card have taken their share, rather than reserved up front — so it can
     never be the reason the ring shrinks. On a wide screen it reaches the
     same width as the other panel; on a laptop, where the card stands well
     off the ring's widest point, it takes the ~130px that remain. */
  --pw-viz-side-w: clamp(
    120px,
    calc(
      50vw - 0.6 * var(--pw-ring) - var(--pw-node-r) - var(--pw-card-gap) -
      var(--pw-card-real) - 14px - 24px
    ),
    var(--pw-viz-w)
  );

  /* Whether the ring may pin. The stylesheet owns this decision — it is the
     only layer that knows the breakpoint and the motion preference — and
     practice-websites.js reads it back to decide whether to run the scrub.
     It has to be a custom property rather than something like the pane's
     `position`, because the off state restyles that pane: reading a value
     the off state itself sets would latch the pin off permanently. */
  --pw-pin: 1;

  position: relative;
}

.mf-pw-benefits__track {
  position: relative;
  block-size: var(--pw-scrub);
}

.mf-pw-benefits__pane {
  position: sticky;
  inset-block-start: 0;
  block-size: 100vh;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
  /* Reserves the band the nav sits over, so `align-items: center` centres the
     ring in the strip the reader can actually see. box-sizing is border-box
     site-wide, so this shortens the content box rather than the pane.

     Less 80px: the ring was sitting further down the strip than it needed to.
     The content is centred in what is left, so the 80px lifts it by 40 — the
     ring itself is unchanged, since --pw-band still measures off the full
     nav clearance. */
  padding-block-start: calc(var(--pw-nav-clear) - 80px);
  /* Paper for the first half of the scrub, coal for the second — the flip
     is what carries the page into the dark What's Included section below. */
  background: var(--paper-100);
  transition: background 1.1s ease;
}

.mf-pw-benefits__pane.is-dark { background: var(--coal-900); }

/* --- Ambient glows ------------------------------------------------------
   Two stacks, one warm-on-paper and one ember-on-coal, crossfaded by the
   pane's .is-dark.

   Each blob's position and strength come from --gx/--gy/--go, which
   practice-websites.js reshuffles every time the scrub advances to the next
   benefit — so the light behind the ring drifts somewhere new on each step
   rather than sitting still. The values below are the pre-JS defaults; the
   long transitions are what turn a reshuffle into a slow wander instead of
   a jump. */

.mf-pw-amb {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  overflow: hidden;
  transition: opacity 1.1s ease;
}

.mf-pw-amb span {
  position: absolute;
  inset-inline-start: var(--gx);
  inset-block-start: var(--gy);
  opacity: var(--go, 1);
  border-radius: 50%;
  translate: -50% -50%;
  animation: pwDrift 16s ease-in-out infinite;
  transition:
    inset-inline-start 1.8s ease,
    inset-block-start 1.8s ease,
    opacity 1.4s ease;
}

.mf-pw-amb-light { opacity: 1; }
.mf-pw-amb-dark { opacity: 0; }
.mf-pw-benefits__pane.is-dark .mf-pw-amb-light { opacity: 0; }
.mf-pw-benefits__pane.is-dark .mf-pw-amb-dark { opacity: 1; }

/* The examples run on coal from the start, so their stack is simply on —
   there is no paper half to cross-fade from the way the benefit pane has. */
.mf-pw-collage__pane .mf-pw-amb-dark { opacity: 1; }

/* The collage itself is held to the section measure so the captures line up
   with everything else on the page, but the light behind them has no reason
   to stop there — clipped to 1350px it leaves two hard vertical seams of
   flat coal, and the widest dark blob sits at --gx: -6%, so the left seam
   cuts straight through its brightest part. The glow layer alone breaks out
   to the viewport; .mf-pw-examples clips the overflow, so nothing widens the
   document. */
.mf-pw-collage__pane .mf-pw-amb {
  inline-size: 100vw;
  inset-inline: 50% auto;
  translate: -50%;
}

.mf-pw-amb-light span:nth-child(1) {
  --gx: 22%;
  --gy: 16%;
  inline-size: 74vh;
  block-size: 74vh;
  background: radial-gradient(circle at 50% 50%, rgb(248 178 112 / 0.5), rgb(248 178 112 / 0.14) 44%, transparent 70%);
  filter: blur(70px);
}

.mf-pw-amb-light span:nth-child(2) {
  --gx: 74%;
  --gy: 78%;
  inline-size: 46vh;
  block-size: 46vh;
  background: radial-gradient(circle at 50% 50%, rgb(240 120 40 / 0.38), transparent 70%);
  filter: blur(60px);
  animation-duration: 19s;
  animation-direction: alternate-reverse;
}

.mf-pw-amb-light span:nth-child(3) {
  --gx: 88%;
  --gy: 30%;
  inline-size: 34vh;
  block-size: 34vh;
  background: radial-gradient(circle at 50% 50%, rgb(254 142 19 / 0.3), transparent 72%);
  filter: blur(52px);
  animation-duration: 12s;
}

.mf-pw-amb-light span:nth-child(4) {
  --gx: 14%;
  --gy: 72%;
  inline-size: 24vh;
  block-size: 24vh;
  background: radial-gradient(circle at 50% 50%, rgb(232 84 10 / 0.24), transparent 72%);
  filter: blur(44px);
  animation-duration: 22s;
}

.mf-pw-amb-dark span:nth-child(1) {
  --gx: -6%;
  --gy: 28%;
  inline-size: 78vh;
  block-size: 78vh;
  background: radial-gradient(circle at 50% 50%, rgb(232 84 10 / 0.22), rgb(232 84 10 / 0.07) 42%, transparent 68%);
  filter: blur(72px);
  animation-duration: 13s;
}

.mf-pw-amb-dark span:nth-child(2) {
  --gx: 96%;
  --gy: 66%;
  inline-size: 62vh;
  block-size: 62vh;
  background: radial-gradient(circle at 50% 50%, rgb(245 130 20 / 0.18), rgb(245 130 20 / 0.05) 44%, transparent 70%);
  filter: blur(64px);
  animation-duration: 17s;
  animation-direction: alternate-reverse;
}

.mf-pw-amb-dark span:nth-child(3) {
  --gx: 30%;
  --gy: 84%;
  inline-size: 34vh;
  block-size: 34vh;
  background: radial-gradient(circle at 50% 50%, rgb(254 142 19 / 0.16), transparent 70%);
  filter: blur(46px);
  animation-duration: 11s;
}

.mf-pw-amb-dark span:nth-child(4) {
  --gx: 72%;
  --gy: 14%;
  inline-size: 22vh;
  block-size: 22vh;
  background: radial-gradient(circle at 50% 50%, rgb(201 74 8 / 0.2), transparent 72%);
  filter: blur(38px);
  animation-duration: 20s;
  animation-direction: alternate-reverse;
}

/* --- The ring itself --- */

.mf-pw-ring {
  position: relative;
  z-index: 1;
  inline-size: var(--pw-ring);
  block-size: var(--pw-ring);
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
}

.mf-pw-ring__spin,
.mf-pw-ring__track,
.mf-pw-ring__arc {
  position: absolute;
  overflow: visible;
  /* The reset gives every svg `max-width: 100%`. That is a different property
     from the inline-size set below, so it is not overridden by it and silently
     clamped the oversized track and arc back to the ring's own width — while
     block-size stayed at 130%, leaving them 15% left of centre and crossing
     the gradient ring. Releasing the cap is what keeps the three circles
     concentric. */
  max-inline-size: none;
}

.mf-pw-ring__spin {
  inset: 0;
  inline-size: 100%;
  block-size: 100%;
  animation: pwSpin 30s linear infinite;
}

.mf-pw-ring__track,
.mf-pw-ring__arc {
  /* r=228 of a 500 viewBox is 91.2% of the ring; the SVG is oversized so the
     stroke's round caps are never clipped by the element box. */
  inset-inline-start: -15%;
  inset-block-start: -15%;
  inline-size: 130%;
  block-size: 130%;
}

.mf-pw-ring__track path {
  stroke: var(--flare-a15);
  transition: stroke 1.1s ease;
}

.mf-pw-benefits__pane.is-dark .mf-pw-ring__track path { stroke: rgb(255 255 255 / 0.12); }

/* The fill runs from the first benefit's node, so the arc starts where the
   orbit starts (113deg, see .mf-pw-orbit__item below). */
.mf-pw-ring__arc { rotate: 113deg; }

.mf-pw-ring__arc circle {
  transition: stroke-dasharray 1.1s cubic-bezier(0.33, 1, 0.68, 1);
}

.mf-pw-ring__core {
  position: relative;
  z-index: 1;
  inline-size: 74%;
  text-align: center;
}

/* Sized off the ring rather than the viewport: the ring now shrinks on short
   and narrow screens, and type keyed to vw would keep its size and burst out
   of the circle. */
.mf-pw-ring__title {
  font-family: var(--font-display);
  font-weight: var(--weight-semibold);
  font-size: clamp(22px, calc(var(--pw-ring) * 0.072), 38px);
  line-height: 1.1;
  letter-spacing: -0.01em;
  color: var(--ink);
  margin: 14px 0 0;
  transition: color 1.1s ease;
}

.mf-pw-ring__lead {
  font-family: var(--font-body);
  font-size: clamp(13px, calc(var(--pw-ring) * 0.027), 15px);
  line-height: 1.6;
  color: var(--ink-muted);
  margin: 13px auto 0;
  max-inline-size: 34ch;
  transition: color 1.1s ease;
}

.mf-pw-benefits__pane.is-dark .mf-pw-ring__title { color: var(--ink-on-dark); }
.mf-pw-benefits__pane.is-dark .mf-pw-ring__lead { color: var(--ink-on-dark-body); }

/* --- Orbit ------------------------------------------------------------
   Each item is a zero-size anchor placed on the ring from its own --i, so
   adding a benefit to practiceWebsites.json re-spaces the ring with no CSS
   change. --pw-ring-n is emitted on the section by the template. */

.mf-pw-orbit {
  list-style: none;
  margin: 0;
  padding: 0;
}

.mf-pw-orbit__item {
  /* 113deg puts the first node at lower-left and runs the ring anticlockwise
     from there, matching the arc's rotation and spin direction. */
  --angle: calc(113deg + var(--i) * (360deg / var(--pw-ring-n)));
  position: absolute;
  inset-inline-start: calc(50% + var(--pw-ring-radius) * cos(var(--angle)));
  inset-block-start: calc(50% + var(--pw-ring-radius) * sin(var(--angle)));
  inline-size: 0;
  block-size: 0;
  z-index: 3;
}

.mf-pw-orbit__node {
  position: absolute;
  inset-inline-start: -24px;
  inset-block-start: -24px;
  inline-size: 48px;
  block-size: 48px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  /* Opaque, so the dashed track never shows through a node. */
  background: var(--paper-300);
  border: 1px solid var(--flare-a18);
  color: var(--flare-600);
  transition:
    background 0.45s ease,
    border-color 0.45s ease,
    color 0.45s ease,
    transform 0.45s ease;
}

.mf-pw-benefits__pane.is-dark .mf-pw-orbit__node {
  background: var(--coal-700);
  border-color: var(--flare-a22);
}

/* Reached: filled and left filled, so the ring reads as a progress track. */
.mf-pw-orbit__item.is-done .mf-pw-orbit__node,
.mf-pw-benefits__pane.is-dark .mf-pw-orbit__item.is-done .mf-pw-orbit__node {
  background: var(--grad-icon);
  border-color: transparent;
  color: var(--ink-on-dark);
}

/* Turned to follow the ring rather than sitting at its drawn angle.

   The tangent at a node is the node's own angle plus a quarter turn. The
   glyph is drawn pointing up and to the right — an eighth turn anticlockwise
   of horizontal — so bringing the two together is the node's angle plus
   135deg. Only while the ring is pinned: in the card grid there is no ring
   for it to follow. */
.mf-pw-benefits[data-pw-pin="on"] .mf-pw-orbit__node.is-tangent svg {
  rotate: calc(var(--angle) + 135deg);
}

.mf-pw-orbit__item.is-active .mf-pw-orbit__node {
  transform: scale(1.16);
  animation: pwNodePulse 2.2s ease-out infinite;
}

/* --- The card that hangs off a node --- */

.mf-pw-bcard {
  position: absolute;
  inset-block-start: 50%;
  /* Both offsets are computed per card by practice-websites.js — see
     placeCards() there for why they cannot be static. */
  margin-block-start: var(--pw-card-shift, 0px);
  inline-size: var(--pw-card-real);
  padding: 19px 22px;
  border-radius: 16px;
  background: var(--ink-on-dark);
  border: 1px solid var(--paper-800);
  box-shadow: var(--shadow-card);
  opacity: 0;
  transform: translateY(-50%) scale(0.94);
  transition:
    opacity 0.45s ease,
    transform 0.45s ease;
  pointer-events: none;
}

.mf-pw-orbit__item.is-active .mf-pw-bcard {
  opacity: 1;
  transform: translateY(-50%) scale(1);
}

/* First half of the ring sits on the dark side of the flip, second half on
   the light — so those cards invert to stay legible against the pane. */
.mf-pw-benefits__pane.is-dark .mf-pw-bcard {
  background: var(--coal-720);
  border-color: var(--coal-400);
  box-shadow: var(--shadow-card-dark);
}

/* Cards on the left half open to the left of their node, the right half to
   the right, so a card never crosses the ring. */
/* Each card sits just outside the ring, beside its own node.

   The two offsets are solved per card by the JS rather than fixed here,
   because the horizontal clearance a card needs depends on how far its own
   vertical span reaches back towards the ring's centre line. A single static
   offset cannot satisfy both ends: small enough to keep the top and bottom
   cards near their nodes, and large enough to keep the left and right ones
   off the dashed track. */
.mf-pw-orbit__item-start .mf-pw-bcard {
  inset-inline-end: var(--pw-card-inset, 112px);
}

.mf-pw-orbit__item-end .mf-pw-bcard {
  inset-inline-start: var(--pw-card-inset, 112px);
}

.mf-pw-bcard__title {
  font-family: var(--font-display);
  font-weight: var(--weight-semibold);
  font-size: 18px;
  color: var(--ink);
  margin: 0 0 6px;
}

.mf-pw-bcard__body {
  font-family: var(--font-body);
  font-size: 14px;
  line-height: 1.6;
  color: var(--ink-muted);
  margin: 0;
}

.mf-pw-benefits__pane.is-dark .mf-pw-bcard__title { color: var(--ink-on-dark); }
.mf-pw-benefits__pane.is-dark .mf-pw-bcard__body { color: var(--ink-on-dark-body); }

/* --- The visual panel that follows the card ---------------------------
   A second panel further out from the ring, carrying a small picture of the
   same benefit: bars for hours saved, a rising line for search rank, one
   invoice for the monthly fee. The card lands first and this follows a beat
   later — the beat is --pw-viz-delay — so the sentence is read before the
   picture confirms it.

   Note the convention here is the opposite of .mf-pw-bcard's: the finished
   state is the default and the *unplayed* state is the exception, scoped to
   [data-pw-pin="on"]. That is what lets the same markup serve the card-grid
   fallback, where nothing is ever marked .is-active and every visual has to
   render already played.

   Only shown from 1440px up (see Responsive) — below that --pw-viz-w is 0,
   every expression that reserves room for it collapses, and the ring is
   exactly the ring that shipped before this panel existed. */

.mf-pw-bviz {
  /* One set of colour roles, re-pointed once when the pane flips. Every
     visual below paints from these rather than naming a palette step itself,
     so the other side of the flip is seven declarations instead of forty.

     The panel runs *against* the pane rather than with it: coal while the
     ring is on paper, paper once the ring goes to coal. The card beside it
     matches the pane, so the pair reads as a sentence and its illustration
     rather than as two of the same thing, and the picture is what catches
     the eye when it arrives a beat later.

     The shadow is the exception — it belongs to the surface underneath, not
     to the panel, so it stays keyed to the pane. */
  --viz-panel: var(--coal-720);
  --viz-border: var(--coal-400);
  --viz-ink: var(--ink-on-dark);
  --viz-dim: var(--ink-on-dark-body);
  --viz-mute: var(--ink-on-dark-dim);
  --viz-rail: var(--coal-400);
  --viz-well: var(--coal-600);

  position: absolute;
  inset-block-start: 50%;
  /* Never the card's line. practice-websites.js hangs the first panel past
     the card's top edge and the second past its bottom, so the column
     brackets the card and no panel edge can ever sit level with a card edge
     — see placeCards() there. The pair leans towards the ring's middle too,
     so a benefit low on the ring carries more of its weight above the card
     and one high on the ring carries more below. Falls back to the card's
     own line before the JS has measured. */
  margin-block-start: var(--pw-viz-shift, var(--pw-card-shift, 0px));
  inline-size: var(--pw-viz-w);
  padding: 15px 16px;
  border-radius: var(--radius-tile);
  background: var(--viz-panel);
  border: 1px solid var(--viz-border);
  box-shadow: var(--shadow-card-sm);
  transform: translateY(-50%);
  transition:
    opacity 0.5s ease var(--pw-viz-delay),
    transform 0.55s cubic-bezier(0.34, 1.32, 0.64, 1) var(--pw-viz-delay);
  pointer-events: none;
}

.mf-pw-benefits__pane.is-dark .mf-pw-bviz,
.mf-pw-benefits:not([data-pw-pin="on"]) .mf-pw-bviz {
  --viz-panel: var(--paper-100);
  --viz-border: var(--paper-800);
  --viz-ink: var(--ink);
  --viz-dim: var(--ink-muted);
  --viz-mute: var(--ink-soft);
  --viz-rail: var(--paper-800);
  --viz-well: var(--paper-300);

  box-shadow: var(--shadow-card-dark-sm);
}

/* Each panel takes its own line from the JS, and the second one its own,
   later beat. */
.mf-pw-bviz-a {
  --pw-viz-shift: var(--pw-viz-a-shift);
  --pw-viz-inset: var(--pw-viz-a-inset);
}

/* The second panel is the one that stays beside the card, so it takes the
   width the ring and card leave rather than the full one. */
.mf-pw-bviz-b {
  --pw-viz-shift: var(--pw-viz-b-shift);
  --pw-viz-inset: var(--pw-viz-b-inset);
  --pw-viz-delay: var(--pw-viz-delay-b);

  inline-size: var(--pw-viz-side-w);
}

/* Each panel stands off the ring by its own amount, solved against the
   curve at the height it sits at — see placePanels() in the JS. The card's
   inset is the fallback for the moment before that has run. */
.mf-pw-orbit__item-start .mf-pw-bviz {
  inset-inline-end: var(--pw-viz-inset, var(--pw-card-inset, 112px));
  transform-origin: right center;
}

.mf-pw-orbit__item-end .mf-pw-bviz {
  inset-inline-start: var(--pw-viz-inset, var(--pw-card-inset, 112px));
  transform-origin: left center;
}

/* Unplayed: only ever while the ring is pinned and this benefit is not the
   one being read. Exits carry no delay — a card being scrolled past should
   not hold its visual on screen for another beat. */
.mf-pw-benefits[data-pw-pin="on"] .mf-pw-orbit__item:not(.is-active) .mf-pw-bviz {
  opacity: 0;
  transform: translateY(-50%) scale(0.88);
  transition-delay: 0s;
  transition-duration: 0.3s;
}

/* When each of a visual's own parts plays, measured from the panel's
   arrival. --n is the part's index within the visual, set in the markup.

   Declared on the descendants rather than on the panel because a custom
   property is substituted where it is declared: computing this once on
   .mf-pw-bviz would resolve --n there — nowhere, so zero — and inherit the
   same delay to every part, which is no stagger at all. */
.mf-pw-bviz * {
  --viz-step: calc(var(--pw-viz-delay) + 0.12s + var(--n, 0) * 0.07s);
}

/* When a visual stops arriving and starts living: after its own parts have
   finished, so the idle motion never fights the entrance. */
.mf-pw-bviz * {
  --viz-idle: calc(var(--pw-viz-delay) + 0.9s);
}

/* --- Shared visual furniture --- */

.mf-pw-viz-track,
.mf-pw-viz-bars,
.mf-pw-viz-cols,
.mf-pw-viz-spark,
.mf-pw-viz-chips,
.mf-pw-viz-faces,
.mf-pw-viz-stat {
  display: grid;
  gap: 9px;
}

.mf-pw-viz-foot {
  font-family: var(--font-ui);
  font-size: 10.5px;
  line-height: 1.4;
  color: var(--viz-dim);
  margin: 0;
}

.mf-pw-viz-foot b {
  color: var(--viz-ink);
  font-weight: var(--weight-semibold);
}

.mf-pw-viz-ends {
  display: flex;
  justify-content: space-between;
  gap: 8px;
  margin: 0;
  font-family: var(--font-ui);
  font-size: 10.5px;
  color: var(--viz-dim);
}

.mf-pw-viz-ends b {
  color: var(--viz-ink);
  font-weight: var(--weight-semibold);
}

/* --- Fast service: a job crossing a filling track --- */

.mf-pw-viz-pill {
  justify-self: start;
  font-family: var(--font-ui);
  font-size: 10.5px;
  font-weight: var(--weight-semibold);
  color: var(--ink-on-dark);
  background: var(--grad-icon);
  border-radius: var(--radius-pill);
  padding: 3px 9px;
}

.mf-pw-viz-track__rail {
  position: relative;
  display: block;
  block-size: 4px;
  margin-block: 4px;
  border-radius: var(--radius-pill);
  background: var(--viz-rail);
}

.mf-pw-viz-track__fill {
  position: absolute;
  inset-block: 0;
  inset-inline-start: 0;
  inline-size: 100%;
  border-radius: var(--radius-pill);
  background: var(--grad-brand-flat);
  /* Clips the sheen that runs along it while the benefit is being read. The
     end dots are siblings, so they stay outside this. */
  overflow: hidden;
  transition: inline-size 0.7s cubic-bezier(0.22, 1, 0.36, 1) var(--viz-step);
}

.mf-pw-viz-track__fill::after {
  content: "";
  position: absolute;
  inset-block: 0;
  inline-size: 45%;
  background: linear-gradient(90deg, transparent, rgb(255 255 255 / 0.55), transparent);
  translate: -140% 0;
}

.mf-pw-viz-track__dot {
  position: absolute;
  inset-block-start: 50%;
  inline-size: 9px;
  block-size: 9px;
  border-radius: 50%;
  translate: -50% -50%;
  background: var(--viz-panel);
  border: 1.5px solid var(--flare-500);
}

.mf-pw-viz-track__dot-a { inset-inline-start: 0; }

.mf-pw-viz-track__dot-b {
  --n: 5;
  inset-inline-start: 100%;
  background: var(--flare-600);
  border-color: transparent;
  transition: scale 0.4s cubic-bezier(0.34, 1.5, 0.64, 1) var(--viz-step);
}

/* --- Save staff time: two rails, before and after --- */

.mf-pw-viz-bar__head {
  display: flex;
  justify-content: space-between;
  gap: 6px;
  margin: 0 0 5px;
  font-family: var(--font-ui);
  font-size: 10.5px;
  color: var(--viz-dim);
}

.mf-pw-viz-bar__head b {
  color: var(--viz-ink);
  font-weight: var(--weight-semibold);
}

.mf-pw-viz-bar__rail {
  display: block;
  block-size: 7px;
  border-radius: var(--radius-pill);
  background: var(--viz-rail);
  overflow: hidden;
}

.mf-pw-viz-bar__rail i {
  display: block;
  block-size: 100%;
  inline-size: var(--fill);
  border-radius: var(--radius-pill);
  background: var(--viz-mute);
  transition: inline-size 0.75s cubic-bezier(0.22, 1, 0.36, 1) var(--viz-step);
}

.mf-pw-viz-bar.is-flare .mf-pw-viz-bar__rail i { background: var(--grad-brand-flat); }

/* --- Financial benefits: spiky hourly bills against one flat line --- */

.mf-pw-viz-cols__plot {
  position: relative;
  display: flex;
  align-items: flex-end;
  gap: 5px;
  block-size: 48px;
}

.mf-pw-viz-cols__plot i {
  flex: 1;
  block-size: var(--h);
  border-radius: var(--radius-xs) var(--radius-xs) 0 0;
  background: var(--viz-mute);
  opacity: 0.5;
  transform-origin: bottom center;
  transition: scale 0.45s cubic-bezier(0.22, 1, 0.36, 1) var(--viz-step);
}

/* Sits at the height the plan costs every month, whatever the bills do. */
.mf-pw-viz-cols__line {
  --n: 6;
  position: absolute;
  inset-inline: 0;
  inset-block-end: 34%;
  block-size: 2px;
  border-radius: var(--radius-pill);
  background: var(--grad-brand-flat);
  transform-origin: left center;
  transition: scale 0.55s cubic-bezier(0.22, 1, 0.36, 1) var(--viz-step);
}

/* --- Higher Google rank: a line that draws itself upward --- */

.mf-pw-viz-spark { position: relative; }

.mf-pw-viz-spark svg {
  display: block;
  inline-size: 100%;
  block-size: 52px;
}

.mf-pw-viz-spark__line {
  fill: none;
  stroke: var(--flare-500);
  stroke-width: 2.5;
  stroke-linecap: round;
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
  stroke-dasharray: 220;
  stroke-dashoffset: 0;
  transition: stroke-dashoffset 0.9s cubic-bezier(0.33, 1, 0.68, 1) var(--viz-step);
}

.mf-pw-viz-spark__tip {
  --n: 8;
  position: absolute;
  inset-block-start: 1px;
  inset-inline-end: 1px;
  inline-size: 9px;
  block-size: 9px;
  border-radius: 50%;
  background: var(--flare-600);
  box-shadow: 0 0 0 3px var(--flare-a20);
  transition: scale 0.4s cubic-bezier(0.34, 1.5, 0.64, 1) var(--viz-step);
}

/* --- Uncapped tasks / no revision limits: a run of pills --- */

.mf-pw-viz-chips__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 5px;
}

.mf-pw-viz-chips__list li {
  font-family: var(--font-ui);
  font-size: 10.5px;
  color: var(--viz-ink);
  background: var(--viz-well);
  border: 1px solid var(--viz-rail);
  border-radius: var(--radius-pill);
  padding: 3px 8px;
  transition:
    opacity 0.35s ease var(--viz-step),
    scale 0.4s cubic-bezier(0.34, 1.5, 0.64, 1) var(--viz-step);
}

/* One chip lit, the rest present but ruled out. */
.mf-pw-viz-chips__list .is-off {
  color: var(--viz-dim);
  background: none;
  border-style: dashed;
}

.mf-pw-viz-chips__list .is-on,
.mf-pw-viz-chips__list .is-more {
  color: var(--ink-on-dark);
  background: var(--grad-icon);
  border-color: transparent;
  font-weight: var(--weight-semibold);
}

/* Chained rather than listed: v1 leads to v2 leads to v3, all for the same
   money. The arrow is drawn in the gap the list already leaves. */
.mf-pw-viz-chips.is-flow .mf-pw-viz-chips__list { gap: 5px 15px; }

.mf-pw-viz-chips.is-flow li + li { position: relative; }

.mf-pw-viz-chips.is-flow li + li::before {
  content: "→";
  position: absolute;
  inset-inline-start: -13px;
  inset-block-start: 50%;
  translate: 0 -50%;
  font-size: 10px;
  color: var(--viz-dim);
}

/* --- Real human support: people, not a queue --- */

.mf-pw-viz-faces__row {
  display: flex;
  margin: 0;
}

.mf-pw-viz-faces__row span {
  inline-size: 34px;
  block-size: 34px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  font-family: var(--font-ui);
  font-size: 11px;
  font-weight: var(--weight-semibold);
  color: var(--ink-on-dark);
  background: var(--grad-icon);
  border: 2px solid var(--viz-panel);
  margin-inline-start: -9px;
  transition: scale 0.4s cubic-bezier(0.34, 1.5, 0.64, 1) var(--viz-step);
}

.mf-pw-viz-faces__row span:first-child { margin-inline-start: 0; }
.mf-pw-viz-faces__row span:nth-child(2) { background: var(--grad-pulse); }
.mf-pw-viz-faces__row span:nth-child(3) { background: var(--grad-brand); }

/* --- Higher Google rank: the result that gets found --- */

.mf-pw-viz-serp {
  display: grid;
  gap: 8px;
}

.mf-pw-viz-serp__row {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0;
  /* The rows below the first are the competition: drawn, but out of focus. */
  opacity: 0.42;
  transition: opacity 0.4s ease var(--viz-step);
}

.mf-pw-viz-serp__row.is-first { opacity: 1; }

/* Indented by exactly the badge the dimmed rows do not carry, so all three
   sets of lines start on the same edge. */
.mf-pw-viz-serp__row:not(.is-first) { padding-inline-start: 26px; }

.mf-pw-viz-serp__row b {
  flex: none;
  inline-size: 18px;
  block-size: 18px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  font-family: var(--font-ui);
  font-size: 10px;
  font-weight: var(--weight-semibold);
  color: var(--ink-on-dark);
  background: var(--grad-icon);
}

.mf-pw-viz-serp__row span {
  flex: 1;
  display: grid;
  gap: 5px;
}

.mf-pw-viz-serp__row i {
  block-size: 5px;
  border-radius: var(--radius-pill);
  background: var(--viz-mute);
}

.mf-pw-viz-serp__row em {
  block-size: 4px;
  inline-size: 62%;
  border-radius: var(--radius-pill);
  background: var(--viz-mute);
  opacity: 0.55;
}

.mf-pw-viz-serp__row.is-first i {
  background: var(--grad-brand-flat);
  transform-origin: left center;
  transition: scale 0.5s cubic-bezier(0.22, 1, 0.36, 1) var(--viz-step);
}

/* --- Real human support: how the exchange actually goes --- */

.mf-pw-viz-chat {
  display: grid;
  gap: 7px;
  justify-items: start;
}

.mf-pw-viz-chat p {
  margin: 0;
  max-inline-size: 92%;
  padding: 7px 10px;
  font-family: var(--font-ui);
  font-size: 10.5px;
  line-height: 1.4;
  transition:
    opacity 0.35s ease var(--viz-step),
    translate 0.4s cubic-bezier(0.22, 1, 0.36, 1) var(--viz-step);
}

.mf-pw-viz-chat__in {
  color: var(--viz-ink);
  background: var(--viz-well);
  border: 1px solid var(--viz-rail);
  border-radius: var(--radius-chip) var(--radius-chip) var(--radius-chip) 3px;
}

.mf-pw-viz-chat__out {
  justify-self: end;
  color: var(--ink-on-dark);
  background: var(--grad-icon);
  border-radius: var(--radius-chip) var(--radius-chip) 3px var(--radius-chip);
}

/* --- One monthly investment --- */

/* Wraps: beside the card on a laptop the panel is only ~120px wide (see
   --pw-viz-side-w), which holds the figure but not the figure and its unit.
   There the unit drops under the figure, whole, rather than running out of
   the panel's edge. */
.mf-pw-viz-stat__v {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 4px 7px;
  margin: 0;
}

.mf-pw-viz-stat__v b {
  font-family: var(--font-display);
  font-size: 40px;
  font-weight: var(--weight-semibold);
  line-height: 1;
  background: var(--grad-brand);
  background-clip: text;
  -webkit-background-clip: text;
  color: transparent;
}

.mf-pw-viz-stat__v em {
  font-family: var(--font-ui);
  font-style: normal;
  font-size: 12px;
  color: var(--viz-ink);
  white-space: nowrap;
}

/* A year of months, every one the same height — the picture of a flat fee. */
.mf-pw-viz-stat__year {
  display: flex;
  align-items: flex-end;
  gap: 3px;
}

.mf-pw-viz-stat__year i {
  flex: 1;
  block-size: 15px;
  border-radius: var(--radius-xs);
  background: var(--grad-brand-v);
  opacity: 0.85;
  transform-origin: bottom center;
  transition: scale 0.35s cubic-bezier(0.22, 1, 0.36, 1) var(--viz-step);
}

/* --- Unplayed states -------------------------------------------------
   Every part above rests in its finished state, so the card grid renders a
   played visual with no JS and no .is-active in sight. These are the values
   it winds back to while the ring is pinned and the benefit is not the one
   being read; the transitions that carry it forward are declared on the
   elements themselves. */

.mf-pw-benefits[data-pw-pin="on"] .mf-pw-orbit__item:not(.is-active) .mf-pw-viz-track__fill {
  inline-size: 0;
}

.mf-pw-benefits[data-pw-pin="on"] .mf-pw-orbit__item:not(.is-active) .mf-pw-viz-track__dot-b {
  scale: 0;
}

.mf-pw-benefits[data-pw-pin="on"] .mf-pw-orbit__item:not(.is-active) .mf-pw-viz-bar__rail i {
  inline-size: 0;
}

.mf-pw-benefits[data-pw-pin="on"] .mf-pw-orbit__item:not(.is-active) .mf-pw-viz-cols__plot i {
  scale: 1 0;
}

.mf-pw-benefits[data-pw-pin="on"] .mf-pw-orbit__item:not(.is-active) .mf-pw-viz-cols__line {
  scale: 0 1;
}

.mf-pw-benefits[data-pw-pin="on"] .mf-pw-orbit__item:not(.is-active) .mf-pw-viz-spark__line {
  stroke-dashoffset: 220;
}

.mf-pw-benefits[data-pw-pin="on"] .mf-pw-orbit__item:not(.is-active) .mf-pw-viz-spark__tip {
  scale: 0;
}

.mf-pw-benefits[data-pw-pin="on"] .mf-pw-orbit__item:not(.is-active) .mf-pw-viz-chips__list li {
  opacity: 0;
  scale: 0.8;
}

.mf-pw-benefits[data-pw-pin="on"] .mf-pw-orbit__item:not(.is-active) .mf-pw-viz-faces__row span {
  scale: 0;
}

.mf-pw-benefits[data-pw-pin="on"] .mf-pw-orbit__item:not(.is-active) .mf-pw-viz-stat__year i {
  scale: 1 0;
}

.mf-pw-benefits[data-pw-pin="on"] .mf-pw-orbit__item:not(.is-active) .mf-pw-viz-serp__row {
  opacity: 0;
}

.mf-pw-benefits[data-pw-pin="on"] .mf-pw-orbit__item:not(.is-active) .mf-pw-viz-serp__row.is-first i {
  scale: 0 1;
}

.mf-pw-benefits[data-pw-pin="on"] .mf-pw-orbit__item:not(.is-active) .mf-pw-viz-chat p {
  opacity: 0;
}

/* Nothing is held on screen on the way out: the whole panel is fading and
   shrinking already, and parts unwinding behind it read as a glitch. */
.mf-pw-benefits[data-pw-pin="on"] .mf-pw-orbit__item:not(.is-active) .mf-pw-viz-track__fill,
.mf-pw-benefits[data-pw-pin="on"] .mf-pw-orbit__item:not(.is-active) .mf-pw-viz-track__dot-b,
.mf-pw-benefits[data-pw-pin="on"] .mf-pw-orbit__item:not(.is-active) .mf-pw-viz-bar__rail i,
.mf-pw-benefits[data-pw-pin="on"] .mf-pw-orbit__item:not(.is-active) .mf-pw-viz-cols__plot i,
.mf-pw-benefits[data-pw-pin="on"] .mf-pw-orbit__item:not(.is-active) .mf-pw-viz-cols__line,
.mf-pw-benefits[data-pw-pin="on"] .mf-pw-orbit__item:not(.is-active) .mf-pw-viz-spark__line,
.mf-pw-benefits[data-pw-pin="on"] .mf-pw-orbit__item:not(.is-active) .mf-pw-viz-spark__tip,
.mf-pw-benefits[data-pw-pin="on"] .mf-pw-orbit__item:not(.is-active) .mf-pw-viz-chips__list li,
.mf-pw-benefits[data-pw-pin="on"] .mf-pw-orbit__item:not(.is-active) .mf-pw-viz-faces__row span,
.mf-pw-benefits[data-pw-pin="on"] .mf-pw-orbit__item:not(.is-active) .mf-pw-viz-stat__year i,
.mf-pw-benefits[data-pw-pin="on"] .mf-pw-orbit__item:not(.is-active) .mf-pw-viz-serp__row,
.mf-pw-benefits[data-pw-pin="on"] .mf-pw-orbit__item:not(.is-active) .mf-pw-viz-serp__row.is-first i,
.mf-pw-benefits[data-pw-pin="on"] .mf-pw-orbit__item:not(.is-active) .mf-pw-viz-chat p {
  transition-delay: 0s;
  transition-duration: 0.2s;
}

/* --- Idle motion ------------------------------------------------------
   What each visual does once it has arrived. Only ever on the benefit being
   read — one panel pair at a time — and only while the ring is pinned, so
   the card grid (which is also where reduced-motion readers land, the pin
   being off for them) stays perfectly still.

   Everything here is slow and small: a pulse on the thing the visual is
   actually claiming, a sheen along a track, a wave across a year. The point
   is that the panel looks live rather than printed, not that it performs. */

/* Fast service — the light runs the length of the track, over and over. */
.mf-pw-benefits[data-pw-pin="on"] .is-active .mf-pw-viz-track__fill::after {
  animation: pwVizSheen 3.4s cubic-bezier(0.5, 0, 0.5, 1) var(--viz-idle) infinite;
}

.mf-pw-benefits[data-pw-pin="on"] .is-active .mf-pw-viz-track__dot-b {
  animation: pwVizPing 2.6s ease-out var(--viz-idle) infinite;
}

/* Save staff time — the short bar is the claim, so it is what breathes. */
.mf-pw-benefits[data-pw-pin="on"] .is-active .mf-pw-viz-bar.is-flare .mf-pw-viz-bar__rail i {
  animation: pwVizBreathe 2.8s ease-in-out var(--viz-idle) infinite;
}

/* Financial benefits — the flat line holds while the bills spike around it. */
.mf-pw-benefits[data-pw-pin="on"] .is-active .mf-pw-viz-cols__line {
  animation: pwVizBreathe 3s ease-in-out var(--viz-idle) infinite;
}

/* Higher Google rank — the landing point, and the rank that earned it. */
.mf-pw-benefits[data-pw-pin="on"] .is-active .mf-pw-viz-spark__tip,
.mf-pw-benefits[data-pw-pin="on"] .is-active .mf-pw-viz-serp__row.is-first b {
  animation: pwVizPing 2.6s ease-out var(--viz-idle) infinite;
}

/* Uncapped tasks, revisions — the lit pill among the ones ruled out. */
.mf-pw-benefits[data-pw-pin="on"] .is-active .mf-pw-viz-chips__list .is-on,
.mf-pw-benefits[data-pw-pin="on"] .is-active .mf-pw-viz-chips__list .is-more {
  animation: pwVizPing 3s ease-out var(--viz-idle) infinite;
}

/* Real human support — people shift about; a queue does not. */
.mf-pw-benefits[data-pw-pin="on"] .is-active .mf-pw-viz-faces__row span {
  animation: pwVizBob 3.2s ease-in-out calc(var(--viz-idle) + var(--n) * 0.24s) infinite;
}

.mf-pw-benefits[data-pw-pin="on"] .is-active .mf-pw-viz-chat__out {
  animation: pwVizBreathe 3s ease-in-out var(--viz-idle) infinite;
}

/* No revision limits — the latest version, with more of them always on. */
.mf-pw-benefits[data-pw-pin="on"] .is-active .mf-pw-viz-chips.is-flow li:last-child {
  animation: pwVizPing 3s ease-out var(--viz-idle) infinite;
}

/* Wherever a visual's whole point is one figure, that figure has a pulse.
   Scale rather than colour: the numeral is gradient-clipped text, so
   anything that touches its paint touches the gradient with it. */
.mf-pw-benefits[data-pw-pin="on"] .is-active .mf-pw-viz-stat__v b {
  animation: pwVizBeat 3s ease-in-out var(--viz-idle) infinite;
}

/* One monthly investment — the same amount, month after month after month. */
.mf-pw-benefits[data-pw-pin="on"] .is-active .mf-pw-viz-stat__year i {
  animation: pwVizWave 2.6s ease-in-out calc(var(--viz-idle) + var(--n) * 0.09s) infinite;
}

/* --- Pin off ------------------------------------------------------------
   The ring needs both room for the cards either side of it and a viewport
   tall enough to hold it, so below the breakpoint (and under reduced motion,
   and with no JS at all) the whole thing degrades to a plain card grid on
   coal. Keyed on :not([data-pw-pin="on"]) so the grid is the default and the
   pin is what has to be switched on — practice-websites.js only sets that
   attribute once it has confirmed the stylesheet actually made the pane
   sticky. */

.mf-pw-benefits:not([data-pw-pin="on"]) .mf-pw-benefits__track { block-size: auto; }

.mf-pw-benefits:not([data-pw-pin="on"]) .mf-pw-benefits__pane {
  position: static;
  block-size: auto;
  display: block;
  /* Was 90px on top. The arch above this closes on the same coal, so the
     dome's own curve is already most of the space over the eyebrow. */
  /* 40px at the foot: What's Included follows on the same coal with its own
     90px top, and 100px here as well left a 190px hole between the last
     benefit and the next eyebrow. */
  padding: 10px 40px 40px;
  background: var(--coal-900);
}

.mf-pw-benefits:not([data-pw-pin="on"]) .mf-pw-amb-light { opacity: 0; }
.mf-pw-benefits:not([data-pw-pin="on"]) .mf-pw-amb-dark { opacity: 1; }

.mf-pw-benefits:not([data-pw-pin="on"]) .mf-pw-ring {
  display: block;
  inline-size: 100%;
  block-size: auto;
  max-inline-size: var(--section-max);
  margin-inline: auto;
}

.mf-pw-benefits:not([data-pw-pin="on"]) .mf-pw-ring__spin,
.mf-pw-benefits:not([data-pw-pin="on"]) .mf-pw-ring__track,
.mf-pw-benefits:not([data-pw-pin="on"]) .mf-pw-ring__arc { display: none; }

.mf-pw-benefits:not([data-pw-pin="on"]) .mf-pw-ring__core {
  inline-size: 100%;
  max-inline-size: 680px;
  margin-inline: auto;
  margin-block-end: 52px;
}

.mf-pw-benefits:not([data-pw-pin="on"]) .mf-pw-ring__title { color: var(--ink-on-dark); }
.mf-pw-benefits:not([data-pw-pin="on"]) .mf-pw-ring__lead { color: var(--ink-on-dark-body); }

.mf-pw-benefits:not([data-pw-pin="on"]) .mf-pw-orbit {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  gap: 16px;
}

.mf-pw-benefits:not([data-pw-pin="on"]) .mf-pw-orbit__item {
  position: static;
  inline-size: auto;
  block-size: auto;
  padding: 24px;
  border-radius: var(--radius-panel);
  background: var(--coal-720);
  border: 1px solid var(--coal-400);
}

.mf-pw-benefits:not([data-pw-pin="on"]) .mf-pw-orbit__node {
  position: static;
  inline-size: 44px;
  block-size: 44px;
  background: var(--grad-icon);
  border-color: transparent;
  color: var(--ink-on-dark);
  margin-block-end: 16px;
  transform: none;
  animation: none;
}

.mf-pw-benefits:not([data-pw-pin="on"]) .mf-pw-bcard {
  position: static;
  inline-size: auto;
  margin: 0;
  padding: 0;
  background: none;
  border: none;
  box-shadow: none;
  opacity: 1;
  transform: none;
  pointer-events: auto;
}

.mf-pw-benefits:not([data-pw-pin="on"]) .mf-pw-bcard__title { color: var(--ink-on-dark); }
.mf-pw-benefits:not([data-pw-pin="on"]) .mf-pw-bcard__body { color: var(--ink-on-dark-body); }

/* The visual is worth keeping here — it is the same picture, it just sits
   under the copy instead of beside it. Nothing winds it back in this layout,
   so it renders already played. */
.mf-pw-benefits:not([data-pw-pin="on"]) .mf-pw-bviz {
  position: static;
  inline-size: auto;
  max-inline-size: 300px;
  margin-block-start: 14px;
  transform: none;
  box-shadow: none;
  pointer-events: auto;
}


/* ==========================================================================
   What's included — the dark bento
   ========================================================================== */

.mf-pw-inc {
  position: relative;
  padding: 90px 40px 110px;
  overflow: clip;
  background: var(--coal-900);
  margin-block-start: -2px;
}

.mf-pw-inc__bloom {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    radial-gradient(ellipse 50% 45% at 100% 30%, rgb(232 84 10 / 0.2), transparent 62%),
    radial-gradient(ellipse 45% 40% at 0% 82%, rgb(160 50 8 / 0.13), transparent 62%);
}

.mf-pw-inc__inner {
  position: relative;
  z-index: 1;
  max-inline-size: var(--section-max);
  margin-inline: auto;
}

.mf-pw-inc__intro {
  text-align: center;
  max-inline-size: 720px;
  margin: 0 auto 52px;
}

.mf-pw-inc__intro .mf-eyebrow { margin-block-end: 22px; }

.mf-pw-inc__lead {
  font-family: var(--font-body);
  font-size: 18px;
  line-height: 1.7;
  color: var(--ink-on-dark-body);
  margin: 18px auto 0;
  max-inline-size: 560px;
}

/* --- Grid ---------------------------------------------------------------
   Six columns with explicit placements for the eight feature cells; the five
   slim tiles then flow into whatever is left. Below the breakpoint the whole
   thing collapses to auto-fit (see the media queries at the foot). */

.mf-pw-bento {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  grid-auto-rows: minmax(92px, auto);
  gap: 16px;
}

.mf-pw-cell {
  background: var(--coal-720);
  border: 1px solid var(--coal-400);
  border-radius: var(--radius-panel);
  padding: 22px;
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.mf-pw-inc__head {
  display: flex;
  gap: 13px;
  align-items: flex-start;
}

.mf-pw-inc__head > svg { flex: none; margin-block-start: 2px; }

.mf-pw-inc__title {
  font-family: var(--font-display);
  font-weight: var(--weight-semibold);
  font-size: 17px;
  color: var(--ink-on-dark);
  margin: 0 0 6px;
}

.mf-pw-inc__body {
  font-family: var(--font-body);
  font-size: 13.5px;
  line-height: 1.6;
  color: var(--ink-on-dark-body);
  margin: 0;
}

.mf-pw-cell-design { grid-column: 1 / span 4; grid-row: 1 / span 5; padding: 28px; }
.mf-pw-cell-bookings { grid-column: 5 / span 2; grid-row: 1 / span 5; }
.mf-pw-cell-photos { grid-column: 1 / span 3; grid-row: 6 / span 2; padding: 26px; }
.mf-pw-cell-banners { grid-column: 4 / span 3; grid-row: 6 / span 2; }
.mf-pw-cell-seo { grid-column: 1 / span 2; grid-row: 8 / span 2; }
.mf-pw-cell-monitor { grid-column: 3 / span 2; grid-row: 8 / span 2; }
.mf-pw-cell-updates { grid-column: 5 / span 2; grid-row: 8 / span 2; }
.mf-pw-cell-speed { grid-column: 1 / span 2; grid-row: 10 / span 2; }
.mf-pw-cell-slim {
  grid-column: span 2;
  position: relative;
  overflow: hidden;
}

/* Every cell warms its border on hover; only the slim ones lift, because the
   big ones hold panels you are meant to point at. */
.mf-pw-cell {
  transition: border-color 0.28s var(--ease-out), translate 0.28s var(--ease-out);
}

.mf-pw-cell:hover { border-color: var(--flare-a30); }
.mf-pw-cell-slim:hover { translate: 0 -3px; }

/* --- The five short tiles, each with its own panel --- */

/* Shared shell: same inset panel the big tiles use, so the row reads as one
   family even though every panel inside is a different shape. */
.mf-pw-cert,
.mf-pw-domain,
.mf-pw-map,
.mf-pw-meter,
.mf-pw-rail {
  margin-block-start: auto;
  border-radius: var(--radius-inset);
  border: 1px solid var(--coal-400);
  background: var(--coal-600);
  font-family: var(--font-ui);
}

/* SSL — a certificate, with a torn edge along the bottom */
.mf-pw-cert {
  position: relative;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 11px 12px 13px;
  overflow: hidden;
}

.mf-pw-cert__seal {
  flex: none;
  display: grid;
  place-items: center;
  inline-size: 30px;
  block-size: 30px;
  border-radius: 50%;
  border: 1px solid var(--status-live-on-dark-line);
  background: var(--status-live-on-dark-soft);
  color: var(--status-live-on-dark);
}

.mf-pw-cert__body { display: flex; flex-direction: column; gap: 2px; min-inline-size: 0; }

.mf-pw-cert__body strong {
  font-size: 11px;
  font-weight: var(--weight-semibold);
  color: var(--ink-on-dark);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.mf-pw-cert__body em { font-size: 9.5px; font-style: normal; color: var(--ink-faint); }

/* The zig-zag foot that says "certificate" without a word of copy. */
.mf-pw-cert__edge {
  position: absolute;
  inset-inline: 0;
  inset-block-end: 0;
  block-size: 5px;
  --tooth: var(--coal-720);
  background:
    linear-gradient(45deg, var(--tooth) 25%, transparent 25%) 0 0 / 8px 5px repeat-x,
    linear-gradient(-45deg, var(--tooth) 25%, transparent 25%) 0 0 / 8px 5px repeat-x;
}

/* Domain — a name split from its suffix */
.mf-pw-domain {
  display: flex;
  align-items: center;
  gap: 0;
  padding: 10px 11px;
  font-size: 12px;
}

.mf-pw-domain__name { color: var(--ink-on-dark); }

.mf-pw-domain__tld {
  padding: 2px 6px;
  margin-inline-start: 3px;
  border-radius: var(--radius-sm);
  background: var(--flare-a15);
  color: var(--flare-500);
  font-weight: var(--weight-bold);
}

.mf-pw-domain__state {
  margin-inline-start: auto;
  display: flex;
  align-items: center;
  gap: 3px;
  font-size: 9px;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--status-live-on-dark);
}

/* Australian hosting — the continent, with the servers marked on it */
.mf-pw-map {
  flex: 1;
  min-block-size: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 18px;
  padding: 14px 16px;
}

/* Sized off its height rather than a fixed width, so it takes whatever room
   the taller tile gives it and keeps its proportions. */
.mf-pw-map svg {
  flex: none;
  inline-size: auto;
  block-size: 100%;
  min-block-size: 70px;
  max-block-size: 190px;
}

.mf-pw-map__land {
  fill: var(--flare-a25);
  stroke: var(--flare-a50);
  /* Hairline at any size — the svg is sized off the tile height, so a scaled
     stroke thickens with it and the silhouette turns into a blob. */
  stroke-width: 1.25;
  vector-effect: non-scaling-stroke;
  stroke-linejoin: round;
}

.mf-pw-map__ping {
  fill: var(--flare-600);
  transform-origin: 83px 59px;
  animation: pwPing 2.6s ease-out infinite;
}

.mf-pw-map__city {
  font-size: 12px;
  color: var(--ink-on-dark-body);
}

/* Security — a strength meter, filled */
.mf-pw-meter {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px;
}

.mf-pw-meter__bars { display: flex; gap: 4px; flex: 1; }

.mf-pw-meter__bars > span {
  flex: 1;
  block-size: 7px;
  border-radius: 2px;
  background: var(--grad-brand);
  transform-origin: left;
}

.mf-anim .mf-pw-meter__bars > span { scale: 0 1; }

.mf-anim .mf-pw-cell-slim.is-in .mf-pw-meter__bars > span {
  animation: pwMeterFill 0.4s var(--ease-out) forwards;
  animation-delay: calc(var(--i) * 110ms);
}

.mf-pw-meter__label {
  flex: none;
  font-size: 9px;
  font-weight: var(--weight-bold);
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--flare-500);
}

/* Same-day changes — a two-stop rail from asked to live */
.mf-pw-rail {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 12px 13px;
  font-size: 9.5px;
  color: var(--ink-faint);
}

.mf-pw-rail__step { display: flex; align-items: center; gap: 5px; flex: none; }

.mf-pw-rail__step i {
  inline-size: 7px;
  block-size: 7px;
  border-radius: 50%;
  border: 1.5px solid var(--coal-300);
}

.mf-pw-rail__step-end { color: var(--flare-500); }

.mf-pw-rail__step-end i {
  border-color: transparent;
  background: var(--grad-brand);
}

.mf-pw-rail__line {
  flex: 1;
  block-size: 1.5px;
  border-radius: 2px;
  background: linear-gradient(90deg, var(--coal-300), var(--flare-600));
  transform-origin: left;
}

.mf-anim .mf-pw-rail__line { scale: 0 1; }

.mf-anim .mf-pw-cell-slim.is-in .mf-pw-rail__line {
  animation: pwMeterFill 0.6s var(--ease-out) 0.1s forwards;
}

/* The five slim tiles are the last five cells in the grid, so they are placed
   from the end — that way the count of feature cells above them can change
   without renumbering anything here. The order in the data is SSL, domain,
   hosting, security, same-day.

   Hosting is the exception to "slim": it stands alongside the speed chart on
   rows 10-11 rather than sitting in the closing row, because a map of
   Australia at one-row height was too small to read as Australia. Speed gives
   up the width for it. The closing row then carries two tiles rather than
   three, which is the only knock-on. */
.mf-pw-bento > :nth-last-child(5) { grid-column: 5 / span 2; grid-row: 10; }
.mf-pw-bento > :nth-last-child(4) { grid-column: 5 / span 2; grid-row: 11; }
.mf-pw-bento > :nth-last-child(3) { grid-column: 3 / span 2; grid-row: 10 / span 2; }
.mf-pw-bento > :nth-last-child(2) { grid-column: 1 / span 3; grid-row: 12; }
.mf-pw-bento > :nth-last-child(1) { grid-column: 4 / span 3; grid-row: 12; }

/* --- Website mock inside the design cell --- */

.mf-pw-mock {
  flex: 1;
  min-block-size: 240px;
  border-radius: var(--radius-inset);
  overflow: hidden;
  border: 1px solid var(--coal-400);
  display: flex;
  flex-direction: column;
}

.mf-pw-mock__bar {
  block-size: 30px;
  flex: none;
  display: flex;
  align-items: center;
  gap: 5px;
  padding-inline: 13px;
  background: var(--coal-600);
  border-block-end: 1px solid var(--coal-400);
}

.mf-pw-mock__bar > span:not(.mf-pw-mock__url) {
  inline-size: 7px;
  block-size: 7px;
  border-radius: 50%;
  background: var(--coal-300);
}

.mf-pw-mock__url {
  margin-inline-start: 7px;
  font-family: var(--font-ui);
  font-size: 10px;
  color: var(--ink-faint);
}

.mf-pw-mock__screen {
  flex: 1;
  /* Without this the image's intrinsic height wins the flex sizing and the
     tile grows to fit it, instead of the image being cropped to the tile. */
  min-block-size: 0;
  overflow: hidden;
  background: var(--coal-800);
}

.mf-pw-mock__screen img {
  display: block;
  inline-size: 100%;
  block-size: 100%;
  /* The capture stops at the practice's own fold, so nothing below it can
     surface here however tall the tile settles — a full-page capture would
     scroll further down the page as the tile grows. Whatever the tile's
     shape then trims (its bottom when it is wider than the capture, its
     sides when it is narrower) is trimmed from a screen's worth of site,
     and anchoring to the top keeps the name and hero in frame either way. */
  object-fit: cover;
  object-position: top center;
}

/* --- Bookings calendar --- */

.mf-pw-cal {
  flex: 1;
  background: var(--coal-600);
  border: 1px solid var(--coal-400);
  border-radius: var(--radius-inset);
  padding: 14px;
  display: flex;
  flex-direction: column;
  font-family: var(--font-ui);
}

.mf-pw-cal__head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-block-end: 10px;
}

.mf-pw-cal__month {
  font-size: 11px;
  font-weight: var(--weight-bold);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--flare-500);
}

/* The chevrons page the month. Spans rather than buttons: the whole panel is
   aria-hidden, and a focusable control inside that is a trap. */
.mf-pw-cal__nav {
  display: flex;
  padding: 3px;
  border-radius: var(--radius-sm);
  color: var(--flare-500);
  cursor: pointer;
  rotate: 90deg;
  transition: background 0.16s var(--ease-out), color 0.16s var(--ease-out);
}

.mf-pw-cal__nav-next { rotate: -90deg; }

.mf-pw-cal__nav:hover { background: var(--flare-a15); }

/* At the ends of the range — you cannot page back before this month. */
.mf-pw-cal__nav.is-off {
  color: var(--coal-300);
  cursor: default;
  background: none;
}

.mf-pw-cal__week,
.mf-pw-cal__grid {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 4px;
}

.mf-pw-cal__week {
  margin-block-end: 5px;
  font-size: 9px;
  font-weight: var(--weight-bold);
  letter-spacing: 0.1em;
  color: var(--ink-faint);
  text-align: center;
}

/* The rows share out whatever height the tile gives rather than being sized
   from their own width — a square cell overflowed the tile entirely. */
.mf-pw-cal__grid {
  flex: 1;
  min-block-size: 0;
  grid-auto-rows: minmax(26px, 1fr);
}

.mf-pw-cal__day {
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 6px;
  border: 1px solid transparent;
  background: var(--coal-400);
  font-size: 11px;
  color: var(--ink-on-dark-body);
  cursor: pointer;
  transition: background 0.16s var(--ease-out), color 0.16s var(--ease-out),
              border-color 0.16s var(--ease-out), scale 0.16s var(--ease-out);
}

.mf-pw-cal__day.is-blank {
  background: none;
  cursor: default;
}

/* Fully booked days stay visible but unpickable — an availability calendar
   that never says no doesn't look like one. */
.mf-pw-cal__day.is-booked {
  background: none;
  color: var(--ink-faint);
  text-decoration: line-through;
  cursor: default;
}

.mf-pw-cal__day.is-today { border-color: var(--flare-a40); }

.mf-pw-cal__day:not(.is-blank, .is-booked, .is-picked):hover {
  background: var(--flare-a20);
  color: var(--ink-on-dark);
  scale: 1.06;
}

.mf-pw-cal__day.is-picked {
  background: var(--grad-brand);
  border-color: transparent;
  color: #fff;
  font-weight: var(--weight-bold);
}

/* --- Time slots under the month --- */

.mf-pw-cal__slots {
  display: flex;
  flex-wrap: wrap;
  gap: 5px;
  margin-block-start: 11px;
}

.mf-pw-cal__slot {
  padding: 4px 8px;
  border-radius: var(--radius-pill);
  border: 1px solid var(--coal-300);
  background: var(--coal-500);
  font-size: 10px;
  color: var(--ink-on-dark-body);
  cursor: pointer;
  transition: background 0.16s var(--ease-out), color 0.16s var(--ease-out),
              border-color 0.16s var(--ease-out);
  animation: pwSlotIn 0.26s var(--ease-out) backwards;
  animation-delay: calc(var(--i, 0) * 45ms);
}

.mf-pw-cal__slot:hover {
  border-color: var(--flare-a40);
  color: var(--ink-on-dark);
}

.mf-pw-cal__slot.is-on {
  background: var(--flare-a20);
  border-color: var(--flare-a50);
  color: var(--flare-500);
  font-weight: var(--weight-bold);
}

.mf-pw-cal__foot {
  margin-block-start: 11px;
  padding-block-start: 10px;
  border-block-start: 1px solid var(--coal-400);
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 10px;
  font-size: 9.5px;
  color: var(--ink-on-dark-body);
}

.mf-pw-cal__state {
  flex: none;
  display: flex;
  align-items: center;
  gap: 4px;
  color: var(--status-live-on-dark);
}

/* --- Stock photography --- */

.mf-pw-photos {
  flex: 1;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 10px;
  min-block-size: 104px;
}

.mf-pw-photo {
  border-radius: 11px;
  border: 1px solid var(--coal-400);
}

.mf-pw-photo-a { background: linear-gradient(140deg, #3a2a18, #7c4118 60%, #b4601f); }
.mf-pw-photo-b { background: linear-gradient(140deg, #24303a, #3f5b63 55%, #7fa08d); }
.mf-pw-photo-c { background: linear-gradient(140deg, #2e2418, #6b4a2c 55%, #c98b52); }

/* --- Seasonal banner --- */

.mf-pw-banner {
  flex: 1;
  min-block-size: 62px;
  border-radius: var(--radius-inset);
  border: 1px solid var(--coal-400);
  padding: 16px 18px;
  display: flex;
  align-items: center;
  gap: 14px;
  background:
    radial-gradient(ellipse 60% 140% at 8% 50%, rgb(232 84 10 / 0.34), transparent 60%),
    var(--coal-600);
}

.mf-pw-banner__mark {
  flex: none;
  inline-size: 40px;
  block-size: 40px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--grad-icon);
  color: var(--ink-on-dark);
}

.mf-pw-banner__text {
  font-family: var(--font-body);
  font-size: 12px;
  line-height: 1.5;
  color: var(--ink-on-dark-body);
}

.mf-pw-banner__text strong {
  display: block;
  font-family: var(--font-display);
  font-weight: var(--weight-semibold);
  font-size: 15px;
  color: var(--ink-on-dark);
  margin-block-end: 2px;
}

/* --- SEO results --- */

.mf-pw-seo {
  flex: 1;
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 7px;
}

.mf-pw-seo li {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 9px 12px;
  border-radius: var(--radius-chip);
  background: var(--coal-600);
  border: 1px solid var(--coal-400);
  font-family: var(--font-ui);
  font-size: 11.5px;
  color: var(--ink-on-dark-body);
}

.mf-pw-seo li span { flex: 1; min-inline-size: 0; }

.mf-pw-seo li em {
  font-style: normal;
  font-weight: var(--weight-bold);
  font-size: 10.5px;
  color: var(--flare-500);
}

/* --- Monitoring trace --- */

.mf-pw-monitor {
  flex: 1;
  border-radius: var(--radius-inset);
  border: 1px solid var(--coal-400);
  background: var(--coal-600);
  padding: 13px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 11px;
  font-family: var(--font-ui);
}

.mf-pw-monitor__url {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 11px;
  color: var(--status-url);
  min-inline-size: 0;
}

.mf-pw-monitor__url > span:first-of-type {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.mf-pw-monitor__state {
  flex: none;
  margin-inline-start: auto;
  display: flex;
  align-items: center;
  gap: 5px;
  padding: 2px 8px 2px 6px;
  border-radius: var(--radius-pill);
  border: 1px solid var(--status-live-on-dark-line);
  background: var(--status-live-on-dark-soft);
  font-size: 9px;
  font-weight: var(--weight-bold);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--status-live-on-dark);
}

.mf-pw-monitor__pulse {
  flex: none;
  inline-size: 6px;
  block-size: 6px;
  border-radius: 50%;
  background: var(--status-live-on-dark);
  animation: pwNodePulseLive 2.4s ease-out infinite;
}

/* --- The check history --- */

.mf-pw-monitor__bars {
  display: flex;
  align-items: flex-end;
  gap: 2px;
  block-size: 26px;
}

.mf-pw-monitor__bar {
  flex: 1;
  min-inline-size: 0;
  block-size: 100%;
  border-radius: 2px;
  background: var(--status-live-on-dark);
  opacity: 0.34;
  /* A single lit band runs the row left to right on repeat: the checks are
     still being made, not a chart that was drawn once. */
  animation: pwMonitorScan 3.4s var(--ease-out) infinite;
  animation-delay: calc(var(--i) * 55ms);
}

.mf-pw-monitor__bar.is-blip {
  background: var(--flare-600);
  block-size: 62%;
}

.mf-pw-monitor__foot {
  display: flex;
  justify-content: space-between;
  gap: 10px;
  font-size: 9.5px;
  color: var(--ink-faint);
}

/* --- SEO rows: each term types itself out, then its rank lands --- */

.mf-anim .mf-pw-seo li { opacity: 0; }

.mf-anim .mf-pw-seo li.is-typed {
  opacity: 1;
  animation: pwRowIn 0.32s var(--ease-out) backwards;
}

/* The caret only exists on the row currently being typed. */
.mf-pw-seo li.is-typing span::after {
  content: "";
  display: inline-block;
  inline-size: 1px;
  block-size: 1em;
  margin-inline-start: 2px;
  vertical-align: -2px;
  background: var(--flare-500);
  animation: pwCaret 0.8s step-end infinite;
}

.mf-anim .mf-pw-seo em {
  opacity: 0;
  scale: 0.5;
}

.mf-anim .mf-pw-seo li.is-ranked em {
  opacity: 1;
  scale: 1;
  animation: pwRankPop 0.42s var(--ease-out);
}

/* --- Update log --- */

/* Two columns: six entries in one stack read as a long list, which is the
   opposite of the point. auto-fit so it falls back to one column when the
   tile is too narrow to split. */
.mf-pw-log {
  flex: 1;
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(148px, 1fr));
  align-content: center;
  gap: 10px 16px;
  font-family: var(--font-body);
  font-size: 12.5px;
  color: var(--ink-on-dark-body);
}

.mf-pw-log li {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  line-height: 1.35;
}

.mf-pw-log li > svg { flex: none; margin-block-start: 2px; }

/* One entry at a time, as though the log were filling in front of you. */
.mf-anim .mf-pw-log li { opacity: 0; }

.mf-anim .mf-pw-log.is-in li {
  animation: pwRowIn 0.45s var(--ease-out) forwards;
  animation-delay: calc(var(--i) * 180ms);
}

/* --- PageSpeed --- */

.mf-pw-speed {
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  gap: 10px;
  min-block-size: 0;
}

/* Everything below is armed by .mf-anim, which the script puts on <html> only
   once it is running. The HTML itself always holds the finished state — the
   full score, a drawn line, typed-out search terms — so without JS these
   tiles are complete rather than blank and waiting on an event that will
   never come. */
/* The chart stretches to whatever height the tile has, and with
   preserveAspectRatio="none" that scales the stroke with it — the taller the
   tile grew, the fatter the line got. non-scaling-stroke pins it to a true
   2px however far the box is stretched. */
.mf-pw-speed__line {
  stroke-width: 2;
  vector-effect: non-scaling-stroke;
}

/* Drawn with a wipe rather than a dash offset. Dash lengths are measured in
   device pixels once the stroke is non-scaling, so pathLength no longer spans
   the path and a dasharray draw breaks into segments; a clip does not care
   how long the path is. */
.mf-anim .mf-pw-speed svg { clip-path: inset(0 100% 0 0); }

.mf-anim .mf-pw-speed.is-in svg {
  clip-path: inset(0 0 0 0);
  transition: clip-path 1.3s var(--ease-out) 0.1s;
}

.mf-pw-speed__score {
  display: flex;
  align-items: baseline;
  gap: 6px;
  margin: 0 0 6px;
}

.mf-pw-speed__score span {
  font-family: var(--font-display);
  font-weight: var(--weight-semibold);
  font-size: 30px;
  line-height: 1;
}

.mf-pw-speed__score em {
  font-style: normal;
  font-family: var(--font-ui);
  font-size: 10px;
  color: var(--ink-faint);
}

.mf-pw-speed svg { inline-size: 100%; flex: 1; min-block-size: 38px; max-block-size: 120px; }


/* ==========================================================================
   Shared section header for the light half of the page
   ========================================================================== */

.mf-pw-sechead {
  text-align: center;
  max-inline-size: 760px;
  margin: 0 auto 56px;
}

.mf-pw-sechead .mf-eyebrow { margin-block-end: 20px; }


/* ==========================================================================
   Pricing
   ========================================================================== */

.mf-pw-pricing {
  position: relative;
  padding: 40px 40px 90px;
}

.mf-pw-pricing__inner {
  max-inline-size: var(--section-max);
  margin-inline: auto;
}

/* Heading and the one-off-project comparison on the left, the two plans on
   the right. The comparison is the argument the heading is making, so the
   two read as one column of prose against a column of prices — and the plans
   no longer need a centred measure to stop looking like panels, because the
   rail already gives them one.

   Areas rather than source order: the markup runs heading → plans →
   comparison, which is the order they stack in once the split collapses,
   while the grid puts the comparison under the heading up here. */
.mf-pw-pricing__split {
  display: grid;
  grid-template-columns: minmax(0, 0.82fr) minmax(0, 1.18fr);
  grid-template-areas:
    "head  cards"
    "note  cards";
  align-content: start;
  gap: 30px 60px;
}

/* Left-aligned only in this section — .mf-pw-sechead is centred everywhere
   else it is used on the page, so the override is scoped rather than made a
   modifier class nothing else would take. */
.mf-pw-pricing .mf-pw-sechead {
  grid-area: head;
  text-align: start;
  max-inline-size: none;
  margin: 0;
}

.mf-pw-pricing .mf-pw-sechead .mf-lead { margin-inline: 0; }

.mf-pw-plans__cards {
  grid-area: cards;
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 24px;
}

.mf-pw-plan {
  position: relative;
  display: flex;
  flex-direction: column;
  padding: 32px 28px;
  border-radius: var(--radius-stage);
  background: var(--paper-100);
  border: 1px solid var(--border-light);
  box-shadow: var(--shadow-tile);
}

/* Gradient ring on the featured plan, painted into the border box so the
   card keeps its paper fill. */
.mf-pw-plan.is-featured {
  border-color: transparent;
  background:
    linear-gradient(var(--paper-100), var(--paper-100)) padding-box,
    var(--grad-border) border-box;
  border-width: 1.5px;
  box-shadow: var(--shadow-card);
}

.mf-pw-plan__flag {
  position: absolute;
  inset-block-start: -13px;
  inset-inline-start: 28px;
  padding: 5px 14px;
  border-radius: var(--radius-pill);
  background: var(--grad-cta);
  color: var(--ink-on-dark);
  font-family: var(--font-ui);
  font-size: 11px;
  font-weight: var(--weight-bold);
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.mf-pw-plan__name {
  font-family: var(--font-ui);
  font-size: 13px;
  font-weight: var(--weight-semibold);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-muted);
  margin: 0;
}

.mf-pw-plan__price {
  display: flex;
  align-items: baseline;
  gap: 8px;
  margin: 14px 0 0;
}

.mf-pw-plan__figure {
  font-family: var(--font-display);
  font-weight: var(--weight-semibold);
  font-size: 48px;
  line-height: 1;
  color: var(--ink);
}

.mf-pw-plan.is-featured .mf-pw-plan__figure {
  background: var(--grad-brand-flat);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  color: transparent;
}

.mf-pw-plan__unit {
  font-family: var(--font-ui);
  font-size: 13px;
  color: var(--ink-soft);
}

/* The badge now says Most Popular, so the discount needs its own home. */
.mf-pw-plan__save {
  margin-inline-start: auto;
  padding: 4px 10px;
  border-radius: var(--radius-pill);
  border: 1px solid var(--status-live-line);
  background: var(--status-live-soft);
  font-family: var(--font-ui);
  font-size: 11px;
  font-weight: var(--weight-bold);
  letter-spacing: 0.04em;
  color: var(--status-live);
  white-space: nowrap;
}

.mf-pw-plan__blurb {
  margin: 8px 0 0;
  font-family: var(--font-body);
  font-size: 13.5px;
  line-height: 1.55;
  color: var(--ink-soft);
  /* Two lines' worth whether the sentence fills them or not, so the price
     rows sit on the same line across both cards. */
  min-block-size: 3.1em;
}

.mf-pw-plan__label {
  margin: 22px 0 0;
  padding-block-start: 20px;
  border-block-start: 1px solid var(--border-light);
  font-family: var(--font-ui);
  font-size: 11px;
  font-weight: var(--weight-bold);
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--ink-muted);
}

.mf-pw-plan__list {
  list-style: none;
  margin: 14px 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
  font-family: var(--font-body);
  font-size: 14px;
  line-height: 1.45;
  color: var(--ink-body);
}

.mf-pw-plan__list li {
  display: flex;
  align-items: flex-start;
  gap: 9px;
}

/* The tick keeps its own line height so it sits on the first line of a
   wrapped item rather than drifting to the middle of the block. */
.mf-pw-plan__list li > svg {
  flex: none;
  margin-block-start: 3px;
}

.mf-pw-plan__addon {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 12px;
  margin: 20px 0 26px;
  padding-block-start: 18px;
  border-block-start: 1px solid var(--border-light);
  font-family: var(--font-body);
  font-size: 13.5px;
  color: var(--ink-muted);
}

.mf-pw-plan__addon-price {
  font-family: var(--font-ui);
  font-weight: var(--weight-semibold);
  color: var(--ink);
  white-space: nowrap;
}

/* `auto` pushes the button to the card's foot so both plans' buttons line up
   however tall their copy runs. The gap above it is carried by the addon
   row's bottom margin, because an auto margin collapses to 0 on the taller
   card and would otherwise leave that one with no breathing room. */
.mf-pw-plan__cta {
  margin-block-start: auto;
  padding: 15px 24px;
  font-size: 14px;
  text-align: center;
}

/* --- One-off project contrast --- */

/* A band under the cards rather than a column beside them, and no wider than
   the pair above it — running past their edges made it the widest thing in
   the section, which is not where the emphasis belongs. */
.mf-pw-contrast {
  grid-area: note;
  display: flex;
  flex-direction: column;
  padding: 32px 36px;
  border-radius: var(--radius-stage);
  background: var(--panel-dark-deep);
  border: 1px solid var(--coal-400);
  box-shadow: var(--shadow-card-dark);
}

.mf-pw-contrast__label {
  font-family: var(--font-ui);
  font-size: 12px;
  font-weight: var(--weight-semibold);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--flare-500);
  margin: 0;
}

/* Number first, the qualification under it, split by a rule. Stacked at every
   width — side by side needs a band the full width of the section, and the
   comparison lives in the narrow rail now. */
.mf-pw-contrast__row {
  display: grid;
  gap: 22px;
  margin-block-start: 20px;
}

.mf-pw-contrast__copy {
  padding-block-start: 22px;
  border-block-start: 1px solid var(--flare-a15);
}

.mf-pw-contrast__lead {
  font-family: var(--font-body);
  font-size: 14px;
  line-height: 1.65;
  color: var(--ink-on-dark-body);
  margin: 0;
}

.mf-pw-contrast__figure {
  font-family: var(--font-display);
  font-weight: var(--weight-semibold);
  /* Sized to the narrower column the band now has, and kept on one line —
     a price range split across two lines reads as two numbers. */
  font-size: clamp(32px, 3.2vw, 46px);
  line-height: 1;
  white-space: nowrap;
  color: var(--ink-on-dark);
  margin: 10px 0 0;
}

.mf-pw-contrast__note {
  font-family: var(--font-ui);
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--ink-on-dark-dim);
  margin: 12px 0 0;
}

.mf-pw-contrast__body {
  font-family: var(--font-body);
  font-size: 13.5px;
  line-height: 1.7;
  color: var(--ink-on-dark-body);
  margin: 12px 0 0;
}

/* --- Billing and trust: three plain columns, deliberately not cards --- */

.mf-pw-trust {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 40px;
  margin-block-start: 72px;
  padding-block-start: 56px;
  border-block-start: 1px solid var(--border-light);
}

.mf-pw-trust__title {
  display: flex;
  align-items: center;
  gap: 12px;
  font-family: var(--font-display);
  font-weight: var(--weight-semibold);
  font-size: 19px;
  color: var(--ink);
  margin: 0 0 20px;
}

.mf-pw-trust__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 12px;
}

.mf-pw-trust__list li {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  font-family: var(--font-body);
  font-size: 14px;
  line-height: 1.6;
  color: var(--ink-muted);
}

.mf-pw-trust__list svg { flex: none; margin-block-start: 4px; }

/* --- Extras and footnote --- */

/* ==========================================================================
   Other costs — the two things outside the subscription

   Its own section below pricing rather than a panel inside it. The layout is
   deliberately unlike the pricing table: a split with the guide's cover, then
   one slim row. These are optional extras, not plans.
   ========================================================================== */

.mf-pw-costs {
  position: relative;
  padding: 20px 40px 90px;
}

.mf-pw-costs__inner {
  max-inline-size: var(--section-max);
  margin-inline: auto;
}

.mf-pw-costs__split {
  max-inline-size: 940px;
  margin: 46px auto 0;
  display: grid;
  grid-template-columns: 260px 1fr;
  gap: 52px;
  align-items: center;
}

.mf-pw-costs__title {
  display: flex;
  align-items: center;
  gap: 10px;
  font-family: var(--font-display);
  font-weight: var(--weight-semibold);
  font-size: 19px;
  color: var(--ink);
  margin: 0 0 12px;
}

.mf-pw-costs__title > svg { flex: none; }

.mf-pw-costs__body {
  font-family: var(--font-body);
  font-size: 15px;
  line-height: 1.75;
  color: var(--ink-muted);
  margin: 0;
}

.mf-pw-costs__body a {
  color: var(--flare-600);
  font-weight: var(--weight-semibold);
}

.mf-pw-costs__cta {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin-block-start: 22px;
}

/* --- The photography guide's cover ------------------------------------- */

.mf-pw-guide {
  position: relative;
  display: block;
  aspect-ratio: 1 / 1.414;
  text-decoration: none;
}

/* The second copy behind, fanned out — one card alone reads as a poster, two
   read as a booklet you could pick up. */
.mf-pw-guide__back {
  position: absolute;
  inset: 0;
  border-radius: var(--radius-inset);
  background: var(--paper-300);
  border: 1px solid var(--border-light);
  rotate: -5deg;
  transform-origin: 50% 100%;
  transition: rotate 0.35s var(--ease-out);
}

.mf-pw-guide__cover {
  position: relative;
  z-index: 1;
  block-size: 100%;
  display: flex;
  flex-direction: column;
  padding: 22px 20px;
  border-radius: var(--radius-inset);
  background: var(--paper-100);
  border: 1px solid var(--border-light);
  box-shadow: var(--shadow-card);
  rotate: 2deg;
  transition: rotate 0.35s var(--ease-out), translate 0.35s var(--ease-out);
}

.mf-pw-guide:hover .mf-pw-guide__cover { rotate: 0deg; translate: 0 -4px; }
.mf-pw-guide:hover .mf-pw-guide__back { rotate: -8deg; }

.mf-pw-guide__mark {
  display: flex;
  color: var(--flare-600);
}

/* The cover is a fixed A-series shape, so the photo takes the slack rather
   than the type: a fixed height here pushed the title into the footer rule
   once the card got small. */
.mf-pw-guide__shot {
  margin-block-start: 16px;
  flex: 1;
  min-block-size: 48px;
  /* Capped well under the slack so the auto margin on the rule always has
     something left to spend — at 150px it swallowed the lot and the footer
     rule ended up on the subtitle's descenders. */
  max-block-size: 108px;
  border-radius: var(--radius-sm);
  background: var(--grad-brand);
  opacity: 0.85;
}

.mf-pw-guide__tag {
  margin-block-start: 16px;
  font-family: var(--font-ui);
  font-size: 8.5px;
  font-weight: var(--weight-bold);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--flare-600);
}

.mf-pw-guide__title {
  margin-block-start: 6px;
  font-family: var(--font-display);
  font-weight: var(--weight-semibold);
  font-size: 20px;
  line-height: 1.15;
  color: var(--ink);
}

.mf-pw-guide__sub {
  margin-block-start: 6px;
  font-family: var(--font-body);
  font-size: 11px;
  line-height: 1.45;
  color: var(--ink-soft);
}

.mf-pw-guide__rule {
  margin-block-start: auto;
  block-size: 2px;
  inline-size: 34px;
  border-radius: 2px;
  background: var(--grad-brand);
}

.mf-pw-guide__lines {
  margin-block-start: 12px;
  display: flex;
  flex-direction: column;
  gap: 5px;
}

.mf-pw-guide__lines i {
  block-size: 4px;
  border-radius: 2px;
  background: var(--border-light);
}

.mf-pw-guide__lines i:nth-child(2) { inline-size: 80%; }
.mf-pw-guide__lines i:nth-child(3) { inline-size: 55%; }

.mf-pw-footnote {
  max-inline-size: 860px;
  margin: 24px auto 0;
  font-family: var(--font-body);
  font-size: 12.5px;
  line-height: 1.7;
  color: var(--ink-soft);
}


/* ==========================================================================
   Timeline — a circular portrait beside three stacked step cards
   ========================================================================== */

/* The timeline runs on coal. Everything inside it that assumes paper is
   re-pointed below, scoped to this section so the shared arc-steps partial
   keeps its light styling everywhere else it is used. */
.mf-pw-timeline {
  position: relative;
  padding: 60px 40px 90px;
  background: var(--coal-900);
  margin-block-start: -2px;
}

.mf-pw-timeline__lead { color: var(--ink-on-dark-body); }

.mf-pw-timeline .mf-pw-tlcard {
  background: var(--panel-dark);
  border-color: var(--coal-400);
}

.mf-pw-timeline .mf-pw-tlcard__title { color: var(--ink-on-dark); }
.mf-pw-timeline .mf-pw-tlcard__body { color: var(--ink-on-dark-body); }
.mf-pw-timeline .mf-pw-tlcard__icon { color: var(--flare-400); }

/* The portrait is a cut-out on white, so on coal it needs its own disc to sit
   on rather than floating on the dark. */
.mf-pw-timeline .mf-pw-tl__halo { border-color: var(--flare-a40); }

.mf-pw-timeline__inner {
  max-inline-size: var(--section-max);
  margin-inline: auto;
}

.mf-pw-tl {
  margin-block-start: 56px;
  display: grid;
  grid-template-columns: minmax(0, 0.68fr) minmax(0, 1fr);
  align-items: center;
  gap: 48px;
}

/* --- Portrait disc ------------------------------------------------------ */

.mf-pw-tl__figure {
  position: relative;
  margin: 0;
  justify-self: center;
  /* The halo sits outside the figure's box — 44px past its leading edge and
     16px past its trailing one — so the figure gives that back or the ring
     clips against the section padding on a tight column. */
  margin-inline: 44px 16px;
  inline-size: min(100% - 60px, 460px);
  aspect-ratio: 1;
}

/* Outline-only circle, larger than the disc and nudged up-left, so it reads
   as a halo behind the photo rather than a border on it. */
.mf-pw-tl__halo {
  position: absolute;
  inset: -30px;
  border-radius: 50%;
  border: 1.5px solid var(--flare-a30);
  translate: -14px -12px;
}

/* Sized as a percentage of the figure, not in pixels, so the arc keeps its
   proportion to the photo at every width without a per-breakpoint override.
   120.5% puts the band's centreline just outside the disc's rim: the inner
   half laps onto the photo, the outer half onto the section. Insets and size
   both set — an SVG is a replaced element, so `inset: -10.25%` alone would
   leave it at its intrinsic size rather than stretching it. */
.mf-pw-tl__swoosh {
  position: absolute;
  inset-block-start: -10.25%;
  inset-inline-start: -10.25%;
  inline-size: 120.5%;
  block-size: 120.5%;
  pointer-events: none;
}

.mf-pw-tl__disc {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  overflow: hidden;
  background: radial-gradient(
    120% 120% at 30% 20%,
    var(--paper-300),
    var(--paper-100)
  );
  box-shadow: var(--shadow-card);
}

.mf-pw-tl__disc img {
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
  object-position: 50% 42%;
  display: block;
}

/* --- Step cards --------------------------------------------------------- */

.mf-pw-tl__steps {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 20px;
}

.mf-pw-tlcard {
  --pw-tl-x: 0px;

  position: relative;
  display: flex;
  align-items: center;
  gap: 18px;
  padding: 24px 34px 24px 58px;
  /* Fully rounded, not a rounded rectangle — the capsule echoes the disc the
     cards curve around, and the numbered disc that breaks out of its leading
     edge. The inline padding is what keeps it safe: the radius bites into the
     top and bottom corners, so the copy starts clear of where it reaches in. */
  border-radius: 999px;
  background: var(--paper-100);
  border: 1px solid var(--border-light);
  box-shadow: var(--shadow-card-sm);
  translate: var(--pw-tl-x) 0;
  transition-delay: calc(var(--pw-tl-i, 0) * 90ms);
}

/* The end cards pull in toward the disc while the middle stays out, so the
   stack's left edge curves around the circle instead of running straight
   past it. Written as first/last rather than nth so a fourth step would
   simply join the flush middle. Set on the list so the arc can be zeroed
   at one specificity when the portrait moves above the cards. */
.mf-pw-tl__steps > .mf-pw-tlcard:first-child,
.mf-pw-tl__steps > .mf-pw-tlcard:last-child {
  --pw-tl-x: -28px;
}

.mf-pw-tlcard__text {
  flex: 1;
  min-inline-size: 0;
}

/* The step icon is a bare glyph inside the card now — no chip behind it, so
   the disc is the only orange mass on the row. */
.mf-pw-tlcard__icon {
  flex: none;
  display: inline-flex;
  color: var(--flare-500);
}

.mf-pw-tlcard__title {
  font-family: var(--font-display);
  font-weight: var(--weight-semibold);
  font-size: 20px;
  color: var(--ink);
  margin: 0 0 8px;
  text-wrap: balance;
}

.mf-pw-tlcard__body {
  font-family: var(--font-body);
  font-size: 14.5px;
  line-height: 1.7;
  color: var(--ink-muted);
  margin: 0;
}

/* The number rides the orange disc, half on and half off the card's leading
   edge — it reads as a layer above the capsule rather than an item inside it,
   and picks up the chip's gradient from .mf-chip-icon-round. */
.mf-pw-tlcard__num {
  position: absolute;
  inset-block-start: 50%;
  inset-inline-start: 0;
  translate: -50% -50%;
  inline-size: 48px;
  block-size: 48px;
  box-shadow: var(--shadow-md);
  font-family: var(--font-display);
  font-weight: var(--weight-bold);
  font-size: 17px;
  line-height: 1;
  color: var(--ink-on-dark);
  pointer-events: none;
}

/* --- Mirrored variant --------------------------------------------------- */

/* .mf-pw-tl-flip puts the disc on the trailing side. Scoped to the width
   where the two columns actually exist — once the disc sits above the stack
   there is nothing to mirror, and an `order` here would drop it underneath. */
@media (min-width: 1024px) {
  .mf-pw-tl-flip { grid-template-columns: minmax(0, 1fr) minmax(0, 0.68fr); }

  .mf-pw-tl-flip .mf-pw-tl__figure {
    order: 2;
    margin-inline: 16px 44px;
  }

  /* The halo leans away from the cards, so mirroring the layout has to
     mirror the offset too — otherwise it reaches back across the gap and
     the figure's reserved margin is on the wrong side. */
  .mf-pw-tl-flip .mf-pw-tl__halo { translate: 14px -12px; }

  /* The swoosh opens to the right; mirrored, it has to open to the left so it
     still turns its back on the cards. */
  .mf-pw-tl-flip .mf-pw-tl__swoosh { scale: -1 1; }

  .mf-pw-tl-flip .mf-pw-tl__steps > .mf-pw-tlcard:first-child,
  .mf-pw-tl-flip .mf-pw-tl__steps > .mf-pw-tlcard:last-child {
    --pw-tl-x: 28px;
  }

  .mf-pw-tl-flip .mf-pw-tlcard {
    flex-direction: row-reverse;
    padding: 24px 58px 24px 34px;
  }

  .mf-pw-tl-flip .mf-pw-tlcard__num {
    inset-inline-start: auto;
    inset-inline-end: 0;
    translate: 50% -50%;
  }

}


/* ==========================================================================
   Live examples
   ========================================================================== */

/* The examples run on coal: eight practice homepages are eight bright, busy
   rectangles, and a dark ground is what lets them read as a set rather than
   as clutter on the page wash. It is also the page's last dark run — Why Us
   comes back into the light below it. */
.mf-pw-examples {
  position: relative;
  padding: 60px 40px 90px;
  background: var(--coal-900);
  margin-block-start: -2px;
  /* The stacks finish deliberately past the screen's edge, which would
     otherwise widen the document and put a scrollbar along the bottom of the
     page. `clip` rather than `hidden`: hidden would make this a scroll
     container and the pane inside it would stop sticking. */
  overflow-x: clip;
}

/* The section's head, above the pin: on the page as the section arrives, gone
   by the time the timeline takes over the middle. */
.mf-pw-examples__head { margin-block-end: 40px; }

.mf-pw-examples__lead,
.mf-pw-collage__lead { color: var(--ink-on-dark-body); }

.mf-pw-examples__inner {
  max-inline-size: var(--section-max);
  margin-inline: auto;
}

/* --- The opening collage -------------------------------------------------

   Six captures open the section as a plain two-column grid, then travel out
   towards the screen's edges as the reader scrolls the pinned pane, each
   column closing into a tilted stack on the way. The gap they leave is where
   "how long it takes" arrives — the section's own head has scrolled past by
   then, so the timeline becomes the heading you are looking at.

   Base state is the fallback, deliberately: the same cards in a plain grid
   with the timeline underneath them. Everything that makes it a collage lives
   in the media query at the end of this block, behind both a width and
   .mf-anim — the class practice-websites.js only sets when JS is running and
   the reader has not asked for reduced motion. So no JS, reduced motion and a
   narrow viewport all land on the same honest fallback without a single
   override going the other way. */

.mf-pw-collage {
  /* Whether the collage may pin. The stylesheet owns the decision — it is
     the layer that knows the breakpoint — and the JS reads it back to decide
     whether to scrub. Same contract as --pw-pin on the benefit ring. */
  --pw-clpin: 0;

  /* Scrub progress: --pw-cp is where the columns are, --pw-cc how far in the
     timeline is. JS writes both onto this element. The values here are the
     finished, open state, so nothing depends on it ever running. */
  --pw-cp: 1;
  --pw-cc: 1;

  max-inline-size: var(--section-max);
  margin-inline: auto;
}

/* The collage cards never take the grid's staggered entry — in the pinned
   layout the scrub is what carries them, and below the breakpoint the
   list has no .is-in of its own to release them. Both classes are on the
   list so this outweighs the .mf-pw-shots rule further down the file. */
.mf-anim .mf-pw-shots.mf-pw-collage__cards > .mf-pw-shot {
  opacity: 1;
  animation: none;
}

/* Unpinned, the showcase captures are still the showcase: wider columns than
   the gallery grid, so eight of them land as rows of two or three rather than
   a thin row of five. */
.mf-pw-shots.mf-pw-collage__cards {
  grid-template-columns: repeat(auto-fill, minmax(340px, 1fr));
}

/* --- The timeline the collage opens onto -------------------------------- */

/* Unpinned this is a block of running text under the captures, so it needs a
   measure of its own — full section width would set the step bodies at twice
   a readable line length. */
.mf-pw-collage__copy {
  max-inline-size: 780px;
  margin: 56px auto 0;
  text-align: center;
}

.mf-pw-collage__copy > .mf-eyebrow { margin-block-end: 20px; }

/* The three steps, numbered. No rail between the discs — the numbers carry
   the order on their own, and a line drawn through centred copy is either a
   strike-through or a pair of stubs either side of it.

   --pw-jnode is the disc's diameter and --pw-jgap the space between steps;
   both are set on the copy block so the short-viewport pass can retune them
   in one place. */
.mf-pw-collage__copy {
  --pw-jnode: 34px;
  --pw-jgap: 30px;
}

.mf-pw-clsteps {
  list-style: none;
  margin: 28px 0 0;
  padding: 0;
  display: grid;
  gap: var(--pw-jgap);
}

/* The disc sits over its copy rather than beside it, so the column reads down
   the middle under a centred heading. */
.mf-pw-clstep { text-align: center; }

.mf-pw-clstep__num {
  margin-inline: auto;
  display: grid;
  place-items: center;
  inline-size: var(--pw-jnode);
  block-size: var(--pw-jnode);
  border-radius: 50%;
  background: var(--grad-brand);
  box-shadow: 0 0 0 5px var(--flare-a15);
  color: var(--ink-on-dark);
  font-family: var(--font-display);
  font-weight: var(--weight-bold);
  font-size: 15px;
  line-height: 1;
}

.mf-pw-clstep__text {
  display: block;
  margin-block-start: 9px;
}

.mf-pw-clstep__title {
  display: block;
  font-family: var(--font-display);
  font-weight: var(--weight-semibold);
  font-size: 18px;
  line-height: 1.3;
  color: var(--ink-on-dark);
}

/* The section's own call to action, in its head — the captures are what it is
   offering to show more of, so it belongs with them rather than at the foot
   of the timeline that follows. */
.mf-pw-examples__cta { margin: 30px 0 0; }

.mf-pw-clstep__body {
  display: block;
  margin-block-start: 6px;
  font-family: var(--font-body);
  font-size: 14.5px;
  line-height: 1.65;
  color: var(--ink-on-dark-body);
}

/* The rest of the gallery reads as a continuation of the captures above it,
   so it sits closer than a grid opening a section would. Both classes,
   because the .mf-pw-shots margin it is trimming is declared further down. */
.mf-pw-shots.mf-pw-shots-rest {
  margin-block-start: 28px;
}

@media (min-width: 1180px) {

  .mf-anim .mf-pw-collage {
    --pw-clpin: 1;

    /* Squared up, until the scrub says otherwise. */
    --pw-cp: 0;
    --pw-cc: 0;

    /* How long the pane is held while the columns travel out. Eight cards
       and three timeline steps is more to get through than six and a line of
       copy was, and the grid now pans before it parts, so the scrub is longer
       than it was. */
    --pw-cl-scrub: 340vh;

    /* The card, and the window onto its capture.

       Only the window's height is under pressure: four cards to a column now
       have to stand clear of each other inside one pinned pane, so it is
       measured off the viewport's height, less the strip the nav takes, and
       every vertical measurement below is built off it. Width is free of
       that — the window is a fixed height with the capture running full-bleed
       through it, so a wider card is a wider crop of the homepage, not a
       taller card. */
    /* One gutter, used both ways: 30px between panels across and down, and
       the margin the grid keeps off the screen's edges at rest. */
    --pw-cl-gap: 30px;
    --pw-cl-edge: 40px;

    /* Two columns and three rows at rest, sized so all six land on one screen.
       That is the point of six rather than eight: the pin opens on the whole
       arrangement held still, instead of on a grid that is cropped at the
       bottom and creeping upward for the first third of the scrub.

       So the height is measured off the opening grid — three windows and the
       two gaps between them, in the strip left under the nav — rather than off
       the stacked end state, which is the looser of the two constraints now
       that a stack is three cards deep rather than four.

       Width then follows the height rather than the viewport: two columns
       across a wide screen would make each panel about four times as wide as
       it is tall, which stops reading as a website and starts reading as a
       banner. Held at 2.3 : 1 instead. */
    --pw-cl-vh: max(
      110px,
      calc(
        (100vh - var(--pw-nav-clear) - 24px - 2 * var(--pw-cl-gap)) / 3
      )
    );
    --pw-cl-w: min(
      560px,
      calc((100vw - 2 * var(--pw-cl-edge) - var(--pw-cl-gap)) / 2),
      calc(var(--pw-cl-vh) * 2.3)
    );

    /* How far the opening grid overruns the pane, and so how far it pans.
       --pw-cl-vh is now solved so three rows fit exactly, so this resolves to
       zero and the pan below is a no-op. It is kept rather than deleted: the
       min() floor of 110px can still win on a very short viewport, and this is
       what stops the bottom row being cut off when it does. */
    --pw-cl-over: max(
      0px,
      calc(
        (3 * var(--pw-cl-vh) + 2 * var(--pw-cl-gap)) -
        (100vh - var(--pw-nav-clear) - 24px)
      )
    );

    /* The pan runs over the first third of the scrub: the grid arrives with
       its top row against the top of the pane and has walked down to its last
       row by the time the columns are properly on their way out. */
    --pw-cl-pan: clamp(0, calc(var(--pw-cp) / 0.32), 1);

    /* Pitch between neighbouring panels in the opening grid, across and down. */
    --pw-cl-colstep: calc(var(--pw-cl-w) + var(--pw-cl-gap));
    --pw-cl-rowstep: calc(var(--pw-cl-vh) + var(--pw-cl-gap));

    /* How far out the stacks travel. Measured off the viewport rather than the
       section, and deliberately past it: a stack finishes with about a third
       of its width off the edge, so the spread reads as continuing beyond the
       screen rather than stopping politely inside it. How far out they go is
       also what sets the centre column's width, and the timeline needs that
       more than the outer edge of a capture does. */
    --pw-cl-x1: calc(50vw - var(--pw-cl-w) * 0.2);

    /* The stacked pitch. Deep on purpose: a stack that closes up harder is a
       shorter stack, and the height that saves inside the pane is height the
       window itself gets to keep. At the ends they are a frame around the
       copy rather than something to read, so a heavier overlap costs the
       reader nothing and buys a materially bigger capture. */
    /* Pitch within a stack. Opened from 0.58 with the drop to three cards: at
       the old pitch a three-card fan spanned barely two window heights and read
       as a huddle rather than a stack. */
    --pw-cl-row1: calc(var(--pw-cl-vh) * 0.64);

    /* The right stack settles a touch lower than the left, so the finished
       spread is balanced rather than mirrored. */
    --pw-cl-drop: calc(var(--pw-cl-vh) * 0.1);
  }

  /* The pane reserves --pw-nav-clear at its top so the first row is not under
     the nav once it pins. Before it pins that reserve is just a hole between
     the section's head and the captures, so the track is pulled up by exactly
     the same amount: the top of the pane slides behind the head, where it has
     nothing in it anyway, and the head's own margin is all that is left
     between the button and the first row. Pinned behaviour is untouched —
     the pane still sticks at 0 and the stage is still inset. */
  .mf-anim .mf-pw-collage {
    margin-block-start: calc(var(--pw-nav-clear) * -1);
  }

  .mf-anim .mf-pw-collage__track {
    position: relative;
    block-size: var(--pw-cl-scrub);
  }

  .mf-anim .mf-pw-collage__pane {
    position: sticky;
    inset-block-start: 0;
    block-size: 100vh;
  }

  /* Copy and cards share one centre. The stage is inset by the strip the
     nav sits over, so that centre is the middle of what can actually be
     seen rather than the middle of the viewport. */
  .mf-anim .mf-pw-collage__stage {
    position: absolute;
    inset: var(--pw-nav-clear) 0 0;
    display: grid;
    place-items: center;
  }

  /* Held to the gap the two columns leave, and kept above every card: while
     the columns are still travelling one is crossing the centre, and copy
     fading in behind it reads as a fault rather than as depth.

     The column is allowed to run taller than the pane — three steps with room
     to breathe do not fit a laptop, and cramping them to make them fit was the
     wrong trade. It pans instead: top-aligned as it arrives, bottom-aligned by
     the time the last step has landed, so whichever line is currently coming
     in is the one in front of you. --pw-cl-copyover is how far it has to
     travel and only JS can know it, because it depends on where the text
     wraps. The column is anchored to the top of the stage rather than centred,
     so the slide has a fixed starting point; --pw-cl-slack is what re-centres
     it on a screen tall enough that it fits, where --pw-cl-copyover is 0 and
     none of this moves. */
  .mf-anim .mf-pw-collage__copy {
    position: relative;
    z-index: 10;
    margin: 0;
    grid-area: 1 / 1;
    max-inline-size: min(
      560px,
      calc(var(--pw-cl-x1) * 2 - var(--pw-cl-w) - 96px)
    );
    align-self: start;
    translate: 0 calc(
      var(--pw-cl-slack, 0px) / 2 -
      var(--pw-cl-copyover, 0px) * var(--pw-cc)
    );
  }

  /* The whole block reads top to bottom as it arrives — eyebrow, then
     heading, then the line under it, then the steps one at a time. Each part
     is faded on its own beat rather than the block as a whole, which would
     multiply the two fades together and leave the last step washed out.

       eyebrow  0.00 → 0.10
       heading  0.08 → 0.22
       lead     0.20 → 0.34
       step n   0.34 + n × 0.20 → + 0.12          */
  .mf-anim .mf-pw-collage__copy > .mf-eyebrow,
  .mf-anim .mf-pw-collage__copy > .mf-h2,
  .mf-anim .mf-pw-collage__lead {
    opacity: var(--cp2);
    translate: 0 calc((1 - var(--cp2)) * 22px);
  }

  .mf-anim .mf-pw-collage__copy > .mf-eyebrow {
    --cp2: clamp(0, calc(var(--pw-cc) / 0.1), 1);
  }

  .mf-anim .mf-pw-collage__copy > .mf-h2 {
    --cp2: clamp(0, calc((var(--pw-cc) - 0.08) / 0.14), 1);
  }

  .mf-anim .mf-pw-collage__lead {
    --cp2: clamp(0, calc((var(--pw-cc) - 0.2) / 0.14), 1);
  }

  /* The journey runs strictly in turn: node, then the line to the next node,
     then that node. Each beat starts where the one before it ends, so nothing
     is ever drawing towards step three while step one is still arriving —
     which is what overlapping windows were doing.

       step n arrives   n * 0.34        → + 0.14
       its line draws   n * 0.34 + 0.14 → + 0.20  */
  .mf-anim .mf-pw-clstep {
    --sp: clamp(
      0,
      calc((var(--pw-cc) - (0.34 + var(--n) * 0.2)) / 0.12),
      1
    );

    opacity: var(--sp);
    translate: 0 calc((1 - var(--sp)) * 18px);
  }



  /* Invisible copy must not swallow a click meant for a card behind it. */
  .mf-anim .mf-pw-collage.is-shut .mf-pw-collage__copy {
    pointer-events: none;
  }

  .mf-anim .mf-pw-collage__cards {
    position: absolute;
    inset: 0;
    display: block;
    margin: 0;
    pointer-events: none;
  }

  /* Every card is the same interpolation between two poses it is told about
     in four numbers: --cx and --ry are where it sits in the opening grid, two
     columns by four rows; --c and --r are which stack it joins and where in it.
     So a card crosses from a slot in the grid to a place in a stack, and
     rotation and the sideways jitter are scaled by the progress from zero,
     which is what keeps the opening grid square and brings the tilt in with
     the movement.

     --d staggers the cards against each other: a card with --d: 0.15 does not
     start until the scrub is 15% in, then covers its distance in the time that
     is left. Without it a stack leaves as one slab. */
  .mf-anim .mf-pw-collage__card {
    --p: clamp(0, calc((var(--pw-cp) - var(--d, 0)) / (1 - var(--d, 0))), 1);

    position: absolute;
    inset-inline-start: 50%;
    inset-block-start: 50%;
    inline-size: var(--pw-cl-w);
    pointer-events: auto;
    will-change: transform;
    transform:
      translate(-50%, -50%)
      translate(
        calc(
          var(--cx) * var(--pw-cl-colstep) * (1 - var(--p)) +
          (var(--c) * var(--pw-cl-x1) + var(--jx) * 1px) * var(--p)
        ),
        calc(
          (
            var(--ry) * var(--pw-cl-rowstep) +
            var(--pw-cl-over) / 2 * (1 - 2 * var(--pw-cl-pan))
          ) * (1 - var(--p)) +
          (
            var(--r) * var(--pw-cl-row1) +
            var(--drop, 0) * var(--pw-cl-drop)
          ) * var(--p)
        )
      )
      rotate(calc(var(--rot) * var(--p) * 1deg));
  }

  /* The window onto the capture, sized so the opening grid of three rows fits
     a pinned pane. The grid below the collage keeps the full 200px. */
  .mf-anim .mf-pw-collage__card .mf-pw-shot__view {
    --pw-shot-vh: var(--pw-cl-vh);
  }

  /* Reading order down the opening grid — 1 2 across the top, then 3 4, 5 6.
     The left column becomes the left stack and the right the right one, so a
     card only ever travels sideways to its stack, never across the middle to
     reach it.

     Three rows rather than four, so --ry and --r run -1, 0, 1 about the centre
     instead of ±0.5, ±1.5. Within a stack the higher card paints over the one
     beneath it, so an overlap eats the top of a capture rather than cutting one
     in half. */
  .mf-anim .mf-pw-collage__card:nth-child(1) {
    --cx: -0.5; --ry: -1; --c: -1; --r: -1;
    --rot: -4; --jx: -18; --d: 0; z-index: 6;
  }

  .mf-anim .mf-pw-collage__card:nth-child(2) {
    --cx: 0.5; --ry: -1; --c: 1; --r: -1; --drop: 1;
    --rot: 3.5; --jx: 16; --d: 0.04; z-index: 3;
  }

  .mf-anim .mf-pw-collage__card:nth-child(3) {
    --cx: -0.5; --ry: 0; --c: -1; --r: 0;
    --rot: 3; --jx: 14; --d: 0.07; z-index: 5;
  }

  .mf-anim .mf-pw-collage__card:nth-child(4) {
    --cx: 0.5; --ry: 0; --c: 1; --r: 0; --drop: 1;
    --rot: -3; --jx: -12; --d: 0.1; z-index: 2;
  }

  .mf-anim .mf-pw-collage__card:nth-child(5) {
    --cx: -0.5; --ry: 1; --c: -1; --r: 1;
    --rot: -2.5; --jx: -10; --d: 0.13; z-index: 4;
  }

  .mf-anim .mf-pw-collage__card:nth-child(6) {
    --cx: 0.5; --ry: 1; --c: 1; --r: 1; --drop: 1;
    --rot: 2.5; --jx: 10; --d: 0.16; z-index: 1;
  }

  /* The pin releases onto the rest of the gallery, so it needs room of its
     own rather than the running-on spacing the fallback wants. */
  .mf-anim .mf-pw-shots-rest {
    margin-block-start: 64px;
  }
}

/* A laptop has to fit three cards a column and three timeline steps into far
   less pane. The cards give that up through --pw-cl-vh, which is measured off
   the viewport; the timeline has to be told, so it tightens here rather than
   running off the bottom of the pin. */
@media (min-width: 1180px) and (max-height: 820px) {
  .mf-anim .mf-pw-collage__copy {
    --pw-jnode: 28px;
    --pw-jgap: 24px;
  }

  .mf-anim .mf-pw-clsteps { margin-block-start: 18px; }

  .mf-anim .mf-pw-clstep__text { margin-block-start: 8px; }

  .mf-anim .mf-pw-clstep__body {
    margin-block-start: 4px;
    font-size: 13.5px;
    line-height: 1.5;
  }

  .mf-anim .mf-pw-clstep {
    gap: 13px;
  }

  .mf-anim .mf-pw-clstep__num { font-size: 13px; }

  .mf-anim .mf-pw-clstep__title { font-size: 16.5px; }
}


/* --- The gallery of sites we run ---------------------------------------- */

.mf-pw-shots {
  list-style: none;
  margin: 52px 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(232px, 1fr));
  gap: 24px;
}

.mf-pw-shot__link {
  display: block;
  text-decoration: none;
}

/* Just the capture, cornered off. No browser chrome, and nothing that moves
   under the pointer: in the collage above, eight of these are already carrying
   a scroll-driven move, and a second motion on top of it reads as a glitch.

   The hairline is light because the ground is coal — it lifts a capture off
   the dark and, once a column has closed into a stack, keeps the overlapping
   edges legible against each other. */
.mf-pw-shot__frame {
  display: block;
  border-radius: var(--radius-inset);
  overflow: hidden;
  background: var(--coal-700);
  border: 1px solid var(--border-on-dark);
  box-shadow: var(--shadow-card-dark);
}

/* A window onto a page taller than itself, so the card shows a homepage as it
   opens rather than the whole of it squashed. --pw-shot-vh is what the
   collage resizes to fit three cards into one pinned pane. */
.mf-pw-shot__view {
  position: relative;
  display: block;
  block-size: var(--pw-shot-vh, 200px);
  overflow: hidden;
  background: var(--paper-100);
}

.mf-pw-shot__view img {
  inline-size: 100%;
  block-size: auto;
  display: block;
}

/* Cards arrive one after another rather than all at once. */
.mf-anim .mf-pw-shots > .mf-pw-shot { opacity: 0; }

.mf-anim .mf-pw-shots.is-in > .mf-pw-shot {
  animation: pwRowIn 0.5s var(--ease-out) forwards;
  animation-delay: calc(var(--i) * 70ms);
}

/* --- The "and 190+ more" tile, sharing the grid --- */

.mf-pw-shot-more {
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 22px;
  border-radius: var(--radius-inset);
  background: var(--coal-700);
  border: 1px dashed var(--border-on-dark);
}

.mf-pw-shot__more-title {
  font-family: var(--font-display);
  font-weight: var(--weight-semibold);
  font-size: 22px;
  margin: 0;
}

.mf-pw-shot__more-body {
  font-family: var(--font-body);
  font-size: 13px;
  line-height: 1.6;
  color: var(--ink-on-dark-body);
  margin: 8px 0 0;
}


/* ==========================================================================
   Why us — light split panel

   The section used to run on coal. It sits below the examples now, which took
   the dark over, so this comes back into the light rather than giving the page
   two dark runs back to back.
   ========================================================================== */

/* The rising horizon ends on flat --paper-600, but the light sections on this
   page have no ground of their own — they show the body's page wash, which is
   warmer and dotted. Where the two met was a straight line across the page.
   Fading the ramp's last stretch lets it dissolve into the wash instead. */
.mf-horizon-up {
  -webkit-mask-image: linear-gradient(180deg, #000 72%, transparent 100%);
  mask-image: linear-gradient(180deg, #000 72%, transparent 100%);
}

.mf-pw-why {
  position: relative;
  padding: 90px 40px 100px;
  overflow: clip;
}

/* The same two corner glows, at the strength a paper ground can carry — on
   coal they were light thrown onto the dark, here they are a warm tint in it. */
.mf-pw-why__bloom {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    radial-gradient(ellipse 45% 50% at 8% 20%, rgb(232 84 10 / 0.07), transparent 62%),
    radial-gradient(ellipse 50% 45% at 96% 88%, rgb(160 50 8 / 0.05), transparent 62%);
  /* Both glows sit close enough to an edge to still be tinted where the
     section ends, which drew a straight line across the page at the top and
     bottom. Fade the layer out towards both so it dissolves into the paper. */
  -webkit-mask-image: linear-gradient(180deg, transparent 0%, #000 30%, #000 70%, transparent 100%);
  mask-image: linear-gradient(180deg, transparent 0%, #000 30%, #000 70%, transparent 100%);
}

.mf-pw-why__inner {
  position: relative;
  z-index: 1;
  max-inline-size: var(--section-max);
  margin-inline: auto;
  display: grid;
  grid-template-columns: 0.95fr 1.05fr;
  gap: 64px;
  align-items: start;
}

.mf-pw-why__lede .mf-eyebrow { margin-block-end: 20px; }

/* The lede arrives in order — eyebrow, heading, lead, then the two figures,
   which count up (practice-websites.js) — rather than fading in as a block.
   The whole block carries the reveal's opacity; the parts each add a rise
   staggered on --i. Once the block is in, everything settles in 1.1s. */
.mf-pw-why__lede > * {
  opacity: 0;
  translate: 0 16px;
  transition:
    opacity 0.6s ease calc(var(--i, 0) * 0.12s),
    translate 0.7s var(--ease-out) calc(var(--i, 0) * 0.12s);
}

.mf-pw-why__lede.is-in > * { opacity: 1; translate: 0 0; }

.mf-pw-why__lead {
  font-family: var(--font-body);
  font-size: 17px;
  line-height: 1.75;
  color: var(--ink-body);
  margin: 20px 0 0;
  max-inline-size: 46ch;
}

.mf-pw-why__stats {
  list-style: none;
  margin: 40px 0 0;
  padding: 0;
  display: flex;
  gap: 48px;
}

.mf-pw-why__stat {
  font-family: var(--font-display);
  font-weight: var(--weight-semibold);
  font-size: 46px;
  line-height: 1;
  margin: 0;
}

.mf-pw-why__stat-label {
  font-family: var(--font-ui);
  font-size: 12.5px;
  font-weight: var(--weight-semibold);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-muted);
  margin: 10px 0 0;
}

/* Points hang off one hairline instead of sitting in boxes — the eye follows
   the line down the column, which is what a row of cards would interrupt. */
.mf-pw-why__points {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 30px;
}

/* The icons carry the column on their own now — a rail as well as them was
   two devices doing one job. The indent is the icon's width plus its gap, so
   the copy hangs off a line the icons themselves draw. */
.mf-pw-why__points li {
  position: relative;
  padding-inline-start: 48px;
}

/* Level with the title's first line, where the dot it replaces used to sit. */
.mf-pw-why__point-icon {
  position: absolute;
  inset-inline-start: 0;
  inset-block-start: -3px;
  inline-size: 32px;
  block-size: 32px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  background: var(--grad-icon);
}

.mf-pw-why__point-title {
  font-family: var(--font-display);
  font-weight: var(--weight-semibold);
  font-size: 19px;
  color: var(--ink);
  margin: 0 0 8px;
}

.mf-pw-why__point-body {
  font-family: var(--font-body);
  font-size: 14.5px;
  line-height: 1.7;
  color: var(--ink-body);
  margin: 0;
  max-inline-size: 52ch;
}


/* ==========================================================================
   Closing CTA
   ========================================================================== */

/* The horizon ramp above already supplies the run-in, so the top padding is
   small — the panel should sit just under where the sky finishes. */
.mf-pw-cta {
  position: relative;
  padding: 20px 40px 120px;
}

.mf-pw-cta__panel {
  position: relative;
  max-inline-size: var(--section-max);
  margin-inline: auto;
  overflow: hidden;
  border-radius: 28px;
  padding: 80px 64px;
  text-align: center;
  background: linear-gradient(135deg, var(--coal-740) 0%, var(--coal-900) 55%, #231206 100%);
  box-shadow: var(--shadow-panel);
}

.mf-pw-cta__glow {
  position: absolute;
  inset-inline: 0;
  inset-block-start: -40%;
  block-size: 120%;
  pointer-events: none;
  background: radial-gradient(
    ellipse 50% 50% at 50% 40%,
    rgb(232 84 10 / 0.28),
    transparent 66%
  );
}

.mf-pw-cta__body { position: relative; z-index: 1; }
.mf-pw-cta__body .mf-eyebrow { margin-block-end: 22px; }

.mf-pw-cta__lead {
  font-family: var(--font-body);
  font-size: 17px;
  line-height: 1.75;
  color: var(--ink-on-dark-body);
  margin: 20px auto 0;
  max-inline-size: 620px;
}

.mf-pw-cta__actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 14px;
  margin-block-start: 34px;
}


/* ==========================================================================
   Keyframes
   ========================================================================== */

/* The browser mock's page scrolling itself. 39s a cycle: a beat at the top,
   ~23s down, a beat and a half at the bottom, then ~12s back up — the return
   is quicker than the descent because nobody is reading on the way back.
   ease-in-out on the animation eases every one of those segments, so the page
   never starts or stops dead. */
@keyframes pwPageScroll {
  0%, 4%    { transform: translateY(0); }
  62%, 66%  { transform: translateY(-65.3%); }
  96%, 100% { transform: translateY(0); }
}

@keyframes pwSpin {
  from { rotate: 0deg; }
  to { rotate: -360deg; }
}

@keyframes pwDrift {
  0%, 100% { scale: 1; }
  50% { scale: 1.14; }
}

@keyframes pwMeterFill {
  to { scale: 1 1; }
}

@keyframes pwPing {
  0% { scale: 1; opacity: 1; }
  55% { scale: 2.4; opacity: 0; }
  100% { scale: 2.4; opacity: 0; }
}

@keyframes pwRowIn {
  from { opacity: 0; translate: 0 7px; }
  to { opacity: 1; translate: none; }
}

@keyframes pwCaret {
  50% { opacity: 0; }
}

@keyframes pwRankPop {
  0% { scale: 0.5; }
  60% { scale: 1.18; }
  100% { scale: 1; }
}

@keyframes pwMonitorScan {
  0%, 55%, 100% { opacity: 0.34; }
  12% { opacity: 1; }
}

@keyframes pwSlotIn {
  from { opacity: 0; translate: 0 4px; }
  to { opacity: 1; translate: none; }
}

/* The live dot glows in green rather than brand orange — it is a status
   light, and orange would read as a warning next to it. */
@keyframes pwNodePulseLive {
  0% { box-shadow: 0 0 0 0 var(--status-live-on-dark-line); }
  70% { box-shadow: 0 0 0 7px rgb(45 158 107 / 0); }
  100% { box-shadow: 0 0 0 0 rgb(45 158 107 / 0); }
}

@keyframes pwNodePulse {
  0% { box-shadow: 0 0 0 0 var(--flare-a50); }
  70% { box-shadow: 0 0 0 16px rgb(232 84 10 / 0); }
  100% { box-shadow: 0 0 0 0 rgb(232 84 10 / 0); }
}

/* --- Benefit visuals, idle ------------------------------------------- */

@keyframes pwVizPing {
  0% { box-shadow: 0 0 0 0 var(--flare-a40); }
  70% { box-shadow: 0 0 0 8px rgb(232 84 10 / 0); }
  100% { box-shadow: 0 0 0 0 rgb(232 84 10 / 0); }
}

@keyframes pwVizSheen {
  0% { translate: -140% 0; }
  60%, 100% { translate: 260% 0; }
}

@keyframes pwVizBreathe {
  0%, 100% { filter: brightness(1); }
  50% { filter: brightness(1.35); }
}

@keyframes pwVizBob {
  0%, 100% { translate: 0 0; }
  50% { translate: 0 -3px; }
}

@keyframes pwVizBeat {
  0%, 100% { scale: 1; }
  50% { scale: 1.045; }
}

@keyframes pwVizWave {
  0%, 100% { opacity: 0.8; }
  50% { opacity: 1; filter: brightness(1.3); }
}


/* ==========================================================================
   Responsive
   ========================================================================== */

/* Below this the ring's cards have nowhere left to go — the expression in
   .mf-pw-bcard would resolve under ~160px. Clearing --pw-pin is the signal
   practice-websites.js reads to leave the pin switched off, which leaves the
   section in its default card-grid state. */
@media (max-width: 1080px) {
  .mf-pw-benefits { --pw-pin: 0; }
  :root { --pw-seam: var(--coal-900); }

  /* With the seam coal, the hero's fade-to-seam was a 490px coal shadow
     creeping up behind the browser frame, showing either side of it above
     the arch. The arch's dome is coal already and the benefits grid opens
     on coal, so the curve itself is the join: the hero stays on the page
     wash right up to it, the way the other heroes do. */
  .mf-pw-hero::after { display: none; }
}

/* The ring is a tall-viewport treatment: below this the derived size drops
   under ~340px, at which point the core heading no longer sits comfortably
   inside the circle and the cards start meeting the nav. The card grid is a
   better presentation there than a cramped ring. */
@media (max-height: 820px) {
  .mf-pw-benefits { --pw-pin: 0; }
  :root { --pw-seam: var(--coal-900); }
}

/* The visual panel only appears once there is room for it beside the card
   without taking that room off the ring. Between the pin breakpoint and
   1440px the ring runs exactly as it did before the panel existed: hidden
   here, and --pw-viz-w left at 0 so every expression that reserves room for
   it collapses to nothing.

   Hidden only while pinned — the card grid below the pin breakpoint has all
   the room it needs and shows the visual under the copy. */
@media (min-width: 1081px) {
  .mf-pw-benefits[data-pw-pin="on"] .mf-pw-bviz { display: none; }
}

@media (min-width: 1440px) {
  .mf-pw-benefits { --pw-viz-w: 190px; }

  .mf-pw-benefits[data-pw-pin="on"] .mf-pw-bviz { display: block; }
}


/* Unpinned (tablet and down) the captures are a plain grid, and a fixed
   200px window over a 460px-wide column shows a letterbox strip of header
   and nothing of the page. The window follows the column's width instead,
   so each capture shows the hero it opens on. The three steps of the
   timeline sit in a row rather than down a centred column, which at these
   widths ran each one-line body across the whole section. */
@media (max-width: 1179px) {
  .mf-pw-shots.mf-pw-collage__cards .mf-pw-shot__view {
    block-size: auto;
    aspect-ratio: 3 / 2;
  }

  .mf-pw-collage__copy { max-inline-size: 960px; }

  .mf-pw-collage__lead {
    max-inline-size: 640px;
    margin-inline: auto;
  }
}

@media (min-width: 700px) and (max-width: 1179px) {
  .mf-pw-clsteps {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 28px;
    margin-block-start: 36px;
    align-items: start;
  }
}

@media (max-width: 1023px) {
  .mf-pw-hero { padding: 96px 32px 0; }

  /* The row is narrower here, so the phone takes a bigger share of it to
     stay readable — it is a percentage of the mock, not of the viewport. */
  /* Under this the end column cannot hold two card columns and still leave
     the browser a usable width. The column dissolves — display: contents puts
     the cards and the phone straight into the row — and the cards take a full
     row of their own above the two devices.

     Above, not below: the row's foot is what hangs into the arch, and a card
     with a sentence on it half-eaten by the curve is not the same as a
     screenshot half-eaten by it. The devices keep the tuck; the copy stays
     clear of it. */
  .mf-pw-hero__mock {
    flex-wrap: wrap;
    row-gap: clamp(18px, 2.4vw, 30px);
  }

  .mf-pw-hero__side { display: contents; }

  .mf-pw-hero__proof {
    order: -1;
    flex-basis: 100%;
    inline-size: 100%;
    /* Held to a card's width and pushed to the end, so it still reads as
       sitting over the phone rather than as a banner across the mock. */
    grid-template-columns: minmax(0, 380px);
    justify-content: end;
  }

  .mf-pw-hero__phone { flex: 0 0 22%; inline-size: 22%; }

  /* The hero is a single centred column at every width now, so the only
     thing left to relax here is the measure on the lead. */
  .mf-pw-hero__lead { max-inline-size: none; }

  /* The bento's explicit placements assume six columns; below that it is
     simply an auto-fit grid and every cell sizes itself. Two class selectors
     so this outweighs both the .mf-pw-cell-* placements and the
     .mf-pw-bento > :nth-last-child() ones without reaching for !important. */
  .mf-pw-bento { grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); }

  .mf-pw-bento > .mf-pw-cell {
    grid-column: auto;
    grid-row: auto;
  }

  .mf-pw-inc,
  .mf-pw-why { padding-inline: 28px; }

  .mf-pw-costs__split { grid-template-columns: 1fr; gap: 30px; }

  /* Not narrower than it is on desktop: the cover is a fixed A-series shape,
     so squeezing its width shortens the box faster than it shortens the type
     inside it, and the title runs into the footer rule. */
  .mf-pw-guide { max-inline-size: 260px; }

  /* One rail. The heading re-centres with every other section header on the
     page — left-aligned made sense against a column of prices, not on its
     own above them. */
  .mf-pw-pricing__split {
    grid-template-columns: 1fr;
    grid-template-areas: "head" "cards" "note";
    gap: 40px;
  }

  .mf-pw-pricing .mf-pw-sechead {
    text-align: center;
    max-inline-size: 760px;
    margin-inline: auto;
  }

  .mf-pw-pricing .mf-pw-sechead .mf-lead { margin-inline: auto; }
  .mf-pw-trust { grid-template-columns: 1fr; gap: 32px; }
  .mf-pw-why__inner { grid-template-columns: 1fr; gap: 48px; }
  .mf-pw-cta__panel { padding: 60px 32px; }

  /* Two columns would squeeze the cards to a few words a line — the portrait
     moves above them instead, same as the hero art does at this width. */
  .mf-pw-tl {
    grid-template-columns: 1fr;
    gap: 48px;
    margin-block-start: 48px;
  }

  .mf-pw-tl__figure {
    inline-size: min(100%, 380px);
    margin-inline: auto;
  }

  /* The disc is centred above the stack now, so there is no circle edge for
     the arc to follow — the cards go back to a flush column. Matches the
     arc selector's specificity and wins on order. */
  .mf-pw-tl__steps > .mf-pw-tlcard:first-child,
  .mf-pw-tl__steps > .mf-pw-tlcard:last-child {
    --pw-tl-x: 0px;
  }
}

@media (max-width: 780px) {
  .mf-pw-hero { padding: 80px 22px 0; }

  /* The frame is the full width of the column here, so its shadow — which
     spreads 90px — reached out under the arch's transparent band and showed
     as a dark smudge either side of the dome. The band paints over the frame
     anyway, so the frame can do without the shadow. */
  .mf-pw-frame { box-shadow: none; }

  /* The browser alone: beside a phone at this width both devices shrink
     past the point of showing anything, and the browser is the claim. */
  .mf-pw-hero__phone { display: none; }

  .mf-pw-plans__cards { grid-template-columns: 1fr; gap: 24px; }

  .mf-pw-pricing,
  .mf-pw-timeline,
  .mf-pw-examples { padding-inline: 22px; }

  /* Six full-width captures ran to three screens of anonymous homepages,
     with "how long it takes" a long way under them. Two columns of shorter
     windows put the whole set on one screen — a sampler to glance down on
     the way to the copy, with the portfolio page for a proper look. */
  .mf-pw-shots.mf-pw-collage__cards {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 12px;
    margin-block-start: 28px;
    --pw-shot-vh: 132px;
  }

  .mf-pw-collage__copy { margin-block-start: 44px; }

  .mf-pw-inc,
  .mf-pw-why { padding-inline: 22px; }

  .mf-pw-cta { padding: 40px 22px 90px; }

  .mf-pw-tl { gap: 44px; margin-block-start: 44px; }
  .mf-pw-tl__figure { inline-size: min(100%, 320px); }
  .mf-pw-tl__halo { inset: -22px; translate: -10px -9px; }

  .mf-pw-tlcard { padding: 22px 28px 22px 52px; }

  .mf-pw-why__stats { gap: 32px; }
  .mf-pw-extras { padding: 26px 22px; }
}

@media (max-width: 560px) {
  /* Too narrow to hold the card off to one side — it takes the full row. */
  .mf-pw-hero__proof { grid-template-columns: minmax(0, 1fr); }

  /* The stack inches right to leave the breakout disc room off the edge. */
  .mf-pw-tl__steps { padding-inline-start: 12px; }

  /* The cards run tall down here, so a capsule would curve straight through
     the copy — the radius is capped instead, still round, no longer a pill. */
  .mf-pw-tlcard {
    gap: 14px;
    padding: 20px 20px 20px 44px;
    border-radius: 34px;
  }

  .mf-pw-tlcard__num {
    inline-size: 40px;
    block-size: 40px;
    font-size: 15px;
  }

  .mf-pw-tlcard__icon svg {
    inline-size: 28px;
    block-size: 28px;
  }

  .mf-pw-plan { padding: 26px 22px; }
  .mf-pw-plan__figure { font-size: 40px; }
  .mf-pw-contrast { padding: 26px 22px; }
  .mf-pw-cta__panel { padding: 48px 22px; }
  .mf-pw-cta__actions .mf-btn { inline-size: 100%; }
}


/* ==========================================================================
   Reduced motion
   The pin, the spin and the drift all come off; the section falls back to
   the same card grid narrow viewports get.
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
  .mf-pw-why__lede > * { opacity: 1; translate: 0 0; transition: none; }
  .mf-pw-benefits { --pw-pin: 0; }
  :root { --pw-seam: var(--coal-900); }

  .mf-pw-ring__spin,
  .mf-pw-amb span,
  .mf-pw-monitor__pulse,
  .mf-pw-monitor__bar,
  .mf-pw-cal__slot,
  .mf-pw-orbit__item.is-active .mf-pw-orbit__node { animation: none; }

  .mf-pw-hero__proof-item {
    transition: none;
    opacity: 1;
    transform: none;
  }

  /* The mock stops scrolling and rests on the practice's first screen — the
     same view it opens on for everyone else. */
  .mf-pw-frame__screen img { animation: none; }

  .mf-pw-monitor__bar { opacity: 0.7; }
  .mf-pw-cal__day, .mf-pw-cal__slot, .mf-pw-cal__nav { transition: none; }
  .mf-pw-cal__day:hover { scale: none; }

  .mf-pw-cell-slim:hover { translate: none; }
  .mf-pw-guide__back, .mf-pw-guide__cover { transition: none; }
  .mf-pw-map__ping { animation: none; }

  .mf-anim .mf-pw-shots > .mf-pw-shot { opacity: 1; animation: none; }
  .mf-pw-tlcard { transition-delay: 0s; }
}
