/* ==========================================================================
   The design system, for the builder's own elements.

   sbi.css styles the SBI sections. This is the other half: it teaches the page
   builder's generic elements — Container, Heading, Text, Button, Image, Icon
   box, Counter, FAQ — to wear the same clothes, so a page built out of them
   looks like the prototype without anybody writing custom CSS per block.

   How it is used: put one of these class names in a block's Advanced → CSS
   classes box. Nothing here applies on its own, so an element that is not
   opted in keeps the builder's plain default and nothing that already exists
   can be repainted by accident.

   ---------------------------------------------------------------------------
   TWO RENDERERS, ONE STYLESHEET

   The same element is drawn twice by different code, and they do not agree on
   the markup inside:

     the published page   Blade, in vendor/larabolt/runtime/resources/views
     the editor canvas    React, in the module's compiled editor bundle

   A Button is the clearest case: the page renders `<a>`, the canvas renders
   `<span>` (it has to be inert while you are editing). An Image renders `<img>`
   on the page and, with no picture chosen yet, a `.ph` placeholder on the
   canvas. So every rule below names both. Style one and the design is right in
   the editor and wrong on the site, or the other way round — which is exactly
   the bug this comment exists to stop being reintroduced.

   The other half of the arrangement is in editor-preview.js: the canvas gets
   these class names from its dress() pass, because the builder only writes
   them onto the element server-side.

   Why the extra layer rather than putting `.btn` straight on a Button: the
   class goes on the element that carries the block's id, and for a Button that
   is the wrapping <div>, not the control inside it. So the rules reach through.
   ========================================================================== */

/* ---------- buttons ----------
   `sbi-btn` on a Button element, plus one of the variants, is the same button
   the sections draw. The builder's own Style tab still owns size and spacing;
   these own the shape and the palette. */

.lb-button.sbi-btn > a,
.lb-button.sbi-btn > span {
  --bg: var(--ink);
  --fg: var(--paper);
  display: inline-flex; align-items: center; justify-content: center; gap: 10px;
  height: 48px; padding: 0 24px; border-radius: var(--pill);
  background: var(--bg); color: var(--fg);
  font-family: var(--f-body); font-weight: 600; font-size: 14.5px; letter-spacing: -.005em;
  transition: transform .25s var(--ease), background .2s, box-shadow .25s, color .2s;
  white-space: nowrap; border: 1px solid transparent; text-decoration: none;
}
.lb-button.sbi-btn > a:hover { transform: translateY(-1px); box-shadow: 0 10px 24px rgba(12, 30, 32, .18); }
.lb-button.sbi-btn > a:active { transform: translateY(0); }

.lb-button.sbi-btn-baize > a, .lb-button.sbi-btn-baize > span { --bg: var(--baize); --fg: var(--on-dark); }
.lb-button.sbi-btn-baize > a:hover { --bg: var(--baize-2); }
.lb-button.sbi-btn-gold > a, .lb-button.sbi-btn-gold > span { --bg: var(--gold-2); --fg: var(--deep); }
.lb-button.sbi-btn-gold > a:hover { --bg: #e2b64a; }
.lb-button.sbi-btn-light > a, .lb-button.sbi-btn-light > span { --bg: var(--paper); --fg: var(--ink); }
.lb-button.sbi-btn-ghost > a, .lb-button.sbi-btn-ghost > span { --bg: transparent; --fg: var(--ink); border-color: var(--line); }
.lb-button.sbi-btn-ghost > a:hover { border-color: var(--ink); box-shadow: none; }

/* On a dark band a ghost button inverts, exactly as `.on-dark .btn-ghost` does
   for the sections. */
.on-dark .lb-button.sbi-btn-ghost > a, .on-dark .lb-button.sbi-btn-ghost > span,
.on-baize .lb-button.sbi-btn-ghost > a, .on-baize .lb-button.sbi-btn-ghost > span {
  --fg: var(--on-dark); border-color: rgba(244, 240, 230, .28);
}
.on-dark .lb-button.sbi-btn-ghost > a:hover,
.on-baize .lb-button.sbi-btn-ghost > a:hover { border-color: var(--on-dark); }

.lb-button.sbi-btn-sm > a, .lb-button.sbi-btn-sm > span { height: 38px; padding: 0 16px; font-size: 13.5px; }
.lb-button.sbi-btn-lg > a, .lb-button.sbi-btn-lg > span { height: 56px; padding: 0 30px; font-size: 15.5px; }

/* ---------- containers ---------- */

/* A responsive grid. Both renderers write `display:flex` inline on every
   container, and an inline style beats a selector — hence !important on the one
   declaration that has to change. Columns fit themselves to the available
   width, so a row of four, five or six cards needs no per-breakpoint setting. */
.lb-container.sbi-grid {
  display: grid !important;
  grid-template-columns: repeat(auto-fit, minmax(var(--sbi-col, 260px), 1fr));
}
.lb-container.sbi-grid > * { min-width: 0; }

/* The bordered panel the sections use for a tile or a sidebar card. */
.lb-container.sbi-card {
  border: 1px solid var(--line); border-radius: var(--r-lg); background: var(--paper);
  overflow: hidden; transition: border-color .2s, box-shadow .3s var(--ease), transform .3s var(--ease);
}
.lb-container.sbi-card:hover { border-color: var(--baize-3); box-shadow: var(--shadow-1); transform: translateY(-2px); }
.on-dark .lb-container.sbi-card,
.on-baize .lb-container.sbi-card { background: rgba(244, 240, 230, .04); border-color: rgba(244, 240, 230, .16); }

/* A row of equal columns that becomes a stack on a phone. */
.lb-container.sbi-cols > * { flex: 1 1 0; min-width: 0; }
@media (max-width: 900px) { .lb-container.sbi-cols > * { flex: 1 1 46%; } }
@media (max-width: 600px) { .lb-container.sbi-cols { flex-direction: column !important; } }

/* ---------- images ----------
   `img` is the published page; `.ph` is the canvas standing in for a picture
   that has not been chosen yet. Both get the same frame so the layout does not
   move when one is. */
.lb-image.sbi-media { overflow: hidden; border-radius: var(--r-lg); }
.lb-image.sbi-media img, .lb-image.sbi-media .ph { border-radius: var(--r-lg); }
.lb-image.sbi-media figcaption {
  font-family: var(--f-mono); font-size: 12px !important; color: var(--ink-mute) !important; margin-top: 10px !important;
}

/* ---------- text ----------
   A Text element carrying a section head: the eyebrow, the display heading with
   its italic emphasis, and the lead. Both renderers put the editor's own markup
   inside, so these only space what the design system already styles. */
.lb-text.sbi-copy > * + * { margin-top: 16px; }
.lb-text.sbi-copy h1, .lb-text.sbi-copy h2, .lb-text.sbi-copy h3, .lb-text.sbi-copy h4 { margin: 0; }
.lb-text.sbi-copy p + p { margin-top: 12px; }

/* ---------- FAQ ----------
   The builder's accordion, in the design system's paper and rule.

   !important throughout because both renderers write this component's border,
   padding and weight inline on each <details>, <summary> and <p>, and an inline
   style beats any selector. Nothing here changes behaviour — only the paint. */
.lb-faq.sbi-faq details {
  border: 0 !important; border-top: 1px solid var(--line) !important;
  border-radius: 0; background: none; padding: 0 !important;
}
.lb-faq.sbi-faq details:last-child { border-bottom: 1px solid var(--line) !important; }
.lb-faq.sbi-faq summary {
  font-family: var(--f-display); font-size: clamp(18px, 1.6vw, 21px); font-weight: 400 !important;
  letter-spacing: -.01em; padding: 20px 0; color: var(--ink); list-style: none;
}
.lb-faq.sbi-faq summary::-webkit-details-marker { display: none; }
.lb-faq.sbi-faq summary::after {
  content: "+"; float: right; font-family: var(--f-mono); font-size: 18px; color: var(--ink-mute);
}
.lb-faq.sbi-faq details[open] summary::after { content: "–"; }
.lb-faq.sbi-faq details > p {
  font-size: 15.5px !important; line-height: 1.65; color: var(--ink-soft);
  opacity: 1 !important; margin: 0 0 20px !important; max-width: 70ch;
}

/* ---------- counters ----------
   Identical markup in both renderers; only the accent on the suffix is written
   inline, so that is the one declaration that has to be forced. */
.lb-counter.sbi-stat > b {
  font-family: var(--f-display); font-weight: 300; letter-spacing: -.03em; color: var(--baize);
}
.lb-counter.sbi-stat > b span { color: var(--gold) !important; }
.on-dark .lb-counter.sbi-stat > b { color: var(--gold-2); }
.on-dark .lb-counter.sbi-stat > b span { color: var(--on-dark-soft) !important; }
.lb-counter.sbi-stat > small {
  font-family: var(--f-mono); font-size: 11.5px !important; font-weight: 400 !important;
  letter-spacing: .12em; text-transform: uppercase; color: var(--ink-mute); opacity: 1 !important;
}
.on-dark .lb-counter.sbi-stat > small { color: var(--on-dark-mute); }

@media (prefers-reduced-motion: reduce) {
  .lb-button.sbi-btn > a, .lb-button.sbi-btn > span, .lb-container.sbi-card { transition: none; }
  .lb-button.sbi-btn > a:hover, .lb-container.sbi-card:hover { transform: none; }
}

/* ==========================================================================
   A hero built from Containers.

   The Hero slider block draws the whole hero from one settings panel: quick to
   fill in, and a single unit — nothing inside it can be selected, moved or
   restyled on its own.

   The behaviour that makes it a slider is not in the block, though. sbi.js
   binds to class names: `.hs` is a slider, `.hs-slide` children are its panels,
   `.hs-dot` are its dots. So an ordinary Container carrying `hs`, holding
   Containers carrying `hs-slide`, IS a slider — and every headline, button and
   image inside it is a real element with its own handle, its own Style tab and
   its own image picker.

   What the rules below do is give those Containers the layout sbi.css already
   describes. They have to use !important for one declaration each, because
   both renderers write `display:flex` inline on every container and an inline
   style beats any selector. Nothing else here is forced.

   The artwork is the other half: `hs-art` in the block is an inline SVG, which
   a Container cannot hold. `php artisan sbi:hero-art` writes the same three
   backdrops to /sbi-blocks/img/hero-{break,endgame,rack}.svg, so a slide takes
   one as an ordinary Background → Image and an editor can swap it for a
   photograph.
   ========================================================================== */

/* Only the slider itself has to be a grid: every slide sits in the same cell,
   which is what lets them cross-fade. Everything inside a slide is left as
   flex so its Layout and Size controls work — see the note above. */
.lb-container.hs {
  display: grid !important;
  /* An explicit track, because the Container writes `justify-content` inline
     and in grid layout that packs the TRACKS, not the content: a single auto
     track then sizes to its widest child and leaves the rest of the band
     empty. That is what stopped the artwork reaching the edge of the window
     and the copy sitting in the centred wrap. */
  grid-template-columns: minmax(0, 1fr) !important;
}

/* A slide's background is the artwork, so it needs the same darkening the
   block's own `::before` lays over it — without it the copy sits on bare
   colour and the contrast goes. */
.lb-container.hs-slide::before {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background: linear-gradient(90deg, rgba(12, 30, 32, .95) 0%, rgba(12, 30, 32, .72) 42%, rgba(12, 30, 32, .1) 100%);
}
/* isolate, not just relative.
   In the block the artwork is its own element at z-index -2 and the gradient
   above it at -1, both painting inside the slider's stacking context. Here
   the artwork is the slide's own background, and a ::before at -1 on an
   element that starts no stacking context paints BEHIND that background —
   so the darkening disappeared and the headline sat on the bare artwork.
   Isolating the slide puts the gradient back between the two. */
.lb-container.hs-slide { position: relative; isolation: isolate; }

/* The photo card beside the copy: a Container holding an Image element, rather
   than the block's own fixed markup. */
.lb-container.hs-photo .lb-image, .lb-container.hs-photo img { width: 100%; height: 100%; }

/* ---------- a section block, bare ----------
   With `bare` on, a section block draws only its live list: the band and the
   heading come from the Container it sits in, out of the builder's own
   elements. The block's own `.wrap` is then a second content width inside one
   that already exists, so it is stood down here rather than taken out of a
   dozen views. */
.sbi-bare > .wrap { width: 100%; max-width: none; margin-inline: 0; padding-inline: 0; }

/* ---------- the prototype's own section layouts ----------
   These class names come from sbi.css, where each is a CSS grid with its
   columns written into the stylesheet. On a Container they are deliberately
   left as flex — which is what both renderers write inline anyway — and the
   proportions come from each column's own Width instead.

   That is the difference between a layout an editor can work with and one they
   cannot. A grid puts its children in tracks the stylesheet owns: the Width
   control does nothing, Direction and Justify do nothing, and anything dragged
   in lands in whatever cell comes next rather than where it was dropped. As
   flex, every control in the Layout and Size panels drives the thing it names.

   So nothing here sets `display`. What remains is the one thing flex cannot
   express on its own.
*/

/* The column beside the questions stays with the reader while the answers
   scroll, as it does on the prototype. */
.lb-container.faq-grid > *:first-child { position: sticky; top: 32px; }
@media (max-width: 860px) { .lb-container.faq-grid > *:first-child { position: static; } }

/* ---------- plain slider dots ----------
   The Hero slider block numbers its slides — 01 02 03 over a progress bar —
   which is the prototype. A hero built out of Containers gets one plain dot per
   slide instead, which is what was asked for and what the marks below draw.

   The block is untouched: this only styles the strip sbi.js builds for a slider
   that had none, and it carries its own class so the two cannot be confused. */
.hs-dots-plain { display: flex; gap: 10px; align-items: center; }
.hs-dots-plain .hs-dot {
  min-width: 0; padding: 6px; display: inline-flex; align-items: center;
  background: none; border: 0; cursor: pointer;
}
.hs-dots-plain .hs-dot i {
  display: block; width: 9px; height: 9px; border-radius: 50%;
  background: rgba(244, 240, 230, .32); border: 0;
  transition: background-color .25s, transform .25s;
}
.hs-dots-plain .hs-dot i::after { content: none; }
.hs-dots-plain .hs-dot:hover i { background: rgba(244, 240, 230, .6); }
.hs-dots-plain .hs-dot.on i { background: var(--gold-2); transform: scale(1.25); }
.hs-dots-plain .hs-dot:focus-visible { outline: 2px solid var(--gold-2); outline-offset: 2px; border-radius: 999px; }

/* ---------- the arrow every SBI button carries ----------
   Render::button() appends Icons::arrow() to every button the design system
   draws, so a button without one is not the prototype's button. A Button
   element prints its label escaped and cannot hold an icon, so the same glyph
   is drawn here — the arrow's own path, masked so it takes the button's colour
   rather than a fixed one, and shifting on hover exactly as `.btn:hover
   svg.arrow` does. */
.lb-button.sbi-btn > a::after,
.lb-button.sbi-btn > span::after {
  content: "";
  width: 16px; height: 16px; flex: none;
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12h14M13 6l6 6-6 6'/%3E%3C/svg%3E");
  -webkit-mask-position: center;
  -webkit-mask-size: contain;
  -webkit-mask-repeat: no-repeat;
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12h14M13 6l6 6-6 6'/%3E%3C/svg%3E");
  mask-position: center;
  mask-size: contain;
  mask-repeat: no-repeat;
  transition: transform .25s var(--ease);
}
.lb-button.sbi-btn > a:hover::after { transform: translateX(3px); }

/* A button that should not carry one — a back link, a dot, a plain control. */
.lb-button.sbi-btn-bare > a::after,
.lb-button.sbi-btn-bare > span::after { content: none; }

@media (prefers-reduced-motion: reduce) {
  .lb-button.sbi-btn > a::after { transition: none; }
  .lb-button.sbi-btn > a:hover::after { transform: none; }
}

/* ---------- two-column bands ----------
   These columns carry a Width each — 50/50, 40/60 — and a gap between them.
   With wrapping on, a flex row breaks its lines from the widths BEFORE anything
   shrinks, so 50% + 50% + a 64px gap is wider than the row and the second
   column drops to a line of its own. That is why the split bands were stacking
   on a screen wide enough for both.

   So they do not wrap. The columns shrink to share the row, which is what the
   prototype's `1fr 1fr` does, and they stack at the width the design system
   already stacks them at rather than at whatever the arithmetic happens to
   give. */
.lb-container.intro-split,
.lb-container.join-grid,
.lb-container.faq-grid,
.lb-container.hs-grid { flex-wrap: nowrap; }

@media (max-width: 860px) {
  .lb-container.intro-split,
  .lb-container.join-grid,
  .lb-container.faq-grid,
  .lb-container.hs-grid { flex-direction: column !important; }

  .lb-container.intro-split > *,
  .lb-container.join-grid > *,
  .lb-container.faq-grid > *,
  .lb-container.hs-grid > * { width: auto !important; max-width: none !important; }
}

/* ---------- a band that runs on from the one above ----------
   `.sbi-blk.sbi-join` does this for a block that is its own band: no padding
   above, and a smaller margin instead, with the band before it dropping its
   padding below so the two read as one. A Container carrying the class needs
   the same, and carries neither `.sbi-blk` nor the adjacency the original
   selector relies on. */
.lb-container.sbi-join { padding-top: 0; margin-top: clamp(40px, 6vw, 72px); }
.lb-container:has(+ .lb-container.sbi-join) { padding-bottom: 0; }

/* A button that leads with the document glyph, as the Calendar PDF one does in
   the prototype. Same masking trick as the arrow, so it takes the button's
   colour; pair it with `sbi-btn-bare`, which takes the trailing arrow off. */
.lb-button.sbi-btn-doc > a::before,
.lb-button.sbi-btn-doc > span::before {
  content: "";
  width: 16px; height: 16px; flex: none;
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6.5 3h7.5l4.5 4.5V19a2 2 0 0 1-2 2h-10a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2Z'/%3E%3Cpath d='M13.5 3v5h5M8.5 13h7M8.5 16.5h5'/%3E%3C/svg%3E");
  -webkit-mask-position: center;
  -webkit-mask-size: contain;
  -webkit-mask-repeat: no-repeat;
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6.5 3h7.5l4.5 4.5V19a2 2 0 0 1-2 2h-10a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2Z'/%3E%3Cpath d='M13.5 3v5h5M8.5 13h7M8.5 16.5h5'/%3E%3C/svg%3E");
  mask-position: center;
  mask-size: contain;
  mask-repeat: no-repeat;
}

/* ---------- the membership bands ----------
   `.mk-band` and `.mk-tiers` are grids in sbi.css; as Containers they stay flex
   so the Layout and Size panels drive them, and the proportions come from each
   column's own Width — the same arrangement as the split bands above, for the
   same reason. They stack at the widths the design system already stacks them
   at rather than wherever the arithmetic happens to break. */
.lb-container.mk-band,
.lb-container.mk-tiers { flex-wrap: nowrap; }

@media (max-width: 1000px) {
  .lb-container.mk-band { flex-direction: column !important; align-items: stretch !important; }
  .lb-container.mk-band > * { width: auto !important; }
}

@media (max-width: 560px) {
  .lb-container.mk-tiers { flex-direction: column !important; }
  .lb-container.mk-tiers > * { width: auto !important; }
}

/* A price card's label, figure and note are a stack. `.mk-t` is a grid in
   sbi.css and its children stack because they are its children; here they sit
   inside a Text element, and a span, a <b> and a <small> in a plain div run
   together on one line. The Text element does the stacking instead. */
.lb-container.mk-t > .lb-text { display: grid; gap: 2px; }

/* ---------- the other way to pay ----------
   A tier carries a yearly price and a monthly one. The headline is whichever
   the block is set to; this is the alternative under it, quiet enough not to
   compete with the figure above. */
.tier .tier-also {
  display: block; margin-top: -8px;
  font-size: 13px; color: var(--ink-mute);
}
.tier.feat .tier-also { color: var(--on-dark-mute); }
.mk-t .mk-also { color: var(--on-dark-soft); font-size: 12px; margin-top: -1px; }

/* ---------------------------------------------------------------- sign out
   The account dropdown's last row. Signing out is a POST on both guards, so
   this one row is a <button> inside a <form> rather than an <a> — `.dd-item`
   lays it out, and these four lines take the browser's button chrome back off
   so it matches the links above it. */
.dd-signout { margin: 0; }
.dd-signout .dd-item {
  width: 100%; border: 0; background: none; color: inherit;
  font: inherit; text-align: left; cursor: pointer;
}

/* ==========================================================================
   The builder's intake form, in the SBI card.

   `[form key="…"]` renders the module's own `.pb-form` markup, and
   user/css/pb-widgets.css dresses it in the console's palette — #d9dfe8
   borders, a #267043 pill. On a page built out of the design system that
   reads as a form borrowed from somewhere else, which is what the contact
   page was showing beside the prototype's own panels.

   Restyled here rather than by rewriting the markup, so the honeypot, the
   rate limit and the reCAPTCHA gate all stay exactly where they are, and any
   form an editor drops on any page gets the same treatment. Scoped to
   `.sbi-blk` so the console's own forms keep the console's styling.

   ref: .form-card / .field / .inp / .check / .btn-baize in sbi.css
   ========================================================================== */
/* Stacked, the card IS the section, so the section keeps no padding of its own.
   Split, the card is one half of an ordinary section and the padding stays. */
.sbi-blk.section:has(.pb-form):not(.sbi-form-split) { padding-block: 0; }

.sbi-blk.section:has(.pb-form) > .wrap-narrow {
  max-width: none;
  padding: clamp(24px, 3vw, 40px);
  border-radius: var(--r-xl);
  background: var(--paper);
  border: 1px solid var(--line);
  box-shadow: var(--shadow-1);
}

/* The heading the block prints above the form is the card's own heading. */
.sbi-blk.section:has(.pb-form) > .wrap-narrow > h2 {
  font-size: 28px;
  margin-top: 0;
}
.sbi-blk.section:has(.pb-form) > .wrap-narrow > div { margin-top: 24px; }

/* The prototype puts the short answers two to a row and lets the message run
   the width. Which fields are short is not this sheet's business — anything
   holding a textarea spans, everything else pairs up. */
.sbi-blk .pb-form__form {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 18px 20px;
}
.sbi-blk .pb-form__row { margin: 0; display: grid; gap: 8px; align-content: start; min-width: 0; }
.sbi-blk .pb-form__row:has(textarea) { grid-column: 1 / -1; }
.sbi-blk .pb-form__check,
.sbi-blk .pb-form__status,
.sbi-blk .pb-form__submit { grid-column: 1 / -1; }

@media (max-width: 640px) {
  .sbi-blk .pb-form__form { grid-template-columns: 1fr; }
}

.sbi-blk .pb-form__row label {
  margin: 0;
  font-family: var(--f-body);
  font-size: 13px;
  font-weight: 600;
  color: var(--ink-2);
  letter-spacing: 0;
}

.sbi-blk .pb-form__row input,
.sbi-blk .pb-form__row select,
.sbi-blk .pb-form__row textarea {
  width: 100%;
  height: 52px;
  border-radius: var(--r);
  border: 1px solid var(--line);
  background: var(--paper);
  padding: 0 16px;
  font-family: var(--f-body);
  font-size: 15px;
  color: var(--ink);
  transition: border-color .2s, box-shadow .2s;
  outline: none;
  appearance: none;
  -webkit-appearance: none;
  box-shadow: none;
}
.sbi-blk .pb-form__row textarea {
  height: auto;
  min-height: 132px;
  padding: 14px 16px;
  line-height: 1.55;
  resize: vertical;
}

/* The select's own arrow went with appearance:none, so draw the design
   system's. The mask keeps it in currentColor rather than a fixed grey. */
.sbi-blk .pb-form__row select {
  padding-right: 42px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%237b7f78' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 14px center;
  background-size: 18px 18px;
}

.sbi-blk .pb-form__row input:hover,
.sbi-blk .pb-form__row select:hover,
.sbi-blk .pb-form__row textarea:hover { border-color: #cfc8b6; }

.sbi-blk .pb-form__row input:focus,
.sbi-blk .pb-form__row select:focus,
.sbi-blk .pb-form__row textarea:focus {
  border-color: var(--baize);
  box-shadow: 0 0 0 4px rgba(26, 58, 61, .1);
}
.sbi-blk .pb-form__row input::placeholder,
.sbi-blk .pb-form__row textarea::placeholder { color: #a3a79f; }

/* The consent line. A native checkbox rather than the design system's drawn
   box, because that one needs a span the module does not render — accent-color
   paints the real control in baize and asks nothing of the markup. */
.sbi-blk .pb-form__check {
  display: flex;
  gap: 12px;
  align-items: flex-start;
  font-size: 14px;
  color: var(--ink-soft);
  line-height: 1.45;
}
.sbi-blk .pb-form__check label {
  font-weight: 400;
  font-size: 14px;
  color: var(--ink-soft);
  display: inline;
}
/*
 | The consent tick, drawn as the prototype draws it.
 |
 | The prototype hides the real input and styles a `<span class="box">` beside
 | it, with the tick as an inline SVG. The intake form has no such span — it is
 | a plain label round a checkbox, and it is shared by every form on the site —
 | so the control is drawn on the input itself instead. Same 22px rounded box,
 | same border, same baize fill and white tick on check.
 |
 | Every declaration is here because the consent row carries `pb-form__row` as
 | well as `pb-form__check`, so the text-field rule above dresses this checkbox
 | as a 52px input with 16px of padding. Taking the height and the padding back
 | is as necessary as drawing the tick.
 */
.sbi-blk .pb-form__check input[type="checkbox"] {
  appearance: none;
  -webkit-appearance: none;
  width: 22px;
  height: 22px;
  margin: 0;
  padding: 0;
  flex-shrink: 0;
  border: 1.5px solid #c9c2b0;
  border-radius: 7px;
  background: var(--paper) center / 13px no-repeat;
  box-shadow: none;
  cursor: pointer;
  transition: background-color .2s, border-color .2s;
}
.sbi-blk .pb-form__check input[type="checkbox"]:checked {
  background-color: var(--baize);
  border-color: var(--baize);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23ffffff' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m5 12.5 4.5 4.5L19 7.5'/%3E%3C/svg%3E");
}
.sbi-blk .pb-form__check input[type="checkbox"]:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: 2px;
}
/* The prototype's `.check.err .box`, on the field the server objected to. */
.sbi-blk .pb-form__check input[type="checkbox"][aria-invalid="true"] { border-color: var(--err); }
.sbi-blk .pb-form__check label { cursor: pointer; }
.sbi-blk .pb-form__check a { color: var(--ink); text-decoration: underline; text-underline-offset: 2px; }

.sbi-blk .pb-form__submit {
  justify-self: start;
  display: inline-flex; align-items: center; justify-content: center; gap: 10px;
  height: 56px; padding: 0 30px;
  border: 1px solid transparent; border-radius: var(--pill);
  background: var(--baize); color: var(--on-dark);
  font-family: var(--f-body); font-weight: 600; font-size: 15.5px; letter-spacing: -.005em;
  transition: transform .25s var(--ease), background .2s, box-shadow .25s;
  filter: none;
}
.sbi-blk .pb-form__submit:hover {
  background: var(--baize-2);
  transform: translateY(-1px);
  box-shadow: 0 10px 24px rgba(12, 30, 32, .18);
  filter: none;
}
.sbi-blk .pb-form__submit:active { transform: translateY(0); }

.sbi-blk .pb-form__status:not(:empty) {
  margin: 0;
  padding: 14px 16px;
  border-radius: 14px;
  background: var(--ivory);
  font-size: 14px;
  color: var(--ink-soft);
}

/* --------------------------------------------------------------------------
   The form beside its heading — the prototype's enquiry layout.

   sbi.css already draws `.enquiry` and `.form-card`; all that is left is the
   button, which reads better filling the card than sitting in its corner the
   way it does when the card is the full width of the section.
   -------------------------------------------------------------------------- */
.sbi-form-split .form-card .pb-form__submit { justify-self: stretch; width: 100%; }

/* The card supplies the padding, so the widget inside it adds none. */
.sbi-form-split .form-card .pb-widget { margin: 0; }

/* --------------------------------------------------------------------------
   A register document whose PDF has not been uploaded yet.

   The card still appears — the document exists and people look for it — but it
   is not a link, because policy.download answers 404 without a file.
   -------------------------------------------------------------------------- */
.doc.is-pending { cursor: default; }
.doc.is-pending:hover { border-color: var(--line); transform: none; }
.doc-soon, .kd-soon { font-family: var(--f-mono); font-size: 10.5px; letter-spacing: .04em; color: var(--ink-mute); white-space: nowrap; }
.key-doc .kd-soon { color: var(--on-dark-mute); }

/* ---------- slide dots, under the copy ----------

   Where a slider assembled from Containers gets its dots. The block's own
   numbered bars live in .hs-bar beside the next-event panel and fill it; three
   plain circles down there do not — they end up level with that panel but a
   long way beneath the buttons they belong to, with the lower half of the
   photo in between.

   So these sit in the copy column instead, directly under the last thing in
   it. `.hs-copy` is a grid with a 24px gap, which is the same rhythm as the
   rest of the column, and the negative top margin pulls them a little closer
   still: they belong to the buttons above them, not to the next block down. */

.hs-dots-inline {
  display: flex;
  gap: 10px;
  align-items: center;
  margin-top: -6px;
}

.hs-dots-inline .hs-dot {
  min-width: 0;
  padding: 6px;
  display: inline-flex;
  align-items: center;
  background: none;
  border: 0;
  cursor: pointer;
}

.hs-dots-inline .hs-dot i {
  display: block;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: rgba(244, 240, 230, .32);
  border: 0;
  transition: background-color .25s, transform .25s;
}

/* The block's bars animate a progress line; these do not have one. */
.hs-dots-inline .hs-dot i::after { content: none; }

.hs-dots-inline .hs-dot:hover i { background: rgba(244, 240, 230, .6); }
.hs-dots-inline .hs-dot.on i { background: var(--gold-2); transform: scale(1.25); }

.hs-dots-inline .hs-dot:focus-visible {
  outline: 2px solid var(--gold-2);
  outline-offset: 2px;
  border-radius: 999px;
}

/* ==========================================================================
   Header chrome on phones
   ==========================================================================

   PageStyles::baseCss() ships a sitewide default that turns every row into a
   stack under 640px:

       .lb-container[style*="flex-direction:row"]     { flex-direction: column !important }
       .lb-container[style*="flex-direction:row"] > * { width: 100% !important }

   That is right for a row of content cards and wrong for the header, which is
   a bar. The bar is built from blocks dropped into Containers whose inline
   style is exactly `flex-direction:row`, so it matched, and every piece of the
   header became its own full-width line down the middle of the screen.

   The default lives in the package, so it is answered here rather than edited,
   and the package's own `[style*="flex-direction:row"]` condition is kept so
   this only ever restores what the inline style already said. It never turns a
   column into a row: the two strips wrapping the bar are columns and stay so.

   Two selectors, because the header nests rows inside rows. The first catches
   a row that holds header blocks. The second catches a row *inside* such a
   row, which the first cannot see: the wordmark sits in its own Container
   holding nothing but the logo — no .sbi-header anywhere in it — so a test for
   header blocks misses it and it alone stayed stacked, with the logo blown up
   to `width:100%` and the icons pushed off to the side of it.

   Specificity (0,3,0) and (0,4,0) against the package's (0,2,0), which is what
   it takes to win from a sheet in <head> against a <style> the renderer writes
   into the body. Content rows holding no header block still stack as before. */
@media (max-width: 640px) {
  .lb-container[style*="flex-direction:row"]:has(.sbi-header),
  .lb-container:has(.sbi-header) .lb-container[style*="flex-direction:row"] {
    flex-direction: row !important;
    align-items: center !important;
  }

  .lb-container[style*="flex-direction:row"]:has(.sbi-header) > *,
  .lb-container:has(.sbi-header) .lb-container[style*="flex-direction:row"] > * {
    width: auto !important;
    max-width: 100% !important;
  }

  /* The logo carries `width:100%` inline, from the Image element's own Style
     tab, and it is the height that is set deliberately. Freeing the width lets
     it draw at its own aspect instead of stretching to whatever box it lands
     in. An author !important is what answers a style attribute. */
  .lb-container:has(.sbi-header) figure.lb-image > img {
    width: auto !important;
    max-width: 100% !important;
  }
}

/* The bar's own hiding rule, for the way the builder prints it.

   sbi.css carries the prototype's `.hdr-actions .hide-md`, which assumes the
   prototype's markup: one .hdr-actions wrapper with .hide-md on the children
   inside it. Here each button is its own block, so each prints its own wrapper
   and the two classes land on the same element — a compound, which a
   descendant selector does not match. Book, Shop and Sign in therefore stayed
   on the bar at every width instead of folding into the burger.

   The block wrapper goes with it. Hiding only the inner .hdr-actions would
   leave an empty flex item behind, and the row's gap is still drawn either
   side of it. The nav block is deliberately left alone: sbi.css:406 hides the
   `.nav` inside it, but that same block also holds the mega panels and the
   mobile drawer, so hiding it would take the burger menu with it.

   Same breakpoint as sbi.css so the two halves of the rule agree. */
@media (max-width: 1220px) {
  .sbi-header:has(> .hdr-actions.hide-md),
  .hdr-actions.hide-md { display: none; }
}

/* The strip above the bar sheds its content on the way down (sbi.css 4121-4128
   hides .u-hide, then the socials and the plain items), which leaves the same
   empty wrappers behind it. Each block here holds a single piece, so a block
   whose one child is gone has nothing left to show. */
@media (max-width: 1220px) {
  .sbi-header.utility:has(> .u-search:only-child) { display: none; }
}

@media (max-width: 860px) {
  .sbi-header.utility:has(> .u-hide:only-child) { display: none; }
}

@media (max-width: 640px) {
  .sbi-header.utility:has(> .socials:only-child),
  .sbi-header.utility:has(> .u-item:only-child:not(.live-pill)) { display: none; }
}
/* ---------- section heads on phones ----------

   A section head is a Container with the heading group on one side and an
   action on the other — "Cues, chalk and care" with Shop all, "Moments from
   the season" with Full gallery. Its inline style is `flex-direction:row`, so
   PageStyles::baseCss() already stacks it under 640px. Between 641 and 760 it
   stayed a row, and `justify-content:space-between` pinned the action to the
   right edge while the heading was squeezed into what was left.

   760px is where sbi.css:2555 already treats the section head as small, so the
   stack starts there instead and the two halves of the design agree.

   The children are widened rather than left to `align-items:flex-end`, which
   the inline style sets for the row and which would otherwise right-align the
   whole stack once the direction flips.

   The gap is restored to the 16px sbi.css:2555 asks for. The builder writes
   `gap:32px` inline, and an inline declaration beats a stylesheet one, so the
   design system's own mobile gap has never been the one that applied. */
@media (max-width: 760px) {
  .lb-container.sec-head[style*="flex-direction:row"] {
    flex-direction: column !important;
    align-items: stretch !important;
    gap: 16px !important;
  }

  .lb-container.sec-head[style*="flex-direction:row"] > * { width: 100% !important; }
}

/* ---------- the hero slider on phones ----------

   The prototype drops the photo from the hero under 960px (sbi.css:1082-1085)
   and runs the copy over the slide's own artwork, which is what the mobile
   preview shows: eyebrow, headline, paragraph, buttons, then the next-event
   card, over the baize and the reds.

   Both halves of that are defeated by what the builder writes inline. The
   photo column is a Container, so it carries `display:flex` in its style
   attribute, and an inline declaration beats the stylesheet's `display:none` —
   the photo stayed on the page and stacked under the copy instead of going
   away. The copy column carries `width:58%`, so even with the photo gone it
   sat in 58% of the row with the rest empty.

   An author `!important` outranks an inline declaration, which is what it
   takes to answer a style attribute. 960px is the prototype's own breakpoint,
   not a new one, so the two agree about where the hero becomes one column.

   The copy keeps the `max-width: 700px` sbi.css:1050 gives it — that is a
   max-width, and nothing inline competes with it. */
@media (max-width: 960px) {
  .lb-container.hs-photo { display: none !important; }
  .lb-container.hs-copy { width: 100% !important; }
}

/* ---------- the masked button glyphs, made safe to fail ----------

   The arrow and the document glyph are drawn by filling a 16px box with
   currentColor and masking that fill down to the shape. When the mask lands,
   you see an arrow. When the browser drops it, the fill is left exactly as it
   was written — a solid 16px block sitting inside the button. That block was
   the "background behind all the buttons": it is not a background at all, it
   is the glyph with its mask missing.

   Three things were making the mask fragile, and all three are now fixed:

   - it was written with the `mask` shorthand, whose `position / size` syntax
     is parsed inconsistently; it is now set with longhands, which every engine
     that supports masking at all accepts;
   - the mask SVGs carried only a viewBox and no width or height, so they had
     no intrinsic size for `contain` to work from; they now carry both;
   - the fill was unconditional. It is now applied only inside @supports, so a
     browser without masking draws nothing instead of a solid block.

   That last one is the part that matters: the glyph may be missing, but the
   button can no longer come out with a filled square in it. */
@supports ((-webkit-mask-image: url("#")) or (mask-image: url("#"))) {
  .lb-button.sbi-btn > a::after,
  .lb-button.sbi-btn > span::after,
  .lb-button.sbi-btn-doc > a::before,
  .lb-button.sbi-btn-doc > span::before { background-color: currentColor; }
}

/* ---------- the icon buttons' rounded clip ----------

   A 44px box with `border-radius: 50%` is a circle tangent to all four sides
   at their midpoints, and that is exactly where a pair of hairlines was
   appearing — one horizontal, one vertical, crossing through each icon button
   on the live site.

   Nothing draws them. They are seams from the way the rounded clip is
   rasterised: inside the sticky header the button ends up on its own
   composited layer, and at a device pixel ratio of 2 the tile boundaries of
   that layer show through the clip. Removing the radius removes them, which is
   how the shape was identified as the trigger rather than any rule.

   Two changes, neither of which alters how the button looks:

   - the radius is given as a length rather than a percentage. On a 44px box
     999px clamps to the same 22px and draws the same circle, but it is
     resolved once from the box instead of recomputed as a percentage of it,
     which is what was landing on fractional values and leaving the seam;
   - `background-clip: padding-box` keeps the fill from being painted under the
     1px border, so the two cannot disagree about where the rounded edge is.

   Scoped so the variants keep their own shapes: `.tke-ord .icon-btn` (6px) and
   anything else with a more specific radius still wins on specificity. */
.icon-btn { border-radius: 999px; background-clip: padding-box; }

.sbi-header .icon-btn {
  border-radius: var(--sbih-icon-radius, 999px);
  background-clip: padding-box;
}

/* ---------- the compositing seams on rounded controls ----------

   The hairlines reach past the control's own box, and neither a border nor a
   background can paint outside the border-box, so what shows is the edge of
   the layer the control is rasterised into rather than anything on the control
   itself.

   They appear wherever a rounded control sits inside a promoted layer — the
   sticky header, the hero (sbi.css:870 puts `will-change: translate` on the
   slide), and the accessibility launcher, which is fixed. At a device pixel
   ratio of 2 the rounded clip lands between device pixels and the tile edge
   bleeds through. Changing the radius moves where the clip meets that tile,
   which is why the lines shifted as the radius was changed rather than going
   away — and why `.btn`, whose radius is a length and never a percentage,
   shows them too.

   Giving each control its own layer removes the shared tile the seam comes
   from. `translateZ(0)` applies no visible transform; the hover rules that set
   `translateY(-1px)` replace it with another transform, so the control stays
   promoted through the transition and nothing moves. */
.icon-btn,
.btn,
.lb-button.sbi-btn > a,
.lb-button.sbi-btn > span,
.sbi-a11y-toggle {
  transform: translateZ(0);
  backface-visibility: hidden;
}

/* `contain: paint` is the half that stops the bleed, but it also clips anything
   meant to sit outside the box — and `.cart-count` is pinned at -3px, outside
   the basket button, so it is held back from that one control. `.btn` already
   carries `overflow: hidden` in sbi.css, so this adds no new clipping there.

   The accessibility launcher is left out too: it belongs to the accessibility
   widget, which may anchor a label or tooltip outside it, and clipping another
   component's furniture is not this sheet's business. */
.icon-btn:not(.cart-btn) { contain: paint; }

/* The one seam the layer fix does not reach: the join in the border itself.

   A border is painted as four segments. Where a segment meets a corner arc the
   two are stitched together, and at a device pixel ratio of 2 that stitch can
   land half a pixel out and show as a hairline. The position of the join is
   set by the radius, which is why the shape of the artefact tracked the radius
   exactly: on a 44px circle the joins are at the four side midpoints, and the
   four hairlines read as a crosshair; on a pill the radius is half the height,
   so the joins are the two cap tangents and what is left is a vertical line at
   the end of the pill.

   Promoting the element to its own layer fixed the circles but cannot fix
   this, because the join is inside the border, not at the layer edge. So the
   outlined buttons stop using a border for their ring and use an inset shadow,
   which is rasterised as one rounded ring with no segments and therefore no
   joins. The border is kept at 1px and made transparent so every box stays
   exactly the size it was.

   `--ring` carries the colour the border-color rules used to set, including
   the inverted one on dark bands and the darker one on hover. The hover lift
   keeps its drop shadow by listing both shadows together; sbi.css sets
   `box-shadow: none` on a ghost hover, which is why the ring is restated. */
.btn-ghost,
.lb-button.sbi-btn-ghost > a,
.lb-button.sbi-btn-ghost > span {
  --ring: var(--line);
  border-color: transparent;
  box-shadow: inset 0 0 0 1px var(--ring);
}

.on-dark .btn-ghost,
.on-baize .btn-ghost,
.on-dark .lb-button.sbi-btn-ghost > a,
.on-dark .lb-button.sbi-btn-ghost > span,
.on-baize .lb-button.sbi-btn-ghost > a,
.on-baize .lb-button.sbi-btn-ghost > span { --ring: rgba(244, 240, 230, .28); }

.btn-ghost:hover,
.lb-button.sbi-btn-ghost > a:hover {
  --ring: var(--ink);
  box-shadow: inset 0 0 0 1px var(--ring);
}

.on-dark .btn-ghost:hover,
.on-baize .btn-ghost:hover,
.on-dark .lb-button.sbi-btn-ghost > a:hover,
.on-baize .lb-button.sbi-btn-ghost > a:hover {
  --ring: var(--on-dark);
  box-shadow: inset 0 0 0 1px var(--ring);
}

/* The ghost variants that set their own border-color, and so kept their border.

   The rule above is `.btn-ghost`, one class. sbi.css sets the colour again on
   more specific selectors, and those kept winning — so on those buttons the
   border was still painted and the join still showed. `.btn-ghost.inv` is the
   one on the dark hero: it is the inverted ghost, written as a class rather
   than relying on an `.on-dark` ancestor, which is why the `.on-dark` rule
   above did not reach it.

   Each one gets its colour moved to `--ring` and its border made transparent,
   at the same specificity as the rule it is answering. The border stays 1px
   and transparent rather than being removed, so the box keeps the size it has
   everywhere else — `border: none` would quietly shrink these buttons by 2px
   in each direction against their solid siblings. */
.btn-ghost.inv,
.lb-button.sbi-btn-ghost.inv > a,
.lb-button.sbi-btn-ghost.inv > span {
  --ring: rgba(244, 240, 230, .28);
  border-color: transparent;
  box-shadow: inset 0 0 0 1px var(--ring);
}

.btn-ghost.inv:hover,
.lb-button.sbi-btn-ghost.inv > a:hover {
  --ring: var(--on-dark);
  box-shadow: inset 0 0 0 1px var(--ring);
}

/* Filled on hover inside a tier card, and inverted on the back of a card. */
.tier:hover .btn-ghost {
  --ring: var(--baize);
  border-color: transparent;
  box-shadow: inset 0 0 0 1px var(--ring);
}

.ct-back .btn-ghost {
  --ring: rgba(244, 240, 230, .25);
  border-color: transparent;
  box-shadow: inset 0 0 0 1px var(--ring);
}

/* The same seam, everywhere else it can appear.

   The join is in the border, so anything that pairs a pill or circular radius
   with a visible 1px border can show it. Searching sbi.css for that pairing
   turns up sixteen, and they are listed here together rather than fixed one at
   a time as each is noticed — the filter chips on the event calendar were the
   third to be reported and would not have been the last.

   These get the layer promotion rather than the ring rewrite. Promotion was
   enough for `.icon-btn`, it needs no knowledge of what colour each component
   paints its border in any of its states, and it cannot therefore get one of
   them wrong. The outlined buttons above still need the ring because their
   seam survived promotion.

   `translateZ(0)` applies no visible transform. Three of these set a transform
   of their own in a hover or open state — `.acc-q .pm` rotates, `.pc-go` and
   `.evh-back` nudge sideways — which replaces it with another transform, so
   they stay promoted and nothing about them moves. */
.icon-btn,
.pager span,
.acc-q .pm,
.pc-go,
.fs-n,
.tp-arr,
.evh-back,
.ftr .socials a,
.utility .socials span,
.sbi-header .socials :is(a, button) {
  transform: translateZ(0);
  backface-visibility: hidden;
}

/* The pills, which promotion does not reach.

   A circle has no straight edge, so its only border joins are at the four side
   midpoints, and promoting it onto its own layer was enough. A pill has two
   straight edges meeting two semicircular caps, and that join sits inside the
   border rather than at the layer edge — so the chips, like the outlined
   buttons before them, keep their hairline however they are composited.

   They therefore stop using a border for their ring and use an inset shadow,
   which is rasterised as one rounded ring with no segments. The border stays
   1px and transparent so the boxes keep their size.

   `--ring` carries each state's colour, and because the shadow is written once
   against the variable, a state only has to set the variable. The border is
   made transparent again in every state sbi.css sets a colour in, at matching
   specificity, or its border-color would come back and the seam with it. */
.chip,
.qty,
.ftr-news form,
.srch-try button,
.as-tabs button,
.u-search {
  border-color: transparent;
  box-shadow: inset 0 0 0 1px var(--ring);
}

.chip { --ring: var(--line); }
.chip:hover { --ring: var(--ink-soft); border-color: transparent; }
.chip.on { --ring: var(--ink); border-color: transparent; }
.on-dark .chip { --ring: var(--felt-line); border-color: transparent; }

.qty { --ring: var(--line); }
.srch-try button { --ring: var(--line); }
.u-search { --ring: rgba(244, 240, 230, .16); }

.as-tabs button { --ring: var(--felt-line); }
.as-tabs button.on { --ring: var(--on-dark); border-color: transparent; }

/* The footer form keeps the themeable rule colour the footer block gives it. */
.ftr-news form { --ring: var(--sbif-rule, var(--felt-line)); border-color: transparent; }

/* ---------- the header's gutter ----------

   The site's container is `max-width: var(--wrap)` with
   `padding-inline: var(--gutter)`, and `--gutter` is
   clamp(16px, 4vw, 48px) — 48px on a desktop, closing to 16px on a phone.

   The header's two rows were built in the editor with a flat `padding: 0 48px`
   written into their style attribute. On a desktop that happens to equal the
   gutter, so the bar looked right and the mismatch went unnoticed; on a phone
   the container had closed to 16px while the header was still holding 48,
   leaving the wordmark and the burger inset by three times as much as the page
   under them and a band of dead space down both sides.

   Handing them the token instead lines the bar up with the container at every
   width — the wordmark starts where the page copy starts, the burger ends
   where it ends — and changes nothing at 1200px and above, where the clamp is
   already at 48px.

   An inline declaration can only be answered with `!important`; the selector
   matches the padding the editor wrote, so a row given a deliberately
   different one is left alone. */
.lb-container[style*="padding:0px 48px 0px 48px"]:has(.sbi-header) {
  padding-inline: var(--gutter) !important;
}

/* ---------- the bar's trailing icons ----------

   The row the header blocks sit in was given `justify-content: flex-start` in
   the editor, so everything packs against the wordmark and the slack collects
   on the right — which is why the basket and the burger float in the middle of
   the bar instead of finishing at the container's edge.

   Rather than change the row's justification, which would also spread the
   items between the ends, the first child is told to absorb the slack. Margin
   auto eats the free space on that side, so the wordmark stays hard left, and
   everything after it — the basket, the burger — is carried over to the right
   edge, ending exactly where the page content ends.

   Only below 1220px, which is where sbi.css hides the main nav and brings in
   the burger. Above that the nav still sits beside the wordmark and is
   supposed to, so the desktop bar is left as it is.

   `:has(> .sbi-header)` is a child test on purpose: it picks the bar, whose
   blocks are its own children, and not the utility strip above, whose children
   are the two grouping containers and which already spaces itself. */
@media (max-width: 1220px) {
  .lb-container[style*="flex-direction:row"]:has(> .sbi-header) > :first-child {
    margin-right: auto;
  }
}

/* ---------- the menu drawer on phones ----------

   sbi.css gives the drawer `width: min(460px, 100%)`, which is the prototype's
   own rule: full width up to 460px, then a 460px panel beyond it. That leaves
   a band of page showing beside the menu on anything between 460px and the
   width where the burger gives way to the full navigation.

   760px is where the tab bar and the section heads already switch to their
   phone form, so the drawer joins them: wherever the burger is the primary
   navigation, opening it covers the screen. Above 760px it goes back to being
   a panel, which is right on a tablet — blanking the whole screen for eight
   links would be heavy-handed there. */
@media (max-width: 760px) {
  .drawer { width: 100%; }
}

/* ==========================================================================
   INNER PAGES, BUILT OUT OF ELEMENTS

   Split.php rebuilds the inner-page bands — the hero, the tab bar, the split
   intro, the feature boxes, the picture-and-copy strip — as Containers, Texts,
   Buttons and Images wearing the prototype's own class names. Almost all of the
   design then applies on its own: `.phero`, `.ibox`, `.sec-head`, `.crumbs` are
   plain class selectors in sbi.css and do not care what element wears them.

   What follows is only where that is not enough, and each rule says why. Three
   things cause it: the Container writes its `display` inline and so beats a
   stylesheet; an Image is a <figure> around an <img> that carries its height
   inline; and the two renderers draw a Button as <a> on the page and <span> on
   the canvas, so both are always named.
   ========================================================================== */

/* ---------- the inner-page hero ----------
   The photograph is an Image element rather than the Container's background,
   so an editor can select it and swap it like any other picture. `.phero
   .ph-art` already takes it out of flow and lays it over the band; the height
   is the one thing it cannot win, because the renderer writes it inline. */
.lb-container.phero > .lb-image.ph-art { margin: 0; }
.lb-container.phero > .lb-image.ph-art img,
.lb-container.phero > .lb-image.ph-art .ph {
  width: 100% !important; height: 100% !important; object-fit: cover; border-radius: 0 !important;
}

/* The breadcrumb and the figures sit above the gradient rather than under it. */
.lb-container.phero > .wrap { position: relative; }

/* ---------- the section tab bar ----------
   The prototype draws each tab as a `<span>`; here a tab is a Button, so it is
   an `<a>` on the page and a `<span>` on the canvas. Everything else — the
   sticky bar, the 58px rail, the scroll on a narrow screen — comes from
   `.subnav` and `.subnav .wrap` without help. */
.lb-button.sbi-tab > a,
.lb-button.sbi-tab > span {
  height: 36px; padding: 0 16px; border-radius: var(--pill);
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 13.5px; color: var(--ink-soft); white-space: nowrap;
  text-decoration: none; background: transparent; border: 0;
  transition: background .2s, color .2s;
}
.lb-button.sbi-tab > a:hover { color: var(--ink); background: var(--ivory); }
.lb-button.sbi-tab.on > a,
.lb-button.sbi-tab.on > span { background: var(--ink); color: var(--paper); }

/* ---------- picture and copy ----------
   Treated as the split intro above it is: two columns that carry a Width each
   and must not wrap before they shrink. See the note on that rule for why. */
.lb-container.split-media { flex-wrap: nowrap; }
.lb-container.split-media > .lb-image.media { aspect-ratio: 5 / 4; width: 50%; margin: 0; }
.lb-container.split-media > .lb-image.media img,
.lb-container.split-media > .lb-image.media .ph {
  width: 100% !important; height: 100% !important; object-fit: cover;
}

/* The picture keeps its place in the document whichever side it is shown on,
   so that when the columns stack it is still above the copy either way. */
@media (min-width: 861px) {
  .lb-container.split-media > .lb-image.media-right { order: 2; }
}

@media (max-width: 860px) {
  .lb-container.split-media { flex-direction: column !important; }
  .lb-container.split-media > * { width: auto !important; max-width: none !important; }
}

/* ---------- feature boxes ----------
   The one place a Container's inline `display:flex` has to be overruled rather
   than worked with: `.ibox-grid` is a grid, and with it come the three column
   counts and the phone scroller sbi.css already writes for it. A flex row would
   mean restating every one of them in widths. */
.lb-container.ibox-grid { display: grid !important; }

/* `.ibox` itself is happy as a flex column — grid or flex, it is a stack with a
   14px gap — so only the two pieces that are positioned need saying. */
.lb-text.ib-n { font-size: 11px !important; line-height: 1.4 !important; }

/* The gold rule along the foot of a box. It is a Divider so that it can be
   moved or taken off like anything else; `.ib-line` draws the line itself, so
   the <hr> inside the element is in the way rather than doing the work. */
.lb-container.ibox > .lb-divider.ib-line { padding: 0 !important; overflow: hidden; }
.lb-container.ibox > .lb-divider.ib-line > * { display: none !important; }

/* ---------- breadcrumb ----------
   Real links here, where the prototype — one document, no navigation — used
   `span[data-goto]`. The colours are the trail's, not the link's. */
.crumbs a { color: inherit; text-decoration: none; transition: color .2s; }
.crumbs a:hover { color: var(--on-dark); }
.crumbs.dark a:hover { color: var(--ink); }

/* ---------- the inner-page hero's figures ----------
   The prototype draws these as `<div class="ph-stat"><b class="num">301</b>
   <span>Members</span></div>`, and a Counter element is the same two values
   with fields to type them into — but it draws `<b>` and `<small>`, and writes
   the size, the weight and the accent inline. So `.phero .ph-stat b` reaches
   the number and loses to the inline font-size, and nothing at all reaches the
   label.

   Stated in full rather than leaning on `.phero .ph-stat`, as `.sbi-stat` above
   it is: a figure keeps its appearance when it is dragged out of the hero. */
.lb-counter.ph-stat { display: grid; gap: 2px; }
.lb-counter.ph-stat > b {
  font-family: var(--f-display); font-weight: 400 !important; font-size: 34px !important;
  line-height: 1 !important; letter-spacing: normal !important; font-variant-numeric: tabular-nums;
}
/* The suffix is part of the number here, not an accent on it. */
.lb-counter.ph-stat > b span { color: inherit !important; font-size: inherit !important; }
.lb-counter.ph-stat > small {
  font-size: 12.5px !important; font-weight: 400 !important; opacity: 1 !important;
  letter-spacing: normal; text-transform: none; color: var(--on-dark-mute);
}

/* Follows `.phero .ph-stat b` down at the width the design system takes it. */
@media (max-width: 760px) {
  .lb-counter.ph-stat > b { font-size: 28px !important; }
}

/* ---------- the closing band's backdrop ----------
   `.cta-art` already lays it over the band and dims it. The difference from
   `.ph-art` above is the fit: the hero asks for `object-fit: cover` on both the
   svg and the img, where this one sets neither and lets the artwork stretch to
   the band. The file carries `preserveAspectRatio="slice"`, so filling the box
   is what the inline <svg> was doing all along. */
.lb-container.cta-band > .lb-image.cta-art { margin: 0; }
.lb-container.cta-band > .lb-image.cta-art img,
.lb-container.cta-band > .lb-image.cta-art .ph {
  width: 100% !important; height: 100% !important; border-radius: 0 !important;
}

/* ---------- a button that leads with a glyph ----------
   The calendar PDF link carries the document icon and no arrow, where every
   other button is the other way round. A Button element prints its label
   escaped and cannot hold an icon, so the glyph is drawn the same way the
   arrow is — its own path, masked so it takes the button's colour. Pair it
   with `sbi-btn-bare`, which takes the arrow off. */
.lb-button.sbi-btn-doc > a::before,
.lb-button.sbi-btn-doc > span::before {
  content: "";
  width: 16px; height: 16px; flex: none; margin-right: 2px;
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6.5 3h7.5l4.5 4.5V19a2 2 0 0 1-2 2h-10a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2Z'/%3E%3Cpath d='M13.5 3v5h5M8.5 13h7M8.5 16.5h5'/%3E%3C/svg%3E");
  -webkit-mask-position: center; -webkit-mask-size: contain; -webkit-mask-repeat: no-repeat;
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6.5 3h7.5l4.5 4.5V19a2 2 0 0 1-2 2h-10a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2Z'/%3E%3Cpath d='M13.5 3v5h5M8.5 13h7M8.5 16.5h5'/%3E%3C/svg%3E");
  mask-position: center; mask-size: contain; mask-repeat: no-repeat;
  background: currentColor;
}

/* ---------- the other two-column bands ----------
   Same arithmetic as intro-split above: columns that carry a Width each must
   not wrap before they shrink, and stack where the design system stacks them. */
.lb-container.rules-grid,
.lb-container.ref-path { flex-wrap: nowrap; }

@media (max-width: 860px) {
  .lb-container.rules-grid,
  .lb-container.ref-path { flex-direction: column !important; }

  .lb-container.rules-grid > *,
  .lb-container.ref-path > * { width: auto !important; max-width: none !important; }
}

/* ---------- the featured coach ----------
   `.coach-feature` is a 360px column beside a 1fr one, and a Container writes
   `display:flex` inline — the one declaration that has to be forced, as with
   `.ibox-grid` above. Everything else, including the stack at 860px, is the
   design system's own. */
.lb-container.coach-feature { display: grid !important; }

/* The portrait is a piece, so in the editor canvas it is a shadow host and the
   `.cf-art` box is inside it rather than on it. Giving the host the same shape
   keeps the column the right size in both. */
.lb-container.coach-feature > .sbi-piece.cf-art { align-self: center; }

/* ---------- the contact band ----------
   `.contact-grid` is the prototype's two columns — the form card against the
   detail cards — and like `.ibox-grid` it is a grid where a Container writes
   `display:flex` inline, so that one declaration has to be forced. The column
   ratio, the gap and the stack on a narrow screen are the design system's. */
.lb-container.contact-grid { display: grid !important; }

/* ---------- the disability programme cards ----------
   `.dis-grid` is the prototype's two columns of programme cards. Same story as
   `.ibox-grid` and `.contact-grid`: a grid where a Container writes
   `display:flex` inline, so only that one declaration is forced and the column
   count, the gap and the phone scroller stay the design system's.

   `.dis` itself is left alone — grid or flex, it is a stack with an 8px gap,
   and the Container already writes that. */
.lb-container.dis-grid { display: grid !important; }

/* An icon with its tile turned off: a glyph in a line of copy rather than the
   52px square a feature box opens with. The span is inline by default, which
   leaves it a descender's worth of space taller than the glyph and knocks the
   line off centre. Nothing sizes the svg here on purpose — whichever line it
   has been dropped into does, as `.dis .mono svg` does at 15px. */
.sbi-piece.sbi-ico { display: inline-flex; align-items: center; }

/* ---------- form validation, in the SBI palette ----------
   `.sbi-blk .pb-form__status:not(:empty)` above repaints the status box ivory
   whatever it is saying, which took the red off a failure and the green off a
   success — the widget's own sheet colours both. The states are given back
   here, in the design system's own tokens rather than the widget's hexes. */
.sbi-blk .pb-form__status.is-err { background: #fdecef; color: var(--err); }
.sbi-blk .pb-form__status.is-ok { background: #e8f5ee; color: #1c5c37; }

/* The per-field message, same red, in the design system's type. */
.sbi-blk .pb-form__error { color: var(--err); font-size: 13px; margin-top: 6px; }
.sbi-blk .pb-form__row [aria-invalid="true"] { border-color: var(--err); }

/* The consent row is a flex line here too, so the message needs the same room
   to drop under it rather than beside the tick. */
.sbi-blk .pb-form__check { flex-wrap: wrap; }
.sbi-blk .pb-form__error { width: 100%; flex-basis: 100%; }
