/* =============================================================================
 * 30-sheet.css -- THE TILED BODY TEXTURE **AND** THE CONTAINED WHITE SHEET.
 *
 * *** DO NOT SPLIT THIS FILE. DO NOT SHIP HALF OF IT. ***
 *
 * These two things are ONE feature. They must always land in the SAME FILE and
 * the SAME COMMIT. This is not a style preference -- it is a defect that has
 * already shipped once, on GlobeFreight, in GF-003: the tiled texture went out
 * without the white card and the result was dark text on dark grey.
 *
 * If a future change deletes one of these two blocks, it MUST delete both.
 * If it moves one of them to another file, it MUST move both.
 * If you are reading this because only one of them exists, THAT IS THE BUG.
 *
 * BYTE-IDENTICAL across both sites. Values arrive per-site from brand.php.
 *
 * -----------------------------------------------------------------------------
 * RETRACTION, 2026-08-06 -- READ THIS BEFORE ACTING ON ANY CONTRAST NUMBER.
 *
 * An earlier revision of this file asserted that AutoTransport has NO white
 * sheet, that body text sits at 2.00:1 directly on the texture, and that the
 * sheet below is therefore a look-changing REPAIR needing owner sign-off.
 *
 * ALL OF THAT IS WRONG AND IT HAS BEEN DISPROVED BY SCREENSHOT
 * (at-services-contrast-check.png, 2026-08-06). THE WHITE CARD IS REAL.
 *
 * The harvest agrees once you read the right rows. In at-target-*.json the
 * rendered text elements resolve their nearest PAINTED ancestor to
 * rgb(255,255,255):
 *
 *     services  1366   p                 #334155 on #FFFFFF   10.35:1  PASS
 *     services  1366   h3                #1E293B on #FFFFFF   14.63:1  PASS
 *     post-158  1366   h1.entry-title    #1E293B on #FFFFFF   14.63:1  PASS
 *     car-tr.   1366   h3.gform_title    #1E293B on #FFFFFF   14.63:1  PASS
 *     home      1366   a.ptp-button      #FFFFFF on #C2431C    5.11:1  PASS
 *     any       1366   footer a / svg    #FFFFFF on #2B2622   14.97:1  PASS
 *
 * The failing rows are CONTAINERS, not text: `body`, `#page`, `header`,
 * `#colophon`. The harvester scores a container's inherited `color` against
 * its own background and takes the concatenated text of every descendant as
 * the sample -- so a wrapper that paints nothing is graded as though all the
 * text inside it were painted directly on the texture. The about-us "h1 at
 * 2.82:1" row is worse still: that element has `renderedMatch: false` and a
 * 0x0 box. It does not render at all.
 *
 * CONSEQUENCES, ACT ON THESE:
 *   1. AT's pass condition is an EMPTY DIFF, and it is not self-contradictory.
 *      Nothing in this file changes the live AutoTransport look.
 *   2. computed-style-parity.cjs must NOT gate on contrast until the ancestor
 *      resolution is fixed and re-validated against a screenshot. The colour
 *      and geometry measurements are trustworthy; the derived ratios are not.
 *   3. STANDING RULE: a computed-style finding is a LEAD, not a fact. Confirm
 *      with a rendered screenshot before it enters a task file, an ADR or a
 *      gate. This is the visual analogue of "never grep served HTML for a hex."
 * -----------------------------------------------------------------------------
 * ========================================================================== */


/* ==========================================================================
 * PART 1 OF 2 -- THE TILED BODY TEXTURE
 * Never ship this part without PART 2 below.
 * ========================================================================== */

/* `body[class]`, NOT `body`, and the attribute selector is load-bearing.
 *
 * MEASURED 2026-08-14 against a real WordPress running this theme (the first
 * time it had ever executed): the canvas rendered #F0F5FA, not --qt-canvas.
 *
 * The winner is Astra's own inline CSS:
 *     .ast-separate-container { background-color: var(--ast-global-color-4) }
 * body_class() puts `ast-separate-container` on <body>, and a CLASS selector
 * (0,1,0) outranks a TYPE selector (0,0,1) -- so `body {}` loses on
 * SPECIFICITY and source order is never consulted. 30-sheet.css already loads
 * after Astra (position 11 vs 2) and it made no difference.
 *
 * `body[class]` is (0,1,1), which clears (0,1,0). Every WordPress body carries
 * a class attribute, so this is not an Astra-specific hack in a file that must
 * stay byte-identical across two sites -- it does not name Astra, and it works
 * the same on a site where nothing contests the rule.
 *
 * NOT !important: this file uses none, and reaching for it here would set a
 * precedent that the next parent-theme collision also gets to break. Raising
 * specificity by one attribute is the smallest thing that wins.
 *
 * WHY THIS WAS INVISIBLE UNTIL NOW. The live site does not have the bug,
 * because kit 163's custom_css carries
 *     body { background-color:#706C6C !important }
 * and !important beats Astra's class rule. Retiring that kit CSS is the WHOLE
 * POINT of ADR-0007 -- so the port would have removed the only thing holding
 * the canvas up, and the texture would have tiled over pale blue instead of
 * grey. Subtle, wrong, and exactly what an empty-diff gate exists to catch. */
body[class] {
	background-color: var(--qt-canvas);
	background-image: var(--qt-canvas-image);
	background-repeat: repeat;
	background-position: left top;
	background-size: auto;
}

/* MEASURED tiles, for provenance -- both are supplied by brand.php, never
 * hardcoded here, because the two sites use different files:
 *   AT  .../uploads/2016/03/bodybg-300x222-1.jpg   on #706C6C
 *   GF  .../uploads/2016/03/bodybg-150x150.jpg     on #FFFFFF (transparent body)
 *
 * GF TRAP, DO NOT GET THIS WRONG: GlobeFreight's texture is delivered by
 * WordPress's `custom-background` INLINE style, not by the heritage
 * stylesheet. The heritage stylesheet's own body rule (line 153) points at a
 * DEAD ic-express.co.za hotlink. Never enqueue that rule -- it 404s AND it
 * republishes a retired brand's domain, which CLAUDE.md forbids. The
 * uploads-path URL lives in brand.php['tokens']['canvas-image'] instead, so
 * the theme owns the texture and no longer depends on a Customizer setting
 * surviving the next update.
 *
 * AT's four classic surfaces measure `background-image: none` with #F0F5FA
 * (404, search) or #FFFFFF (page 79, post 158) -- they have no texture because
 * the Elementor kit CSS never loads there. The rule above is what finally
 * gives 404, search, page 79 and post 158 the same body as the rest of the
 * site. That is a restoration on those four surfaces, and it is the one part
 * of the "classic surfaces differ" finding that IS true and screenshot-
 * confirmed. */


/* ==========================================================================
 * PART 2 OF 2 -- THE CONTAINED WHITE SHEET
 * This is what makes PART 1 readable. Never ship PART 1 without this.
 * ========================================================================== */

/* The sheet is the white card body content sits on inside the textured body.
 * In the Genesis heritage theme it was #wrap. Here it is .qt-container,
 * emitted by chrome-header.php inside #content.site-content.
 *
 * GF MEASURED (gf-target-*.json, #wrap on all three widths):
 *     width 1030px, margin 0 auto, background #fff,
 *     border-radius 10px, box-shadow NONE
 *     1030px at 1366 (x=168); 100% at 768 and 390.
 * AT MEASURED: container max-width 1240px, padding 0 20px, sheet #FFFFFF
 *     square (no radius, no shadow).
 *
 * Corrections to previously documented GF values -- all four were wrong, all
 * four came from gf-restore-additional.css / globefreight-restore-style.php,
 * which are untested PROPOSALS and must not be lifted from:
 *   the sheet is 1030px, NOT 1060px
 *   there is NO box-shadow -- separation is border-radius:10px alone
 *   #F1592A is the submit-button/input colour, links are #5397B4
 *   #3498DB / #2980b9 are Easy Pricing Tables plugin CSS, not brand tokens
 *     (MEASURED: .ptp-button is #fff on #3498DB with a #2980b9 bottom border
 *      on the reconstruction too -- plugin chrome, present on both target and
 *      live, and it fails AA at 3.15:1 on both. Pre-existing; not this
 *      theme's to introduce and not this theme's to silently change.) */

.qt-container {
	max-width: var(--qt-measure);
	width: 100%;
	margin-inline: auto;
	background-color: var(--qt-sheet);
	border-radius: var(--qt-sheet-radius);
	box-shadow: var(--qt-sheet-shadow);
	padding-inline: var(--qt-gutter);
	padding-block: var(--qt-sheet-pad);
	color: var(--qt-ink);
}

/* Text ON the sheet is stated here, immediately next to the sheet, on purpose.
 * This pairing is the exact thing that broke on both sites. If --qt-sheet
 * changes, THIS is what must be re-checked, and it must pass AA (4.5:1).
 * Today:  AT #334155 on #FFFFFF = 10.35:1.  GF #333333 on #FFFFFF = 12.63:1. */

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

/* Below 1024px the sheet is full-width -- GF measures 100% at both 768 and
 * 390. Combined with the universal `box-sizing: border-box` in 10-reset.css
 * this also avoids importing GF's heritage 9px overflow at 390
 * (#footer-widgets 92% + 20px padding + 1px border under content-box). The
 * live site does not have that bug; do not reproduce it. */

/* #content is the sheet's OUTER wrapper and must stay transparent. Two nested
 * white boxes produce a double edge that is invisible at 1366 and obvious at
 * 768 -- the sheet lives on .qt-container, here and nowhere else. */
#content.site-content {
	background-color: transparent;
}

/* Full-bleed Elementor sections need to escape this container or hero bands
 * render as narrow white strips. The escape is implemented in
 * 70-elementor-bridge.css, deliberately NOT here -- so that the pair above
 * stays a self-contained, reviewable unit. */

/* ==========================================================================
 * END OF THE PAIR. Both parts present? Good. If not, stop and fix it.
 * ========================================================================== */
