/**
 * The three Bootstrap behaviours published content still depends on.
 *
 * WHY IT IS HERE. Editors have been writing Bootstrap 4 markup into rich-text
 * fields for years, and the previous theme shipped Bootstrap site-wide, so
 * nothing ever declared the dependency. This theme ships no Bootstrap - and the
 * markup does not fail loudly when the CSS goes away, it fails INVERTED:
 * `.collapse` renders EXPANDED, `.modal` renders INLINE in the page body, and
 * every `.tab-pane` renders stacked. Content written to be hidden becomes
 * visible, which is the one failure mode a diff of the templates cannot show.
 *
 * MEASURED on staging 2026-09-05 by probes/bootstrap-orphans.py: twelve
 * published objects carry this markup and no longer get Bootstrap - ten
 * cause-funds entries (each one `.collapse`, the "Previous Grants" table, which
 * the fund artboard draws as a single 12px link and the page was rendering as
 * 33 visible rows, 1676px tall), one blog post from 2016 with four full modal
 * dialogs, and one supporters story with two tab panes. The event pages are NOT
 * in that set: they carry a legacy Elementor widget, so inc/legacy.php enqueues
 * the previous bundle for them and real Bootstrap is present - which is exactly
 * why this file must not load there as well.
 *
 * WHAT IT IS NOT. Not a Bootstrap port and not a step toward one. It is the
 * smallest set of rules that makes the markup already stored in the database
 * behave the way its author saw it behave, and it is scoped to those class
 * names alone. When the last object stops using them this file goes, the same
 * way inc/legacy.php goes.
 *
 * The geometry is Bootstrap 4's, because these pages were written against it.
 * Only the palette moved onto the theme's tokens.
 */

/* ------------------------------------------------------------------ collapse
 *
 * `:not(.show)` rather than a plain `.collapse { display: none }`: three of the
 * stored blocks ship `class="collapse show"` and are meant to render open.
 */
.collapse:not(.show) {
	display: none;
}

/*
 * The in-between state the script sets while a panel animates. Height is
 * animated rather than max-height so a long table does not run its transition
 * against a guessed ceiling and land early.
 */
.collapsing {
	position: relative;
	height: 0;
	overflow: hidden;
	transition: height 0.35s ease;
}

@media (prefers-reduced-motion: reduce) {
	.collapsing {
		transition: none;
	}
}

/* --------------------------------------------------------------------- tabs */

.tab-content > .tab-pane {
	display: none;
}

.tab-content > .tab-pane.active {
	display: block;
}

/* -------------------------------------------------------------------- modals
 *
 * `display: none` carries no `!important`, deliberately. Bootstrap's own JS
 * opens a dialog by writing `style="display: block"` on the element, so on a
 * page where the real bundle is also present the inline style still wins and
 * this rule cannot fight it. That is the safety net behind the PHP-side gate,
 * not a substitute for it.
 */
.modal {
	position: fixed;
	top: 0;
	left: 0;
	z-index: 1050;
	display: none;
	width: 100%;
	height: 100%;
	overflow-x: hidden;
	overflow-y: auto;
	outline: 0;
}

.modal.show {
	display: block;
}

.modal-backdrop {
	position: fixed;
	top: 0;
	left: 0;
	z-index: 1040;
	width: 100vw;
	height: 100vh;
	background-color: var(--b26-ink);
	opacity: 0.5;
}

/* The scroll lock. Bootstrap also compensated for the scrollbar width; that
   compensation is skipped here because it needs a measurement at open time and
   its absence shifts the page by the scrollbar width for the moment a dialog is
   open, which is a smaller defect than the arithmetic being wrong. */
body.modal-open {
	overflow: hidden;
}

.modal-dialog {
	position: relative;
	width: auto;
	max-width: 500px;
	margin: 1.75rem auto;
	pointer-events: none;
}

/* VERTICAL CENTRING, on 39 published objects and on no rule until now.
 *
 * The previous theme shipped Bootstrap 4.6, whose compiled app.min.css carries
 * `.modal-dialog-centered` - verified by reading that file, not from memory.
 * This theme ships no Bootstrap, so those 39 dialogs have been opening pinned
 * to the top of the viewport instead of centred in it.
 *
 * THE VALUE IS 3.5rem AT EVERY WIDTH, WHICH IS NOT WHAT BOOTSTRAP WROTE, and
 * the difference is deliberate. Bootstrap's rule is `calc(100% - 1rem)` with a
 * `calc(100% - 3.5rem)` override from 576px up, because ITS `.modal-dialog`
 * carries `margin: .5rem` below that breakpoint and `1.75rem auto` above it -
 * the subtrahend is always twice the vertical margin. The `.modal-dialog` rule
 * above uses `1.75rem auto` at ALL widths, so copying Bootstrap's mobile value
 * here would subtract 1rem where 3.5rem of margin exists and overflow the
 * dialog by 2.5rem on a phone. One value, matching this theme's own box.
 *
 * The `::before` is Bootstrap's own workaround for engines that ignore a
 * percentage min-height inside a flex container; it is kept because dropping it
 * would be a silent behaviour change on exactly the browsers it was added for.
 * Its `-moz-min-content` twin IS dropped: unprefixed `min-content` has worked in
 * Firefox since 66, and the prefix only ever served versions older than that.
 * `modal-dialog-scrollable`, `modal-lg` and `modal-sm` are NOT reproduced -
 * measured across published content, all three are used by zero objects, and a
 * rule nothing selects is dead weight in a file that loads on 60 views. */
.modal-dialog-centered {
	display: flex;
	align-items: center;
	min-height: calc(100% - 3.5rem);
}

.modal-dialog-centered::before {
	display: block;
	height: calc(100vh - 3.5rem);
	height: min-content;
	content: "";
}

.modal-content {
	position: relative;
	display: flex;
	flex-direction: column;
	width: 100%;
	pointer-events: auto;
	background-color: var(--b26-white, #fbfbfb);
	background-clip: padding-box;
	border: 1px solid var(--b26-rule, rgba(54, 44, 44, 0.15));
	border-radius: var(--b26-radius-md, 10px);
	outline: 0;
}

.modal-header {
	display: flex;
	align-items: flex-start;
	justify-content: space-between;
	padding: 1rem;
	border-bottom: 1px solid var(--b26-rule, rgba(54, 44, 44, 0.15));
}

.modal-title {
	margin: 0;
	line-height: 1.5;
}

.modal-body {
	position: relative;
	flex: 1 1 auto;
	padding: 1rem;
}

.modal-footer {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: flex-end;
	gap: 0.5rem;
	padding: 0.75rem;
	border-top: 1px solid var(--b26-rule, rgba(54, 44, 44, 0.15));
}

/* The dismiss control. Bootstrap's `.close` is a bare <button>, so it needs its
   own reset - the theme's button styles do not reach it. */
.modal .close {
	padding: 0;
	background: transparent;
	border: 0;
	font-size: 1.5rem;
	font-weight: 700;
	line-height: 1;
	color: var(--b26-ink, #362c2c);
	opacity: 0.5;
	cursor: pointer;
}

.modal .close:hover,
.modal .close:focus {
	opacity: 1;
}

/* --------------------------------------------------------------------- fade
 *
 * Scoped to the two components that use it here. `.fade` is a generic enough
 * name that a bare rule would reach markup this file knows nothing about.
 */
.modal.fade:not(.show),
.tab-pane.fade:not(.active) {
	opacity: 0;
}

.modal.fade,
.tab-pane.fade {
	transition: opacity 0.15s linear;
}

@media (prefers-reduced-motion: reduce) {
	.modal.fade,
	.tab-pane.fade {
		transition: none;
	}
}

/* ----------------------------------------------------------------- carousels
 *
 * THE DEFECT. `.carousel-item` is `display: none` in Bootstrap and only the
 * slide carrying `.active` is shown. This theme defines neither, so every
 * slide renders at once, stacked down the page. Measured 2026-09-06 on
 * /2021-annual-report/ and /2022-annual-report/: the served body markup is
 * byte-identical on production and staging - 2 `carousel-item` divs, exactly 1
 * carrying `active` - and only the CSS differs.
 *
 * WHAT IS PORTED. All of it now - the hiding half and the sliding half both,
 * transcribed from themes/tlycs/assets/vendor/bootstrap/scss/_carousel.scss
 * :14-52 rather than from memory.
 *
 * THIS COMMENT USED TO SAY THE TRANSITIONS WERE DELIBERATELY LEFT OUT, on the
 * ground that nothing drove them. That was true when it was written and stopped
 * being true in the same change that added the engine to bootstrap-bridge.js -
 * Sandro, 2026-09-06: give it the functionality the original pages have. The
 * rules below are therefore load-bearing, not decorative: without them the
 * engine swaps `.active` instantly and the slide jumps.
 *
 * `transform .6s ease-in-out` is Bootstrap 4.6.1's own `$carousel-transition`
 * default, and 600 ms is the number bootstrap-bridge.js waits before it stops
 * expecting `transitionend`. Change one and the other has to move with it.
 *
 * `.active` is spelled `.carousel-item.active` rather than bare `.active`,
 * which is a class ordinary content uses for its own purposes.
 */
.carousel {
	position: relative;
}

.carousel-inner {
	position: relative;
	width: 100%;
	overflow: hidden;
}

.carousel-inner::after {
	display: block;
	clear: both;
	content: "";
}

.carousel-item {
	position: relative;
	display: none;
	float: left;
	width: 100%;
	margin-right: -100%;
	backface-visibility: hidden;
	transition: transform 0.6s ease-in-out;
}

/*
 * A visitor who asks for less motion still gets the slide change, just without
 * the travel. The engine does not depend on `transitionend` firing - it carries
 * its own timer - so a zero-duration transition here is safe rather than a
 * carousel that stops halfway.
 */
@media (prefers-reduced-motion: reduce) {
	.carousel-item {
		transition: none;
	}
}

/*
 * The incoming and outgoing slides are both on screen while one is travelling,
 * which is why `display` cannot be `.active` alone.
 */
.carousel-item.active,
.carousel-item.carousel-item-next,
.carousel-item.carousel-item-prev {
	display: block;
}

.carousel-item.carousel-item-next:not(.carousel-item-left),
.carousel-item.active.carousel-item-right {
	transform: translateX(100%);
}

.carousel-item.carousel-item-prev:not(.carousel-item-right),
.carousel-item.active.carousel-item-left {
	transform: translateX(-100%);
}
