/* Panel Set
 *
 * Loaded by the block itself (see the enqueue_assets callback in inc/template-blocks.php), so it is
 * only downloaded on pages that use one. Everything here is keyed on classes the block emits -- no
 * page ids, no block-id hashes, no filename matches. See DESCOPING-PLAYBOOK.md.
 *
 * Sizes and colours deliberately mirror the Slider block so the two read as the same family: the
 * same 30/60px arrow, the same 6px dots, the same tropaz stroke and blaze-orange active dot.
 */

.panel-set {
  /* The bare chevron fills its box, so it needs far less of one than the ringed mark: at 30px the
     ring left roughly a third of the box as actual ink, which is why the mobile arrows read as
     small. 22px of chevron is visibly larger than 30px of ring, and hands 16px per side back to the
     content -- which matters, because on a 375px screen this block's track is only ~200px wide. */
  --panelArrowSize: 22px;
  --panelArrowGap: 6px;
  position: relative;
}

@media screen and (min-width: 768px) {
  .panel-set {
    --panelArrowSize: 60px;
    --panelArrowGap: 15px;
  }
}

/* A panel set hands its content ~76px less width than a plain section, because the arrows are inset
   rather than overlaid. A grid's column MINIMUM does not know that: `--gc-col-min: 260px` is an
   ordinary value everywhere else on the site, but inside a panel on a 375px screen the track is only
   ~263px wide, so the column refuses to shrink, overflows, and slick's `overflow:hidden` quietly
   crops it -- text and all.
   Relaxing the minimum (not the count, not the maximum, not the gap) lets the column shrink to the
   space it actually has. The grid's own logic is untouched; it simply stops being handed a floor it
   cannot honour. Scoped inside .panel-set so no other grid on the site is affected.

   `!important` is required, not decorative: grid-container writes `--gc-col-min` as an INLINE style
   on the element, and an inline custom property beats a stylesheet one exactly as any other inline
   declaration does. */
@media screen and (max-width: 767px) {
  .panel-set .grid-container {
    --gc-col-min: 0px !important;
  }
}

/* The arrows span the full width of the panel set and the content is inset to clear them, rather
   than the arrows overlapping the media. */
.panel-set__track {
  margin: 0 calc(var(--panelArrowSize) + var(--panelArrowGap));
  position: relative;
}

/* Before slick runs -- in the editor, and for the moment between load and init -- the panels are
   plain blocks and simply stack. Nothing is hidden, so an author always sees every panel. */
.panel-set__panel {
  min-width: 0;
}

.panel-set .slick-list,
.panel-set .slick-track {
  min-width: 0;
}

/* slick sets an inline width on every slide; let the panel fill it rather than fight it. */
.panel-set .slick-slide > div {
  height: 100%;
}

.panel-set .slick-arrow {
  position: absolute;
  /* `top` is written by panel-set.js from the measured anchor block; 50% is only the pre-measure
     fallback, used if JS has not run yet. */
  top: 50%;
  transform: translate(0, -50%);
  left: calc(-1 * (var(--panelArrowSize) + var(--panelArrowGap)));
  width: var(--panelArrowSize);
  padding: 0;
  border: none;
  background: none;
  -webkit-appearance: none;
  appearance: none;
  cursor: pointer;
  z-index: 2;
}

.panel-set .slick-arrow.slick-next {
  left: auto;
  right: calc(-1 * (var(--panelArrowSize) + var(--panelArrowGap)));
}

.panel-set .slick-arrow svg {
  width: 100%;
  height: auto;
  display: block;
}

.panel-set .slick-arrow.slick-next svg {
  transform: scaleX(-1);
}

/* Two marks ship in every button and the breakpoint picks one (see panel-set.js).
 * Desktop keeps the theme's ringed arrow so a Panel Set matches the Slider on Technology.
 * Below 768 the ring is dropped: at a 30px button the ring is most of the footprint and the chevron
 * inside it is only about a third of that, which reads as a small smudge on a phone. Bare, the same
 * footprint gives a full-size chevron. */
/* Selectors carry `.slick-arrow` so they out-specify `.panel-set .slick-arrow svg` above (three
 * classes beats two classes plus a type). Without it the generic rule's `display:block` wins and
 * BOTH marks render. */
.panel-set .slick-arrow .panel-set__mark--bare { display: none; }

@media screen and (max-width: 767px) {
  .panel-set .slick-arrow .panel-set__mark--ring { display: none; }
  .panel-set .slick-arrow .panel-set__mark--bare { display: block; }
}

/* No transition on the base rule -- the Slider block has one here and it is deliberately not copied.
 *
 * Kept as a note because it cost several passes to diagnose: while the arrows also changed colour as
 * a STATE, the transitioned change sat pinned at its start value indefinitely, and a `display:none`
 * sibling mark (which cannot animate) showed the correct colour instead. That asymmetry reads
 * exactly like "this SVG refuses to be recoloured", and was misdiagnosed as such for a while.
 * The state colouring has since been removed, but the rule stands: if a property both animates and
 * encodes state, do not transition it. Hover keeps its transition, where it is a real effect. */
.panel-set .slick-arrow circle,
.panel-set .slick-arrow path {
  stroke: var(--c-tropaz);
}

/* Icy Blue arrows ("Arrow colour" on the Panel Set), for a set on a dark background.
 *
 * Only the base colour. The hover rule below carries a pseudo-class and so out-specifies this, which
 * is what keeps hover identical whichever colour the arrow rests at. */
.panel-set--arrows-icy .slick-arrow circle,
.panel-set--arrows-icy .slick-arrow path {
  stroke: var(--c-hawkes-blue, #B4DFFD);
}

.panel-set .slick-arrow:hover circle,
.panel-set .slick-arrow:hover path,
.panel-set .slick-arrow:focus circle,
.panel-set .slick-arrow:focus path {
  stroke: var(--c-blaze-orange);
  -webkit-transition: stroke 0.3s ease-in-out;
  transition: stroke 0.3s ease-in-out;
}

.panel-set .slick-dots {
  display: flex;
  justify-content: center;
  list-style-type: none;
  margin: 0;
  padding: 20px 0 0;
}

.panel-set .slick-dots li {
  list-style-type: none;
  margin: 0 5px;
}

.panel-set .slick-dots button {
  display: block;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  overflow: hidden;
  text-indent: -9999px;
  /* Cool Sky rather than the Slider's blue-grey: the grey reads as disabled next to the orange
     active dot, where these are all live destinations. Brand colour, so it holds on both the light
     and the dark sections a Panel Set sits on. */
  background: var(--c-half-baked, #47A8ED);
  opacity: 0.7;
  border: none;
  padding: 0;
  -webkit-appearance: none;
  appearance: none;
  cursor: pointer;
  -webkit-transition: opacity 0.3s ease-in-out;
  transition: opacity 0.3s ease-in-out;
}

.panel-set .slick-dots button:hover,
.panel-set .slick-dots button:focus {
  opacity: 1;
}

.panel-set .slick-dots .slick-active button {
  opacity: 1;
  background: var(--c-blaze-orange);
}

/* Honour core's alignment classes inside a panel.
 *
 * The editor's alignment control writes `has-text-align-center` onto the block, but the rule that
 * backs it ships in core's BLOCK-LIBRARY stylesheet for that block type, and this theme only
 * enqueues a couple of those (paragraph, notably -- not heading). So on a heading the class arrives
 * with nothing behind it and the alignment silently does nothing.
 *
 * Scoped to .panel-set rather than fixed globally: the same gap exists site-wide, but changing it
 * everywhere would re-align headings on pages nobody asked me to touch. */
.panel-set .has-text-align-center { text-align: center; }
.panel-set .has-text-align-left   { text-align: left; }
.panel-set .has-text-align-right  { text-align: right; }

/* A heading that FOLLOWS something inside a panel needs air above it.
 *
 * Written as `* + .wp-block-heading` on purpose: it matches a heading placed under its media (the
 * Overview panel's caption) and NOT a heading that opens a column beside the media, which is already
 * spaced by the grid gap. Structural, so it needs no marker class and no knowledge of which panel
 * this is. */
.panel-set__panel * + .wp-block-heading {
  margin-top: 24px;
}

/* Centre panel headings once the layout is a single column.
 *
 * 991px is the theme's own 1-column boundary -- it is the width at which grid-container emits
 * `--gc-col-count:1` for these panels -- so this tracks the layout rather than inventing a
 * breakpoint. A heading sitting above a full-width stack reads as a caption for it; left-aligned
 * against a centred image it reads as a stray. */
@media screen and (max-width: 991px) {
  .panel-set__panel .wp-block-heading {
    text-align: center;
  }
}

/* Let a group fill its grid column.
 *
 * The theme gives `.wp-block-group` an explicit width, so a group used as a grid item sizes to its
 * content instead of its column: measured at 375px, a 199px column held a 139px group whose icon
 * list needed 189px, and slick's `overflow:hidden` cropped the difference. `justify-items: stretch`
 * on the grid cannot help -- stretch only applies where the item's width is `auto`.
 *
 * Restoring `auto` inside a panel hands the column width back to the group. Not `100%`: `auto`
 * leaves margins and box-sizing alone, and behaves correctly if the group is ever given padding. */
.panel-set .panel-set__panel .wp-block-group {
  width: auto;
}

/* Centre the media in its column.
 *
 * The panel grids are set to "Stretch Across" so a group fills its column (see above), which means a
 * figure now fills the column too -- and an image narrower than that figure sits at its left edge
 * instead of under the middle of it. At most widths the image happens to fill the column and the
 * difference does not show, which is exactly why it reads as intermittent.
 *
 * Centring the image inside its own figure fixes it without giving up the stretch the group needs. */
.panel-set__panel .wp-block-image img,
.panel-set__panel figure img {
  display: block;
  margin-left: auto;
  margin-right: auto;
}

/* Deliberately NOT indented to the icon-list gutter.
 *
 * An icon list sets its text 80px in (a 60px icon figure plus 20px of padding on
 * `.icon_list__content`), and a paragraph-only panel was twice given the same 80px so the body copy
 * would not slide sideways when paging. Both times that was wrong: copy in a paragraph panel belongs
 * under its own heading, flush with the column, exactly as the heading is. The alignment that has to
 * hold across panels is HEADING to HEADING; the gutter is a property of icon lists, not a text margin
 * the whole block shares. */

/* Overlaid arrows: white, with a drop shadow.
 *
 * Once the set bleeds, the arrows sit ON the media rather than beside it, so their colour can no
 * longer be chosen against the section background -- it has to survive whatever image is underneath.
 * White plus a shadow reads on both a bright sky and a dark road, which is exactly the range in the
 * comparison this was built against.
 *
 * The shadow goes on the SVG via `filter: drop-shadow()`, not `box-shadow` on the button: the button
 * is a transparent rectangle, so a box-shadow would draw a soft rectangle around the mark instead of
 * following the chevron. */

/* Room for artwork to spill above and below the slide.
 *
 * `.slick-list` must clip horizontally -- that is what hides the neighbouring panels -- and CSS will
 * not give one axis `visible` while the other is `hidden` (it computes to `auto` and you get a
 * scrollbar). So the shadow on a scaled image was being cut at the slide's edge: measured, the image
 * painted 240-671 inside a list of 258-653, losing 18px top and bottom.
 *
 * Padding enlarges the clip box; the equal negative margin takes the space back out of the layout.
 * Net effect: nothing moves, and 60px of spill room appears on each side. The arrows are positioned
 * from the set's own box, so they do not shift either. */
.panel-set .slick-list {
  /* content-box is load-bearing. The theme sets `box-sizing: border-box` globally, and slick writes
     an inline HEIGHT on this element for adaptiveHeight (395px, measured). Under border-box the
     padding below comes OUT of that height -- the content area fell to 275px while the panel inside
     was still 395px, and 120px of every panel was clipped. content-box makes the padding add to the
     height instead, which is the whole intent: a taller clip box around the same content. */
  box-sizing: content-box;
  padding-top: 60px;
  padding-bottom: 60px;
  margin-top: -60px;
  margin-bottom: -60px;
}

/* Stacked view: give the panel its side padding back to the artwork.
 *
 * grid-container carries 30px of horizontal padding, which is right for a section sitting directly on
 * the page. Inside a panel set it is charged on top of the arrow inset the track already pays -- at
 * 576px the track is 480px wide and the picture was getting 420 of it, with the remaining 60 spent on
 * padding inside padding. Dropping it is worth about 14% on every image, and the arrows are unaffected
 * because they sit outside the track, not inside the grid.
 *
 * Only where the panel is a single column: above that the padding is separating two columns of
 * content and is doing real work. */
@media screen and (max-width: 991px) {
  .panel-set__panel .grid-container {
    padding-left: 0;
    padding-right: 0;
  }
}

/* One height for every panel image, once the panel is a single column.
 *
 * Stacked, the pictures are read one after another rather than side by side, so what matters is that
 * they agree with each other -- a 457px-tall reader followed by a 377px-tall shield reads as an
 * inconsistency, not as two different products. Width cannot be the shared measure: the readers are
 * landscape and the shields near-square, so equal widths would make the shields half again as tall.
 *
 * 72cqw is the height a reader already takes at the full track width (1151/1601 of it), so the
 * readers are unchanged and everything else comes to meet them. Container units rather than pixels so
 * it tracks the track; the grid is the container because its width comes from the track and does not
 * depend on its own contents -- putting the container on the item instead would be a cycle.
 *
 * `!important` beats the width-cap rule's `height:auto !important` (_relocated-block-rules.scss).
 * Selectors stop at one level of nesting so they reach the media figure in both sets -- a bare figure
 * in Optical Readers, one inside a flex-container in Signature -- without reaching the icon-list
 * check marks, which sit deeper. */
@media screen and (max-width: 991px) {
  .panel-set__panel .grid-container {
    container-type: inline-size;
  }

  /* An Aligned rows grid is EXCLUDED from both of the rules below.
     Those rules assume a panel whose media is one picture spanning the track, and size it against the
     TRACK (72cqw). An Aligned rows grid holds several pictures side by side in a column each, and
     already sizes its media against a COLUMN. Applying the track measure to a column-wide picture
     gives it a box roughly twice the height its artwork can fill, and `object-fit: contain` turns the
     remainder into empty space -- measured at 375px: a 158px box holding 97px of artwork, so 61px of
     it was nothing at all, on every image, in every panel. */

  /* The figure's width cap has to lift too, or the height lands and the picture just letterboxes
     inside a box it is no longer allowed to fill -- measured, a shield given 457px of height stayed
     353px wide and so drew no larger. */
  .panel-set.panel-set .panel-set__panel.panel-set__panel .grid-container.grid-container:not(.is-style-aligned-rows) > figure.wp-block-image,
  .panel-set.panel-set .panel-set__panel.panel-set__panel .grid-container.grid-container:not(.is-style-aligned-rows) > * > figure.wp-block-image {
    max-width: none !important;
    width: auto !important;
  }

  /* Seven classes deep on purpose. _relocated-block-rules.scss carries
     `.page-section:has(.icon_list__wrap) … .flex-container … img { height: auto !important }`, which
     is six classes and matches ONLY the set whose media sits inside a flex-container -- so the height
     took on one set and was silently dropped on the other, which reads as the rule not working at all
     rather than as a cascade problem. */
  .panel-set.panel-set .panel-set__panel.panel-set__panel .grid-container.grid-container:not(.is-style-aligned-rows) > figure.wp-block-image > img,
  .panel-set.panel-set .panel-set__panel.panel-set__panel .grid-container.grid-container:not(.is-style-aligned-rows) > * > figure.wp-block-image > img {
    height: 72cqw !important;
    width: auto !important;
    max-width: 100% !important;
    object-fit: contain;
    margin-left: auto;
    margin-right: auto;
  }
}

/* The shadow trim is a STACKED-view correction; it must not shrink a panel image's box here.
 *
 * "Close the gap" pulls its neighbours in with a negative margin, which also takes that much off the
 * image's layout height. Side by side that is actively harmful: the panel's height comes from the
 * image's box, the artwork-scale transform then draws the picture taller than that box, and the
 * track clips whatever hangs below. Measured at 1600 with an 11.8% trim, the box fell from 395px to
 * 328px and 100px of the reader was cut off.
 *
 * Stacked, the same trim is exactly what is wanted, and there is no transform to overflow. */
@media screen and (min-width: 992px) {
  .panel-set .obm-img-trimmed img {
    margin-top: 0 !important;
    margin-bottom: 0 !important;
  }
}

/* Stacked view: the gutter belongs between the media and the heading, not inside the pair.
 *
 * Same root cause as the two-column case -- a hoisted heading is a grid item, so the row gap falls
 * between it and its own copy -- but the desktop rules are behind a min-width query and never reached
 * here. Measured at 576: 65px between heading and copy against the 25px in the set whose heading is
 * still nested, and 64px between the picture and the heading against that set's 40px.
 *
 * Zeroing the row gap alone would close BOTH, so the media-to-heading distance is handed back as a
 * margin, read from the block's own gutter variable so it tracks whatever the author sets. What is
 * left between heading and copy is the heading's own 25px margin -- exactly the nested case. */
@media screen and (max-width: 991px) {
  /* Stacked, a panel set's content lines up with every other section on the page.
   *
   * Side by side the arrows sit beside the content and the content clears them, which is right when
   * there is width to spend. Stacked there is not: at 375 the content started 78px in -- 30px of the
   * sizing container's own inset plus a 28px arrow inset -- against 20px for every other section, so
   * a panel read as an indented block rather than as part of the page.
   *
   * Both insets come off and the arrows move ONTO the content instead. That is affordable here and
   * not on desktop, because stacked artwork is centred in a track much wider than itself: the arrow
   * lands on the empty margin of the picture, not on the picture. It also keeps the arrow at its own
   * size -- sized to the mark rather than to whatever gap is left over -- so the phone chevron and
   * the tablet ring are both unchanged. Content gains 58px per side. */
  /* EVERY sizing container in the section, not only the one holding the set.
     A panel set section usually has two: one for the heading and intro, one for the set. Freeing
     only the set's put the panel's copy 30px LEFT of the intro paragraph directly above it -- the
     inconsistency simply moved rather than went away. The section is the unit that has to line up. */
  .page-section:has(.panel-set) > .sizing-container {
    /* The 30px-per-side inset is a WIDTH, not a margin: `.page-section > .sizing-container` ships
       `width: calc(100% - 60px)` and the box is then centred. Zeroing the margins does nothing --
       the box simply stays 60px narrow and stays centred, which is exactly what it looked like. */
    width: 100%;
    margin-left: 0;
    margin-right: 0;
  }

  .panel-set__track {
    margin-left: 0;
    margin-right: 0;
  }

  .panel-set .slick-arrow {
    left: 0;
  }

  .panel-set .slick-arrow.slick-next {
    left: auto;
    right: 0;
  }

  .panel-set__panel .grid-container:has(> .wp-block-heading) {
    row-gap: 0;
  }

  /* The same halving for a panel whose heading is still nested in its text column: there the gap
     between picture and copy is the grid's own row gap, not a margin, so it needs saying separately
     -- otherwise the two sets sit at 20px and 40px under otherwise identical artwork.

     Aligned rows is excluded. This halving assumes the row gap is the distance between a picture and
     the copy beside it. In an Aligned rows grid it is the distance between one ROW OF ITEMS and the
     next, which is a different measurement with a different right answer -- halved, it left a caption
     10px above the next row's picture and 20px below its own, so it read as belonging to the row
     underneath. That layout sets its own row gap; leave it to. */
  .panel-set__panel .grid-container:not(:has(> .wp-block-heading)):not(.is-style-aligned-rows) {
    row-gap: calc(var(--gc-grid-gap, 40px) / 2);
  }

  /* Half the gutter, not all of it. The full 40px is a COLUMN measure -- the room two columns of
     content need between them -- and stacked it lands under the picture, where the artwork's own
     shadow is already providing separation. */
  .panel-set__panel .grid-container:has(> .wp-block-heading) > .wp-block-heading {
    margin-top: calc(var(--gc-grid-gap, 40px) / 2);
  }

  /* And the same for the space above the picture. The set's wrapper carries a 50px top margin, which
     separates it from the heading and intro above; stacked, that sits directly on top of artwork that
     is flush to its own top edge, so it reads as padding on the image.

     EXCEPT where the panel leads with a heading rather than a picture. Then this margin is not the
     only thing in play: the section heading's own 25px bottom margin sits above it, and the two do
     not collapse, because a page section is a flex container and margins do not collapse inside one.
     So the two headings ended up 50px apart -- under a 30px phone heading that reads as a break
     between unrelated things rather than as a title and its subtitle. Dropping this half hands the
     spacing to the heading's own margin and leaves 25px.

     The condition is structural, not a page match: only a panel whose FIRST child is a heading
     stacks two headings this way. A panel that leads with media keeps the 25px, because there the
     gap sits between a heading and a picture, where it is not too much. */
  .sizing-container:has(> .panel-set):not(:has(.panel-set__panel > .wp-block-heading)) {
    margin-top: 25px !important;
  }
}

/* A hoisted heading fills its column at EVERY width.
 *
 * Once the heading is a grid item, `justify-items: start` -- which these grids set -- sizes it to its
 * own text instead of its track. Above 992px the placement rules below stretch it; below that nothing
 * did, and a stacked panel heading measured 131px in a 420px column and wrapped to a stack of short
 * lines. The desktop rules keep their own `justify-self` for the spanning case; this is the floor. */
.panel-set__panel .grid-container > .wp-block-heading {
  justify-self: stretch;
}

/* Panel layout: where the media, the heading and the text sit.
 *
 * Only applies to a grid that actually HAS the heading as a direct child -- `:has(> .wp-block-heading)`
 * is a guard, not decoration. A panel whose heading is still nested inside its text column matches
 * none of this and lays out exactly as it did before; without the guard, "the media" (the child that
 * is neither the heading nor after it) matched BOTH columns and stacked them in the first track.
 *
 * The three children are in a fixed DOM order -- media, heading, text -- chosen for the two things
 * that read it positionally and must not change:
 *   - panel-set.js anchors the arrows to the FIRST block in the grid, so the media stays first;
 *   - the stacked view has no explicit placement, so it falls out as media, heading, text, which is
 *     the order the panels had when the heading lived inside the text column.
 *
 * Three children in a two-column grid cannot be left to auto-placement -- it would put the heading in
 * column 1 and push the text onto a second row -- so every item is placed explicitly.
 *
 * Matched by POSITION RELATIVE TO THE HEADING rather than by tag or class, because the two sets on
 * this site wrap their panel content differently: Optical Readers uses a core image beside a core
 * group, Signature Markers uses two flex-containers. "The media" is the child that is neither the
 * heading nor after it; "the text" is everything after the heading. The background div that
 * grid-container prepends when "stack on mobile" is set is excluded by name -- it is not content.
 *
 * All of it above 991px, where these grids are still two columns; below that nothing is placed and
 * the DOM order stands. */
@media screen and (min-width: 992px) {
  /* No row gap once the heading is a grid item.
   *
   * The gutter is a COLUMN measure -- it separates the media from the copy -- but a grid applies it
   * to rows as well, and the heading's row sits directly above the copy's. So hoisting the heading
   * silently inserted the gutter between a heading and its own list, on top of the 25px bottom
   * margin the heading already carries: measured 55px, against 25px in the set whose heading is
   * still nested inside its text column. Zeroed here so that distance is the heading's margin and
   * nothing else, which is what the nested version was giving.
   *
   * Rows only, so the space between the media and the copy is untouched. Above the breakpoint only,
   * so the stacked view keeps the gutter between its three stacked blocks. */
  .panel-set__panel .grid-container:has(> .wp-block-heading) {
    row-gap: 0;

    /* The heading's row is sized to the heading, and the copy is pulled to the top of the row below.
     *
     * Both are needed because the media spans both rows, and CSS shares a spanning item's height out
     * equally between the auto tracks it covers: a 377px shield made the heading's row ~188px tall,
     * so the copy began halfway down the panel with a chasm under the heading -- and it survived
     * zeroing the gap, because the space was inside the tracks rather than between them.
     *
     * The two content rows are `min-content`, with a FLEXIBLE spacer above and below them. Both parts
     * are load-bearing:
     *
     *   - min-content collapses each row to its own block, so the heading sits directly above the
     *     copy with only its own 25px margin between them. Left as `auto`, the media -- which spans
     *     every row -- grew them: a spanning item contributes to each intrinsic track it covers, and
     *     the heading's row measured 218px with the copy 155px adrift.
     *   - the 1fr spacers absorb the media's remaining height and, being equal, split it evenly above
     *     and below. That is what centres the heading and copy AS A PAIR against the picture, which
     *     is the thing the eye compares. Sizing the rows alone left the pair hard against the top. */
    grid-template-rows: 1fr min-content min-content 1fr;
  }

  /* `!important` because _relocated-block-rules.scss ships
     `.page-section:has(.icon_list__wrap) .grid-container > .flex-container { align-self: center !important }`
     for the plain two-column sections, and it matches these panels too. Without it the copy stayed
     centred in its track: harmless on a panel whose icon list fills the row, but the overview panel's
     two-line paragraph sat 155px below its heading. */
  .panel-set .panel-set__panel.panel-set__panel .grid-container:has(> .wp-block-heading) > .wp-block-heading ~ *:not(.block_bg__stack) {
    align-self: start !important;
  }

  /* Default: heading at the top of the text column, media alongside spanning both rows. */
  .panel-set__panel .grid-container:has(> .wp-block-heading) > *:not(.block_bg__stack):not(.wp-block-heading):not(.wp-block-heading ~ *) {
    grid-column: 1;
    grid-row: 1 / -1;
  }
  /* `justify-self` is not decoration: these grids are set to `justify-items: start`, so a plain
     heading block shrinks to the width of its own text -- measured 253px inside a 555px column, and
     unchanged when told to span both columns, which reads as the setting doing nothing at all. The
     flex-container columns have widths of their own and so never showed it. */
  .panel-set__panel .grid-container:has(> .wp-block-heading) > .wp-block-heading {
    grid-column: 2;
    grid-row: 2;
    justify-self: stretch;
  }
  .panel-set__panel .grid-container:has(> .wp-block-heading) > .wp-block-heading ~ *:not(.block_bg__stack) {
    grid-column: 2;
    grid-row: 3;
  }

  /* A panel column must not be wider than its column.
   *
   * `.flex-container` is a content-box element carrying 50px of side padding, so `width: 100%` makes
   * it 100px WIDER than the track it sits in -- measured 611px in a 511px column. It overflows to
   * the right, and its content box starts 50px in from the left, which pushes a centred picture 50px
   * further from the copy than the column implies. Border-box hands both back. */
  .panel-set__panel .grid-container > .flex-container {
    box-sizing: border-box;
  }

  /* Media on the left: give the picture more of the row than the copy.
   *
   * The mirror of the media-right split below. It also buys the artwork room to grow: the panel set
   * clips at its track, and a scaled picture is centred in its column, so how large the scale can go
   * before the near edge is cut depends on how wide that column is. At an equal 550px split the
   * readers were already at the limit -- 633px painted against a first clip at 639. */
  .panel-set:not(.panel-set--media-right) .panel-set__panel .grid-container {
    grid-template-columns: 1.08fr 0.92fr;
  }

  /* Media on the right: give the copy more of the row than the picture.
   *
   * Equal columns leave the shield floating in the middle of a half it does not fill -- 353px of
   * artwork in a 655px box -- so the space between the copy and the picture measured 181px while the
   * copy was wrapping early in its own 555px column. Shifting the split moves half the reduction into
   * the text column and takes the other half out of the empty space beside the shield.
   *
   * A ratio rather than pixels, so it holds at every width the panel is still two columns. */
  .panel-set--media-right .panel-set__panel .grid-container:has(> .wp-block-heading) {
    grid-template-columns: 1.08fr 0.92fr;
  }

  /* Media on the right ("Media position" on the Panel Set): the same layout mirrored. */
  .panel-set--media-right .panel-set__panel .grid-container:has(> .wp-block-heading) > *:not(.block_bg__stack):not(.wp-block-heading):not(.wp-block-heading ~ *) {
    grid-column: 2;
  }
  .panel-set--media-right .panel-set__panel .grid-container:has(> .wp-block-heading) > .wp-block-heading,
  .panel-set--media-right .panel-set__panel .grid-container:has(> .wp-block-heading) > .wp-block-heading ~ *:not(.block_bg__stack) {
    grid-column: 1;
  }

  /* "Heading position: Above the panel" -- a setting on the SET, so every panel in it agrees. Panels
   * swap in place, and a heading that moves between them reads as the layout shifting rather than
   * the content changing. */
  .panel-set--heading-top .panel-set__panel .grid-container:has(> .wp-block-heading) {
    /* Two rows here, not four: the heading is a band across the top, so there is no pair to centre
       and the spacers would only push the media and copy apart. */
    grid-template-rows: min-content 1fr;
  }
  .panel-set--heading-top .panel-set__panel .grid-container:has(> .wp-block-heading) > .wp-block-heading {
    grid-column: 1 / -1;
    grid-row: 1;
  }
  .panel-set--heading-top .panel-set__panel .grid-container:has(> .wp-block-heading) > *:not(.block_bg__stack):not(.wp-block-heading) {
    grid-row: 2;
  }
}

/* The Overview panel's diagram, capped so its panel matches its siblings.
 *
 * In the In-/On-product set, Overview holds ONE centred diagram while Fuel, In-product and
 * On-product each hold a three-up grid of small marks. Measured at 1440: the three are 450px tall
 * and Overview was 1165 -- the diagram alone rendered 961x1072. The track reserves the tallest
 * panel, so paging off Overview left ~700px of empty space under every other panel.
 *
 * The cap is arithmetic, not taste: panel 450 = heading 39 + its 25px margin + image + 29px of
 * panel padding, so the image gets 450 - 64 - 29 = 357. Change the siblings' height and this
 * number is stale -- it is the one thing here that does not derive itself.
 *
 * Keyed on SHAPE, not on the block id (those hash their attributes and go stale -- see memory
 * `reyal-page-section-block-id-hash`): `figure.aligncenter` is what the single-diagram panel has
 * and the three-up panels, which are `wp-block-image size-full`, do not. Checked across the page:
 * the only matches are this panel and slick's clone of it.
 *
 * `!important` because the width-cap rule in _relocated-block-rules.scss sets `height: auto
 * !important` on these figures, and `width` has to be released for the height cap to drive the
 * scale -- otherwise the image keeps its 961px width and simply letterboxes.
 *
 * EVERY width, deliberately -- this is the one figure that opts out of the mobile growth rules
 * above. Those lift the caps below 992 so a shrunken mark grows back; applied to this diagram it
 * took it from 320x357 to 601x670 the pixel below the breakpoint, very nearly doubling as the
 * other panels merely reflowed from two columns to one. A diagram that changes size while the
 * layout around it only rewraps reads as a fault. Capping it everywhere keeps it the same size
 * across that crossing, which is the whole point.
 *
 * `max-width: 100%` is what keeps this honest on a narrow phone: the height cap alone would let
 * a 320px-wide diagram sit in a 300px column.
 *
 * WHY 338. That is what the Aligned Rows formula gives the three-up panels beside this one:
 * (100cqw - (cols-1)*gap)/cols * --aligned-rows-media-h, which at desktop is (1140-60)/3 * 0.94.
 * This diagram sits in a ONE-column grid, so the same formula handed it 1140 * 0.94 = 1072 --
 * the oversized graphic. Matching the neighbours' number puts it on their line.
 *
 * It is a fixed number rather than the formula because the neighbours' own height moves with
 * their column count (338 at three columns, ~326 at two), and this diagram is deliberately held
 * at one size across breakpoints. Equal to them at desktop, steady everywhere else -- the two
 * goals cannot both hold at every width. */
.panel-set__panel figure.aligncenter img {
  max-height: 338px !important;
  width: auto !important;
  height: auto !important;
  max-width: 100%;
}
