/* ==========================================================================
   Template: listing / index pages   (.br-listing__*)
   --------------------------------------------------------------------------
   Drives three pages: /insurance/ (23 cover types), /industry/ (31
   industries) and /blog/ (39 posts, newest first, with dates).

   Depends on tokens.css + base.css. Load them FIRST, in that order.

   WHAT THIS SHARES WITH THE SIGNED-OFF HOME PAGE
   ----------------------------------------------
   Everything structural. There is not one hex, one radius, one gap and one
   type size in this file that is not a token, and the components are the
   home page's own:

     · the neutral band   --br-bg-band, the surface the services grid and the
                          footer already sit on
     · the hairline       --br-border, the one divider in the system
     · the h1             .br-display-md (58.514 @1440) — byte-identical to the
                          home page's "Built for operational industries". The
                          only thing this file adds is `text-wrap: balance`,
                          because these titles come from the CMS rather than
                          being art-directed; see the note on the rule.
     · the eyebrow        .br-eyebrow, the hero form's kicker
     · the lead           .br-lead
     · the entry title    .br-h4 on an <h2> — the "level is semantics, size is
                          presentation" split the trust row already makes
     · the entry copy     .br-body-sm, the services grid's own label scale
     · hover feedback     thicken the underline; do NOT try to move a
                          near-black label 12 values (services.css:516)
     · focus              2px ring at 2px offset, moved off the inline onto a
                          block so a wrapped title does not get a notched
                          two-rectangle ring (services.css:531)
     · the hit target     the whole row, anchored to the <li>, never the
                          inline <a> (services.css:485)

   WHAT IS NEW, AND WHY
   --------------------
   1. COLUMN FLOW, NOT A ROW GRID. The services grid settled on 4-up because
      twelve items divide into three full rows with no orphan cell. 23 and 31
      are both prime: at ANY column count above one they leave a part-filled
      last row, which on a row grid reads as missing cells directly above the
      footer seam — the exact failure the services comment rejected 5-up for.

      A multi-column flow has no cells to leave empty. The list runs down
      column one, down column two, down column three, and a last column that
      is one entry shorter is simply what the bottom of a column set looks
      like. It is also already this system's idiom: .br-footer__primary flows
      its four link groups through a multi-column for the same reason.

      The entries are held to a uniform height (see .br-listing__item), so the
      hairlines line up across all three columns and the columns balance
      exactly rather than raggedly.

   2. NO TICK DISC. The services grid marks each row with a 40px gold disc.
      Repeated 31 times beside a two-line description that would stop being an
      accent and start being wallpaper, which is the one thing the gold in this
      system is not allowed to be. It would also break: services.css:287
      records that the disc is centred against the WHOLE text block, so a
      four-line label floats it off the first baseline — and every entry here
      is four lines by construction. The hairline does the marking instead.

   3. A PROSE BLOCK. None of the three pages carries body copy today (the
      extracted content has an empty body for /blog/ and no record at all for
      the two index pages), but the placeholder exists and the rest of the
      site's bodies use eleven elements. All eleven are styled here — see
      section 3 — so an intro paragraph, a list or an FAQ accordion dropped
      into {{body}} lands correctly rather than unstyled.

      THE PROSE BLOCK IS NOT THIS FILE'S OWN SYSTEM. There are four sibling
      long-prose templates — article, page, service, industry — and they have
      already reconciled the values a reading column needs. This file now
      reads the same ones rather than inventing a fifth set:

        centred measure   margin-inline: auto, like all four siblings
        h2 rung           --br-prose-h2-* (34 @1440), the shared long-form
                          step, not the 45.457 section-poster rung
        p to p            --br-flow-xs (18.77), the house paragraph gap
        into h3 / h4      --br-flow-sm, not h2's --br-flow-md
        accordion bank    a rule above the first, a rule under the last of
                          each RUN, and no rule doubled between two
        summary focus     the row's own ring, so one page has one ring shape

      Where those differ from what this file did first, the rule carries a
      note saying what the old value was and what it looked like. Nothing in
      this section is a preference; every value is a sibling's.

   4. IT CLOSES ON A CONTACT CARD. rebuild/sections/speak.html, spliced by
      scripts/_lt-build.mjs, exactly as the standalone-page template splices
      it. /insurance/ and /industry/ are the highest-intent pages on the site
      and both used to end on a list of links and the legal block.

   THE ONE NEW TOKEN: --br-measure-prose. Its derivation is in tokens.css.
   ========================================================================== */

/* ==========================================================================
   1. PAGE HEAD  — the masthead band
   --------------------------------------------------------------------------
   On the neutral band, not on white. Three reasons, in order of weight:

     · The page has no hero photograph and no form, so under a white nav bar a
       white head gives the h1 nothing to sit against — the page starts with a
       heading floating in the same white as the nav above it.
     · The band is where this system already puts an index (the services grid),
       so a reader arriving from the home page meets a surface they have seen.
     · It leaves the entries themselves on white. 31 rows of hairline-separated
       copy is the longest continuous run of text on the site; the band is a
       masthead, not a reading surface.

   Rhythm is 3u over the head and 2u under it — --br-section-y-lg / -y, both
   straight off the scale. The extra unit on top is the air the hero would
   otherwise have given the h1.
   ========================================================================== */

.br-listing__head {
  background: var(--br-bg-band);
  padding-block: var(--br-section-y-lg) var(--br-section-y);
}

/* All three optional lines in the masthead collapse when the generator passes
   an empty string, so a page with no eyebrow, no lead and no count does not
   ship three empty boxes and 60px of phantom rhythm. The generator must pass
   "" — NOT whitespace, which is a child node and defeats :empty.

   THE INTRO WAS MISSING FROM THIS LIST and the template's own documentation
   promised it ("Pass \"\" to omit — the element collapses"). It did not: an
   empty <p class="br-lead"> contributes no height, but it keeps its
   margin-top, so an omitted lead still pushed the count 28px down the band.
   Guarded here because the promise is the documented contract. */
.br-listing__eyebrow:empty,
.br-listing__intro:empty,
.br-listing__count:empty { display: none; }

/* THE EYEBROW IS RE-COLOURED ON THIS SURFACE, AND IT HAS TO BE.

   .br-eyebrow paints --br-text-accent, which on a light surface resolves to
   --br-gold-ink #8a6d00. That value was measured and chosen to clear 4.5:1 on
   WHITE, where it lands at 4.92:1. On the neutral band it is 4.20:1 — and an
   eyebrow is 11.5px bold, which is normal-size text under WCAG 1.4.3 (the
   large-text exemption starts at 18.66px bold), so 4.5 is the bar and it
   misses it. Nothing on the home page catches this because the home page
   never puts an eyebrow on the band.

   --br-ink-olive is the existing answer, not a new one: it is the measured
   warm gold-family ink already in the palette (the filled check badge on the
   card proof points), it is 9.23:1 on the band, and it stays recognisably in
   the gold family rather than falling back to plain ink. Scoped to this block
   only — the token set is untouched, so an eyebrow anywhere else still gets
   the measured #8a6d00 on the white it was measured against. */
.br-listing__head .br-eyebrow { color: var(--br-ink-olive); }

.br-listing__eyebrow { margin-bottom: var(--br-space-3); }

/* The h1 is display type, not the Inter section scale.

   Every page in this system opens on the Archivo face — the home page's h1 is
   .br-display-lg — and a listing page that opened on a 600-weight Inter
   heading would be the only page on the site whose title was set in the body
   font. --display-md is the smallest step of that ramp (58.51 @1440) and the
   right one: it is the same size the home page gives "Built for operational
   industries", which is also a block title rather than the page's opening
   statement.

   Both measures are the system's own utilities rather than new numbers:
   .br-measure-wide (840) on the heading and .br-measure (604) on the lead.
   Those are the two constrained widths measured off the signed-off design.
   Measured at 1440, the longest of the three titles ("Insurance solutions for
   established Australian businesses") sets THREE lines inside the 840, not the
   two an earlier draft of this comment claimed. The wrap is balanced rather
   than shortened — see below.

   TEXT-WRAP IS RE-ENABLED, AND THAT IS THE POINT OF THE RULE.

   base.css:219 sets `text-wrap: initial` on the display ramp, on the stated
   reasoning that display headings in this system are art-directed and carry
   an explicit break. Nothing art-directs THIS one: the generator substitutes
   whatever string the content record holds, and the three it holds today are
   35, 30 and 57 characters. Left greedy, the 57-character one broke
   669 / 656 / 335 at 1440 and dropped "businesses" onto a line of its own —
   the widow the balancer exists to prevent.

   The precedent is speak.css:130, which re-enables balance on a
   .br-display-lg heading for the identical reason and says so in as many
   words: most display headings on this page are art-directed, this one is
   not. A CMS-fed page title is the strongest version of "this one is not".

   Balance is capped by the engine at a handful of lines, which is well above
   anything a page title reaches, and it costs nothing on the two short
   titles: both already set one and two lines respectively and balancing does
   not move them. */
.br-listing__title {
  margin: 0;
  text-wrap: balance;
}

/* h1 → lead. --br-flow-2xs (u/2, 14.08 @1440) was the first value here and it
   is measurably too tight: at 58.5px of display type on 49.7px of leading,
   half a unit reads as
   a collision rather than an interval. Measured across every heading/lead pair
   on the signed-off home page, the gap is never below 18.77 (2u/3) and is
   28.15 (1u) in five of the eight — so 1u is the house value, not a compromise
   between two of them. */
.br-listing__intro { margin-top: var(--br-flow-sm); }

/* The count. Small, muted, and deliberately NOT an eyebrow: an eyebrow is a
   label for what follows, this is a fact about what follows. It answers the
   only question a directory of 31 items provokes before you start reading —
   how many of these are there — and it is data, so the generator fills it.

   IT IS ALSO RE-COLOURED ON THIS SURFACE, for the same reason the eyebrow
   four rules above is. --br-text-muted is #6a6c6a, measured and chosen
   against WHITE, where it is 5.30:1 and the blog dateline uses it safely. On
   --br-bg-band it is 4.52:1 — a pass against WCAG 1.4.3 by two hundredths,
   which is not a pass anyone should rely on: it moves the day the band or the
   neutral ramp is retuned, and nothing would catch it.

   --br-neutral-700 is the next step down the ramp the palette already
   defines, it is 8.00:1 on the band, and it is a NEUTRAL — which the eyebrow's
   --br-ink-olive escape is not. Gold-family ink is right for a label; this is
   a count, and the comment above says out loud that it is not an eyebrow.
   Making it the only gold-adjacent line in the masthead would contradict
   that. Read straight off the ramp rather than through --br-text, because
   this is not body copy either. */
.br-listing__count {
  margin-top: var(--br-flow-2xs);
  color: var(--br-neutral-700);
}

/* ==========================================================================
   2. THE INDEX
   ========================================================================== */

.br-listing__index {
  padding-block: var(--br-section-y);
}

/* The column flow.

   `column-count` rather than `column-width`: the number of columns is a
   design decision at each breakpoint, not something to let the browser derive
   from a minimum width — a derived count changes at widths nobody chose and
   would put four columns on a 1920 screen, which takes the entry measure
   below the point where a two-line description fits.

   The gap is 2u (56.31 @1440). No column-rule: the horizontal hairlines
   already carry the structure, and adding verticals turns a directory into a
   table. */
.br-listing__list {
  margin: 0;
  padding: 0;
  list-style: none;
  column-count: 1;
  column-gap: var(--br-flow-lg);
}

/* Every entry, including the first of each column, carries its rule above it.
   That is deliberate: in a column flow there is no way to know which entry
   starts a column, and a rule at the top of each one is what makes three
   columns read as three columns of the same list. The first entry's rule
   doubles as the separator between the head band and the index.

   `break-inside: avoid` is load-bearing, not defensive — without it Chrome
   will split an entry across a column break and leave a title at the foot of
   one column with its description at the head of the next. */
/* UNIFORM HEIGHT IS WHAT MAKES THE COLUMNS WORK, AND IT IS RESERVED ON THE
   ENTRY, NOT ON THE TITLE.

   The height every entry has to reach is two lines of title, two lines of
   description, the gap between them and the padding — which is exactly the
   sum below. Reserving it on the whole entry means a one-line title keeps its
   description directly underneath it and the slack falls at the BOTTOM of the
   box, where it is invisible. Reserving it on the title instead (which is
   what this did first) opens a 28px hole between every short title and its
   own description, and the description stops looking like it belongs to the
   title above it. Same total height either way; completely different read.

   What the uniformity buys: the hairlines line up across all three columns.
   They do not — and the whole grid reads as broken — if entries differ by as
   little as 1px, because the error accumulates down the column. Measured
   drift is now 0.00px at all nine widths on all three pages.

   It also makes the balance predictable: 8/8/7 for the 23 cover types,
   11/11/9 for the 31 industries, 20/19 for the 39 posts. The last column
   ending one or two entries short is the point — that is what the bottom of a
   column set looks like, and it is the thing a row grid cannot do without
   leaving visibly empty cells above the footer seam.

   It is a min-height, not a height. A title that genuinely needs a third line
   gets one; losing a word out of a navigation label to keep a rule straight
   is the wrong trade. Measured against all 93 real entries at
   390/768/1024/1440: not one title reaches three lines, so the three-line cap
   below is a hard stop that never fires — exactly like the cap on
   .br-services__label.

   THE 1px IN THE SUM IS THE HAIRLINE, and leaving it out is a real bug rather
   than a rounding nicety. box-sizing is border-box, so min-height includes the
   border — an entry with a two-line title measured 148.405 against a reserved
   147.405 and every two-line title above a given row pushed that row 1px down
   its column. Measured on /insurance/ at 1024: 16 entries at 147.39 and 7 at
   148.38, and the rules across three columns were up to 3.94px out of true.
   With the hairline in the sum every entry is one number and the drift is
   zero. It is written as a literal 1px because that is what the border-top
   below declares; if that ever becomes 2px, this becomes 2px.

   AND IT IS ONLY SPENT WHERE THERE ARE COLUMNS TO KEEP IN REGISTER. Below
   576 the list is a single column, so there is no neighbouring column for a
   rule to line up with and the reservation buys nothing — it only pays. Most
   titles fit one line on a phone, so every entry carried 28px of slack: 868px
   of blank down a 31-item page, on the device with the least room to spare.
   So --_br-listing-row holds the number and --_br-listing-entry-h is `auto`
   until a media query with more than one column switches it on. */
.br-listing__list {
  --_br-listing-row: calc(
    1px + 2 * var(--br-h4-lh) + var(--br-space-2) + 2 * var(--br-body-sm-lh) + 2 * var(--br-flow-xs)
  );
  --_br-listing-entry-h: auto;
}

.br-listing__item {
  position: relative;              /* containing block for the row hit area */
  break-inside: avoid;
  -webkit-column-break-inside: avoid;
  page-break-inside: avoid;

  display: flex;
  flex-direction: column;
  gap: var(--br-space-2);

  min-height: var(--_br-listing-entry-h);
  padding-block: var(--br-flow-xs);
  border-top: 1px solid var(--br-border);

  transition: background-color var(--br-dur) var(--br-ease);
}

.br-listing__item-title {
  margin: 0;

  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
  overflow: hidden;

  /* A single unbreakable token in a title had nothing to break on and ran
     straight out of its column into the neighbouring one. `anywhere` rather
     than `break-word` because it also lowers the min-content contribution, so
     the column can shrink to fit instead of merely clipping the symptom.
     Zero cost on real content — all 93 titles break on their own spaces. */
  overflow-wrap: anywhere;
}

.br-listing__link {
  color: var(--br-text-strong);
  text-decoration: underline;
  text-underline-offset: 0.3em;
  /* Pinned rather than left at `auto` for the reason services.css:469 gives:
     the two rasterise identically, but `auto` cannot be animated and hover
     needs something to move. */
  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 — services.css:485, and the same
   mistake is available here. An absolutely-positioned pseudo on an INLINE
   element takes its LAST line box as a containing block, not the union of
   them, so growing the target off the <a> gives a two-line title a target
   that covers part of its second line and none of its first. Anchoring to the
   <li> gives every entry the full row — never less than 96px tall — on every
   line of a wrapped title, and makes the description tappable too, which is
   what a finger aims at anyway. */
.br-listing__link::after {
  content: "";
  position: absolute;
  inset: 0;
}

/* The description. Two lines, clamped.

   Clamping is not a nicety here: 28 of the 93 descriptions are cut off at 300
   characters by the extraction and end mid-word. Two lines with an ellipsis is
   an honest "there is more on the other side of this link"; four lines of a
   sentence that stops mid-word is not.

   The scale is --br-body-sm, which is the services grid's own label scale
   (16/24 at >=992, 14/22 below) — set on the block, not only inline, so a
   block whose strut is taller than its content cannot add 2px to every wrapped
   line and push the whole column out of register. */
.br-listing__excerpt {
  margin: 0;
  min-height: calc(2 * var(--br-body-sm-lh));

  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  overflow: hidden;

  font-size: var(--br-body-sm-size);
  line-height: var(--br-body-sm-lh);
  letter-spacing: var(--br-body-sm-ls);
  color: var(--br-text);
  overflow-wrap: anywhere;
}

/* AN ENTRY WITH NO DESCRIPTION RESERVES NOTHING.

   The min-height above exists so a one-line description does not leave the
   entry an inch shorter than its neighbours — but with no description at all
   it reserved 44px of blank between the title and the next hairline, which
   reads as a load failure rather than as a short entry. Every one of the 93
   real entries has a description, so this is a guard for a filtered or newly
   seeded directory rather than a live fault.

   It costs nothing to fix: the uniform height that keeps the hairlines in
   register across columns lives on .br-listing__item, not here, so removing
   the excerpt's own reserve moves the slack to the bottom of the box, which
   is where the note on .br-listing__item already argues it belongs. */
.br-listing__excerpt:empty {
  min-height: 0;
  display: none;
}

/* The dateline — articles only. Above the title, which is where a reader
   scanning an archive expects it, and small and muted so 39 of them do not
   compete with 39 titles. Plain, not an eyebrow: an eyebrow is uppercase gold
   and would make the date the loudest thing in the entry. */
.br-listing__date {
  margin: 0;
  font-size: var(--br-small-size);
  line-height: var(--br-small-lh);
  letter-spacing: var(--br-small-ls);
  color: var(--br-text-muted);
}

/* -- states --------------------------------------------------------------

   Hover moves two things. The underline thickens, which is the signal this
   system already uses everywhere a near-black label cannot usefully change
   colour (base.css:498, services.css:516) — the colour move from #1f1902 to
   #2b2305 is real, faithful and invisible, so it rides along rather than
   carrying the state on its own.

   The row also takes --br-neutral-50, the measured "warm neutral hover wash".
   The services grid does not do this and does not need to: twelve one-line
   links on a tinted band are unambiguous about which one you are pointing at.
   Thirty-one four-line entries on white are not — with the underline alone,
   pointing at the description of entry 17 gives no feedback at all until the
   eye finds the title two lines above it. The wash tells you which ROW you are
   on, which is what the hit area actually is.

   :has() is the whole mechanism, because the pointer is usually over the
   description rather than the link. Engines without it (Safari < 15.4,
   Firefox < 121) keep the underline, which is the pre-existing behaviour and
   never a broken one. */
.br-listing__item:has(.br-listing__link:hover) { background: var(--br-neutral-50); }

.br-listing__link:hover {
  color: var(--br-ghost-hover-color);
  text-decoration-thickness: 2px;
}

.br-listing__link:active { color: var(--br-ink-active); }

/* Press feedback for touch, which never sees :hover — same plate, same
   reason the ghost button's press rule is unfenced in base.css:528. */
.br-listing__item:has(.br-listing__link:active) { background: var(--br-neutral-50); }

/* FOCUS RING ON THE ROW.
   base.css's global ring lands on the <a>, and Chrome draws one outline per
   inline fragment — so a two-line title gets two overlapping rectangles with
   a step where they meet, which reads as a rendering fault. services.css
   solved this by moving the ring to the label block; here it moves one level
   further out, onto the <li>, because the <li> is what the hit area covers.
   A keyboard user should see a ring around exactly the thing Enter will
   activate, and that is the whole row.

   Values are the house ring restated, not changed: 2px at 2px offset, per the
   written decision at base.css:355 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. The radius is bumped from --br-radius-xs to
   --br-radius-sm only because the ring is now tracing a ~150px-tall box
   rather than a line of text; a 2px corner on a box that size reads as a
   mitre, not a radius. */
.br-listing__link:focus-visible { outline: none; }

.br-listing__item:has(.br-listing__link:focus-visible) {
  outline: 2px solid var(--br-focus);
  outline-offset: 2px;
  border-radius: var(--br-radius-sm);
  background: var(--br-neutral-50);
}

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

/* -- forced colours ------------------------------------------------------
   Forced-colors modes throw away author background-color, so the hover and
   focus washes vanish. The underline and the outline both survive, so the row
   is still legible and still shows focus — but the hairlines are the page's
   whole structure and a 12%-alpha border repaints unpredictably. Pin it to
   CanvasText so the directory keeps its rules. */
@media (forced-colors: active) {
  .br-listing__item { border-top-color: CanvasText; }
}

/* -- column steps --------------------------------------------------------
   576 and 1200 are the system's own breakpoints — the container gutter steps
   at 576, 768, 992 and 1200.

   THE STEPS ARE SET BY THE LONGEST REAL TITLE, NOT BY TASTE. The reserved box
   holds two lines; the moment a column is narrow enough to push a real title
   onto a third, every rule below it in that column drops 28px out of register
   with its neighbours. So each step is placed where the widest title in the
   set still sets two lines, measured:

     >=1200  3 columns, 297px an entry at 1200 and 376px at 1440. The longest
             industry title ("Plumbers Insurance Designed to Protect Your
             Trade", 49 characters) sets two lines at both.
     576-1199  2 columns. Three was tried here and is wrong: at 1024 it gives
             252px an entry and that same title goes to three lines, which
             measured as 3.9px of drift across the three columns and would
             have been 28px on any width where a second title tipped over.
             1024 is one of the four judged widths.
     <576    1 column.

   Deliberately no four-column step at 1920. Four takes the entry to 328px and
   six of the 31 industry titles reach three lines. Same argument, and the same
   conclusion, as the services grid holding 25% above 1366 instead of stepping
   to 20%.

   THE COUNT IS A CEILING, NOT A COUNT. Each step is written `min(n, --_br-
   listing-cols)`, where the generator passes the number of entries on the
   <ul> as an inline custom property. A directory can never be given more
   columns than it has rows to fill them with.

   The case this catches is short lists, and it is a rendering-fault read
   rather than a spacing nit: with two entries and three columns the flow puts
   one entry in column one and one in column two, so two hairlines stop at
   two-thirds width above a visibly empty third column and the page looks like
   it failed to load its last third. It is not reachable on the three live
   pages (23 / 31 / 39 entries) — this is a floor under a filtered view, a
   newly seeded directory, or the day a category ships with one cover type in
   it.

   The fallback is the ceiling itself, so a generator that has not been taught
   to pass the property renders exactly as this file did before: three columns
   above 1200, two above 576. Nothing regresses if the hook is missing.

   AND IT IS BEHIND @supports, WHICH IS NOT DEFENSIVENESS. A `var()` makes a
   declaration valid at parse time and invalid at COMPUTED-VALUE time if the
   substituted value does not parse — and an invalid-at-computed-value-time
   `column-count` does not fall back to an earlier declaration, it falls back
   to the property's initial value, `auto`. On any engine that does not accept
   a math function where an <integer> is expected, the unguarded version would
   therefore put all 23, 31 and 39 entries in ONE column at every width. That
   is a much worse page than the one this rule is trying to improve, traded
   for a case that cannot occur on the three live pages.

   So the plain integers are declared first and stand on their own, and the
   ceiling is layered on only where the engine has said it can parse it. Same
   shape as the two `@supports not (selector(:has(*)))` guards elsewhere in
   this file. */
@media (min-width: 576px) {
  .br-listing__list {
    column-count: 2;
    --_br-listing-entry-h: var(--_br-listing-row);
  }
}
@media (min-width: 1200px) { .br-listing__list { column-count: 3; } }

@supports (column-count: min(2, 3)) {
  @media (min-width: 576px) {
    .br-listing__list { column-count: min(2, var(--_br-listing-cols, 2)); }
  }
  @media (min-width: 1200px) {
    .br-listing__list { column-count: min(3, var(--_br-listing-cols, 3)); }
  }
}

/* ARTICLES — the blog index. One column, then two at 1200.

   Post titles run to 90 characters against 49 for the longest industry, and
   they carry a dateline as well as a description, so this variant needs a
   wider entry than the directories do to hold the same two lines. Measured:
   two columns at 1200 give 473px and the longest title sets two lines; at 1024
   they give 404px and two titles set three, which is where the 60px of rule
   drift in the first pass came from.

   Below 1200 it is a single full-width row list rather than two cramped
   columns — which is what a blog archive looks like anyway, and with one
   column there is no cross-column register to break. */
.br-listing--articles .br-listing__list {
  column-count: 1;
  --_br-listing-entry-h: auto;
  /* One more reserved line and one more gap than a directory entry: the
     dateline. */
  --_br-listing-row: calc(
    1px + var(--br-small-lh) + var(--br-space-2)
    + 2 * var(--br-h4-lh) + var(--br-space-2) + 2 * var(--br-body-sm-lh) + 2 * var(--br-flow-xs)
  );
}
@media (min-width: 1200px) {
  .br-listing--articles .br-listing__list {
    column-count: 2;
    --_br-listing-entry-h: var(--_br-listing-row);
  }
}
@supports (column-count: min(2, 3)) {
  @media (min-width: 1200px) {
    .br-listing--articles .br-listing__list { column-count: min(2, var(--_br-listing-cols, 2)); }
  }
}

/* ==========================================================================
   3. PROSE  — {{body}}
   --------------------------------------------------------------------------
   The whole vocabulary the extracted content actually uses, counted across all
   105 bodies: p 1148, a 347, h2 562, h3 192, h4 16, ul 262, ol 11, li 1086,
   strong 504, em 21, figure 70, img 83, figcaption 4, blockquote 6,
   details 47, summary 47, iframe 8, br 44, article 20, div 11, svg 54, h1 6.
   Every one of them is answered below. A template that styles paragraphs and
   nothing else looks broken on two thirds of this site.
   ========================================================================== */

/* The measure is on the BLOCK, not on its children, and that is the fix for a
   bug rather than a shortcut. Capping `> *` leaves anything nested one level
   deeper uncapped — and 20 of the extracted bodies wrap their content in an
   <article> and 11 in a <div>, so on those pages every paragraph would have
   run the full 1240px container. It also let figures out: a stock photograph
   rendered 1240px wide directly under a 680px heading, which reads as two
   different pages stacked. One cap on the block holds everything, however
   deeply the CMS nested it.

   AND IT IS CENTRED. This was left flush left in the first pass, on the
   reasoning that every block on the home page starts at the container's left
   edge — which is true and is the wrong comparison. Every block on the home
   page also FILLS the container; a 680px column inside a 1240px container is
   not a home-page block, it is a reading measure, and this site already
   settled what happens to those. All four sibling long-prose templates centre
   theirs (article.css:121, page.css:234, service.css:227, industry.css:305)
   and page.css:214-231 writes the argument out at length, naming this file as
   one of the templates it took the decision from.

   Left-aligned it measured x 100..780 at 1440 with 560px of empty white down
   its right for the whole length of the block, sharing no edge with the
   footer band beneath it — a visible seam between two parts of one page.
   Centred, it sits on the same axis as the contact card and the footer, and
   the seam is gone. */
.br-listing__prose {
  max-width: var(--br-measure-prose);
  margin-inline: auto;
  padding-block: 0 var(--br-section-y);
}

.br-listing__prose:empty { display: none; }

/* Vertical rhythm as a single flow rule rather than per-element margins, so
   an element's spacing does not depend on what the CMS happened to put next
   to it. Headings get a larger space ABOVE them, which is what makes a
   heading read as belonging to the block below rather than the one above.

   THE LADDER IS THE HOUSE LADDER, not this file's own. service.css:236-244
   writes it out and page.css, industry.css and article.css all sit on it:

     paragraph to paragraph      2u/3   18.769 @1440   --br-flow-xs
     into an h2                  4u/3   37.538         --br-flow-md
     into an h3 / h4             1u     28.154         --br-flow-sm
     out of any heading          u/3     9.385         --br-flow-3xs

   Two of those were wrong here and both were wrong in the same direction —
   the body copy got less air than any sibling gives it while the sub-headings
   got more. p → p was --br-flow-2xs (14.077), the tightest paragraph gap
   anywhere on the site and the only one below 2u/3; and h3 and h4 shared h2's
   4u/3, so a card-title-scale heading was separated from the text above it by
   the same interval as a section heading. Both now read the shared values.

   H1 IS IN BOTH SELECTOR LISTS. Six of the 105 extracted bodies ship one (see
   the note under the heading scale below), and with the lists starting at h2
   a body h1 took the generic paragraph gap above it and the generic gap below
   — 14.077 either side of the largest thing in the column. The file already
   knew those six bodies existed; this was an omission in the rhythm rules,
   not an unconsidered case. */
.br-listing__prose > * + * { margin-top: var(--br-flow-xs); }

.br-listing__prose > * + :is(h1, h2) { margin-top: var(--br-flow-md); }
.br-listing__prose > * + :is(h3, h4, h5, h6) { margin-top: var(--br-flow-sm); }
.br-listing__prose > :is(h1, h2, h3, h4, h5, h6) + * { margin-top: var(--br-flow-3xs); }

/* Elementor wraps some bodies in <article> and <div>. They are transparent
   containers, so the flow rule has to reach inside them or every child in a
   wrapped body sits flush against its neighbour. Same interval as the block
   above, for the same reason: the wrapper is not a design decision. */
.br-listing__prose :is(article, div) > * + * { margin-top: var(--br-flow-xs); }

/* THE BODY H2 IS THE LONG-FORM RUNG, NOT THE SECTION RUNG.

   base.css gives a bare <h2> --br-h2-size — 45.457 at 1440 — and that step is
   correct for what it was measured on: a full-width band on the home page,
   spent seven times on seven genuine sections with nothing else near it. It
   is wrong inside a 680px reading measure. On the real /faq/ body, "Did you
   know, you can obtain cover for Cyclones in Northern Queensland?" sets THREE
   lines of 45px type in this column and reads as a page title rather than as
   a section heading — and it is 34% larger than the same string on every
   sibling template.

   --br-prose-h2-* is the shared answer, and tokens.css:1382 says so in as
   many words after the site briefly grew two long-form h2 rungs: "New
   long-form templates should read --br-prose-h2-*, which is the one whose
   name says what it is for." 34.000 at 1440, leading 1.2, tracking -0.02em.
   page.css:302 and industry.css read it; article.css reads its own 32px step
   for reasons recorded in that token's comment.

   Only the size moves. The intervals are the ladder above, and h3 (24.629,
   the card-title scale) and h4 (20, the label) are already right off base.css
   and are not restated.

   H1 IS IN THE SAME RULE, and that is why they are grouped. Six bodies in the
   extracted content ship an <h1>. None of them is one of this template's three
   pages, so this is a guard rather than a live fault: the page's single h1 is
   the title in the head band, and a second one in the body would give the
   document two. Setting it at the body-h2 rung means it does not LOOK like a
   second page title. The real fix belongs in the extractor — demote body h1s
   to h2 — and is flagged rather than silently patched here, because changing
   a heading level changes the document outline and that is a content
   decision. */
.br-listing__prose :is(h1, h2) {
  font-size: var(--br-prose-h2-size);
  line-height: var(--br-prose-h2-lh);
  letter-spacing: var(--br-prose-h2-ls);
}

/* Links in body copy are .br-link's treatment, applied by element rather than
   by class because the extracted HTML carries no classes. Kept in lockstep
   with base.css section 6 — if one changes, change both. */
.br-listing__prose a {
  color: var(--br-text-strong);
  font-weight: var(--br-weight-semibold);
  text-decoration: underline;
  text-underline-offset: 0.3em;
  text-decoration-thickness: 1px;
  border-radius: var(--br-radius-xs);
  transition:
    color var(--br-dur) var(--br-ease),
    text-decoration-thickness var(--br-dur) var(--br-ease);
}
.br-listing__prose a:hover { color: var(--br-ink-hover); text-decoration-thickness: 2px; }
.br-listing__prose a:active { color: var(--br-ink-active); }

/* Emphasis. 21 <em>s in the content set and the UA default already renders
   them correctly, so this rule changes nothing on screen — it is declared for
   the reason article.css:323 gives: stated rather than left implicit so
   nobody adds a colour to it later thinking the omission was an oversight.
   <i> rides along because the export uses both. */
.br-listing__prose :is(em, i) { font-style: italic; }

/* EMPTY ELEMENTS. Real content: 22 empty <p>s across the 105 extracted
   bodies, a WordPress export artefact rather than anything anyone typed.
   Left alone each one punches a paragraph's worth of phantom rhythm into the
   column. `:empty` matches an element with no children and no text at all,
   which is exactly what these are — a <p> holding a single space is NOT
   matched and still renders, because that is content somebody typed. Same
   rule, same reasoning, as service.css:276. */
.br-listing__prose :is(p, h1, h2, h3, h4, li):empty { display: none; }

/* -- lists ---------------------------------------------------------------
   1086 <li>s across the site, so this is the second most common block after
   the paragraph and it has to be right.

   The marker is coloured, not replaced. ::marker keeps the browser's own
   hanging indent, its own numbering for <ol>, and its own behaviour when a
   list item wraps — all three of which a ::before pseudo has to reimplement
   and usually gets wrong on the second line.

   --br-text-accent is the gold that is legible on white (#8a6d00, the eyebrow
   colour, 5.9:1). That is the only gold allowed to carry text weight on a
   light surface, and at 6px of dot per bullet it is an accent rather than
   decoration — the test being that removing it costs nothing but noticing it
   costs nothing either. Full brand gold (#f1c305) was the obvious alternative
   and is 1.7:1 on white: the markers would read as missing. */
.br-listing__prose :is(ul, ol) {
  padding-left: var(--br-space-6);
}

.br-listing__prose li::marker { color: var(--br-text-accent); }

.br-listing__prose li + li { margin-top: var(--br-flow-3xs); }

/* A nested list is a continuation of its parent item, not a new block. */
.br-listing__prose li > :is(ul, ol) { margin-top: var(--br-flow-3xs); }

/* -- blockquote ----------------------------------------------------------
   Six in the whole site, all of them a single pulled sentence inside an
   article. A gold rule is the right accent here precisely BECAUSE it is rare:
   one 3px bar on one page is the definition of an accent, and it is the same
   move the design already makes with the full-bleed gold band — colour used
   once, to mark the one thing worth stopping on. */
.br-listing__prose blockquote {
  margin-inline: 0;
  padding-left: var(--br-flow-sm);
  border-left: 3px solid var(--br-gold);
  color: var(--br-text);
}

.br-listing__prose blockquote p {
  font-size: var(--br-body-lg-size);
  line-height: var(--br-body-lg-lh);
  letter-spacing: var(--br-body-lg-ls);
}

/* -- figures, images, embeds ---------------------------------------------
   Everything stays inside the reading measure, including photographs — see
   the note on the block above. They carry the system's content-card radius
   (1u) so they belong to the same family as the cards on the home page. */
.br-listing__prose figure {
  margin-inline: 0;
  margin-block: var(--br-flow-md);
}

.br-listing__prose img {
  width: 100%;
  height: auto;
  border-radius: var(--br-radius-lg);
}

.br-listing__prose figcaption {
  margin-top: var(--br-flow-3xs);
  font-size: var(--br-small-size);
  line-height: var(--br-small-lh);
  letter-spacing: var(--br-small-ls);
  color: var(--br-text-muted);
}

/* Eight iframes in the content, all of them maps or video. A fixed
   width/height attribute pair on a 320px screen is a horizontal scrollbar on
   the whole document, so the box is forced fluid and given a ratio to reserve
   its space before it loads. */
.br-listing__prose iframe {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 9;
  border: 0;
  border-radius: var(--br-radius-lg);
}

/* 54 inline <svg>s, all of them Elementor's own icon set inside accordions.
   They arrive with no width attribute, which makes them fill their container.
   Held to the system icon size. */
.br-listing__prose svg {
  width: var(--br-icon);
  height: var(--br-icon);
}

/* -- accordion  (details / summary) --------------------------------------
   47 of each across the site — the FAQ page alone has eight.

   Native <details>, so it opens, closes, takes focus and answers Enter and
   Space with no JavaScript at all. Nothing here adds behaviour; it only
   replaces the browser's default disclosure triangle with the chevron the
   rest of this system uses, and gives the group the one hairline.

   THE CHEVRON IS THE SELECT CHEVRON. Same path, same 1.85 stroke, same
   14px box as .br-select in base.css:1010 — the geometry there was fitted by
   sweeping stroke weight against the reference's rendered ink, and there is
   no reason for this page to carry a second, differently-weighted chevron.
   Keep the three in lockstep: light select, dark select, this one. If you
   change the path or the weight, change all three and re-run _r4-chev.mjs.

   The extracted markup carries `tabindex="0"` and a hardcoded
   `aria-expanded="true|false"` on every <summary>. Both come from the CMS the
   content was pulled out of and both are wrong on a native disclosure: the
   summary is already focusable, and a hardcoded aria-expanded LIES the moment
   the user toggles it, because nothing updates it. Neither is styled around
   or depended on here, and the correct fix is in the extractor — flagged, not
   silently patched, because stripping attributes is the extractor's job. */
/* CONSECUTIVE ACCORDIONS ARE ONE BANK. article.css:570 states the house rule
   — "a rule above the first, a rule under each, no rule doubled between two"
   — and page.css:815 states the spacing half of it: "Air around a run, not
   between its rows."

   Both were broken here, and they compounded. Every <details> carried its own
   border-top AND took --br-flow-2xs from the generic flow rule, so every
   adjacent pair in an eight-question FAQ rendered as rule / 14px of white /
   rule: eight questions, fourteen visible hairlines, and a stutter between
   each one instead of a single divided list.

   The bottom rule was `:last-of-type`, which closes the last accordion ON THE
   PAGE rather than the last of a run. The city pages ship two separate
   accordion banks in one body, so the first bank had no bottom rule at all
   and ended on an open edge. `:not(:has(+ details))` is the test that means
   what the design means — it is the last row of ITS run — and the mirror test
   `:not(details + details)` is the first row of one. That pair is page.css's
   shape, taken verbatim rather than reinvented, and the margin-top reset on
   `details + details` is what stops the flow rule reopening the gap the
   borders just closed. */
.br-listing__prose details { border-block-start: 1px solid var(--br-border); }

.br-listing__prose details:not(details + details) { margin-block-start: var(--br-flow-md); }

.br-listing__prose details:not(:has(+ details)) {
  border-block-end: 1px solid var(--br-border);
  margin-block-end: var(--br-flow-md);
}

.br-listing__prose details + details { margin-top: 0; }

/* Without :has(), `:not(:has(+ details))` never matches and the run would
   close on nothing. Fall back to the page-scoped test — right for a body with
   one bank, which is 46 of the 47 accordions in the content set, and never
   worse than no closing rule at all. */
@supports not (selector(:has(*))) {
  .br-listing__prose details:last-of-type {
    border-block-end: 1px solid var(--br-border);
    margin-block-end: var(--br-flow-md);
  }
}

.br-listing__prose details[open] { padding-bottom: var(--br-flow-2xs); }

/* THE PADDING IS ON THE SUMMARY, NOT ON THE DETAILS, and that is a tap-target
   decision rather than a styling one. Only the <summary> is clickable; padding
   on its parent makes the row LOOK 54px tall while the thing you can actually
   press is the 26px line of text inside it. Measured that way first: every
   accordion header came back 680x26 against WCAG 2.5.8's 24px minimum — it
   scraped a pass and had no margin at all at a smaller root font size. Moved
   here it is 54px, which clears 2.5.5's 44px as well, and the visible row is
   pixel-identical. */
.br-listing__prose summary {
  position: relative;
  padding-block: var(--br-flow-2xs);
  padding-right: var(--br-space-8);
  cursor: pointer;
  list-style: none;

  font-size: var(--br-h4-size);
  line-height: var(--br-h4-lh);
  letter-spacing: var(--br-h4-ls);
  font-weight: var(--br-heading-weight);
  color: var(--br-text-heading);

  transition: color var(--br-dur) var(--br-ease);
}

.br-listing__prose summary::-webkit-details-marker { display: none; }

.br-listing__prose summary:hover { color: var(--br-ink-hover); }

/* THE SUMMARY GETS THE ROW'S RING, NOT THE GLOBAL ONE.

   This deliberately deferred to base.css's global
   :where(...summary...):focus-visible, on the reasoning that the values are
   the same 2px at 2px offset. The values are — the SHAPE is not. base.css
   draws at --br-radius-xs (2px), which on a line of text is invisible and on
   a 680px full-width flex row is a near-square-cornered rectangle that reads
   as a page-level outline rather than as a control. page.css:881 overrides
   the same global rule for exactly that reason and says so.

   The consequence of deferring was worse than a rectangle: one page carried
   two focus-ring shapes. Tab through /insurance/ with a body and the index
   rows show an 8px-radius ring with a neutral wash (see .br-listing__item
   above), then the accordion 300px below shows a bare 2px-radius box. Same
   page, same key, two answers. Restated here at the row's own values so the
   page has one ring. */
.br-listing__prose summary:focus-visible {
  outline: 2px solid var(--br-focus);
  outline-offset: 2px;
  border-radius: var(--br-radius-sm);
}

.br-listing__prose summary::after {
  content: "";
  position: absolute;
  right: 0;
  top: 50%;
  width: 14px;
  height: 14px;
  margin-top: -7px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%231f1902' stroke-width='1.85' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6.62 8.82 12 14.67 17.38 8.82'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: center;
  background-size: 14px 14px;
  transition: transform var(--br-dur) var(--br-ease);
}

.br-listing__prose details[open] > summary::after { transform: rotate(180deg); }

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

/* The panel. `summary + *` rather than a wrapper, because the extracted
   markup puts the answer as a bare sibling of the summary with no container
   to hang a class on. */
.br-listing__prose details > summary + * { margin-top: var(--br-flow-3xs); }

/* Forced colours drops the chevron's background-image outright, which would
   leave the accordion with no open/closed affordance at all beyond the panel
   itself. Repaint it as a CSS triangle in the system palette. */
@media (forced-colors: active) {
  .br-listing__prose summary::after {
    background: none;
    width: 0;
    height: 0;
    margin-top: -3px;
    border-inline: 6px solid transparent;
    border-top: 7px solid CanvasText;
  }
  .br-listing__prose details { border-block-start-color: CanvasText; }
  .br-listing__prose details:not(:has(+ details)) { border-block-end-color: CanvasText; }
}

/* ==========================================================================
   4. NARROW WIDTHS
   The system halves its spacing scale at 320 and below (services.css:589).
   Nothing here needs redistributing the way the chip row did — the entries
   are already a single column by then — but the reserved boxes get tight, so
   the padding comes in one step.
   ========================================================================== */

@media (max-width: 320px) {
  .br-listing__item { padding-block: var(--br-flow-2xs); }
  .br-listing__prose :is(ul, ol) { padding-left: var(--br-space-5); }
}
