/* =============================================================================
 * 60-forms.css -- form styling. The highest-risk file in this theme.
 *
 * BYTE-IDENTICAL across both sites.
 *
 * *** THE ONE RULE: EVERY SELECTOR IN THIS FILE IS SCOPED. ***
 *
 * Never `input`. Never `select`. Never `textarea`. Never `label`. Never
 * `button`. Not once, not "just for the reset", not inside a media query.
 *
 * Why this is not pedantry:
 *   - Gravity Forms 1.8.18 is a ~2014 plugin on the legacy rg_* schema. It
 *     renders AutoTransport's money form, which converts ~40% of the ten
 *     people who reach it in a quarter. There is REAL PERFORMANCE TO PROTECT
 *     here -- this is the one form on either site that demonstrably works.
 *   - A bare `input` rule reaches Gravity, Forminator, ElementsKit, Royal
 *     Addons, the search form, the comment form and wp-admin's front-end
 *     surfaces simultaneously. The failure is silent and site-wide.
 *   - The non-regression gate is playwright-form-fieldcount.cjs against banked
 *     baselines: /car-transport/ 13/23, /boat-transport/ 17/25,
 *     /commercial-vehicle-transport/ 19/23,
 *     /construction-machinery-transport/ 21/23, /track-vehicle/ 31/12.
 *     Run it after ANY chrome change, not just after form changes.
 *
 * Allowed scopes, exhaustively:
 *   .gform_wrapper      Gravity Forms (AutoTransport)
 *   .forminator-ui      Forminator (both sites)
 *   .qt-form            our own form markup
 *   .qt-form-frame      the same-origin iframe wrapper
 *   .qt-searchform      handled in 50-components.css, not here
 * ========================================================================== */


/* ==========================================================================
 * GRAVITY FORMS -- AutoTransport only.
 *
 * THE CORRECT AMOUNT OF CSS HERE IS ALMOST ZERO, AND THAT IS THE DELIVERABLE.
 *
 * AT's pass condition is an EMPTY DIFF. The live Gravity form already renders
 * the way the owner approved, inside the white sheet, and it converts. Every
 * declaration added below is a chance to move it. So this block sets flow
 * spacing and NOTHING ELSE -- no control sizing, no colours, no font-size.
 *
 * TWO MEASURED DEFECTS ARE DELIBERATELY *NOT* FIXED HERE:
 *   1. input#input_2_1 computes font-size 11px at 390/768/1366. Below 16px
 *      iOS zooms the viewport on focus -- on the 40%-converting money form.
 *   2. input#gform_submit_button_2 is #046BD2 Astra blue, never rebranded,
 *      against a site whose CTA is #C2431C.
 * Both are real. Both belong to WS3, made deliberately, one at a time, with
 * playwright-form-fieldcount.cjs and the banked conversion baseline either
 * side of the change. Smuggling them into the chrome port would mean a
 * conversion regression and a look regression land in the same commit with no
 * way to tell which caused what.
 * ========================================================================== */

.gform_wrapper {
	margin-block: var(--qt-space-4);
}

/* Gravity 1.8 lays its fields out with a <ul> carrying inline widths. Its
 * markup predates flexbox by years and changing `display` here collapses the
 * whole form. Reset the list bullets the theme's own `ul` margin would
 * otherwise introduce, and stop. */
.gform_wrapper .gform_fields {
	list-style: none;
	margin: 0;
	padding: 0;
}

.gform_wrapper .gfield_label {
	font-family: var(--qt-font-body);
	color: var(--qt-ink-heading);
}

/* The required asterisk. --qt-error is a red on both sites; on the white sheet
 * AT's #B91C1C is 6.4:1 and GF's is the same value, both clearing AA. */
.gform_wrapper .gfield_required {
	color: var(--qt-error);
}

/* Validation copy MUST pass AA on --qt-sheet -- a validation message nobody
 * can read is a lost lead, which is the same failure R1 exists to prevent. */
.gform_wrapper .validation_message,
.gform_wrapper .gfield_description.validation_message {
	color: var(--qt-error);
}

/* No .gform_wrapper input / select / textarea / submit rule exists in this
 * file. That absence is the deliverable. Do not "complete" it. */


/* ==========================================================================
 * FORMINATOR -- both sites. AT 1.55.1, GF 1.56.0.
 *
 * Stays registered for 30 days after each cutover, so it is live on money
 * pages the whole time and must look like the site. Unlike Gravity there is
 * nothing to protect: GlobeFreight's five Forminator forms are BARE (one
 * lifetime entry across all of them), so styling them is a strict improvement
 * with no baseline to regress.
 * ========================================================================== */

/* THE CASCADE FACT THAT GOVERNS THIS WHOLE SECTION, measured 2026-08-12 on
 * globefreight.co.za (Forminator 1.56.2, modules 315 and 317):
 * quadtech-60-forms-css is enqueued BEFORE all eight Forminator stylesheets --
 * the per-form generated `uploads/forminator/.../style-NNN.css` first, then
 * icons, utilities, grid.open, form-default.base, .select2 and .full. So on a
 * specificity TIE Forminator wins, and every declaration below was checked
 * against those eight before it was written. Three consequences:
 *   1. LAYOUT IS NOT OURS. `.forminator-row{display:flex}`,
 *      `.forminator-col{flex:1;padding:0 15px}` and
 *      `[data-design=default] .forminator-input{width:100%;box-sizing:border-box}`
 *      already do it, from a sheet that loads after us. No row/col/grid rule
 *      and no width rule appears in this file. Adding one only starts a fight
 *      we lose.
 *   2. ANYTHING THE PER-FORM SHEET SETS IS ID-LOCKED. Its selectors read
 *      `.forminator-ui#forminator-module-317.forminator-design--default X`
 *      -- (1,4,0), and NNN differs per form AND per site, so a shared
 *      stylesheet can never match it. Those values are Forminator Design-tab
 *      settings, not CSS ones; change them there.
 *   3. What is left is genuinely uncontested, and that is what is styled here.
 *
 * Card treatment, and the two things it deliberately does NOT do.
 * background-color, padding and box-shadow are set by nothing in any of the
 * eight sheets, so they land at (0,1,0) and give the form the same panel
 * `.qt-card` builds in 50-components.css. Forminator supplies `width:100%`
 * and `box-sizing:border-box` here, so the padding stays inside the column and
 * we set no width of our own.
 *
 * THERE IS NO `border` AND NO `border-radius` BELOW, and that is measured, not
 * forgotten. The per-form sheet opens with a bare ID rule --
 *   #forminator-module-317{border-width:0;border-style:none;border-radius:0}
 * -- which is (1,0,0) against our (0,1,0) and loads after us. A `border`
 * shorthand here would ship border-COLOR with zero width and no style: a token
 * that reads as applied and renders as nothing, which is exactly the
 * half-styled element 00-tokens.css warns about. So the edge is drawn with an
 * inset box-shadow instead -- uncontested on this element in all states -- and
 * --qt-card-radius is left unused because the corners are pinned square at the
 * form's own id. The sheet carries the site's radius; the panel inside it does
 * not need one.
 *
 * `margin-block` is INERT today and is kept only as the value we would want:
 * `.forminator-ui.forminator-custom-form[data-design=default]{margin:30px 0}`
 * is (0,3,0) and loads after us. Do not "fix" the form's outer spacing here --
 * it is not what renders. */
.forminator-ui {
	margin-block: var(--qt-space-4);
	padding: var(--qt-gutter);
	background-color: var(--qt-card-bg);
	box-shadow: inset 0 0 0 var(--qt-border-w) var(--qt-card-border);
	font-family: var(--qt-font-body);
}

.forminator-ui .forminator-label {
	font-family: var(--qt-font-body);
	font-weight: var(--qt-fw-heading);
	color: var(--qt-ink-heading);
}

/* WHY THERE IS NO `select.forminator-select2` BRANCH HERE any more (removed
 * 2026-08-12): select2 does not REPLACE the native <select>. It INSERTS A
 * SIBLING -- <span class="forminator-select select2 select2-container"> -- and
 * leaves the native element in the DOM, clipped and screen-reader-only. So a
 * rule on `select.forminator-select2` paints an element nobody can see.
 * Forminator's own generated CSS states the mechanism in its selectors:
 *   select.forminator-select2 + .forminator-select .selection
 *   .select2-selection--single[role="combobox"] { border-color:#777771 }
 * Removing it changed nothing visually. Do not re-add it.
 *
 * OPEN, MEASURED, DELIBERATELY NOT ACTED ON -- `.forminator-select` below is
 * that inserted span, i.e. the select2 CONTAINER, not the painted control. The
 * painted control is `.select2-selection--single|--multiple[role="combobox"]`
 * inside it, and its border/background/ink are ID-locked by the per-form sheet
 * at (1,5,0) -- the `.forminator-title` trap again. So on the one live form
 * that has a select (GF module 317, `forminator-select2-multiple`) the border
 * below draws a SECOND box around select2's own. Dropping `.forminator-select`
 * from this block is a live rendering change on a quote form, so it is flagged
 * for a per-change go-ahead rather than smuggled into a chrome commit.
 *
 * How much of this block actually renders, for whoever reads it next:
 *   background-color, color, border-COLOR  land (nothing else sets them)
 *   min-height, padding, border-width/style, border-radius  are overridden by
 *     `[data-design=default] .forminator-input` at (0,4,0) -- unset/9px/1px/2px
 *   font-size is overridden by the per-form sheet's 16px at (1,3,0); that
 *     happens to sit exactly on the --qt-fs-input iOS-zoom floor, so it is not
 *     worth fighting. font-family is overridden by that sheet's `inherit`,
 *     which then inherits --qt-font-body off `.forminator-ui` above -- the
 *     brand font arrives by inheritance, not by this declaration. */
.forminator-ui .forminator-input,
.forminator-ui .forminator-textarea,
.forminator-ui .forminator-select {
	min-height: var(--qt-control-h);
	padding: var(--qt-control-pad);
	border: var(--qt-border-w) solid var(--qt-input-border);
	border-radius: var(--qt-radius);
	background-color: var(--qt-input-bg);
	color: var(--qt-input-ink);
	font-family: var(--qt-font-body);
	font-size: var(--qt-fs-input);
}

.forminator-ui .forminator-button-submit {
	min-height: var(--qt-control-h);
	padding: var(--qt-control-pad);
	background-color: var(--qt-accent);
	border: var(--qt-border-w) solid var(--qt-accent);
	border-radius: var(--qt-radius);
	color: var(--qt-accent-contrast);
	font-family: var(--qt-font-body);
	font-size: var(--qt-fs-base);
	font-weight: var(--qt-fw-heading);
	cursor: pointer;
	transition: var(--qt-transition);
}

.forminator-ui .forminator-button-submit:hover,
.forminator-ui .forminator-button-submit:focus-visible {
	background-color: var(--qt-accent-dark);
	text-decoration: underline;
}

/* Help text under a label. `color` is set by nothing in any of the eight
 * sheets, so this lands at (0,2,0). Its font-size is NOT set here: the
 * per-form sheet pins 12px at (1,3,0) and would win. */
.forminator-ui .forminator-description {
	color: var(--qt-ink-muted);
}

/* ---- checkboxes ----------------------------------------------------------
 * Live markup:  <label class="forminator-checkbox">
 *                 <input type="checkbox">            clipped, by !important
 *                 <span class="forminator-checkbox-box" aria-hidden="true">
 *                 <span class="forminator-checkbox-label">Stackable?</span>
 *
 * THE BOX IS NOT OURS TO PAINT, and no rule for it appears below on purpose.
 * Its border-color, fill and check colour come from
 *   .forminator-ui#forminator-module-317.forminator-design--default
 *   .forminator-checkbox .forminator-checkbox-box{border-color:#777771;
 *   background-color:#EDEDED;color:#097BAA}
 * -- (1,4,0), loading after us, with a different module id per form and per
 * site. Input- or accent-token rules aimed at it would be dead bytes on both
 * sites. It is a Design-tab value; change it there, as with the section title.
 *
 * The label span IS reachable, and it is the half of the control that matters
 * for WCAG 2.2 SC 2.5.8, which this theme measures on the target UNIONED WITH
 * THE LABEL (same rule as .qt-form__tile below). Forminator makes the row
 * `pointer-events:none` and hands `pointer-events:all` to these spans, so the
 * spans ARE the target: the box is 20x20 and pinned at (0,6,0), the label is
 * where the 24px floor can actually be set. Note the label keeps `display:
 * block` from `.forminator-checkbox span` at (0,4,0), so its 20px line-height
 * sits 2px above centre inside the 24px box -- accepted, because out-specifying
 * a rule that is doing no harm costs more than 2px is worth. */
.forminator-ui .forminator-checkbox-label {
	min-height: var(--qt-control-min);
	color: var(--qt-ink);
}

/* ---- file upload ---------------------------------------------------------
 * <button class="forminator-button forminator-button-upload">Choose File</button>
 *
 * MEASURED: the per-form sheet gives this button type only. `.forminator-button`
 * at (0,4,0) gives it geometry and then ZEROES its edges -- `border:0`,
 * `box-shadow:none` -- and nothing in any of the eight sheets sets
 * background-color or color. So today it renders as the raw user-agent button:
 * an OS-grey slab in the middle of a branded quote form. That is the one
 * genuinely unstyled control on either site.
 *
 * background-color and color are uncontested and would land at (0,2,0); the
 * compound below is (0,5,0) only so the hover/focus pair beneath it can clear
 * `.forminator-button:hover|:focus|:active{text-decoration:none}` at (0,5,0),
 * where a tie would go to Forminator because it loads second. Adding
 * `.forminator-design--default` and [data-design] to the root compound is the
 * SMALLEST way to get there without !important, which this file does not use.
 * All four hooks are on the live <form>; [data-color-option] is deliberately
 * left out so this survives a Design-tab colour-mode change.
 *
 * NO INSET RING HERE, unlike `.forminator-ui` above: Forminator sets
 * `box-shadow:none` on `.forminator-button` again at :hover, :focus AND
 * :active, all (0,5,0), so holding a decorative hairline would cost a
 * four-state specificity chase to stop the edge flickering off under the
 * cursor. Not worth it. --qt-input-bg carries the job instead -- the button
 * then shares its surface with the text inputs stacked above it, and reads as
 * a control on the --qt-card-bg panel rather than dissolving into it.
 *
 * Surface tokens rather than the accent on purpose: this is the secondary
 * action a few hundred pixels above the submit CTA, and two accent-coloured
 * buttons in one form make the visitor choose between them. */
.forminator-ui.forminator-custom-form.forminator-design--default[data-design="default"] .forminator-button-upload {
	background-color: var(--qt-input-bg);
	color: var(--qt-ink-heading);
	transition: var(--qt-transition);
}

/* Underline, not a colour shift -- the affordance every other button in this
 * theme uses (50-components.css), so it survives greyscale and forced-colours
 * and invents no hover shade. `.forminator-button` pins `text-decoration:none`
 * at (0,4,0); the pseudo-class carries this pair to (0,6,0). */
.forminator-ui.forminator-custom-form.forminator-design--default[data-design="default"] .forminator-button-upload:hover,
.forminator-ui.forminator-custom-form.forminator-design--default[data-design="default"] .forminator-button-upload:focus-visible {
	text-decoration: underline;
}

/* ---- focus ---------------------------------------------------------------
 * THERE IS NO FOCUS RULE HERE, AND THAT IS A MEASUREMENT RATHER THAN AN
 * OVERSIGHT. Forminator does kill the focus ring on inputs, textareas, buttons
 * and the select2 combobox -- but every one of those rules is scoped to
 * `[data-color-option=default]`:
 *   .forminator-ui.forminator-custom-form[data-design=default][data-color-option=default]
 *   .forminator-input:focus { outline:0 }
 * Both live forms serve `data-color-option="theme"`, so not one of them
 * matches, and 10-reset.css's `:focus-visible{outline:2px solid
 * var(--qt-focus-ring)}` survives on every control. Adding a ring here would
 * duplicate a rule that already works.
 *
 * RE-CHECK THIS IF ANYONE MOVES A FORM OFF "theme" COLOURS in the Design tab.
 * That single dropdown switches on eight `outline:0` rules at (0,6,0) and
 * silently removes the focus indicator from the entire form -- a WCAG 2.4.7
 * failure that is invisible to a mouse user and does not touch this file.
 *
 * The checkbox box is the one exception: the per-form sheet draws its own
 * `outline:2px solid #254DEB` on `input:focus-visible + .forminator-checkbox-box`
 * at (1,5,0). Visible, so not a defect -- but it is a hardcoded blue rather
 * than --qt-focus-ring, and it is ID-locked out of reach from here.
 *
 * Two more classes are absent for the same ID-lock reason, recorded so nobody
 * re-derives it: `.forminator-required` (the label asterisk) is pinned to
 * #E51919 at (1,4,0), and `.forminator-response-message` -- the success and
 * error banner -- has its background and ink pinned at (1,4,0). Both are
 * Design-tab values. --qt-error is NOT reachable on either. */


/* ==========================================================================
 * QUADTECH FORM -- our own markup, and the same-origin iframe wrapper.
 * ========================================================================== */

/* The 220px MIN-HEIGHT FLOOR is part of the FORM-022 contract and is not
 * negotiable -- it is what stops a zero-height frame on first paint.
 *
 * IT IS A *VISUAL* FLOOR AND NOTHING ELSE. It is NOT the accept threshold for
 * inbound height messages. The kit legitimately sends any height >= 120px, and
 * a parent that rejects everything under 180px silently drops the whole
 * 120-179 band -- including the reference's own ~150px thank-you panel. That
 * would leave a visitor staring at a blank box in the moment after they
 * submitted a lead. The accept threshold lives in _shared/js/form-embed.js and
 * is 120. Two numbers, two jobs; do not merge them.
 *
 * The rest of the contract also lives in form-embed.js: an explicit
 * postMessage (authoritative: true) may grow OR SHRINK the frame while a poll
 * may only grow, which is what stops the post-submit thank-you leaving a blank
 * 2500px box. */
.qt-form-frame {
	display: block;
	width: 100%;
	min-height: 220px;
	border: 0;
	background: transparent;
}

.qt-form {
	font-family: var(--qt-font-body);
	color: var(--qt-ink);
}

/* Step 1 is a TAP, not a keystroke. From the teardown: AutoTransport currently
 * opens with a REQUIRED TEXT INPUT ("From: Origin Town*"), the highest-cost
 * possible opener; GlobeFreight opens with "Name*", asking a stranger's name
 * before they have said what they want. Every benchmark opens with a category
 * tile or chip. These classes are where that lands. */
.qt-form__tiles,
.qt-form__chips {
	display: flex;
	flex-wrap: wrap;
	gap: var(--qt-space-2);
	margin-block: 0 var(--qt-space-4);
	padding: 0;
	list-style: none;
}

/* >= 24x24 measured UNIONED WITH THE LABEL; 44px here, which is HIG comfort.
 * The honeypot is excluded from that gate by id="hp" AND
 * class="all4cms-hp-field"; do not style it visible. */
.qt-form__tile,
.qt-form__chip {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: var(--qt-space-1);
	min-height: 44px;
	min-width: 44px;
	padding: var(--qt-space-2) var(--qt-gutter);
	background-color: var(--qt-card-bg);
	border: var(--qt-border-w) solid var(--qt-card-border);
	border-radius: var(--qt-card-radius);
	color: var(--qt-ink-heading);
	font-family: var(--qt-font-body);
	font-size: var(--qt-fs-base);
	cursor: pointer;
	transition: var(--qt-transition);
}

/* Selected state. Distinguishable WITHOUT colour alone: the border thickens to
 * 2px and a check glyph appears, so it survives greyscale and forced-colours. */
.qt-form__tile[aria-pressed="true"],
.qt-form__chip[aria-pressed="true"] {
	border-width: 2px;
	border-color: var(--qt-accent);
	background-color: var(--qt-accent);
	color: var(--qt-accent-contrast);
	font-weight: var(--qt-fw-heading);
}

.qt-form__tile[aria-pressed="true"]::before,
.qt-form__chip[aria-pressed="true"]::before {
	content: "\2713";
	font-weight: 700;
}

/* "I don't know" / "Not sure" is a first-class third option on every attribute
 * radio -- the single most repeated pattern in the teardown and the #1
 * abandonment killer. It is a normal option, not a de-emphasised one: it gets
 * the SAME rules as any other chip, and this selector deliberately adds no
 * opacity, no smaller font and no muted colour. */
.qt-form__option--unsure {
	font-style: normal;
	opacity: 1;
}

.qt-form__error {
	color: var(--qt-error);
	font-size: var(--qt-fs-small);
	margin-block-start: var(--qt-space-1);
}

/* The lead reference shown to the visitor after submit. R4 traceability is the
 * SAME string on screen, in the CPT row, and in the email subject. Selectable,
 * legible and monospaced -- people quote it on the phone. */
.qt-form__ref {
	display: inline-block;
	padding: var(--qt-space-1) var(--qt-space-2);
	background-color: var(--qt-card-bg);
	border: var(--qt-border-w) solid var(--qt-card-border);
	border-radius: var(--qt-radius);
	font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
	font-size: var(--qt-fs-base);
	font-weight: var(--qt-fw-heading);
	color: var(--qt-ink-heading);
	user-select: all;
}

/* Honeypot. Hidden from humans, reachable by bots, and EXCLUDED from the
 * 24x24 target gate by id AND class. Never `display:none` it -- some bots skip
 * display:none fields, which defeats the trap. Off-screen, zero-opacity,
 * removed from the tab order by the markup's tabindex="-1". */
.all4cms-hp-field {
	position: absolute !important;
	inset-inline-start: -9999px;
	inset-block-start: auto;
	width: 1px;
	height: 1px;
	overflow: hidden;
	opacity: 0;
	pointer-events: none;
}
