/*
 * Elevation, gradient, and metal.
 *
 * The 2026 visual layer. It loads after components.css and cards.css and does two
 * jobs: it supplies opt in utilities for lit surfaces, glass, metal frames, edge
 * lighting, seams and asymmetric compositions, and it upgrades the primitives every
 * page is built from so a page becomes dimensional by using the system rather than
 * by collecting decorative classes.
 *
 * One file, on purpose. The whole visual direction can be reviewed in one place and
 * reverted by removing one entry from the stylesheet registry.
 *
 * The material being described is fabricated metal: anodised aluminium, powder
 * coated steel, machined edges, a drafting grid, and light raking across a plane.
 * That is the vocabulary. It is not glass morphism for its own sake and it is not
 * a technology product.
 *
 * Rules that keep it premium rather than loud:
 *
 *   Light has a direction. Every surface is lit from the upper left and every
 *   highlight sits on a top or left edge, every shadow on a bottom or right one. A
 *   page where highlights point in different directions looks cheap immediately.
 *
 *   Elevation levels are far enough apart to see. Base surface, panel, card. If two
 *   planes need explaining they are the same plane.
 *
 *   A card never sits on a background close to its own value. On a dark section a
 *   card is light, or it is charcoal glass with a bright edge. Navy on navy is
 *   banned.
 *
 *   Glow is structural, not decorative. It marks the call action and the focal
 *   point of a composition. Nothing else glows.
 *
 *   Contrast is measured, not assumed. Bounds are recorded in docs/DESIGN-SYSTEM.md.
 *
 *   Nothing here is required for comprehension. Remove every rule in this file and
 *   the site is still legible, navigable, and correctly structured.
 */

/* ===========================================================================
 * 1. Lit surfaces
 *
 * These replace the flat fills on the existing surface classes rather than adding a
 * parallel set, so every section already written against the surface tokens becomes
 * a lit plane without being touched.
 * ======================================================================== */

.afc-surface--dark {
	background-color: var(--afc-navy-dark);
	background-image: var(--afc-gradient-navy);
}

.afc-surface--darker {
	background-color: var(--afc-navy-deep);
	background-image: var(--afc-gradient-navy-deep);
}

.afc-surface--subtle {
	background-image: var(--afc-gradient-light);
}

.afc-surface--stone {
	background-image: var(--afc-gradient-stone);
}

/* Charcoal is the third dark option. Cooler and greyer than navy, so two dark
   sections can sit against each other without reading as one long band. */
.afc-surface--charcoal {
	background-color: var(--afc-charcoal);
	background-image: var(--afc-gradient-charcoal);
	color: var(--afc-color-text-on-dark);
}

.afc-surface--charcoal :where(h1, h2, h3, h4, h5, h6) {
	color: var(--afc-color-text-on-dark);
}

.afc-surface--charcoal :where(.afc-text-muted, .afc-caption, p) {
	color: var(--afc-color-text-muted-on-dark);
}

/* ===========================================================================
 * 2. Texture: drafting grid, brushed grain, sheen
 *
 * The grid has a minor line every 44 pixels and a major every 176, which is how a
 * drawing sheet is actually ruled. It is masked to fade down the section, so it
 * reads as light falling across a surface rather than as a tiled pattern. Fixed
 * pixel spacing on purpose: a drawing grid does not scale with the viewport.
 * ======================================================================== */

.afc-surface--architectural,
.afc-surface--metal {
	position: relative;
	isolation: isolate;
}

.afc-surface--architectural::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: -1;
	background-image:
		var(--afc-metal-sheen),
		repeating-linear-gradient(0deg, var(--afc-grid-line-major) 0 1px, transparent 1px var(--afc-metal-grid-major)),
		repeating-linear-gradient(90deg, var(--afc-grid-line-major) 0 1px, transparent 1px var(--afc-metal-grid-major)),
		repeating-linear-gradient(0deg, var(--afc-grid-line-minor) 0 1px, transparent 1px var(--afc-metal-grid-minor)),
		repeating-linear-gradient(90deg, var(--afc-grid-line-minor) 0 1px, transparent 1px var(--afc-metal-grid-minor));
	-webkit-mask-image: linear-gradient(172deg, #000 0%, rgba(0, 0, 0, 0.62) 55%, rgba(0, 0, 0, 0.06) 96%);
	mask-image: linear-gradient(172deg, #000 0%, rgba(0, 0, 0, 0.62) 55%, rgba(0, 0, 0, 0.06) 96%);
	pointer-events: none;
}

/* The same drawing grid on a light plane, ruled in navy instead of white. */
.afc-surface--subtle.afc-surface--architectural::before,
.afc-surface--stone.afc-surface--architectural::before {
	background-image:
		repeating-linear-gradient(0deg, var(--afc-grid-line-major-light) 0 1px, transparent 1px var(--afc-metal-grid-major)),
		repeating-linear-gradient(90deg, var(--afc-grid-line-major-light) 0 1px, transparent 1px var(--afc-metal-grid-major)),
		repeating-linear-gradient(0deg, var(--afc-grid-line-minor-light) 0 1px, transparent 1px var(--afc-metal-grid-minor)),
		repeating-linear-gradient(90deg, var(--afc-grid-line-minor-light) 0 1px, transparent 1px var(--afc-metal-grid-minor));
}

/* Brushed metal, for a narrower band. The grain is a light and a dark stripe in
   five pixels, which survives a high density screen without moire. */
.afc-surface--metal {
	background-color: var(--afc-charcoal);
	background-image: var(--afc-gradient-charcoal);
	color: var(--afc-color-text-on-dark);
	box-shadow: var(--afc-metal-edge-strong);
}

.afc-surface--metal::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: -1;
	background-image: var(--afc-metal-brushed), var(--afc-metal-sheen);
	pointer-events: none;
}

/* ===========================================================================
 * 3. Radial lighting behind featured content
 *
 * A soft field of colour placed behind a focal point, sized in viewport units so it
 * stays a pool of light rather than becoming a visible disc.
 * ======================================================================== */

.afc-lit {
	position: relative;
	isolation: isolate;
}

.afc-lit::before {
	content: "";
	position: absolute;
	inset-block-start: -12%;
	inset-inline-start: 50%;
	z-index: -1;
	inline-size: min(120%, 68rem);
	aspect-ratio: 3 / 2;
	translate: -50% 0;
	background-image: var(--afc-glow-field-blue);
	pointer-events: none;
}

.afc-lit--red::before {
	background-image: var(--afc-glow-field-red);
}

.afc-lit--offset::before {
	inset-inline-start: 18%;
	inset-block-start: -25%;
}

/* ===========================================================================
 * 4. Edges, hairlines, and seams
 *
 * A section boundary is the cheapest place to add quality. An illuminated top edge
 * makes a dark band read as a machined chamfer catching the light, which is the
 * single most visible thing in this file.
 * ======================================================================== */

/* The short accent bar above section headings. Keeps its dimensions, gains a
   gradient along its length so it reads as anodised rather than painted. */
.afc-rule {
	inline-size: 72px;
	block-size: 4px;
	background-image: var(--afc-gradient-border-accent);
}

/* A full width divider, distinct from the accent bar. Fades at both ends so it can
   stop without leaving a hard corner. */
.afc-hairline {
	display: block;
	inline-size: 100%;
	block-size: 1px;
	border: 0;
	margin: 0;
	background-image: var(--afc-gradient-rule);
}

.afc-surface--dark .afc-hairline,
.afc-surface--darker .afc-hairline,
.afc-surface--charcoal .afc-hairline {
	background-image: var(--afc-gradient-rule-on-dark);
}

.afc-hairline--accent {
	block-size: 3px;
	background-image: var(--afc-gradient-rule-accent);
}

/* Illuminated edges. */
.afc-edge-lit,
.afc-edge-lit-red,
.afc-seam-top,
.afc-seam-bottom {
	position: relative;
}

.afc-edge-lit::before,
.afc-edge-lit-red::before {
	content: "";
	position: absolute;
	inset-block-start: 0;
	inset-inline: 0;
	block-size: 1px;
	pointer-events: none;
}

.afc-edge-lit::before {
	background-image: var(--afc-gradient-edge-lit);
}

.afc-edge-lit-red::before {
	block-size: 2px;
	background-image: var(--afc-gradient-edge-lit-red);
	box-shadow: 0 0 18px rgba(248, 47, 47, 0.45);
}

.afc-seam-top::before,
.afc-seam-bottom::after {
	content: "";
	position: absolute;
	inset-inline: 0;
	block-size: 3px;
	background-image: var(--afc-gradient-rule-accent);
	pointer-events: none;
}

.afc-seam-top::before {
	inset-block-start: 0;
}

.afc-seam-bottom::after {
	inset-block-end: 0;
}

/* Where a dark plane meets a light one, a shadow cast down from the dark side
   reads as one plane in front of another. Two flat colours meeting at a hard line
   is the thing that makes a page look flat. */
.afc-seam-shadow {
	position: relative;
}

.afc-seam-shadow::after {
	content: "";
	position: absolute;
	inset-block-start: 100%;
	inset-inline: 0;
	block-size: var(--afc-space-lg);
	background-image: linear-gradient(180deg, rgba(7, 13, 32, 0.22) 0%, rgba(7, 13, 32, 0.06) 45%, rgba(7, 13, 32, 0) 100%);
	pointer-events: none;
	z-index: 1;
}

/* An overlapping section. The band is pulled up over the one before it and casts a
   shadow upward, so the two genuinely overlap rather than abut. */
.afc-overlap {
	position: relative;
	z-index: 2;
	margin-block-start: calc(var(--afc-space-2xl) * -1);
	box-shadow: 0 -30px 60px rgba(7, 13, 32, 0.28);
}

/* ===========================================================================
 * 5. Metal frames and gradient borders
 *
 * Two backgrounds, one clipped to the padding box and one to the border box. That
 * gives a real gradient border with no pseudo element and no mask compositing, so
 * it works everywhere and it can be as thick as it needs to be to be seen.
 * ======================================================================== */

.afc-frame-metal,
.afc-frame-accent,
.afc-frame-metal-dark {
	border: 2px solid transparent;
	background-origin: border-box;
	background-clip: padding-box, border-box;
}

.afc-frame-metal {
	background-image: var(--afc-gradient-card), var(--afc-gradient-border-metal);
}

.afc-frame-accent {
	background-image: var(--afc-gradient-card), var(--afc-gradient-border-accent);
}

.afc-frame-metal-dark {
	background-image: var(--afc-gradient-charcoal), var(--afc-gradient-border-metal-dark);
	color: var(--afc-color-text-on-dark);
}

/* ===========================================================================
 * 6. Panels: three visible elevation levels
 * ======================================================================== */

.afc-panel {
	padding: var(--afc-space-md);
	border: 2px solid transparent;
	background-image: var(--afc-gradient-card), var(--afc-gradient-border-metal);
	background-origin: border-box;
	background-clip: padding-box, border-box;
	box-shadow: var(--afc-metal-edge-light), var(--afc-depth-md);
}

.afc-panel--raised {
	padding: var(--afc-space-lg);
	box-shadow: var(--afc-metal-edge-light), var(--afc-depth-xl);
}

.afc-panel--glass {
	border-color: transparent;
	background-image:
		linear-gradient(155deg, rgba(255, 255, 255, 0.14) 0%, rgba(255, 255, 255, 0.05) 55%, rgba(255, 255, 255, 0.02) 100%),
		var(--afc-gradient-border-metal-dark);
	color: var(--afc-color-text-on-dark);
	box-shadow: var(--afc-metal-edge-strong), var(--afc-depth-on-dark);
	-webkit-backdrop-filter: blur(16px) saturate(130%);
	backdrop-filter: blur(16px) saturate(130%);
}

.afc-panel--glass :where(h1, h2, h3, h4, h5, h6) {
	color: var(--afc-color-text-on-dark);
}

.afc-panel--dark {
	padding: var(--afc-space-lg);
	border-color: transparent;
	background-image: var(--afc-gradient-navy), var(--afc-gradient-border-metal-dark);
	color: var(--afc-color-text-on-dark);
	box-shadow: var(--afc-metal-edge-strong), var(--afc-depth-on-dark-lg);
}

/* ===========================================================================
 * 7. Lift
 * ======================================================================== */

.afc-lift {
	transition:
		transform var(--afc-duration) var(--afc-ease-standard),
		box-shadow var(--afc-duration) var(--afc-ease-standard);
}

.afc-lift:hover,
.afc-lift:focus-within {
	transform: translateY(var(--afc-lift));
	box-shadow: var(--afc-metal-edge-light), var(--afc-depth-xl);
}

/* ===========================================================================
 * 8. The primary call action
 *
 * The most important element on the site, so the one place with a gradient, an
 * inner highlight, and a glow. The inner highlight is what makes a filled button
 * read as a physical key rather than a coloured rectangle.
 * ======================================================================== */

.afc-btn--primary {
	background-color: var(--afc-color-brand-red);
	background-image: var(--afc-gradient-red);
	border-color: transparent;
	box-shadow:
		inset 0 1px 0 rgba(255, 255, 255, 0.42),
		inset 0 -1px 0 rgba(0, 0, 0, 0.25),
		var(--afc-glow-red);
	transition:
		background-image var(--afc-duration-fast) var(--afc-ease-standard),
		transform var(--afc-duration-fast) var(--afc-ease-standard),
		box-shadow var(--afc-duration-fast) var(--afc-ease-standard);
}

.afc-btn--primary:hover,
.afc-btn--primary:focus-visible {
	background-image: var(--afc-gradient-red-hover);
	box-shadow:
		inset 0 1px 0 rgba(255, 255, 255, 0.5),
		inset 0 -1px 0 rgba(0, 0, 0, 0.25),
		var(--afc-glow-red-strong);
	transform: translateY(var(--afc-lift-sm));
}

/* Pressed returns to the surface. A button that only ever rises feels unresponsive
   at the moment it is actually used. */
.afc-btn--primary:active {
	transform: translateY(0);
	box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.3);
}

.afc-btn--primary[aria-disabled="true"],
.afc-btn--primary:disabled {
	background-image: none;
	box-shadow: none;
	transform: none;
}

/* Secondary and outline stay flat by design. Two competing raised buttons side by
   side destroy the hierarchy the raised one exists to create. */
.afc-btn--outline,
.afc-btn--secondary {
	transition:
		background-color var(--afc-duration-fast) var(--afc-ease-standard),
		border-color var(--afc-duration-fast) var(--afc-ease-standard),
		color var(--afc-duration-fast) var(--afc-ease-standard);
}

/* The outline button carries navy text on a navy border, which is correct on a
   light section and invisible on a dark one. On a dark plane it becomes a machined
   plate: white lettering, a bright edge, and a faint metal fill. White on the
   lightest part of that fill measures better than 12 to 1. */
.afc-surface--dark .afc-btn--outline,
.afc-surface--darker .afc-btn--outline,
.afc-surface--charcoal .afc-btn--outline,
.afc-cta--dark .afc-btn--outline,
.afc-footer-cta .afc-btn--outline,
.afc-btn--outline-light {
	border-color: rgba(255, 255, 255, 0.42);
	color: var(--afc-white);
	background-color: transparent;
	background-image: linear-gradient(155deg, rgba(255, 255, 255, 0.16) 0%, rgba(255, 255, 255, 0.03) 100%);
	box-shadow: var(--afc-metal-edge-strong);
}

.afc-surface--dark .afc-btn--outline:hover,
.afc-surface--darker .afc-btn--outline:hover,
.afc-surface--charcoal .afc-btn--outline:hover,
.afc-cta--dark .afc-btn--outline:hover,
.afc-footer-cta .afc-btn--outline:hover,
.afc-btn--outline-light:hover {
	border-color: var(--afc-white);
	color: var(--afc-white);
	background-image: linear-gradient(155deg, rgba(255, 255, 255, 0.28) 0%, rgba(255, 255, 255, 0.10) 100%);
}

/* ===========================================================================
 * 9. Cards on a light plane
 *
 * White card, anodised metal border, a bright inner top edge, and a layered shadow
 * that puts it clearly one level above the surface. The gradient accent bar across
 * the top is the immediately visible part.
 * ======================================================================== */

.afc-service-card,
.afc-project-card,
.afc-review-card,
.afc-city-card {
	border: 1px solid transparent;
	background-image: var(--afc-gradient-card), var(--afc-gradient-border-metal);
	background-origin: border-box;
	background-clip: padding-box, border-box;
	box-shadow: var(--afc-metal-edge-light), var(--afc-depth-md);
	transition:
		transform var(--afc-duration) var(--afc-ease-standard),
		box-shadow var(--afc-duration) var(--afc-ease-standard);
}

/* The accent bar. Drawn rather than bordered so it can be a gradient, and inert so
   it is invisible to assistive technology. */
.afc-service-card::after,
.afc-project-card::after,
.afc-city-card::after {
	content: "";
	position: absolute;
	inset-block-start: 0;
	inset-inline: 0;
	block-size: 3px;
	background-image: var(--afc-gradient-border-accent);
	z-index: 2;
	pointer-events: none;
}

.afc-service-card:hover,
.afc-service-card:focus-within,
.afc-project-card:hover,
.afc-project-card:focus-within,
.afc-city-card:hover,
.afc-city-card:focus-within {
	transform: translateY(var(--afc-lift));
	box-shadow: var(--afc-metal-edge-light), var(--afc-depth-xl);
	border-color: transparent;
}

/* ===========================================================================
 * 10. Cards on a dark plane
 *
 * Navy on navy is banned. A card on a dark section is either light, which is the
 * default because it reads instantly, or charcoal glass with a bright edge, which
 * is for a card sitting over photography where a light block would be too heavy.
 * ======================================================================== */

.afc-surface--dark .afc-service-card,
.afc-surface--darker .afc-service-card,
.afc-surface--charcoal .afc-service-card,
.afc-surface--dark .afc-project-card,
.afc-surface--darker .afc-project-card,
.afc-surface--charcoal .afc-project-card,
.afc-surface--dark .afc-city-card,
.afc-surface--darker .afc-city-card {
	background-image: var(--afc-gradient-card-cool), var(--afc-gradient-border-metal);
	box-shadow: var(--afc-metal-edge-light), var(--afc-depth-on-dark);
}

.afc-surface--dark .afc-service-card:hover,
.afc-surface--darker .afc-service-card:hover,
.afc-surface--dark .afc-project-card:hover,
.afc-surface--darker .afc-project-card:hover {
	box-shadow: var(--afc-metal-edge-light), var(--afc-depth-on-dark-lg);
}

/*
 * A dark section turns all of its headings and links white, which is right for text
 * on the plane and wrong for text inside a light card sitting on that plane. Without
 * this the card titles are white on near white and simply disappear.
 *
 * The glass variants are excluded, because their fill is dark and their text is
 * supposed to stay light.
 */
.afc-surface--dark :where(.afc-service-card, .afc-project-card, .afc-city-card, .afc-panel):not(.afc-service-card--dark, .afc-service-card--glass, .afc-panel--glass, .afc-panel--dark) :where(h1, h2, h3, h4, h5, h6),
.afc-surface--darker :where(.afc-service-card, .afc-project-card, .afc-city-card, .afc-panel):not(.afc-service-card--dark, .afc-service-card--glass, .afc-panel--glass, .afc-panel--dark) :where(h1, h2, h3, h4, h5, h6),
.afc-surface--charcoal :where(.afc-service-card, .afc-project-card, .afc-city-card, .afc-panel):not(.afc-service-card--dark, .afc-service-card--glass, .afc-panel--glass, .afc-panel--dark) :where(h1, h2, h3, h4, h5, h6) {
	color: var(--afc-color-text-strong);
}

.afc-surface--dark :where(.afc-service-card, .afc-project-card, .afc-city-card, .afc-panel):not(.afc-service-card--dark, .afc-service-card--glass, .afc-panel--glass, .afc-panel--dark) :where(a:not(.afc-btn)),
.afc-surface--darker :where(.afc-service-card, .afc-project-card, .afc-city-card, .afc-panel):not(.afc-service-card--dark, .afc-service-card--glass, .afc-panel--glass, .afc-panel--dark) :where(a:not(.afc-btn)),
.afc-surface--charcoal :where(.afc-service-card, .afc-project-card, .afc-city-card, .afc-panel):not(.afc-service-card--dark, .afc-service-card--glass, .afc-panel--glass, .afc-panel--dark) :where(a:not(.afc-btn)) {
	color: var(--afc-color-text-strong);
}

.afc-surface--dark :where(.afc-service-card, .afc-project-card, .afc-city-card, .afc-panel):not(.afc-service-card--dark, .afc-service-card--glass, .afc-panel--glass, .afc-panel--dark) :where(p, li, .afc-text-muted, .afc-caption),
.afc-surface--darker :where(.afc-service-card, .afc-project-card, .afc-city-card, .afc-panel):not(.afc-service-card--dark, .afc-service-card--glass, .afc-panel--glass, .afc-panel--dark) :where(p, li, .afc-text-muted, .afc-caption),
.afc-surface--charcoal :where(.afc-service-card, .afc-project-card, .afc-city-card, .afc-panel):not(.afc-service-card--dark, .afc-service-card--glass, .afc-panel--glass, .afc-panel--dark) :where(p, li, .afc-text-muted, .afc-caption) {
	color: var(--afc-color-text-muted);
}

/* The read more line is brand red on every surface, and it is a paragraph, so it
   has to win against the muted rule above. */
.afc-surface--dark .afc-service-card__more,
.afc-surface--darker .afc-service-card__more,
.afc-surface--charcoal .afc-service-card__more {
	color: var(--afc-color-brand-red);
}

.afc-surface--dark .afc-service-card--glass .afc-service-card__more,
.afc-surface--darker .afc-service-card--glass .afc-service-card__more,
.afc-surface--dark .afc-service-card--dark .afc-service-card__more,
.afc-surface--darker .afc-service-card--dark .afc-service-card__more {
	color: var(--afc-red-bright);
}

/* Charcoal glass. The bright top edge is what separates it from the plane behind,
   so it is the one thing here that must not be softened. Text is white and the
   fill is dark, so contrast comes from the card rather than from the backdrop. */
.afc-service-card--dark,
.afc-service-card--glass {
	border: 1px solid transparent;
	background-image:
		linear-gradient(155deg, rgba(70, 84, 116, 0.55) 0%, rgba(26, 32, 48, 0.72) 55%, rgba(16, 20, 32, 0.82) 100%),
		var(--afc-gradient-border-metal-dark);
	background-origin: border-box;
	background-clip: padding-box, border-box;
	box-shadow: var(--afc-metal-edge-strong), var(--afc-depth-on-dark);
	-webkit-backdrop-filter: blur(14px) saturate(130%);
	backdrop-filter: blur(14px) saturate(130%);
}

.afc-service-card--dark::after,
.afc-service-card--glass::after {
	background-image: var(--afc-gradient-edge-lit);
	block-size: 1px;
}

.afc-service-card--dark .afc-service-card__title,
.afc-service-card--dark .afc-service-card__title a,
.afc-service-card--glass .afc-service-card__title,
.afc-service-card--glass .afc-service-card__title a {
	color: var(--afc-color-text-on-dark);
}

.afc-service-card--dark .afc-service-card__text,
.afc-service-card--glass .afc-service-card__text {
	color: var(--afc-color-text-muted-on-dark);
}

.afc-service-card--dark:hover,
.afc-service-card--glass:hover {
	transform: translateY(var(--afc-lift));
	box-shadow: var(--afc-metal-edge-strong), var(--afc-depth-on-dark-lg);
}

.afc-service-card--glass .afc-service-card__icon,
.afc-service-card--dark .afc-service-card__icon {
	border-color: rgba(255, 255, 255, 0.28);
	background-image: linear-gradient(155deg, rgba(255, 255, 255, 0.16) 0%, rgba(255, 255, 255, 0.03) 100%);
	color: var(--afc-white);
}

/* The county card is deliberately dark, because it carries a photograph behind its
   own text. It gets the lit navy plane and a bright edge instead of a light fill. */
.afc-county-card:not(.afc-county-card--light) {
	background-image: var(--afc-gradient-navy);
	box-shadow: var(--afc-metal-edge-strong), var(--afc-depth-on-dark);
}

/* ===========================================================================
 * 11. Trust metrics
 *
 * The numeral is the point of the card, so it gets the gradient. A real colour is
 * declared outside the support query and only replaced inside it, so an engine that
 * cannot clip a background to text renders navy rather than nothing.
 * ======================================================================== */

.afc-trust-card {
	border-block-start: 0;
	padding-block-start: var(--afc-space-sm);
	position: relative;
}

.afc-trust-card::before {
	content: "";
	position: absolute;
	inset-block-start: 0;
	inset-inline: 0;
	block-size: 4px;
	background-image: var(--afc-gradient-border-accent);
}

.afc-trust-card--boxed {
	border: 1px solid transparent;
	background-image: var(--afc-gradient-card), var(--afc-gradient-border-metal);
	background-origin: border-box;
	background-clip: padding-box, border-box;
	box-shadow: var(--afc-metal-edge-light), var(--afc-depth-md);
}

/* Facts, not links, so depth but never movement. A hover that moves something
   unclickable is a false affordance. */
.afc-trust-card:hover {
	transform: none;
}

@supports (background-clip: text) or (-webkit-background-clip: text) {
	.afc-trust-card__metric {
		background-image: var(--afc-gradient-text-navy);
		-webkit-background-clip: text;
		background-clip: text;
		color: transparent;
	}

	.afc-surface--dark .afc-trust-card__metric,
	.afc-surface--darker .afc-trust-card__metric,
	.afc-surface--charcoal .afc-trust-card__metric {
		background-image: var(--afc-gradient-text-light);
	}
}

/* ===========================================================================
 * 12. Call sections
 * ======================================================================== */

.afc-cta--dark,
.afc-footer-cta {
	position: relative;
	isolation: isolate;
	background-image: var(--afc-gradient-navy);
	overflow: hidden;
}

.afc-cta--dark::after,
.afc-footer-cta::after {
	content: "";
	position: absolute;
	inset-block-end: -30%;
	inset-inline-start: 50%;
	z-index: -1;
	inline-size: min(150%, 80rem);
	aspect-ratio: 5 / 2;
	translate: -50% 0;
	background-image: var(--afc-glow-field-red);
	pointer-events: none;
}

/* The existing red hairline across the top of the footer call section becomes an
   illuminated edge with a bloom. */
.afc-footer-cta::before {
	block-size: 2px;
	background-image: var(--afc-gradient-edge-lit-red);
	box-shadow: 0 0 24px rgba(248, 47, 47, 0.5);
}

/* ===========================================================================
 * 13. Images
 * ======================================================================== */

/* A photograph sitting on the page as an object. */
.afc-media--dimensional {
	box-shadow: var(--afc-metal-edge-light), var(--afc-depth-lg);
}

.afc-surface--dark .afc-media--dimensional,
.afc-surface--darker .afc-media--dimensional,
.afc-surface--charcoal .afc-media--dimensional {
	box-shadow: var(--afc-metal-edge-strong), var(--afc-depth-on-dark-lg);
}

/* An offset accent frame drawn behind the image and out of register with it, which
   is a drafting convention rather than a decoration. Inert, so it has no content. */
.afc-media-framed {
	position: relative;
	isolation: isolate;
}

/*
 * An outline frame, offset behind the photograph, so its interior has to stay
 * transparent.
 *
 * The two background trick used by the cards above cannot do this. It works by
 * covering the border box layer with an opaque layer clipped to the padding box, and
 * an opaque interior is a filled rectangle, not a frame. A transparent layer covers
 * nothing, so the border gradient floods the whole element and the frame renders as
 * a solid block.
 *
 * Two masks composited against each other are what leaves a hole in the middle. The
 * fallback is a plain solid border, which is still a frame, just not a graded one.
 */
.afc-media-framed::before {
	content: "";
	position: absolute;
	inset-block: var(--afc-space-sm) calc(var(--afc-space-sm) * -1);
	inset-inline: calc(var(--afc-space-sm) * -1) var(--afc-space-sm);
	z-index: -1;
	border: 2px solid var(--afc-steel-600);
	pointer-events: none;
}

/* The accent frame is a strong move and belongs to one element per page at most.
   Metal is the default, because a red frame on every photograph stops meaning
   anything. */
.afc-media-framed--accent::before {
	border-color: var(--afc-red);
}

@supports ((mask-composite: exclude) or (-webkit-mask-composite: xor)) {
	.afc-media-framed::before {
		border-color: transparent;
		background-image: var(--afc-gradient-border-metal);
		background-origin: border-box;
		background-clip: border-box;
		-webkit-mask-image: linear-gradient(#000 0 0), linear-gradient(#000 0 0);
		-webkit-mask-clip: padding-box, border-box;
		-webkit-mask-composite: xor;
		mask-image: linear-gradient(#000 0 0), linear-gradient(#000 0 0);
		mask-clip: padding-box, border-box;
		mask-composite: exclude;
	}

	.afc-media-framed--accent::before {
		background-image: var(--afc-gradient-border-accent);
	}
}

/* The frame would otherwise push the section wider on a phone. */
@media (max-width: 599px) {
	.afc-media-framed::before {
		inset-inline: 0 var(--afc-space-2xs);
	}
}

/* A gradient scrim with a spotlight, for text placed over photography. Stronger
   than a plain scrim, and the spotlight draws the eye to the subject. */
.afc-media-lit {
	position: relative;
	isolation: isolate;
}

.afc-media-lit::after {
	content: "";
	position: absolute;
	inset: 0;
	background-image:
		radial-gradient(70% 60% at 30% 35%, rgba(96, 132, 220, 0.18) 0%, rgba(96, 132, 220, 0) 65%),
		linear-gradient(190deg, rgba(7, 13, 32, 0.15) 0%, rgba(7, 13, 32, 0) 35%, rgba(7, 13, 32, 0.72) 82%, rgba(7, 13, 32, 0.92) 100%);
	pointer-events: none;
}

/* ===========================================================================
 * 14. Compositions
 *
 * Rows of identical rectangles are the thing that makes a site look like a stock
 * theme. These four give a page a focal point instead. All of them collapse to a
 * single column in document order, with no overlap, below the tablet breakpoint.
 * ======================================================================== */

/* 14a. Mosaic. The first item becomes a large feature spanning two columns and two
   rows, the rest fill in around it. Mixed sizes from one grid. */
.afc-mosaic {
	display: grid;
	gap: var(--afc-gap-grid);
	grid-template-columns: repeat(auto-fit, minmax(min(100%, 16rem), 1fr));
}

@media (min-width: 900px) {
	.afc-mosaic {
		grid-template-columns: repeat(3, minmax(0, 1fr));
	}

	.afc-mosaic > :first-child {
		grid-column: span 2;
		grid-row: span 2;
	}

	.afc-mosaic--right > :first-child {
		grid-column: 2 / span 2;
		grid-row: 1 / span 2;
	}
}

/* 14b. Offset columns. Alternate items ride lower, which turns a flat row into an
   editorial rhythm without changing any card. Columns are declared here so the
   utility works on its own rather than depending on a second grid class. */
.afc-offset-grid {
	display: grid;
	gap: var(--afc-gap-grid);
	grid-template-columns: repeat(auto-fit, minmax(min(100%, 17rem), 1fr));
}

@media (min-width: 900px) {
	.afc-offset-grid > :nth-child(even) {
		margin-block-start: var(--afc-space-2xl);
	}

	.afc-offset-grid--deep > :nth-child(3n + 2) {
		margin-block-start: var(--afc-space-xl);
	}

	.afc-offset-grid--deep > :nth-child(3n + 3) {
		margin-block-start: calc(var(--afc-space-2xl) + var(--afc-space-md));
	}
}

/* 14c. Feature split. An image and a content panel that genuinely overlap, on a
   twelve column grid. The panel is the raised plane, so it must come second in the
   stacking order and carry the larger shadow. */
.afc-feature-split {
	display: grid;
	gap: var(--afc-space-sm);
}

@media (min-width: 900px) {
	.afc-feature-split {
		grid-template-columns: repeat(12, minmax(0, 1fr));
		align-items: center;
		gap: 0;
	}

	.afc-feature-split__media {
		grid-column: 1 / span 7;
		grid-row: 1;
	}

	.afc-feature-split__panel {
		grid-column: 7 / span 6;
		grid-row: 1;
		z-index: 2;
	}

	.afc-feature-split--reverse .afc-feature-split__media {
		grid-column: 6 / span 7;
	}

	.afc-feature-split--reverse .afc-feature-split__panel {
		grid-column: 1 / span 6;
	}
}

/* 14d. Editorial pair. The layout lives in components.css, because it is structure
   rather than surface. Only the material is set here: a thicker white reveal around
   the foreground plate and the largest shadow in the system, so the two photographs
   read as two planes at different heights. */
@media (min-width: 768px) {
	.afc-media-stack__secondary {
		z-index: 2;
		border-width: 8px;
		box-shadow: var(--afc-depth-xl);
	}
}

/* 14e. A tall card in a mosaic. The first item spans two rows, so its photograph
   grows to take up the slack instead of leaving a field of empty card below the
   text. Without this the feature slot looks like a layout fault. */
@media (min-width: 900px) {
	.afc-mosaic > :first-child {
		display: flex;
		flex-direction: column;
	}

	.afc-mosaic > :first-child .afc-service-card__media,
	.afc-mosaic > :first-child .afc-project-card__media {
		flex: 1 1 auto;
		aspect-ratio: auto;
		min-block-size: 18rem;
	}
}

/* ===========================================================================
 * 15. Entrance motion refinement
 *
 * The reveal itself lives in motion.css. This adds a little scale and a longer
 * travel to a revealing panel, which reads as an object settling into place rather
 * than a block fading in. Only elements that already opt into a reveal are
 * affected, and the reduced motion rules still govern whether any of it runs.
 * ======================================================================== */

@media (prefers-reduced-motion: no-preference) {
	.afc-js [data-afc-reveal="panel"] {
		opacity: 0;
		transform: translateY(calc(var(--afc-reveal-distance) * 1.6)) scale(0.97);
		transition:
			opacity var(--afc-duration-reveal) var(--afc-ease-entrance),
			transform var(--afc-duration-reveal) var(--afc-ease-entrance);
	}

	.afc-js [data-afc-reveal="panel"].is-revealed {
		opacity: 1;
		transform: none;
	}
}
