/* =============================================================================
 * 20-chrome.css -- header, primary nav, footer. The chrome the theme now OWNS.
 *
 * BYTE-IDENTICAL across both sites. This file is the reason Astra, TT4, HFE,
 * ElementsKit and Elementor Pro's Theme Builder can all update freely without
 * stranding either site: none of them render chrome any more.
 *
 * Markup contract -- from _shared/php/chrome-header.php, chrome-footer.php,
 * nav-walker.php and nav.js:
 *
 *   #page.qt-site
 *     header#masthead.qt-header
 *       .qt-header__inner
 *         .qt-brand > .qt-brand__link[--text] > .qt-brand__logo | .qt-brand__wordmark
 *         button.qt-nav-toggle > .qt-nav-toggle__bar
 *         nav#qt-primary-nav.qt-nav[.is-open]
 *           > ul#qt-primary-menu.qt-menu.qt-menu--primary
 *               > li[.qt-has-children][.is-open]
 *                   > a  [> img.qt-menu__img]
 *                   > button.qt-submenu-toggle
 *                   > ul.sub-menu
 *         .qt-header__cta > .qt-header__phone            (only when brand.php has a phone)
 *         a.qt-btn.qt-btn--primary.qt-header__quote      (only when brand.php has quote_url)
 *             DIRECT child of .qt-header__inner, NOT inside .qt-header__cta --
 *             it needs to be a flex item of the header row to claim a full-width
 *             line of its own below 1024px. Nested one level deeper, `flex: 1 1
 *             100%` would resolve against .qt-header__cta and do nothing.
 *     #content.site-content > .ast-container.qt-container
 *     footer#colophon.qt-footer                      -- the sheet GROUND
 *       .qt-footer__inner                            -- the painted BAND
 *         .qt-footer__nav > ul#qt-footer-menu.qt-menu.qt-menu--footer
 *             the whole <nav> is absent on GF -- chrome-footer.php resolves the
 *             menu BEFORE emitting the wrapper, so an unresolved slot costs no
 *             element and no --qt-space-3 gap
 *         nav.qt-footer__sitemap                       -- brand.php link groups
 *           > .qt-footer__group
 *               > h2.qt-footer__group-title#qt-footer-group-N
 *               + ul.qt-footer__links[aria-labelledby]
 *             absent entirely unless brand.php['footer_link_groups'] yields at
 *             least one group with at least one usable link -- same
 *             build-then-emit discipline as the footer menu above
 *         .qt-footer__cols > .qt-footer__col.qt-footer__col--N
 *             N is the SIDEBAR id, not the position. AT registers 1, GF 3; only
 *             sidebars with a widget in them render, so GF ships 2 today
 *         .qt-footer__legal > .qt-footer__copyright
 *
 * BREAKPOINT: 1024px, and it is not negotiable here. nav.js hard-codes
 * matchMedia('(min-width: 1024px)') to reset the mobile nav, and 30-sheet.css
 * switches the sheet gutter at the same width. Three files, one number.
 * The parity gate measures 390 / 768 / 1366, so 768 behaves as MOBILE on both
 * sites -- which also matches Astra scaling root text to 14.592px at <=768.
 * ========================================================================== */

/* ---- header shell --------------------------------------------------------
 * AT MEASURED (.ast-primary-header-bar, all 8 surfaces x 3 widths):
 *   background #FFFFFF, border-bottom 1px solid #EAEAEA, content height 80px.
 * GF MEASURED (#header): a background IMAGE (the banner), border-radius
 *   10px 10px 0 0, margin-top 20px, height 310px at 1366.
 * Both are expressible as the same rule; the tokens differ. */
.qt-header {
	background-color: var(--qt-header-bg);
	background-image: var(--qt-header-bg-image);
	background-repeat: no-repeat;
	background-position: left top;
	border-bottom: var(--qt-border-w) solid var(--qt-header-border);
	border-radius: var(--qt-header-radius);
	position: relative;
	z-index: 20;
}

.qt-header__inner {
	display: flex;
	align-items: center;
	justify-content: space-between;
	flex-wrap: wrap;
	gap: var(--qt-space-3);
	max-width: var(--qt-measure);
	margin-inline: auto;
	padding-inline: var(--qt-gutter);
	min-height: var(--qt-header-h-mobile);
}

/* flex-wrap is a MOBILE declaration and it is load-bearing there: .qt-nav asks
 * for `flex: 1 1 100%; order: 3` so the open panel can take a line of its own
 * under the brand and the toggle. In a nowrap row that 100% basis is
 * unreachable and the panel is squeezed onto the toggle's line instead.
 *
 * It goes back to nowrap at >=1024 ON PURPOSE, and this is the part that is
 * easy to get wrong. Flex lines are filled from each item's HYPOTHETICAL main
 * size, and .qt-menu--primary is itself a wrap container, so the nav's
 * hypothetical size is the sum of every top-level item on one line. On
 * GlobeFreight that is several times --qt-measure. Allowing a wrap here
 * therefore does NOT hand the nav a tidy second row: the nav overflows line 2
 * on its own and strands .qt-header__cta on a THIRD line. A nav that shares the
 * row beats a phone number sitting alone under it. */
@media (min-width: 1024px) {
	.qt-header__inner {
		flex-wrap: nowrap;
		min-height: var(--qt-header-h);
		padding-inline: var(--qt-gutter-lg);
	}
}

/* ---- brand ---------------------------------------------------------------
 * The colour is --qt-wordmark-ink and NOT --qt-ink-heading, which is what this
 * rule used to read. --qt-ink-heading is the heading ink for the WHITE SHEET;
 * once GlobeFreight's header-bg became #2B2622 it put the wordmark at 1.18:1 on
 * the band, and it could not be flipped to white because the same token paints
 * every h1-h6 in 10-reset, 40-content, 50-components and 60-forms. A token that
 * follows the band is the only thing that serves both surfaces.
 * GF MEASURED #FFFFFF on #2B2622 = 14.97:1. AT is unchanged. */
.qt-brand__link {
	display: inline-flex;
	align-items: center;
	gap: var(--qt-space-2);
	text-decoration: none;
	color: var(--qt-wordmark-ink);
}

.qt-brand__link:hover,
.qt-brand__link:focus {
	text-decoration: none;
}

.qt-brand__logo {
	display: block;
	/* HEIGHT is the binding constraint inside a band; width follows from the
	 * aspect ratio. Width-only capping rendered GlobeFreight's 1303x569 artwork
	 * 350x153 inside a 115px header. max-width stays as the secondary guard for
	 * a squat logo, and `width:auto` stops a wide one being squashed. */
	max-height: var(--qt-logo-max-h-mobile);
	max-width: var(--qt-logo-max-w);
	width: auto;
	height: auto;
	/* The artwork is supplied on its own opaque ground matched to --qt-header-bg.
	 * Should a transparent version ever replace it, nothing here needs to change. */
	object-fit: contain;
}

/* The text wordmark is what BOTH sites render until D5's cleared artwork
 * exists. R7: GlobeFreight's current logo has "a division of IC-Express" baked
 * into the artwork, which CLAUDE.md forbids publishing -- so this is not a
 * placeholder, it is the shipping state for GF until the owner approves a
 * replacement. Style it properly. */
/* MOBILE-FIRST, and the smaller size here is a MEASUREMENT, not taste.
 *
 * At --qt-fs-h3 (24px) with white-space:nowrap, "AutoTransport" is ~165px. Add
 * the 44px toggle, a nowrap phone number at ~110px, two --qt-space-3 gaps and
 * 2x --qt-gutter of padding and the row needs ~399px inside a 390px viewport.
 * flex-wrap then strands .qt-header__cta on a line of its own -- the same
 * failure the desktop nowrap comment above describes, arriving from the other
 * direction. --qt-fs-h4 buys ~27px and the row fits.
 *
 * GlobeFreight is unaffected: its brand renders artwork, and .qt-brand__logo is
 * capped by --qt-logo-max-h-mobile rather than by this rule. */
.qt-brand__wordmark {
	font-family: var(--qt-font-heading);
	font-size: var(--qt-fs-h4);
	font-weight: var(--qt-fw-heading);
	line-height: 1.1;
	letter-spacing: var(--qt-ls-heading);
	text-transform: none;
	color: inherit;
	white-space: nowrap;
}

@media (min-width: 1024px) {
	.qt-brand__wordmark {
		font-size: var(--qt-fs-h3);
	}
}

/* ---- primary nav ---------------------------------------------------------
 * Mobile first: the nav is a panel that nav.js opens. Desktop (>=1024px) it is
 * an inline row. AT MEASURED a.menu-link: padding 0 16px, line-height 80px,
 * font-size 16px, colour #111111, hover #C2431C, current #045CB4.
 * GF MEASURED .menu-primary: a #F0F0F0 gradient pill, border-radius 5px,
 * box-shadow 0 0 10px #323232, height/line-height 43px, item colour #5D5D5D,
 * item padding 0 60px. Both are the same rule with different tokens. */
.qt-nav {
	display: none;
	flex: 1 1 100%;
	order: 3;
}

.qt-nav.is-open {
	display: block;
}

.qt-menu--primary {
	list-style: none;
	margin: 0;
	padding: 0;
	background-color: var(--qt-nav-bg);
	background-image: var(--qt-nav-bg-image);
	border-radius: var(--qt-nav-radius);
	box-shadow: var(--qt-nav-shadow);
	font-size: var(--qt-fs-nav);
	font-weight: var(--qt-fw-nav);
}

.qt-menu--primary li {
	position: relative;
	list-style: none;
}

/* Padding gives a >= 24x24 target measured UNIONED WITH THE LABEL. At the
 * mobile size the block padding alone clears 44px. */
.qt-menu--primary a {
	display: block;
	padding: var(--qt-space-2) var(--qt-gutter);
	color: var(--qt-nav-ink);
	text-transform: var(--qt-nav-transform);
	text-decoration: none;
	min-height: var(--qt-control-min);
	transition: var(--qt-transition);
}

/* Two signals, one rule. AutoTransport MEASURED changes the INK (#111111 ->
 * #C2431C on hover, #045CB4 when current) and leaves the background alone.
 * GlobeFreight's heritage nav does the opposite: the ink stays #5D5D5D and
 * li:hover paints a horizontal grey gradient. Both sites supply both tokens,
 * so neither site carries a rule the other has to fight. */
.qt-menu--primary a:hover,
.qt-menu--primary a:focus-visible {
	color: var(--qt-nav-ink-hover);
	background-image: var(--qt-nav-bg-hover);
	text-decoration: none;
}

.qt-menu--primary .current-menu-item > a,
.qt-menu--primary .current_page_item > a,
.qt-menu--primary .current-menu-ancestor > a {
	color: var(--qt-nav-ink-current);
	background-image: var(--qt-nav-bg-current);
}

@media (min-width: 1024px) {

	/* Desktop gets the full cap. This file is MOBILE-FIRST, so the base rule
	 * above carries --qt-logo-max-h-mobile and this overrides it -- putting
	 * the desktop value in the base rule would render a 64px logo inside a
	 * 64px mobile bar with zero clearance. */
	.qt-brand__logo {
		max-height: var(--qt-logo-max-h);
	}

	.qt-nav {
		display: block;
		flex: 0 1 auto;
		order: 0;
	}

	.qt-menu--primary {
		display: flex;
		flex-wrap: wrap;
		align-items: center;
		justify-content: flex-end;
	}

	/* The chevron belongs BESIDE its label, not under it. At >=1024
	 * .qt-submenu-toggle drops to position:static, and the <a> ahead of it is
	 * display:block, so inside a block <li> the button is pushed onto a line of
	 * its own -- one dead 8px row per parent item, on both sites.
	 *
	 * Direct children ONLY. `.qt-menu--primary li` would also catch the
	 * .sub-menu items, and a flex row there lays the dropdown's links out
	 * side-by-side instead of stacking them. Mobile is untouched: the toggle is
	 * position:absolute below 1024 and needs the <li> to stay a block box for
	 * the <a> to fill. */
	.qt-menu--primary > li {
		display: flex;
		align-items: center;
	}

	/* Pulling the chevron up beside the label costs the <a> its full-width
	 * block box, so a:hover no longer paints under the button -- a ~18px
	 * unpainted notch on every parent item, and only on the sites that signal
	 * hover with a background. Paint the ITEM, which is what GlobeFreight's
	 * heritage nav MEASURED does anyway (li:hover lays a horizontal grey
	 * gradient; the ink stays #5D5D5D). Free on AutoTransport, which signals
	 * hover by ink and supplies --qt-nav-bg-hover: none. Focus stays on the
	 * anchor's :focus-visible rule -- :focus-within here would also fire on a
	 * mouse click, which is the distinction that rule exists to keep. */
	.qt-menu--primary > li:hover {
		background-image: var(--qt-nav-bg-hover);
	}

	/* white-space: no-op on a nav that fits. Where the row IS too narrow the
	 * menu is meant to break BETWEEN items -- .qt-menu--primary already carries
	 * flex-wrap -- rather than split a two-word label down the middle and take
	 * the height of the whole bar with it. */
	.qt-menu--primary > li > a {
		padding: var(--qt-nav-item-pad);
		line-height: var(--qt-lh-nav);
		white-space: nowrap;
	}
}

/* Depth-2 submenu. 17 items on both sites; the heritage nav had dropdowns.
 * On mobile the submenu is a disclosure driven by nav.js's real <button>;
 * on desktop it is an absolutely positioned panel opened by hover OR by the
 * same button, so keyboard and touch both work. Hover alone is not reachable. */
.qt-menu--primary .sub-menu {
	list-style: none;
	margin: 0;
	padding: 0;
	display: none;
	background-color: var(--qt-submenu-bg);
	border: var(--qt-border-w) solid var(--qt-submenu-border);
	border-radius: var(--qt-radius);
	box-shadow: var(--qt-submenu-shadow);
}

.qt-menu--primary li.is-open > .sub-menu {
	display: block;
}

.qt-menu--primary .sub-menu a {
	padding-inline-start: calc(var(--qt-gutter) * 2);
}

@media (min-width: 1024px) {

	.qt-menu--primary .sub-menu {
		position: absolute;
		inset-block-start: 100%;
		inset-inline-start: 0;
		min-width: 220px;
		z-index: 30;
	}

	.qt-menu--primary li:hover > .sub-menu,
	.qt-menu--primary li:focus-within > .sub-menu {
		display: block;
	}

	.qt-menu--primary .sub-menu a {
		padding: var(--qt-space-2) var(--qt-gutter);
		line-height: normal;
	}
}

/* nav.js injects this button before every .sub-menu.
 *
 * `color: inherit` was wrong the moment a header band stopped matching the
 * page: the button's ancestors up to <body> paint no colour, so the chevron
 * inherited --qt-ink (#333333) rather than the nav ink beside it -- 1.18:1 on
 * GlobeFreight's #2B2622 band. At >=1024 it is pointer-events:none decoration
 * and the cost is only cosmetic, but BELOW 1024 it is the real disclosure
 * control for GF's three submenus, and an invisible control is a defect, not a
 * detail. --qt-nav-ink is by definition legible on --qt-nav-bg. */
.qt-submenu-toggle {
	position: absolute;
	inset-block-start: 0;
	inset-inline-end: 0;
	width: 44px;
	height: 44px;
	background: transparent;
	border: 0;
	cursor: pointer;
	color: var(--qt-nav-ink);
}

.qt-submenu-toggle::before {
	content: "";
	display: block;
	width: 8px;
	height: 8px;
	margin: 0 auto;
	border-inline-end: 2px solid currentColor;
	border-block-end: 2px solid currentColor;
	transform: rotate(45deg);
	transition: var(--qt-transition);
}

.qt-submenu-toggle[aria-expanded="true"]::before {
	transform: rotate(-135deg);
}

@media (min-width: 1024px) {
	.qt-submenu-toggle {
		position: static;
		width: auto;
		height: auto;
		padding: 0 var(--qt-space-1);
		pointer-events: none;
	}
}

/* An image used AS a menu label. nav-walker.php rebuilds GlobeFreight item
 * #138's raw <img> title into this element rather than printing it as literal
 * text. It has to be styled or the fix trades one visible defect for another. */
.qt-menu__img {
	display: inline-block;
	max-height: 1.5em;
	width: auto;
	vertical-align: middle;
}

/* ---- mobile toggle -------------------------------------------------------
 * 44x44 -- above the 24x24 WCAG 2.2 floor and at Apple HIG comfort. */
.qt-nav-toggle {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 44px;
	height: 44px;
	padding: 0;
	background: transparent;
	border: 0;
	color: var(--qt-nav-ink);
	cursor: pointer;
}

.qt-nav-toggle__bar,
.qt-nav-toggle__bar::before,
.qt-nav-toggle__bar::after {
	display: block;
	width: 22px;
	height: 2px;
	background-color: currentColor;
	transition: var(--qt-transition);
}

.qt-nav-toggle__bar {
	position: relative;
}

.qt-nav-toggle__bar::before,
.qt-nav-toggle__bar::after {
	content: "";
	position: absolute;
	inset-inline-start: 0;
}

.qt-nav-toggle__bar::before { inset-block-start: -7px; }
.qt-nav-toggle__bar::after  { inset-block-start: 7px; }

.qt-nav-toggle[aria-expanded="true"] .qt-nav-toggle__bar {
	background-color: transparent;
}

.qt-nav-toggle[aria-expanded="true"] .qt-nav-toggle__bar::before {
	inset-block-start: 0;
	transform: rotate(45deg);
}

.qt-nav-toggle[aria-expanded="true"] .qt-nav-toggle__bar::after {
	inset-block-start: 0;
	transform: rotate(-45deg);
}

@media (min-width: 1024px) {
	.qt-nav-toggle {
		display: none;
	}
}

/* ---- header CTA ---------------------------------------------------------
 * RETRACTION: an earlier revision of this comment said "both are empty today
 * pending the owner, so this selector matches nothing on either site". That
 * stopped being true when the numbers landed -- AT brand.php carries
 * 086 9990 559 and GF carries the owner-supplied number -- and the block below
 * shipped to two live headers with no rules at all behind it.
 *
 * It is the third child of a space-between row, so the only thing it needs is
 * to hold its own: the number is white-space:nowrap, so a shrunk box would not
 * reflow it, it would spill it. flex: 0 0 auto is what keeps the nav, not the
 * phone, absorbing the squeeze. */
.qt-header__cta {
	display: flex;
	align-items: center;
	gap: var(--qt-space-2);
	flex: 0 0 auto;
}

/* Same story as the wordmark, one step worse. This read --qt-accent, which is
 * the submit-button BACKGROUND in five places -- so it cannot be lightened to
 * clear the band without changing the colour of every button on both sites. On
 * GF's #2B2622 the raw accent #F1592A measures 4.42:1 and FAILS AA; the
 * band-scoped token carries #F26A3F at 4.92:1 instead. AT is unchanged. */
.qt-header__phone {
	display: inline-flex;
	align-items: center;
	/* A phone number IS a tap target, and it was not one. WCAG 2.2 SC 2.5.8
	 * measures the target unioned with the label: a 16px line of text is ~19px
	 * tall, under the 24px floor. This is the single most-tapped thing in the
	 * header on a phone, so it gets HIG comfort rather than the bare floor. */
	min-height: 44px;
	font-weight: var(--qt-fw-heading);
	color: var(--qt-phone-ink);
	white-space: nowrap;
	text-decoration: none;
}

.qt-header__phone:hover,
.qt-header__phone:focus-visible {
	text-decoration: underline;
}

/* ---- the header quote CTA ------------------------------------------------
 * The header carried a phone and no quote action at all, on a site whose whole
 * purpose is collecting quote requests. NN/g's hidden-navigation study is the
 * argument for putting it here rather than only in the menu: hiding an action
 * roughly halves the chance it is used, and this is THE action.
 *
 * It composes .qt-btn--primary from 50-components.css rather than restating
 * those values -- one home for what a primary button looks like. Only the
 * PLACEMENT lives here.
 *
 * Renders only when brand.php supplies quote_url, so a site that has not set
 * one ships no empty button. GlobeFreight is therefore unaffected until its
 * brand.php gains the key -- the same safe-degrade the phone block uses. */
.qt-header__quote {
	/* Below 1024 it takes a full-width line of its own UNDER the brand row.
	 * The alternative -- squeezing it inline -- needs ~447px of content in a
	 * 390px viewport, so something would wrap anyway; better to choose WHAT
	 * wraps than to let flex decide. A permanently visible primary action is
	 * also what the competitor teardown found in the sites that convert. */
	order: 4;
	flex: 1 1 100%;
	justify-content: center;
}

@media (min-width: 1024px) {
	.qt-header__quote {
		order: 0;
		flex: 0 0 auto;
	}
}

/* ---- footer --------------------------------------------------------------
 * THE FOOTER SETS ITS OWN BACKGROUND ON THE FOOTER ELEMENT. That is the whole
 * point of the child theme owning the chrome.
 *
 * MEASURED on AutoTransport: footer#colophon itself computes rgba(0,0,0,0);
 * the #2B2622 band is painted by Astra's INNER footer-builder rows
 * (.site-primary-footer-wrap / .site-below-footer-wrap), and those rows do not
 * render at all on the four classic surfaces (404, search, page 79, post 158).
 * So classic and Elementor surfaces do not match today -- kit CSS is absent on
 * the classic templates, which the plan confirms visually.
 *
 * NOTE, AND THIS MATTERS: the automated claim that AutoTransport's footer text
 * renders "white on white at 1:1" on those surfaces was RETRACTED. A rendered
 * screenshot (at-classic-footer-check.png, 2026-08-06) shows white text on a
 * dark band, perfectly readable. The harvester scored the OUTER <p>/<div>,
 * whose computed colour is the inherited body ink, while the visible text is
 * inside child spans that hardcode color:#ffffff. Painting the background on
 * the footer element is a CONSOLIDATION -- one rule, both surfaces, no
 * dependency on Astra's builder rows -- not a repair of a defect that exists.
 *
 * Do not "fix" AutoTransport's footer-html-1 / footer-html-2 /
 * footer-copyright-editor widgets. Against a dark footer their hardcoded white
 * is correct, and it renders correctly today. */

/* TWO LAYERS, AND THE SPLIT IS THE FIX.
 *
 * footer#colophon is a SIBLING of #content, so it lands OUTSIDE .qt-container
 * -- the white sheet from 30-sheet.css. Painting the band on the footer
 * ELEMENT therefore bled it edge-to-edge under a sheet that stops at
 * --qt-measure, and on GlobeFreight the result reads as a slab dropped on the
 * bare texture rather than the bottom of the card. Heritage had it the other
 * way round: #footer-widgets lived INSIDE #wrap. The measured tokens say the
 * same thing out loud -- a full-bleed viewport band does not carry
 * border-radius:5px and box-shadow:0 0 10px #323232; an inset card does.
 *
 * So .qt-footer is now the SHEET GROUND (--qt-sheet at --qt-measure) and
 * .qt-footer__inner is the BAND (every footer token it used to hold). The band
 * already had max-width:--qt-measure, so it fills the ground exactly and the
 * white shows only in the two TOP corners, where the band's own radius rounds
 * away from a square-topped ground -- which is the join heritage had, and which
 * is what welds this element to the sheet stopping directly above it.
 *
 * The ground's BOTTOM corners take --qt-footer-radius, not --qt-sheet-radius,
 * and that is not a slip: GF measures the sheet at 10px and the footer box at
 * 5px, so a 10px ground under a 5px band leaves the band's corners poking
 * outside the curve. overflow:hidden would fix it and would also clip
 * --qt-footer-shadow (MEASURED 0 0 10px #323232), which is the more visible
 * loss. Matching the two radii costs nothing on either site -- AT is 0/0.
 *
 * On AutoTransport the band is square and opaque, so the ground never shows at
 * all and the only change there is that the dark bar now stops at 1240px
 * instead of at the viewport edge.
 *
 * Not done in PHP. chrome-footer.php's closing order (.ast-container/#content
 * then #page) is load-bearing for Astra's five non-Elementor surfaces, and
 * nothing here needs the footer moved inside #content to work. */
.qt-footer {
	max-width: var(--qt-measure);
	margin-inline: auto;
	background-color: var(--qt-sheet);
	border-radius: 0 0 var(--qt-footer-radius) var(--qt-footer-radius);
	color: var(--qt-footer-ink);
}

.qt-footer__inner {
	max-width: var(--qt-measure);
	margin-inline: auto;
	padding-inline: var(--qt-gutter);
	padding-block: var(--qt-space-5) var(--qt-space-3);
	background-color: var(--qt-footer-bg);
	background-image: var(--qt-footer-bg-image);
	border-top: var(--qt-border-w) solid var(--qt-footer-rule);
	border-radius: var(--qt-footer-radius);
	box-shadow: var(--qt-footer-shadow);
	display: flex;
	flex-direction: column;
	gap: var(--qt-space-3);
}

@media (min-width: 1024px) {
	.qt-footer__inner {
		padding-inline: var(--qt-gutter-lg);
	}
}

/* MEASURED AT: footer link and footer svg both #FFFFFF on #2B2622 -- 14.97:1.
 * MEASURED GF: #footer-widgets a is #5397B4 on the #F0F0F0 gradient -- 2.86:1,
 * which FAILS AA. That failure is present in the heritage target AND on the
 * live site; it is pre-existing, not introduced here, and the plan says decide
 * it explicitly rather than silently. It is NOT silently fixed here: GF's
 * brand.php ships the measured #5397B4 and the exception is documented. */
.qt-footer a {
	color: var(--qt-footer-link);
	text-decoration: none;
}

.qt-footer a:hover,
.qt-footer a:focus {
	color: var(--qt-footer-link);
	text-decoration: underline;
}

/* currentColor keeps the social icons matched to the footer ink on both sites
 * -- AT MEASURED #colophon svg { fill: currentColor } and #FFFFFF at 14.97:1. */
.qt-footer svg {
	fill: currentColor;
}

/* The focus ring is an ink colour, which is invisible on AT's dark footer.
 * Re-point it to the footer ink here rather than weakening the global rule. */
.qt-footer :focus-visible {
	outline-color: var(--qt-footer-ink);
}

.qt-menu--footer {
	display: flex;
	flex-wrap: wrap;
	gap: var(--qt-space-2) var(--qt-space-3);
	list-style: none;
	margin: 0;
	padding: 0;
}

.qt-menu--footer a {
	display: inline-block;
	padding-block: var(--qt-space-1);
	min-height: var(--qt-control-min);
}

/* Gate: zero href="#" in the footer. That is a served-HTML grep, not a CSS
 * concern -- noted here because this is where someone would look. */

/* Footer sitemap -- the headed link columns from brand.php['footer_link_groups'].
 * Distinct from .qt-footer__cols below: that grid is WIDGET areas and its column
 * count is a token because it is MEASURED per site. This one is navigation the
 * theme owns, so the count is not a token at all -- auto-fit means a site can add
 * or drop a group in brand.php without touching this file or inventing a
 * --qt-sitemap-cols nobody measured.
 *
 * No template below 1024: a bare `display: grid` stacks every group full-width,
 * which is what a thumb wants and what the 390 parity viewport measures. */
.qt-footer__sitemap {
	display: grid;
	gap: var(--qt-space-3);
}

@media (min-width: 1024px) {
	.qt-footer__sitemap {
		grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
	}
}

.qt-footer__links {
	list-style: none;
	margin: 0;
	padding: 0;
}

/* The 24px floor is WCAG 2.2 SC 2.5.8; a 15px line plus 5px padding-block
 * clears it at 25px.
 *
 * .qt-footer__col a is in this rule because WIDGET content was the gap. The
 * footer menu had the treatment and the sitemap gets it by construction, but a
 * link typed into a text widget got nothing -- MEASURED at 20px in a headless
 * render at all three parity viewports, which is under the floor. GlobeFreight's
 * phone number and its only email link are both exactly that, so the two most
 * valuable targets in the footer were the two that missed. Widget markup is
 * arbitrary and owner-edited, so the floor has to come from here; it cannot be
 * left to whoever writes the widget. */
.qt-footer__links a,
.qt-footer__col a {
	display: inline-block;
	padding-block: var(--qt-space-1);
	min-height: var(--qt-control-min);
}

/* Footer columns. AT renders 1, GF renders 3 (.footer-widgets-1/2/3 in the
 * heritage markup, carrying the Visa-Mastercard composite badge in column 1
 * and a Facebook like-box iframe in column 3 -- NOT a trust badge, that claim
 * was refuted). The count is a token so the grid stays byte-identical. */
.qt-footer__cols {
	display: grid;
	gap: var(--qt-space-3);
}

@media (min-width: 1024px) {
	.qt-footer__cols {
		grid-template-columns: repeat(var(--qt-footer-cols), minmax(0, 1fr));
	}

	/* --qt-footer-cols is the REGISTERED count. The RENDERED count is decided
	 * per request: quadtech_render_footer_widgets() emits a .qt-footer__col only
	 * for a sidebar is_active_sidebar() says has something in it. GlobeFreight
	 * registers three and fills two (qt-footer-3 is empty), so the badge and the
	 * contact block were being laid out across two thirds of the footer with a
	 * dead third track holding the remainder. Collapse to what actually
	 * rendered.
	 *
	 * :has() takes the specificity of its argument, so these beat the rule above
	 * wherever they match, order notwithstanding. Where :has() is unsupported
	 * the grid falls back to the registered count -- today's behaviour, not a
	 * worse one. repeat(auto-fit, minmax(0, 1fr)) is NOT the shorter way to
	 * write this: auto-fit resolves its repetition count from a definite track
	 * size, and a 0 minimum makes that count infinite, so the whole declaration
	 * is invalid. */
	.qt-footer__cols:has(> .qt-footer__col:nth-child(1):last-child) {
		grid-template-columns: minmax(0, 1fr);
	}

	.qt-footer__cols:has(> .qt-footer__col:nth-child(2):last-child) {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

/* min-width:0 on both, or a long unbroken string in one cell refuses to shrink
 * and the whole grid overflows. That is the 390 horizontal-overflow gate. */
.qt-footer__col,
.qt-footer__group {
	min-width: 0;
}

/* `color: inherit` is load-bearing, not tidiness: 10-reset paints every h1-h6
 * --qt-ink-heading, which is #333333 on BOTH sites, and AutoTransport's footer
 * band is dark. Inheriting picks up --qt-footer-ink instead. A sitemap heading
 * and a widget heading sit side by side in the same band, so they read the same
 * token rather than drifting apart. */
.qt-widget__title,
.qt-footer__group-title {
	font-size: var(--qt-fs-h4);
	color: inherit;
	margin-block-end: var(--qt-space-2);
}

.qt-footer__legal {
	border-top: var(--qt-border-w) solid var(--qt-footer-rule);
	padding-block-start: var(--qt-space-3);
	font-size: var(--qt-fs-small);
	text-align: center;
}
