/* ═══════════════════════════════════════════════════════════════════════════
   SITE CONTAINER
   ═══════════════════════════════════════════════════════════════════════════ */

:root {
	--ci-container-width:   1280px;
	--ci-container-padding: 2rem;
}

*,
*::before,
*::after {
	box-sizing: border-box;
}

html {
	margin: 0;
	padding: 0;
	/* hidden (not clip) — clip has known inconsistencies with touch-swipe
	   scrolling on iOS Safari, letting a stray overflowing element cause
	   real horizontal scroll even though it's visually clipped elsewhere. */
	overflow-x: hidden;

	/* Keep the scrollbar's space reserved even when there is no scrollbar.

	   Opening a modal locks the page with overflow: hidden, which takes the
	   scrollbar away — and on Chrome that hands ~15px back to the viewport.
	   Everything anchored to the right edge jumps: the header is position:
	   fixed, so it is sized by the viewport rather than by <body>, and the
	   burger and nav bar slid 15px right the instant a video opened.

	   Reserving the gutter permanently means the width never changes, so
	   there is nothing to compensate for. ce-scroll-lock still measures and
	   pads as a fallback for browsers without this property — where the
	   gutter is stable it measures zero and does nothing. */
	scrollbar-gutter: stable;
}


/* ── While a modal is open: stop blurring the page behind it ─────────────────
   backdrop-filter is the most expensive thing on these pages. Each element
   carrying one gets its own compositing layer and makes the browser re-sample
   and blur whatever is behind it, every time that region is repainted. The
   Maestro page has 18 of them.

   The cost that matters is NESTING: the modal's own backdrop carries
   blur(8px), so every frame of its fade makes the browser re-sample the
   page underneath — and eighteen of the things it is sampling are themselves
   live blurs. That is the case worth avoiding, and it is a desktop one.

   Hence the min-width. Below it the modal's backdrop has no blur at all
   (maestro.css drops it on phones and darkens the dim to compensate), so
   there is nothing re-sampling the page and the eighteen layers just sit
   there, already rasterised, under an opaque sheet. Turning them off there
   would buy nothing and cost something real: switching backdrop-filter off
   forces all eighteen to re-raster in a single frame, and on a phone that
   repaint is the very flash the staged entrance exists to avoid.

   None of the work is visible either way: the modal's backdrop covers the
   page at 82% black on a desktop and 94% on a phone, so the cards underneath
   are a rumour.

   Scoped to .wp-site-blocks, which is the page content. Every modal on this
   site is a direct child of <body>, outside it — so the modal's own backdrop
   blur, the one you can actually see, is untouched. */
@media (min-width: 768px) {
	html.ce-modal-open .wp-site-blocks *,
	html.ce-modal-open .wp-site-blocks {
		backdrop-filter: none !important;
		-webkit-backdrop-filter: none !important;
	}
}

/* And stop a finger dragging the page behind the modal.

   overflow: hidden holds the document, but iOS Safari will still let a touch
   drag the background under an overlay. The old fix for that was switching
   <body> to position: fixed, which is exactly what made the page jump: it
   makes the document unscrollable, Safari resizes its own chrome to suit, and
   everything shifts — on open and again on close.

   touch-action does the same job with no layout consequence at all: the
   browser simply refuses to treat a touch here as a scroll. Scoped to the
   page content, so the modal — a sibling of .wp-site-blocks, not a child —
   keeps normal touch behaviour and can still be scrolled and pinched. */
html.ce-modal-open .wp-site-blocks {
	touch-action: none;
}

/* Deliberately NOT also setting overflow-x on body. Per spec, whenever
   overflow-x and overflow-y differ, the "visible" side is silently forced
   to compute as auto — there's no way to keep it truly visible. Setting
   overflow-x:hidden on BOTH html and body used to give each of them their
   own independent auto-computed overflow-y, turning both into separate
   scroll containers. Real page scroll happens on html, but position:sticky
   descendants of body resolved their containing block to body — which
   never itself scrolls — so sticky elements anywhere on the site just
   scrolled away like static content instead of sticking. html alone is
   enough to clip horizontal overflow; body doesn't need to repeat it. */
body {
	margin: 0;
	padding: 0;
}

img,
video,
iframe {
	max-width: 100%;
}

.site-container {
	max-width: var(--ci-container-width);
	margin-left: auto;
	margin-right: auto;
	padding-left: var(--ci-container-padding);
	padding-right: var(--ci-container-padding);
}

/* ── White section divider ── */
.section-divider {
	background-color: #ffffff;
	height: 0.3rem;
}

/* ── Editor-entered content must not be able to push the page sideways ───────
   Everything else on this site is laid out by the theme, so its widths are
   known. Post bodies are not: they are whatever an editor pastes in, and two
   published posts were already wide enough at 390px to give the whole page a
   horizontal scroll.

   Both were unbreakable runs of text rather than anything oversized:

     a bare URL — https://globalschoolsforum.org/sites/... — one 414px token
     with no space in it, in a 311px column;

     a sentence pasted from a word processor, which arrived with every space
     as &nbsp;. "with&nbsp;a&nbsp;sequenced&nbsp;skills&nbsp;and&nbsp;knowledge&nbsp;framework."
     is a single 50-character word as far as line breaking is concerned,
     because a non-breaking space is precisely a refusal to break there.

   break-word, not anywhere: this only breaks a word that cannot fit on a line
   of its own, so ordinary prose wraps between words exactly as before and only
   the token that would otherwise overflow is broken.

   A guard, not a cure — an editor can still paste a URL that breaks mid-word
   unattractively, and the &nbsp; runs are worth cleaning out of the posts
   themselves. But no future paste can silently break the page layout. */
.entry-content,
.wp-block-post-content {
	overflow-wrap: break-word;
}

/* ── Off-screen honeypot ─────────────────────────────────────────────────────
   The decoy field from inc/form-guard.php, which both the enquiry form and the
   lead-magnet popup print. It lives here rather than in either component's
   stylesheet because the two load on different pages — in a component file it
   would be missing wherever the other form appeared, and an unstyled honeypot
   is a visible text input asking to be left empty.

   Off-screen rather than display:none: some automated fillers skip anything
   not rendered, and the point is that a script finds it while a person does
   not. It is already out of the tab order and the accessibility tree. */
.ce-form-guard {
	position: absolute;
	left: -9999px;
	width: 1px;
	height: 1px;
	overflow: hidden;
}

/* ── Cloudflare Turnstile ──────────────────────────────────────────────────
   The widget is invisible for most visitors, so it usually occupies no space
   at all — but when Cloudflare decides to show an interactive challenge it
   needs somewhere to appear without shoving the submit button off the modal.
   Given room in the flow rather than positioned, so it simply collapses when
   there is nothing to draw. */
.ce-turnstile,
.ca-turnstile {
	margin: 0.25rem 0 0;
	min-height: 0;
}

.ce-turnstile:not(:empty),
.ca-turnstile:not(:empty) {
	margin: 0.75rem 0 0;
}
