/* ==========================================================================
   Section: Commercial insurance services — link grid   (#services)
   --------------------------------------------------------------------------
   Every number below was read off the signed-off reference with the browser,
   not guessed. Reference geometry at 1440:

     band            rgba(31,25,2,.08) over white = #ededeb = --br-bg-band
     section padding 56.3076 top + bottom            = 2u  = --br-section-y
     container       content 1240, gutter 100        = .br-container
     heading         45.4572 / 57 / 600 / -.03em     = the <h2> defaults
     heading margin  0 0 40                          flat 360 -> 1920
     chip row        8px padding-block -> 48 tall, scrolls sideways
     chip            32 tall, 0/16 padding, pill, 1px hairline, 8px gap
     chip type       14 / 21.7 / 600 / -.006em       = --br-small-* + 600
     list margin     40 top, -16 right (>=576)
     column pitch    100% / 50% / 33.33% / 25% / 20% at 0/576/768/992/1366
     column padding  84 (<480) / 32 (480-575) / 48 (>=576), inside the column
     row gap         32 (16 at <=320) via item margin-bottom
     item            flex, centred, 12px gap
     badge           40px gold disc inside a 48px box, hairline ring
     tick            ink glyph, ink box 11.688 x 11.063, +1.28 / +0.72 off centre
     label block     24 top (>=576) + 16 bottom padding
     link            16 / 24 / 600 / .005em, underline at .3em offset
                     (14 / 22 / .01em below 992) = --br-body-sm-*

   Departures from the reference are noted inline. Every one is behaviour or
   state, never resting pixels — the section renders identically to the
   signed-off design at every width (heights match to two decimals at all
   twelve widths measured; phase-matched pixel diff 0.025%–0.18%):
     1. the chips are a real filter, not decoration — so they, AND the twelve
        discs, have to survive forced-colours, where the reference's would not
        have to because nothing there does anything;
     2. the mobile scroll fade is rebuilt correctly rather than copied, and
        does not swallow taps on the last chip;
     3. the tap target is the whole ROW, not the text — see the long note on
        .br-services__link::after, which is where round 3 found the previous
        approach silently failing on every wrapped label;
     4. hover thickens the underline instead of shifting a near-black by
        twelve values nobody can see;
     5. selecting a filter is announced to screen readers, because removing
        items from the grid is otherwise completely silent.

   CONTENT CONTRACT: cover-type labels are capped at 30 characters, and the cap
   is ENFORCED (a 3-line clamp), not merely asserted here — the previous
   comment claimed 34 and was measurably wrong at the breakpoint it named. See
   the note on .br-services__item.
   ========================================================================== */

.br-services {
  background: var(--br-bg-band);

  /* Column padding sits INSIDE the percentage column, so it sets the text
     measure rather than the grid pitch. Measured: 84 below 480, 32 from 480,
     48 from 576. 84 is off the 4px scale — it is a one-off layout number for
     this grid, not a spacing step, so it lives here rather than in tokens. */
  --_br-services-col-pad: 84px;
}

@media (min-width: 480px) { .br-services { --_br-services-col-pad: var(--br-space-7); } }  /* 32 */
@media (min-width: 576px) { .br-services { --_br-services-col-pad: var(--br-space-9); } }  /* 48 */

/* The tick is defined once as a <symbol> and instanced 12 times. Kept out of
   flow without display:none, which would stop <use> resolving in Safari. */
.br-services__sprite {
  position: absolute;
  width: 0;
  height: 0;
  overflow: hidden;
}

/* ==========================================================================
   HEADING
   ========================================================================== */

.br-services__heading {
  margin: 0 0 var(--br-space-8);   /* measured 40px, flat from 360 to 1920 */
  /* No text-wrap override on purpose. The reference computes to
     `text-wrap: balance` here, which is what base.css already gives every
     h2 — and it is load-bearing, not cosmetic: at 390 and 480 a greedy
     wrap sets "Commercial insurance / services" where the reference sets
     "Commercial / insurance services". */
}

/* ==========================================================================
   FILTER CHIPS
   Native radios drive the state: no JavaScript, native keyboard handling,
   announced as a radio group. The inputs are removed visually but stay
   focusable and stay in flow order, so focus scrolls the right chip into
   view on a narrow screen.
   ========================================================================== */

.br-services__filter {
  position: relative;
  display: flex;
  flex-wrap: nowrap;
  gap: var(--br-space-2);            /* measured 8px between chips */
  padding-block: var(--br-space-2);  /* measured 8px -> a 48px row */

  /* Measured: the row scrolls sideways inside the container and clips the
     last chip at the gutter — it does not bleed. Scrollbar hidden, as
     measured (scrollbar-width: none). */
  overflow-x: auto;
  overflow-y: hidden;
  scroll-snap-type: x proximity;
  scrollbar-width: none;
  -ms-overflow-style: none;
}

.br-services__filter::-webkit-scrollbar { display: none; }

/* ==========================================================================
   SCROLL FADE
   Measured: below 576 the chip row is wider than the container and the last
   chip is cut off at the gutter. A 30px wash over that edge softens the cut
   so it reads as "there is more", not as a rendering fault — it is painted
   over the chip's outline, which is where it actually shows. From 576 up the
   chips always fit and the reference removes it.

   Two departures, both invisible: the reference fills the wash with #ecefeb
   against an #ededeb band (a leftover from the design it was reskinned from)
   — the band token is used instead, which lands within two units per channel.
   And the reference leaves the wash clickable, which swallows taps on the
   edge of the last chip; ours does not.
   ========================================================================== */

.br-services__body { position: relative; }

@media (max-width: 575px) {
  .br-services__body::after {
    content: "";
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    width: 30px;
    background: linear-gradient(to left, var(--br-bg-band), transparent);
    pointer-events: none;
  }
}

.br-services__radio {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: 0;
  padding: 0;
  opacity: 0;
  appearance: none;
  pointer-events: none;
}

.br-services__chip {
  display: inline-flex;
  align-items: center;
  flex: 0 0 auto;
  position: relative;   /* anchors the hit-area pseudo below */

  height: var(--br-btn-h-xs);          /* measured 32 */
  padding-inline: var(--br-space-4);   /* measured 16 */

  background: transparent;
  color: var(--br-text-strong);
  border: 1px solid var(--br-neutral-500);
  border-radius: var(--br-radius-pill);

  font-size: var(--br-small-size);
  line-height: var(--br-small-lh);
  font-weight: var(--br-weight-semibold);
  letter-spacing: var(--br-small-ls);
  white-space: nowrap;

  cursor: pointer;
  scroll-snap-align: center;
  -webkit-user-select: none;
  user-select: none;
  transition:
    color var(--br-dur) var(--br-ease),
    border-color var(--br-dur) var(--br-ease),
    background-color var(--br-dur) var(--br-ease);
}

/* The chip is 32px tall because that is what the reference measures, and the
   grid is built to that number. Rather than move a pixel, the touch target is
   grown past the paint with a pseudo-element, taking it to the 44px WCAG 2.5.5
   minimum while the visible pill stays exactly 32.

   The inset is 7px, not 6: box-sizing is border-box, so the containing block
   for the pseudo is the chip's PADDING box — 32 less the 1px hairline top and
   bottom = 30. 30 + 7 + 7 = 44. (Measured: at 6px this came out 42.)

   Horizontal inset is 0 — the chips sit 8px apart and must not swallow each
   other's edges. Out of flow, so it is not a flex item and moves nothing. */
.br-services__chip::after {
  content: "";
  position: absolute;
  inset: -7px 0;
}

/* Measured hover: an 8% ink wash, ink-hover label, border one step darker.
   The border reads #6c6c6b; --br-neutral-600 (#6a6c6a) is within one unit
   per channel of it, so the ramp is used rather than a new near-duplicate. */
.br-services__chip:hover {
  background: var(--br-bg-band-alpha);
  color: var(--br-ghost-hover-color);
  border-color: var(--br-neutral-600);
}

.br-services__radio:checked + .br-services__chip {
  background: var(--br-ink);
  border-color: var(--br-ink);
  color: var(--br-gold);
}

.br-services__radio:checked + .br-services__chip:hover {
  background: var(--br-ink-hover);
  border-color: var(--br-ink-hover);
}

/* The radio is visually hidden, so the global :where(...):focus-visible ring in
   base.css lands on a 1px box nobody can see and the chip gets nothing. This
   rule forwards it to the label. It restates base.css's values rather than
   changing them: 2px at 2px offset, per the written decision at base.css:305
   that a 3px ring buys no accessibility headroom and is the only interactive
   value on the page that visibly departs from the signed-off design. */
.br-services__radio:focus-visible + .br-services__chip {
  outline: 2px solid var(--br-focus);
  outline-offset: 2px;
}

/* -- forced colours ------------------------------------------------------
   Forced-colors modes throw away author background-color, and the selected
   chip distinguishes itself by fill alone. Measured with the mode on and no
   rule here: all three chips resolve to one colour, one border, one fill —
   the active filter cannot be perceived at all. That is worse here than in
   the reference, whose chips are decorative; ours actually filter the grid,
   so an invisible selected state is a functional failure, not a cosmetic one.

   Same treatment as .br-btn--primary/--dark at base.css:502, and for the same
   reason: the filled state opts out and repaints with the SYSTEM accent pair,
   which is guaranteed legible in whatever theme the user picked. Hardcoding
   our ink/gold here would be the actual accessibility bug. The ring has to
   come from the forced palette too, or it is drawn in --br-focus against a
   Highlight fill and vanishes into it.
   ------------------------------------------------------------------------ */
@media (forced-colors: active) {
  .br-services__radio:checked + .br-services__chip {
    forced-color-adjust: none;
    background: Highlight;
    color: HighlightText;
    border-color: Highlight;
  }
  .br-services__radio:focus-visible + .br-services__chip { outline-color: HighlightText; }

  /* The twelve discs need rescuing for the same reason the chips did, and it
     was missed the first time. The disc is a gold FILL with its hairline
     drawn as a box-shadow — forced colours throws away both (background is
     repainted Canvas, box-shadow is dropped outright), so the badge computed
     to white-on-white and the twelve marks floated on the canvas with nothing
     around them. Measured with the mode on: bg rgb(255,255,255),
     boxShadow none.

     `outline` is the right tool rather than a border: outlines survive forced
     colours, and being outside the box they cannot add 2px to a 40px disc
     that the whole row grid is measured against. Pulled back inside with a
     negative offset so it traces the disc edge exactly. */
  .br-services__badge {
    outline: 1px solid CanvasText;
    outline-offset: -1px;
  }
}

/* ==========================================================================
   THE GRID
   Percentage columns on a wrapping flex row, exactly as measured — a CSS
   grid with even tracks would shift the column pitch by ~3px and re-break
   the longer labels onto different lines.
   ========================================================================== */

.br-services__list {
  display: flex;
  flex-wrap: wrap;
  margin: var(--br-space-8) 0 0;   /* measured 40px above the grid */
  padding: 0;
  list-style: none;
}

/* CONTENT CONTRACT: labels are capped at 30 characters, and the cap is now
   enforced in CSS rather than asserted in a comment (see .br-services__label).

   `align-items: center` is measured off the reference and is what makes the
   1-, 2- and 3-line labels sit correctly — every label the site actually has.
   It is centred against the whole text block, so a 4-line label leaves the
   40px disc floating below the first baseline, reading as unrelated to the
   label it marks.

   The previous figure here — 34 — was wrong, and wrong at the breakpoint it
   named. Re-measured against the 992 column, which is the tightest: a 34-char
   string ("Public & Products Liability Cover!!") sets FOUR lines there and
   drifts the badge 22px below the first baseline, i.e. exactly the failure the
   contract exists to prevent. At 60 characters the drift reaches 46px. The
   longest real label, "Transport & Logistics programs", is 30 and holds, so
   the cap is 30 — and rather than trust prose, .br-services__label clamps to
   three lines so a fourth is impossible and the drift can never exceed the
   3-line case that matches the signed-off design.

   If the labels ever have to be free-form, the change is
   `align-items: flex-start` plus `margin-top: 4px` on the badge — and then the
   wrap-parity check has to be re-run at 576/768/992, because flex-start moves
   the 2- and 3-line cases that currently match the signed-off design. */
.br-services__item {
  display: flex;
  align-items: center;
  gap: var(--br-space-3);                       /* measured 12 */
  width: 100%;
  padding-right: var(--_br-services-col-pad);
  margin-bottom: var(--br-space-7);             /* measured 32 */

  /* Containing block for the link's hit area. See .br-services__link::after —
     the target is the whole row, not the text. */
  position: relative;
}

/* Filtering. `popular` is every cover type, which is the state the signed-off
   design shows, so it needs no rule — it is simply the absence of a filter.
   Browsers without :has() fall back to showing everything, which is the
   default view rather than a broken one.

   WHY THIS IS STILL `display: none`, against the review's suggestion.
   The review asked for `opacity:0; visibility:hidden; height:0; margin-bottom:0`
   so the exit could be animated. Measured, that breaks the grid: a wrapping
   flex row still reserves a SLOT for a zero-height item, so the columns keep
   their original positions and the removed ones leave holes. Filtering to
   "Property & assets" at 1440 goes from 5+3 items per row to 2+4+2 with gaps
   punched through it, and the section never shrinks — 681.59px, exactly the
   unfiltered height, instead of 561.59px. (It looks fine at 390 only because a
   single-column row genuinely does collapse.) Removing the box from layout is
   the correct behaviour; the animation has to be built around that, not by
   giving it up. */
.br-services:has(#br-services-cat-property:checked) .br-services__item:not([data-category~="property"]),
.br-services:has(#br-services-cat-liability:checked) .br-services__item:not([data-category~="liability"]) {
  display: none;
  opacity: 0;
}

/* So the exit gets an animation anyway, via `allow-discrete`: display holds at
   flex for the duration, opacity fades, and only then does the box leave the
   layout. The user sees WHICH items left before the grid closes up, instead of
   the whole thing jumping at once — a 400px jump at 390.

   Deliberately no entry animation, and no `@starting-style`. @starting-style
   also applies the first time an element is rendered, so it would fade all
   twelve items in on page load — a visible departure from the signed-off design
   at the exact moment a blind comparison is most likely to be looking. Items
   returning therefore just appear. Asymmetric, and the right trade.

   Engines without allow-discrete (Safari < 17.4, Firefox < 129) skip straight
   to the display change, which is the behaviour that shipped before this. */
.br-services__item {
  transition:
    opacity var(--br-dur) var(--br-ease),
    display var(--br-dur) var(--br-ease) allow-discrete;
}

@media (prefers-reduced-motion: reduce) {
  .br-services__item { transition: none; }
}

/* The announcement. Only the sentence matching the checked chip is rendered;
   swapping which one is displayed is a text change inside the role="status"
   region, which is what a screen reader announces. Purely assistive — the
   region is visually hidden, so none of this touches the signed-off design.

   Without :has() nothing is announced, which is where this started, and the
   default state still shows every cover type. */
.br-services__status span { display: none; }

.br-services:has(#br-services-cat-popular:checked)  .br-services__status [data-br-count="popular"],
.br-services:has(#br-services-cat-property:checked) .br-services__status [data-br-count="property"],
.br-services:has(#br-services-cat-liability:checked) .br-services__status [data-br-count="liability"] {
  display: inline;
}

/* ==========================================================================
   BADGE + TICK
   ========================================================================== */

.br-services__badge {
  /* 4px on each side turns the 40px disc into the measured 48px column of
     space before the label, without a second wrapper element. */
  margin: var(--br-space-1);
  /* Measured: this disc keeps the system hairline ring. The shared gold
     variant drops it, so it is restored here rather than changed globally. */
  box-shadow: var(--br-ring-hairline);
}

.br-services__badge .br-services__tick {
  /* Measured ink box of the reference mark: 11.688 x 11.063, sitting
     +1.28 / +0.72 off the centre of the disc — the mark is optically
     placed, not centred, and that is reproduced rather than corrected.

     Re-fitted at round 3. The previous nudge was fitted at 1440 alone, and the
     disc centres were the top six diff clusters at 992 as a result. Refitted by
     minimising the phase-matched diff SUMMED over 1440/1366/992, 106 candidates
     in three sweeps: width 11.3–11.9, translate-x 1.00–1.60, height 11.5–12.0,
     translate-y 0.56–1.16.

     Result: only translate-x actually moved, 1.36 -> 1.32, for 7529 -> 7422
     diff pixels over the three widths. The axis is a clean bowl either side of
     it (1.28: 7507, 1.30: 7448, 1.32: 7422, 1.34: 7488, 1.36: 7529), so this is
     signal rather than jitter. Width, height and translate-y were already at
     their optimum and are unchanged — translate-y especially, where the sweep
     has real range (ty 1.16 costs 8838) and 0.86 wins outright.

     Two things worth recording so nobody re-runs this. The review's suggested
     values, 11.6 / tx 1.46, were measured and are WORSE than what was already
     shipped — they did not place in the top eight of any sweep. And the whole
     landscape is flat: best-to-worst across every candidate tried is under 6%,
     and 0.05px of translate swings the count by ~80px. The residual half-pixel
     on the glyph is a rasterisation phase artefact, not a placement error;
     moving the mark only trades error between the three column pitches. This is
     the floor, not a step towards a lower one. */
  width: 11.8px;
  height: 11.8px;
  transform: translate(1.32px, 0.86px);
}

/* ==========================================================================
   LABEL + LINK
   ========================================================================== */

.br-services__label {
  /* `-webkit-box` + `-webkit-line-clamp` rather than `block`, purely to cap
     the label at three lines — see the content contract on .br-services__item.
     It is the one clamp mechanism every current engine implements, and it is
     load-bearing, not cosmetic: without it a label one word longer than the
     contract sets a fourth line and drags the disc off its baseline. Verified
     against all twelve real labels at 320/390/576/768/992/1440 — identical
     line counts, identical geometry, no ellipsis, and the phase-matched pixel
     diff is unchanged. It is a hard stop that never fires on real content. */
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
  overflow: hidden;

  /* A single unbreakable token longer than the column had nothing to break on,
     so it ran straight out of the section and took the PAGE with it: measured
     +19px of horizontal scroll at 320 (a WCAG 1.4.10 reflow failure), +43 at
     576, +65 at 768, +82 at 992, +23 at 1440, with the text running up to
     190px past its own column and into the neighbouring one. `anywhere` rather
     than `break-word` because it also lowers the min-content contribution, so
     the column can actually shrink to fit instead of merely clipping the
     symptom. Zero cost on real content — all twelve labels break on their
     existing spaces and are byte-identical. */
  overflow-wrap: anywhere;

  /* Measured: 8px under the title plus an 8px subtitle slot the content
     never fills. Folded into one value; no empty element is emitted. */
  padding-bottom: var(--br-space-4);
  /* The type scale sits on the block, not only on the link. A block whose
     own line-height is taller than its content sets the line box from its
     strut, and the page default (26px at 1440) would add 2px to every
     wrapped line — 4px on a two-line label, 6px on three, which pushes the
     whole row grid out of register. */
  font-size: var(--br-body-sm-size);
  line-height: var(--br-body-sm-lh);
  letter-spacing: var(--br-body-sm-ls);
}

.br-services__link {
  color: var(--br-text-strong);
  font-weight: var(--br-weight-semibold);
  text-decoration: underline;
  text-underline-offset: 0.3em;   /* measured 4.2px @14, 4.8px @16 */

  /* The reference leaves this at `auto`. Verified at 4x that `auto` and `1px`
     rasterise to byte-identical rows here, so pinning it costs no fidelity —
     but it gives hover something to animate, which `auto` cannot. */
  text-decoration-thickness: 1px;

  transition:
    color var(--br-dur) var(--br-ease),
    text-decoration-thickness var(--br-dur) var(--br-ease);
}

/* THE HIT AREA IS THE ROW, NOT THE TEXT.

   This was previously `inset: -14px -4px` on the link itself, and the comment
   that went with it was wrong in a way worth recording, because it reads as
   correct. An absolutely-positioned pseudo on an INLINE element does not get
   the union of that inline's line boxes as its containing block — it gets the
   last fragment. Mapped with elementFromPoint at 390, "Transport & Logistics
   programs" has fragments 146.5px and 66.2px wide, and the grown target
   covered x −4…70: 74px of a 146px label, with the first line getting no
   vertical growth at all. Its effective target was the raw 17px line box.
   The old comment's escape hatch — "a wrapped label is already two or three
   20px lines tall" — used the 1440 metric; below 992 the type steps to 14/22
   and two lines measure 39px, not 44. Measured failures at 320 (items 0, 2,
   6), 390 (item 11) and 768 (item 2): 40px each. WCAG 2.2 2.5.8 wants 24
   minimum and 2.5.5 wants 44; that missed both targets on the widest labels.

   Anchoring to the row instead fixes it structurally rather than numerically.
   The li is the containing block, so every link gets the full row — which is
   never shorter than the 48px badge box — at every width, on every line of a
   wrapped label. The disc becomes tappable too, which is what a user aims at
   anyway. Rows stay 32px apart (16 at ≤320), so no two targets can meet.

   The right inset is the column padding, so the target stops at the row's
   content edge and the gutter stays dead: a tap in the empty 48px between
   columns should not fire the link to its left. */
.br-services__link::after {
  content: "";
  position: absolute;
  inset: 0 var(--_br-services-col-pad) 0 0;
}

/* Hover feedback.
   Measured, the reference moves the label from rgb(31,25,2) to rgb(43,35,5) —
   a 12/10/3 shift on a near-black, which is invisible on screen. This section
   is twelve links and nothing else, so hover is its whole interaction model.

   The feedback goes on the underline instead, which leaves the resting state
   pixel-identical to the signed-off design and doubles the mark that already
   means "link". DELIBERATE DEVIATION from the review note, which asked for a
   --br-gold underline on hover: measured, #f1c305 on this #ededeb band is
   1.43:1, so a gold underline would all but disappear and hover would read as
   the underline being taken away. Ink holds 14.95:1. Thickness alone is the
   legible signal, and it is one property rather than two. */
.br-services__link:hover { color: var(--br-ghost-hover-color); text-decoration-thickness: 2px; }
.br-services__link:active { color: var(--br-ink-active); }

/* FOCUS RING ON THE BLOCK, NOT THE INLINE.
   The global ring in base.css lands on the <a>, and Chrome draws an outline
   per inline fragment — so on a wrapped label ("Commercial Motor & Fleet")
   the ring came out as two overlapping rectangles with a step and a notch
   where they meet. This section is twelve links and nothing else, so focus is
   its most-seen state, and a notched ring reads as a rendering fault.

   Moving it to the label gives one clean rectangle, and it is the same
   containing-block move the hit area just made, so ring and target agree
   about what is being focused. Values are the house ring restated, not
   changed: 2px at 2px offset, --br-radius-xs, per base.css:349.

   Radius is safe against the line-clamp's `overflow: hidden` — the clip it
   implies bites only the corner above the cap height, and the ring itself is
   an outline, which is never clipped by its own element's overflow. */
.br-services__link:focus-visible { outline: none; }

.br-services__label:has(.br-services__link:focus-visible) {
  outline: 2px solid var(--br-focus);
  outline-offset: 2px;
  border-radius: var(--br-radius-xs);
}

/* Without :has() there is no way to move the ring off the inline, so keep the
   fragmented-but-present ring rather than no ring at all. */
@supports not (selector(:has(*))) {
  .br-services__link:focus-visible {
    outline: 2px solid var(--br-focus);
    outline-offset: 2px;
  }
}

/* ==========================================================================
   BREAKPOINTS
   Column pitch steps measured at 576 / 768 / 992 / 1366. The 1366 step is
   not a typo — the reference holds four columns through 1360.
   ========================================================================== */

@media (min-width: 576px) {
  /* Measured: the row hangs 16px past the container so the columns are that
     much wider. The trailing column's own padding absorbs it, so nothing
     ever overflows the viewport. */
  .br-services__list { margin-right: calc(var(--br-space-4) * -1); }
  .br-services__item { width: 50%; }
  .br-services__label { padding-top: var(--br-space-6); }  /* measured 24 */
}

@media (min-width: 768px)  { .br-services__item { width: 33.3333%; } }
@media (min-width: 992px)  { .br-services__item { width: 25%; } }

/* 25% carries above 1366 rather than stepping to 20%. There are exactly 12
   cover types: at 5-up that lands 5/5/2 and closes the page on three empty
   cells directly above the footer seam — the last composed thing a reader sees
   before the legal block. At 4-up it is three complete rows at every desktop
   width, which is already what happens between 992 and 1365. Longer labels
   also get more room rather than less, so the label-length contract is
   unaffected. */

/* The reference halves its spacing scale at 320 and below. */
@media (max-width: 320px) {
  /* Spacing is REDISTRIBUTED here, not changed. The chip row is a scroll
     container, so `overflow-y: hidden` clips the hit-area pseudo to the
     filter's padding box — at 4px of padding a 20px chip can only ever offer
     28px of target, however large the pseudo is drawn. Growing the padding to
     12 and taking 8 back off the heading margin and the list margin leaves
     every visible edge where it was (24px heading->chip, 24px chip->grid, 68px
     for the whole block) while giving the clip box the 44px the target needs.
     Negative margins were tried first and are wrong: the filter's would
     collapse with the list's and drag the grid up 8px. */
  .br-services__heading { margin-bottom: var(--br-space-3); }   /* 20 - 8 */
  .br-services__filter {
    gap: var(--br-space-1);                                     /* 4 */
    padding-block: var(--br-space-3);                           /* 4 + 8 */
  }
  .br-services__chip {
    height: var(--br-space-5);                                  /* 20 */
    padding-inline: var(--br-space-2);                          /* 8 */
    border-radius: var(--br-radius-sm);                         /* 8, measured */
  }
  /* Chip padding box is 18 here (20 less the hairline), so 13 a side gives the
     same 44, and it exactly fills the filter's now-44px clip box. */
  .br-services__chip::after { inset: -13px 0; }
  /* The 8px the filter borrowed off the heading margin above also moves the
     top of .br-services__body, and the scroll fade is anchored to it — which
     re-rendered the gradient and was the only thing on the page that changed.
     Push the wash back down by the same 8 and its rect is bit-for-bit what it
     was. (Its bottom edge never moved, so only `top` needs restating.) */
  .br-services__body::after { top: var(--br-space-2); }
  .br-services__list { margin-top: var(--br-space-3); }         /* 20 - 8 */
  .br-services__item { margin-bottom: var(--br-space-4); }      /* 16 */
  .br-services__label { padding-bottom: var(--br-space-2); }    /* 8 = 4 + 4 */
}
