/* ==========================================================================
   6 — HEAR FROM OUR MEMBERS
   R8z — CARD GRID, by direction, from a supplied reference. 3 × 2 cards on
   the black page ground, each --color-surface-panel, heading centred.

   ⚠⚠ WHAT THIS COSTS. Read design-rules R8z before extending it.

     · §16: "narrative sections (3–7) as cards — NEVER". This is a card grid
       in a narrative section. Not an edge case; the rule has no reading that
       admits it.
     · §16 also caps card-based sections at THREE page-wide. §4, §10 and §11
       were the three. This is the fourth — the cap is exceeded, not met.
     · §15 permits ZERO consecutive sections sharing a layout pattern. Built 5
       (What Makes Us Different) is uncontained thirds and this is thirds.
       Contained vs uncontained is not a different pattern for this purpose:
       the reader sees three columns twice running. This is §15's first live
       violation since R6m, and the fixes are the same shape — change one of
       the two patterns, or put a section between them.

   WHAT THIS REPLACED. A staggered offset column whose spec read: "no quote
   marks, no avatars, no containers — the offset is the device." All three are
   reversed and the offset is gone. Nothing of the old section survives except
   its closing space, below.
   ========================================================================== */

/* R14j — the eyebrow is an inline-flex box inside a centred flex column, so
   it already sits on the centre line; this only stops the <p> stretching to
   the column's full width and taking the frame with it. */
/* R15c — the 7-5 head is withdrawn. .members__head, .members__head-lede and
   .members__sub are deleted: R14k added them for a left-aligned head with a
   right-hand subtext, R14l removed the subtext, and this returns the section
   to .section__title--center, which every other head on the page uses.

   The eyebrow rule stays — it is an inline-flex box, and this is what stops
   the <p> stretching to the column's full width and taking the frame with it.
   .section__title--center does the centring. */
.members__eyebrow { display: flex; }

/* ==========================================================================
   R13x — THE VIDEO ROW. Two cards above the text grid.

   HALVES, WHERE THE GRID BELOW IS THIRDS. That is deliberate and it is what
   keeps §15's adjacency rule from getting worse: the section already repeats
   §5's thirds (see R8z), and a second row of thirds directly above would have
   made the repetition internal as well as consecutive. Two-up reads as a
   different object from three-up.

   3:2, THE PLACEHOLDER FAMILY'S OWN RATIO. The reference's cards are nearer
   5:3 and a video still is natively 16:9 — so ⚠ WHEN THE STILLS LAND THEY WILL
   CROP, losing roughly 16% of the frame's width. 3:2 is chosen over 16:9
   because the card has to hold a pull-quote and an attribution, and at 16:9
   the two collide at any width below about 600px.
   ========================================================================== */
.members__videos {
  display: grid;
  gap: var(--gap-grid);
  list-style: none;
  margin: 0;
  /* ⚠ margin-block-start MUST FOLLOW THE `margin: 0` SHORTHAND, and it is not
     decoration. layout.css sets `.section__title + *` to the
     heading-to-content interval, and this list IS that adjacent sibling — but
     `margin: 0` here resets all four sides, this stylesheet loads after
     layout.css, and both selectors are (0,1,0), so the shorthand won and the
     gap vanished. It was masked for months by a style="" attribute in the
     markup; removing that attribute at R17i is what exposed it.

     The shorthand still has to stay — it is what clears the UA's default <ul>
     margin. The longhand after it re-supplies the one side that is wanted. */
  margin-block-start: var(--gap-heading-to-content);
  padding: 0;
}

@media (min-width: 768px) {
  .members__videos { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

.members__video {
  position: relative;
  isolation: isolate;
  display: grid;
  align-content: space-between;
  gap: var(--space-lg);
  aspect-ratio: 3 / 2;
  padding: var(--gap-card-padding);
  overflow: hidden;
  border-radius: var(--radius-control);   /* 0 — the reference rounds; §14 does not */
}

/* ⚠ R17e — BELOW 768 THE CARD IS NO LONGER THE PICTURE. The name plate moves
   out from over the thumbnail and sits beneath it, so the card is the frame
   plus the plate rather than a single 3:2 box:

     · aspect-ratio goes to auto — the frame carries the 3:2 now, and leaving
       it here would squeeze the picture to fit the plate as well
     · padding goes to 0 — it moved to the frame, where the chip is
     · align-content: space-between is meaningless with the rows sized to
       their content, so the gap does the spacing instead

   ⚠ THIS BLOCK MUST STAY BELOW THE RULE IT OVERRIDES. Media queries add no
   specificity; source order decides. */
/* R17l — 767 -> 991, by direction: landscape phones and tablets take the
   portrait-phone layout, not the desktop one. A landscape phone is 667-932px
   wide, which sits in the 768-991 band, so the old boundary left it on the
   desktop composition it is far too narrow for.

   THIS IS NOW THE SAME LINE EVERY OTHER BELOW-DESKTOP RULE USES — the
   logo-only header, the sticky dock, and the panel paddings all break at 992.
   The page has one boundary between "desktop" and "everything else" again
   rather than two. */
@media (max-width: 991px) {
  .members__video {
    aspect-ratio: auto;
    padding: 0;
    gap: var(--space-sm);
  }
}

/* THE THUMBNAIL IS THE CARD'S GROUND, not a row in it. .ph is left on so the
   grey and its IMAGE label survive as the placeholder state; when a still
   arrives it becomes an <img> in the same box and .ph stays as the load and
   404 ground, exactly as it does in §9's board and §6's avatars. */
/* --------------------------------------------------------------------------
   THE FRAME — R17e

   `display: contents` FROM 768 UP, and that is what makes this change free
   above mobile. An element with `display: contents` generates no box: the
   thumbnail, the chip and the play control become direct children of
   .members__video again, so the card lays out exactly as it did before this
   wrapper was added. Nothing about the desktop card is re-derived.

   BELOW 768 it becomes a real box, and it has to, because the three things
   inside it need ONE containing block for the name card to move out from
   under them. .members__thumb is `inset: 0` and .play is centred on
   50%/50% — both resolve against the nearest positioned ancestor. With the
   card holding the plate too, that ancestor was the whole card; the play
   control would have centred on the card INCLUDING the name below it, and
   the thumbnail would have covered it. Pinning them to a 3:2 frame is what
   lets the plate sit after the picture rather than on it.

   The padding is the card's own, moved inward with the chip: the chip is
   inset by its parent, and its parent is now the frame. */
.members__frame { display: contents; }

@media (max-width: 991px) {
  .members__frame {
    display: block;
    position: relative;
    aspect-ratio: 3 / 2;
    overflow: hidden;
    padding: var(--gap-card-padding);
  }
}

.members__thumb {
  position: absolute;
  inset: 0;
  z-index: var(--layer-base);
}

/* R14q — the still fills the thumbnail box. block-size: 100% for the reason
   every <img> on this page needs it: `height="960"` is a presentational hint
   and wins wherever no CSS sets a height. The files are 1440x960, exactly the
   card's 3:2, so cover crops nothing today. */
.members__thumb img {
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
}

/* R14z — THE SCRIM IS REMOVED, by direction. Three rules go: the base band,
   the ≥992 band and the ≥1200 band with its horizontal mask.

   ✅ AND THE ATTRIBUTION IS COVERED WITHOUT ONE. Removing the scrim left the
   names at 1.61:1 and 1.38:1 on bare photograph, against the 4.5:1 normal
   text needs — unreadable rather than merely low-contrast. R15a puts an
   opaque plate under those three lines instead, which fixes them at 17.9:1
   and costs the picture only the area the words occupy. See .members__video-id
   below.

   ✅ THE PLAY GLYPH IS UNAFFECTED. --color-surface-glass-deep was computed for
   the ≥1200 case where the band already stopped short of the disc, so the
   backdrop under it was a scrim of zero before this change: Philip 3.21:1,
   Rebekah 3.97:1, unchanged. */

/* ⚠ R14y — RESTORED. These four rules were deleted by mistake at the previous
   revision: the undo replaced a span reaching from the scrim comment to the
   attribution rule, and everything between the two went with it — the chip,
   the head, the quote and the stacking rule. Nothing about them had been
   asked to change.

   ⚠ .members__play IS NOT IN THIS LIST. The component positions it
   absolutely, and `position: relative` here would fight that and drop the
   disc out of the card's centre. It takes the z-index on its own below. */
.members__video-head,
.members__video-id { position: relative; z-index: var(--layer-raised); }

.members__video-head { display: grid; gap: var(--space-md); justify-items: start; }

/* Violet ground, white label — 5.82:1. Square, like every other box on the
   page; the reference's chip is rounded and §14 is not. */
.members__chip {
  padding: var(--space-2xs) var(--space-xs);
  background-color: var(--color-accent-identity-deep);
  border-radius: var(--radius-control);
  font-size: var(--font-size-meta);
  font-weight: var(--font-weight-semibold);
  letter-spacing: var(--letter-spacing-caps);
  text-transform: uppercase;
  line-height: 1;
  color: var(--color-text-heading);
}

/* R15a — THE PLATE. The scrim went at R14z and left the attribution on bare
   photograph at 1.38:1; this puts a ground under the words instead.

   ✅ IT IS THE BETTER HALF OF THE TRADE. A scrim buys legibility by dimming
   the PHOTOGRAPH — which is why every revision from R13x to R14z was an
   argument about how much of the picture to spend. A plate costs only the
   area the words occupy, and being opaque it fixes the contrast at 17.9:1
   rather than leaving it to be re-measured whenever the still or the gradient
   moves. Both films are now unobscured except behind three lines of text.

   ⚠ justify-self: start IS LOAD-BEARING. .members__video is a grid, and a grid
   item stretches to its column by default — without this the plate would run
   the full width of the card and become the band the scrim just stopped being.

   --color-surface-panel is the page's own container grey, so the block reads
   as one of the page's boxes laid on the still rather than as a new object.
   The 2px violet rule stays as its leading edge; it was the attribution's mark
   before it had a ground and it still is. */
.members__video-id {
  justify-self: start;
  display: flex;
  flex-direction: column;
  gap: 0;
  padding: var(--space-sm);
  background-color: var(--color-surface-panel);
  border-inline-start: var(--border-emphasis) solid var(--color-accent-identity-deep);
}

/* R17f — THE PLATE STRETCHES TO THE PICTURE'S WIDTH AT ≤767, by direction.

   justify-self: start is what made it shrink to its longest line — correct
   while it sat OVER the thumbnail, where a full-width bar would have covered
   the whole lower third of the photograph. Below the picture there is nothing
   to cover, and a plate ending mid-card reads as unfinished rather than as
   fitted. `stretch` is the grid default, so this only undoes the base rule.

   ⚠ IT HAS TO SIT HERE, AFTER THAT RULE, NOT IN THE ≤767 BLOCK FURTHER UP.
   Media queries add no specificity: a `justify-self: stretch` written before
   `justify-self: start` loses to it at every width. Fourth time this has
   decided an edit in this project.

   The 2px violet leading edge and the panel ground are untouched — the plate
   just runs the full width now. */
@media (max-width: 991px) {
  .members__video-id { justify-self: stretch; }
}

/* R14n — THE CONSTRUCTION MOVED TO components/play.css, and §6's disc changed
   with it: it was a SOLID violet fill with a white glyph, and is now the same
   glass disc §3 uses. The two were the page's only play controls and had
   drifted into two different objects.

   52px and a 24px glyph rather than the component's 80/30 — these sit on
   cards, not at a section's centre of gravity. Centring and stacking come
   from the component. */
.members__play {
  --play-size: var(--icon-box-size);
  --play-glyph-size: var(--icon-size-feature);
  z-index: var(--layer-raised);
}

/* ==========================================================================
   R13y — THE SEPARATOR
   ========================================================================== */
.members__sep {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: var(--space-lg);
  margin-block: var(--space-3xl);
  color: var(--color-accent-identity-deep);
}

.members__sep-rule {
  block-size: var(--border-hairline);
  /* --color-border-strong, not border-default: 0.10 white on pure black is
     1.3:1 and simply is not there. The same call §11's lattice made. */
  background-color: var(--color-border-strong);
}

/* THE SIZE, and it has moved twice.

   R14m took it 24 -> 30, by direction. R15x takes it back to 24, by
   direction, once the mark became Assets/Quote.svg — and the two are not the
   same 24. The old path was square, so 30 rendered a 30x30 mark. This one is
   1.15:1, so 30 rendered 34.5 wide: the glyph changed size when the artwork
   changed, without the token moving. Back at --icon-size-feature it is 24
   tall and ~27.6 wide, which is slightly under the old 30x30 in both
   directions.

   ⚠ THE STEP IS THE ICON FAMILY'S, NOT A PICKED NUMBER. §13 keeps icon sizes
   as their own set (15 · 16 · 18 · 20 · 24 · 30) that does not answer to the
   spacing scale, so the legal move down from --icon-size-pixel-lg is
   --icon-size-feature. There is nothing between them.

   ⚠ NEITHER TOKEN IS REALLY THIS MARK'S. --icon-size-pixel-lg is named for
   the pixel grid (30 = 2:1 with the 15-unit glyph grid, paired with
   `crispEdges`) and --icon-size-feature is named for feature icons. This is a
   curved decorative mark and takes the SIZE and not the rendering rule that
   goes with either name. */
.members__sep-mark {
  inline-size: auto;
  block-size: var(--icon-size-feature);
  fill: currentColor;
}

/* ==========================================================================
   R13y — THE SCROLL RAIL
   Six cards in a track, three in view. Was a 3x2 grid.

   ⚠ IT ENDS THE §15 ADJACENCY VIOLATION R8z CREATED. Built 5 is uncontained
   thirds and this section was thirds — the first live breach of "zero
   consecutive sections sharing a layout pattern". A scroll rail is not a
   thirds grid: it is one row that continues past the frame, which is a
   different pattern to read even though three cards are visible at once.
   R8z's other two costs stand — the card grid in a narrative section, and the
   card-section count — but this one is closed.
   ========================================================================== */
/* --------------------------------------------------------------------------
   THE TITLE GROUP — R15r

   Nested inside .section__title so the group has TWO intervals rather than
   one: .section__title's 32px title-group gap holds the eyebrow off, and this
   16px holds the heading to its subtitle (§4, heading -> paragraph). A single
   flex column can only give one, which is why §5 nests too.

   ⚠ THIS IS A SECOND COPY OF .principles__head / .principles__sub — three
   rules, identical in both files. The same note stands here as on
   .hero__pause: two copies is where drift starts, and the moment a third
   section wants a centred heading-plus-subtitle it should be promoted to a
   layout utility rather than written again.

   .t-lead caps at --measure-prose-wide and centres through the parent's
   text-align; margin-inline: auto centres the BOX once that cap bites. */
.members__head {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--gap-heading-to-paragraph);
}

.members__sub { margin-inline: auto; }

/* R15s — one clause per line, blocks rather than a <br>. Same rule and same
   reasoning as .principles__sub-line. */
.members__sub-line { display: block; }

/* R17i — the margin was a style="" attribute in the markup. The rail follows
   the separator, so it takes the grid gutter rather than a section interval. */
.members__rail {
  position: relative;
  margin-block-start: var(--gap-grid);
}

.members__grid {
  display: flex;
  gap: var(--gap-grid);
  list-style: none;
  margin: 0;
  padding: 0;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  /* Momentum scrolling stays inside the rail rather than chaining to the page
     when it hits an end — a horizontal flick at the last card must not start
     scrolling the document sideways. */
  overscroll-behavior-x: contain;
  /* Hidden, and the buttons below are what replaces it. Firefox and WebKit
     need separate declarations; neither is a fallback for the other. */
  scrollbar-width: none;
}

.members__grid::-webkit-scrollbar { display: none; }

/* THE FOCUS RING GOES OUTSIDE THE CLIPPED BOX. A scroll container clips its
   own children, and a ring drawn on the inside edge would be cut along three
   sides. The offset puts it clear of the overflow. */
.members__grid:focus-visible {
  outline: var(--border-emphasis) solid var(--color-accent-confirm);
  outline-offset: var(--border-emphasis);
}

/* THE CARD WIDTH IS THE VIEWPORT DIVIDED, NOT A FIXED px. Three across at
   desktop, two at tablet, and 85% on mobile — the 15% left showing is the
   affordance that says the row continues, which matters most where the
   buttons are hardest to hit.

   flex: 0 0 <basis> and not `width`: a flex item with a percentage width still
   shrinks, and six shrunk cards would fit the row and defeat the scroll. */
.members__card {
  flex: 0 0 85%;
  scroll-snap-align: start;
}

@media (min-width: 768px) {
  .members__card { flex-basis: calc((100% - var(--gap-grid)) / 2); }
}

@media (min-width: 992px) {
  .members__card { flex-basis: calc((100% - (var(--gap-grid) * 2)) / 3); }
}

/* --------------------------------------------------------------------------
   THE CONTROLS
   -------------------------------------------------------------------------- */
.members__rail-nav {
  display: flex;
  justify-content: flex-end;
  gap: var(--space-2xs);
  margin-block-start: var(--space-md);
}

/* R15e — THE STROKE ONLY, by direction. The 48 → 64 box and the 16 → 24 glyph
   went back at the same revision: the edge was doing the work, and the size
   was not needed once it could be seen.

   THE EDGE WAS FAILING §18. --color-border-strong is white at 0.20, which over
   pure black composites to roughly #333 — 1.66:1. §18 sets 3:1 for non-text
   UI, and the boundary of a control is exactly that. A boundary nobody can
   see is why these read as two empty squares.

   --color-control-stroke is the token that already answers this question:
   violet #865BFF at 4.95:1, the secondary button's stroke, chosen there on
   the same ground ("comfortably past the 3:1 a UI boundary needs, unlike
   violet as a text ground"). §6 is a violet-accented section, so this spends
   no new accent. The glyph stays white and carries all the reading at 21:1;
   the violet never has to.

   THE BOX IS BACK TO --tap-target-min, not a picked size: §18 sets 48x48 as
   the floor for a touch target and this is the smallest control on the page.

   HOVER lost its border-colour move and kept its fill. It used to send the
   border to --color-accent-identity-deep, which is 3.61:1 — DIMMER than the
   resting stroke now is, so hovering would have degraded the edge. The ground
   stepping up is §5's card hover, and R5i already says a control's stroke
   does not brighten on hover. */
.members__scroll {
  display: flex;
  align-items: center;
  justify-content: center;
  inline-size: var(--tap-target-min);
  block-size: var(--tap-target-min);
  padding: 0;
  background-color: transparent;
  border: var(--border-hairline) solid var(--color-control-stroke);
  border-radius: var(--radius-control);
  color: var(--color-text-heading);
  cursor: pointer;
  transition: border-color var(--duration-base) var(--ease-standard),
              background-color var(--duration-base) var(--ease-standard);
}

.members__scroll:hover,
.members__scroll:focus-visible {
  background-color: var(--color-surface-panel);
}

/* Disabled at the ends. 0.4 is the page's own disabled step (button.css), so
   a spent control looks the same everywhere. */
.members__scroll[disabled] {
  opacity: 0.4;
  cursor: not-allowed;
}

.members__scroll svg {
  inline-size: var(--icon-size-inline);
  block-size: var(--icon-size-inline);
}

/* THE CARD. --color-surface-panel is 1.17:1 off the page ground — the same
   lift §4's box takes, which is what "the same dark grey as the section
   before" resolves to.

   `align-content: space-between` pins the attribution to the card's floor, so
   the avatars line up across a row whatever length the quotes run to. Without
   it, a short quote lifts its attribution and the row reads as ragged. */
.members__card {
  display: grid;
  align-content: space-between;
  gap: var(--space-lg);
  padding: var(--gap-card-padding);
  background-color: var(--color-surface-panel);
  border-radius: var(--radius-control);   /* 0 — R6x */
}

/* R9c — MATCHED TO §4's ✗ ROWS, by direction: same size, weight, leading and
   colour. Was H4 in the old section, body-lg at R8z, and is now body/300.

     size     --font-size-body     18 / 18 / 17
     weight   --font-weight-light  300
     leading  --line-height-body   148%  (was --line-height-lead, 130%)
     colour   white — 17.93:1 on the card

   The 148% leading is a gain here rather than a side effect: three of these
   quotes run to two paragraphs, and 130% was tuned for a single lead line.

   IT STAYS MUNDIAL, which is the part of the old note that still holds: the
   heading face announces, and a quotation is the one thing on the page that
   should sound like a person rather than the page.

   ⚠⚠ WEIGHT 300 AT 18px ON A DARK GROUND IS THE THIRD OVERRIDE OF §16's
   22px FLOOR. R8e suspended it on light grounds; R8k suspended it for §4's ✗
   rows on black and said in terms that the rule "should be replaced, not
   patched again — patching it a third time is how a rule stops meaning
   anything." This is that third patch, and the floor should now be treated as
   RETIRED rather than exceptional. See design-rules R9c for what replaces it.

   Contrast is not the concern: 17.93:1. Rendering is — a light stroke on a
   dark field blooms at its edges and thins an already-thin stem. It cannot be
   measured from the values; it has to be looked at, ideally on a non-retina
   screen. If it shimmers, --font-weight-regular here costs the weight match
   and nothing else. */
.members__text {
  margin: 0;
  font-size: var(--font-size-body);
  font-weight: var(--font-weight-light);
  line-height: var(--line-height-body);
  color: var(--color-text-heading);
}

.members__text p { margin: 0; }

/* Three of the six quotes run to two paragraphs (R9a). --space-md between
   them, not the card's own --space-lg: a paragraph break inside one person's
   speech must read as smaller than the break between the quote and its
   attribution, or the second paragraph starts to look like a second quote. */
.members__text p + p { margin-block-start: var(--space-md); }

.members__author {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
}

/* ⚠ THE AVATAR PLACEHOLDER CANNOT USE .ph's OWN GROUND. .ph fills with
   --color-surface-hover #1A1A1A, which against this card's #171717 measures
   1.03:1 — it would not be there at all. It takes --color-bg-base instead:
   1.17:1, reading as a hole punched in the card rather than a chip laid on
   it. Same inversion §4's ✗ badge needed for the same reason.

   50% radius — the sixth consumer of --radius-avatar, and the first that is
   literally what the token was named for. Radius values page-wide still stand
   at three (0 · 32 · 50%).

   BLOCKER: no member portraits exist. When they land they take §11a's
   grayscale-at-rest treatment like every other portrait on the page. */
/* R9t — SIZED FROM THE TEXT, not from the box family.

   The instruction was that the circle should complement the combined height
   of the name and the role, so it is CALCULATED rather than picked:

     (--font-size-small 16 + --font-size-meta 14) x --line-height-body 1.48
     = 44.4px

   That is the exact height of the two stacked lines now the gap is 0. Neither
   --icon-box-size-sm (40) nor --icon-box-size (52) is that number, and
   hard-coding 44 would go stale the moment either type size moved. The
   calc tracks them.

   ⚠ IT DEPENDS ON THE LINE-HEIGHT BEING INHERITED. Neither .members__name nor
   .members__role sets one, so both take --line-height-body from base.css. If
   either is ever given its own, this calc has to be updated with it. */
.members__avatar {
  flex: 0 0 auto;
  /* R13i — THE TWO LINES PLUS ONE STEP, by direction: bigger, so the faces
     are recognisable. 44px -> 56px, about 27%.

     THE DERIVATION IS KEPT AND EXTENDED RATHER THAN REPLACED. The original
     value was the combined height of the name and the role beside it, so the
     circle finished exactly level with the text block. It is now that height
     plus --space-xs, which means the circle OVERHANGS the two lines by 6px
     top and bottom — .members__author centres them, so the overhang is even.
     A picked number like 56px would have looked identical today and stopped
     tracking the type scale; this still moves if the sizes or the body
     leading do.

     ⚠ THE "sized to the two lines" RELATIONSHIP IS THEREFORE GONE as an
     equality. It survives as the base of the expression, which is the honest
     way to record that it was deliberate and has been deliberately exceeded.
     The next step up is --space-sm (60px), at which point the avatar starts
     setting the row's height instead of the text. */
  --avatar-size: calc(
    (var(--font-size-small) + var(--font-size-meta)) * var(--line-height-body)
    + var(--space-xs)
  );
  inline-size: var(--avatar-size);
  block-size: var(--avatar-size);
  background-color: var(--color-bg-base);
  border-radius: var(--radius-avatar);
}

/* R13h — THE PORTRAITS. Five of the six members have one; the sixth keeps the
   bare circle, so .ph stays on ALL of them: it is the ground that shows while
   an image loads, the fallback if one 404s, and the finished state for the
   member whose photograph has not been supplied. One class, three jobs.

   .ph already carries overflow: hidden, which is what makes the square file a
   circle — the radius above is on the span, and without the clip the image
   would simply paint over it.

   block-size: 100% for the reason it is needed on every <img> on this page:
   `height="500"` is a presentational hint and wins wherever no CSS sets a
   height. Without it each avatar would be 44px wide by 500px tall.

   object-position: center top — the files are square headshots and the circle
   is 44px. A centred crop on a square source crops nothing, so this only
   matters if a future portrait is not square; biasing to the top keeps the
   eyes rather than the chin. */
.members__avatar img {
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
  object-position: center top;
}

.members__author-text {
  display: flex;
  flex-direction: column;
  /* R9t — 8px -> 0, by direction: reduce the space between name and role.
     ZERO IS THE ONLY REDUCTION AVAILABLE. §4's spacing scale starts at 8 and
     values outside it are prohibited, so 4px is not a legal step down. The
     lines do not collide at 0 — each carries its own leading, leaving roughly
     7px of internal space at these sizes. */
  gap: 0;
  min-inline-size: 0;
}

.members__name {
  font-size: var(--font-size-small);
  font-weight: var(--font-weight-semibold);
  color: var(--color-text-heading);
}

/* --color-text-body, not --color-text-muted: muted is 5.19:1 on this card
   against body's 8.65:1, and the role line is the smallest type in the
   section. */
.members__role {
  font-size: var(--font-size-meta);
  color: var(--color-text-body);
}

/* --------------------------------------------------------------------------
   THE SETUP — the one thing carried over from the old section.
   160px of empty black beneath the last card, so the plate in §7 arrives
   against nothing. This space is the setup for the page's colour peak and is
   not negotiable: the plate's impact is entirely a function of what precedes
   it.
   -------------------------------------------------------------------------- */
/* ⚠⚠ R17c — 160 -> 80 BELOW 992 ONLY, by direction, AND THIS ONE IS
   DOCUMENTED AS NON-NEGOTIABLE. design-rules.md §15a says: "§6 keeps 160px
   of empty black beneath it. §7's impact is a function of arriving against
   nothing. This must survive any rework of either section."

   It survives at desktop, untouched. Below 992 it is halved, because the
   instruction was to reduce large padding on mobile and this is the largest
   on the page — and because 160px of black on a 390px-wide screen is close to
   half a viewport of nothing, which reads as the page having ended rather
   than as a held breath before the plate.

   80 is still twice the section's own mobile padding, so the plate still
   arrives against a gap no other section gets. If the effect is judged lost
   on a real device, this is the line to put back first. */
.members { padding-block-end: var(--space-4xl); }

@media (min-width: 992px) {
  .members { padding-block-end: var(--space-6xl); }
}
