/* ==========================================================================
   HERO — "Commercial insurance, that works."
   --------------------------------------------------------------------------
   Depends on tokens.css + base.css.

   Every number below was measured off the signed-off reference, and the
   ramps were walked rather than sampled: 320 / 360 / 375 / 390 / 414 / 430 /
   440 / 450 / 460 / 470 / 476-481 / 540 / 576 / 600 / 700 / 767 / 768 / 800 /
   860 / 900 / 960 / 980 / 991 / 992 / 993 / 1000 / 1024 / 1100-1110 / 1150 /
   1180 / 1198 / 1199 / 1200 / 1220 / 1280 / 1360 / 1440 / 1600 / 1728 / 1920.
   Sampling four widths and fitting one straight line through them is what
   put this section wrong between the samples the first time round; anything
   that turned out to be stepped is now stepped.

   Surface model:
     .br-hero        full-bleed photo + one flat warm overlay
     .br-hero__intro .br-on-dark  → white type, gold focus ring, white
                                    ghost-button plate on hover
     .br-hero__form  a white card, so it deliberately sits OUTSIDE the
                     dark surface set and keeps the default light tokens
                     (ink focus ring, #d9d9d9 control borders).
   ========================================================================== */

.br-hero {
  /* ----------------------------------------------------------------------
     Hero-only measured constants.
     These are NOT in tokens.css on purpose: they describe this one section
     — its asymmetric block padding and the lead-form card's own small type
     ramp — and nothing else on the page reuses them. Everything that IS
     shared (colour, radius, control geometry, gaps, section rhythm) still
     comes from a global token.
     ---------------------------------------------------------------------- */
  --br-hero-pad-top: 76px;             /* measured, flat at every width */
  --br-hero-pad-bottom: 104px;         /* measured, flat at every width */

  --br-hero-form-title-size: 21px;     /* measured: Archivo 700 */
  --br-hero-form-title-lh: 25.62px;    /* measured (1.22) */
  --br-hero-form-title-ls: -0.01em;    /* measured: -0.21px at 21px */
  --br-hero-form-title-gap: 6px;       /* measured */

  --br-hero-form-sub-size: 13.5px;     /* measured */
  --br-hero-form-sub-lh: 20.25px;      /* measured (1.5) */
  --br-hero-form-sub-gap: 22px;        /* measured: gap down to the first field */

  --br-hero-form-note-size: 12.5px;    /* measured */
  --br-hero-form-note-gap: 14px;       /* measured */

  position: relative;
  isolation: isolate;

  /* Nothing in this section is meant to escape it, and the headline runs
     `overflow-wrap: normal` so the word "Commercial" can hang the one pixel
     the reference hangs it (see the long note on .br-hero__title). That
     leaves one way for pathological content — a 60-character token, a pasted
     URL — to widen the document, so it is closed here.

     `clip`, not `hidden`: `hidden` makes this a scroll container, which lets
     the browser scroll the section itself when a control inside takes focus
     and breaks position:sticky for anything the assembly pass puts in here.
     `clip` just clips. The x axis only, so nothing vertical is affected.

     Measured: without this, a 60-char token in the h1 pushed the document to
     1195px inside a 320px viewport. With it, all seven cases in
     _r4-stress.mjs are flat across 280-1920. */
  overflow-x: clip;

  /* The photo resolves to this if it 404s or is still decoding, so the white
     headline never lands on a white page. */
  background-color: var(--br-ink);

  /* ----------------------------------------------------------------------
     THE SEPIA CORRECTION.  Read the numbers before changing this back.

     THE treatment is one flat warm overlay laid over the dusk photo — a 6%
     top-to-bottom settle, not a decorative gradient. That part is unchanged
     and is still the signed-off look. What changed is the overlay INK.

     Warren's note was "the home page looks more sepia colourwise". The first
     assumption — that we had drifted off the wise-scaffold reference — is
     WRONG, and it was tested rather than argued. Photo + overlay sampled at
     nine points across the hero box, ours against
     test_html/broadrisk/home-hero-h-photo.html, foreground hidden, same
     fractional coordinates, 1440x900:

         mean delta ours - ref:   R 0.0   G 0.0   B 0.0

     Pixel-identical at every point. We reproduced the reference exactly; the
     reference is itself what reads as sepia. So this is not a regression to
     undo, it is a property of the ink to correct.

     The ink was rgba(31,25,2). Its blue channel is 2 — effectively zero — so
     at .84 opacity it does not darken the photograph's blue, it DELETES it,
     and replaces the whole field with its own hue. Measured across the nine
     points, before: hue 43-60 deg at 25-52% saturation. That is the textbook
     description of sepia, and it is the ink doing it, not the photograph.

     Warren's own live site puts a NEUTRAL overlay on this same photo —
     linear-gradient(90deg,#000000E0,#00000082), site-archive/index.html — so
     "less sepia" is him asking for the picture he already has.

     The fix is the blue channel and nothing else: 2 -> 16. Blue carries only
     0.0722 of relative luminance, so restoring it neutralises the cast
     without lightening the plate the white type sits on. Measured, same nine
     points, before -> after:

         sky-top-centre       (36,36,21) 59/26%  ->  (36,36,33) 57/ 4%
         sky-upper-right      (37,37,22) 60/25%  ->  (37,37,34) 63/ 4%
         sky-upper-left       (39,37,22) 53/28%  ->  (39,37,33) 39/ 8%
         mid-centre           (34,31,12) 49/47%  ->  (34,31,24) 38/19%
         mid-left-edge        (44,36,16) 43/46%  ->  (44,36,28) 31/22%
         mid-right-edge       (35,30,11) 48/52%  ->  (35,30,22) 36/22%
         lower-left           (43,41,25) 51/27%  ->  (43,41,36) 38/ 9%
         shadow-bottom        (33,30,14) 51/39%  ->  (33,30,25) 39/13%
         shadow-bottom-right  (34,31,16) 52/37%  ->  (34,31,27) 39/12%

     Every R and every G is unchanged to the digit. The photograph is NOT
     desaturated and NOT re-graded — only the blue the ink was crushing comes
     back. Mean saturation 36.3% -> 12.5%; every point still reads warm
     (hue 31-63 deg), so it is still a warm dark overlay, just not a sepia one.

     Contrast held, by the method documented on .br-hero__sub below —
     brightest plate pixel inside the paragraph's own box, 85% white
     composited over it:

         .br-hero__sub   7.41:1  ->  7.36:1     (AAA, >= 7:1)
         .br-hero__title 9.50:1  ->  9.42:1     (pure white)

     Mean plate luminance rises 2.9%, which is below the threshold where the
     hero reads as a lighter picture.

     Why 16 and not more: at blue 18 the sky points cross to blue-dominant
     (260 deg) and at 20 the whole field goes cool. 16 is the last value where
     every sampled point is still on the warm side of neutral.

     Scoped to .br-hero deliberately. --br-photo-overlay is defined on
     .br-on-photo in tokens.css and the industry, landing and insurance-index
     templates all inherit it; changing it there would re-grade 100+ pages
     Warren has not looked at yet. This is the page he reviewed. Roll it up to
     the token once he confirms the direction.
     ---------------------------------------------------------------------- */
  /* The overlay now lives ONCE, on .br-on-photo in tokens.css — pure black,
     horizontal, matching his live page exactly. The local override that used
     to sit here has gone: it was a warm ink, which is what kept the sepia,
     and keeping a second copy here is how the home page and the other 106
     pages drift apart. */

  background-image: var(--br-photo-overlay), url("../../assets/homebanner.jpg");
  background-repeat: no-repeat, no-repeat;
  background-size: auto, cover;
  background-position: 0% 0%, 50% 50%;
}

/* Measured: 76 top / 104 bottom, and it does NOT scale with the viewport. */
.br-hero__inner {
  padding-block: var(--br-hero-pad-top) var(--br-hero-pad-bottom);
}

/* --------------------------------------------------------------------------
   GRID
   Gutter between the columns is 2u, so it rides the shared fluid unit and
   lands on the reference at every width (48.00@320, 48.23@390, 51.14@768,
   53.11@1024, 56.31@1440, 60.00@1920).

   The columns are NOT a 1:1 split everywhere, and this is the bit that was
   wrong before. `1fr` is `minmax(auto, 1fr)`, so a track cannot be squeezed
   below the min-content width of what is in it — and from 1199 to ~1300 the
   word "Commercial" set at 82-87px is wider than half the row, so the
   headline column pushes the form column narrower. Measured, reference vs
   this file, headline column / form column:

       1100   443.16 / 443.16   (fits: even split)
       1199   502.80 / 481.75   ("Commercial" at 82.68px = 502.80)
       1200   522.98 / 422.56   ("Commercial" at 86.00px = 522.98)
       1280   528.16 / 496.78   ("Commercial" at 86.86px = 528.16)
       1360   552.16 / 552.16   (fits again: even split)

   So this is not a breakpoint to hard-code, it is min-content sizing doing
   its job — `repeat(2, 1fr)` reproduces all five rows for free, where
   `repeat(2, minmax(0, 1fr))` forced an even split and cost the headline
   column 49px at 1200, which pushed the sub-headline to four lines against
   the reference's three.

   Below 768 the single track keeps its 0 floor, so a viewport narrower than
   any real device still cannot produce a horizontal scrollbar.
   -------------------------------------------------------------------------- */
.br-hero__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--br-flow-lg);
  align-items: center;
}

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

/* --------------------------------------------------------------------------
   LEFT COLUMN — headline, sub-headline, calls to action
   Measured rhythm: headline → sub is 18.77 (2u/3), sub → buttons is
   18.77 + 14.08 (u/2). That extra half-unit is a margin on the button row
   itself, top AND bottom, and the trailing one is load-bearing: it is what
   pulls the whole stack ~7px above the optical centre of the card.
   -------------------------------------------------------------------------- */
.br-hero__intro {
  display: flex;
  flex-direction: column;
  gap: var(--br-flow-xs);

  /* Measured, and deliberate. In the reference this column is a 12-of-12
     cell of a percentage grid, and it lands exactly 1px narrower than the
     track that holds it at EVERY width (287 in a 288 track at 320; 590.84
     in a 591.84 track at 1440; 521.98 in a 522.98 track at 1200). That 1px
     is not decoration — it is the width the headline and the sub-headline
     are wrapped against, so leaving it out shifts glyph rasterisation by a
     subpixel and can flip a line break at the boundary. Reproduced as a
     value, not inherited as a bug. */
  width: calc(100% - 1px);
}

/* The display utility paints headings in --br-text-heading, which goes gold
   on a dark surface. The hero headline is the one that stays white. */
.br-hero__title {
  color: var(--br-text-strong);

  /* Measured on the reference: text-wrap computes to `balance`. This is the
     single most visible thing about the hero, because at 320-480 greedy
     wrapping gives "Commercial / insurance, that / works." — a 338px line
     followed by a 152px stub — where balancing gives the reference's
     "Commercial / insurance, / that works." (219 / 191 / 201 at 320). Three
     near-equal lines at 0.85 leading IS the signature of this hero, and it
     is the balancer that produces them, not the column width. */
  text-wrap: balance;

  /* NO font-weight here. It carried `var(--br-weight-black)` until round 5,
     when --br-display-weight — which was wrongly set to 800 — was corrected to
     900 in tokens.css. The utility now declares the reference's own weight, so
     restating it locally would only re-open the split this override was
     papering over. */
}

/* --------------------------------------------------------------------------
   THE WORD "COMMERCIAL" MUST NOT BREAK. Read this before touching
   overflow-wrap anywhere that can reach this heading.

   base.css sets `overflow-wrap: break-word` on all of h1-h6 — a correct,
   deliberate guard against an unbreakable pasted token scrolling the page
   sideways (it was added after a renewal h2 took the document to 1409px
   inside a 390px viewport). It is right for every other heading on the site
   and wrong for this one, because this one is also `text-wrap: balance`.

   The two together misfire in a narrow band. From 1199 to ~1300 the headline
   column is one pixel narrower than the word "Commercial" set at 82-87px —
   that is the min-content squeeze documented on the grid above, and it is
   reproduced from the reference on purpose. `break-word` hands the balancer
   permission to split anywhere, and to even out three lines it takes it:

       1199-1300   "Commercia / l insurance, / that works."

   No hyphen, no explanation, in 87px type, in the first thing anyone sees.
   The reference leaves the word whole and lets it hang that one pixel over
   the column edge, where it is invisible. Verified after this rule: line
   breaks match the reference at 320 / 390 / 1150 / 1199 / 1200 / 1240 /
   1280 / 1300 / 1360.

   Turning the guard off does re-open the hole it was added for, so the hole
   is closed on the section instead — see `overflow-x: clip` on .br-hero
   above. That was verified, not assumed: with `overflow-wrap: normal` and no
   clip, a 60-character token in this h1 took the document to 1195px inside a
   320px viewport, and a pasted URL to 700px. With the clip, every case in
   _r4-stress.mjs is flat from 280 to 1920.

   Below 320 there is no real device left to protect and the band that
   misfires is nowhere near, so base.css's `break-word` is allowed to stand —
   a broken word is the better failure there.
   -------------------------------------------------------------------------- */
@media (min-width: 320px) {
  .br-hero__title { overflow-wrap: normal; }
}

.br-hero__sub {
  font-size: var(--br-body-size);
  line-height: var(--br-body-lh);
  letter-spacing: var(--br-body-ls);
  font-weight: var(--br-weight-semibold);

  /* Measured: 85% white.

     Contrast, re-measured properly after a review claimed this was 2.06:1 and
     called for a scrim. Method, so the next reader can redo it rather than
     trust the number: hide the h1 and this paragraph with visibility:hidden,
     screenshot this paragraph's own bounding box (that is photo + overlay and
     nothing else), take the pixel with the highest relative luminance, then
     composite 85% white over THAT pixel to get the colour the glyphs actually
     rasterise to, and compare the two.

     Worst case over 320 / 360 / 414 / 480 / 600 / 700 / 768 / 900 / 992 /
     1024 / 1200 / 1280 / 1440 / 1600 / 1920 is 7.40:1 at 1440 — brightest
     plate pixel rgb(75,70,43), glyphs rgb(228,227,223). Every other width is
     7.4-8.4:1, and against the mean plate it is 9.8-11.7:1. That clears AAA
     (7:1) for normal text at every width, not just AA.

     The 2.06:1 finding came from sampling rgb(176,170,159), which is a pixel
     of the RAW photo — no pixel that bright survives the .84/.78 overlay
     anywhere inside this box. No scrim: it would darken the left of a photo
     the client signed off, and it would buy nothing. */
  color: var(--br-white-a85);
}

/* --------------------------------------------------------------------------
   The reference wraps the sub-headline against a NARROWER box than the
   headline, and that box steps twice — at 768 and at 992, not at 1024.
   Measured target widths, and what these two rules produce (max error
   0.05px at any sampled width):

     width   ref box   here      width   ref box   here
     768     261.52    261.48    1100    436.56    436.58
     800     274.73    274.71    1199    496.14    496.14
     900     316.03    316.05    1200    516.33    516.32
     991     353.63    353.68    1440    585.00    584.99
     992     383.06    383.06    1920    682.78    682.78

   Below 768 there is no narrowing at all — the paragraph fills the column.
   -------------------------------------------------------------------------- */
@media (min-width: 768px) {
  .br-hero__sub { max-width: calc(83.3333% - 3.05px); }
}
@media (min-width: 992px) {
  .br-hero__sub { max-width: calc(100% - 4.73px - 0.0776vw); }
}

/* --------------------------------------------------------------------------
   CALLS TO ACTION
   The two buttons sit side by side when the column can hold them and take a
   full line each when it cannot — and the switch is driven by the COLUMN,
   not the viewport. Measured, walking one pixel at a time through both
   transitions: the column flips at the same place in both, regardless of the
   gap, which rules out a viewport breakpoint.

     column 444.41 (viewport 478)  → stacked
     column 445.41 (viewport 479)  → side by side
     column 444.64 (viewport 1105) → stacked
     column 445.13 (viewport 1106) → side by side

   So: a container query at 445px. Note this is why the buttons stack again
   from 768 to ~1105 — the two-column layout halves the headline column and
   it drops back under the threshold. A viewport media query cannot express
   that without three hard-coded bands that break the moment the gutters move.
   -------------------------------------------------------------------------- */
.br-hero__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--br-flow-2xs);
  margin-block: var(--br-flow-2xs);
  container: br-hero-actions / inline-size;
}

/* `min-width: 0` and `white-space: normal` are load-bearing, not tidy-up.
   .br-btn sets `white-space: nowrap` (base.css) so a side-by-side pair never
   breaks mid-label. A flex item's automatic minimum size is its min-content
   width, and for nowrap content that is the whole label on one line — so at
   `flex: 1 1 100%` in a 390px column, a ghost label longer than the column
   cannot shrink and pushes scrollWidth past the viewport. Measured with a
   43-character label: 406px against a 390px viewport, i.e. a horizontal
   scrollbar one copy edit away. The primary was already immune because its
   `min-width: min(var(--br-btn-min-w), 100%)` caps at 100%; the ghost had no
   equivalent.
   Stacked, the label is allowed to wrap inside the pill. Side by side, nowrap
   comes back below, so the measured single-line geometry is unchanged. */
.br-hero__actions > * {
  flex: 1 1 100%;
  min-width: 0;
  white-space: normal;
}

@container br-hero-actions (min-width: 445px) {
  .br-hero__actions > * { flex: 0 1 auto; white-space: nowrap; }
}

/* Re-assert the gold pill's measured 200px floor, which the blanket
   `min-width: 0` above would otherwise cancel — hero.css loads after
   base.css and the two selectors tie on specificity, so the last one wins.
   Caught by eye in a side-by-side: without this the pill renders 131px at
   1440 against the reference's 198px, which is the single most conspicuous
   element in the section.
   `min()` keeps the 100% cap, so the floor can still never cause an
   overflow — the ghost is the only child that needed the 0, and it has it.
   Must stay ABOVE the <=991 rule below, which deliberately drops this floor
   again on small screens. */
.br-hero__actions > .br-btn--primary {
  min-width: min(var(--br-btn-min-w), 100%);
}

/* Fallback for anything without container queries (pre-16 Safari). Without
   this the buttons would stay stacked forever, which is the wrong layout on a
   desktop. These are the VIEWPORT widths at which the column above crosses
   445px, so the bands land in the same places — they are just brittle to a
   gutter change in a way the container query is not, which is why they are
   the fallback and not the rule. */
@supports not (container-type: inline-size) {
  @media (min-width: 479px) and (max-width: 767px) { .br-hero__actions > * { flex: 0 1 auto; white-space: nowrap; } }
  @media (min-width: 1106px) { .br-hero__actions > * { flex: 0 1 auto; white-space: nowrap; } }
}

/* The gold pill's 200px floor is a DESKTOP-ONLY rule in the reference, and
   base.css currently applies it at every width. Measured on the reference's
   own primary: min-width computes to `auto` at 390 / 600 / 767 / 768 / 900 /
   991 and to `200px` at 992 / 1024 / 1440 — so between 479 and 767, where the
   two CTAs sit side by side in a single column, the reference's "Get a quote"
   is 136.89px wide and ours was 200px.

   This is a base.css rule, not a hero rule: the same 992 gate belongs on
   --br-btn-min-w for the whole page. It is corrected locally rather than
   globally only because several sibling sections have already been verified
   against the current behaviour and a shared-token change mid-flight would
   move their renders without anyone re-measuring them. Flagged for the
   assembly pass. */
@media (max-width: 991px) {
  .br-hero__actions > .br-btn--primary { min-width: 0; }
}

/* DELIBERATE DEVIATION, and the only geometric one in this section.
   At 320px and below the reference drops its button padding from 11px 24px
   to 4px 12px, which makes every pill in the hero 34px tall instead of 48px
   (measured: 34.00 at 300 / 319 / 320, 48.00 from 340 up). Three pills in
   this section, so our hero is 42px taller than the reference at exactly
   320px and identical at every other width.
   We do not reproduce it: 34px is below any sane touch target, 320px is a
   real device width (the original SE is still in the wild), and a taller
   button does not read as the cheaper build in a side-by-side. Recorded here
   so the 42px is understood as a decision rather than a miss. */

/* --------------------------------------------------------------------------
   RIGHT COLUMN — the lead form
   Measured: the card is pinned to the right edge of the container (464 wide,
   right edge flush with the gutter) and goes full width once the columns
   stack. Card geometry itself — 24px radius, 32/32/26 padding, the
   0 24px 64px shadow — is the shared .br-card--form.
   -------------------------------------------------------------------------- */
.br-hero__aside {
  display: flex;
  justify-content: flex-end;

  /* Lets this track give way when the headline's min-content claims more
     than half the row (see the grid note above). Without it the form's own
     intrinsic width would fight the headline for the 1199-1300 band and
     neither column would land on the reference. */
  min-width: 0;
}

/* The card is a light island. Its type ramp is a full step smaller than the
   page's, and because letter-spacing inherits as a computed length, setting
   it once here gives every child the reference's exact tracking. */
.br-hero__form {
  font-size: var(--br-small-size);
  line-height: var(--br-small-lh);
  letter-spacing: var(--br-small-ls);
}

/* The field labels take their tracking from the card, not from their own
   font size. Measured on the reference: -0.084px, which is -0.006em resolved
   against the card's 14px — letter-spacing inherits as a computed LENGTH, so
   the label keeps the parent's number even though it is set at 13px.
   base.css re-declares -0.006em on .br-field-label, which at 13px resolves to
   -0.078px and left "Company name" 0.07px wide of the reference. Inheriting
   is both the correct value and the correct mechanism. */
.br-hero__form .br-field-label { letter-spacing: inherit; }

.br-hero__form-title {
  font-family: var(--br-font-display);
  font-size: var(--br-hero-form-title-size);
  line-height: var(--br-hero-form-title-lh);
  letter-spacing: var(--br-hero-form-title-ls);
  font-weight: var(--br-weight-bold);
  color: var(--br-text-strong);
  margin-bottom: var(--br-hero-form-title-gap);

  /* DELIBERATE TYPOGRAPHIC DEVIATION — the only one in this card, and the
     only unforced one in the section. Documented because an unexplained
     value in this file reads as an accident.

     The reference sets no text-wrap here, so the line breaks greedily and at
     390px leaves a one-word widow:

         ref     "Get a structured insurance"  258.9px
                 "review"                       64.9px

     `pretty` rebalances the last lines:

         here    "Get a structured"            157.5px
                 "insurance review"            166.3px

     Same two lines, same box, same height — the card geometry does not move.
     Kept because a single orphaned word under a 21px heading is the kind of
     detail a side-by-side reads as the cheaper build, and because the fix
     costs nothing structurally.

     Consequence to know before you chase it: this is what the residual
     0.675% mobile pixel diff against the reference IS. Section-relative
     geometry is otherwise identical at 390 and at 1440. If you are hunting a
     mobile regression, this band (css y 565-605) is expected — start
     elsewhere. */
  text-wrap: pretty;
}

.br-hero__form-sub {
  font-size: var(--br-hero-form-sub-size);
  line-height: var(--br-hero-form-sub-lh);
  color: var(--br-text-muted);
  margin-bottom: var(--br-hero-form-sub-gap);
}

/* No margin on the submit: the last field already carries the measured 16px,
   and inside a flex card there is no margin collapsing to absorb a second. */
.br-hero__form-note {
  font-size: var(--br-hero-form-note-size);
  color: var(--br-text-muted);
  text-align: center;
  margin-top: var(--br-hero-form-note-gap);
}
