/**
 * b2be-blocks base stylesheet.
 *
 * This is the shared block library's own neutral structure. Every selector
 * is wrapped in :where(...), which has zero specificity, so a theme rule that
 * sets the same property with any class selector wins, whatever the load
 * order. Two limits (Codex review, 24 Sep): among zero-specificity rules the
 * later one wins, and a value the theme sets on a parent and leaves to
 * inheritance does not beat a property this file sets on the element itself.
 * Added 2026-09-24 after Opascope's insights cards rendered
 * as a plain bulleted list with full-width images, because the grid and the
 * card layout lived only in Escalate's child theme and nowhere in this
 * library. This file gives every b2be-* block sane structure (layout,
 * spacing, image shape, list resets) on any site. Colour, type and brand
 * decisions stay in each child theme.
 *
 * No brand colours or fonts here. Where a shape needs a colour to read at
 * all (a card edge, a marker circle), it uses currentColor through
 * color-mix(), which inherits whatever colour the surrounding page already
 * has and costs nothing to a child theme that sets its own.
 */

/* No rule on images in general. A descendant rule such as [class*="b2be-"] img
   reached every image inside .b2be-wrap, which wraps whole pages, and cut the
   height of Opascope's slider photo on the first preview (24 Sep). Instead,
   every block that prints an image names it here, so none can overflow its box
   (Codex pass 3: the gallery card had lost its sizing), and nothing else is
   touched. Blocks with their own image rules further down add to this. */
:where(.b2be-gcard img, .b2be-marquee__logo img, .b2be-footer__logo img, .b2be-logo img, .b2be-pressbar__inner img, .b2be-card__img img, .b2be-pressstrip__shot img, .b2be-fig img, .b2be-cs-card img, .b2be-embed img) { max-width: 100%; height: auto; }

/* --------------------------------------------------------------- layout -- */
/* .b2be-wrap centres content with a side gutter, so a page has a readable
   measure before a theme sets its own max width. .b2be-band is a full-width
   section wrapper (used by the marquee) and needs no more than that. No
   box-sizing and no width here: on Opascope, whose own wrap rule sets the
   measure and the padding, border-box moved the padding inside the measure
   and narrowed every page by twice the gutter (24 Sep). */
:where(.b2be-wrap) { max-width: 75rem; margin-inline: auto; padding-inline: var(--wp--preset--spacing--40, 1.5rem); }
:where(.b2be-band) { width: 100%; }

/* --------------------------------------------------------------- header -- */
/* The row layout the mobile menu script depends on: a flex row that can
   collapse into a stacked nav under a burger button. Without this, the nav
   links and the burger both render as an unstyled stack down the page. */
:where(.b2be-header__inner) { display: flex; align-items: center; justify-content: space-between; gap: var(--wp--preset--spacing--40, 1.5rem); flex-wrap: wrap; }
:where(.b2be-logo) { display: inline-flex; align-items: center; }
:where(.b2be-nav) { display: flex; align-items: center; flex-wrap: wrap; gap: var(--wp--preset--spacing--40, 1.5rem); }
:where(.b2be-header__cta) { display: flex; align-items: center; gap: var(--wp--preset--spacing--30, 1rem); }
/* The burger is three bars drawn with span elements and no shape of its own;
   without this it is three stacked full-width lines. Hidden above the nav
   breakpoint, since the row nav is already usable there. */
:where(.b2be-burger) { display: none; position: relative; width: 1.75em; height: 1.5em; padding: 0; background: none; border: 0; cursor: pointer; }
:where(.b2be-burger span) { position: absolute; left: 0; right: 0; height: 2px; background: currentColor; }
:where(.b2be-burger span:nth-child(1)) { top: 0; }
:where(.b2be-burger span:nth-child(2)) { top: 45%; }
:where(.b2be-burger span:nth-child(3)) { bottom: 0; }
/* Below the breakpoint the row nav is replaced by the burger. The theme's own
   script toggles the .open class on both elements; this is only the shape
   that makes that toggle mean something. */
@media (max-width: 860px) {
	:where(.b2be-nav) { display: none; }
	:where(.b2be-nav.open) { display: flex; flex-direction: column; align-items: flex-start; width: 100%; }
	:where(.b2be-burger) { display: block; }
}

/* -------------------------------------------------------------- marquee -- */
/* An endlessly scrolling strip needs its overflow clipped and a track twice
   the width of one pass, animated by exactly half its own width. The PHP
   renderer already prints the track twice and sets animation-duration per
   instance inline; this file only names the animation and its shape. */
:where(.b2be-marquee) { overflow: hidden; }
:where(.b2be-marquee__track) { display: flex; align-items: center; gap: var(--wp--preset--spacing--50, 2rem); width: max-content; animation: b2be-marquee 30s linear infinite; }
:where(.b2be-marquee__logo) { display: inline-flex; align-items: center; flex-shrink: 0; }
:where(.b2be-marquee__logo img) { display: block; width: auto; }
@keyframes b2be-marquee {
	from { transform: translateX(0); }
	to { transform: translateX(-50%); }
}
@media (prefers-reduced-motion: reduce) {
	:where(.b2be-marquee__track) { animation: none; }
}

/* --------------------------------------------------------- listing/cards -- */
/* The listing block's whole reason to exist: a grid that is one, two, three
   or four across depending on the block's own setting, collapsing before it
   runs out of room. Without this, .b2be-cards is a plain <ul> and every card
   stacks as a bulleted list line, which is the fault this file exists to fix. */
:where(.b2be-cards) { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--wp--preset--spacing--50, 2rem); list-style: none; margin: 0; padding: 0; }
:where(.b2be-listing__item) { list-style: none; }
:where(.b2be-listing--cols-1) { grid-template-columns: 1fr; }
:where(.b2be-listing--cols-2) { grid-template-columns: repeat(2, 1fr); }
:where(.b2be-listing--cols-3) { grid-template-columns: repeat(3, 1fr); }
:where(.b2be-listing--cols-4) { grid-template-columns: repeat(4, 1fr); }
@media (max-width: 1024px) {
	:where(.b2be-listing--cols-3), :where(.b2be-listing--cols-4) { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 720px) {
	:where(.b2be-listing--cols-2), :where(.b2be-listing--cols-3), :where(.b2be-listing--cols-4) { grid-template-columns: 1fr; }
}
/* Each card stacks its own parts top to bottom, with the date pinned to the
   bottom of the card rather than sitting wherever the text happens to end. */
:where(.b2be-card) { display: flex; flex-direction: column; }
:where(.b2be-card__img) { margin: 0; }
:where(.b2be-card__img img) { display: block; width: 100%; aspect-ratio: 16 / 9; object-fit: cover; }
:where(.b2be-card__date) { margin-top: auto; }
:where(.b2be-pagination) { display: flex; flex-wrap: wrap; align-items: center; gap: var(--wp--preset--spacing--20, 0.5rem); }

/* ------------------------------------------------------------ press strip -- */
/* The coverage pieces are printed as a plain <ul>; without a grid this reads
   as a bulleted list of photographs, the exact fault this file exists for. */
:where(.b2be-pressstrip__grid) { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr)); gap: var(--wp--preset--spacing--50, 2rem); }
:where(.b2be-pressstrip__item) { list-style: none; }
:where(.b2be-pressstrip__card) { display: flex; flex-direction: column; height: 100%; text-decoration: none; overflow: hidden; border: 1px solid color-mix(in srgb, currentColor 15%, transparent); border-radius: var(--wp--preset--spacing--20, 0.5rem); }
:where(.b2be-pressstrip__shot) { display: block; width: 100%; aspect-ratio: 16 / 9; overflow: hidden; }
:where(.b2be-pressstrip__shot img) { width: 100%; height: 100%; object-fit: cover; display: block; }
:where(.b2be-pressstrip__body) { display: flex; flex-direction: column; flex: 1; gap: var(--wp--preset--spacing--20, 0.4rem); padding: var(--wp--preset--spacing--30, 1rem); }
:where(.b2be-pressstrip__more) { margin-top: auto; }
@media (max-width: 720px) {
	:where(.b2be-pressstrip__grid) { grid-template-columns: 1fr; }
}

/* ------------------------------------------------------------ term chips -- */
:where(.b2be-chips), :where(.b2be-hero__pagenav) { display: flex; flex-wrap: wrap; gap: var(--wp--preset--spacing--20, 0.5rem); }
:where(.b2be-cat__tags) { display: flex; flex-wrap: wrap; gap: var(--wp--preset--spacing--20, 0.5rem); }
:where(.b2be-tag) { display: inline-flex; align-items: center; padding: 0.25em 0.75em; border-radius: 999px; }

/* ------------------------------------------------------------- post meta -- */
:where(.b2be-postmeta) { display: flex; flex-wrap: wrap; align-items: center; gap: var(--wp--preset--spacing--20, 0.6rem); }
:where(.b2be-postmeta__face) { width: 2.4em; height: 2.4em; border-radius: 50%; object-fit: cover; flex-shrink: 0; }
/* A small dot between the author and the date; it needs to be a dot, not a
   letter "o", to read as a separator rather than stray text. */
:where(.b2be-postmeta__sep) { width: 4px; height: 4px; border-radius: 50%; background: color-mix(in srgb, currentColor 40%, transparent); flex-shrink: 0; }
:where(.b2be-postmeta__tags) { display: flex; flex-wrap: wrap; gap: var(--wp--preset--spacing--20, 0.5rem); }

/* -------------------------------------------------------- table of contents -- */
/* The renderer prints a plain <ul> inside .b2be-toc with no class of its own,
   so the list reset has to reach it as a descendant. */
:where(.b2be-toc ul) { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--wp--preset--spacing--20, 0.55rem); }
:where(.b2be-toc__l a) { display: inline-block; }

/* ---------------------------------------------------------------- footer -- */
:where(.b2be-footer__grid) { display: grid; grid-template-columns: 2fr 1fr 1fr 1fr; gap: var(--wp--preset--spacing--50, 2rem); }
@media (max-width: 720px) {
	:where(.b2be-footer__grid) { grid-template-columns: 1fr; }
}
/* Each column's link list is a plain <ul> with no class of its own, same as
   the table of contents above. */
:where(.b2be-footer__col ul) { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--wp--preset--spacing--20, 0.5rem); }
:where(.b2be-footer__bottom) { display: flex; flex-wrap: wrap; justify-content: space-between; gap: var(--wp--preset--spacing--30, 1rem); }
:where(.b2be-footer__bottomlinks) { display: flex; flex-wrap: wrap; align-items: center; gap: var(--wp--preset--spacing--30, 1rem); }

/* ------------------------------------------------------------------ form -- */
:where(.b2be-form) { display: grid; gap: var(--wp--preset--spacing--30, 1rem); }
:where(.b2be-form__row) { display: grid; grid-template-columns: 1fr 1fr; gap: var(--wp--preset--spacing--30, 1rem); }
@media (max-width: 600px) {
	:where(.b2be-form__row) { grid-template-columns: 1fr; }
}
/* The honeypot field a bot fills in and a person never sees: off screen
   rather than display:none, which some bots skip past. */
:where(.b2be-form__hp) { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

/* --------------------------------------------------------------- buttons -- */
:where(.b2be-btn) { display: inline-flex; align-items: center; gap: 0.5em; text-decoration: none; }

/* -------------------------------------------------------------- statcard -- */
:where(.b2be-statcard) { display: flex; flex-direction: column; }

/* ------------------------------------------------------------------ rail -- */
/* Numbered steps in a row, collapsing to a stack before the row gets tight. */
:where(.b2be-rail) { display: flex; flex-wrap: wrap; gap: var(--wp--preset--spacing--50, 2rem); }
@media (max-width: 720px) {
	:where(.b2be-rail) { flex-direction: column; flex-wrap: nowrap; }
}
:where(.b2be-rail__step) { flex: 1 1 12rem; display: flex; flex-direction: column; align-items: center; text-align: center; gap: var(--wp--preset--spacing--20, 0.5rem); }
:where(.b2be-rail__dot) { width: 2.5em; height: 2.5em; flex-shrink: 0; border-radius: 50%; display: flex; align-items: center; justify-content: center; background: color-mix(in srgb, currentColor 15%, transparent); }

/* ---------------------------------------------------------------- figure -- */
/* The offset plate sits behind the photo, so the photo needs to stack above
   it, and the plate needs a fill or the whole device is invisible. */
:where(.b2be-fig) { position: relative; }
:where(.b2be-fig__plate) { position: absolute; inset: 0; background: color-mix(in srgb, currentColor 15%, transparent); }
:where(.b2be-fig__arch) { position: relative; z-index: 1; height: 100%; overflow: hidden; }
:where(.b2be-fig__img) { display: block; width: 100%; height: 100%; object-fit: cover; }

/* --------------------------------------------------------------- gallery -- */
/* No carousel script ships in this file, so the base behaviour is a plain
   horizontal scroll: every card sits in view or one swipe away, rather than
   piled up full width one after another. */
:where(.b2be-gal) { position: relative; overflow: hidden; }
:where(.b2be-gal__track) { display: flex; gap: var(--wp--preset--spacing--30, 1rem); overflow-x: auto; scroll-snap-type: x proximity; }
:where(.b2be-gcard) { flex: 0 0 auto; scroll-snap-align: start; min-width: 14rem; display: flex; flex-direction: column; }
:where(.b2be-gcard__in) { display: flex; flex-direction: column; gap: var(--wp--preset--spacing--20, 0.4rem); }
:where(.b2be-gal__ui) { display: flex; align-items: center; justify-content: space-between; gap: var(--wp--preset--spacing--30, 1rem); }
:where(.b2be-gal__dots) { display: flex; gap: 0.5em; }
:where(.b2be-gal__arrows) { display: flex; gap: 0.5em; }
:where(.b2be-gal__btn) { display: inline-flex; align-items: center; justify-content: center; width: 2.5em; height: 2.5em; border-radius: 50%; border: 1px solid color-mix(in srgb, currentColor 30%, transparent); background: none; cursor: pointer; }

/* -------------------------------------------------------------- pressbar -- */
:where(.b2be-pressbar__inner) { position: relative; display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: var(--wp--preset--spacing--20, 0.75rem); }
:where(.b2be-pressbar__dot) { width: 4px; height: 4px; border-radius: 50%; background: color-mix(in srgb, currentColor 40%, transparent); flex-shrink: 0; }
/* The close control has to sit in the corner without pushing the outlet
   marks around, which a button in the normal flow cannot do; this is the
   one place in this file position is load-bearing rather than decorative. */
:where(.b2be-pressbar--notice .b2be-pressbar__inner) { padding-right: 2.75rem; }
:where(.b2be-pressbar__close) { position: absolute; right: 0; top: 50%; transform: translateY(-50%); display: inline-flex; align-items: center; justify-content: center; width: 1.75em; height: 1.75em; padding: 0; background: none; border: 0; cursor: pointer; }

/* ----------------------------------------------------------------- embed -- */
/* A click-to-load video frame: fixed aspect ratio so the page does not jump
   when the iframe replaces the poster image, and a play button centred over
   both states. */
:where(.b2be-embed) { position: relative; padding: var(--wp--preset--spacing--30, 1rem); border: 1px solid color-mix(in srgb, currentColor 15%, transparent); border-radius: var(--wp--preset--spacing--20, 0.5rem); }
:where(.b2be-embed__frame) { position: relative; width: 100%; aspect-ratio: 16 / 9; overflow: hidden; border-radius: var(--wp--preset--spacing--20, 0.5rem); }
:where(.b2be-embed__frame img), :where(.b2be-embed__frame iframe) { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; border: 0; display: block; }
:where(.b2be-embed__play) { position: absolute; inset: 0; width: 100%; display: flex; align-items: center; justify-content: center; padding: 0; background: none; border: 0; cursor: pointer; }
:where(.b2be-embed__disc) { width: 3.4em; height: 3.4em; border-radius: 50%; display: flex; align-items: center; justify-content: center; background: color-mix(in srgb, currentColor 15%, transparent); }

/* --------------------------------------------------------------- cs-card -- */
:where(.b2be-cs-card) { display: flex; flex-direction: column; padding: var(--wp--preset--spacing--40, 1.5rem); border: 1px solid color-mix(in srgb, currentColor 15%, transparent); border-radius: var(--wp--preset--spacing--20, 0.5rem); }
:where(.b2be-cs-card__logo) { display: block; height: 2.75em; margin-bottom: var(--wp--preset--spacing--20, 0.75rem); }
:where(.b2be-cs-card__logo img) { height: 100%; width: auto; display: block; }
:where(.b2be-cs-card__stats) { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--wp--preset--spacing--30, 1rem); }
@media (max-width: 600px) {
	:where(.b2be-cs-card__stats) { grid-template-columns: 1fr 1fr; }
}
:where(.b2be-cs-card__stat) { display: flex; flex-direction: column; text-align: center; }
