/* =========================================================================
   Alt Creative — engine layer
   =========================================================================

   BRAND-NEUTRAL BY DESIGN. Nothing here may reference a colour, typeface, or
   any Alt Creative visual decision.

   The parent is the engine; the child is the identity. If you are reaching
   for this file to change how something *looks*, you are in the wrong file —
   go to the active child theme's assets/css/brand.css.

   Only two kinds of rule belong here:
     1. Universal correctness that every site wants regardless of brand.
     2. Accessibility scaffolding.

   Deliberately absent: fonts, colours, button shape, card treatment, section
   backgrounds. All of that is identity and lives in the child.
   ====================================================================== */

/* -------------------------------------------------------------------------
   Text handling

   Never break a word without a proper hyphen. Random mid-word breaks look
   broken regardless of what brand is on top.
   ---------------------------------------------------------------------- */

body {
	hyphens: auto;
	-webkit-hyphens: auto;
	word-break: normal;
	overflow-wrap: break-word;
}

/* Headings and UI labels must NOT hyphenate. Body copy can break a long word
   with a soft hyphen (above); large display type cannot — a mid-word break
   like "inter-section" reads as broken, especially in a serif. Wrap whole
   words instead, and let long words overflow-wrap only as a last resort. */
h1, h2, h3, h4, h5, h6,
.h1, .h2, .h3, .h4, .h5, .h6,
.display-1, .display-2, .display-3, .display-4, .display-5, .display-6,
.btn, .navbar-brand, .nav-link {
	hyphens: manual;
	-webkit-hyphens: manual;
	overflow-wrap: break-word;
}

/* -------------------------------------------------------------------------
   Accessibility

   Colours here intentionally use currentColor / system defaults so the child
   can restyle them without fighting a hardcoded value.
   ---------------------------------------------------------------------- */

.skip-link {
	position: absolute;
	left: -9999px;
	top: 0;
	z-index: 999;
	padding: 0.75rem 1.25rem;
}

.skip-link:focus {
	left: 0;
}

:focus-visible {
	outline: 3px solid currentColor;
	outline-offset: 2px;
}

/* Respect the user's motion preference. Universal, not a brand call. */
@media (prefers-reduced-motion: reduce) {
	*,
	*::before,
	*::after {
		animation-duration: 0.01ms !important;
		animation-iteration-count: 1 !important;
		transition-duration: 0.01ms !important;
		scroll-behavior: auto !important;
	}
}

/* -------------------------------------------------------------------------
   Media

   Stops oversized uploads from blowing out layouts. Not a brand decision.
   ---------------------------------------------------------------------- */

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

/* -------------------------------------------------------------------------
   Media slots

   Constrains an image to a fixed aspect regardless of what was uploaded, and
   crops rather than distorts. A client sends a portrait phone photo for a slot
   designed around a landscape image and the layout survives.

   Mechanic, not identity — every brand wants this, so it lives in the engine.

   Note `height: auto` above would fight `aspect-ratio`, hence the override.
   ---------------------------------------------------------------------- */

.alt-media {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
	object-position: center;
}

.alt-media-1x1  { aspect-ratio: 1 / 1;  }
.alt-media-4x3  { aspect-ratio: 4 / 3;  }
.alt-media-3x2  { aspect-ratio: 3 / 2;  }
.alt-media-16x9 { aspect-ratio: 16 / 9; }
.alt-media-21x9 { aspect-ratio: 21 / 9; }   /* full-bleed bands */
.alt-media-3x4  { aspect-ratio: 3 / 4;  }   /* portrait slots */

/* -------------------------------------------------------------------------
   Eyebrow / label primitive

   A small kicker above a heading ("AS SEEN IN", "ABOUT"). The section library
   uses .alt-eyebrow widely, so it needs a sane neutral default — otherwise a
   barely-branded child renders it as ordinary body text and the sections look
   unfinished. This is structural, like .alt-media: colour and typeface stay
   neutral (currentColor, inherited font), and a brand restyles it in brand.css
   exactly the way it restyles the section backgrounds. It is part of the
   library's vocabulary, alongside .alt-section-light / -white / -dark.
   ---------------------------------------------------------------------- */

.alt-eyebrow,
.alt-label,
.overline {
	display: inline-block;
	font-size: 0.8em;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	opacity: 0.75;
}

/* -------------------------------------------------------------------------
   Hero with a background image

   The obvious way to do this is `background-image` in CSS. Don't. Three
   reasons, all of which have teeth:

     1. A CSS background cannot carry a `srcset`, so every visitor downloads
        the full-size file — on the one image where that costs the most.
     2. It is invisible to lcimg.py, which manages real <img> elements.
     3. It is the LCP element, and a CSS background cannot take
        fetchpriority="high".

   So the image is a real <img> pinned behind the content, and this is the
   plumbing that puts it there. Mechanic, not identity — every brand wants a
   hero that can hold a photo.

   .alt-hero-scrim is a readability wash. Text on an arbitrary photo has no
   guaranteed contrast ratio, and a scrim is the only fix that survives the
   client swapping the image later. The neutral default here is a plain dark
   wash; a brand recolours it in brand.css, exactly like .alt-eyebrow.
   ---------------------------------------------------------------------- */

.alt-hero {
	position: relative;
	overflow: hidden;
	display: flex;
	align-items: center;
}

.alt-hero-media {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	object-fit: cover;
	object-position: center;
	z-index: 0;
}

.alt-hero-scrim {
	position: absolute;
	inset: 0;
	z-index: 1;
	background: rgba(0, 0, 0, 0.45);
}

.alt-hero-body {
	position: relative;
	z-index: 2;
	width: 100%;
}

/* Height variants. A hero needs a floor, or a short headline collapses it. */
.alt-hero-sm { min-height: 40vh; }
.alt-hero-md { min-height: 60vh; }
.alt-hero-lg { min-height: 80vh; }
.alt-hero-xl { min-height: 100vh; }

/* -------------------------------------------------------------------------
   Hero inside a carousel — control stacking

   .alt-hero-body is z-index 2 so it clears the background image (0) and the
   scrim (1). Bootstrap's carousel controls are z-index 1, and .alt-hero-body
   is full-width, so it covers them completely: the arrows render, hover, and
   do nothing at all because the click never reaches them.

   Nothing errors and the carousel still auto-advances, so this looks like a
   working slider until someone actually tries an arrow.

   Verified with document.elementFromPoint() at the arrow's centre, which
   returned .alt-hero-body rather than the button.
   ---------------------------------------------------------------------- */

.carousel .carousel-control-prev,
.carousel .carousel-control-next,
.carousel .carousel-indicators {
	z-index: 3;
}

/* -------------------------------------------------------------------------
   Spacer

   WP Bakery pages are full of [vc_empty_space] — an empty 32px block used to
   set vertical rhythm inside a section. There is no visible content, so a
   content-driven rebuild drops every one of them without noticing, and each
   section comes out 32-128px shorter. The error accumulates down the page:
   ours ran 226px short overall, which puts everything below the fold in the
   wrong place even when every section is individually correct.

   Reproduce them. Height matches WP Bakery's default; override inline with a
   utility class where the original specified one.
   ---------------------------------------------------------------------- */

.alt-spacer { height: 32px; }
.alt-spacer-50 { height: 50px; }
.alt-spacer-250 { height: 250px; }

/* Section rhythm.

   These live in the PARENT on purpose. The section library and every build
   script emit `alt-space-lg` and friends, but until now only the child theme
   defined them — Cheryl's did, Poole's did not, and the result was three
   front-page sections with no vertical padding whatsoever. Nothing errors: an
   undefined class is not a warning, it is just a section that sits flush
   against its neighbour, and it took a page-height comparison to notice.

   A child theme overrides the VARIABLES, not the rules. Then forgetting to
   override yields the default rhythm rather than none at all. Cheryl's child
   theme still sets these four rules against her own `--co-*` variables; child
   CSS loads after the parent, so hers continue to win and nothing about the
   live site changes. */
:root {
	--alt-space-sm: 20px;
	--alt-space-md: 30px;
	--alt-space-lg: 50px;
	--alt-space-xl: 80px;
}

.alt-space-sm { padding-top: var(--alt-space-sm); padding-bottom: var(--alt-space-sm); }
.alt-space-md { padding-top: var(--alt-space-md); padding-bottom: var(--alt-space-md); }
.alt-space-lg { padding-top: var(--alt-space-lg); padding-bottom: var(--alt-space-lg); }
.alt-space-xl { padding-top: var(--alt-space-xl); padding-bottom: var(--alt-space-xl); }

/* Hero focal point.

   Which part of the photo survives the crop is an editorial decision, not a
   styling one: a landscape whose subject sits along the bottom edge becomes a
   picture of empty sky when it is centre-cropped into a short band. WP Bakery
   pages express this as background-position on the section, so a rebuild that
   only reproduces `cover` silently reframes the image. Measure the original's
   computed background-position before assuming centre. */
.alt-hero-focus-top    .alt-hero-media { object-position: center top; }
.alt-hero-focus-bottom .alt-hero-media { object-position: center bottom; }

/* -------------------------------------------------------------------------
   QUOTE CAROUSEL — indicators below the content, not over it

   Bootstrap's .carousel-indicators are absolutely positioned at the bottom of
   the carousel because they are designed to sit ON a photo. A quote carousel
   has no photo, so the default overlays the dots on the last line of the
   quote — which reads as a rendering bug rather than a control.

   Structural, not brand: this is about where they sit. Their colour belongs in
   the child, because Bootstrap's default indicator is white and invisible on a
   light section.
   ---------------------------------------------------------------------- */

.alt-quote-indicators {
	position: static;
	margin: 1.5rem 0 0;
	padding: 0;
}

/* The carousel collapses to the tallest slide's height only while animating;
   between slides it takes the active one. Quotes vary a lot in length, so the
   section jumps on every advance unless the items share a floor. */
.alt-quote-carousel .carousel-item { min-height: 100%; }

/* An image carousel is a fixed-shape frame — .alt-media handles the ratio, but
   the item itself must not add its own line-height gap under the image. */
.alt-image-carousel .carousel-item > img { display: block; width: 100%; }


/* -------------------------------------------------------------------------
   HEADER SEARCH (opt-in — see the alt_header_search filter in header.php)

   At rest only the toggle shows; the field is collapsed. Structural only —
   the icon's size and colour are the brand's business.

   The panel is absolutely positioned so revealing it does not change the
   header's height. A search box that pushes the navigation down on click is
   the kind of movement that reads as a bug.
   ---------------------------------------------------------------------- */

.alt-header-search { position: relative; }

.alt-search-toggle {
	background: none;
	border: 0;
	padding: 0;
	line-height: 1;
	display: inline-flex;
	align-items: center;
	color: inherit;
}

.alt-search-panel {
	position: absolute;
	right: 0;
	top: 100%;
	z-index: 20;
	min-width: 260px;
}

/* WordPress's default search form markup, whatever the theme's searchform.php
   emits — keep it on one line and let the brand size it. */
.alt-search-panel form { display: flex; gap: 0; }
.alt-search-panel input[type="search"],
.alt-search-panel input[type="text"] { flex: 1 1 auto; min-width: 0; }
