/* ---------------------------------------------------------------------------
   Section layout.

   Bands stack in normal document flow and are free to grow with their content.
   Curves are shape dividers anchored to a band edge; the rest of each band is
   flat colour, so reflowing text can never desync from the artwork the way it
   would against a fixed 1440x2730 canvas.
   --------------------------------------------------------------------------- */

/* --- Header ---------------------------------------------------------------- */

/* comp: header occupies 0-150, with the logo at 33.6 and the utility row
   ending at 125. Padding expressed in vw against the 1440 artboard so the band
   is 150 tall at comp width — it was rendering 119, which started the hero
   media 31px high and pulled everything below it up. */
.site-header {
  position: relative;
  /* Must outrank every sibling in .band-page, not just clear the background.
     z-index:2 tied with .page-head (and the daisy decoration), and DOM order
     broke the tie the wrong way: the title block painted over the services
     dropdown and swallowed the pointer, so only the top two items were
     reachable. The submenu's own z-index:30 cannot help — it is trapped in the
     stacking context this rule creates. */
  z-index: 6;
  padding-block: 2.33cqw 1.74cqw;
}

.site-header > .wrap {
  display: grid;
  grid-template-columns: auto 1fr;
  grid-template-areas:
    "logo primary"
    "logo utility";
  /* align-items: start so the logo sits at its comp y (33.6) rather than being
     centred against a taller right-hand column. The comp's header is 150 tall:
     33.6 padding + 91.4 content + 25 padding. The right column drives that
     content height — nav at 54.9, utility row ending at 125 — so the offsets
     below are what make the band the right height, and everything downstream
     depends on it. */
  align-items: start;
  column-gap: var(--gutter);
  row-gap: 1.39cqw; /* comp: nav row ends ~79.9, utility starts 99.9 */
}

/* 180px floor overflowed a 320px viewport once the burger and social icons were
   alongside it (339 > 320). 140 clears it with room to spare. */
.logo {
  grid-area: logo;
  display: block;
  width: clamp(140px, 18.75vw, 270px);
}

.logo img {
  width: 100%;
  height: auto;
}

/* Primary nav + social */
.header-primary {
  grid-area: primary;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: clamp(0.7rem, 1.6vw, 1.35rem);
  padding-top: 1.48cqw; /* comp: nav baseline row at 54.9, band top at 33.6 */
}

.nav {
  display: flex;
  align-items: center;
  gap: clamp(0.7rem, 1.6vw, 1.35rem);
}

/* The services trigger is a <button>, so it needs the anchors' appearance
   applied explicitly — .nav a does not reach it. */
.nav-trigger {
  padding: 0;
  font-family: inherit;
  background: none;
  border: 0;
  cursor: pointer;
}

.nav a,
.nav-trigger {
  font-size: var(--fs-ui);
  line-height: 1.4;
  color: var(--white);
  text-decoration: none;
  white-space: nowrap;
  letter-spacing: 0.09px;
}

.nav a:hover,
.nav a:focus-visible,
.nav-trigger:hover,
.nav-trigger:focus-visible {
  text-decoration: underline;
}

.nav a[aria-current="page"],
.nav-trigger[aria-current="page"] {
  color: var(--plum);
  font-weight: 700;
}

/* --- Services dropdown (ISS-009) --------------------------------------------
   Values sampled from desktop artboard 3, the only place the comp draws it
   open: panel 264x263 in solid #E1E9D9 (the green header behind does NOT bleed
   through, so it is opaque, not a tinted white), 1px #C8C8C8 rules between
   items, centred under the SERVICES trigger.
   --------------------------------------------------------------------------- */

.nav-group {
  position: relative;
  display: flex;
  align-items: center;
  --submenu-gap: 0.55rem;
}

.submenu {
  position: absolute;
  top: calc(100% + var(--submenu-gap));
  left: 50%;
  translate: -50%;
  z-index: 30;
  width: 264px;
  margin: 0;
  padding: 13px 0 10px;
  list-style: none;
  background: #e1e9d9;
  border-radius: 8px;
  box-shadow: 0 6px 18px rgb(0 0 0 / 18%);

  /* Hidden by default without leaving it in the tab order. visibility (rather
     than display) keeps it animatable and keeps :focus-within workable. */
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.14s ease;
}

/* Hover covers mouse; focus-within covers keyboard without any script, so the
   menu is operable even if the enhancement below never runs. */
/* :not([data-dismissed]) is on every opener rather than a separate override.

   Escape returns focus to the trigger, which lives inside .nav-group, so
   :focus-within would otherwise re-open the menu instantly and it could never
   be dismissed from the keyboard. A separate override rule does NOT work:
   `.nav-group:focus-within .submenu` is (0,3,0) and beats `.submenu[data-x]`
   at (0,2,0), so it wins regardless of source order. Excluding the state at
   each opener is specificity-independent and cannot be broken by reordering.

   data-dismissed is set only by Escape and cleared the moment the pointer or
   focus genuinely leaves. */
.nav-group:hover .submenu:not([data-dismissed]),
.nav-group:focus-within .submenu:not([data-dismissed]),
.submenu[data-open]:not([data-dismissed]) {
  opacity: 1;
  visibility: visible;
}

/* Invisible bridge across the gap between trigger and panel.

   Without it the menu is unusable with a mouse: the panel sits 8.8px below the
   trigger, and mid-gap the element under the cursor is .wrap — outside
   .nav-group — so :hover drops and pointerleave fires before you ever reach the
   items. The bridge is part of the submenu, so crossing it keeps the pointer
   inside the group. It inherits visibility:hidden when closed, so it never
   blocks anything it shouldn't. */
.submenu::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: calc(var(--submenu-gap) * -1);
  height: var(--submenu-gap);
}

/* Rules are INSET from the panel edge (comp: 224 wide inside a 264 panel), so
   they cannot be a plain border-top on the item. */
.submenu li + li {
  position: relative;
}

.submenu li + li::before {
  content: "";
  position: absolute;
  top: 0;
  left: 20px;
  right: 20px;
  height: 1px;
  background: #c8c8c8;
}

.submenu a {
  display: block;
  padding: 7px 18px;
  font-size: 11.5px;
  line-height: 1.3;
  font-weight: 400;
  color: #3c3c3b;
  text-align: center;
  text-decoration: none;
  white-space: nowrap;
}

.submenu a:hover,
.submenu a:focus-visible {
  color: var(--plum);
  text-decoration: underline;
}

/* The page you are on is shown in plum and bold, as on artboard 3. */
.submenu a[aria-current="page"] {
  color: var(--plum);
  font-weight: 600;
}

/* Trigger picks up the same highlight while its menu is open. */
.nav-group:hover > .nav-trigger,
.nav-group:focus-within > .nav-trigger {
  color: var(--plum);
}

.social-links {
  display: flex;
  gap: 0.35rem;
  margin-left: 0.5rem;
}

.social-links a {
  display: block;
  width: 25px;
  height: 25px;
  flex: none;
}

/* Utility row: pay pill + search */
.header-utility {
  grid-area: utility;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 0.6rem;
}

/* Same pill as .pay (24 tall, 12px/600 white label, white ring) in the
   site-visit tab's amber. Client amend 2026-10-24. */
.book-visit {
  display: block;
  flex: none;
  padding: 3.5px 9.6px; /* + 17px line = 24 tall */
  border-radius: 12px;
  background: #edac3c;
  box-shadow: inset 0 0 0 1px var(--white);
  font-size: 12px;
  line-height: 17px;
  font-weight: 600;
  color: var(--white);
  letter-spacing: 0.05px;
  white-space: nowrap;
  text-decoration: none;
}

.pay {
  position: relative;
  display: block;
  width: 125.6px;
  height: 24px;
  flex: none;
  text-decoration: none;
}

/* The pill arrives as a fill/stroke PAIR — 1:299 body, 1:300 outline. Using
   one half alone leaves a hollow shape. Same for the cursor glyph. */
.pay .pay-fill,
.pay .pay-ring {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

.pay .pay-label {
  position: absolute;
  left: 9.6px;
  top: 3.5px;
  font-size: 12px;
  line-height: 17px;
  font-weight: 600;
  color: var(--white);
  letter-spacing: 0.05px;
  white-space: nowrap;
}

.pay .pay-cursor {
  position: absolute;
  left: 107.1px;
  top: 13.1px;
  width: 15.6px;
  height: 15.8px;
}

.pay .pay-cursor img { position: absolute; }
.pay .pay-cursor .cur-fill { left: 2.3px; top: 2.3px; width: 11.1px; height: 11.2px; }
.pay .pay-cursor .cur-ring { width: 15.6px; height: 15.8px; }

/* Search — field is also a pair: 1:63 is a 50%-white body, 1:64 the outline. */
.search {
  position: relative;
  width: 232px;
  height: 25.1px;
  flex: none;
}

.search .search-fill,
.search .search-ring {
  position: absolute;
  left: 0;
  top: 0;
  width: 200px;
  height: 25.1px;
}

.search input {
  position: absolute;
  left: 10px;
  top: 0;
  width: 165px;
  height: 25.1px;
  border: 0;
  background: none;
  font-family: var(--font-body);
  font-size: 12px;
  font-weight: 600;
  color: var(--black);
}

.search input::placeholder { color: var(--black); opacity: 1; }

/* The microphone is FOUR vectors — capsule, cradle, stem, base. Any one alone
   renders as a meaningless fragment (the stray "U" the cradle makes). */
.search .search-mic {
  position: absolute;
  left: 180.6px;
  top: 3.8px;
  width: 10.1px;
  height: 17.5px;
  /* It is a <button> since voice search landed (was a decorative span). The
     reset is what keeps the geometry identical: a UA button brings padding, a
     border and its own font, and the four parts are positioned against this
     box's padding edge. */
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

/* Hit area. The drawn mic is 10.1x17.5 — well under the 24x24 minimum for a
   touch target — so an absolutely positioned pseudo inside the (absolute)
   button widens what can be pressed to 24.1x31.5 without touching the button
   box or the four part rects. -7px on both axes, not -7px/-6px: 10.1 + 12 is
   22.1, still short of 24. It overhangs the field's right end, which costs
   about 1.4px of the input's own click strip there. */
.search .search-mic::before {
  content: "";
  position: absolute;
  inset: -7px;
}

.search .search-mic img { position: absolute; }
.search .search-mic .mic-capsule { left: 2.2px; top: 0;      width: 5.8px;  height: 10.6px; }
.search .search-mic .mic-cradle  { left: 0;     top: 7.4px;  width: 10.1px; height: 5.5px; }
.search .search-mic .mic-stem    { left: 4.5px; top: 12.1px; width: 1.2px;  height: 5.5px; }
.search .search-mic .mic-base    { left: 1.6px; top: 16.4px; width: 6.9px;  height: 1.1px; }

/* The button ships `hidden` and the script un-hides it only where the Web
   Speech API exists. Pair the attribute with the class rule rather than
   leaving the UA's [hidden] to fight it (L-036/L-040). */
.search .search-mic[hidden] { display: none; }

/* Focus ring for all three shells. NOT currentColor: that is black in the
   header and footer but white inside the magenta overlay, where the ring
   lands on the field's translucent-white pill and would disappear. Black is
   the colour the input text and placeholder already use in every shell. */
.search-mic:focus-visible {
  outline: 2px solid var(--black);
  outline-offset: 2px;
}

/* Listening. Gated on no-preference like the daisy spin rather than left to
   the global reduce clamp in base.css — that only shortens durations, which
   would turn an infinite pulse into a flicker. */
@media (prefers-reduced-motion: no-preference) {
  @keyframes mic-pulse {
    from, to { opacity: 1; }
    50%      { opacity: 0.4; }
  }
  .search-mic[aria-pressed="true"] .mic-capsule {
    animation: mic-pulse 1s ease-in-out infinite;
  }
}

.search .search-submit {
  position: absolute;
  left: 206.9px;
  top: 0;
  width: 25.1px;
  height: 25.1px;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
}

/* Burger — hidden on desktop, the whole nav on mobile (mobile artboard 02). */
.burger {
  display: none;
  width: 44px;
  height: 44px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: var(--plum);
  color: var(--white);
  cursor: pointer;
}

/* --- Hero band ------------------------------------------------------------- */

/* The band BOX stays 1440 — .daisy-1 and .blob are positioned as percentages of
   it, so widening it would fling them apart. Only the gradient bleeds, via the
   pseudo-element below. That gradient is also what colours the header, which
   sits inside this band and has no background of its own. */
.band-hero {
  padding-bottom: 0;
}

.band-hero::before {
  content: "";
  position: absolute;
  inset-block: 0;
  left: var(--bleed-inset);
  width: 100vw;
  /* Below the dividers and arcs (-1) so it is purely the backdrop. */
  z-index: -3;
  background: linear-gradient(90deg, #ea068c 0%, #e665a2 100%);
}

/* Every piece of bleeding artwork on the homepage, grouped so the one
   easy-to-miss requirement lives in a single place: `img { max-width: 100% }`
   in base.css clamps these straight back to their band's width, which cancels
   the bleed entirely above 1440 while still looking right below it.

   All five SVGs carry preserveAspectRatio="none", so each stretches to whatever
   box it is given rather than letterboxing inside it. Their heights are pinned
   individually below. */
.band-hero .floral,
.band-hero .arcs,
.band-hero .divider,
.band-main .arcs,
.band-main .divider {
  left: var(--bleed-inset);
  width: 100vw;
  max-width: none;
}

/* Floral line-art across the top. Bleeds with the gradient — capped at 1440 it
   would stop dead mid-stroke with pink continuing past it. */
.band-hero .floral {
  top: 0;
  z-index: 0;
  opacity: 1;
  /* Pinned to the comp's 625.7/1440 like the dividers and arcs. Left on `auto`
     it scales proportionally, so at 2560 the line-art would reach 1112px down
     the page instead of 626 and drag the daisy motif across the hero. */
  height: 43.45cqw;
}

.hero-media {
  position: relative;
  overflow: hidden;
  /* Full bleed, with the comp height PINNED rather than an aspect ratio.
     43.55cqw is 627.1/1440, so below the cap this is identical to the
     `aspect-ratio: 1440/627.1` it replaces; above it the height holds at 627.1
     and the video becomes a wider letterbox instead of growing to 1115px tall
     on a 2560 monitor. object-fit: cover crops the extra width. */
  width: 100vw;
  margin-inline: var(--bleed-inset);
  height: 43.55cqw;
  /* The curved bottom edge is the exact comp path. mask-size: 100% 100% lets
     it track the element as it scales, rather than a fixed pixel box. */
  -webkit-mask-image: url("../assets/svg/hero-photo-mask.svg");
  mask-image: url("../assets/svg/hero-photo-mask.svg");
  -webkit-mask-size: 100% 100%;
  mask-size: 100% 100%;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
}

.hero-media > video,
.hero-media > img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 40%;
  background: #000;
}

/* Headline sits over the media on desktop, below it on mobile (T-015). */
/* inset-inline: 0 (not inset-inline-start: 0) so the .wrap's max-width and auto
   margins still centre it — pinned to the start edge, the headline sat at the
   48px gutter instead of the 192.5 content column. */
.hero-copy {
  position: absolute;
  inset-inline: 0;
  top: clamp(3rem, 5vw, 4.5rem);
  z-index: 2;
}

.hero-headline {
  margin: 0;
  /* Safety cap only — the three lines come from explicit <br>s in the markup,
     because no max-width can produce them (see the note there). */
  max-width: 683px;
  font-family: var(--font-display);
  font-size: var(--fs-display);
  font-weight: 400;
  line-height: 1.13;
  color: var(--white);
  letter-spacing: 0.031em;
}

.play {
  position: absolute;
  left: 50%;
  top: 46%;
  translate: -50% -50%;
  width: clamp(40px, 3.47vw, 50px);
  aspect-ratio: 1;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  z-index: 3;
}

.play[hidden] { display: none; }

/* The disc is a WHITE circle carrying a luminance mask made of a dark-grey
   radial (#3C3C3B -> #575756). That grey luminance is what makes it read as a
   translucent ~30% disc. Unmasked it comes out solid white and swallows the
   triangle. mask-mode: luminance is required — the default treats an SVG image
   as an ALPHA mask, and this one is fully opaque, so alpha gives 100%. */
.play .play-ring {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  -webkit-mask-image: url("../assets/svg/play-button-mask.svg");
  mask-image: url("../assets/svg/play-button-mask.svg");
  -webkit-mask-size: 100% 100%;
  mask-size: 100% 100%;
  mask-repeat: no-repeat;
  mask-mode: luminance;
}

.play .play-tri {
  position: absolute;
  left: 36%;
  top: 28%;
  width: 38%;
  height: 44%;
}

/* Strapline under the hero, right-aligned column as in the comp */
.hero-intro {
  /* comp: media ends 777, strapline starts 806 — a 29 gap, i.e. 2.01cqw. */
  margin: 2.01cqw 0 0 auto;
  max-width: 30ch;
  font-size: var(--fs-lead);
  font-weight: 300;
  line-height: 1.28;
  color: var(--white);
}

/* Shape dividers OVERLAY their band edge rather than sitting in flow.

   This is not a style preference. In the comp the hero curve begins at y=617
   while the video runs to y=777 — the sweep starts *behind* the media and the
   strapline sits on top of it. Stacking the divider after the content instead
   added ~470px of dead magenta and pushed every band below it out of place.

   z-index -1 inside the band's isolated stacking context paints them above the
   band's own background but behind its content, which is exactly the layering
   the artwork assumes. Bands reserve room with padding, expressed in vw so the
   reserved space tracks the curve as it scales. */
.divider {
  position: absolute;
  left: 0;
  width: 100%;
  height: auto;
  z-index: -1;
}

.band-hero { padding-bottom: 13.2cqw; } /* comp: intro ends 895, band ends 1085 */

/* Bleeds with the band's gradient. The height is PINNED to the comp — 485/1440
   — rather than left to `auto`, which would scale the curve proportionally and
   overshoot the 13.2cqw of padding reserved for it above. Pinned, the sweep
   simply gets shallower as the viewport widens and the vertical rhythm holds.
   Requires preserveAspectRatio="none" on the SVG, added there. */
.band-hero .divider {
  bottom: 0;
  height: 33.68cqw;
}

/* ---------------------------------------------------------------------------
   Page header band — the shared pattern for the 13 inner pages.

   The homepage sets no theme and falls back to the brand magenta, so one
   stylesheet serves both. Inner pages get --theme / --theme-light inline on
   .site from src/site.json.
   --------------------------------------------------------------------------- */

/* No background colour: the band IS its SVG shape (Figma 1:1616), which has a
   curved bottom edge. A rectangular background behind it would square it off.
   min-height keeps the band at the artboard's 925.6 so the curve is undistorted
   at desktop; the shape stretches if content ever makes the band taller. */
/* z-index 1 so the band paints ABOVE the section that follows it. The pale
   underlay is 995 tall against the band's 925.6, so 69 units hang below the
   band box — and .band-body, being later in the document, was painting its
   white over them. The result was the curve looking flat-cut at its lowest
   point: the artboard reaches ~994 on the right, this was stopping at ~915.

   Safe because the overhang only exceeds the band where the pale edge is low,
   which is x>800 — the right-hand side, where band-body has no content. */
.band-page {
  position: relative;
  /* Products sets --page-z: 2 (site.json headerStyle) to stay above its raised
     band-body (--body-z: 1 below). Without it the white body paints over the
     bottom of the header photo, which on phones hangs below the header band. */
  z-index: var(--page-z, 1);
  min-height: 64.28cqw;
}

.band-body {
  position: relative;
  /* Products raises this to 1 so the quote's circular wash, which hangs below
     the band, paints OVER the gallery band rather than under it. Equal z-index
     is resolved by DOM order and the gallery is the later sibling, so it wins
     by default. Raising it is only safe because that page also ends this band
     exactly where the gallery starts — otherwise the white background here
     would cover the gallery's top edge. The same lift is how a decoration that
     hangs into the gallery gets above it (every .band is isolated, base.css). */
  z-index: var(--body-z, 0);
}

/* ---------------------------------------------------------------------------
   Full bleed for the inner-page band artwork — the counterpart to the homepage
   rule further up, same reasoning: these four ARE the band's background, so
   capping them at 1440 would leave white gutters beside a curve that no longer
   ends anywhere meaningful.

   max-width: none is load-bearing. `img { max-width: 100% }` in base.css clamps
   these straight back to the band's width, which cancels the bleed above 1440
   while still looking correct below it — see the homepage note.

   Every page's .band-arcs bleeds. Contact used to be the exception — its slot
   held a small inline-positioned decoration rather than the header sweep, so
   the inline left/width beat this rule — but that decoration is now a
   .page-deco and Contact carries the real 1440 x 730 sweep (1:8256).
   --------------------------------------------------------------------------- */
.band-shape,
.band-underlay,
.band-floral,
.band-arcs,
.about-team::after {
  left: var(--bleed-inset);
  width: 100vw;
  max-width: none;
}

.band-shape {
  position: absolute;
  /* top/bottom only, NOT `inset: 0`. inset is shorthand for all four sides, so
     it re-set left:0 after the bleed rule above — same specificity, later in
     the file, so it won — and the band stopped dead at the canvas edge with
     white beside it while the pale underlay ran on past.
     Height stays 100%: the shape fills whatever height the band has. */
  top: 0;
  bottom: 0;
  height: 100%;
  z-index: -1;
}

/* 1:1611 — the header's bottom boundary: a pale edge sitting just under the
   band's curve.

   scaleY(-1) is REQUIRED. This vector carries the same stored vertical flip as
   every other export (its raw y of 994.99 is the pre-transform position), and
   inlining the path without it fills the shape DOWNWARD to y995 instead of up
   to a mirrored edge. Unflipped the pale ran ~470 deep and was covered by the
   next section; flipped it is the ~36 boundary the design intends — at x0 the
   band ends at 527.6 and the mirrored pale edge is at 995-431.3 = 563.7. */
.band-underlay {
  position: absolute;
  top: 0;
  /* Pinned from the SVG's own viewBox by the build — 994.99 on the service
     pages, 802.3 on About, 554.97 on the legal pages. Left on `auto` it would
     grow taller as it bleeds and swamp the section below. */
  height: var(--underlay-h, auto);
  z-index: -2;
}

/* 1:2252 — a 1440x626 window at the band's top; the art itself hangs off the
   top-right and is mostly clipped. */
.band-floral {
  position: absolute;
  top: 0;
  /* 625.7/14.4 — the same window on every page, so it is a constant here
     rather than a build-emitted variable. */
  height: 43.451cqw;
  z-index: 0;
  pointer-events: none;
}

/* 1:2253 — arcs over the band, under the opaque circular photo */
.band-arcs {
  position: absolute;
  top: 7.64cqw; /* y110 on the 1440 artboard */
  /* Build-emitted from the SVG's own viewBox: an 810 window on the service
     pages, 730 on Contact, 480 on the legal ones. The `auto` fallback only
     applies to a page with no arcs-header.svg at all — there are none now. */
  height: var(--arcs-h, auto);
  z-index: 0;
  pointer-events: none;
}

/* Copy sits left, clear of the circular photo. comp: title at x175, two lines
   at ~52px cap with an 81 pitch, intro three lines beneath. */
.page-head {
  position: relative;
  z-index: 2;
  /* Per page: .page-head starts at artboard y150, and the title sits at 269 on
     Garden Maintenance, 246.4 on Landscaping and 264.4 on the two privacy
     pages. Set from site.json — there is no shared value. */
  padding-top: var(--head-top, 8.2cqw);
}

/* comp: the title occupies roughly x175-660, which is what makes
   "Garden Maintenance" break onto two lines. */
.page-head-copy {
  /* No shared cap. The 480 here forced "& Tree Management" onto a third line on
     artboard 6, whose title box is 743 wide. Title and intro are capped
     separately below: the intro is ~460 on every artboard, but the title box
     varies (471 / 476 / 743), so line breaks are set explicitly in the heading
     rather than left to a width to decide. */
  max-width: none;
}

.page-title {
  max-width: 51.6cqw; /* 743 / 1440, the widest title box in the set */
}

/* comp: cap height measures ~52px across two lines on an 81 pitch. Fraunces has
   a 0.70 cap ratio, so that is a ~74px face, not the ~58 first guessed. */
.page-title {
  margin: 0;
  font-family: var(--font-display);
  font-size: clamp(2.5rem, 5.14vw, 74px);
  font-weight: 400;
  line-height: 1.1;
  color: var(--white);
}

.page-intro {
  margin: clamp(1rem, 2.4cqw, 2.2rem) 0 0;
  /* comp 1:2638 is 24px on 33 leading across ~460 — NOT body size. The 34ch
     cap was guesswork and wrapped it to 311. */
  max-width: 31.95cqw; /* 460 / 1440 */
  font-size: clamp(1.125rem, 1.67cqw, 24px);
  font-weight: 300;
  line-height: 1.375; /* 33 / 24 */
  color: var(--white);
}

/* Circular header photo. Figma node 1:1865 — 500 diameter at (728, 238), NOT
   the 450 at (975, 470) I first read off a screenshot. */
.page-photo {
  position: absolute;
  z-index: 1;
  /* All three differ per artboard: Garden Maintenance 500 at (728, 238),
     Landscaping 500 at (704.5, 237.7), Land Management 597 at (601.6, 200).
     Set from site.json. */
  left: var(--photo-x, 50.56%);
  top: var(--photo-y, 16.53cqw);
  width: var(--photo-w, 34.72%);
  aspect-ratio: 1;
  border-radius: 50%;
  overflow: hidden;
}

/* Vector exports used to arrive with a stored vertical flip, undone here by a
   rule keyed on the "node-" filename prefix. That was fragile: assets outside
   the prefix (assets/svg/pages/) silently escaped it and rendered upside down,
   and any rule with its own transform overrode it on specificity. Both failure
   modes actually happened. The flip is now baked into the SVG files, so a
   vector is correct wherever it is used and however it is referenced.
   Search the files for "flip-baked". Inline <svg> (.band-underlay) still
   carries its transform in CSS — that is explicit and local, not path-keyed. */
/* ---------------------------------------------------------------------------
   PAGE DECORATIONS — leaves and daisies, positioned against the band that owns
   each one: horizontal as a % of width, vertical in cqw so both axes track the
   artwork as the canvas scales.

   Colours are baked per theme (#CBE7B4, #E5F3D9, #7DC242, #375448 are the green
   page's). Other themes need their own exports — not recolourable via --theme.
   --------------------------------------------------------------------------- */
/* RULE (client, 2026-10-22): decorations — the daisies, leaves and hexagons —
   paint ABOVE everything else in their section: photos, gallery images, panels,
   band shapes and text. They are outline art at partial opacity, so the copy
   stays legible, and pointer-events: none keeps them out of every click. 5 sits
   under the site header (6, which shares .band-page's stacking context), the
   site-visit tab (20) and the mobile menu (50). No per-decoration z-index: the
   old inline `z` values from site.json no longer render. .m-deco follows the
   same rule in the <= 720 block. See docs/layout-rules.md section 5. */
.page-deco {
  position: absolute;
  z-index: 5;
  pointer-events: none;
  height: auto;
}

/* band-page, whose top is artboard y0 */
/* z-index 2 puts it over the photo (z-index 1), as in the artboard. */

/* band-body, whose top is artboard y925.6 */

/* 1:2258 — the gallery band's pale rim, NOT a wash behind the body. Placed in
   band-body first, it showed ~330 tall instead of the intended 111.5, because
   nothing there covers it. It belongs to the gallery band, offset -7.74cqw so
   its top sits 111.5 above the band, with the band's own shape painting over
   the remainder. Sits at z-index -1 BEFORE .band-shape (also -1), so DOM order
   puts the shape on top. Not flipped — 1:2258 has no stored transform. */
.band-rim {
  position: absolute;
  left: 0;
  top: -7.74cqw;
  width: 100%;
  height: auto;
  z-index: -1;
  pointer-events: none;
}


/* band-gallery, whose top is artboard y1712 */

.page-photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* --- Inner page body ------------------------------------------------------- */

/* overflow-x: clip contains the quote's bleeding circular wash. `clip` rather
   than `hidden` so it does not become a scroll container. Without it the blob
   (-14% left, 128% wide) escapes the column once the prose goes full-width
   below the breakpoint, and the page scrolls sideways — a pseudo-element, so
   it is invisible to any querySelectorAll-based overflow hunt. */
.band-body {
  background: var(--white);
  /* comp: band starts 926, section title at 984 */
  padding-block: 4.03cqw var(--body-pad-bottom, clamp(2rem, 5cqw, 4.5rem));
  overflow-x: clip;
}


/* comp: two lines spanning y984-1090, a 53 pitch */
.section-title {
  /* Every inner artboard puts the prose 62 below the title's LAST line, whether
     the title runs to two lines or three — so this is one constant, not a
     per-page value. The old 6.5cqw was a two-line-only figure that happened to
     land correctly by cancelling against the wrong line-height below; it broke
     as soon as a three-line title doubled that error. Kept as a variable only
     so a future artboard can differ. */
  margin: 0 0 var(--title-gap, 1.16cqw);
  font-family: var(--font-display);
  font-size: clamp(1.75rem, 2.78vw, 40px);
  font-weight: 400;
  /* Every inner artboard sets a 40 pitch on a 40px face. The previous 1.32 made
     each line 12.8 too tall, which pushed the prose, the panel, the quote and
     the gallery band down with it — masked on the two-line pages because the
     title also started ~6 high and --title-gap had been tuned to absorb the
     rest, and glaring on the three-line ones where the error doubled. */
  line-height: 1;
  color: var(--theme, var(--magenta));
}

/* comp: prose ~480 and panel 551 with a 48 gap, across the 1078 content span */
.page-cols {
  display: grid;
  grid-template-columns: minmax(0, 480fr) minmax(0, 551fr);
  gap: 4.45%;
  align-items: start;
}

.page-prose p {
  margin: 0 0 1.15em;
  font-size: var(--fs-body);
  line-height: 1.55;
}

/* The quote sits on a pale circular wash, as on the homepage testimonials.
   Drawn with a pseudo-element so it can bleed outside the text column. */
/* comp 1:2003 — the quote box is 286 wide at x233, i.e. narrower than the 480
   prose column and indented 52 from it. It was inheriting the full column at
   469 wide.

   This also corrects the wash: the ::before below is sized 150% / -24.8% of
   the QUOTE, figures taken from the comp's 429 circle at x162. Against a
   469-wide quote those percentages produced a 704 blob; against 286 they give
   429 at x162, which is exact. */
.page-quote {
  position: relative;
  max-width: 19.86cqw; /* 286 / 1440 */
  /* Indent is per page: 52 on Garden Maintenance (233-181), 69.7 on
     Landscaping (250.7-181). Set from site.json. */
  /* --quote-pull is a negative bottom margin, used where the artboard lets the
     quote hang past the end of its band (Products, into the gallery). It pulls
     the COLUMN's bottom up without moving the quote, so the band can end on the
     gallery's edge while the quote still overhangs it. */
  margin: clamp(1.5rem, 4cqw, 3rem) 0 var(--quote-pull, 0) var(--quote-indent, 3.61cqw);
  padding: clamp(1.5rem, 3cqw, 2.5rem) 0 0;
  font-size: var(--fs-body);
  font-style: italic;
  font-weight: 600;
  line-height: 1.306; /* comp 1:2003 is 188 tall over 9 lines = 20.9, not the 24 a 1.5 gives */
}

/* The real wash from Figma 1:2002 — a 429 circle at (162,1400) sitting behind
   the 286-wide quote box at (233,1496). Hence 150% of the quote's width, offset
   -24.8% horizontally and 6.67cqw up. Was a hand-rolled CSS gradient before. */
.page-quote::before {
  content: "";
  position: absolute;
  z-index: -1;
  left: -24.8%;
  /* -6.67cqw is the offset from the quote's TEXT top on Garden Maintenance, but
     it is applied from the element top, which the padding above puts ~43 higher.
     Products measures its own (1342 against an element top of 1403.5) rather
     than inherit that discrepancy. */
  top: var(--quote-blob-top, -6.67cqw);
  width: 150%;
  aspect-ratio: 1;
  /* Per page: each artboard ships its own wash, with the theme baked into its
     gradient (green -> #E5F3D9, amber -> #F4D56E). Set from the build, because
     a stylesheet cannot know the page slug. */
  background: var(--quote-blob) center / contain no-repeat;
}

.page-quote p {
  margin: 0;
  /* Set HERE, not on .page-quote: `.page-prose p` is (0,2,0) and beats the
     block-level (0,1,0) rule, so the paragraph kept the prose column's 1.55.
     comp 1:2003 is 188 tall over 9 lines = 20.9 at 16px. */
  line-height: 1.306;
}

.page-quote cite {
  display: block;
  margin-top: 1.1em;
  font-style: normal;
  font-weight: 600;
  color: var(--theme, var(--magenta));
}

/* comp: 708-1259 x 1184-1855 — a rounded themed block */
.service-panel {
  /* The panel's top relative to the prose column is per artboard: it sits level
     with the prose on Garden Maintenance and Landscaping, but ~100 higher on
     Land Management, where the comp tucks it up under the section title. */
  margin-top: var(--panel-top, 0);
  border-radius: 24px;
  background: var(--theme, var(--magenta));
  color: var(--white);
  padding: clamp(1.5rem, 3.4cqw, 3rem) clamp(1.25rem, 2.8cqw, 2.5rem);
}

.service-panel h3 {
  margin: 0 0 1.1em;
  font-family: var(--font-display);
  /* comp 1:2883 is 37px on 50 leading, not the 31 measured off a screenshot. */
  font-size: clamp(1.5rem, 2.57cqw, 37px);
  font-weight: 400;
  line-height: 1.35; /* 50 / 37 */
  color: var(--white);
}

.service-panel ul {
  margin: 0;
  padding-left: 1.15em;
  list-style: disc;
}

/* comp: the panel is 672 tall for a two-line heading plus nine bullets, which
   needs noticeably more air between items than a default list gives — it came
   out 149px short at 0.85em. */
.service-panel li {
  /* comp: 20px SemiBold on 28 leading, bullets 49.6 apart (1317.1 -> 1366.7).
     One line is 28 tall, so the gap is 21.6 = 1.08em. These were previously
     body-size and regular weight, tuned by eye off a screenshot. */
  margin-bottom: 1.08em;
  font-size: clamp(1rem, 1.39cqw, 20px);
  font-weight: 600;
  line-height: 1.4; /* 28 / 20 */
}

.service-panel li:last-child {
  margin-bottom: 0;
}

/* --- Gallery band ---------------------------------------------------------- */

/* Same treatment: the gallery band is its shape (Figma 1:1755), 871 tall on the
   1440 artboard = 60.5cqw. */
.band-gallery {
  position: relative;
  min-height: 60.49cqw;
  padding-bottom: clamp(2.5rem, 6cqw, 5rem);
}

.gallery-title {
  margin: 0 0 clamp(1.25rem, 3cqw, 2.6rem);
  padding-top: clamp(2rem, 11cqw, 10rem); /* clears the curve above it */
  font-family: var(--font-display);
  font-size: clamp(1.75rem, 3.06vw, 44px);
  font-weight: 400;
  color: var(--white);
}

/* comp: 4 columns of 228 on a 284 pitch — a 56 gap, 5.2% of the content span */
.gallery-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 4.6% 5.2%;
}

.gallery-tile {
  aspect-ratio: 1;
  background: #000;
  overflow: hidden;
}

/* Client photography (Client Docs/Service Images, 2026-09-11): eight per
   service, shipped as 600px square centre crops under assets/img/gallery/,
   i.e. 2.6x the 228 comp tile. The black stays as the loading backdrop. */
.gallery-tile img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

@media (max-width: 900px) {
  /* the 286 comp width is a two-column-layout figure; stacked, it should fill */
  .page-quote {
    max-width: none;
    margin-left: 0;
  }

  .page-cols {
    grid-template-columns: minmax(0, 1fr);
    gap: clamp(1.5rem, 5cqw, 3rem);
  }

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

@media (max-width: 900px) {
  .page-head-copy {
    max-width: none;
  }

  /* Below the layout switch the circle moves out of the copy's way rather than
     overlapping it — the mobile artboards stack these (T-015). */
  .page-photo {
    position: relative;
    left: auto;
    top: auto;
    width: min(70%, 340px);
    margin: clamp(1.5rem, 5cqw, 3rem) auto 0;
  }
}

/* --- Services band --------------------------------------------------------- */

/* Circles overlap the hero curve above and the magenta band below, exactly as
   in the comp (grid 1040-1763; hero ends 1085; magenta starts 1531). Offsets
   are in vw so the overlap scales with the artwork rather than drifting.
   z-index keeps the circles above the magenta band they hang over. */
/* Deliberately transparent: the circles overlap the hero curve above them
   (comp grid 1040 vs hero end 1085), so painting a white background here would
   cover the pale sweep they are supposed to sit on. The page background does
   the job. z-index keeps the tiles above the magenta band below. */
.band-services {
  position: relative;
  z-index: 2;
  margin-top: -3.1cqw;
  padding-bottom: 0;
}

/* The homepage pulls the circles up under the band above it. The article pages
   have no such band — the prose simply ends — so the negative margin there put
   the first row 44 high. Comp: the row-1 tile top is 1106.9, derived from its
   label at 1184.4 (a two-line label centred in a 225 tile), not read off the
   nested disc vectors, whose coordinates are in a transformed space. */
.band-article + .band-services {
  margin-top: 0;
  /* On the homepage another band follows the circles, so .band-services ships
     no bottom padding. Here the footer follows directly and the comp leaves
     106 between the second tile row and the footer's first line. */
  padding-bottom: 3.6cqw;
}

/* comp: tiles 225 wide on a 276.67 pitch across the 1055 content column, so the
   column gap is 51.67 = 4.9% of that column, and the row gap is 48.

   The two are set SEPARATELY on purpose. A shorthand `gap: 4.9%` looks right
   but silently collapses the row gap to zero: percentage row-gap resolves
   against the container's block size, which is indefinite for an auto-height
   grid. That cost 48px of grid height, which let the magenta band below ride
   up over the second row of circles. */
.services-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  column-gap: 4.9%;
  row-gap: clamp(0.75rem, 3.33vw, 48px);
  /* The grid is 1055 wide on EVERY artboard that carries it — 225 tiles on a
     276.67 pitch — but the inner pages set --wrap to 1078, which inflated the
     tiles to 230 when this moved into a shared partial. Cap it in cqw, not px:
     a pixel cap is what previously stopped the grid growing with the page. On
     the homepage --wrap is already 1055, so this is a no-op there. */
  max-width: 73.26cqw; /* 1055 / 1440 */
}
/* Client amends 2026-10-20: ten tiles leave a short last row; centre it. Four
   columns: a last row of two starts in column 2. Three columns (<= 900): a lone
   last tile sits in column 2. */
.services-grid > .service:nth-child(4n+1):nth-last-child(2) { grid-column-start: 2; }
/* A lone last tile spans columns 2-3 and sits centred at one tile's width:
   with a 4.9% gap a tile is 0.21325 of the grid and the two-column area is
   0.4755, so 0.21325 / 0.4755 = 44.85% of the area. */
.services-grid > .service:nth-child(4n+1):last-child {
  grid-column: 2 / span 2;
  justify-self: center;
  width: 44.85%;
}

/* NO max-width. Capping these at their comp pixel size stopped the grid growing
   with the page and left it 300px short, which then dragged every band below it
   out of position. The tile fills its cell and stays square. */
.service {
  position: relative;
  display: block;
  width: 100%;
  aspect-ratio: 1;
  text-decoration: none;
}

.service .disc,
.service .ring,
.service .icon {
  position: absolute;
  pointer-events: none;
}

.service .disc { inset: 0; width: 100%; height: 100%; }
.service .ring { inset: 4.4%; width: 91.1%; height: 91.1%; }

.service .icon {
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  width: 62%;
  height: auto;
}

/* Client amend 2026-09-14 (after the mobile round): the two portrait icons are
   sized by an explicit width at every viewport — plant-supply (node-1-243,
   77 x 150) at 38%, hydroseeding (node-1-283, 110 x 144) at 52%. Height stays
   auto so the artwork keeps its aspect; the attribute selector outranks the
   mobile `height: 62%` bound below, which still governs the other six. This
   supersedes ISS-028 for these two tiles. Do not fold them back to 62%. */
.service[data-service="plant-supply"] .icon { width: 38%; height: auto; }
.service[data-service="hydroseeding"] .icon { width: 52%; height: auto; }

.service .label {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  font-family: var(--font-display);
  font-size: var(--fs-tile);
  line-height: 1.1; /* was 1.35 — client 2026-10-21: tighter, more legible */
  color: var(--white);
  text-align: center;
  letter-spacing: 0.02em; /* was 0.046em; keeps "Hydroseeding" inside the ring at 29px */
}

/* --- Magenta band: testimonials + case studies ----------------------------- */

/* comp: band starts 1531, services grid ends 1538 — they abut with only a
   sliver of overlap, so this is a small nudge, not the large negative pull an
   earlier (mis-measured) grid extent suggested. */
/* Like .band-hero, the box stays 1440 so .daisy-3, .daisy-4 and .blob keep
   their percentage positions; only the gradient bleeds. */
.band-main {
  position: relative;
  z-index: 1;
  margin-top: -0.5cqw;
  padding-top: 5.5cqw; /* comp: band 1531 -> testimonials title 1610 */
  padding-bottom: 4.86cqw; /* comp: 70 from the last content to the band end (measured cases -> band; the cases row went 2026-09-11) */
}

.band-main::before {
  content: "";
  position: absolute;
  inset-block: 0;
  left: var(--bleed-inset);
  width: 100vw;
  z-index: -3;
  background: linear-gradient(270deg, #e665a2 0%, #ea068c 100%);
}

/* Height pinned to the comp's 400/1440 for the same reason as the hero
   divider — see the note there. */
.band-main .divider {
  top: 0;
  height: 27.78cqw;
}

/* ---------------------------------------------------------------------------
   Arc hairlines (source 1:32 in the hero, 1:46 in the magenta band).

   Each is a pair of ~3000px-diameter circles — a 4px #E665A2 stroke and a 1px
   white one — clipped to a 1440x810 window. That clipping is what turns two
   enormous circles into the shallow sweeps that cross the artwork.

   NOT z-index -1 like the other decorations: in the source these sit AFTER the
   hero media and after the magenta band, so they overlay them. Behind, they
   would be invisible. Content still stacks above via its own z-index.
   --------------------------------------------------------------------------- */
.arcs {
  position: absolute;
  left: 0;
  width: 100%;
  height: auto;
  pointer-events: none;
}

/* Both bleed, with height pinned to the 810 clipping window (810/1440), so the
   hairlines run edge to edge without the window growing taller than the comp. */
.band-hero .arcs {
  top: 15.97cqw; /* comp: y 230 of the 1440 artboard */
  z-index: 1;
  height: 56.25cqw;
}

.band-main .arcs {
  top: -0.36cqw; /* comp: y 1525.8, just above the band's own top at 1531 */
  z-index: 0;
  height: 56.25cqw;
}

/* Decorative daisies. Positioned in vw on BOTH axes so they track the artwork
   as it scales — a percentage of band height would drift as content reflows,
   which is the whole failure mode this rebuild exists to remove.
   comp positions, in the 1440-wide artboard space. */
.daisy { z-index: 0; }

.band-hero .daisy-1 { left: 10.66%; bottom: 5.05cqw; width: 13.05cqw; }
.band-hero .daisy-2 { left: 51.63%; bottom: 4.2cqw;  width: 7.96cqw; }
.band-main .daisy-3 { left: 64.38%; top: 18.35cqw;   width: 9.91cqw; }
.band-main .daisy-4 { left: 52.18%; top: 30.42cqw;   width: 4.31cqw; }

/* The pale radial blob behind the testimonial copy.
   comp: 807 wide (56%) at x=53 (3.7%), y=1225 — 306 above the band's own top. */
/* z-index 0, not the -1 the other decorations use: it must sit ABOVE the arc
   hairlines (source order 1:46 then 1:49) while staying below the copy. */
.band-main .blob {
  position: absolute;
  pointer-events: none;
  z-index: 0;
  top: -21.25cqw;
  left: 3.7%;
  width: 56%;
  aspect-ratio: 1;
  border-radius: 50%;
  background: linear-gradient(180deg, #fff 0%, #f5c1da 100%);
}

/* comp: the quote box is 580 wide, which is what gives it five lines. A ch-based
   cap is font-dependent and came out narrower, running to six lines and making
   the whole block 70px too tall. */
/* No padding-top: .band-main already carries the comp's 79px gap from band top
   to the "Testimonials" heading. Adding more here pushed the whole block 40px
   down and made it read as too tall. */
.testimonials {
  position: relative;
  z-index: 1;
  max-width: 580px;
}

.testimonials h2 {
  margin: 0 0 clamp(1rem, 2vw, 1.75rem);
  font-family: var(--font-display);
  font-size: var(--fs-heading);
  font-weight: 400;
  color: var(--magenta);
  letter-spacing: 0.02em;
}

.testimonial-quote {
  margin: 0;
  font-size: var(--fs-body);
  font-weight: 600;
  font-style: italic;
  line-height: 1.32;
  color: var(--black);
}

.testimonial-quote p { margin: 0; }

.testimonial-author {
  margin: clamp(1rem, 2vw, 1.5rem) 0 0;
  font-size: var(--fs-body);
  font-weight: 600;
  color: var(--magenta);
}

.pager {
  display: flex;
  gap: 7px;
  margin-top: clamp(1rem, 2vw, 1.5rem);
}

.pager button {
  width: 14px;
  height: 14px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: #cfcfcf;
  cursor: pointer;
}

.pager button[aria-current="true"] { background: #4a4a4a; }

/* --- Footer ---------------------------------------------------------------- */

/* Full bleed on every page. The box itself widens rather than a pseudo-element
   doing it: unlike the bands, the footer has no percentage-positioned children
   — > .wrap is a grid that re-centres itself against whatever width it is
   given. */
.site-footer {
  background: var(--pink-pale);
  padding-block: clamp(2rem, 4vw, 3.4rem);
  font-size: var(--fs-ui);
  color: var(--black);
  width: 100vw;
  margin-inline: var(--bleed-inset);
}

.site-footer > .wrap {
  display: grid;
  grid-template-columns: minmax(0, 1.4fr) auto auto minmax(0, 1.2fr);
  gap: clamp(1.5rem, 3vw, 3rem);
}

.footer-brand .logo {
  width: clamp(200px, 18.75vw, 270px);
  margin-bottom: clamp(2rem, 5vw, 4rem);
}

.copyright { margin: 0; line-height: 1.4; }

.footer-nav ul {
  margin: 0;
  padding: 0;
  list-style: none;
  line-height: 1.96;
}

.footer-nav a {
  color: var(--black);
  text-decoration: none;
  white-space: nowrap;
}

.footer-nav a:hover,
.footer-nav a:focus-visible { text-decoration: underline; }

.footer-utility {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: clamp(1.5rem, 3vw, 2.6rem);
}

/* Wraps because the search field is a fixed-size composite — its mic and submit
   glyphs are absolutely positioned at comp offsets, so it cannot fluidly shrink.
   At 320 it plus the social icons exceeded the content column; wrapping moves
   the icons to their own line rather than breaking the field. */
.footer-utility-top {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.6rem;
}

/* Accreditation marks share a baseline. Anchored by their bottom edges so they
   stay aligned despite differing heights — set from the top, BALI sat 10.9px low. */
.accreditations {
  display: flex;
  align-items: flex-end;
  gap: clamp(1rem, 1.7vw, 1.5rem);
}

.accreditations .jersey { width: 73.6px; height: auto; }
.accreditations .bali { width: 140px; height: auto; }

/* --- Floating site-visit CTA ------------------------------------------------
   Lives outside every band on purpose: a transformed ancestor would become its
   containing block and it would scroll away instead of floating. */
.site-visit {
  position: fixed;
  /* Pinned to the WINDOW edge. This used to track the 1440 canvas edge instead,
     via `max(0px, calc((100% - var(--design-w) * 1px) / 2))`, so it would not
     strand itself out on the white margin — but now the homepage bands bleed to
     the viewport, a tab stopping short of the edge reads as misaligned.

     Applies on every page, including the inner ones that still cap at 1440. It
     therefore sits in the white margin there. That is deliberate: it is a
     floating overlay rather than part of the canvas, and having the same
     element pin to two different edges depending on the page is worse than
     having it consistently hug the window.

     right: 0 is exact — a fixed element resolves against the initial containing
     block, which EXCLUDES the scrollbar. (100vw would include it and push the
     tab half a scrollbar width off-screen.) */
  right: 0;
  top: clamp(90px, 14vw, 200px);
  width: 58px;
  height: 264.5px;
  z-index: 20;
  text-decoration: none;
}

.site-visit .tab-fill { position: absolute; left: 0.6px; top: 0.3px; width: 56.9px; height: 263.7px; }
.site-visit .tab-ring { position: absolute; left: 0; top: 0; width: 58px; height: 264.5px; }

/* The calendar glyph is six vectors: body, header band, inner band, two binder
   rings and the date block. */
.site-visit .tab-icon { position: absolute; left: 0; top: 0; width: 58px; height: 50px; }
.site-visit .tab-icon img { position: absolute; }
.site-visit .tab-icon .cal-body   { left: 14px;   top: 12.6px; width: 30.1px; height: 27.3px; }
.site-visit .tab-icon .cal-band   { left: 14px;   top: 12.6px; width: 30.1px; height: 9.3px; }
.site-visit .tab-icon .cal-inner  { left: 14.5px; top: 13.1px; width: 28.9px; height: 8.7px; }
.site-visit .tab-icon .cal-ring-l { left: 22.3px; top: 9.8px;  width: 2.2px;  height: 7.6px; }
.site-visit .tab-icon .cal-ring-r { left: 33.5px; top: 9.8px;  width: 2.2px;  height: 7.6px; }
.site-visit .tab-icon .cal-date   { left: 16.1px; top: 21.8px; width: 25.8px; height: 15.8px; }

.site-visit .tab-label {
  position: absolute;
  left: 16px;
  top: 49.1px;
  font-size: 20px;
  line-height: 28px;
  font-weight: 700;
  color: var(--white);
  letter-spacing: -0.16px;
  white-space: nowrap;
  writing-mode: vertical-rl;
}



/* ---------------------------------------------------------------------------
   Mobile. Full layout is T-015 against artboards 01-13 of the mobile comp;
   this is the structural switch the architecture exists to make possible.
   --------------------------------------------------------------------------- */

@media (max-width: 900px) {
  .nav,
  .header-utility { display: none; }

  .burger { display: block; }

  .site-header > .wrap {
    grid-template-columns: auto 1fr;
    grid-template-areas: "logo primary";
  }

  .services-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .services-grid > .service:nth-child(4n+1):nth-last-child(2) { grid-column-start: auto; }
  .services-grid > .service:nth-child(4n+1):last-child { grid-column: auto; justify-self: stretch; width: 100%; }
  .services-grid > .service:nth-child(3n+1):last-child { grid-column-start: 2; }

  .site-footer > .wrap {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .footer-utility { align-items: flex-start; }

  .hero-intro { margin-inline: 0; max-width: none; }

  /* Desktop's fixed line breaks would strand short lines on a narrow screen;
     let the headline wrap to the available width instead. */
  .hero-headline br { display: none; }
}

@media (max-width: 560px) {
  .services-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .site-footer > .wrap { grid-template-columns: minmax(0, 1fr); }
}

/* ---------------------------------------------------------------------------
   ABOUT (artboard 2, Figma 1:821)

   Not the service template — its own layout, and the only page that stacks
   FIVE differently-themed bands: magenta header, pale-green "a word", green
   bio, magenta team. Each band ships its own export under
   assets/svg/pages/about/, as on the service pages.

   Positions are taken from the artboard. Horizontal values are a percentage of
   the 1440 canvas; vertical values are in cqw so both axes scale together.
   --------------------------------------------------------------------------- */

.about-head {
  position: relative;
  min-height: 50.85cqw; /* band 732.3 / 1440 */
  padding-bottom: clamp(2rem, 5cqw, 4rem);
}

/* The header photo is masked to a circle, 649 across at (491.8, 189). */
.about-hero {
  position: absolute;
  left: 34.15%; /* 491.8 / 1440 */
  top: 13.13cqw; /* 189 / 1440 */
  width: 45.07%; /* 649 / 1440 */
  aspect-ratio: 1;
  border-radius: 50%;
  overflow: hidden;
  z-index: 1;
}

.about-hero img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Ethos and History are the same component mirrored: a circular image with a
   themed card overlapping it, the card offset the opposite way each time. */
.about-feature {
  position: relative;
  /* The word band's two sweeps start 200 above this section's end and would
     otherwise paint over the History card (later band, own stacking context).
     In the comp the card sits on the pale rim, so this band paints above. */
  z-index: 1;
}

.about-feature .circle {
  position: absolute;
  width: 27.22%; /* 392 / 1440 */
  aspect-ratio: 1;
  border-radius: 50%;
  overflow: hidden;
  z-index: 0;
}

.about-feature .circle img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.about-card {
  position: absolute;
  width: 47.97%; /* 690.7 / 1440 */
  z-index: 1;
  color: var(--white);
}

.about-card .card-bg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: -1;
}

.about-card .card-inner {
  padding: 3.4cqw 4.1cqw 3cqw;
}

.about-card h2 {
  margin: 0 0 0.5em;
  font-family: var(--font-display);
  font-size: clamp(1.5rem, 2.57cqw, 37px);
  font-weight: 400;
  line-height: 1.35;
}

.about-card p {
  margin: 0;
  font-size: clamp(0.9rem, 1.11cqw, 16px);
  font-weight: 300;
  line-height: 1.45;
}

/* "A word from Andrew" — display heading in the left column, prose in the
   right, on the pale green band.

   Each band needs its own height and padding: the shape images are absolute
   (inset 0, z-index -1) so they take whatever height the section has, and
   without padding the sections collapsed into one another. */
.about-word,
.about-bio,
.about-team {
  position: relative;
}

/* Section spans y1473.8 -> 1834.3 (where the bio band starts): 360.5. The
   sweeps are taller than the section and start above it — see below. */
.about-word {
  /* Lifted above .about-bio so the daisy that hangs into it paints on top
     (decoration rule, docs/layout-rules.md section 5; every .band is isolated). */
  z-index: 1;
  min-height: 25.03cqw; /* 360.5 / 1440 */
  padding-block: clamp(2.5rem, 7cqw, 6rem) clamp(0.5rem, 1cqw, 1rem);
}

/* The two word sweeps at their artboard geometry, not stretched to the
   section. Pale 1:863: top y1274.5, 999.1 tall. Green 1:868: top y1386,
   887.6 tall. Offsets are from the section top at y1473.8. */
.about-word .band-shape {
  bottom: auto;
}
.about-word .word-pale {
  top: -13.84cqw; /* (1274.5 - 1473.8) / 1440 */
  height: 69.38cqw; /* 999.1 / 1440 */
}
.about-word .word-green {
  top: -6.1cqw; /* (1386 - 1473.8) / 1440 */
  height: 61.64cqw; /* 887.6 / 1440 */
}

/* Section spans y1834.3 -> 2455.8 (the team band's top): 621.5. The heading
   pair starts at y2074, the prose ends at y2401. */
.about-bio {
  min-height: 43.16cqw; /* 621.5 / 1440 */
  padding-block: clamp(2.5rem, 16.65cqw, 15rem) clamp(1rem, 1.9cqw, 2rem);
}

/* 1:873 at its true 439.5 height. It sits inside the word sweep (identical
   bottom curve), so stretching it to the section would draw a second, wrong
   crescent below the sweep. */
.about-bio .band-shape {
  bottom: auto;
  height: 30.52cqw; /* 439.5 / 1440 */
}

/* Section top is y2455.8 on the artboard. "Key Team" sits 130 below it and
   the prose a further 96 down (heading cap top y2596, prose top y2681):
   the two columns are NOT top-aligned in this band. */
.about-team {
  min-height: 65.9cqw; /* 948.9 / 1440 */
  padding-block: clamp(2.5rem, 9cqw, 8.5rem) 0;
}

/* The band shape (1:827) is 948.9 tall; the section runs on past that to
   hold the inset team photo (the comp's photo band is full-bleed black, so
   nothing shows beside it there). Keep the shape at its true height so its
   top curve is not stretched, and continue its ramp underneath with a
   pseudo-element that bleeds like the shape does (a plain background on the
   section stops at the 1440 canvas and leaves white notches beside the photo
   on wide screens). The export's gradient evaluated at x0 and x1440 is
   #e82994 -> #e7559e. */
.about-team .band-shape {
  bottom: auto;
  height: 65.9cqw;
}
.about-team::after {
  content: "";
  position: absolute;
  top: 65.9cqw;
  bottom: 0;
  z-index: -1;
  background: linear-gradient(90deg, #e82994, #e7559e);
  pointer-events: none;
}
.about-team .prose {
  margin-top: 6.67cqw; /* 96 / 1440 */
}

/* The two hairline arcs (1:2258-style rim) are drawn OVER the magenta in the
   comp — a 4px pink and a 1px white — so unlike the gallery rim this one
   paints above the band shape. Still below the copy (.wrap is positioned
   later in the DOM). */
.about-team .band-rim {
  z-index: 0;
  /* The file's viewBox is 3440 wide (1000 beyond the artboard each side) so
     the arcs run on past the 1440 cap on wide screens as true circles. Place
     it so the artboard's x0 lands on the band's x0. */
  left: -69.44%; /* -1000 / 1440 */
  width: 238.89%; /* 3440 / 1440 */
  max-width: none; /* or the global img reset clamps it straight back to 100% */
}

.about-split {
  display: grid;
  /* Heading column ends at artboard x420 (240 past the wrap's left edge at 180).
     The wrap is 1078 wide on inner pages, so that 240 is 22.26% OF THE WRAP, not
     16.67% of 1440 — the earlier value resolved against 1078 and started the prose
     ~60px too far left, which slid the bio prose under the portrait. */
  grid-template-columns: 22.26% 1fr;
  gap: 0;
  align-items: start;
}

/* The "A word from Andrew" prose is 709.9 wide on the artboard. Without the cap
   it ran the full column. The bio and team bands narrow it further below. */
.about-split .prose {
  max-width: 49.3cqw;
}

/* Bio prose sits LEFT of the portrait circle (at 61.05% / x879); cap it so it
   clears the circle instead of sliding under it. 448 wide on the artboard. */
.about-bio .prose {
  max-width: 31cqw; /* 448 / 1440 */
}

/* The Key Team band is magenta: heading and prose are WHITE in the comp (they
   rendered dark), and the prose is a narrower column than the word band's. */
.about-team .about-split h2,
.about-team .prose {
  color: #fff;
}
.about-team .prose {
  max-width: 38cqw; /* 547 / 1440 */
}

.about-split h2 {
  margin: 0;
  font-family: var(--font-display);
  font-size: clamp(1.75rem, 3.06cqw, 44px);
  font-weight: 400;
  line-height: 1.2;
  color: var(--theme, var(--plum));
}

.about-split .prose p {
  margin: 0 0 1.15em;
  font-size: clamp(0.9rem, 1.11cqw, 16px);
  font-weight: 300;
  line-height: 1.45;
}

.about-split .prose p:last-child {
  margin-bottom: 0;
}

/* On the green sweep the copy is WHITE: heading at 38px with a tight 40px
   pitch (three lines over 107 on the artboard), prose 16px semibold on a
   20.75 pitch, and the sign-off in the brand yellow. */
.about-word .about-split h2 {
  color: #fff;
  font-size: clamp(1.6rem, 2.64cqw, 38px);
  line-height: 1.05;
}
.about-word .prose {
  color: #fff;
}
.about-word .about-split .prose p {
  font-weight: 600;
  line-height: 1.3; /* 20.75 pitch over nine lines on the artboard */
}
.about-word .prose strong {
  color: #f1c840;
  font-weight: 600;
}

/* Name and role are two lines of the same display setting in the comp, both
   the dark end of the green ramp. */
.about-bio .prose h3,
.about-bio .prose .role {
  font-family: var(--font-display);
  font-size: clamp(1.5rem, 2.57cqw, 37px);
  font-weight: 400;
  line-height: 1.2;
  color: #607e47;
}

.about-bio .prose h3 {
  margin: 0;
}

.about-bio .prose .role {
  display: block;
  margin-bottom: 0.5em;
}

/* Bio prose runs on a 20.75 pitch with a ~20px paragraph gap on the artboard
   (lines at y2182 … 2401); the team prose on a 22 pitch. */
.about-bio .about-split .prose p {
  line-height: 1.3;
  margin-bottom: 1.25em;
}
.about-team .about-split .prose p {
  line-height: 1.375;
}

/* The bio portrait, 400 across at (879.1, 1823.3) — 10.7 ABOVE the band it
   sits on, so it overlaps the band edge as the gallery decorations do. */
.about-portrait {
  position: absolute;
  left: 61.05%; /* 879.1 / 1440 */
  top: -0.74cqw; /* 1823.3 - 1834.3 */
  width: 27.78%; /* 400 / 1440 */
  aspect-ratio: 1;
  border-radius: 50%;
  overflow: hidden;
  z-index: 0; /* behind the prose, which overlaps it in the comp */
}

.about-portrait img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* The comp's photo band (1:1172) starts 444 below the team band's top, which
   puts the outline daisy (1:1294) across the photo's top edge rather than
   inside it. The 90% width is the client's call (2026-09-10); the top edge
   follows the artboard. */
.about-team-photo {
  display: block;
  width: 90%;
  height: auto;
  margin-top: clamp(1.5rem, 4.8cqw, 4.5rem);
  margin-inline: auto;
}

@media (max-width: 900px) {
  .about-hero,
  .about-portrait {
    position: static;
    width: min(80%, 420px);
    margin: 1.5rem auto;
  }
  .about-feature .circle {
    position: static;
    width: min(70%, 340px);
    margin: 0 auto 1rem;
  }
  .about-card {
    position: static;
    width: 100%;
  }
  .about-split {
    grid-template-columns: 1fr;
    gap: 1rem;
  }
  /* Stacked single column — drop the desktop caps that keep prose clear of the
     portrait/curve, or the text would be needlessly narrow on small screens. */
  .about-split .prose,
  .about-bio .prose,
  .about-team .prose {
    max-width: none;
  }
  /* Stacked, the sections grow with their copy and the sweeps' curves no
     longer fit: stretched, the green's rising bottom edge left white copy
     running onto white, and the bio crescent became a diagonal swoosh across
     the (same-coloured) name. So: a flat ramp behind the word band, no pale
     rim, no crescent (it is invisible inside the sweep on the artboard too). */
  .about-word {
    background: linear-gradient(90deg, #607e47, #7dc242);
  }
  .about-word .band-shape,
  .about-bio .band-shape,
  .about-word .page-deco {
    display: none;
  }
  .about-bio {
    padding-block: 2.5rem 2rem;
  }
  .about-team .prose {
    margin-top: 0;
  }
  .about-team-photo {
    margin-top: 1.5rem;
  }
}

/* ---------------------------------------------------------------------------
   LEGAL PAGES (privacy statement / privacy policy)

   Same shell as the inner pages but a much shorter header band — 485.6 against
   925.6 — no header photo, and long-form prose across the full content column.
   --------------------------------------------------------------------------- */

.band-legal {
  position: relative;
  z-index: 1;
  min-height: 33.72cqw; /* 485.6 / 1440 */
  padding-bottom: clamp(1.5rem, 4cqw, 3rem);
}

.legal-body {
  position: relative;
  /* Top padding puts the first line at the artboard's 604.1. The band ends at
     486 and the pale underlay runs to 555, so the previous 5cqw started the text
     at 550 — on top of the wash rather than clear of it. */
  padding-block: clamp(2.5rem, 8.2cqw, 7.4rem) clamp(2.5rem, 6cqw, 5rem);
}

.legal-body h2 {
  margin: 2em 0 0.6em;
  font-family: var(--font-display);
  font-size: clamp(1.25rem, 1.94cqw, 28px);
  font-weight: 400;
  line-height: 1.3;
  color: var(--theme, var(--plum));
}

.legal-body h2:first-child {
  margin-top: 0;
}

.legal-body p,
.legal-body li {
  font-size: clamp(0.875rem, 0.97cqw, 14px);
  font-weight: 300;
  line-height: 1.6;
}

.legal-body p {
  margin: 0 0 1em;
}

/* The artboards set bold runs in Open Sans Bold. This has to be an explicit 700
   and not the UA default: <strong> is `font-weight: bolder`, which is RELATIVE,
   and the body copy above is 300 — so bolder resolves to 400, one step up, and
   the run renders all but identically to its surroundings. */
.legal-body strong {
  font-weight: 700;
}

.legal-body ul {
  margin: 0 0 1.4em;
  padding-left: 1.4em;
}

.legal-body li {
  margin-bottom: 0.35em;
}

.legal-body .lead {
  margin-bottom: 0.8em;
}

/* --- search results (T-071): the legal column, a list of eyebrow / link / snippet --- */
/* The status echoes the visitor's query; a long unbroken string must wrap
   rather than widen the column. */
.search-results .search-status { margin: 0 0 1.2em; overflow-wrap: anywhere; }
.search-list { list-style: none; margin: 0; padding: 0; }
.search-list li { padding: 1.1cqw 0; border-top: 1px solid var(--theme-pale, #f5c1da); }
.search-list li:first-child { border-top: 0; }
.search-list .eyebrow { display: block; font-size: clamp(0.7rem, 0.8cqw, 12px); font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--theme, #ea068c); }
.search-list a { font-family: var(--font-display); font-size: clamp(1.1rem, 1.6cqw, 23px); font-weight: 400; color: var(--theme, #ea068c); text-decoration: none; }
.search-list a:hover, .search-list a:focus-visible { text-decoration: underline; }
.search-list .snippet { margin: 0.3em 0 0; }
.search-list mark { background: var(--theme-pale, #f5c1da); color: inherit; padding: 0 0.1em; }

/* MOBILE, the whole legal shell (<= 720) — the three legal pages, /search/ and
   /pay-invoice/. There is no mobile artboard for these pages, so unlike the
   service and About headers there is no `-m` art to swap in: the desktop band
   art stays and the band itself is re-proportioned.

   T-080, client amend 2026-09-14 — "the pink header needs to be larger to
   provide proper background to the title". The desktop band is 33.72cqw and the
   header bar above the title does NOT scale with the container (91.5px, the
   200px logo of T-077), so at 360 the title landed at y120-190 inside a
   178.9-213.9 band whose shape has a RISING bottom edge: at the title's right
   end the pink stops at 0.78-0.93 of the band's height, i.e. above the text.
   "Privacy Policy" and "Statement" both ran off the pink onto white.

   Doubling the band to 67.44cqw is the whole fix. .band-shape is `height: 100%`
   so the sweep stretches with it (preserveAspectRatio="none" on every one of
   these exports), and the underlay and arcs are pinned in cqw by theme.ts, so
   they have to be doubled by hand or they stay registered to the old 485.6 and
   the pale rim disappears under the pink. Doubled, the three keep exactly their
   desktop relationship and the title clears the curve by 8.1-8.4cqw at 360 —
   the same clearance the 1440 artboard gives it.

   The floral is deliberately NOT doubled: it is a fixed 43.451cqw window on
   every page and the only representational art in the band, so stretching it 2x
   would visibly egg-shape the daisies. It hangs off the top-right either way. */
@media (max-width: 720px) {
  .band-legal {
    min-height: 67.44cqw; /* 2 x the desktop 33.72 */
  }
  /* x2 of the build-emitted heights, NOT the literals they currently hold
     (38.539cqw = 554.966/14.4 and 33.333cqw = 480/14.4 for the legal set):
     read through the variables so a re-export of the art, or a page that grows
     its own asset dir and stops falling back to `legal` in theme.ts, keeps
     mobile in step with the shape instead of silently drifting. Were either
     variable ever undefined there is no fallback inside the calc(): the
     declaration is invalid at computed-value time, and `height` — not
     inherited — reverts to its initial `auto`. That is the same `auto` the
     desktop rules name explicitly as their var() fallback, so the art degrades
     to its intrinsic height rather than collapsing. */
  .band-legal .band-underlay { height: calc(var(--underlay-h) * 2); }
  .band-legal .band-arcs { height: calc(var(--arcs-h) * 2); }

  /* The underlay is 1.1429 x the band, so it overhangs it by 9.638cqw (2 x
     38.539 - 67.44) and the pale wash lands inside .legal-body's top padding.
     That padding is clamp(2.5rem, 8.2cqw, 7.4rem) — FLAT at 40px below 488px
     wide, so the overhang caught up with it: +5.3px of clearance at 360, +0.1
     at 414, negative past ~415, and by 720 the wash was clipping the ascenders
     of the first line on all five pages. 12cqw scales with the overhang instead
     of flattening out, and leaves 12 - 9.638 = 2.362cqw between the wash and
     the first line at every width — 7.6px at 320, 17.0px at 720. */
  .legal-body { padding-top: 12cqw; }

  .search-list li { padding: 3cqw 0; }
  .search-list a { font-size: clamp(14px, 4.4cqw, 32px); }
  .search-list .eyebrow { font-size: clamp(9px, 2.7cqw, 19px); }
}

/* ---------------------------------------------------------------------------
   TIPS & ADVICE (index: Figma 67:4, article: 67:644)

   Replaces the old NEWS & TIPS artboard 11, whose nine cards were placeholder
   copy. The new set is an INDEX plus per-article detail pages.

   Index: header band 587.8, a filter pill row, then a 2 x 2 card grid. Cards
   are 515 x 420 on a 565 horizontal pitch (180 / 745) and a 462.8 vertical one
   (705.3 / 1168.1), radius 29.9.

   The card fills are four horizontal gradients. They are NOT exported as SVG:
   unlike the header bands, nothing is clipped to a curve here, so a CSS
   linear-gradient over a rounded box is exact and saves four files.

   Every card's photo sits at the SAME place — 222.6 across, at (222.6, -23)
   from the card's top-left, so it straddles the top edge. That was worth
   checking rather than assuming: the four masks arrive at wildly different
   absolute coordinates because each is nested in its own transformed group.

   The pills are drawn as buttons rather than exported as fill/stroke pairs:
   they are plain rounded rectangles, and they need to be real controls for the
   filtering to work at all.
   --------------------------------------------------------------------------- */

.band-tips {
  position: relative;
  z-index: 1;
  min-height: 40.82cqw; /* 587.8 / 1440 */
  padding-bottom: clamp(1.5rem, 4cqw, 3rem);
}

.tips-filter {
  display: flex;
  align-items: baseline;
  /* comp: FILTER: label at (183.2, 406.8), pills start at x255 and every wrapped
     row aligns back to 255 — so the pills are their own block, not siblings of
     the label in one wrap flow. */
  gap: 0.69cqw; /* 255 - 245.2, the label's right edge to the first pill */
  margin-top: 5.49cqw; /* 406.8 - 327.7, measured from the h1's line box */
  position: relative;
  z-index: 2;
}

.tips-filter .pills {
  display: flex;
  flex-wrap: wrap;
  gap: 0.382cqw 0.59cqw; /* row pitch 41.5 over a 36 pill; 8.5 between pills */
  /* Both are required. As a flex item this block sizes to max-content and
     overhangs the column — flex-wrap inside does nothing, because there is no
     constraint to wrap AGAINST. min-width:0 defeats the auto minimum. */
  flex: 1;
  min-width: 0;
  /* The comp's pill rows end at 941 / 959.6 / 679.5, i.e. the block is ~705
     wide and stops well short of the 1259 column edge — the pills keep clear
     of the band's descending curve on the right. Without this they wrap purely
     on the column and the rows come out four pills long instead of the comp's
     4 / 4 / 2. */
  max-width: 48.96cqw; /* 705 / 1440 */
}

/* NOT --fs-ui. That token is the 12px nav/footer size, and reusing it here
   made every pill about a quarter too narrow, so seven fitted on the first row
   where the comp fits four. Measured off the artboard text boxes: the label is
   18 (w62, h25) and the pills 16 (SHOW ALL w81, GARDEN MAINTENANCE w186). */
.tips-filter .filter-label {
  font-size: clamp(0.875rem, 1.25cqw, 18px);
  font-weight: 700;
  letter-spacing: 0.09px;
  color: var(--white);
}

.tips-filter button {
  /* 36 tall on a 16px face: 22.4 line + 2 x 6.8. 0.94em horizontal is the
     comp's 111-wide SHOW ALL pill around 81 of text. */
  padding: 0.42em 0.94em;
  font: inherit;
  font-size: clamp(0.8rem, 1.111cqw, 16px);
  line-height: 1.4;
  color: var(--white);
  background: transparent;
  border: 1px solid var(--white);
  border-radius: 999px;
  cursor: pointer;
  white-space: nowrap;
}

.tips-filter button:hover,
.tips-filter button:focus-visible {
  background: rgb(255 255 255 / 15%);
}

.tips-filter button[aria-pressed="true"] {
  background: var(--white);
  color: var(--theme, var(--plum));
  font-weight: 600;
}

/* ---- index card grid ---------------------------------------------------- */

.tips-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  column-gap: 3.472cqw; /* 50  / 1440 */
  row-gap: 2.972cqw;    /* 42.8 / 1440 — a LENGTH, not a percentage: percentage
                           row-gap resolves against an indefinite block size on
                           an auto-height grid and silently computes to zero. */
  /* 705.3 - 587.8: the band's min-height fixes where this section starts, so
     the first card row is placed from here, not from the filter's flow. */
  padding-block: clamp(2rem, 8.16cqw, 117.5px) clamp(1.5rem, 3.86cqw, 55.6px);
}

.tips-card {
  position: relative;
  display: flex;
  flex-direction: column;
  aspect-ratio: 515 / 420;
  padding: 36.3% 5.83% 0; /* 187.1 / 515 down to the label; 30 / 515 in */
  border-radius: 2.076cqw; /* 29.9 / 1440 */
  background: var(--card-grad);
  color: var(--white);
}

/* Faint line-art behind the copy — a leaf on card 1, daisies on 2 and 3,
   hexagons on 4. Not a shared decoration: each is a different drawing at its
   own offset and size, so all three values come from the card, not the sheet.
   Opacity is baked into the exports (0.15 / 0.25), so none is set here. */
.tips-card .deco {
  position: absolute;
  left: var(--deco-x);
  top: var(--deco-y);
  width: var(--deco-w);
  height: auto;
  pointer-events: none;
  /* MUST override the shared .deco, which sets z-index:-1 so header decorations
     sit behind their band's content. .tips-card paints its own background, and
     a negative z-index child goes behind THAT — the art loaded, measured and
     positioned correctly, and was invisible. Nothing here creates a stacking
     context, so 0 is enough to put it back in flow order, above the gradient
     and below the photo. */
  z-index: 0;
}

/* The photo overhangs the card's top edge, so the card must not clip it. Each
   card therefore paints in DOM order; the grid gap is wider than the overhang
   so no circle reaches the card above it. */
.tips-card .photo {
  position: absolute;
  left: 43.22%;  /* 222.6 / 515 */
  top: -5.48%;   /* -23   / 420 */
  width: 43.22%;
  aspect-ratio: 1;
  border-radius: 50%;
  overflow: hidden;
}

.tips-card .photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Sampled per card off the artboard, because it is NOT one value: white on
   card 1, then each card's own light gradient stop (#7DC242, #00CAFF) and a
   pale pink on card 4. Set beside --card-grad on the article. */
.tips-card .num {
  margin: 0 0 0.3em;
  color: var(--num-color, #f5f5f5);
  font-size: clamp(0.8rem, 1.111cqw, 16px);
  font-weight: 700;
  line-height: 1.375; /* 22 / 16 */
  letter-spacing: 0.1em;
}

.tips-card h2 {
  margin: 0;
  max-width: 84%; /* 432 / 515 — the comp's title box, clear of the circle */
  font-size: clamp(1.05rem, 1.868cqw, 26.9px);
  font-weight: 300; /* Open Sans LIGHT — the card titles are not the display face */
  line-height: 1.487; /* 39.99 / 26.9 — the inner span's leading, not the
                        outer box's 38, which is only the first line. */
}

/* Not a pill: the comp puts a 25 ring-and-ellipsis glyph at x210 — the card's
   own left padding — with the label 33.4 to its right. An enclosing border was
   the first guess off a thumbnail and is not in the artboard. */
.tips-card .read-more {
  display: inline-flex;
  align-items: center;
  gap: 0.58cqw; /* 243.4 - 235, the ring's right edge to the label */
  margin-top: auto;
  margin-bottom: 9.5%; /* 40 / 420 */
  align-self: flex-start;
  font-size: clamp(0.85rem, 1.25cqw, 18px);
  font-weight: 600;
  line-height: 1.389; /* 25 / 18 */
  color: #f5f5f5;
  text-decoration: none;
}

.tips-card .read-more img {
  width: 1.736cqw; /* 25 / 1440 */
  max-width: 25px;
  height: auto;
  flex: none;
}

.tips-card .read-more:hover,
.tips-card .read-more:focus-visible {
  text-decoration: underline;
  text-underline-offset: 0.25em;
}

/* Carousel dots. Static numerals in the comp — there is no second page of
   cards yet, so they are rendered as a list and not wired to anything. */
.tips-dots {
  display: flex;
  justify-content: center;
  gap: 2.2cqw;
  margin: 0;
  padding: 0 0 clamp(2rem, 5cqw, 4rem);
  list-style: none;
}

.tips-dots li {
  width: 1.7em;
  height: 1.7em;
  display: grid;
  place-items: center;
  font-size: clamp(0.85rem, 1.25cqw, 18px);
  font-weight: 600;
  line-height: 1;
  color: var(--theme-light, var(--theme));
  border: 1px solid var(--theme-light, var(--theme));
  border-radius: 50%;
}

.tips-dots li[data-current="true"] {
  color: var(--white);
  background: var(--theme-light, var(--theme));
}

/* ---- article detail ------------------------------------------------------ */

/* The article's header band is 467.8, well short of the 925.6 that .band-page
   sets for the service pages. Without this the whole article lands ~545 low.

   The two band heights are declared here rather than emitted by the build.
   Everywhere else the build reads them out of the page's own band-underlay.svg
   and arcs-header.svg, so a hand-copied number cannot go stale — but these
   articles have no per-page files to read: the artwork is inline and shared, so
   the geometry is fixed for the whole template and this IS its one source. */
.band-page.band-article-head {
  min-height: 32.49cqw;   /* 467.8   / 1440 */
  --underlay-h: 37.305cqw; /* 537.189 / 1440 */
  --arcs-h: 32.097cqw;     /* 462.2   / 1440 */
}

.band-article {
  position: relative;
  /* MUST outrank the header band. .band-page carries z-index:1 and its pale
     underlay hangs 537 down, well past the band itself — with z-index auto
     here, that underlay painted straight over the back link and it vanished.
     An earlier sibling with a higher z-index wins regardless of DOM order. */
  z-index: 2;
  padding-top: 1.354cqw; /* 487.3 - 467.8, to the back link's ring */
  padding-bottom: clamp(2rem, 5cqw, 4rem);
}

/* Not a filled pill — same construction as the cards' READ MORE: a 25 ring
   with an arrow (67:795 + 67:797) at x180, then the label at 213.4. Both are
   the theme colour, so the asset lives in the article's own directory. */
.tips-back {
  display: inline-flex;
  align-items: center;
  gap: 0.583cqw; /* 213.4 - 205, the ring's right edge to the label */
  margin-top: 0;
  font-size: clamp(0.8rem, 1.111cqw, 16px);
  font-weight: 600;
  letter-spacing: 0.05em;
  color: var(--theme);
  text-decoration: none;
}

.tips-back .back-glyph {
  width: 1.736cqw; /* 25 / 1440 */
  max-width: 25px;
  height: auto;
  flex: none;
}

.tips-back:hover,
.tips-back:focus-visible {
  text-decoration: underline;
  text-underline-offset: 0.25em;
}

/* comp 67:648 — a 327 leaf at (698.4, 845.1), tucked under the photo. Percent
   of the band, which spans the full 1440 canvas. */
.article-leaf {
  position: absolute;
  left: 48.5%;   /* 698.4 / 1440 */
  top: 26.2cqw;  /* 845.1 - 467.8, from the top of this band */
  width: 22.71%; /* 327 / 1440 */
  height: auto;
  z-index: 0;
  pointer-events: none;
}

.article-body {
  display: grid;
  grid-template-columns: 41.67cqw 1fr; /* 600 / 1440 prose, photo in the rest */
  column-gap: 3.74cqw; /* 834.9 - 781, so the photo lands on its comp x */
  align-items: start;
  padding-top: 4.94cqw; /* 589.2 - 517, the back link box to the label */
}

/* Open Sans Bold 16/22 in #58585a — a dark grey, NOT the theme colour. The
   reference code reports #edac3c on this node, but that belongs to the title
   beside it; the label's own tag carries #58585a. */
.article-num {
  margin: 0;
  font-size: clamp(0.8rem, 1.111cqw, 16px);
  font-weight: 700;
  line-height: 1.375; /* 22 / 16 */
  letter-spacing: 0.1em;
  color: #58585a;
}

.article-title {
  margin: 0.2em 0 0;
  font-size: clamp(1.5rem, 2.493cqw, 35.9px);
  font-weight: 300; /* Open Sans Light, as on the cards */
  line-height: 1.114; /* 40 / 35.9 — the inner span's leading; the 50 on the
                        outer node is the first line's box, not the pitch. */
  color: var(--theme);
}

/* No margin: the title's own line box already ends at the comp's 717.8, where
   the first paragraph starts. A margin here pushed the prose 35 low — the
   Figma text box (85) is tighter than the CSS line box (100) for the same two
   lines, so the box heights are not comparable, only the flow positions. */
.article-prose {
  margin-top: 1.375cqw; /* 717.8 - 698, the title's two 40 lines from 618 */
}

.article-prose p {
  margin: 0 0 1.3em;
  font-size: clamp(0.875rem, 1.111cqw, 16px);
  font-weight: 300;
  line-height: 1.375; /* 22 / 16 */
}

.article-prose ul {
  margin: 0 0 1.3em;
  padding-left: 1.1em;
}

.article-prose li {
  font-size: clamp(0.875rem, 1.111cqw, 16px);
  font-weight: 300;
  line-height: 1.375;
}

/* comp: a 430 circle at (834.9, 541.6) — it rides up level with the back pill,
   well above the prose it sits beside. */
.article-photo {
  width: 29.86cqw; /* 430 / 1440 */
  aspect-ratio: 1;
  margin-top: -3.31cqw; /* 541.6 - 589.2 */
  border-radius: 50%;
  overflow: hidden;
}

.article-photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

@media (max-width: 900px) {
  .tips-grid { grid-template-columns: 1fr; }
  .tips-card { aspect-ratio: auto; padding-top: 30%; padding-bottom: 2rem; }
  .article-body { grid-template-columns: 1fr; }
  .article-photo { order: -1; width: min(60%, 320px); margin: 0 0 1.5rem; }
}

/* ---------------------------------------------------------------------------
   CONTACT (artboard 12, Figma 1:7524)

   Header band 735.6. Form at x180 width 525 beside the "Where to find us"
   panel (713.8 x 1071.2 at 726.2, 724.5).

   FIELD TREATMENT, taken from the exported vectors rather than guessed:
     text fields   1px #EA068C outline, TRANSPARENT (1:7843 etc is a ring path,
                   not a fill) — and the label sits INSIDE the box, bold, with
                   any placeholder following it in grey
     dropdown rows solid #E665A2 (1:7937, 1:7939)
     submit        solid #F1C040 amber (1:7870), not the page magenta
   An earlier pass had these as grey boxes with labels above, which was
   invented rather than measured.
   --------------------------------------------------------------------------- */

.band-contact {
  position: relative;
  z-index: 1;
  min-height: 51.08cqw; /* 735.6 / 1440 */
  padding-bottom: clamp(1.5rem, 4cqw, 3rem);
}

.contact-body {
  position: relative;
  min-height: 74.38cqw; /* the panel is 1071.1 tall and drives this section */
}

/* The form keeps the left half of the content column; the panel is positioned
   against the SECTION, not this grid, because it overhangs the column. */
.contact-cols {
  padding-block: clamp(2rem, 5cqw, 4rem) clamp(2.5rem, 6cqw, 5rem);
}

.contact-form,
.pay-form {
  width: 48.7%; /* 525 of the 1078 content column */
}

.contact-form,
.pay-form,
.find-us {
  min-width: 0;
}

.contact-form h2,
.pay-form h2,
.find-us h2 {
  margin: 0 0 1em;
  font-family: var(--font-display);
  font-size: clamp(1.375rem, 2.57cqw, 37px);
  font-weight: 400;
  line-height: 1.25;
  color: var(--theme, var(--plum));
}

/* --- fields: the box IS the border, the label lives inside it --------------- */

.field {
  display: flex;
  align-items: center;
  gap: 0.4em;
  min-height: 2.08cqw; /* 30 / 1440 */
  margin-bottom: 0.69cqw; /* 40 pitch - 30 height */
  padding: 0.3em 0.7em;
  border: 1px solid #ea068c;
}

.field > label {
  font-size: clamp(0.8rem, 0.9cqw, 13px);
  font-weight: 700;
  white-space: nowrap;
}

.field .optional,
.field .hint {
  font-size: clamp(0.8rem, 0.9cqw, 13px);
  font-weight: 300;
  color: #8a8a8a;
}

.field input:not([type="checkbox"]):not([type="radio"]),
.field textarea {
  flex: 1;
  min-width: 0;
  padding: 0;
  font: inherit;
  font-size: clamp(0.8rem, 0.9cqw, 13px);
  font-weight: 300;
  color: var(--black);
  background: transparent;
  border: 0;
}

.field input::placeholder,
.field textarea::placeholder {
  color: #8a8a8a;
}

.field input:focus-visible,
.field textarea:focus-visible {
  outline: 2px solid #ea068c;
  outline-offset: 3px;
}

/* T-083: Ideal Postcodes Address Finder. The widget wraps #address-lookup in
   div.idpc_autocomplete and hangs its list (div.idpc_af) off it, absolutely
   positioned, so nothing below moves. The wrapper takes the input's flex slot;
   the list is drawn like the comp's open dropdown: magenta ring, #E665A2 rows.
   Selectors carry .contact-form so they beat the style the widget injects. */
.contact-form .field:has(> .idpc_autocomplete) {
  position: relative;
}

/* The widget makes its wrapper the positioning context, which would hang the
   list off the input's left edge, after the label. Static here so the list is
   positioned against the whole field box and lines up with its ring. */
.contact-form .field > .idpc_autocomplete {
  position: static;
  flex: 1;
  min-width: 0;
}

.field .idpc_autocomplete > input {
  width: 100%;
}

.contact-form .idpc_af {
  top: calc(100% + 0.3em);
  left: -1px;
  right: -1px;
  min-width: 0;
  padding: 0;
  font: inherit;
  font-size: clamp(0.8rem, 0.9cqw, 13px);
  font-weight: 300;
  color: var(--black);
  background: #fff;
  border: 1px solid #ea068c;
  border-radius: 0;
  box-shadow: 0 0.4em 1em rgba(0, 0, 0, 0.12);
}

.contact-form .idpc_af > ul {
  margin: 0;
  padding: 0;
  list-style: none;
}

.contact-form .idpc_af > ul > li {
  padding: 0.45em 0.7em;
  cursor: pointer;
}

.contact-form .idpc_af > ul > li:hover,
.contact-form .idpc_af > ul > li[aria-selected="true"] {
  background: #e665a2;
  color: #fff;
}

.contact-form .idpc_af .idpc_error {
  padding: 0.45em 0.7em;
  color: #8a8a8a;
  background: transparent;
}

/* T-085: the what3words component wraps #what3words. It takes the input's flex
   slot; its suggestion list is absolutely positioned by the component. Item
   classes per developer.what3words.com (no shadow DOM), restyled to the form. */
.contact-form .field > what3words-autosuggest {
  display: block;
  flex: 1;
  min-width: 0;
}

.contact-form .field what3words-autosuggest input {
  width: 100%;
}

/* The component's own wrapper is the positioning context for its list, which
   would hang it off the input after the label. Static, and the field relative,
   so the list lines up with the field ring like the address finder's. The
   component ships its rules as long child chains, so these chains are one step
   longer to win on specificity without !important. Highlight classes are the
   component's own: .match for the exact match, .active for the keyboard cursor. */
.contact-form .field:has(> what3words-autosuggest) {
  position: relative;
}

.contact-form what3words-autosuggest > .what3words-autosuggest {
  position: static;
}

.contact-form what3words-autosuggest > .what3words-autosuggest > .what3words-autosuggest-suggestions > .what3words-autosuggest-items {
  top: calc(100% + 0.3em);
  left: -1px;
  right: -1px;
  width: auto !important; /* the component writes the input's width inline */
  font-size: clamp(0.8rem, 0.9cqw, 13px);
  background: #fff;
  border: 1px solid #ea068c;
  border-bottom-color: #ea068c;
  filter: none;
  box-shadow: 0 0.4em 1em rgba(0, 0, 0, 0.12);
}

.contact-form what3words-autosuggest > .what3words-autosuggest > .what3words-autosuggest-suggestions > .what3words-autosuggest-items > .what3words-autosuggest-item {
  padding: 0.45em 0.7em;
  box-shadow: none;
  background: #fff;
}

.contact-form what3words-autosuggest > .what3words-autosuggest > .what3words-autosuggest-suggestions > .what3words-autosuggest-items > .what3words-autosuggest-item > .what3words-autosuggest-address {
  height: auto;
  font-size: inherit;
  font-weight: 400;
  line-height: 1.4;
  color: var(--black);
}

.contact-form what3words-autosuggest > .what3words-autosuggest > .what3words-autosuggest-suggestions > .what3words-autosuggest-items > .what3words-autosuggest-item > .what3words-autosuggest-nearest-place > .what3words-autosuggest-nearest-place-text > div:first-child {
  font-size: 0.9em;
  line-height: 1.4;
  color: #8a8a8a;
}

.contact-form what3words-autosuggest > .what3words-autosuggest > .what3words-autosuggest-suggestions > .what3words-autosuggest-items > .what3words-autosuggest-item:hover,
.contact-form what3words-autosuggest > .what3words-autosuggest > .what3words-autosuggest-suggestions > .what3words-autosuggest-items > .what3words-autosuggest-item.match,
.contact-form what3words-autosuggest > .what3words-autosuggest > .what3words-autosuggest-suggestions > .what3words-autosuggest-items > .what3words-autosuggest-item.active,
.contact-form what3words-autosuggest > .what3words-autosuggest > .what3words-autosuggest-suggestions > .what3words-autosuggest-items > .what3words-autosuggest-item:active {
  background: #e665a2;
  box-shadow: none;
  filter: none;
}

.contact-form what3words-autosuggest > .what3words-autosuggest > .what3words-autosuggest-suggestions > .what3words-autosuggest-items > .what3words-autosuggest-item:hover > .what3words-autosuggest-address,
.contact-form what3words-autosuggest > .what3words-autosuggest > .what3words-autosuggest-suggestions > .what3words-autosuggest-items > .what3words-autosuggest-item.match > .what3words-autosuggest-address,
.contact-form what3words-autosuggest > .what3words-autosuggest > .what3words-autosuggest-suggestions > .what3words-autosuggest-items > .what3words-autosuggest-item.active > .what3words-autosuggest-address,
.contact-form what3words-autosuggest > .what3words-autosuggest > .what3words-autosuggest-suggestions > .what3words-autosuggest-items > .what3words-autosuggest-item:hover > .what3words-autosuggest-nearest-place > .what3words-autosuggest-nearest-place-text > div:first-child,
.contact-form what3words-autosuggest > .what3words-autosuggest > .what3words-autosuggest-suggestions > .what3words-autosuggest-items > .what3words-autosuggest-item.match > .what3words-autosuggest-nearest-place > .what3words-autosuggest-nearest-place-text > div:first-child,
.contact-form what3words-autosuggest > .what3words-autosuggest > .what3words-autosuggest-suggestions > .what3words-autosuggest-items > .what3words-autosuggest-item.active > .what3words-autosuggest-nearest-place > .what3words-autosuggest-nearest-place-text > div:first-child {
  color: #fff;
}

/* T-087: "Choose on the map" inside the what3words field, and the dialog. */
.field-btn {
  flex: none;
  margin-left: 0.4em;
  padding: 0 0.6em;
  font: inherit;
  font-size: clamp(0.8rem, 0.9cqw, 13px);
  font-weight: 700;
  line-height: 1.15; /* shorter than the input's line so the field keeps its height */
  color: #ea068c;
  background: var(--white);
  border: 1px solid #ea068c;
  cursor: pointer;
}

.field-btn[hidden] {
  display: none;
}

.field-btn .btn-short {
  display: none;
}

.field-btn:hover,
.field-btn:focus-visible {
  color: var(--white);
  background: #ea068c;
  outline: none;
}

.w3w-dialog {
  width: min(92vw, 60cqw);
  max-width: none;
  height: min(85vh, 45cqw);
  max-height: none;
  padding: 0;
  font-family: inherit;
  color: var(--black);
  background: var(--white);
  border: 1px solid #ea068c;
}

.w3w-dialog::backdrop {
  background: rgba(0, 0, 0, 0.45);
}

.w3w-dialog[open] {
  display: flex;
  flex-direction: column;
}

.w3w-dialog-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1em;
  padding: 0.6em 0.9em;
  border-bottom: 1px solid #ea068c;
}

.w3w-dialog-head h2 {
  margin: 0;
  font-size: clamp(0.9rem, 1.1cqw, 16px);
  font-weight: 700;
  color: #ea068c;
}

.w3w-dialog-close {
  padding: 0 0.3em;
  font: inherit;
  font-size: 1.1em;
  color: #ea068c;
  background: none;
  border: 0;
  cursor: pointer;
}

.w3w-dialog-map {
  position: relative;
  flex: 1;
  min-height: 0;
}

.w3w-dialog-map what3words-map,
.w3w-map-canvas {
  display: block;
  width: 100%;
  height: 100%;
}

/* Until Google has placed it, and whenever the map has failed, the slotted
   location button would sit in normal flow at the foot of the map area,
   over the bar. */
what3words-map:not(.hydrated) .w3w-locate,
.w3w-dialog.is-failed .w3w-locate {
  display: none;
}

.w3w-locate {
  margin: 0 10px 10px 0;
  padding: 0.4em 0.9em;
  font: inherit;
  font-size: clamp(0.8rem, 0.9cqw, 13px);
  font-weight: 700;
  color: #ea068c;
  background: var(--white);
  border: 1px solid #ea068c;
  border-radius: 2px;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.3);
  cursor: pointer;
}

.w3w-dialog-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.6em 1em;
  padding: 0.6em 0.9em;
  border-top: 1px solid #ea068c;
}

.w3w-dialog-hint {
  flex: 1 1 14em;
  margin: 0;
  font-size: clamp(0.8rem, 0.9cqw, 13px);
  font-weight: 300;
  color: #8a8a8a;
}

.w3w-dialog-hint.is-words {
  font-size: clamp(0.9rem, 1.1cqw, 16px);
  font-weight: 700;
  color: var(--black);
}

.w3w-dialog-actions {
  display: flex;
  gap: 0.6em;
}

.w3w-dialog-cancel,
.w3w-dialog-use {
  padding: 0.45em 1em;
  font: inherit;
  font-size: clamp(0.8rem, 0.9cqw, 13px);
  font-weight: 700;
  border: 1px solid #ea068c;
  cursor: pointer;
}

.w3w-dialog-cancel {
  color: #ea068c;
  background: var(--white);
}

.w3w-dialog-use {
  color: var(--black);
  background: #f1c040;
  border-color: #f1c040;
}

.w3w-dialog-use:disabled {
  color: #8a8a8a;
  background: #f4f4f4;
  border-color: #dcdcdc;
  cursor: default;
}

/* Country toggle: the default GBR context already covers Jersey. */
.contact-form .idpc_af .idpc_toolbar {
  display: none;
}

.field input:disabled {
  color: #8a8a8a;
}

.field-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.69cqw;
}

.field-row .field {
  margin-bottom: 0.69cqw;
}

/* The message box is 90 tall and its label sits on the first line. */
.field-tall {
  display: block;
  min-height: 6.25cqw; /* 90 / 1440 */
}

.field-tall > label {
  float: left;
  margin-right: 0.4em;
}

.field-tall textarea {
  display: block;
  width: 100%;
  min-height: 5cqw;
  padding-top: 0.1em;
  resize: vertical;
  /* No float clearing: the label floats left so the first line of the textarea
     sits beside it, matching "Additional information/Message  Type here...". */
}

/* The comp draws no box around the option groups — fieldset is used for the
   grouping semantics only, so its default border and padding are removed. */
.contact-form fieldset,
.pay-form fieldset {
  margin: 0;
  padding: 0;
  border: 0;
}

/* --- circular checkboxes / radios ------------------------------------------ */

.opt-list {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.35em 3em;
  margin: 0.9cqw 0 1.4cqw;
}

.opt-list.one-col {
  grid-template-columns: 1fr;
  gap: 0.45em;
}

.opt {
  display: flex;
  align-items: center;
  gap: 0.8em;
  font-size: clamp(0.8rem, 0.9cqw, 13px);
  font-weight: 300;
  cursor: pointer;
}

/* Services list puts the control on the RIGHT of the label; the referral list
   puts it on the left. */
.opt-list:not(.left-control) .opt {
  justify-content: space-between;
}

.opt-list.left-control .opt {
  justify-content: flex-start;
}

.opt input[type="checkbox"],
.opt input[type="radio"] {
  appearance: none;
  flex: none;
  width: 0.97cqw;
  min-width: 13px;
  aspect-ratio: 1;
  margin: 0;
  border: 1px solid #ea068c;
  border-radius: 50%;
  cursor: pointer;
}

.opt input:checked {
  background: radial-gradient(circle, #ea068c 0 45%, transparent 46%);
}

.opt input:focus-visible {
  outline: 2px solid #ea068c;
  outline-offset: 2px;
}

.group-label {
  display: block;
  margin-top: 1.4cqw;
  font-size: clamp(0.8rem, 0.9cqw, 13px);
  font-weight: 700;
}

.group-label .hint {
  font-weight: 300;
  color: #8a8a8a;
}

/* --- the "best time to visit" dropdown -------------------------------------
   <details>, so the disclosure works with no JavaScript. The comp draws it
   OPEN: a bordered summary row, then solid #E665A2 option rows. */

.select-drop {
  margin: 1.4cqw 0;
}

.select-drop > summary {
  display: flex;
  align-items: center;
  gap: 0.4em;
  min-height: 2.08cqw;
  padding: 0.3em 0.7em;
  font-size: clamp(0.8rem, 0.9cqw, 13px);
  font-weight: 700;
  list-style: none;
  border: 1px solid #ea068c;
  cursor: pointer;
}

.select-drop > summary::-webkit-details-marker {
  display: none;
}

.select-drop > summary::after {
  content: "\2715";
  margin-left: auto;
  font-weight: 400;
  color: #ea068c;
}

.select-drop:not([open]) > summary::after {
  content: "\25BC";
  font-size: 0.7em;
}

.select-drop .opt-list {
  grid-template-columns: 1fr;
  gap: 0;
  margin: 0;
}

.select-drop .opt {
  justify-content: space-between;
  min-height: 2.08cqw;
  padding: 0.3em 0.7em;
  color: var(--white);
  font-weight: 400;
  background: #e665a2;
}

.select-drop .opt input[type="radio"],
.select-drop .opt input[type="checkbox"] {
  border-color: var(--white);
}

/* T-084: the three period headings inside the open list. White rows between
   the solid option rows, ringed like the summary so the column reads as one box. */
.select-drop .slot-group {
  display: flex;
  align-items: center;
  min-height: 2.08cqw;
  margin: 0;
  padding: 0.3em 0.7em;
  font-size: clamp(0.8rem, 0.9cqw, 13px);
  font-weight: 700;
  color: #ea068c;
  background: var(--white);
  border: 1px solid #ea068c;
  border-top: 0;
}

.select-drop .opt input:checked {
  background: radial-gradient(circle, #fff 0 45%, transparent 46%);
}

/* --- dropzone: dashed magenta, not a grey panel ---------------------------- */

.dropzone {
  margin: 1.4cqw 0;
  padding: 2.4cqw 1rem;
  text-align: center;
  font-size: clamp(0.8rem, 0.9cqw, 13px);
  font-weight: 300;
  border: 1px dashed #ea068c;
}

.dropzone .browse {
  color: #ea068c;
  font-weight: 700;
}

/* The native file control is visually hidden — the comp draws only the prompt
   text. It stays in the tab order and the <label> is its trigger, so keyboard
   and screen-reader users still reach it. */
.dropzone input[type="file"] {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
}

.dropzone label {
  cursor: pointer;
}

.dropzone input[type="file"]:focus-visible + label,
.dropzone label:focus-within {
  outline: 2px solid #ea068c;
  outline-offset: 4px;
}

/* Drag hover. Background only — a border change would move the box. */
.dropzone.is-over { background: #fdeaf3; }

/* The attached-file list, a sibling of the dropzone (ISS-027).
   EMPTY AT REST AND MUST STAY THAT WAY: no margin, no padding, no border here,
   so an empty <ul> self-collapses and the page measures exactly as it did
   before. The gap above only appears once there is a file to show. */
.dropzone-files {
  list-style: none;
  margin: 0;
  padding: 0;
  font-size: clamp(0.8rem, 0.9cqw, 13px);
  font-weight: 300;
}
.dropzone-files:not(:empty) { margin: 0.6cqw 0 0; }

.dropzone-files li {
  display: flex;
  align-items: center;
  gap: 0.5em;
  padding: 0.15em 0;
}

/* min-width: 0 so a long filename ellipses instead of pushing the button out. */
.dropzone-files .name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}

.dropzone-files .size { color: #8a8a8a; }

.dropzone-files .remove {
  margin-left: auto;
  padding: 0 0.5em;
  font: inherit;
  font-weight: 700;
  line-height: 1.4;
  color: #ea068c;
  background: none;
  border: 1px solid #ea068c;
  border-radius: 4px;
  cursor: pointer;
}
.dropzone-files .remove:hover,
.dropzone-files .remove:focus-visible {
  color: #fff;
  background: #ea068c;
}

/* --- submit: amber, full width -------------------------------------------- */

.contact-form .submit,
.pay-form .submit {
  display: block;
  width: 100%;
  margin-top: 1.4cqw;
  padding: 0.8em 2em;
  font: inherit;
  font-size: clamp(0.95rem, 1.25cqw, 18px);
  font-weight: 700;
  color: var(--white);
  background: #f1c040;
  border: 0;
  border-radius: 6px;
  cursor: pointer;
}

.contact-form .submit:hover,
.contact-form .submit:focus-visible,
.pay-form .submit:hover,
.pay-form .submit:focus-visible {
  background: #edac3c;
}

/* --- status + data-protection note under the submit (T-026) ---------------- */

/* Empty until the worker rejects something; then magenta, like the field rings. */
.form-status {
  margin: 0;
  font-size: clamp(0.8rem, 0.9cqw, 13px);
  font-weight: 700;
  color: #ea068c;
}
.form-status:not(:empty) { margin-top: 0.8cqw; }

.form-consent {
  margin: 1.1cqw 0 0;
  font-size: clamp(0.75rem, 0.83cqw, 12px);
  font-weight: 300;
  line-height: 1.45;
  color: var(--black);
}
.form-consent a {
  color: #ea068c;
  font-weight: 700;
  text-decoration: none;
}
/* Client amends 2026-10-20: the marketing opt-in wraps to several lines, so the
   circle sits on the first line rather than centred on the block. */
.form-optin .opt {
  align-items: flex-start;
  line-height: 1.45;
}
.form-optin .opt input[type="checkbox"] {
  margin-top: 0.2em;
}
.form-optin a {
  color: #ea068c;
  font-weight: 700;
  text-decoration: none;
}
.form-consent a:hover,
.form-consent a:focus-visible { text-decoration: underline; }

/* --- where to find us ------------------------------------------------------ */

.find-us {
  position: absolute;
  left: 50.43%; /* 726.2 / 1440 */
  top: -0.77cqw; /* panel top 724.5 vs this section's start at 735.6 */
  width: 49.57%; /* 713.8 / 1440 */
  min-height: 74.38cqw; /* 1071.1 / 1440 */
  /* heading at x815 y1010 -> 88.8 / 285.5 inside the panel */
  padding: 19.83cqw 3cqw 3cqw 6.17cqw;
}

/* The wash is a CIRCLE (1:7587), and the panel box is only 713.8 of its 1071.2
   diameter — the artboard clipped it at the canvas edge. Sizing the image to
   the panel would keep that clip, which is what left a hard edge and a white
   channel down the right of any viewport past 1440.

   So it is squared off its own height instead and allowed to run past the
   panel: aspect-ratio 1 against height:100% means the SVG's square viewBox
   renders 1:1 however tall the panel ends up, so the circle is revealed rather
   than stretched. Its gradient reaches white at the right tip, so it fades out
   instead of ending on an edge, and the overhang needs no cut-off.

   Below 1440 nothing changes on screen: the overhang lands outside the viewport
   and html { overflow-x: clip } absorbs it, exactly where the old clip was.

   max-width: none is load-bearing — `img { max-width: 100% }` in base.css would
   otherwise clamp this straight back to the panel width and restore the clip,
   silently and only above 1440. */
.find-us .panel-bg {
  position: absolute;
  left: 0;
  top: 0;
  height: 100%;
  width: auto;
  aspect-ratio: 1;
  max-width: none;
  z-index: -1;
}

.find-us h2 {
  color: #357aac;
}

/* 1:8257 — a 445 x 250 window on the map. It was missing entirely. */
.find-us .map {
  width: 30.9cqw; /* 445 / 1440 */
  max-width: 100%;
  aspect-ratio: 445 / 250;
  margin-bottom: 1.9cqw;
  object-fit: cover;
}

.find-us dl {
  display: grid;
  grid-template-columns: 10cqw 1fr; /* labels x815, values x959 */
  gap: 0.25em 0;
  margin: 0;
  font-size: clamp(0.85rem, 1.11cqw, 16px);
}

.find-us dt {
  font-weight: 400;
  color: #357aac;
}

.find-us dd {
  margin: 0;
  font-weight: 300;
  color: var(--black);
}

.find-us dd + dt {
  margin-top: 0.3em;
}

.find-us a {
  color: inherit;
  text-decoration: none;
}

.find-us a:hover,
.find-us a:focus-visible {
  text-decoration: underline;
}

@media (max-width: 900px) {
  .contact-body { min-height: 0; }
  .contact-form,
  .pay-form { width: 100%; }

  .find-us {
    position: static;
    width: 100%;
    min-height: 0;
    margin-top: 2rem;
  }
  .opt-list { grid-template-columns: 1fr; }

  /* Labels stop being nowrap once there is no room for them beside the input. */
  .field { flex-wrap: wrap; }
  .field > label { white-space: normal; }

  /* Paired fields (Town/Postcode, Forename/Surname) stack: side by side they
     could not shrink below their own min-content and overflowed at 320. */
  .field-row { grid-template-columns: minmax(0, 1fr); }
  /* Undo the Products band/gallery overlap below the breakpoint. It is measured
     off the desktop artboard, where the quote sits in a narrow column beside the
     panel; once the columns stack, a band with no bottom padding and a quote
     hanging past it just collides with the gallery. These beat the inline custom
     properties because they set the resolved property, not the variable. */
  .band-body { padding-bottom: clamp(2rem, 5cqw, 4.5rem); }
  .page-quote { margin-bottom: 0; }

  .find-us { padding: 2rem 1.5rem; }
  /* The panel is static and full width here, so the wash goes back to filling
     its box. Squaring it off the height (see the desktop rule) would make it
     far wider than the screen on a tall stacked panel. */
  .find-us .panel-bg { width: 100%; height: 100%; aspect-ratio: auto; }
  .find-us .map { width: 100%; }
  .find-us dl { grid-template-columns: 1fr; }
  .find-us dd { margin-bottom: 0.6em; }
}

/* ---------------------------------------------------------------------------
   PAY INVOICE OR DEPOSIT

   No artboard — content from the existing live page, styling inherited from the
   contact form so the two match. Only the centred tail below the fields and the
   narrower column are specific to it.
   --------------------------------------------------------------------------- */

.pay-form {
  max-width: 47.6cqw; /* the live form sits in a ~685 column */
  margin-inline: auto;
}

.pay-terms {
  margin: 1.4cqw 0 0;
  justify-items: center;
}

.pay-terms .opt {
  font-weight: 300;
}

.pay-terms a {
  color: #ea068c;
  font-weight: 600;
}

/* Return-state banners. Hidden until scripts.html reads ?pay=… from the URL
   and stamps data-pay on the form — the page is static, so the state has to
   come from the query string CityPay redirects back with. */
.pay-status {
  display: none;
  margin: 1.4cqw 0 0;
  text-align: center;
  font-weight: 600;
}

.pay-form[data-pay="success"] .pay-status-success { display: block; color: #607e47; }
.pay-form[data-pay="failure"] .pay-status-failure { display: block; color: #b3261e; }
.pay-form[data-pay="error"] .pay-status-error { display: block; color: #b3261e; }


.pay-note {
  margin: 1.2cqw 0 0;
  text-align: center;
  font-size: clamp(0.8rem, 0.9cqw, 13px);
  font-weight: 300;
  color: #6a6a6a;
}

@media (max-width: 900px) {
  .pay-form { max-width: none; }
  .pay-form .field-row { grid-template-columns: 1fr; }
}


/* ===========================================================================
   MOBILE SHELL — T-060, mobile artboards 1 (header) and 2 (menu).

   The mobile comp is 720 wide = 360 CSS px; every figure below is the
   artboard value / 2. These are fixed px on purpose: the header and the menu
   are chrome, not artwork that should scale with the canvas, and the comp
   draws them at one size. Applies wherever the burger is the nav (<= 900).
   =========================================================================== */

/* Never on desktop, whatever state a resize left behind. */
.site-menu { display: none; }

/* Scroll lock while the overlay is up. On <html>: the body's overflow-x: clip
   is what absorbs the full-bleed overhang and must stay. */
html.menu-open { overflow: hidden; }

@media (max-width: 900px) {
  /* --- Header: 91.5 tall; logo 150 wide at (26.5, 35.5); two 24.5 plum
         social circles 6 apart ending at 288.5; a 30 white-ring burger at
         305 -> 335. Everything centres on y ~50.

         Client amend 2026-09-14 (T-077): logo widened to 200px below,
         departing from the artboard's 150. Header height is unchanged
         (91.5, min-height driven) so nothing below it shifts. --- */
  .site-header {
    padding-block: 0;
    /* Clips the daisy below: on the homepage the photo strip starts exactly
       where the header ends, so this is where the artboard cuts it too. No
       dropdown to clip on mobile — the nav is display: none here. */
    overflow: hidden;
  }

  /* The large daisy behind the top-right of every mobile header (artboards
     1-13 all carry it, in the page's own colour at ~14%). A mask rather than
     an <img> so it can take var(--theme): custom properties do not cross into
     an image document. Same file as the menu's daisy. */
  .site-header::before {
    content: "";
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    aspect-ratio: 720 / 400;
    z-index: -1;
    background: var(--theme, var(--magenta));
    opacity: 0.14;
    pointer-events: none;
    -webkit-mask: url("../assets/svg/mobile/menu-daisy.svg") no-repeat 0 0 / 100% auto;
    mask: url("../assets/svg/mobile/menu-daisy.svg") no-repeat 0 0 / 100% auto;
  }

  .site-header > .wrap {
    grid-template-columns: auto 1fr;
    grid-template-areas: "logo primary";
    align-items: center;
    min-height: 91.5px;
    padding-inline: 26px;
    row-gap: 0;
  }

  /* Client amend 2026-09-14: mobile logo 200px (artboard has 150 at 1x). */
  .site-header .logo { width: 200px; }

  /* Narrow-phone guard for the amend above (T-077 review note, found while
     probing T-076). The row is rigid: 26 padding + logo + 20 grid gap + 55 of
     social + 16.5 + a 30 burger. With a 200 logo the burger's right edge sits
     at 347.5, so anything narrower than ~348 clips it — and html's
     overflow-x: clip means it vanishes silently rather than scrolling into
     view, taking the only way into the menu with it. Measured at 320:
     burger [317.5 .. 347.5], 27.5px off-screen. 160 pulls that back to 307.5.
     348 is the measured fit point, so that is the threshold — anything lower
     leaves a band of widths that still lose the burger. Every 360-class
     artboard width keeps the client's 200. */
  @media (max-width: 348px) {
    .site-header .logo { width: 160px; }
  }

  .header-primary {
    padding-top: 0;
    gap: 0;
  }

  .site-header .social-links {
    gap: 6px;
    margin: 0 16.5px 0 0;
  }
  .site-header .social-links a {
    width: 24.5px;
    height: 24.5px;
  }

  /* The comp's burger is a white outline ring, not a filled plum disc. */
  .burger,
  .menu-close {
    display: grid;
    place-items: center;
    width: 30px;
    height: 30px;
    padding: 0;
    border: 1px solid var(--white);
    border-radius: 50%;
    background: none;
    color: var(--white);
    cursor: pointer;
    flex: none;
  }
  .burger svg,
  .menu-close svg {
    width: 16px;
    height: 16px;
  }

  /* --- Overlay --- */
  .site-menu {
    display: block;
    position: fixed;
    inset: 0;
    z-index: 50;
    overflow-y: auto;
    /* Sampled left -> right: (234,9,141) -> (232,53,151) -> (230,98,161). */
    background: linear-gradient(90deg, var(--magenta), var(--magenta-soft));
    color: var(--white);
  }
  /* Must follow the rule above: the UA's [hidden] { display: none } has lower
     specificity than .site-menu and would otherwise lose to display: block. */
  .site-menu[hidden] { display: none; }

  .site-menu > * { position: relative; z-index: 1; }

  /* Decoration: the large pale daisy behind the top-right of the bar, and the
     two hairline arcs across the bottom. Both from the artboard's own paths
     (assets/svg/mobile/). */
  .menu-daisy,
  .menu-arcs {
    position: absolute;
    z-index: 0;
    pointer-events: none;
    height: auto;
  }
  .menu-daisy {
    top: 0;
    left: 0;
    width: 100%; /* drawn in artboard coordinates: 720 wide, cropped at y400 */
    opacity: 0.14;
  }
  .menu-arcs {
    left: 0;
    bottom: 0;
    width: 100%;
  }

  /* The bar repeats the header (same measurements) with the X in the
     burger's place — including the client's 200px logo (T-077), so the
     overlay's brand mark matches the one it covers. The artboard has 150. */
  .menu-bar {
    display: flex;
    align-items: center;
    min-height: 91.5px;
    padding-inline: 26px;
  }
  .menu-bar .logo { width: 200px; }
  .menu-bar .social-links {
    gap: 6px;
    margin: 0 16.5px 0 auto;
  }
  .menu-bar .social-links a {
    width: 24.5px;
    height: 24.5px;
  }

  /* Narrow-phone guard for the 200 logo, the overlay's own. The header's is
     348 (above); this bar's fit point is different because the row is
     different: flex, no 20px grid gap, and the social block is pushed right by
     an auto margin rather than a 1fr column. Nothing here can shrink (the logo
     has a definite width, the two 24.5 circles are flex: none, the X is
     flex: none), so the bar's minimum is 26 + 200 + 55 + 16.5 + 30 + 26 =
     353.5 — below that it overflows. The X's right edge then pins at
     26 + 200 + 55 + 16.5 + 30 = 327.5 regardless of viewport, i.e. it is
     clipped below 328 (7.5px lost at 320); .site-menu's overflow-y: auto makes
     overflow-x compute to auto, so it can be scrolled back rather than
     vanishing as the header's burger does, but a horizontal scrollbar inside
     the overlay is a regression in its own right. So the guard takes the
     stricter of the two numbers: 353. At 160 the bar's minimum is 313.5, which
     fits every phone width down to 320 with the padding intact. */
  @media (max-width: 353px) {
    .menu-bar .logo { width: 160px; }
  }

  /* Links: 16.5px caps on a 35 pitch, first one boxed at y120.5. The comp has
     six (with CASE STUDIES); we ship five, so everything below sits 35 higher
     than its artboard y. */
  .menu-nav {
    display: flex;
    flex-direction: column;
    align-items: center;
    margin-top: 29px;
  }
  /* SERVICES is a <button> (client amend 2026-09-14, T-076) and every other
     row is an <a>; they share this rule so the disclosure is typographically
     indistinguishable from its siblings. Change one, change both. */
  .menu-nav a,
  .menu-nav .menu-services-toggle {
    font-family: var(--font-body);
    font-size: 16.5px;
    font-weight: 400;
    line-height: 35px;
    color: var(--white);
    text-decoration: none;
  }
  /* Undo the UA's button chrome only — the type above is already shared. */
  .menu-nav .menu-services-toggle {
    appearance: none;
    border: 0;
    margin: 0;
    padding: 0;
    background: none;
    cursor: pointer;
  }
  .menu-nav a:hover,
  .menu-nav a:focus-visible,
  .menu-nav .menu-services-toggle:hover,
  .menu-nav .menu-services-toggle:focus-visible { text-decoration: underline; }

  /* The Services sub-menu: "All services" (the old SERVICES destination) plus
     the seven from getServices() that are not PRODUCTS — that one keeps its
     own top-level row. No artboard draws this state — see the departure note
     in MobileMenu.astro. Indented under the toggle and set a step smaller so
     the five top-level rows still read as the top level.

     Eight extra rows overflow a 360x640 viewport; .site-menu is overflow-y:
     auto (above), so the overlay scrolls rather than clipping them. */
  /* Client 2026-09-14: the sub-services sit indented under SERVICES, not
     left-aligned in the centred column. The nav centres its rows, so the
     SERVICES label's left edge is 50% minus half its width (71.4 / 2 at the
     16.5px base); the list's left edge sits on it. Smaller type so the
     longest label (PROPERTY & BLOCK MANAGEMENT) fits at 360 and wraps at 320
     rather than overflowing. No "All services" item. */
  .menu-services {
    list-style: none;
    margin: 0 0 0 calc(50% - 35.7px);
    padding: 0 6px 0 0;
    text-align: left;
  }
  /* Must follow the rule above for the same reason .site-menu[hidden] does:
     never leave [hidden] to fight a class rule on its own (L-036/L-040). */
  .menu-services[hidden] { display: none; }
  .menu-services a {
    display: block;
    font-size: 12px;
    line-height: 24px;
  }

  /* The header's pill (125.6 x 24; comp 124.5 x 25.5), 11 under the links,
     with the site-visit pill beside it (client amend 2026-10-28). The pair is
     centred as the lone pay pill was, so the row's height is unchanged. */
  .menu-pills {
    display: flex;
    justify-content: center;
    gap: 8px;
    margin-top: 11px;
  }

  /* Search: bar x25 -> 302.5 (277.5 wide, 24.5 tall), 7.5 gap, 24.5 submit
     circle. Drawn in CSS — the header's 200-wide export would stretch. */
  .menu-search {
    display: flex;
    align-items: center;
    gap: 7.5px;
    margin: 46.5px 25.5px 0;
  }
  .menu-search-field {
    position: relative;
    flex: 1 1 auto;
    height: 24.5px;
    border: 1px solid var(--white);
    border-radius: 999px;
    background: rgba(255, 255, 255, 0.5);
  }
  .menu-search-field input {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    padding: 0 28px 0 10px;
    border: 0;
    background: none;
    font-family: var(--font-body);
    font-size: 12px;
    font-weight: 600;
    color: var(--black);
  }
  .menu-search-field input::placeholder { color: var(--black); opacity: 1; }
  .menu-search .search-mic {
    position: absolute;
    right: 9px;
    top: 3px;
    width: 10.1px;
    height: 17.5px;
    /* Same button reset and hit area as the header/footer mic — see
       .search .search-mic. */
    padding: 0;
    border: 0;
    background: none;
    font: inherit;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
  }
  .menu-search .search-mic::before {
    content: "";
    position: absolute;
    inset: -7px;
  }
  /* Must follow the rule above, for the reason .menu-services[hidden] does. */
  .menu-search .search-mic[hidden] { display: none; }
  .menu-search .search-mic img { position: absolute; }
  .menu-search .search-mic .mic-capsule { left: 2.2px; top: 0;      width: 5.8px;  height: 10.6px; }
  .menu-search .search-mic .mic-cradle  { left: 0;     top: 7.4px;  width: 10.1px; height: 5.5px; }
  .menu-search .search-mic .mic-stem    { left: 4.5px; top: 12.1px; width: 1.2px;  height: 5.5px; }
  .menu-search .search-mic .mic-base    { left: 1.6px; top: 16.4px; width: 6.9px;  height: 1.1px; }
  .menu-search-submit {
    flex: none;
    width: 24.5px;
    height: 24.5px;
    padding: 0;
    border: 0;
    background: none;
    cursor: pointer;
  }
  .menu-search-submit img { width: 100%; height: 100%; }

  /* Legal links: 12px caps on a 24 pitch, 48.5 under the search. */
  .menu-legal {
    display: flex;
    flex-direction: column;
    align-items: center;
    margin-top: 48.5px;
    padding-bottom: 120px; /* clears the arcs on a short screen */
  }
  .menu-legal a {
    font-family: var(--font-body);
    font-size: 12px;
    font-weight: 400;
    line-height: 24px;
    color: var(--white);
    text-decoration: none;
  }
  .menu-legal a:hover,
  .menu-legal a:focus-visible { text-decoration: underline; }

  /* --- Site-visit tab: the comp draws it at exactly half the desktop size
         (30 x 148.5 at the right edge, top y92.5). Its internals are fixed px,
         so scale the whole thing rather than restate them. --- */
  .site-visit {
    top: 92.5px;
    /* The artboard draws it at half the desktop size; the client asked for a
       third more (2026-09-12): 0.5 x 1.33. */
    transform: scale(0.665);
    transform-origin: 100% 0;
  }
}


/* ===========================================================================
   MOBILE HOMEPAGE — T-061 (hero) and T-062 (grid, testimonials, footer),
   mobile artboard 1 (720 x 3590 = 360 x 1795 CSS).

   Applies at <= 720 — the artboard's own width, so at 720 the page IS the
   artboard 1:1 and at 360 it is the artboard at 2:1. Geometry is in cqw
   (artboard units / 7.2) so it scales with the canvas between those two;
   type is cqw with px floors. Above 720 the desktop layout (cqw against
   1440) continues to apply and none of this does.

   The carousel is omitted here (owner, 2026-09-11); the desktop block stays
   untouched pending ISS-020.
   =========================================================================== */

.m-only { display: none; }

/* The headline's mobile-only line breaks (see index.html). Off everywhere
   except the mobile block below; the >=900 block's "br { display: none }"
   covers the tablet range in between. */
.hero-headline .br-m { display: none; }

@media (max-width: 720px) {
  .m-only { display: block; }

  /* --- Hero band. The artboard: header 0-92, photo 92-294.5 with a bowed
         bottom, headline from y242 over the photo's lower edge, intro from
         y384, magenta sweep ending 486 (left) -> 562.5 (centre) -> 538
         (right), pale underlay to 534.5 -> 635.5 -> 631.7. The band BOX ends
         at y547.5, where the services' first row starts; the two sweeps hang
         below it as absolute art and the circles paint over them. --- */
  .band-hero { padding-bottom: 30.5cqw; }
  .band-hero::before { display: none; }
  .band-hero .floral,
  .band-hero .divider,
  .band-hero .arcs,
  .band-hero .daisy-1,
  .band-hero .daisy-2 { display: none; }

  .m-hero-underlay,
  .m-hero-band,
  .m-hero-arcs {
    position: absolute;
    left: var(--bleed-inset);
    width: 100vw;
    max-width: none;
    pointer-events: none;
  }
  .m-hero-underlay { top: 5.56cqw; height: 170.97cqw; z-index: -3; } /* y40 -> 1271 */
  .m-hero-band     { top: 0;       height: 156.25cqw; z-index: -2; } /* y1 -> 1125 */
  .m-hero-arcs     { top: 0;       height: 156.25cqw; z-index: 1; }

  /* Photo strip: full width, 405/720 tall, the bow on the video itself so the
     headline can hang below the box without being clipped. Poster only —
     scripts.html withholds autoplay at this width. */
  .hero-media {
    width: 100%;
    margin-inline: 0;
    height: 56.25cqw;
    overflow: visible;
    -webkit-mask-image: none;
    mask-image: none;
  }
  .hero-media > video,
  .hero-media > img {
    object-position: center;
    -webkit-mask-image: url("../assets/svg/mobile/hero-photo-mask.svg");
    mask-image: url("../assets/svg/mobile/hero-photo-mask.svg");
    -webkit-mask-size: 100% 100%;
    mask-size: 100% 100%;
    -webkit-mask-repeat: no-repeat;
    mask-repeat: no-repeat;
  }
  .play {
    width: 12.5cqw; /* 90 / 720 */
    top: 45.4%; /* centre y184 of the 92 -> 294.5 strip */
  }

  /* Headline: (45, 242), 23px on a 30 pitch, four lines over 270. It starts
     52.5 above the strip's bottom, so it is positioned from the strip top
     (150 = 41.7cqw) and the intro below clears it with its own margin. */
  .hero-copy {
    top: 41.7cqw;
    padding-inline: 12.5cqw;
  }
  /* 25px (a 62 bbox at 2x over Fraunces' 1.233 ascent+descent) on a 30
     pitch; the mobile breaks on, the desktop-only ones off. */
  .hero-headline {
    max-width: 75cqw;
    font-size: clamp(21px, 6.94cqw, 50px);
    line-height: 1.2;
  }
  .hero-headline br,
  .hero-headline .br-m { display: inline; } /* .br-m: must outrank the global hide */
  .hero-headline .br-d { display: none; }

  /* Intro: (45, 384), 14.5px light on an 18 pitch, 270 wide. */
  .band-hero > .wrap { padding-inline: 12.5cqw; }
  .hero-intro {
    margin: 24.9cqw 0 0; /* strip ends 294.5, intro starts 384 */
    max-width: 75cqw;
    font-size: clamp(13px, 4.03cqw, 29px);
    line-height: 1.24;
  }

  /* The two white daisies: 136 wide at (411, 932) and 63 wide at (614, 584)
     on the artboard. The band-main exports are the same motif at the right
     sizes (142.8 and 62 wide). Above the sweeps and the photo corner. */
  .band-hero .m-daisy-a { left: 57.1%; top: 129.4cqw; width: 18.9cqw; z-index: 1; }
  .band-hero .m-daisy-b { left: 85.3%; top: 81.1cqw;  width: 8.75cqw; z-index: 1; }

  /* --- Services: 3 x 3 circles of 105 (210/720) at x 14 / 127.5 / 241 and
         y 547.5 / 662 / 777.5 — 8.5 between columns, 9.5 between rows. --- */
  .band-services { margin-top: 0; }
  .band-services .wrap { padding-inline: 3.9cqw; }
  .services-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    column-gap: 2.36cqw;
    row-gap: 2.64cqw;
    max-width: none;
  }
  /* T-081.1. The desktop rule sizes the icon by WIDTH alone (62%, height
     auto), so a portrait icon overshoots: plant-supply's art is 77.4 x 150
     (1:1.94), which at 62% wide renders 120% of the tile TALL and bursts the
     ring — what the client read as the background being "too large".
     Hydroseeding's (109.7 x 144) reaches 81% against a 45-67% family. Bound
     the icon in BOTH axes — a 62% square with the art letterboxed inside —
     so a portrait icon is limited by height the way a landscape one is
     limited by width. The five square/landscape icons are unmoved; only
     tree-surgery (1:1.08) also shrinks, by 4.8% of the tile.
     DEPARTURE from the mobile artboard — see ServicesGrid.astro. */
  .service .icon {
    height: 62%;
    object-fit: contain;
  }

  /* T-081.2. Label legibility on a phone: +15% (13.1px -> 15.1px at 360).
     Fraunces ships at 400 only (base.css), so a heavier weight would
     synthesise a faux bold — the size carries it instead. The tighter
     line-height and half tracking buy back the room the larger type costs,
     which is what keeps the three-line labels ("Hydroseeding & Lawn
     Services") inside their disc down to 320.
     DEPARTURE from the mobile artboard — see ServicesGrid.astro. */
  .service .label {
    font-size: clamp(13px, 4.45cqw, 32px); /* was clamp(12px, 4.2cqw, 26px); client 2026-10-21 */
    line-height: 1.05;
    letter-spacing: 0.01em;
  }

  /* --- Testimonials on the pale circle. The artboard's circle is centred
         (151.4, 989.7) r198.6 — top y791, behind the grid's last row (which
         paints above via .band-services' z-index), bottom y1188. Heading at
         y901.5, quote y946.5 -> 1077, author y1092.5. No magenta band, no
         arcs, no dots, no carousel below the breakpoint. --- */
  .band-main {
    margin-top: 0;
    padding-top: 5.3cqw;
    padding-bottom: 34.4cqw; /* to the enlarged circle's bottom at y1391 */
  }
  .band-main::before,
  .band-main .divider,
  .band-main .arcs,
  .band-main .daisy-3,
  .band-main .daisy-4,
  .pager { display: none; }
  /* The artboard's circle is 397 across (110.3cqw at x -13.1cqw), sized for
     the single Storm quote. The carousel block holds the tallest of twelve
     quotes plus the dot row, so the circle is scaled up on the same centre
     line (x151.4) to keep both inside it: 600 across, bottom at y1391. */
  .band-main .blob {
    top: -25.4cqw;   /* 791 - 882.5 */
    left: -41.3cqw;  /* 151.4 - 300 */
    width: 166.7cqw; /* 600 / 360: also holds the centred dot row at y1257 */
    background: linear-gradient(90deg, #fef8fb, #f5c1da); /* export: near-white at x0, pink at x700 */
  }
  .band-main .wrap { padding-inline: 12.5cqw; }
  .testimonials { max-width: 75cqw; }
  .testimonials h2 {
    margin-bottom: 3.9cqw;
    font-size: clamp(21px, 6.94cqw, 50px);
  }
  .testimonial-quote {
    font-size: clamp(11px, 3.39cqw, 24px);
    line-height: 1.33;
  }
  .testimonial-author {
    margin-top: 4.3cqw;
    font-size: clamp(11px, 3.39cqw, 24px);
  }

  /* --- Footer (y1477.5 -> 1795): logo 152 wide at (25, 1503.5) with the two
         social circles at (279 / 309.5, 1506.5); two link columns at x24.5
         and x179.5 from y1558 on a 20 pitch; the badges under the legal
         column at y1633.5; a full-width search at y1699.5; the copyright at
         y1749. The wrappers go display: contents so the grid can place the
         social row and the copyright where the artboard has them. --- */
  .site-footer {
    padding-block: 7.2cqw 9.2cqw;
    font-size: clamp(9px, 2.7cqw, 19px);
  }
  .site-footer > .wrap {
    grid-template-columns: 43.06cqw minmax(0, 1fr); /* col 2 at x179.5 */
    grid-template-areas:
      "logo   social"
      "nav1   nav2"
      "nav1   badges"
      "search search"
      "copy   copy";
    gap: 0;
    padding-inline: 6.9cqw;
  }
  .footer-brand,
  .footer-utility,
  .footer-utility-top { display: contents; }
  .footer-brand .logo {
    grid-area: logo;
    width: 42.2cqw;
    margin: 0;
  }
  .site-footer .social-links {
    grid-area: social;
    justify-self: end;
    align-self: start;
    gap: 5.5px;
    margin: 0.8cqw 0 0;
  }
  .site-footer .social-links a { width: 25px; height: 25px; }
  .footer-nav[aria-label="Footer"] { grid-area: nav1; }
  .footer-nav[aria-label="Legal"]  { grid-area: nav2; }
  .footer-nav { margin-top: 6.4cqw; }
  .footer-nav ul { line-height: 2.06; }
  .accreditations {
    grid-area: badges;
    display: flex;
    align-items: center;
    gap: 4.1cqw;
    margin-top: 6.25cqw;
  }
  .accreditations .jersey { width: 12.4cqw; }
  .accreditations .bali { width: 23.75cqw; }

  /* Search: bar x24.5 -> 303 (278.5 x 25.5), 7.5 gap, 25.5 submit disc. The
     200-wide ring export would stretch, so the bar is drawn here and only the
     mic and submit vectors are kept. */
  .site-footer .search {
    grid-area: search;
    width: 100%;
    height: 25.5px;
    margin-top: 8.5cqw;
  }
  .site-footer .search::before {
    content: "";
    position: absolute;
    left: 0;
    top: 0;
    right: 33px;
    height: 25.5px;
    border: 1px solid var(--magenta-soft);
    border-radius: 999px;
    background: var(--white);
  }
  .site-footer .search .search-ring { display: none; }
  .site-footer .search input {
    left: 0;
    width: calc(100% - 33px);
    height: 25.5px;
    padding: 0 28px 0 10px;
  }
  .site-footer .search .search-mic { left: auto; right: 42px; top: 4px; }
  .site-footer .search .search-submit {
    left: auto;
    right: 0;
    width: 25.5px;
    height: 25.5px;
  }
  .copyright {
    grid-area: copy;
    margin-top: 6.8cqw;
  }
}


/* ===========================================================================
   TESTIMONIALS CAROUSEL — T-057 part 2/3 (homepage).

   Without the script every slide is in flow, stacked. Once the script marks
   the block data-enhanced the slides share one grid cell, so the block is as
   tall as the TALLEST quote and nothing below it moves as they cycle; parked
   slides are visibility: hidden (kept in layout, out of paint and out of the
   tab order). The block therefore runs ~70px taller than the comp's single
   Storm quote on desktop, which the case-study row below inherits.
   =========================================================================== */
.testimonial-slides { display: grid; }

.testimonial-slide { margin: 0; }

.testimonials:not([data-enhanced]) .testimonial-slide + .testimonial-slide {
  margin-top: 1.5em;
}

.testimonials[data-enhanced] .testimonial-slide { grid-area: 1 / 1; }

.testimonials[data-enhanced] .testimonial-slide:not([data-current]) {
  visibility: hidden;
}

/* One dot per quote (the artboard draws three static ones). Centred in the
   block: left-aligned, the row started outside the pale circle. */
.pager {
  flex-wrap: wrap;
  justify-content: center;
}
.pager button { transition: background-color 150ms ease; }
.pager button:hover,
.pager button:focus-visible { background: #8a8a8a; }
.pager button[aria-current="true"] { background: #4a4a4a; }
.pager button:focus-visible { outline: 2px solid var(--magenta); outline-offset: 2px; }

@media (max-width: 720px) {
  /* The mobile artboard has no dots, but with twelve quotes the reader needs
     the control. Smaller, under the author. */
  .pager {
    display: flex;
    gap: 5px;
    margin-top: 4.3cqw;
  }
  .pager button {
    width: 10px;
    height: 10px;
  }
}


/* ===========================================================================
   MOBILE INNER-PAGE TEMPLATE — T-063, mobile artboards 4-11 (and the shared
   header on 12/13). Artboard units / 7.2 = cqw. The per-page artwork comes
   from assets/svg/pages/<slug>/mobile/ via the build (see page-header.html);
   the geometry below is shared by every service artboard:

     header band 913 tall (Land Management 1013), title at (90, 249) 35px on a
     35 pitch, photo circle ~500 at the band's lower edge, pale rim 510-1008
     under the curve, arcs in the 505-910 window; body from the band's end,
     section title 25px at +126, prose 12.2px on a 16.25 pitch at x90; the
     services panel a 620-wide rounded block at x50, 25px heading, 12.2px
     semibold bullets; gallery band with a 42-unit pale rim above its curve,
     "Gallery" at +200, 285 tiles on a 335 pitch at x50.
   =========================================================================== */
@media (max-width: 720px) {
  /* --- Header band --- */
  .band-page {
    min-height: var(--m-header-h, 126.78cqw);
    /* No overflow clip: the photo circle overhangs the band's bottom edge. */
  }
  .band-page .band-shape,
  .band-page .band-underlay,
  .band-page .band-floral,
  .band-page .band-arcs,
  .band-page .page-deco,
  .page-intro { display: none; }

  .band-shape-m {
    position: absolute;
    left: 0;
    top: 0;
    width: 100%;
    height: var(--m-header-h, 126.78cqw);
    z-index: -1;
    pointer-events: none;
  }
  /* The pale rim: a plain rectangle on the artboard from 403 above the band's
     end to 95 below it (510 -> 1008 on a 913 band), showing under the curve. */
  .band-page::after {
    content: "";
    position: absolute;
    left: 0;
    width: 100%;
    top: calc(var(--m-header-h, 126.78cqw) - 55.97cqw);
    height: 69.17cqw;
    background: var(--theme-pale, #f5c1da);
    z-index: -2;
    pointer-events: none;
  }
  .arcs-m {
    position: absolute;
    left: 0;
    width: 100%;
    top: var(--m-arcs-top, 70.14cqw);
    height: var(--m-arcs-h, 56.25cqw);
    z-index: 0;
    pointer-events: none;
  }
  .m-deco {
    position: absolute;
    z-index: 5; /* above everything in its section — see the .page-deco RULE */
    height: auto;
    pointer-events: none;
  }
  /* Solid colour washes are not decorations: About's two pale circles behind
     the Ethos and History cards stay under the copy. */
  .m-deco.m-wash { z-index: 0; }

  .page-head {
    padding-top: 7.9cqw; /* title box at y120: the 91.5 bar + 28.5 */
    padding-inline: 12.5cqw 11cqw; /* titles at x90 on every mobile artboard; the right inset keeps them clear of the site-visit tab (38.6 wide at 0.665) */
  }
  .page-head-copy { max-width: none; }
  .page-title {
    max-width: none;
    font-size: clamp(28px, 9.72cqw, 70px); /* 35px: an 86.9 bbox at 2x over 1.233 */
    line-height: 1;
  }
  .page-subtitle {
    margin: 2cqw 0 0;
    font-family: var(--font-display);
    font-size: clamp(16px, 5.56cqw, 40px);
    font-weight: 400;
    line-height: 1.2;
    color: var(--white);
  }
  /* The circle at its artboard position, straddling the band's lower edge. */
  .page-photo {
    position: absolute;
    left: var(--m-photo-x, 24.26%);
    top: var(--m-photo-y, 60.17cqw);
    width: var(--m-photo-w, 69.44%);
    margin: 0;
  }

  /* --- Body --- */
  .band-body {
    padding-top: 17.5cqw;   /* band end 913 -> section title box 1039 */
    padding-bottom: 13.5cqw; /* panel end 2710 -> gallery rim 2807 */
  }
  .band-body > .wrap { padding-inline: 12.5cqw; } /* copy at x90 */
  .band-body .page-deco { display: none; }
  .section-title {
    margin-bottom: 3.3cqw; /* title last line 1201 -> prose 1225 */
    font-size: clamp(20px, 6.94cqw, 50px);
    line-height: 1;
  }
  .page-cols { gap: 0; }
  .page-prose p {
    font-size: clamp(11px, 3.36cqw, 24px); /* 12.1px: a 32.9 bbox over 1.362 */
    line-height: 1.35; /* 32.5 pitch */
    margin-bottom: 1.32em; /* one blank line between paragraphs */
  }
  /* The quote is not on the mobile artboard (it came with the client's amends);
     it takes the prose measure and drops the desktop wash. */
  .page-quote {
    max-width: none;
    margin: 4.4cqw 0 0;
    padding-top: 0;
    font-size: clamp(11px, 3.36cqw, 24px);
  }
  /* The wash stays a circle: the page's own quote-blob (white -> theme pale),
     150% of the quote's width and centred on it, as the homepage testimonials
     sit on theirs. Centring on the box rather than offsetting from its top
     keeps every page's quote inside the circle whatever its length. */
  .page-quote::before {
    left: -25%;
    top: 50%;
    width: 150%;
    translate: 0 -50%;
  }
  .page-quote p { line-height: 1.35; }

  .service-panel {
    margin: 15.5cqw -5.56cqw 0; /* prose end 1745 -> panel 1857; panel at x50 against copy at x90 */
    border-radius: 4.2cqw;
    padding: 4cqw 5.9cqw 6.4cqw;
  }
  .service-panel h3 {
    margin-bottom: 1.9cqw; /* heading 1997 -> first bullet 2011 */
    font-size: clamp(20px, 6.94cqw, 50px);
    line-height: 1;
  }
  .service-panel ul { padding-left: 3.47cqw; } /* the bullet hangs 25 units left of the text */
  .service-panel li {
    margin-bottom: 1.27em; /* 62-unit bullet pitch: one 31 line + 31 */
    font-size: clamp(11px, 3.39cqw, 24px);
    line-height: 1.27;
  }

  /* --- Gallery band: the pale rim is the band's own background; the themed
         shape starts 42 below the band's top and runs to its end. --- */
  .band-gallery {
    min-height: 0;
    padding-top: 27.9cqw;  /* rim top 2807 -> "Gallery" box 3007 */
    padding-bottom: 9.7cqw; /* last tile 4427 -> band end 4497 */
    background: var(--theme-pale, #f5c1da);
  }
  .band-gallery .band-rim,
  .band-gallery .band-shape,
  .band-gallery .page-deco { display: none; }
  .band-gallery .band-shape-m {
    top: var(--m-gallery-rim, 5.83cqw);
    bottom: 0;
    height: auto;
  }
  .band-gallery > .wrap { padding-inline: 6.94cqw; } /* tiles at x50 */
  .gallery-title {
    margin: 0 0 11cqw 5.9cqw; /* "Gallery" at x92.5; tiles start 3137 */
    padding-top: 0;
    font-size: clamp(20px, 6.94cqw, 50px);
    line-height: 1;
  }
  .gallery-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 6.94cqw; /* 285 tiles on a 335 pitch */
  }
}


/* ===========================================================================
   MOBILE ABOUT — T-064, mobile artboard 3 (720 x 5812 = 360 x 2906 CSS).
   Artboard units / 7.2 = cqw; the artwork is under assets/svg/pages/about/
   mobile/. Bands, top to bottom (artboard y / 2):
     header 0-396 (pale underlay to 430), title 35px at (45,124), photo
     circle 324.5 across at (18,176) over the band's edge; Ethos card
     (25,551) 310 x 238 and History card (25,826) 310 x 252 — no circles on
     mobile; the pale rim of the word band from 1040, its green sweep from
     1055 (curve 1079 -> 1055) to 1687/1527; bio crescent 1517-1731 with the
     200 portrait at (145,1521); Key Team band 2070-2389 (curve 2094 -> 2146)
     over a full-bleed 200 photo band; footer from 2589.
   =========================================================================== */
@media (max-width: 720px) {
  .about-head {
    min-height: 119.37cqw; /* to the pale underlay's end, 859.5 */
    padding-bottom: 0;
    /* Above .about-feature (z-index 1) so the header daisy that hangs into it
       paints on top — decoration rule, docs/layout-rules.md section 5. */
    z-index: 2;
  }
  .about-head .band-underlay,
  .about-head .band-shape,
  .about-head .band-floral,
  .about-head .page-deco { display: none; }
  .m-about-underlay,
  .m-about-band,
  .m-about-arcs,
  .m-about-word,
  .m-about-bio,
  .m-about-team,
  .m-about-team-arcs {
    position: absolute;
    left: var(--bleed-inset);
    width: 100vw;
    max-width: none;
    pointer-events: none;
  }
  .m-about-underlay { top: 0; height: 119.37cqw; z-index: -3; }
  .m-about-band     { top: 0; height: 109.93cqw; z-index: -2; }
  .m-about-arcs     { top: 1.04cqw; height: 98.96cqw; z-index: 0; }
  .about-head .page-head { padding-top: 7.9cqw; }
  .about-head .page-title {
    font-size: clamp(28px, 9.72cqw, 70px);
    line-height: 1;
  }
  /* CLIENT AMEND 2026-09-14 (T-078): both header daisies paint IN FRONT of the
     photo circle. They were `.m-deco { z-index: 0 }` against `.about-hero`'s 1,
     and neither `.about-head` nor `.band` opens a stacking context, so the
     circle clipped them (deco-3 at its top edge, deco-4 at its bottom-right).
     "Above the photo" is paint order, not position: deco-4 sits below the
     circle's centre, so a positional reading is not available for it.
     2 also clears the following `.about-feature` band (z-index 1), which paints
     over this whole section; the header is z-index 6 and still sits on top. */
  /* Now covered by the .m-deco rule (z-index 5); kept as a no-op marker. */

  /* 649 across at (35.5, 353): almost the full width, straddling the curve. */
  .about-hero {
    position: absolute;
    left: 4.93%;
    top: 49.01cqw;
    width: 90.13%;
    margin: 0;
    z-index: 1;
  }

  /* --- Ethos / History: two stacked cards, the circles gone. This section
         runs from the underlay's end (859.5) to the word band's rim (2079). --- */
  .about-feature {
    min-height: 0 !important; /* the inline desktop min-height */
    padding-top: 33.78cqw; /* 859.5 -> 1102.7 */
  }
  .about-feature .circle,
  .about-feature .page-deco { display: none; }
  .about-card {
    position: relative;
    left: auto !important; /* the desktop inline offsets */
    top: auto !important;
    width: auto;
    margin: 0 6.94cqw; /* x50 -> 670 */
    border-radius: 4.86cqw; /* 35 */
    z-index: 1;
  }
  /* The cards are not adjacent siblings (a hidden circle sits between), so the
     second one is addressed as the section's last child.

     CLIENT AMEND 2026-09-14 (T-078) — DEPARTS FROM MOBILE ARTBOARD 3: on the
     artboard the History card overhangs the word band's rim by 38
     (`margin-bottom: -10.7cqw`; the section ended at the rim and the card ran
     on). The client asked for a gap between it and "A word from Andrew", so the
     bottom margin becomes the same 10cqw that separates this card from the
     Ethos one above — the page's own rhythm rather than a new number.

     The space goes below the card rather than above the band on purpose: the
     word band's sweep (`.m-about-word`) is positioned from the band's own top,
     so growing `.about-feature` moves band, sweep and copy together and nothing
     inside the band shifts relative to it. Net effect at ≤720: `.about-word`
     and every band below it (bio, team, footer) move down 20.7cqw. */
  .about-card:last-child { margin: 10cqw 6.94cqw; } /* the 10cqw card rhythm above and below */
  .about-card .card-bg { display: none; }
  .about-card.about-card { background: linear-gradient(90deg, #ae4976, #e665a2); }
  .about-card:last-child { background: linear-gradient(90deg, #357aac, #00caff); }
  .about-card .card-inner { padding: 3.5cqw 5.56cqw 6.4cqw; } /* heading 28 below the top, copy at x92.5, 47 under the last line */
  .about-card h2 {
    margin-bottom: 0.3em;
    font-size: clamp(20px, 6.94cqw, 50px);
    line-height: 1;
  }
  .about-card p {
    font-size: clamp(11px, 3.39cqw, 24px);
    line-height: 1.33;
  }

  /* --- A word from Andrew: the sweep 30.7 below the band top; heading at
         +134 (2214), copy 12.2px white. --- */
  .about-word {
    min-height: 0;
    padding-block: 18.75cqw 4.4cqw; /* 2079 -> heading 2214; signature end 3002 -> bio 3034 */
    /* T-079: WHITE, not the artboard's pale rim. T-064 approximated the rim
       (a ~12-28 crescent hugging the sweep's top curve at the two ends, 1:863)
       with `#e5f3d9` across the whole band, which reads as a flat-topped pale
       rectangle 15-71 tall above the curve — invisible while the History card
       overhung it, obvious once T-078 opened a 10cqw gap there. The artboard
       is white either side of that thin rim, so white is the closer answer
       until a mobile pale shape is extracted (mobile.json has none).
       `#fff` and not `background: none`: the <=900 block above paints a flat
       green ramp here, which would swallow the sweep's top curve entirely. */
    background: #fff;
  }
  .about-word .band-shape,
  .about-word .page-deco { display: none; }
  /* The desktop lift (above .about-bio) is for a desktop-only daisy; here it would
     cover the phone daisy hanging down from .about-feature. */
  .about-word { z-index: auto; }
  /* T-079: the sweep is sized to the BAND, not pinned at the artboard's
     1263.4 (175.47cqw). `band-word.svg` is `preserveAspectRatio="none"`, so it
     stretches. The artboard's sweep runs from 30.7 below the band top to 339.4
     below the bio band's top (2109.7 -> 3373.1 against 2079/3034) — 4.26cqw and
     47.14cqw — but only while the band is the artboard's 955 tall. The live
     copy is longer (an extra body line), so the band runs ~46 (6.4cqw) deeper
     at 360 — it was ~96 (13.3cqw) until the heading folded to the artboard's
     two lines below: at the fixed height the sweep's rising bottom edge crossed
     the sign-off,
     leaving "...ging Director" in #f1c840 on the pale rim, and opened a white
     wedge between the sweep and the bio crescent that the artboard has as one
     green mass. Anchoring the bottom to the band instead keeps both true at any
     copy length; at the artboard's own height it resolves to 175.5cqw, i.e.
     unchanged. */
  .m-about-word { top: 4.26cqw; height: calc(100% + 42.88cqw); z-index: -1; }
  .about-word > .wrap { padding-inline: 12.5cqw; }
  .about-word .about-split h2 {
    font-size: clamp(20px, 6.94cqw, 50px);
    line-height: 1;
    margin-bottom: 3.5cqw; /* 2325.7 -> 2351 */
  }
  /* Two lines here, three on desktop. wordHeading is "A word\nfrom\nAndrew"
     and the heading is rendered with brTextSpaced, which turns each \n into
     " <br /> " — the 1440 comp's three lines, with a space either side of each
     break that the break itself swallows. Mobile artboard 3 sets it as
     "A word / from Andrew", so the second <br /> is dropped here and the two
     lines run on with the space showing through. One Prismic field, both
     artboards the same words, so this is the comp being followed rather than a
     second heading string. Do NOT swap the h2 back to plain brText: without
     the spaces this rule prints "fromAndrew" (a <br> carries no whitespace and
     `content`/`::after` on it are inert in Chrome — both measured). */
  .about-word .about-split h2 br:nth-of-type(2) { display: none; }
  .about-word .about-split .prose p {
    font-size: clamp(11px, 3.39cqw, 24px);
    font-weight: 600;
    line-height: 1.33;
  }
  .about-word .prose strong { font-weight: 600; }

  /* --- Bio: crescent 428 tall from the section top, portrait 400 at (290,
         +8), name at +435, copy from +571. --- */
  .about-bio {
    min-height: 0;
    padding-block: 60.42cqw 6.6cqw; /* 3034 -> name 3469; copy end 4093 -> team 4140 */
  }
  .about-bio .band-shape { display: none; }
  .m-about-bio { top: 0; height: 59.49cqw; z-index: -1; }
  .about-portrait {
    position: absolute;
    left: 40.28%;
    top: 1.15cqw;
    width: 55.56%;
    margin: 0;
    z-index: 0;
  }
  .about-bio > .wrap { padding-inline: 12.5cqw; }
  .about-bio .about-split { gap: 0; } /* the desktop grid's empty first cell */
  .about-bio .prose h3,
  .about-bio .prose .role {
    font-size: clamp(20px, 6.94cqw, 50px);
    line-height: 1;
  }
  .about-bio .prose .role { margin-bottom: 3.3cqw; } /* 3581 -> 3605 */
  .about-bio .about-split .prose p {
    font-size: clamp(11px, 3.39cqw, 24px);
    line-height: 1.33;
    margin-bottom: 1.33em;
  }

  /* --- Key Team: the band 637 tall with its top curve, arcs in the 4154-4559
         window, heading at +112, copy from +200, then the full-bleed photo
         band 400 tall. --- */
  .about-team {
    min-height: 0;
    padding-top: 15.6cqw; /* 4140 -> 4252 */
    background: none;
  }
  .about-team .band-rim,
  .about-team .band-shape,
  .about-team .page-deco,
  .about-team::after { display: none; }
  .m-about-team      { top: 0; height: 88.54cqw; z-index: -1; }
  .m-about-team-arcs { top: 2.03cqw; height: 56.25cqw; z-index: 0; }
  .about-team > .wrap { padding-inline: 12.5cqw; }
  .about-team .about-split h2 {
    font-size: clamp(20px, 6.94cqw, 50px);
    line-height: 1;
    margin-bottom: 3.6cqw; /* 4314 -> 4340 */
  }
  .about-team .prose { margin-top: 0; }
  .about-team .about-split .prose p {
    font-size: clamp(11px, 3.39cqw, 24px);
    line-height: 1.33;
    margin-bottom: 1.33em;
  }
  .about-team-photo {
    width: 100vw;
    height: 55.56cqw; /* the artboard's 400-tall photo band */
    margin: 11cqw 0 0 var(--bleed-inset); /* copy end 4698 -> photo 4777 */
    object-fit: cover;
  }
}


/* ===========================================================================
   MOBILE CONTACT (T-065, artboard 13) and TIPS & ADVICE (T-066, artboard 12).
   Both build their own header band rather than using page-header, so the
   header treatment is restated for their band classes; the page-head rules
   above already apply to them.
   =========================================================================== */
@media (max-width: 720px) {
  .band-contact,
  .band-tips {
    position: relative;
    z-index: 1;
    min-height: var(--m-header-h, 126.78cqw);
    padding-bottom: 0;
  }
  .band-contact .band-shape,
  .band-contact .band-underlay,
  .band-contact .band-floral,
  .band-contact .band-arcs,
  .band-contact .page-deco,
  .band-tips .band-shape,
  .band-tips .band-underlay,
  .band-tips .band-floral,
  .band-tips .band-arcs { display: none; }
  .band-contact::after,
  .band-tips::after {
    content: "";
    position: absolute;
    left: 0;
    width: 100%;
    top: calc(var(--m-header-h, 126.78cqw) - 55.97cqw);
    height: 69.17cqw;
    background: var(--theme-pale, #f5c1da);
    z-index: -2;
    pointer-events: none;
  }

  /* --- Contact: "Where to find us" FIRST, on its pale-blue blob that starts
         225 units up under the header band (y688 -> 1759), then the form. --- */
  .contact-body {
    display: flex;
    flex-direction: column;
    min-height: 0;
  }
  .contact-body .page-deco { display: none; }
  .find-us {
    order: 0;
    position: relative;
    left: auto;
    top: auto;
    width: auto;
    min-height: 0;
    margin: 0;
    padding: 18.9cqw 6.94cqw 0; /* heading box at y1049; copy at x50 */
  }
  .find-us .panel-bg { display: none; }
  .find-us::before {
    content: "";
    position: absolute;
    left: var(--bleed-inset);
    width: 100vw;
    top: -31.25cqw;    /* 688 - 913 */
    height: 148.75cqw; /* 1071 */
    background: url("../assets/svg/pages/contact/mobile/band-findus.svg") center / 100% 100% no-repeat;
    z-index: -1;
    pointer-events: none;
  }
  .find-us h2,
  .contact-form h2 {
    margin-bottom: 3.5cqw;
    font-size: clamp(16px, 5.56cqw, 40px); /* 20px: a 49.6 bbox at 2x */
    line-height: 1.25;
  }
  .find-us .map {
    width: 100%;
    aspect-ratio: 2 / 1;
    margin-bottom: 2.2cqw;
  }
  .find-us dl {
    grid-template-columns: 31.25cqw 1fr; /* labels x50, values x275 */
    row-gap: 1.4cqw;
    font-size: clamp(11px, 3.36cqw, 24px);
  }
  .find-us dt { font-size: clamp(12px, 3.94cqw, 28px); }
  .find-us dd { line-height: 1.35; }
  .find-us dd + dt { margin-top: 0; }
  .contact-body > .wrap {
    order: 1;
    padding-inline: 6.94cqw;
  }
  .contact-cols { padding-block: 8.6cqw 7.2cqw; } /* blob end 1759 -> heading 1792; note end -> footer 3504 */
  .contact-form { width: 100%; }

  /* Fields: 620 x 40 boxes on a 55 pitch in the artboard, label at x64 in
     10.7px bold. Height raised 50% to 60 (AJS, 2026-09-15: too small to tap);
     the pitch gap stays. The "best time" summary matches the fields. */
  .field {
    min-height: 8.34cqw;
    margin-bottom: 2.08cqw;
    padding: 0 1.94cqw;
  }
  .field > label,
  .field .optional,
  .field .hint,
  .field input:not([type="checkbox"]):not([type="radio"]),
  .field textarea,
  .group-label,
  .select-drop summary,
  .dropzone { font-size: clamp(9px, 2.97cqw, 21px); }
  .field-row {
    grid-template-columns: 1fr 1fr;
    gap: 2.22cqw; /* 352 -> 368 */
  }
  .field-row .field { margin-bottom: 2.08cqw; }
  .contact-form fieldset { margin-top: 2.6cqw; }
  .contact-form .opt-list:not(.one-col) {
    display: grid;
    grid-template-columns: 1fr 1fr;
    column-gap: 3cqw;
    row-gap: 0;
  }
  .opt {
    font-size: clamp(9px, 2.7cqw, 19px);
    line-height: 5cqw; /* rows on an 18 pitch */
  }
  /* Circles 50% larger on phones (AJS, 2026-09-15): the desktop rule's 13px
     floor is what a phone gets, too small to tap. 20px, inside the row. */
  .opt input[type="checkbox"],
  .opt input[type="radio"] {
    width: 2.7cqw;
    min-width: 20px;
  }
  .select-drop summary { min-height: 8.34cqw; }
  .field-tall { min-height: 16.67cqw; } /* 120 */
  .field-tall textarea { min-height: 12cqw; }
  .dropzone {
    min-height: 16.67cqw;
    margin: 2.08cqw 0;
    padding: 5.5cqw 1rem;
  }
  .dropzone-files { font-size: clamp(9px, 2.7cqw, 19px); }
  .dropzone-files:not(:empty) { margin-top: 1.5cqw; }
  .contact-form .submit {
    height: 9.72cqw; /* 70 */
    margin-top: 4cqw;
    padding: 0;
    font-size: clamp(11px, 3.39cqw, 24px);
    text-transform: uppercase;
    border-radius: 2cqw;
  }
  /* The row is 418px at 400 wide: label, "(optional)" and the full button
     left the input 81px. Drop the hint (the label carries no asterisk, so
     the field reads as optional) and shorten the button to "Map". */
  .field-btn { font-size: clamp(9px, 2.7cqw, 19px); }
  .field-w3w .optional,
  .field-btn .btn-long { display: none; }
  .field-btn .btn-short { display: inline; }
  .w3w-dialog {
    width: 100vw;
    height: 100dvh;
    margin: 0;
    border: 0;
  }
  .w3w-dialog-head h2,
  .w3w-dialog-hint,
  .w3w-dialog-cancel,
  .w3w-dialog-use,
  .w3w-locate { font-size: clamp(9px, 2.7cqw, 19px); }
  .w3w-dialog-hint.is-words { font-size: clamp(11px, 3.3cqw, 23px); }
  .form-note {
    margin: 3.4cqw 0 0 0.7cqw;
    font-size: clamp(9px, 2.7cqw, 19px);
    font-weight: 300;
  }
  .form-status { font-size: clamp(9px, 2.7cqw, 19px); }
  .form-status:not(:empty) { margin-top: 2cqw; }
  .form-consent {
    margin: 2.4cqw 0 0 0.7cqw;
    font-size: clamp(9px, 2.5cqw, 18px);
  }

  /* --- Tips & Advice: one dropdown for the filter under the title, then the
         (redesigned) cards in one column 310 wide on a 265 pitch. --- */
  .tips-filter {
    flex-direction: column;
    align-items: flex-start;
    gap: 2.5cqw;
    margin-top: 9.6cqw; /* title box end 155 -> label 189.5 */
  }
  .tips-filter .pills { display: none; }
  .tips-filter .filter-label { font-size: clamp(11px, 3.8cqw, 27px); }
  .band-tips .wrap { padding-inline: 12.5cqw; } /* filter at x90 */
  .tips-filter .filter-select {
    display: block;
    width: 69.44cqw; /* 500 */
    height: 6.94cqw; /* 50 */
    padding: 0 8cqw 0 3cqw;
    font: inherit;
    font-size: clamp(9px, 3.39cqw, 24px);
    font-weight: 600;
    color: var(--black);
    background: #f5f5f5 url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' fill='none' stroke='%237dc242' stroke-width='2'/%3E%3C/svg%3E") no-repeat right 3cqw center / 3cqw auto;
    border: 1px solid var(--theme, #607e47);
    border-radius: 999px;
    appearance: none;
    -webkit-appearance: none;
  }
  .band-tips + .band > .wrap { padding-inline: 6.94cqw; }
  .tips-grid {
    grid-template-columns: minmax(0, 1fr);
    row-gap: 4.17cqw; /* 30 */
    padding-block: 20.14cqw 8.6cqw; /* band end 603 -> first card 748; last card -> numerals */
  }

  /* Client 2026-09-14: the card photo sits further right and smaller on
     mobile — left 58.22%, width 37.22% (desktop 43.22% / 43.22%; top -5.48%
     unchanged). Not on the mobile artboard (ISS-023); do not fold back. */
  .tips-card .photo { left: 58.22%; width: 37.22%; }
  .tips-dots { padding-bottom: 7.9cqw; }
}


/* ===========================================================================
   TIPS & ADVICE — filter and paging (ISS-012, ISS-024). The index script
   hides cards outside the current filter/page with the hidden attribute and
   rebuilds the numerals as buttons; both need rules the static markup did not.
   =========================================================================== */
.tips-card[hidden] { display: none; }

/* No article carries the chosen service. */
.tips-grid[data-empty="true"]::before {
  content: "No articles for this service yet.";
  grid-column: 1 / -1;
  padding: 2rem 0;
  font-size: var(--fs-body);
  color: var(--theme, var(--plum));
}

.tips-dots[hidden] { display: none; }

/* The numeral buttons take the li's ring and fill; the li keeps its size. */
.tips-dots li:has(button) {
  padding: 0;
  border: 0;
  background: none;
}
.tips-dots button {
  width: 1.7em;
  height: 1.7em;
  display: grid;
  place-items: center;
  padding: 0;
  font: inherit;
  font-size: inherit;
  font-weight: 600;
  line-height: 1;
  color: var(--theme-light, var(--theme));
  background: none;
  border: 1px solid var(--theme-light, var(--theme));
  border-radius: 50%;
  cursor: pointer;
}
.tips-dots button:hover,
.tips-dots button:focus-visible {
  background: var(--theme-pale, #f5f5f5);
}
.tips-dots button[aria-current="page"] {
  color: var(--white);
  background: var(--theme-light, var(--theme));
}


/* ===========================================================================
   FACEBOOK POSTS — T-067. The comp's three-card carousel (1:141 ff., drawn
   with black thumbs and white captions): 257.1 cards at x 270 / 591.4 /
   912.9 on a 900 track with 64.3 gaps, arrows outside it at 180 and 1220,
   the row starting 203 below the testimonials. It was labelled case studies
   and is the latest Facebook posts. Below 720, mobile artboard 1: one 171
   card centred on its own magenta band (y2197-2955 at 2x) with arcs and two
   daisies, arrows at x30 / x295.
   =========================================================================== */
.fb-posts {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 3.47cqw; /* comp: arrow right edge 220 -> first card 270 */
  margin-top: 13.4cqw; /* comp: testimonials end 1870 -> cards start 2073 */
  margin-inline: max(-0.87cqw, -12.5px); /* arrows sit outside the 1055 column */
}

.fb-track {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(1rem, 4.47vw, 64.3px);
}

.fb-card {
  display: flex;
  flex-direction: column;
  background: var(--white);
  color: var(--black);
  text-decoration: none;
}

.fb-card[hidden] { display: none; }
/* No script: the first page only. */
.fb-posts:not([data-enhanced]) .fb-card:nth-child(n + 4) { display: none; }

.fb-card .thumb {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 1;
  object-fit: cover;
  background: #000;
}

/* The comp's white strip under the thumb, 80 tall: date and two lines. */
.fb-card .caption {
  display: block;
  height: clamp(48px, 5.6vw, 80px);
  padding: 0.55cqw 0.9cqw;
  overflow: hidden;
}

.fb-card time {
  display: block;
  font-size: var(--fs-ui);
  font-weight: 600;
  line-height: 1.4;
  color: var(--magenta);
}

.fb-card .text {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  font-size: var(--fs-ui);
  font-weight: 300;
  line-height: 1.35;
}

.fb-card:hover .text,
.fb-card:focus-visible .text { text-decoration: underline; }

.carousel-btn {
  position: relative;
  width: 40px;
  height: 40px;
  flex: none;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
}

.carousel-btn[hidden] { display: none; }

/* Ring and chevron are separate vectors; the ring alone is an empty circle. */
.carousel-btn img { position: absolute; }
.carousel-btn .btn-ring { left: 0; top: 0; width: 40px; height: 40px; }
.carousel-btn .btn-chevron { top: 14.2px; width: 5.9px; height: 11.7px; }
.carousel-prev .btn-chevron { left: 15.8px; }
.carousel-next .btn-chevron { left: 18.3px; }
.carousel-btn:focus-visible { outline: 2px solid var(--white); outline-offset: 3px; border-radius: 50%; }

.m-posts-band,
.m-posts-arcs,
.m-posts-daisy { display: none; }

@media (max-width: 720px) {
  /* The block bleeds to the full width and carries the artboard's band; the
     testimonials circle above overlaps its top as drawn. Band 758 tall at 2x
     (379): card at +119, arrows at +216.5, 35 under the card. */
  .band-main { padding-bottom: 0; }
  .fb-posts {
    display: block;
    margin: 9cqw -12.5cqw 0;
    padding: 33cqw 0 9.7cqw;
  }
  .m-posts-band,
  .m-posts-arcs {
    display: block;
    position: absolute;
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
    pointer-events: none;
  }
  .m-posts-band { z-index: -1; }
  .m-posts-arcs { z-index: 0; }
  .m-posts-daisy {
    display: block;
    position: absolute;
    z-index: 0;
    height: auto;
    pointer-events: none;
  }
  .m-posts-daisy-1 { left: 8.19%; top: 81.25cqw; width: 14.72%; }  /* (59, 2782) 106 wide */
  .m-posts-daisy-2 { left: 81.81%; top: 37.08cqw; width: 8.61%; }  /* (589, 2464) 62 wide */
  .fb-track {
    display: block;
    position: relative;
    z-index: 1;
    width: 47.5cqw; /* 342 / 720 */
    margin-inline: auto;
  }
  .fb-posts:not([data-enhanced]) .fb-card:nth-child(n + 2) { display: none; }
  .fb-card .caption {
    height: 14.86cqw; /* 107 / 720 */
    padding: 1.5cqw 2.5cqw;
  }
  .fb-card time,
  .fb-card .text { font-size: clamp(9px, 2.7cqw, 19px); }
  .carousel-btn {
    position: absolute;
    z-index: 2;
    top: 60.14cqw; /* (2630 - 2197) / 7.2 */
    width: 35px;
    height: 35px;
    scale: 0.875; /* the 40px ring at the artboard's 35 */
    transform-origin: top left;
  }
  .carousel-prev { left: 8.33cqw; }
  .carousel-next { right: 8.33cqw; transform-origin: top right; }
}


/* ===========================================================================
   MOBILE TIPS & ADVICE ARTICLES (<= 720). No mobile artboard for these: the
   header is the index's mobile band (603 at 2x, inline and themed in
   tips-band.html) and the body stacks — back link, the photo centred, NUMBER,
   title, prose — at the service template's measure (copy at x45, 12.2px on a
   16.25 pitch, 25px display headings).
   =========================================================================== */
@media (max-width: 720px) {
  .band-page.band-article-head {
    --m-header-h: 83.75cqw;  /* 603 */
    --m-arcs-top: 27.08cqw;  /* 195 */
    --m-arcs-h: 56.25cqw;    /* 405 */
    min-height: var(--m-header-h);
  }
  .band-article-head .band-shape,
  .band-article-head .band-underlay,
  .band-article-head .band-floral,
  .band-article-head .band-arcs { display: none; }

  .band-article {
    padding-top: 6cqw;
    padding-bottom: 8cqw;
  }
  .band-article > .wrap { padding-inline: 12.5cqw; }
  .tips-back { font-size: clamp(11px, 3.06cqw, 16px); }
  .article-leaf {
    left: 56%;
    top: 20cqw;
    width: 44%;
  }
  .article-body {
    grid-template-columns: minmax(0, 1fr);
    padding-top: 5cqw;
  }
  .article-photo {
    order: -1;
    width: 55.56cqw; /* 200: the About portrait's mobile size */
    margin: 0 auto 6cqw;
    position: relative;
    z-index: 1;
  }
  .article-num { font-size: clamp(9px, 2.97cqw, 21px); }
  .article-title {
    font-size: clamp(20px, 6.94cqw, 50px);
    line-height: 1.1;
  }
  .article-prose { margin-top: 3cqw; }
  .article-prose p,
  .article-prose li {
    font-size: clamp(11px, 3.36cqw, 24px);
    line-height: 1.35;
  }
}
