/**
 * The utility layer.
 *
 * Declared last in avia_css_layer_order(), which is the only reason a layer of
 * single classes can work here at all: layers resolve before specificity, so a
 * (0,1,0) rule in this file beats a (0,4,1) vendor chain in avia-baseline
 * without an !important. Hand-rolled utilities normally fail in an estate this
 * size for exactly the opposite reason -- one class cannot win against vendor
 * descendant selectors, everyone reaches for !important, and the vocabulary
 * becomes unusable within a month.
 *
 * This file declares its own layer, so it is exempt from the cascade block.
 *
 * The precondition, worth stating plainly because it is invisible: a utility
 * outranks vendor CSS only on a request that builds the cascade block, since
 * without the block's @layer statement every vendor sheet is unlayered, and
 * unlayered beats every layer. The block is built by the first call to
 * avia_css_layer_assign(), so a surface that wants to use these classes needs a
 * stylesheet of its own in a layer -- which it needs anyway. On a surface with
 * no layered sheet the utilities still apply, they just lose the same ties our
 * unlayered components lose today. Check for the block before assuming a class
 * here will win on a page nobody has measured.
 *
 *
 * WHAT EARNS A CLASS HERE
 *
 * One test, and it excludes most of what a framework would ship: a utility
 * exists only for a property whose entire set of legitimate values is already a
 * token scale, and which carries no meaning about what the element is. Font
 * size qualifies -- there are nine sizes and no tenth, and a size says nothing
 * about the thing being sized. Width does not: there is no scale of widths, so
 * a width utility is an arbitrary value with a class name on it.
 *
 * That test is what keeps this file from growing into Bootstrap, which is not a
 * hypothetical: three copies of Bootstrap 5.3.0-alpha1 are loaded across this
 * estate, two of them byte-identical, for roughly forty utility classes.
 *
 *
 * WHAT IS DELIBERATELY MISSING
 *
 * There are no margin utilities, and this is the point of the file rather than
 * an omission. `mb-3` appears 104 times in our templates; those are what this
 * replaces, not what it reproduces. Space between siblings belongs to the
 * element that contains them -- u-stack, u-cluster and u-grid-auto own a gap,
 * and u-gap-* retunes it -- because a gap cannot leak, cannot collapse, and
 * disappears along with the container when the last child is hidden. A margin
 * carried by the child does none of those things, and every "why is there a
 * space under this when it is empty" bug is one.
 *
 * u-push is the single exception: pushing one item to the far end of a flex row
 * is a genuine use of auto margin and there is no gap that expresses it.
 *
 * There are no padding utilities either, for a different reason: padding is
 * inside the box, so it is part of what a component looks like rather than part
 * of how it is arranged. It belongs in the component's own rule.
 *
 *
 * HOW TO USE IT
 *
 * The u- prefix is not decoration. It was measured: .muted, .normal and every
 * .gap-* already exist in the theme and in Bootstrap, and since this layer wins
 * over both, an unprefixed collision would silently restyle vendor markup on
 * every page -- .gap-2 alone is live in fifteen of our own templates. The
 * prefix also makes the second rule enforceable by reading the markup:
 *
 *   Our CSS never names a u- class in a selector.
 *
 * A u- class is vocabulary for markup, in one direction only. The moment a
 * stylesheet contains `.avia-card .u-bold`, the utility has become a hook and
 * changing it in one template breaks another. Give the element an avia- class
 * and target that.
 *
 * The same cluster of utilities appearing on three elements is a component
 * waiting to be extracted, not a pattern to keep repeating.
 */

@layer avia-utilities {

	/* Type size. */
	.u-text-2xs { font-size: var(--avia-text-2xs); }
	.u-text-xs { font-size: var(--avia-text-xs); }
	.u-text-sm { font-size: var(--avia-text-sm); }
	.u-text-base { font-size: var(--avia-text-base); }
	.u-text-md { font-size: var(--avia-text-md); }
	.u-text-lg { font-size: var(--avia-text-lg); }
	.u-text-xl { font-size: var(--avia-text-xl); }
	.u-text-2xl { font-size: var(--avia-text-2xl); }
	.u-text-3xl { font-size: var(--avia-text-3xl); }

	/* Weight. */
	.u-normal { font-weight: var(--avia-weight-normal); }
	.u-medium { font-weight: var(--avia-weight-medium); }
	.u-semibold { font-weight: var(--avia-weight-semibold); }
	.u-bold { font-weight: var(--avia-weight-bold); }

	/* Line height. */
	.u-leading-none { line-height: var(--avia-leading-none); }
	.u-leading-tight { line-height: var(--avia-leading-tight); }
	.u-leading-snug { line-height: var(--avia-leading-snug); }
	.u-leading-normal { line-height: var(--avia-leading-normal); }

	/*
	 * Colour by role. These are the only colour utilities there will be: a
	 * class per palette entry is how a palette stops being semantic, and the
	 * moment a component needs a colour that is not one of these roles, the
	 * answer is a token, not a class.
	 */
	.u-text-heading { color: var(--avia-color-heading); }
	.u-text-body { color: var(--avia-color-text); }
	.u-text-muted { color: var(--avia-color-muted); }
	.u-text-accent { color: var(--avia-color-accent); }
	.u-text-success { color: var(--avia-color-success); }
	.u-text-warning { color: var(--avia-color-warning); }
	.u-text-danger { color: var(--avia-color-danger); }

	/*
	 * Layout primitives. Three arrangements cover nearly everything: things
	 * down the page, things along a line, and things that wrap into as many
	 * columns as fit.
	 *
	 * Each reads --u-gap through a fallback rather than setting gap outright,
	 * so u-gap-* below is order-independent -- it sets a custom property these
	 * resolve, instead of competing with them for the same declaration at the
	 * same specificity in the same layer.
	 *
	 * The defaults differ on purpose. Spacing nests: an inner gap that matches
	 * its outer gap makes two groups read as one, so a cluster starts tighter
	 * than a stack.
	 */
	.u-stack {
		display: flex;
		flex-direction: column;
		gap: var(--u-gap, var(--avia-space-4));
	}

	.u-cluster {
		display: flex;
		flex-wrap: wrap;
		align-items: center;
		gap: var(--u-gap, var(--avia-space-3));
	}

	/*
	 * min() on the track floor is what stops this overflowing: below 240px of
	 * available width the column falls back to 100% instead of forcing a
	 * horizontal scrollbar. Retune the floor with --u-min on the element.
	 */
	.u-grid-auto {
		display: grid;
		gap: var(--u-gap, var(--avia-space-5));
		grid-template-columns: repeat(auto-fill, minmax(min(var(--u-min, 240px), 100%), 1fr));
	}

	/* Gap, on the spacing scale. Applies to flex and grid alike. */
	.u-gap-1 { --u-gap: var(--avia-space-1); }
	.u-gap-2 { --u-gap: var(--avia-space-2); }
	.u-gap-3 { --u-gap: var(--avia-space-3); }
	.u-gap-4 { --u-gap: var(--avia-space-4); }
	.u-gap-5 { --u-gap: var(--avia-space-5); }
	.u-gap-6 { --u-gap: var(--avia-space-6); }
	.u-gap-7 { --u-gap: var(--avia-space-7); }
	.u-gap-8 { --u-gap: var(--avia-space-8); }

	/* Alignment inside a primitive. */
	.u-items-start { align-items: flex-start; }
	.u-items-center { align-items: center; }
	.u-items-end { align-items: flex-end; }
	.u-justify-center { justify-content: center; }
	.u-justify-between { justify-content: space-between; }
	.u-justify-end { justify-content: flex-end; }

	/* The one legitimate auto margin: push this item to the far end. */
	.u-push { margin-inline-start: auto; }

	.u-text-center { text-align: center; }

	/*
	 * Text that has to fit. Both of these need a minimum width to shrink
	 * against inside a flex or grid item, which is what min-width: 0 supplies
	 * -- without it a flex item's automatic minimum size is its content, and
	 * neither the ellipsis nor the clamp ever engages.
	 */
	.u-truncate {
		min-width: 0;
		overflow: hidden;
		text-overflow: ellipsis;
		white-space: nowrap;
	}

	.u-clamp-2,
	.u-clamp-3 {
		display: -webkit-box;
		-webkit-box-orient: vertical;
		min-width: 0;
		overflow: hidden;
	}

	.u-clamp-2 { -webkit-line-clamp: 2; }
	.u-clamp-3 { -webkit-line-clamp: 3; }

	/*
	 * Present to a screen reader, absent from the page. This does not pass the
	 * token test above -- there is no scale here -- and it is in the file for
	 * the reason u-truncate is: one job, one canonical recipe, no arbitrary
	 * value to choose. It replaces `.sr-only`, which our markup was reading off
	 * Font Awesome's stylesheet, a dependency nothing declared and nobody would
	 * guess from the class name.
	 *
	 * clip-path rather than clip, and a 1px box rather than zero, because a
	 * zero-sized element is skipped by some screen readers and `clip` is
	 * deprecated.
	 */
	.u-visually-hidden {
		position: absolute;
		width: 1px;
		height: 1px;
		overflow: hidden;
		clip-path: inset(50%);
		white-space: nowrap;
	}
}
