/*---------------- Blockbuilder design tokens (relative only — tenant CSS owns colour/type) ----------------*/
/* Accelerator tokens (Design Studio Advanced pane): what Small/Medium/
   Large SPACING and the two width words MEAN for this site — themeable
   per site via --theme-* (historic literals as fallbacks; an unset theme
   is byte-identical). Blocks store the var reference, so a redefinition
   re-styles every block that ever picked that word — retroactively, by
   design. */
.blk-page								{ --blk-space-xs:var(--theme-space-xs, .5rem); --blk-space-s:var(--theme-space-s, 1rem); --blk-space-m:var(--theme-space-m, 1.75rem); --blk-space-l:var(--theme-space-l, 3rem); --blk-space-xl:var(--theme-space-xl, 5rem);
										  --blk-radius-s:var(--theme-radius-s, 4px); --blk-radius-m:var(--theme-radius-m, 10px); --blk-radius-l:var(--theme-radius-l, 20px);
										  --blk-content:min(var(--theme-content-w, 46rem), 100cqw); --blk-gap:var(--blk-space-m); --blk-rhythm:var(--blk-space-m);
										  container-type:inline-size; }	/* 100cqw = the page column (the viewport on the clean shell) */
/*-- vertical rhythm: siblings breathe; grid/column cells manage their own flow.
   Rhythm rides its OWN var: --blk-gap is also each block's cell/track gap,
   so a child that sets its own Gap inline (a grid, a band tightening its
   contents) shadows the inherited value — margin-top:var(--blk-gap) then
   read the child's INNER gap for the space ABOVE it, and a Gap:None
   wrapper could never make such a child sit flush. Container Gap sets
   BOTH: --blk-gap for the cells, --blk-rhythm for the flow between
   children; self-set cell gaps never leak into the rhythm. --*/
.blk-page .blk + .blk					{ margin-top:var(--blk-rhythm); }
/* No measure cap on text blocks — reading width is the CONTAINER's job
   (Width = Reading); a second route here left text stopping at 46rem
   inside full-width layouts (folder template, 2026-07-24). */
/* heading pairs stay deliberately tight — but they FOLLOW Gap Inside
   downward (min), else a container's rhythm control looks dead on the
   most common pairing (heading + text): flush means flush */
.blk-page .blk-heading + .blk			{ margin-top:min(var(--blk-rhythm), var(--blk-space-s)); }
/* Middle/Bottom mean what they say: the stack's trailing margin (a lone
   hero h1's .8em base margin = 20px off-centre at 50px type) must not
   count toward vertical centring — the pane said Middle, so render
   middle. Top alignment keeps the margin: it reads as flow there. */
/* Placement: Overlay — the block leaves the flow and pins to a corner of
   its container (badge over a photo, ribbon, play button). The container
   that HOLDS an overlay becomes the positioning context via :has, so no
   prop is needed on the parent. Offset still nudges from the corner. */
.blk-page .blk-container:has(> .-ovl)	{ position:relative; }
.blk-page .-ovl						{ position:absolute; z-index:2; margin:0 !important;
	/* .blk-container is width:100% for the flow; an overlay sizes to its
	   own content instead (a badge, a ribbon), and a full-width overlay
	   band is said by giving the overlay a Width instead */
										  width:auto; }
.blk-page .-ovl-tl					{ top:0; left:0; }
.blk-page .-ovl-tr					{ top:0; right:0; }
.blk-page .-ovl-bl					{ bottom:0; left:0; }
.blk-page .-ovl-br					{ bottom:0; right:0; }
.blk-page .-ovl-c					{ top:50%; left:50%; translate:-50% -50%; }
/* Gap Inside = None is FLUSH: the rhythm owns margin-top between blocks,
   so a child's OWN bottom margin (a heading's .8em) must not reopen the
   gap the operator just closed. Scoped to the container that asked. */
.blk-page .blk-container.-flush > .blk	{ margin-bottom:0; }
.blk-page .blk-container.-vmid > :last-child,
.blk-page .blk-container.-vbot > :last-child
										{ margin-bottom:0; }
/* Vertical Alignment = Fill: the children grow to the box's height (an
   equal share each); a grid child then stretches its own row and slots */
.blk-page .blk-container.-vfill > .blk	{ flex:1 1 auto; min-height:0; }
/* a text block's last paragraph carries the theme's 1em bottom margin,
   which collapses through the (paddingless) block and shows as dead
   space at the foot of a padded container or slot — the card case. The
   rhythm margin above the next block supplies the flow spacing. */
.blk-page .blk-text > :last-child		{ margin-bottom:0; }
/* grid/column cells sit side by side — no sibling rhythm. Carousel and
   banner TRACK children too: slides ride the track (or stack, in fade/
   banner mode) and the sibling margin pushed every slide after the first
   down by --blk-gap — glaring once fade stacked them. .blk-page prefix +
   last position so it beats BOTH (0,3,0) rules above */
.blk-page .blk-grid > .blk,
.blk-page .blk-columns > .blk,
.blk-page .blk-gallery-grid > .blk,
.blk-page .blk-car-track > .blk,
.blk-page .blk-banner-track > .blk			{ margin-top:0; }

/*---------------- Blockbuilder block primitives ----------------*/
/* Background focal points: inline styles set the --blk-bgpos vars; the
   media query switches to the mobile point — which inline
   background-position could never do. Harmless on blocks without a
   background image. */
.blk-page .blk							{ background-position:var(--blk-bgpos,50% 50%); }
@media (max-width:768px) {
	.blk-page .blk						{ background-position:var(--blk-bgpos-m,var(--blk-bgpos,50% 50%)); }
}

/* Show On (device visibility): the renderer stamps data-blk-show on the
   live render only — the editor canvas ghosts instead (block_editor.css).
   display:none removes the box but the node is still a .blk sibling, so
   .blk + .blk rhythm still lands on the next band (a desktop-only header
   above a mobile-only one left an empty slice on the phone; reverse the
   order and there is no predecessor). Zero the gap after a hidden Show On.
   Columns keep their track template until they STACK (640cqw phones /
   900cqw tablets) — Show On hides at 768px VIEWPORT, so a desktop-only
   sidebar slot (the 270px nav column) was display:none while its track
   still reserved space. Collapse the row to 1fr whenever a direct-child
   slot is the one being hidden. Put Show On on the SLOT, not an inner
   block, or the track cannot see it. */
@media (max-width:768px) {
	.blk-page [data-blk-show='desk']	{ display:none !important; }
	.blk-page [data-blk-show='desk'] + .blk	{ margin-top:0; }
	.blk-page .blk-columns:has(> [data-blk-show='desk'])	{ grid-template-columns:1fr; }
}
@media (min-width:769px) {
	.blk-page [data-blk-show='mob']		{ display:none !important; }
	.blk-page [data-blk-show='mob'] + .blk	{ margin-top:0; }
	.blk-page .blk-columns:has(> [data-blk-show='mob'])	{ grid-template-columns:1fr; }
}

/* Pin the box model — tenant stylesheets may or may not carry a global
   border-box reset, and block behaviour must not vary by site. Blocks are
   border-box, width words included: padding stays inside the box, so a
   padded band never pokes past its column or the glass (the honest-box
   ruling — see the Page/Wide/Reading rule below). */
.blk-page .blk							{ box-sizing:border-box; }
/* Responsive columns: --blk-cols is the CAP, --blk-colmin (when set) is
   the drop point. The minmax track floor is EITHER the exact Nth share
   (colmin unset/0 → exactly N columns, the original behaviour) OR the
   minimum width — auto-fill then fits as many as space allows, never
   more than N. The -0.5px guards float rounding at the exact-N width. */
.blk-grid								{ display:grid; gap:var(--blk-gap,1rem);
										  grid-template-columns:repeat(auto-fill, minmax(max(var(--blk-colmin,0px), calc((100% - (var(--blk-cols,2) - 1) * var(--blk-gap,1rem)) / var(--blk-cols,2) - 0.5px)), 1fr)); }
/* Fit Content: one row, each track only as wide as its own content —
   a header cluster, a button pair, a payment-icon strip. The auto-fill
   recipe above cannot express this (its track floor is a percentage
   calc), hence a class rather than another --blk-cols value. Narrow
   containers fall back to wrapping rather than overflowing. */
.blk-grid.-fit							{ grid-template-columns:none; grid-auto-flow:column; grid-auto-columns:max-content; justify-content:start; align-items:center; }
@container (max-width:520px) {
	.blk-grid.-fit						{ grid-auto-flow:row; grid-auto-columns:auto; }
}
.blk-columns							{ display:grid; grid-template-columns:var(--blk-cols-template,1fr 1fr); gap:var(--blk-gap,1rem);
	/* tenant-proof (same defence as the img rule above): the legacy
	   Foundation grid in responsive.css carries
	   `[class*=column]+[class*=column]:last-child{float:right}`, and
	   `blk-columns` matches that attribute selector — so the SECOND and
	   last Columns block in any container floated right and shrink-wrapped
	   to its content (Holy Trinity's composed event card, 2026-08-28). */
	float:none; }
/* …and it must WIN: the Foundation selector is (0,3,0) and ours is not,
   so this is !important for the same reason the img rule above is —
   legacy sheets tie or beat block selectors on load order. */
.blk-page .blk-columns					{ float:none !important; }
/* Columns stacking — container queries against .blk-page (the page
   column, not the viewport): a narrow band stacks even on wide screens.
   Default stacks on phone widths; -stack-tablet earlier; -stack-never
   opts out entirely. */
@container (max-width:640px) {
	.blk-columns:not(.-stack-never)		{ grid-template-columns:1fr; }
	/* Stacked Order: Right First — an alternating image|text / text|image
	   page stays image,text,image,text once stacked (designers' ask).
	   Order the SECOND track first; two-column rows only need the flip
	   on one child, and deeper tracks keep source order after it. */
	.blk-columns.-stack-swap:not(.-stack-never) > .blk:first-child	{ order:1; }
}
@container (max-width:900px) {
	.blk-columns.-stack-tablet			{ grid-template-columns:1fr; }
	.blk-columns.-stack-tablet.-stack-swap > .blk:first-child		{ order:1; }
}
/* Column Rule: a line drawn in the GAP between tracks, on each item's
   leading edge (::before = left, ::after = top), so tracks never move.
   Weight / style / colour chain to the theme Divider tokens; Rule Length
   is the line's run along the gap, centred on the item. Columns is
   one row (every item but the first); Grid knows its count (-rnN), so
   nth-child exempts the first column and the first row. */
.blk-columns.-rule, .blk-grid.-rule	{ --blk-rule:var(--blk-rule-w, var(--theme-divider-weight, 1px)) var(--blk-rule-style, solid) var(--blk-rule-c, var(--theme-divider-color, #ccc));
	/* the pseudo lives on the ITEM, whose own --blk-gap (a slot's stacked
	   spacing) would otherwise be the one read — pin the track gap here */
	--blk-rule-gap:var(--blk-gap, 1rem);
	> *								{ position:relative; }
	> *::before, > *::after				{ content:""; position:absolute; pointer-events:none; display:none; }
	> *::before							{ top:50%; height:var(--blk-rule-len, 100%); left:calc(var(--blk-rule-gap) / -2); transform:translate(-50%, -50%); border-left:var(--blk-rule); }
	> *::after							{ left:50%; width:var(--blk-rule-len, 100%); top:calc(var(--blk-rule-gap) / -2); transform:translate(-50%, -50%); border-top:var(--blk-rule); }
}
/* Content length: the line spans the item's content box — inset by its
   own padding shorthand (--blk-pad0, emitted beside padding). Reset on
   the item so an ancestor's value never inherits in. */
.blk-columns.-rule-fit, .blk-grid.-rule-fit	{
	> *								{ --blk-pad0:0; }
	> *::before							{ inset:var(--blk-pad0); left:calc(var(--blk-rule-gap) / -2); right:auto; height:auto; transform:translateX(-50%); }
	> *::after							{ inset:var(--blk-pad0); top:calc(var(--blk-rule-gap) / -2); bottom:auto; width:auto; transform:translateY(-50%); }
}
.blk-columns.-rule > * + *::before	{ display:block; }
.blk-grid.-rule:not(.-rule-rows) > *::before	{ display:block; }
.blk-grid.-rule-rows > *::after,
.blk-grid.-rule-both > *::after		{ display:block; }
.blk-grid.-rn1 > *::before,
.blk-grid.-rn2 > :nth-child(2n+1)::before,
.blk-grid.-rn3 > :nth-child(3n+1)::before,
.blk-grid.-rn4 > :nth-child(4n+1)::before,
.blk-grid.-rn5 > :nth-child(5n+1)::before,
.blk-grid.-rn6 > :nth-child(6n+1)::before	{ display:none; }
.blk-grid.-rn1 > :nth-child(-n+1)::after,
.blk-grid.-rn2 > :nth-child(-n+2)::after,
.blk-grid.-rn3 > :nth-child(-n+3)::after,
.blk-grid.-rn4 > :nth-child(-n+4)::after,
.blk-grid.-rn5 > :nth-child(-n+5)::after,
.blk-grid.-rn6 > :nth-child(-n+6)::after	{ display:none; }
/* stacked Columns: the separation is the point, so the rule turns
   horizontal (between the stacked items); Swapped puts the DOM-first
   item second, so the rule moves onto it */
@container (max-width:640px) {
	.blk-columns.-rule:not(.-stack-never) > * + *::before	{ display:none; }
	.blk-columns.-rule:not(.-stack-never) > * + *::after	{ display:block; }
	.blk-columns.-rule.-stack-swap:not(.-stack-never) > :nth-child(2)::after	{ display:none; }
	.blk-columns.-rule.-stack-swap:not(.-stack-never) > :first-child::after	{ display:block; }
}
@container (max-width:900px) {
	.blk-columns.-rule.-stack-tablet > * + *::before	{ display:none; }
	.blk-columns.-rule.-stack-tablet > * + *::after		{ display:block; }
	.blk-columns.-rule.-stack-tablet.-stack-swap > :nth-child(2)::after	{ display:none; }
	.blk-columns.-rule.-stack-tablet.-stack-swap > :first-child::after	{ display:block; }
}
.blk-container							{ margin-inline:auto; width:100%; }
/* inside a parent that sets Horizontal Alignment (flex + align-items),
   the child container must not self-centre: flex auto margins absorb
   free space BEFORE alignment gets a say, so a Reading-width container
   ignored the parent's Left/Right. Alignment-parent decides. */
.blk-page .blk[style*="align-items"] > .blk-container	{ margin-inline:0; }
/* Full Bleed: break out of the page column to the viewport edge (the
   full-width-gallery idea as a container option). 100vw includes the
   scrollbar — pair with overflow-x:hidden on the page shell if a sliver
   of horizontal scroll appears. */
/* Full (Bleed) RETIRED 2026-08-29 (operator: "clean clean clean"): it
   resolved to width:100% in every context — at the top level, where
   .blk-page is already viewport-wide on the clean shell, AND nested inside
   a Page column, where it filled rather than broke out. That made it a
   second way to say Section. The 100vw + negative-margin breakout it was
   invented for was removed in v14 as damaging (Denmead phone footer,
   2026-08-17). A strip that paints to the glass is a Section band with a
   Page inner. */
/* Page / Wide / Reading: HONEST BOXES (operator ruling 2026-08-18 —
   supersedes both the viewport-shrink model and the padding-outside-
   the-column model; both fought the box). The width word IS the box:
   background (colour or image) fills it edge to edge, padding insets
   the content, border-box keeps the padding INSIDE the column so a
   padded Page band on a phone is glass-wide, never overflowing. The
   theme's Side Gutter (--theme-page-pad) is only the DEFAULT
   padding-inline, and on PAGE ALONE (operator, after use 2026-08-19:
   Page is the width that meets the glass; Wide/Reading usually nest
   inside a Page band, where a second default compounded the inset) —
   any explicit Padding on the container is an inline shorthand and
   overrides it wholesale (padding:0 = truly none; 40px 0 MEANS zero
   sides). Full and Section never take the default: Full is deliberate
   glass paint, Section fills its parent and rides the parent's inset.
   A to-the-glass colour strip is still Full wrapping Page. */
.blk-page .blk-container.-page,
.blk-page .blk-container.-reading		{ box-sizing:border-box; }
.blk-page .blk-container.-page			{ max-width:min(var(--theme-page-width, 100cqw), 100cqw); margin-inline:auto; padding-inline:var(--theme-page-pad, 0px); }
/* Background Video (Container): a muted looping layer under the children.
   z-index:0 makes the container its own stacking context, so the -1 video
   paints above the element's OWN background (colour/image = the poster
   while frames load, and what reduced-motion visitors keep) and below
   every child. Same focal vars as background images. */
.blk-container.-hasvid					{ position:relative; z-index:0;
	> .blk-bgvid						{ position:absolute; inset:0; width:100%; height:100%; object-fit:cover; object-position:var(--blk-bgpos,50% 50%); z-index:-1; pointer-events:none; }
}
@media (max-width:768px) {
	.blk-container.-hasvid > .blk-bgvid	{ object-position:var(--blk-bgpos-m,var(--blk-bgpos,50% 50%)); }
}
/* Extend Behind The Page Header (Trinity pattern, block half): pull the
   band up by the header's height so its media runs to the viewport top.
   The SHELL completes it — default.js measures #header into
   --blk-header-h on :root and site_shell.css stacks the header above
   the slid-under band; a translucent header background lets the media
   show through. Pages with no such band see no change (calc resolves
   to 0). Frontend-only class: the editor canvas has no site header to
   slide under. Scoped to #main-content: the compiled header/footer
   fields are .blk-page trees too, and the flag on a band INSIDE the
   header made it pull ITSELF up by its own height — off-screen, and a
   feedback loop while its height was observed (Ilkley, 2026-08-20).
   The pull engages only when the band actually LEADS with media — a
   direct-child gallery (an empty bound banner renders nothing, so on
   bannerless fleet pages the flag quietly stands down instead of
   tucking the h1 under the header), the band's own background image,
   or a video hero (-hasvid on the band itself or its direct child —
   the video-hero-is-container pattern, Bellevue home). */
#main-content .blk-container.-under-header:has(> .blk-gallery-grid),
#main-content .blk-container.-under-header:has(> .-hasvid),
#main-content .blk-container.-under-header.-hasvid,
#main-content .blk-container.-under-header[style*="background-image"]
										{ margin-top:calc(0px - var(--blk-header-h, 0px)); }

/* Pin While Scrolling (Interactions V2): the vnav pattern — a container
   in a page-body column pins under the sticky header while its row's
   neighbours scroll, and releases when its grid area runs out (native
   sticky containment — no JS). --blk-stick-h is the STICKY header's
   height (default.js; 0 when the header scrolls away, so the pin goes
   to the glass top). On a direct columns child the slot must hug its
   content or its grid area IS the full row and sticky has nowhere to
   move. Live-only class: the editor canvas never traps blocks. */
#main-content .blk-container.-pin-scroll	{ position:sticky; top:calc(var(--blk-stick-h, 0px) + var(--blk-space-s, 12px)); }
.blk-columns > .-pin-scroll				{ align-self:start; }

/* When Pinned (Container, interactions family): the band's inline style
   re-emits background/padding through --blk-bg/--blk-pad vars (fallback
   chain to the --blk-*0 originals), and the pinned header redefines
   them. Solid strips the alpha in CSS — relative color reads the
   ORIGINAL value (a swatch var included), so a palette change keeps
   both states honest; browsers without relative color simply keep the
   translucent band. Compact swaps in the pre-computed 40%-vertical
   shorthand. Only #header.is-stuck arms any of it: no sticky header,
   no editor canvas, no page-body effect. */
/* the solid twin is a pre-computed LITERAL (--blk-bg-stuck from
   ContainerType) — never a relative color: browsers refuse to
   interpolate a transition into rgb(from var(...) ...) and the fade
   wedged at the start value forever (Chrome + Firefox, 2026-08-20) */
#header.is-stuck [data-blk-stuck~="solid"]		{ --blk-bg:var(--blk-bg-stuck); }
#header.is-stuck [data-blk-stuck~="compact"]	{ --blk-pad:var(--blk-pad-stuck); }
/* the classic shrinking header shrinks its LOGO too: sized images in a
   compact band scale to 75% of their own width (ImageType emits the
   --blk-imgw0 pair; unsized images have no pair and are untouched) */
#header.is-stuck [data-blk-stuck~="compact"] .blk-image img
										{ --blk-imgw:calc(var(--blk-imgw0, 100%) * 0.75); }
#header [data-blk-stuck]				{ transition:background-color 0.25s ease, padding 0.25s ease; }
#header [data-blk-stuck] .blk-image img	{ transition:max-width 0.25s ease; }
@media (prefers-reduced-motion: reduce) {
	#header [data-blk-stuck],
	#header [data-blk-stuck] .blk-image img
										{ transition:none; }
}
/* Scroll Cue: the hero "more below" chevron — white over photography with
   a gentle bob (stilled for reduced-motion visitors); blocks.js scrolls
   to whatever follows the container (delegated click) */
.blk-container.-cue						{ position:relative; }
.blk-scroll-cue							{ position:absolute; left:50%; bottom:0.9em; z-index:1; width:2.6em; height:2.6em; margin-left:-1.3em; padding:0; border:0; background:transparent; cursor:pointer; color:#fff;
	svg									{ width:100%; height:100%; filter:drop-shadow(0 1px 3px rgba(0,0,0,0.5)); }
	animation:blk-cue-bob 2.2s ease-in-out infinite;
}
@keyframes blk-cue-bob					{ 0%, 100% { transform:translateY(0); } 50% { transform:translateY(7px); } }
@media (prefers-reduced-motion: reduce) {
	.blk-scroll-cue						{ animation:none; }
}
.blk-heading							{ scroll-margin-top:2rem; }
.blk-image								{ margin:0;
	img									{ display:block; max-width:100%; height:auto; }
	/* Media block, video src: the player sizes to the file's own frame once
	   metadata lands, capped by the figure — same rhythm as an image */
	video								{ display:block; max-width:100%; height:auto; }
	figcaption							{ font-size:0.9em; color:#666; padding-top:0.3em; }
}
/* Arc (Media block): the wrapper is the media's exact size; the media clips
   to a pill on a box grown by the overshoot top and bottom, and the
   wrapper's pseudo draws the SAME pill as a bordered box, so a Border on
   the block becomes the line along the arc. Only the pseudo's arc-side
   border paints; its straight edges sit outside the box. */
/* No clip-path: Safari rejects a negative inset(), which the overshoot
   needs. The PILL is taller than the wrapper by the overshoot (d, a
   fraction of the wrapper's height) and rounded; the wrapper's overflow
   cuts its straight edges. Inside it the picture is painted as a cover
   background at the offset that lines it up with the wrapper — top
   d/(1+2d) of the pill, height 1/(1+2d) — so the in-flow <img> only
   holds the size (and the alt text). The ring is a pseudo on the pill's
   padding box, so the border never shifts the picture. Video keeps the
   media element itself inside the pill. */
.blk-arc								{ position:relative; display:block; width:fit-content; max-width:100%; overflow:clip;
	> img								{ opacity:0; }
}
.blk-arc-pill							{ position:absolute; left:0; right:0; top:calc(-100% * var(--blk-arc-d)); bottom:calc(-100% * var(--blk-arc-d)); border-radius:var(--blk-arc-round); overflow:clip; pointer-events:none;
	&::after							{ content:""; position:absolute; inset:0; border-radius:inherit; border:var(--blk-arc-bw,0) solid var(--blk-arc-bc,transparent); }
}
.blk-arc.-left .blk-arc-pill::after		{ border-right-width:0; }
.blk-arc.-right .blk-arc-pill::after	{ border-left-width:0; }
.blk-arc-pic							{ position:absolute; left:0; right:0; top:calc(100% * var(--blk-arc-d) / (1 + 2 * var(--blk-arc-d))); height:calc(100% / (1 + 2 * var(--blk-arc-d))); background:var(--blk-arc-src) var(--blk-bgpos, 50% 50%) / cover no-repeat; }
/* a video cannot be a background: the player itself sits in the pill at
   the same offset (the placeholder tile in edit mode likewise) */
.blk-arc.-video							{ > video, > .blk-video-ph { opacity:0; } }
.blk-arc.-video .blk-arc-pill			{ pointer-events:auto;
	> video, > .blk-video-ph			{ position:absolute; left:0; right:0; top:calc(100% * var(--blk-arc-d) / (1 + 2 * var(--blk-arc-d))); height:calc(100% / (1 + 2 * var(--blk-arc-d))); width:100%; object-fit:cover; }
}
/* Mixed media: a video tile IS an image tile — same figure, same chrome,
   same sort/selection — presenting its poster with a play badge over it.
   The badge stays clickable (blocks.js uses it as a lightbox hit target,
   the only one a poster-less tile has), and the dark plate stands in when
   the video has no poster at all. */
.blk-image.-video						{ position:relative;
	/* poster-tile form only (gallery tiles, and the Media block in edit mode
	   where a live player would swallow the selection click) — a figure that
	   holds a real player letterboxes itself and must not get a plate */
	&:not(:has(video))					{ background:#1a1a1a; }
	&:not(:has(img)):not(:has(video))	{ min-height:8rem; }
	.blk-video-play						{ position:absolute; top:50%; left:50%; transform:translate(-50%,-50%); width:52px; height:52px; border-radius:50%; background:rgba(0,0,0,0.6); color:#fff; display:flex; align-items:center; justify-content:center;
		svg								{ width:28px; height:28px; margin-left:3px; }
	}
}
/* tenant-proof: sites commonly declare img{width:100%} (Warwick does, at
   several specificities, loading after this file), and inside a
   fit-content context (container Horizontal Alignment) 100% of a
   shrink-to-fit parent is cyclic → the image collapses to 0 and
   vanishes. Blocks own their image sizing — !important because tenant
   selectors can tie and win on load order; the gallery tile rule below
   re-asserts width:100% the same way for uniform tiles. */
.blk-page .blk-image img				{ width:auto !important; }
/* …and SVGs exported without width/height have NO intrinsic width, so a
   fit-content figure still collapses them to 0 (rasters survive on their
   natural size). Under content alignment the image FIGURE keeps full
   width instead of shrink-wrapping, and the img aligns itself with auto
   margins — same visual result, no intrinsic-size dependence. */
.blk-page .blk[style*="align-items"] > .blk-image				{ align-self:stretch; }
/* horizontal centring of an image keys on the CONTENT alignment the
   operator set, which in a stacked container is align-items. In a ROW
   container align-items is the VERTICAL axis, so these must not fire
   there — valign:center was sliding logos to the middle of their
   column (13.4) */
.blk-page .blk[style*="flex-direction:column"][style*="align-items:center"] > .blk-image img	{ margin-inline:auto; }
.blk-page .blk[style*="flex-direction:column"][style*="align-items:flex-end"] > .blk-image img	{ margin-left:auto; }
/* Divider: wrapper block (padding sits AROUND the line) + inner <hr>
   carrying line/weight/colour/width inline from prepare(). */
/* full width even in shrink-to-fit contexts (halign:center columns): an
   hr has no intrinsic width, so Full/Half rendered ZERO wide there and
   only the explicit Short survived (Denmead home, 2026-08-17) */
.blk-page .blk-divider					{ width:100%; }
.blk-divider hr							{ margin:0; height:0; }
/* CONTENT dividers (the inline editor's hr): the theme's Divider element
   is the default look; the Divider BLOCK's inline styles override
   per-instance. Same token chain both ways — studio default, block
   overrides (operator ruling 2026-08-17, the Table Style pattern). */
.blk-page .blk-text hr,
.blk-page .blk-html hr					{ border:0; height:0; border-top:var(--theme-divider-weight,1px) var(--theme-divider-style,solid) var(--theme-divider-color,#ccc); margin:var(--theme-divider-space,16px) 0; }

/* Inline content icons: <span class="thm-ic" style="--tic:var(--theme-ic-iN)">
   — an atom the inline editors insert from the theme Icons palette
   (icon-before-text rows: the FontAwesome-prefixed contact links no
   vocabulary could say). currentColor through a mask, so the icon takes
   the surrounding text colour and size; a palette swap rethemes every
   use already in content. Monochrome by design — a multi-colour glyph
   belongs in an Image block. */
.blk-page .thm-ic						{ display:inline-block; width:1em; height:1em; vertical-align:-0.125em; background:currentColor; -webkit-mask:var(--tic) center/contain no-repeat; mask:var(--tic) center/contain no-repeat; margin-right:0.35em; }
/* The hanging icon gutter is an OPT-IN para-style recipe (icon_hang →
   the theme emits it under .thm-ps-pN), never inferred from content
   shape — an implicit :has rule bent Capel's CENTRED footer line
   (operator 2026-08-26). The fixed atom margin above is what makes the
   opted-in gutter exact: atomTidy strips the stored nbsp at frontend
   render, so icon 1em + the style's 0.55em = a deterministic 1.55em. */

/* Video: responsive embed — aspect-ratio inline from prepare() */
.blk-video								{ position:relative; overflow:hidden;
	iframe								{ display:block; width:100%; height:100%; border:0; }
}

/* Image Shape: cover-crop to --blk-shape, filling the column so a row of
   shaped images lines up; the focal point steers the crop through the
   --blk-bgpos the banner reads. Gallery tiles keep the gallery's rule. */
.blk-page .blk-image.-shaped > img,
.blk-page .blk-image.-shaped > .blk-arc > img	{ width:100% !important; aspect-ratio:var(--blk-shape); object-fit:cover; object-position:var(--blk-bgpos, 50% 50%); }	/* !important: the tenant-proof width:auto above */
.blk-page .blk-image.-shaped > .blk-arc	{ width:100%; }	/* a shaped image fills the column; its arc wrapper must too */
/* Image Shape = Fill: the picture takes the box it sits in (a stretched
   slot, or a Fill container's share), cover-cropped; the arc wrapper
   follows the figure so the arc runs the full height */
.blk-page .blk-image.-fill				{ height:100%; flex:1 1 auto; min-height:0; }
.blk-page .blk-image.-fill > img,
.blk-page .blk-image.-fill > .blk-arc > img	{ width:100% !important; height:100%; object-fit:cover; object-position:var(--blk-bgpos, 50% 50%); }
.blk-page .blk-image.-fill > .blk-arc	{ width:100%; height:100%; }
/* Image Mask: the picture cover-crops to the SVG's proportions and shows
   through its filled area; the focal point steers the crop as for Shape */
.blk-page .blk-image.-masked > img		{ width:100% !important; aspect-ratio:var(--blk-mask-ar); object-fit:cover; object-position:var(--blk-bgpos, 50% 50%);
										  -webkit-mask-image:var(--blk-mask); -webkit-mask-size:100% 100%; -webkit-mask-repeat:no-repeat; mask-image:var(--blk-mask); mask-size:100% 100%; mask-repeat:no-repeat; }

/* Gallery: grid of Image children; --blk-thumb (aspect + cover-crop) makes
   uniform tiles; lightbox chrome lives in blocks.js */
.blk-gallery-grid							{ display:grid; gap:var(--blk-gap,1rem);
	grid-template-columns:repeat(auto-fill, minmax(max(var(--blk-colmin,0px), calc((100% - (var(--blk-cols,3) - 1) * var(--blk-gap,1rem)) / var(--blk-cols,3) - 0.5px)), 1fr));
	.blk-image img						{ width:100% !important; aspect-ratio:var(--blk-thumb, auto); object-fit:cover; }
	&[data-gal-lightbox] .blk-image img,
	&[data-gal-lightbox] .blk-image .blk-video-play	{ cursor:zoom-in; }
	/* tile chrome — the gallery's Image Padding/Border/Corners settings,
	   uniform across bound tiles and static Image children. !important:
	   a static child's own appearance renders as INLINE style, which
	   would win per property and break the uniform-tiles ruling — the
	   panel no longer offers per-image appearance in galleries, and this
	   keeps legacy stored values from competing either (2026-07-28) */
	.blk-image							{ padding:var(--blk-tile-pad,0) !important; border:var(--blk-tile-border,none) !important; border-radius:var(--blk-tile-radius,0) !important; box-shadow:var(--blk-tile-shadow,none) !important; overflow:hidden; }
}
/* Thumbnail gallery: main image + strip (bottom, or left like a product
   page). Source figures stay hidden — main is a clone, so caption and
   tile-chrome styling apply to it automatically. */
.blk-gallery-grid.-thumbs				{ display:block;
	.blk-tg-src							{ display:none; }
	.blk-tg-main						{ position:relative;
		.blk-image img					{ width:100% !important; aspect-ratio:auto; object-fit:contain; max-height:70vh; }
	}
	.blk-tg-strip						{ display:flex; gap:8px; margin-top:10px; overflow-x:auto; scrollbar-width:thin; }
	.blk-tg-thumb						{ flex:0 0 auto; width:64px; height:64px; padding:0; border:2px solid transparent; border-radius:6px; background:none; cursor:pointer; overflow:hidden;
		img								{ width:100%; height:100%; object-fit:cover; display:block; }
		&:hover							{ border-color:#9fb3cd; }
		&.-on							{ border-color:#2b6cb0; }
	}
}
.blk-gallery-grid.-thumbs.-thumbs-left	{ display:grid; grid-template-columns:76px minmax(0,1fr); gap:10px; align-items:start;
	.blk-tg-strip						{ grid-row:1; grid-column:1; flex-direction:column; margin-top:0; overflow-x:hidden; overflow-y:auto; max-height:70vh; }
	.blk-tg-main						{ grid-row:1; grid-column:2; }
}

/* Gallery captions: display is a GALLERY setting; per-image data supplies
   only the text. Over-image: caption on a translucent strip along the
   bottom; -scrim-auto starts dark and blocks.js reclassifies per image
   from the bottom-strip luminance (-cap-light / -cap-dark on the figure —
   the adaptive treatment designers hand-build with custom classes). */
.blk-gallery-grid.-cap-none .blk-image figcaption		{ display:none; }
.blk-gallery-grid.-cap-over .blk-image					{ position:relative;
	figcaption											{ position:absolute; left:0; right:0; bottom:0; margin:0; padding:0.45em 0.7em; font-size:0.85em; line-height:1.35; }
}
.blk-gallery-grid.-cap-over.-scrim-dark .blk-image figcaption,
.blk-gallery-grid.-cap-over.-scrim-auto .blk-image figcaption		{ background:rgba(18,20,24,0.55); color:#fff; }
.blk-gallery-grid.-cap-over.-scrim-light .blk-image figcaption		{ background:rgba(255,255,255,0.72); color:#1f2329; }
/* per-figure auto verdicts — after the scrim defaults so they win the tie */
.blk-gallery-grid.-cap-over .blk-image.-cap-dark figcaption		{ background:rgba(18,20,24,0.55); color:#fff; }
.blk-gallery-grid.-cap-over .blk-image.-cap-light figcaption	{ background:rgba(255,255,255,0.72); color:#1f2329; }
/* Where the over-image caption sits (gallery prop caption_pos). Bottom is
   the default and needs no rule. Top anchors the same full-width strip to
   the top edge; Centre floats it instead — the scrim shrinks to a rounded
   backdrop behind the TEXT rather than banding the image. Banner slides
   are .blk-image figures inside the gallery, so both land on them too;
   the scrim/auto rules above still supply the colours. */
.blk-gallery-grid.-cap-over.-cap-top .blk-image figcaption
														{ top:0; bottom:auto; }
.blk-gallery-grid.-cap-over.-cap-center .blk-image figcaption
														{ top:50%; bottom:auto; left:50%; right:auto; transform:translate(-50%,-50%); width:max-content; max-width:82%; text-align:center; border-radius:6px; }
/* Banner only: the dots overlay the band's bottom edge, so a bottom caption
   would sit under them. Dots sit at bottom:0.9em and are 0.65em across —
   about 1.6em of band is theirs, and captions render at 0.85em, so 2.2em of
   caption padding (≈1.9em of band) clears them. Keyed on a BUILT dot, so a
   dots-off banner (and a single-slide one) keeps the tighter caption. */
.blk-gallery-grid.-banner:has(.blk-car-dot):not(.-cap-top):not(.-cap-center) figcaption
														{ padding-bottom:2.2em; }

/* Gallery carousel layout: the image list on the carousel track — full
   snap cells, image centred at natural size (contain within 75vh) */
.blk-gallery-grid.-carousel				{ display:block;
	/* slides centre their image vertically — shorter images sit middle
	   of the track, not pinned to the top */
	/* Columns = images per view (default 3, like the grid); 1 restores the
	   classic one-image carousel */
	.blk-car-track > .blk				{ flex:0 0 max(var(--blk-colmin, 0px), calc((100% - (var(--blk-cols, 1) - 1) * var(--blk-gap, 0rem)) / var(--blk-cols, 1))); min-width:0; scroll-snap-align:start; scroll-snap-stop:always; margin:0; display:flex; flex-direction:column; justify-content:center; }
	.blk-image img						{ margin-inline:auto; aspect-ratio:auto; object-fit:contain; max-height:75vh; }
}

/* Gallery banner layout: the image list as full-width bands that CROSSFADE
   into one another — a slideshow, not a scrolling track (operator ruling:
   "banners rotate by fading one to another"). Slides stack absolutely and
   only .-on is opaque, so auto-play, arrows and dots all fade alike; the
   markup is .blk-banner / .blk-banner-track precisely so initCarousel (which
   binds .blk-carousel) never scrolls these slides. Slides cover-crop to
   --blk-banner-h around each media row's own focal point (--blk-bgpos,
   50% 50% when the row has none) — one focal per row, no separate mobile
   point (ruling: content on the row). Video rows play muted-looping,
   cropped the same way; blocks.js pauses the ones that are faded out. */
.blk-gallery-grid.-banner				{ display:block;
	.blk-banner							{ position:relative; }
	/* the band height lives on the TRACK now that slides stack: an inset-0
	   slide has no height of its own to give the band. (height, NOT
	   min-height: a Static-source banner's slides are the block's own Image
	   children, each holding a real <img> at width:100% whose natural height
	   — a 4:3 photo across a 1100px band is ~820px — always exceeded the
	   setting, so the band sized to the photo and the Height control did
	   nothing. A bound row is an empty figure carrying a background-image,
	   which is why the same control worked there.) */
	.blk-banner-track					{ position:relative; overflow:hidden; height:var(--blk-banner-h,420px); }
	.blk-banner-track > .blk			{ position:absolute; inset:0; margin:0; opacity:0; transition:opacity .8s ease;
										  background-size:cover; background-repeat:no-repeat; background-position:var(--blk-bgpos,50% 50%); }
	/* no-JS (or pre-bind) fallback: with nothing marked active the band would
	   read blank, so slide 1 shows until blocks.js claims the gallery. Bound
	   slides also carry -on server-side; static children can't, hence this. */
	&:not([data-banner-bound]) .blk-banner-track > .blk:first-child	{ opacity:1; }
	.blk-banner-track > .blk.-on		{ opacity:1; }
	/* …and with the band definite, a static child's image cover-crops into it
	   exactly like a bound row. Width is left to the gallery tile rule's
	   !important 100% (a plain width here would lose to .blk-page's). */
	.blk-banner-track > .blk img		{ height:100%; object-fit:cover; object-position:var(--blk-bgpos,50% 50%); }
	.blk-banner-track > .blk.-video video	{ position:absolute; inset:0; width:100%; height:100%; object-fit:cover; object-position:var(--blk-bgpos,50% 50%); }
	figcaption							{ position:absolute; left:0; right:0; bottom:0; margin:0; padding:12px 16px; color:#fff;
										  background:linear-gradient(transparent,rgba(0,0,0,0.55)); }
	/* dots overlay the band (there is no strip below a full-bleed banner to
	   sit in) and go light-on-dark to read against photography */
	.blk-car-dots						{ position:absolute; left:0; right:0; bottom:0.9em; z-index:1; padding-top:0; }
	.blk-car-dot						{ background:rgba(255,255,255,0.55); box-shadow:0 1px 3px rgba(0,0,0,0.35);
		&.-on							{ background:#fff; }
	}
}
/* a visitor who asked for less motion gets the slideshow without the
   dissolve — navigation still works, it just cuts */
@media (prefers-reduced-motion: reduce) {
	.blk-gallery-grid.-banner .blk-banner-track > .blk	{ transition:none; }
	.blk-carousel.-fade .blk-car-track > .blk-car-slide	{ transition:none; }
}

/* Waterfall: CSS-columns masonry — images keep their heights and flow
   down each column. WYSIWYG: the editor renders it too (editor-only
   children span all columns via column-span in block_editor.css). */
/* columns shorthand takes BOTH: min width + max count — the same colmin
   setting drives waterfall responsiveness natively */
.blk-gallery-grid.-waterfall			{ display:block; columns:var(--blk-colmin,auto) var(--blk-cols,3); column-gap:var(--blk-gap,1rem);
	> .blk								{ break-inside:avoid; margin:0 0 var(--blk-gap,1rem); }
	.blk-image img						{ aspect-ratio:auto; }
}
.blk-lightbox							{ position:fixed; inset:0; z-index:9999; background:rgba(10,12,16,0.92); display:flex; align-items:center; justify-content:center;
	img									{ max-width:92vw; max-height:88vh; display:block; box-shadow:0 8px 40px rgba(0,0,0,0.5); }
	video								{ max-width:92vw; max-height:88vh; display:block; box-shadow:0 8px 40px rgba(0,0,0,0.5); }
	button								{ position:absolute; border:0; background:rgba(255,255,255,0.12); color:#fff; cursor:pointer; border-radius:50%; width:44px; height:44px; display:flex; align-items:center; justify-content:center;
		svg								{ width:22px; height:22px; }
		&:hover							{ background:rgba(255,255,255,0.25); }
	}
	.blk-lb-close						{ top:18px; right:18px; }
	.blk-lb-prev						{ left:18px; top:50%; transform:translateY(-50%); }
	.blk-lb-next						{ right:18px; top:50%; transform:translateY(-50%); }
	.blk-lb-count						{ position:absolute; bottom:16px; left:50%; transform:translateX(-50%); color:rgba(255,255,255,0.8); font-size:13px; }
}

/* Button: call-to-action link. Every look comes from the THEME's button
   tokens (Design Studio Buttons pane + its per-variant panes) with the
   historic literals as fallbacks — an unset theme renders
   byte-identically to before. Typography and shape (font, size, weight,
   transform, tracking, border width, radius) are ONE set for every
   variant; colours are per variant, and Outline / Outline Light / Text
   chain to the Filled / Light pair when unset so a brand recolour
   ripples every variant. Size variants multiply the theme size (a bare
   em there would ignore it). */
/* .thm-btn: the IN-BODY CTA class (third want: Capel, NF, Crawley all
   carry .button-cta pills in body HTML that our bound bodies rendered
   as text links). A link the inline content marks thm-btn dresses as
   the theme button — same tokens, same variants; site_convert's
   cta_class step rewrites legacy button-cta tokens to it. */
.blk-btn,
.blk-page a.thm-btn						{ display:inline-block; padding:var(--theme-btn-pad-y, 0.65em) var(--theme-btn-pad-x, 1.6em); border:var(--theme-btn-border-width, 2px) solid var(--theme-btn-bg, #2d2d2d); border-radius:var(--theme-btn-radius, 6px); background:var(--theme-btn-bg, #2d2d2d); color:var(--theme-btn-text, #fff); font-family:var(--theme-btn-font, inherit); font-size:var(--theme-btn-size, 1em); font-weight:var(--theme-btn-bold, 600); text-transform:var(--theme-btn-transform, inherit); letter-spacing:var(--theme-btn-letter-spacing, inherit); text-decoration:none; line-height:1.3; cursor:pointer;
	/* hover: the fade is the default; --theme-btn-hover-fx = 1 (Recolour)
	   stops it and the per-variant hover colours take over, each falling
	   back to the variant's resting colour */
	&:hover								{ opacity:calc(1 - 0.15 * (1 - var(--theme-btn-hover-fx, 0))); background:var(--theme-btn-hover-bg, var(--theme-btn-bg, #2d2d2d)); border-color:var(--theme-btn-hover-bg, var(--theme-btn-bg, #2d2d2d)); color:var(--theme-btn-hover-text, var(--theme-btn-text, #fff)); }
	&.-light							{ background:var(--theme-btn-light-bg, #fff); border-color:var(--theme-btn-light-text, #2d2d2d); color:var(--theme-btn-light-text, #2d2d2d);
		&:hover							{ background:var(--theme-btn-light-hover-bg, var(--theme-btn-light-bg, #fff)); border-color:var(--theme-btn-light-hover-text, var(--theme-btn-light-text, #2d2d2d)); color:var(--theme-btn-light-hover-text, var(--theme-btn-light-text, #2d2d2d)); }
	}
	&.-outline							{ background:none; border-color:var(--theme-btn-outline-border, var(--theme-btn-bg, #2d2d2d)); color:var(--theme-btn-outline-text, var(--theme-btn-bg, #2d2d2d));
		&:hover							{ background:var(--theme-btn-outline-hover-bg, none); border-color:var(--theme-btn-outline-border, var(--theme-btn-bg, #2d2d2d)); color:var(--theme-btn-outline-hover-text, var(--theme-btn-outline-text, var(--theme-btn-bg, #2d2d2d))); }
	}
	/* white-on-photo CTAs (earned at the THIRD want: Crawley, St Martin's,
	   Holy Trinity hero pills) — Outline in the LIGHT colours by default. */
	&.-outline-light					{ background:none; border-color:var(--theme-btn-outline-light-border, var(--theme-btn-light-bg, #fff)); color:var(--theme-btn-outline-light-text, var(--theme-btn-light-bg, #fff));
		&:hover							{ background:var(--theme-btn-outline-light-hover-bg, none); border-color:var(--theme-btn-outline-light-border, var(--theme-btn-light-bg, #fff)); color:var(--theme-btn-outline-light-hover-text, var(--theme-btn-outline-light-text, var(--theme-btn-light-bg, #fff))); }
	}
	/* the underlined-link look: own colour / weight / underline
	   (btn_txt_*; weight falls back to the shared button weight) */
	&.-text								{ background:none; border-color:transparent; color:var(--theme-btn-txt-color, inherit); font-weight:var(--theme-btn-txt-bold, var(--theme-btn-bold, 600)); text-decoration:var(--theme-btn-txt-underline, underline); padding-inline:0.2em;
		&:hover							{ background:none; border-color:transparent; color:var(--theme-btn-txt-hover-color, var(--theme-btn-txt-color, inherit)); }
	}
	/* Small and Large: the studio's Small / Large Buttons sections, each
	   falling back to the historic ratio of the button size; Small may
	   harden its weight */
	&.-sm								{ padding:var(--theme-btn-sm-pad-y, 0.45em) var(--theme-btn-sm-pad-x, 1.1em); font-size:var(--theme-btn-sm-size, calc(var(--theme-btn-size, 1em) * 0.9)); font-weight:var(--theme-btn-sm-bold, var(--theme-btn-bold, 600)); }
	&.-lg								{ padding:var(--theme-btn-lg-pad-y, 0.85em) var(--theme-btn-lg-pad-x, 2.2em); font-size:var(--theme-btn-lg-size, calc(var(--theme-btn-size, 1em) * 1.15)); }
}

/* Carousel: native CSS scroll-snap — swipe/momentum/keyboard from the
   browser; blocks.js adds dots, arrow paging and optional auto-advance.
   Slides are full-width snap cells and hold any blocks. */
.blk-carousel							{ position:relative; }
.blk-car-track							{ display:flex; overflow-x:auto; scroll-snap-type:x mandatory; overscroll-behavior-x:contain; scrollbar-width:none;
	&::-webkit-scrollbar				{ display:none; }
}
/* multi-across (2026-07-27): --blk-cols slides per view (1 = classic full-
   width); the same columns/gap/colmin vocabulary as the grid. Arrows and
   auto-advance page by view width and WRAP — the infinite feel for free. */
.blk-car-track							{ gap:var(--blk-gap, 0px); }
/* Ticker auto-play: a continuous glide — snap would fight the per-frame
   scroll, and the glide IS the navigation, so the nav chrome goes */
.blk-carousel.-ticker .blk-car-track	{ scroll-snap-type:none; }
.blk-carousel.-ticker .blk-car-arrow,
.blk-carousel.-ticker .blk-car-dots		{ display:none; }
/* Fade auto-play (single-column hero slideshows): slides GRID-STACK in one
   cell — in flow, unlike the banner's absolute slides, so the track takes
   the tallest slide's height (composed slides have no fixed band height) —
   and cross-fade by opacity; blocks.js moves the -on class with the same
   engine as the banner. First slide shows until JS binds (no-JS fallback). */
.blk-carousel.-fade .blk-car-track		{ display:grid; overflow:visible; scroll-snap-type:none;
	> .blk-car-slide					{ grid-area:1/1; opacity:0; transition:opacity .8s ease; pointer-events:none; }
	> .blk-car-slide.-on				{ opacity:1; pointer-events:auto; }
}
.blk-carousel.-fade:not([data-car-bound]) .blk-car-track > .blk-car-slide:first-child	{ opacity:1; pointer-events:auto; }
/* fade heroes wear their dots ON the image, banner-style (the strip below
   otherwise breaks the block's bottom edge — and its rounded corners —
   away from the picture), light-on-dark to read against photography */
.blk-carousel.-fade .blk-car-dots		{ position:absolute; left:0; right:0; bottom:0.9em; z-index:1; padding-top:0; }
.blk-carousel.-fade .blk-car-dot		{ background:rgba(255,255,255,0.55); box-shadow:0 1px 3px rgba(0,0,0,0.35);
	&.-on								{ background:#fff; }
}
.blk-car-track > .blk-car-slide			{ flex:0 0 max(var(--blk-colmin, 0px), calc((100% - (var(--blk-cols, 1) - 1) * var(--blk-gap, 0rem)) / var(--blk-cols, 1))); min-width:0; scroll-snap-align:start; scroll-snap-stop:always; margin-top:0; box-sizing:border-box; }
.blk-car-arrow							{ position:absolute; top:50%; transform:translateY(-50%); z-index:1; width:2.6em; height:2.6em; padding:0; border:0; border-radius:50%; background:rgba(255,255,255,0.85); color:#333; cursor:pointer; box-shadow:0 1px 4px rgba(0,0,0,0.25); display:flex; align-items:center; justify-content:center;
	svg									{ width:1.4em; height:1.4em; }
	&.-prev								{ left:0.6em; }
	&.-next								{ right:0.6em; }
	&:hover								{ background:#fff; }
}
/* arrows reveal on hover where hover exists; touch devices keep them
   visible (no hover to reveal with) — applies to the carousel track and
   the thumbnail gallery's main image alike */
@media (hover:hover) {
	.blk-car-arrow						{ opacity:0; transition:opacity 0.15s ease; }
	.blk-carousel:hover .blk-car-arrow,
	.blk-banner:hover .blk-car-arrow,
	.blk-tg-main:hover .blk-car-arrow,
	.blk-car-arrow:focus-visible		{ opacity:1; }
}
.blk-car-dots							{ display:flex; justify-content:center; gap:0.55em; padding-top:0.8em; }
.blk-car-dot							{ width:0.65em; height:0.65em; padding:0; border:0; border-radius:50%; background:#c9c9c9; cursor:pointer; transition:background .15s ease;
	&.-on								{ background:#555; }
}

/* Accordion: native details/summary — zero JS; exclusive-open via the
   shared name attribute. Card tab chrome (2026-08-25, the Phoenix FAQ):
   the ITEM is the card — question row + open answer as one box — via the
   shared --blk-tile-* vars (fallbacks ARE the historic look: 1px #ddd,
   square, transparent). Gap rides a dedicated --blk-acc-gap (never
   --blk-gap — that inherits from ancestor containers); -split switches
   off the joined-stack border collapse. */
.blk-accordion							{ display:flex; flex-direction:column; gap:var(--blk-acc-gap,0px); }
.blk-accordion .blk-accitem + .blk-accitem				{ margin-top:0; }
.blk-accordion:not(.-split) .blk-accitem + .blk-accitem	{ border-top:0; }
details.blk-accitem						{ border:var(--blk-tile-border,1px solid #ddd); border-radius:var(--blk-tile-radius,0); background:var(--blk-tile-bg,transparent); color:var(--blk-tile-color,inherit); box-shadow:var(--blk-tile-shadow,none); padding:var(--blk-tile-pad,0);
	/* slide-open (2026-08-26, the source jQuery-slide look with zero JS):
	   modern engines animate ::details-content height; others snap open
	   exactly as before — progressive enhancement, reduced-motion stilled */
	interpolate-size:allow-keywords;
	&::details-content					{ block-size:0; overflow-y:clip; transition:block-size .28s ease, content-visibility .28s allow-discrete; }
	&[open]::details-content			{ block-size:auto; }
	/* Title Bar Background paints CLOSED items only — an open item joins
	   its content (the North Finchley tab-accordion look) */
	&:not([open]) > summary				{ background:var(--blk-acc-title-bg,transparent); }
	summary								{ padding:0.8em 1em; font-weight:600; cursor:pointer; list-style:none; display:flex; align-items:center; gap:0.6em;
		&::before						{ content:''; width:0.55em; height:0.55em; border-right:2px solid currentColor; border-bottom:2px solid currentColor; transform:rotate(-45deg); transition:transform .18s ease; flex:0 0 auto; }
		&::-webkit-details-marker		{ display:none; }
	}
	&[open] > summary::before			{ transform:rotate(45deg); }
	.blk-accitem-body					{ padding:0.3em 1em 1em; }
}
/* icon variants (Card tab): Right moves the glyph to a ::after pushed to
   the far edge; Plus swaps the chevron for +/− text glyphs. */
.blk-accordion.-ic-right details.blk-accitem summary::before			{ content:none; }
.blk-accordion.-ic-right details.blk-accitem summary::after				{ content:''; width:0.55em; height:0.55em; border-right:2px solid currentColor; border-bottom:2px solid currentColor; transform:rotate(-45deg); transition:transform .18s ease; flex:0 0 auto; margin-left:auto; }
.blk-accordion.-ic-right details.blk-accitem[open] > summary::after		{ transform:rotate(45deg); }
.blk-accordion.-ic-plus details.blk-accitem summary::before				{ content:'+'; width:auto; height:auto; border:0; transform:none; font-size:1.2em; line-height:1; font-weight:400; }
.blk-accordion.-ic-plus details.blk-accitem[open] > summary::before		{ content:'−'; transform:none; }
.blk-accordion.-ic-plus.-ic-right details.blk-accitem summary::after	{ content:'+'; width:auto; height:auto; border:0; transform:none; font-size:1.2em; line-height:1; font-weight:400; }
.blk-accordion.-ic-plus.-ic-right details.blk-accitem[open] > summary::after	{ content:'−'; transform:none; }
/* Caret: the small filled dropdown triangle (North Finchley) — down when
   closed, flipped when open */
.blk-accordion.-ic-caret details.blk-accitem summary::before,
.blk-accordion.-ic-caret.-ic-right details.blk-accitem summary::after	{ content:''; width:0; height:0; border:0; border-left:5px solid transparent; border-right:5px solid transparent; border-top:6px solid currentColor; transform:none; transition:transform .18s ease; }
.blk-accordion.-ic-caret details.blk-accitem[open] > summary::before,
.blk-accordion.-ic-caret.-ic-right details.blk-accitem[open] > summary::after	{ transform:rotate(180deg); }
.blk-accordion.-ic-caret.-ic-right details.blk-accitem summary::before	{ content:none; }
@media (prefers-reduced-motion: reduce) {
	details.blk-accitem summary::before,
	details.blk-accitem::details-content,
	.blk-accordion.-ic-right details.blk-accitem summary::after			{ transition:none; }
}

/* Tabs: bar + one panel. Critical layout owned under .blk-page — tenants
   style tab bars; we keep flex, gaps, and panel stack intact. */
.blk-page .blk-tabs						{ display:block; }
.blk-page .blk-tabs-bar					{ display:flex; flex-wrap:wrap; gap:0.25em 0.5em; margin:0 0 1em; padding:0; border-bottom:1px solid #ddd; list-style:none; }
.blk-page .blk-tabs-btn					{ appearance:none; -webkit-appearance:none; font:inherit; cursor:pointer; margin:0 0 -1px; padding:0.55em 0.95em; border:1px solid transparent; border-bottom-color:#ddd; border-radius:4px 4px 0 0; background:transparent; color:inherit;
	&.-on								{ border-color:#ddd; border-bottom-color:#fff; background:#fff; font-weight:600; }
}
.blk-page .blk-tabs > .blk-tab			{ margin-top:0; }
.blk-page .blk-tabs > .blk-tab[hidden]	{ display:none !important; }

/*---------------- Phase 4 — product / folder module blocks ----------------*/
/* Product price: size segments match .blk-btn; strike RRP/orig when on offer.
   Tenant CSS owns brand colour; we only set layout + offer chrome. */
.blk-page .blk-prod-price				{ line-height:1.3;
	&.-sm .price						{ font-size:0.9em; }
	&.-lg .price						{ font-size:1.35em; font-weight:600; }
	.price								{ font-size:1.15em; font-weight:600; }
	.price-orig .amount					{ text-decoration:line-through; opacity:0.7; margin-right:0.5em; }
	.price-rrp .amount					{ text-decoration:line-through; opacity:0.55; font-size:0.9em; }
	.price-both							{ display:flex; flex-wrap:wrap; gap:0.35em 1em; }
	.vat-status,.vat-label				{ font-size:0.85em; opacity:0.75; }
}
/* Buy: reuses .blk-btn; qty sits inline. Nested price/variants keep form flow. */
.blk-page .blk-prod-buy					{
	.shop-wrapper						{ display:flex; flex-wrap:wrap; align-items:center; gap:0.6em; }
	input.qty,.blk-prod-qty-preview		{ width:3.2em; text-align:center; padding:0.45em 0.3em; border:1px solid #ccc; border-radius:4px; font-size:1em; box-sizing:border-box; }
	/* submit resets — tenants style buttons aggressively */
	input.blk-btn[type=submit]			{ appearance:none; -webkit-appearance:none; font:inherit; cursor:pointer; }
	/* children inside the form don't double the page rhythm */
	.blk + .blk							{ margin-top:var(--blk-space-s); }
}
/* Variants: leave the attribute chrome to product.css when loaded; baseline only. */
.blk-page .blk-prod-variants			{
	.variant-block						{ margin:0; }
	.variant-block dd					{ margin:0 0 0.6em; }
}
/*---------------- Popup (CTA dialog) ----------------*/
/* The SHELL is the fixed viewport layer (overlay + placement); the .blk
   inside is the dialog box, whose look comes entirely from the standard
   Appearance props. z-index sits above sticky headers — tenants pin
   theirs in the low hundreds; --blk-popup-z lets a site go higher. */
.blk-popup-shell						{ position:fixed; inset:0; z-index:var(--blk-popup-z,9000); display:flex; padding:16px; pointer-events:none;
	&[hidden]							{ display:none; }
	&.-overlay							{ background:rgba(0,0,0,0.45); pointer-events:auto; }
	&.-centre							{ align-items:center; justify-content:center; }
	&.-corner							{ align-items:flex-end; justify-content:flex-end; }
	&.-bar								{ align-items:flex-end; justify-content:center; padding:0; }
	> .blk-popup						{ pointer-events:auto; position:relative; width:min(520px, 100%); max-height:calc(100vh - 32px); overflow-y:auto;
		/* the box's OWN look is Appearance-driven; these are only the
		   defaults a bare popup needs to read as a dialog at all */
		background:var(--blk-popup-bg,#fff); border-radius:var(--theme-radius-m,10px); box-shadow:0 10px 40px rgba(0,0,0,0.28); padding:24px;
	}
	&.-bar > .blk-popup					{ width:100%; max-width:none; border-radius:0; }
}
/* entrance: a plain fade/rise unless the block carries its own reveal fx */
.blk-popup-shell:not([hidden]) > .blk-popup	{ animation:blk-popup-in .28s ease-out; }
@keyframes blk-popup-in					{ from { opacity:0; transform:translateY(12px); } }
@media (prefers-reduced-motion: reduce) {
	.blk-popup-shell > .blk-popup		{ animation:none; }
}
.blk-popup-close						{ position:absolute; top:8px; right:8px; z-index:2; width:32px; height:32px; display:flex; align-items:center; justify-content:center; border:0; border-radius:50%; background:rgba(255,255,255,0.85); color:#374151; cursor:pointer; padding:0;
	svg									{ width:17px; height:17px; }
	&:hover								{ background:#fff; color:#111; }
}

/* House table style: the studio's Table Style tokens with the historic
   matrix literals as fallbacks — consumers (price matrix, delivery
   options, future Table block) wear .thm-table or these matrix classes */
table.thm-table							{ width:100%; border-collapse:collapse; border:var(--theme-tbl-border-width,1px) var(--theme-tbl-border-style,solid) var(--theme-tbl-border-color,#e5e5e5); background:#fff; color:inherit;
	th,td								{ padding:var(--theme-tbl-cell-pad,0.55em) 0.75em; border:var(--theme-tbl-border-width,1px) var(--theme-tbl-border-style,solid) var(--theme-tbl-border-color,#e5e5e5); text-align:left; }
	th									{ font-weight:var(--theme-tbl-head-bold,600); background:var(--theme-tbl-head-bg-color,#f7f7f7); color:var(--theme-tbl-head-color,inherit); }
	tbody tr:nth-child(even) td			{ background:var(--theme-tbl-stripe-color,transparent); }
}
/* Matrix: defensive table baseline — tenants restyle tables hard. */
.blk-page .blk-prod-matrix				{
	table								{ width:100%; border-collapse:collapse; border:var(--theme-tbl-border-width,1px) var(--theme-tbl-border-style,solid) var(--theme-tbl-border-color,#e5e5e5); background:#fff; color:inherit; font:inherit; }
	th,td								{ padding:var(--theme-tbl-cell-pad,0.55em) 0.75em; border:var(--theme-tbl-border-width,1px) var(--theme-tbl-border-style,solid) var(--theme-tbl-border-color,#e5e5e5); text-align:left; }
	th									{ font-weight:var(--theme-tbl-head-bold,600); background:var(--theme-tbl-head-bg-color,#f7f7f7); color:var(--theme-tbl-head-color,inherit); }
	tbody tr:nth-child(even) td			{ background:var(--theme-tbl-stripe-color,transparent); }
	tr.no-qty,tr.not-on-offer			{ display:none; }
	&.-compact th,&.-compact td			{ padding:0.3em 0.5em; font-size:0.92em; }
	/* offer column empty when not on offer — hide c3 */
	.price-break:not(.on-offer) .c3,
	.price-break:not(.on-offer) th.c3	{ display:none; }
}
/* ChurchSuite events: house cards over the vendor's headless embed —
   same responsive column recipe, cards ARE .blk-card (Card tab chrome
   applies). The <template> children are inert until Alpine stamps them. */
.blk-page .blk-cs-grid					{ display:grid; gap:var(--blk-gap,1.5rem);
										  grid-template-columns:repeat(auto-fill, minmax(max(var(--blk-colmin,14rem), calc((100% - (var(--blk-cols,3) - 1) * var(--blk-gap,1.5rem)) / var(--blk-cols,3) - 0.5px)), 1fr)); }
.blk-page .blk-cs-card					{ text-decoration:none; color:var(--blk-tile-color,inherit); }
.blk-page .blk-cs-card .blk-card-snippet	{ padding-bottom:0.85em; }

/* Card lists (folder_list / related_list): gallery-grid column machinery +
   shared .blk-card chrome via --blk-tile-* (fallbacks ARE the default look).
   colmin DEFAULTS to 14rem here (the card carousel's floor): with 0px, any
   shrink-to-fit ancestor makes the width indefinite, the percentage share
   resolves to auto, and auto-fill collapses to ONE column (Denmead home,
   2026-08-17 — the list needed an explicit colmin just to be 3-across).
   At normal widths the Nth share exceeds 14rem, so exact-N is unchanged. */
.blk-page .blk-folder-list,
.blk-page .blk-related-list				{ display:grid; gap:var(--blk-gap,1rem);
										  grid-template-columns:repeat(auto-fill, minmax(max(var(--blk-colmin,14rem), calc((100% - (var(--blk-cols,3) - 1) * var(--blk-gap,1rem)) / var(--blk-cols,3) - 0.5px)), 1fr)); }
/* border-box: cards are NOT .blk (which gets it globally) — content-box
   made each card's border add outside the carousel flex-basis, so the
   last card's right border clipped past the track (operator 2026-07-28) */
.blk-page .blk-card						{ display:flex; flex-direction:column; gap:0.5em; box-sizing:border-box; padding:var(--blk-tile-pad,0); border:var(--blk-tile-border,1px solid #e8e8e8); border-radius:var(--blk-tile-radius,0); box-shadow:var(--blk-tile-shadow,none); overflow:hidden; background:var(--blk-tile-bg,#fff); color:var(--blk-tile-color,inherit); transition:box-shadow .15s ease, background-color .15s ease;
	&:hover								{ box-shadow:var(--blk-tile-shadow,0 4px 14px rgba(0,0,0,0.1)); filter:brightness(0.99); }
}
/* Card tab Hover cell (2026-08-25): '' = the lift above. Tint mixes the
   card bg toward the card TEXT colour (literal #333 fallback — 'inherit'
   would void the color-mix) so dark-on-light darkens and light-on-brand
   lightens; both alternates cancel the default lift/brightness. */
.blk-page .-hov-none .blk-card:hover	{ box-shadow:var(--blk-tile-shadow,none); filter:none; }
.blk-page .-hov-tint .blk-card:hover	{ box-shadow:var(--blk-tile-shadow,none); filter:none;
										  background:color-mix(in srgb, var(--blk-tile-bg,#fff) 86%, var(--blk-tile-color,#333)); }
/* Card tab Selected (Show Current Page, the pill-nav want): the marked
   card takes the Selected pair, falling back to the ordinary tile look.
   Hover effects stand down on it (after the hover rules — the tie must
   break this way): the state is a statement, not an invitation. */
.blk-page .blk-card.-sel				{ background:var(--blk-tile-sel-bg,var(--blk-tile-bg,#fff)); color:var(--blk-tile-sel-color,var(--blk-tile-color,inherit));
	&:hover								{ box-shadow:var(--blk-tile-shadow,none); filter:none; background:var(--blk-tile-sel-bg,var(--blk-tile-bg,#fff)); }
}
/* Imageless items in a CUSTOM row card: an image-only first column
   collapses so the text spans the full row (the source-list look —
   North Finchley's dateless first news item reserved a dead 230px
   track). Curated cards already skip the figure per item. */
/* :not(:has(…)), never :empty (whitespace text nodes defeat it) and
   never :has(:not(:has(…))) — :has cannot nest inside :has, the whole
   selector silently drops. This reads: a -no-img card's columns whose
   FIRST column contains no block. */
.blk-page .blk-card.-no-img .blk-columns:not(:has(> .blk-container:first-child .blk))	{ grid-template-columns:1fr;
	> .blk-container:first-child		{ display:none; }
}
/* Item Width Hug (Flow mode): pill rows — each card as wide as its
   content, wrapping; gap still reads from the grid rule above. */
.blk-page .blk-folder-list.-hug,
.blk-page .blk-related-list.-hug		{ display:flex; flex-wrap:wrap;
	> .blk-card							{ flex:0 0 auto; }
	&.-hug-c							{ justify-content:center; }
}
.blk-page .blk-card-img					{ margin:0; aspect-ratio:var(--blk-card-aspect,4/3); overflow:hidden; background:#f3f3f3;
	img									{ display:block; width:100% !important; height:100%; max-width:none; object-fit:cover; }
}
/* flex:1 — the link must FILL the card: composed templates pin their
   bottom band with margin-top:auto INSIDE the link (the frontend repeat
   pass wraps card content in it; edit mode doesn't), and auto margins
   need the free space to live in the same flex context
   (operator 2026-07-29: pinned in edit, not on the front). */
.blk-page .blk-card-link				{ display:flex; flex-direction:column; gap:0.5em; flex:1 1 auto; text-decoration:none; color:inherit; font-weight:inherit; }	/* the theme's Links element (colour, bold, underline) styles prose links, not a card's wrapper */
.blk-page .blk-card-title				{ padding:0 0.75em; }
.blk-page .blk-card-title:not([class*="thm-ps-"])	{ font-weight:600; }	/* the chrome's weight is a default: a named Title Style decides its own */
.blk-page .blk-card-snippet				{ font-size:0.92em; opacity:0.85; padding:0 0.75em 0.85em; line-height:1.4; }
.blk-page .blk-card-price				{ padding:0 0.75em; margin-top:auto; font-weight:600;
	.price-was							{ margin-left:0.5em; font-weight:400; opacity:0.6; text-decoration:line-through; }
}
.blk-page .blk-card-buy					{ padding:0.5em 0.75em 0.85em; text-align:var(--blk-card-buy-align,left); }
/* COMPOSED cards (repeater card template): generic blocks inherit the
   curated card's look by POSITION — the fallback renders the original
   hand-written markup, the template renders real blocks, and without
   these the two drifted (bottom-pinned price/buy, 4:3 crop, card type
   scale — operator 2026-07-29). */
.blk-page .blk-card .blk				{ margin:0; }
/* COMPOSED cards own their rhythm outright: the chrome's 0.5em flex gap
   exists for the curated image/title/snippet units, but between Card
   Items blocks it is an uncancellable 8px that surfaces under overlay
   compositions (the Denmead caption strip sat proud of the card bottom
   by exactly this gap, 2026-08-17). Composers space with padding. */
.blk-page .blk-card:has(> .blk),
.blk-page .blk-card-link:has(> .blk)	{ gap:0; }
.blk-page .blk-card .blk-heading		{ padding:0 0.75rem; color:inherit; }
/* compact title default — a named Style on the heading must win (custom
   row cards match source list typography through the theme, never CSS) */
.blk-page .blk-card .blk-heading:not([class*="thm-ps-"])	{ font-size:1em; font-weight:600; }
/* rem gutter, not em: a heading and text in one card column must share
   a left edge whatever the title's named-style size */
.blk-page .blk-card .blk-text			{ font-size:0.92em; opacity:0.85; padding:0 0.75rem; line-height:1.4; }
.blk-page .blk-card .blk-image			{ margin:0; aspect-ratio:var(--blk-card-aspect,4/3); overflow:hidden; background:#f3f3f3;
	img									{ display:block; width:100% !important; height:100%; max-width:none; object-fit:cover; }
}
/* List Image on Hover (legacy pg_image is_list_image=9, carried into the
   curated card): the hover image stacks over the base and fades in on
   pointer-over or keyboard focus. Touch has no hover — base image stands. */
.blk-page .blk-card-img.-has-hover		{ position:relative;
	img.-hover							{ position:absolute; inset:0; opacity:0; transition:opacity 0.25s ease; }
}
.blk-page .blk-card:hover .blk-card-img.-has-hover img.-hover,
.blk-page .blk-card:focus-within .blk-card-img.-has-hover img.-hover
										{ opacity:1; }
@media (prefers-reduced-motion:reduce) {
	.blk-page .blk-card-img.-has-hover img.-hover	{ transition:none; }
}

/* Caption placement (curated cards, Captions prop): 'over' anchors the
   title as a scrim bar on the card bottom; 'hover' hides it below the
   crop (chrome overflow:hidden) and slides it up on pointer-over or
   keyboard focus. Touch has no hover — the bar stays visible; reduced
   motion drops the slide. Overlay modes pair with image+title cards. */
.blk-page [class*="-cap-"] .blk-card	{ position:relative; }
.blk-page .-cap-over .blk-card-title,
.blk-page .-cap-hover .blk-card-title	{ position:absolute; left:0; right:0; bottom:0; margin:0; padding:0.7em 0.75em; background:var(--blk-cap-bg, rgba(0,0,0,0.45)); text-align:center; }
/* the overlay's own colours are defaults: a named Title Style (thm-ps-N) carries its colour and must win */
.blk-page .-cap-over .blk-card-title:not([class*="thm-ps-"]),
.blk-page .-cap-hover .blk-card-title:not([class*="thm-ps-"])	{ color:#fff; }
.blk-page .-cap-hover .blk-card-title	{ transform:translateY(101%); transition:transform 0.25s ease; }
.blk-page .-cap-hover .blk-card:hover .blk-card-title,
.blk-page .-cap-hover .blk-card:focus-within .blk-card-title
										{ transform:translateY(0); }
@media (hover:none) {
	.blk-page .-cap-hover .blk-card-title	{ transform:none; }
}
@media (prefers-reduced-motion:reduce) {
	.blk-page .-cap-hover .blk-card-title	{ transition:none; transform:none; }
}

/* Caption chrome (earned: Ilkley sub-line + Bellevue pill looks).
   Pill hugs the title (left/right auto-margins centre it without a
   transform, so the hover slide composes); position cells move the
   OVERLAY caption — centre and bottom-left are On Image only (the
   captionClass whitelist gates them). The second line renders only
   when the list is in an overlay mode (renderCards blanks it
   otherwise). */
.blk-page .-cap-pill .blk-card-title	{ left:0; right:0; width:max-content; max-width:85%; margin:0 auto 0.75em; padding:0.45em 1.2em; border-radius:999px; background:var(--blk-cap-bg, rgba(255,255,255,0.92)); }
.blk-page .-cap-pill .blk-card-title:not([class*="thm-ps-"])	{ color:#1f2329; }
.blk-page .-capp-center .blk-card-title	{ bottom:50%; translate:0 50%; margin-bottom:0; }
.blk-page .-capp-bl .blk-card-title		{ margin-left:0.75em; margin-right:auto; margin-bottom:0.75em; text-align:left; }
.blk-page .-capp-bl:not(.-cap-pill) .blk-card-title
										{ left:0; right:auto; max-width:85%; }
/* Bottom Left + Pill = the flush-left lozenge (the Bellevue source
   look): anchored to the card's left edge, rounded on its free end
   only, lifted clear of the bottom — a floating pill with a margin
   reads tentative where the flush anchor reads designed. */
.blk-page .-cap-pill.-capp-bl .blk-card-title
										{ margin-left:0; margin-bottom:1.1em; padding:0.5em 1.4em 0.5em 1em; border-radius:0 999px 999px 0; }
/* Panel = the inset tint wash (earned: North Finchley's Navy inset
   tiles). The caption box fills the image behind a proportional margin
   (the source's fixed 30px ≈ 8% of its tile — proportional holds across
   column counts); padding, the subtle 3% rounding and the Caption
   Colour tint are the source's own numbers, with the bar's dark scrim
   as the unset fallback. Position cells keep their meaning INSIDE the
   panel: Bottom (default) sits the text at the panel's foot, Centre
   centres it, Bottom Left also left-aligns (text-align rides the
   earlier -capp-bl rule; inset/translate here override its geometry). */
.blk-page .-cap-panel .blk-card-title	{ inset:8%; translate:none; width:auto; max-width:none; margin:0; padding:15px; border-radius:3%; background:var(--blk-cap-bg, rgba(0,0,0,0.45)); color:#fff;
										  display:flex; flex-direction:column; justify-content:flex-end; }
.blk-page .-cap-panel.-capp-center .blk-card-title
										{ justify-content:center; }
.blk-card-more							{ display:block; font-size:0.78em; font-weight:400; opacity:0.85; margin-top:0.2em; }

/* grouped bottom bands (pinned container) keep the card rhythm */
.blk-page .blk-card .blk-container		{ display:flex; flex-direction:column; gap:0.5em; }
/* Bottom-pinning is NOT css magic: the Buy Button block owns an
   'Align To Card Bottom' option that emits margin-top:auto INLINE —
   identical in edit/preview/frontend by construction. Price styling
   keys on the ROLE class the renderer stamps on item-bound blocks
   (-bind-item-price), never on where the block sits — the sibling
   heuristic died the moment price moved into columns. */
.blk-page .blk-card .-bind-item-price	{ font-size:1em; font-weight:600; opacity:1; }
/* Page List carousel: cards become snap cells on the shared track — width
   from the SAME columns/colmin vars the grid uses, so both layouts read one
   set of settings. -car kills the grid display on the block itself. */
.blk-page .blk-folder-list.-car			{ display:block; }
.blk-carousel.-cards .blk-car-track		{ gap:var(--blk-gap,1rem);
	> .blk-card							{ flex:0 0 max(var(--blk-colmin,14rem), calc((100% - (var(--blk-cols,3) - 1) * var(--blk-gap,1rem)) / var(--blk-cols,3))); min-width:0; scroll-snap-align:start; margin-top:0; }
}

/* File downloads: list or grid of download links. */
.blk-page .blk-file-list				{
	&.-list								{ display:flex; flex-direction:column; gap:var(--blk-gap,0.5rem); }
	&.-grid								{ display:grid; gap:var(--blk-gap,1rem);
										  grid-template-columns:repeat(auto-fill, minmax(max(10rem, calc((100% - (var(--blk-cols,3) - 1) * var(--blk-gap,1rem)) / var(--blk-cols,3) - 0.5px)), 1fr)); }
	.blk-file-row						{ display:flex; align-items:center; gap:0.75em; padding:0.65em 0.85em; border:1px solid #e8e8e8; border-radius:6px; text-decoration:none; color:inherit; background:#fff;
		&:hover							{ background:#fafafa; border-color:#d0d0d0; }
	}
	.blk-file-icon						{ flex:0 0 auto; width:2.2em; height:2.2em; display:flex; align-items:center; justify-content:center;
		img								{ max-width:100%; max-height:100%; display:block; }
	}
	.blk-file-ext						{ display:inline-block; font-size:0.65em; font-weight:700; letter-spacing:0.04em; padding:0.25em 0.4em; border-radius:3px; background:#eee; color:#555; }
	.blk-file-body						{ flex:1 1 auto; min-width:0; display:flex; flex-direction:column; gap:0.15em; }
	.blk-file-title						{ font-weight:600; }
	.blk-file-desc						{ font-size:0.9em; opacity:0.8; }
	.blk-file-size						{ flex:0 0 auto; font-size:0.85em; opacity:0.7; white-space:nowrap; }
}
/* AV gallery: responsive columns of players. */
.blk-page .blk-av-list					{ display:grid; gap:var(--blk-gap,1rem);
										  grid-template-columns:repeat(auto-fill, minmax(max(12rem, calc((100% - (var(--blk-cols,2) - 1) * var(--blk-gap,1rem)) / var(--blk-cols,2) - 0.5px)), 1fr)); }
.blk-page .blk-av-item					{ display:flex; flex-direction:column; gap:0.45em; }
.blk-page .blk-av-player				{ position:relative; aspect-ratio:16/9; background:#111; border-radius:4px; overflow:hidden;
	iframe,video						{ display:block; width:100% !important; height:100%; border:0; max-width:none; object-fit:contain; }
	&.-audio							{ aspect-ratio:auto; background:transparent;
		audio							{ width:100%; }
	}
}
.blk-page .blk-av-ph					{ position:relative; aspect-ratio:16/9; background:#1a1a1a; border-radius:4px; overflow:hidden; display:flex; align-items:center; justify-content:center;
	img									{ position:absolute; inset:0; width:100%; height:100%; object-fit:cover; opacity:0.85; }
}
.blk-page .blk-av-title					{ font-weight:600; font-size:0.95em; }

/* Form block fills its container — constrain width by wrapping it in the
   layout, never a form-level max-width (operator 2026-08-18). */
.blk-page .blk-form-ref					{ width:100%; }
.blk-page .blk-form						{ display:flex; flex-direction:column; gap:var(--blk-gap,var(--blk-space-s,1rem)); width:100%; }
.blk-page .blk-form-fields				{ display:flex; flex-direction:column; gap:var(--blk-gap,var(--blk-space-s,1rem)); }
/* fields are .blk siblings — the page rhythm margin would STACK on the
   flex gap (spacing read as bigger than tempo, operator 2026-07-27) */
.blk-page .blk-form-fields > .blk		{ margin-top:0; }
.blk-page .blk-ffield,
.blk-page .blk-fcaptcha					{ display:flex; flex-direction:column; gap:0.35rem;
	.blk-ffield-label					{ font-weight:600; }
	.input-block						{ display:block; }
	input:not([type="radio"]):not([type="checkbox"]),
	select, textarea					{ width:100%; max-width:100%; box-sizing:border-box; }
	/* tenant contact-form CSS commonly grids/floats label rows — checks and
	   radios OWN their layout: tick then text, left, whatever the theme says
	   (operator screenshots 2026-07-27, twice — hence the heavy hand) */
	.blk-ffield-check,
	.blk-ffield-radio					{ display:flex !important; align-items:center; justify-content:flex-start !important; gap:0.5em; font-weight:400; text-align:left !important; width:100%; float:none !important;
		input							{ flex:0 0 auto; width:auto !important; margin:0 !important; float:none !important; position:static !important; }
		.blk-ffield-label, span			{ flex:0 1 auto; width:auto !important; text-align:left !important; float:none !important; position:static !important; margin:0 !important; }
	}
	.blk-ffield-radios					{ display:flex; flex-direction:column; gap:0.35em; }
}
.blk-page .blk-fcaptcha-img				{ margin:0.25em 0;
	img									{ display:block; max-width:100%; height:auto; }
}
/* Honeypot: off-screen, never display:none (some bots skip hidden fields —
   off-screen looks fillable to them, invisible to humans; tabindex -1
   keeps keyboards out) */
.blk-page .blk-hp						{ position:absolute !important; left:-9999px !important; top:auto; width:1px; height:1px; overflow:hidden; }
/* Postcode picker: input + Find share a row; the picked address echoes
   below in small print */
.blk-page .blk-ffield .blk-pcode		{ display:flex; gap:0.5em; align-items:stretch;
	input								{ flex:1 1 auto; min-width:0; }
	.blk-btn							{ flex:0 0 auto; }
}
.blk-page .blk-pcode-label				{ display:block; font-size:0.9em; opacity:0.8; padding:0.35em 0.2em; }
/* Unit suffix (the KG box): input + dark unit cell share one row */
.blk-page .blk-ffield .input-block.-unit	{ display:flex; align-items:stretch;
	input								{ flex:1 1 auto; min-width:0; border-top-right-radius:0; border-bottom-right-radius:0; }
	.blk-ffield-unit					{ flex:0 0 auto; display:flex; align-items:center; padding:0 0.9em; background:#2d2d2d; color:#fff; font-weight:700; font-size:0.85em; letter-spacing:0.04em; border-radius:0 6px 6px 0; }
}
/* Section title inside a form ('Your Details', 'Address' groupings) */
.blk-page .blk-ffield-title				{ margin:0.75em 0 0; font-size:0.82em; font-weight:700; letter-spacing:0.06em; text-transform:uppercase; opacity:0.8; }
/* Floating labels (form Labels = Floating): label starts inside the input
   and floats to a small line at the top edge on focus/content — the
   modern-form look, done with :has() so the label can stay before the
   input in source order. Only rows the template marked -float (text-ish
   + textarea); selects/checks/radios/titles keep above-labels. */
.blk-page .blk-form.-labels-float .blk-ffield.-float	{ position:relative;
	.blk-ffield-label					{ position:absolute; top:0.62em; left:0.8em; z-index:1; font-weight:400; opacity:0.55; pointer-events:none;
										  transition:top .15s ease, font-size .15s ease, opacity .15s ease; }
	input, textarea						{ padding-top:1.35em; }
	/* the label plays the placeholder's role at rest — a real placeholder
	   would double up under it; it appears once the label floats away */
	input::placeholder, textarea::placeholder			{ color:transparent; }
	&:has(input:focus) input::placeholder,
	&:has(textarea:focus) textarea::placeholder			{ color:inherit; opacity:0.4; }
	&:has(input:focus) .blk-ffield-label,
	&:has(textarea:focus) .blk-ffield-label,
	&:has(input:not(:placeholder-shown)) .blk-ffield-label,
	&:has(textarea:not(:placeholder-shown)) .blk-ffield-label
										{ top:0.25em; font-size:0.72em; opacity:0.75; }
}
.blk-page .blk-fsubmit					{ margin-top:0.25rem; }
.blk-page .blk-form-msg					{ padding:0.85em 1em; border-radius:6px; background:#eef7ee; color:#1a5c1a;
	&.-error							{ background:#fdecec; color:#8a1f1f; }
	&.-ok								{ background:#eef7ee; color:#1a5c1a; }
}

/* Directory blocks: baseline only — tenant CSS owns the legacy inner
   classes (directory-tel1, directory-email, directory-social). */
.blk-page .blk-dir-contact				{ line-height:1.6;
	.directory-contact					{ font-weight:600; }
	ul.directory-social					{ list-style:none; margin:0.5em 0 0; padding:0; display:flex; flex-wrap:wrap; gap:0.35em 1em; }
}
/* columns inside a card (price | buy footer pattern): compact by default.
   Literal 0.5em, not var(--blk-gap,…): the list's row gap cascades into
   the card, so the fallback would leak it. An EXPLICIT Gap/Vertical
   Alignment on the columns wins — ColumnsType emits both inline. */
.blk-page .blk-card .blk-columns		{ gap:0.5em; align-items:center; }

/*---------------- interactions (V1 2026-08-03) ----------------*/
/* Click actions: the carrier advertises itself; the action runs in
   blocks.js (delegated). Editor canvases never carry these attrs. */
[data-blk-act]							{ cursor:pointer; }

/* Reveal: .blk-rvl-pre (initial state) is JS-APPLIED, never static — a
   visitor whose JS fails sees every block. .blk-in plays the entrance
   (once, or per visit under data-blk-rvl-rpt). A block with an inline
   Offset transform keeps it (inline wins): reveal degrades to its opacity
   half there, by design. Strength (data-blk-amt) multiplies every motion
   distance through --blk-rvl-amt; the pure fades have no distance and
   ignore it. Flip caps shy of 90° — past edge-on it reads mirrored. */
.blk-rvl-pre							{ opacity:0; transition:opacity .6s ease-out, transform .6s ease-out; will-change:opacity, transform; }
.blk-rvl-pre[data-blk-amt=subtle]		{ --blk-rvl-amt:.55; }
.blk-rvl-pre[data-blk-amt=strong]		{ --blk-rvl-amt:1.7; }
.blk-rvl-pre[data-blk-rvl=fade_out]		{ opacity:1; }
.blk-rvl-pre[data-blk-rvl=fade_up]		{ transform:translateY(calc(28px * var(--blk-rvl-amt,1))); }
.blk-rvl-pre[data-blk-rvl=fade_down]	{ transform:translateY(calc(-28px * var(--blk-rvl-amt,1))); }
.blk-rvl-pre[data-blk-rvl=slide_up]		{ opacity:1; transform:translateY(calc(44px * var(--blk-rvl-amt,1))); }
.blk-rvl-pre[data-blk-rvl=slide_down]	{ opacity:1; transform:translateY(calc(-44px * var(--blk-rvl-amt,1))); }
.blk-rvl-pre[data-blk-rvl=slide_left]	{ opacity:1; transform:translateX(calc(44px * var(--blk-rvl-amt,1))); }
.blk-rvl-pre[data-blk-rvl=slide_right]	{ opacity:1; transform:translateX(calc(-44px * var(--blk-rvl-amt,1))); }
.blk-rvl-pre[data-blk-rvl=scale]		{ transform:scale(calc(1 - .14 * var(--blk-rvl-amt,1))); }
.blk-rvl-pre[data-blk-rvl=rotate]		{ transform:rotate(calc(-8deg * var(--blk-rvl-amt,1))) scale(calc(1 - .06 * var(--blk-rvl-amt,1))); }
.blk-rvl-pre[data-blk-rvl=flip]			{ transform:perspective(800px) rotateY(min(calc(85deg * var(--blk-rvl-amt,1)), 89deg)); }
.blk-rvl-pre[data-blk-rvl=bounce]		{ transform:scale(calc(1 - .3 * var(--blk-rvl-amt,1))); }
.blk-rvl-pre.blk-in						{ opacity:1; transform:none; }
.blk-rvl-pre.blk-in[data-blk-rvl=fade_out]	{ opacity:0; }
.blk-rvl-pre.blk-in[data-blk-rvl=bounce]	{ transition:none; animation:blk-rvl-bounce .65s cubic-bezier(.34,1.56,.64,1) both; }
@keyframes blk-rvl-bounce				{ 0% { opacity:0; transform:scale(calc(1 - .3 * var(--blk-rvl-amt,1))); } 60% { opacity:1; transform:scale(calc(1 + .06 * var(--blk-rvl-amt,1))); } 80% { transform:scale(.98); } 100% { opacity:1; transform:scale(1); } }
/* V2 pacing tokens (Delay / Speed on the On Reveal row). Stagger's
   per-child delays are inline from blocks.js and win over these. */
.blk-rvl-pre[data-blk-rvl-delay=short]	{ transition-delay:.15s; animation-delay:.15s; }
.blk-rvl-pre[data-blk-rvl-delay=medium]	{ transition-delay:.4s; animation-delay:.4s; }
.blk-rvl-pre[data-blk-rvl-delay=long]	{ transition-delay:.8s; animation-delay:.8s; }
.blk-rvl-pre[data-blk-rvl-dur=fast]		{ transition-duration:.35s; animation-duration:.4s; }
.blk-rvl-pre[data-blk-rvl-dur=slow]		{ transition-duration:1.1s; animation-duration:1s; }

/* Ambient (V2): a quiet infinite loop while the block is idle. Waits
   for the block's entrance (a not-yet-revealed block must keep its
   offset pre state — animation would override the transform), then
   floats or breathes through the strength multiplier. */
[data-blk-amb-amt=subtle]				{ --blk-amb-amt:.55; }
[data-blk-amb-amt=strong]				{ --blk-amb-amt:1.7; }
[data-blk-amb=float]:not(.blk-rvl-pre),
.blk-rvl-pre.blk-in[data-blk-amb=float]	{ animation:blk-amb-float 4.5s ease-in-out 1s infinite; }
[data-blk-amb=pulse]:not(.blk-rvl-pre),
.blk-rvl-pre.blk-in[data-blk-amb=pulse]	{ animation:blk-amb-pulse 3.6s ease-in-out 1s infinite; }
@keyframes blk-amb-float				{ 0%, 100% { transform:translateY(0); } 50% { transform:translateY(calc(-7px * var(--blk-amb-amt,1))); } }
@keyframes blk-amb-pulse				{ 0%, 100% { transform:scale(1); } 50% { transform:scale(calc(1 + .035 * var(--blk-amb-amt,1))); } }

/* Hover: a reversible nudge, pure CSS. Strength (data-blk-hov-amt)
   multiplies through --blk-hov-amt; flip stays a full turn — a partial
   flip holds edge-on and reads broken, so strength doesn't apply. */
[data-blk-hov]							{ transition:opacity .25s ease, transform .25s ease; }
[data-blk-hov-amt=subtle]				{ --blk-hov-amt:.55; }
[data-blk-hov-amt=strong]				{ --blk-hov-amt:1.7; }
[data-blk-hov=fade]:hover				{ opacity:calc(1 - .35 * var(--blk-hov-amt,1)); }
[data-blk-hov=up]:hover					{ transform:translateY(calc(-6px * var(--blk-hov-amt,1))); }
[data-blk-hov=down]:hover				{ transform:translateY(calc(6px * var(--blk-hov-amt,1))); }
[data-blk-hov=left]:hover				{ transform:translateX(calc(-6px * var(--blk-hov-amt,1))); }
[data-blk-hov=right]:hover				{ transform:translateX(calc(6px * var(--blk-hov-amt,1))); }
[data-blk-hov=scale]:hover				{ transform:scale(calc(1 + .05 * var(--blk-hov-amt,1))); }
[data-blk-hov=rotate]:hover				{ transform:rotate(calc(3deg * var(--blk-hov-amt,1))); }
[data-blk-hov=flip]:hover				{ transform:perspective(800px) rotateY(180deg); }
[data-blk-hov=bounce]:hover				{ animation:blk-hov-bounce .5s ease; }
@keyframes blk-hov-bounce				{ 0%, 100% { transform:none; } 30% { transform:translateY(calc(-8px * var(--blk-hov-amt,1))); } 55% { transform:translateY(2px); } 75% { transform:translateY(calc(-4px * var(--blk-hov-amt,1))); } }

/* Group hover (V2, Applies To = Images Inside): the card pattern —
   hover the block, the effect plays on the images within; the block
   itself stays still (the reset outranks the self rules by attribute
   count). Images crop at their figure so a zoom stays inside the
   card. Scale zooms IN for images — the classic card treatment.
   Bounce/flip are self-only effects and do nothing in this mode. */
[data-blk-hov][data-blk-hov-t=img]:hover		{ transform:none; opacity:1; animation:none; }
[data-blk-hov-t=img] .blk-image					{ overflow:hidden; }
[data-blk-hov-t=img] img						{ transition:opacity .25s ease, transform .25s ease; }
[data-blk-hov=fade][data-blk-hov-t=img]:hover img	{ opacity:calc(1 - .35 * var(--blk-hov-amt,1)); }
[data-blk-hov=up][data-blk-hov-t=img]:hover img		{ transform:translateY(calc(-6px * var(--blk-hov-amt,1))); }
[data-blk-hov=down][data-blk-hov-t=img]:hover img	{ transform:translateY(calc(6px * var(--blk-hov-amt,1))); }
[data-blk-hov=left][data-blk-hov-t=img]:hover img	{ transform:translateX(calc(-6px * var(--blk-hov-amt,1))); }
[data-blk-hov=right][data-blk-hov-t=img]:hover img	{ transform:translateX(calc(6px * var(--blk-hov-amt,1))); }
[data-blk-hov=scale][data-blk-hov-t=img]:hover img	{ transform:scale(calc(1 + .07 * var(--blk-hov-amt,1))); }
[data-blk-hov=rotate][data-blk-hov-t=img]:hover img	{ transform:rotate(calc(2deg * var(--blk-hov-amt,1))) scale(1.03); }

@media (prefers-reduced-motion: reduce) {
	[data-blk-hov], .blk-rvl-pre, [data-blk-amb], [data-blk-hov-t=img] img
										{ transition:none; animation:none; }
	[data-blk-hov]:hover, [data-blk-hov-t=img]:hover img
										{ transform:none; opacity:1; }
}

/* breadcrumb: the legacy .path class carries default.css's 12px bottom
   margin — inside a block the rhythm system owns spacing (default.css
   itself stays untouched: unflagged sites' legacy widget still needs it) */
.blk-page .blk-breadcrumb .path			{ margin:0; }
/* Embed block: full-width iframe panel; the editor tile is inert */
.blk-page .blk-embed iframe				{ display:block; width:100%; border:0; }
/* Widget links follow the SURROUNDING text, not the site link token:
   a widget's injected content is foreign — the page's link colour is
   tuned to the page's own surfaces, never to whatever band the widget
   lands in (North Finchley's verse reference: periwinkle on gold ≈
   2.9:1, failing AA; inherited #444 ≈ 6.3:1). A provider stylesheet
   that sets its own colour still wins. */
.blk-page .blk-widget a					{ color:inherit; }
.blk-embed-ph							{ display:flex; flex-direction:column; align-items:center; justify-content:center; gap:6px; background:#eef1f5; border:1px dashed #c3cad4; border-radius:6px; color:#5f6b7a;
	svg									{ width:34px; height:34px; }
}
.blk-embed-host							{ font-weight:600; font-size:14px; }
.blk-embed-note							{ font-size:12px; color:#8a94a3; }

/* A block that SETS its text colour carries its links with it — a navy
   band's links read in the band colour, never the theme link purple.
   The attribute match is exact: ';color:' / leading 'color:' cannot match
   'background-color:'. Blocks without an explicit colour keep theme links.
   BUTTONS are excluded: .blk-btn carries its own bg/text PAIR from the theme
   tokens, and this rule ties (0,3,1) with .blk-btn.-light but lands later in
   the file — so without the :not() a Light button in a coloured band inherited
   the band's colour and went white-on-white (Wylam hero, 2026-08-28). */
.blk-page .blk[style^="color:"] a:not(.blk-btn):not(.thm-btn),
.blk-page .blk[style*=";color:"] a:not(.blk-btn):not(.thm-btn)
										{ color:inherit; }

/* Site Component (frontend): furniture obeys the BLOCK colour context —
   links inherit the block's text colour instead of the theme link colour,
   so a utility-bar cluster on a dark band reads in the band's colour with
   no tenant CSS. Scoped to the component block only: links in ordinary
   text blocks keep the theme link colour. */
.blk-page .blk-component a,
.blk-page .blk-component a:visited		{ color:inherit; }
/* Block-friendly furniture dress (the stop-gap variant the operator
   accepted while component theming is designed): inside a component block
   the legacy header widgets lose their hardcoded chrome — no bordered box,
   text from the block context, the empty-trolley grey becomes a fade of
   the context colour. Id-qualified because the legacy module selectors
   carry ids. */
.blk-page .blk-component #pane-trolley	{ border:none; }
.blk-page .blk-component #pane-trolley li,
.blk-page .blk-component #user-pane li	{ color:inherit; }
.blk-page .blk-component .trolley-empty #pane-trolley li
										{ color:inherit; opacity:0.6; }
.blk-page .blk-component #search input[type="text"]
										{ width:min(330px, 86cqw); padding:10px 12px; border:1px solid #d9d9d9; background:#fff; font-size:1em; box-sizing:border-box; }
/* Search (Icon): the compact form factor both church conversions
   wanted — a currentColor magnifier <label>; clicking it focuses the
   input (native label behaviour, zero JS) and :focus-within expands
   the field; blur collapses it. Enter submits as the open box does. */
.blk-page .blk-component #search-toggle	{ display:flex; align-items:center; }
.blk-page .blk-component #search-toggle label
										{ display:inline-flex; cursor:pointer; padding:0.3em; color:inherit; }
.blk-page .blk-component #search-toggle svg
										{ width:1.35em; height:1.35em; }
.blk-page .blk-component #search-toggle .visually-hidden
										{ position:absolute; width:1px; height:1px; overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; }
.blk-page .blk-component #search-toggle input[type="text"]
										{ width:0; padding:10px 0; margin:0; opacity:0; border:1px solid transparent; background:#fff; font-size:1em; box-sizing:border-box; transition:width 0.25s ease, opacity 0.2s ease, padding 0.25s ease; }
.blk-page .blk-component #search-toggle:focus-within input[type="text"]
										{ width:min(240px, 60cqw); padding:10px 12px; opacity:1; border-color:#d9d9d9; color:#1f2329; }
@media (prefers-reduced-motion:reduce) {
	.blk-page .blk-component #search-toggle input[type="text"]	{ transition:none; }
}
/* outer spacing is the BLOCK's job (gap/padding props) — trim the
   furniture's own stray outer margins so component gaps read evenly */
.blk-page .blk-component > :first-child	{ margin-top:0; }
.blk-page .blk-component > :last-child	{ margin-bottom:0; }
/* Mobile Menu Button: bare glyph, the block box IS the button — hug the
   icon on BOTH axes so Background / rounding / padding read as its
   chrome (full rounding = a circle). align-self beats the grid/flex
   default stretch, which pulled the button row-tall into a lozenge
   beside a taller cell (operator screenshot 2026-08-19). */
.blk-page .blk-component:has(> #menu-icon-wrapper)	{ width:fit-content; height:fit-content; align-self:center; }
.blk-page .blk-component #menu-icon		{ display:flex; cursor:pointer; }
.blk-page .blk-component .hamb-icon-svg	{ display:block; }
.blk-page .blk-component ul				{ margin:0; padding-left:0; }

/* Social Links block: discs in currentColor, glyphs knocked out (the
   band colour shows through) — colour rides the block's Text Colour */
.blk-social ul							{ display:flex; flex-wrap:wrap; gap:12px; margin:0; padding:0; list-style:none; }
.blk-social li							{ line-height:0; }
.blk-social a							{ display:block; color:inherit; }
.blk-social svg							{ width:var(--blk-social-size, 36px); height:var(--blk-social-size, 36px); fill:currentColor; }
.blk-social-ph							{ padding:8px 12px; border:1px dashed #c3cad4; border-radius:6px; color:#8a94a3; font-size:13px; }

/* per-media tile scale (logo normalising): the figure carries
   --blk-img-scale ('NN%'); the modern `scale` property takes the
   percentage directly. Attribute-scoped — no identity transform on
   every image. Bound tiles and static Media children both emit it. */
.blk-page .blk-image[style*="--blk-img-scale"] > img,
.blk-page .blk-image[style*="--blk-img-scale"] > .blk-arc > img	{ scale: var(--blk-img-scale); transform-origin:center; }
