/* ============================================================
   client_custom.css — Service-Tech Corporation (stc) · Skill 6A/6B
   Loaded AFTER stc-global.css on every page. Post-launch tweaks +
   build-time additions the QA-approved stc-global.css should not carry.
   ============================================================ */

/* Skill 6B — generic in-body image slot for GENERATED pages (LSP / bulk
   spoke / hub bodies). The design's .ph__note is position:absolute and the
   hand-built templates always nest .ph inside a positioned frame; generated
   body images need the same frame or the note escapes to the viewport
   top-left. Scoped to .fig so it never touches the hand-built .ph slots. */
.fig { margin: var(--sp-5) 0; }
.fig .ph {
  position: relative;
  aspect-ratio: 16 / 9;
  min-height: 200px;
  border-top: var(--rule) solid var(--teal);
  overflow: hidden;
}

/* Skill 6C — footer column labels are chrome, not outline headings (R28): was <h4>,
   now <div class="footcol"> with the same styling. */
.footer .footcol { font: 600 13px/1.2 var(--font-body); letter-spacing: .14em; text-transform: uppercase; color: var(--white); margin: 0 0 var(--sp-3); padding-bottom: 8px; border-bottom: 2px solid var(--teal); display: inline-block; }

/* Skill 6C — slots filled with client photos by _build_tools/wire-images.js: the frame keeps its
   reserved box (no CLS); the photo covers it. Hero backgrounds already use .hero__bg>img. */
.ph--img { position: relative; background: none; overflow: hidden; }
.ph--img > img, .founder__photo > img, .ba__pane > img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.ba__tag { position: relative; z-index: 1; }
.office__img.ph--img { aspect-ratio: 3 / 2; }

/* Skill 6C — mid-page CTA band background photo (the design's .bg scrim sits on top). */
.cta-band .bg > img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }

/* Skill 6C — full-bleed hero (Ugi, 2026-09-23): the photo fills the whole hero block. hero-bleed.js moves
   the breadcrumb bar and the trust strip inside .hero; here they become translucent bars over the photo.
   The hero's own .container rules (padding, grid, display:block) must not leak into their containers. */
.hero--bleed > .breadcrumbs, .hero--bleed > .trust-strip { position: relative; z-index: 1; background: transparent; background-image: none; }
.hero--bleed > .breadcrumbs { border-bottom: 1px solid rgba(255, 255, 255, .12); }
.hero--bleed > .breadcrumbs > .container, .hero--bleed > .trust-strip > .container { padding-top: 0; padding-bottom: 0; }
.hero--bleed > .trust-strip { background: rgba(17, 17, 17, .55); border-top: 1px solid rgba(255, 255, 255, .12); padding: var(--sp-5) 0; }
.hero--bleed > .trust-strip > .container { display: block; } /* its computed layout outside the hero */

/* Skill 6C R28 — a CTA band's line of copy is chrome, not an outline heading (Heading_Hierarchy_Standard):
   finalize.js renders it as <p class="cta-band__title">; these are the h2 declarations it used to inherit. */
.cta-band .cta-band__title { font-family: var(--font-display); font-weight: 700; line-height: 1.05; letter-spacing: .005em; text-wrap: balance; font-size: var(--fs-h2); color: var(--on-dark); margin: 0 0 var(--sp-2); }

/* Skill 6C R25 — AVIF heroes render <picture> (AVIF, then the manifest WebP fallback). The picture box must not
   break the absolutely positioned cover images the design positions as direct children. */
picture { display: contents; }
.hero--bg .hero__bg > picture > img, .ph--img > picture > img, .founder__photo > picture > img, .ba__pane > picture > img, .cta-band .bg > picture > img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }

/* Skill 6C R29 — reserve the HubSpot form's height so the page does not reflow when it arrives
   (measured 2026-09-23: iframe 608px desktop / 854px at 390px, identical in Chromium and WebKit). */
#estimate-form { min-height: 677px; }
@media (max-width: 768px) { #estimate-form { min-height: 910px; } }
/* Skill 6C R34 — a card grid's short last row is centred, not stranded left (skill 5:200, skill 6:946).
   Flex-wrap at the same column counts and gaps the grid used; justify-content centres the remainder. */
@media (min-width: 640px) { .postgrid { display: flex; flex-wrap: wrap; justify-content: center; } .postgrid > * { flex: 0 1 calc((100% - var(--card-gap)) / 2); min-width: 0; } }
@media (min-width: 1000px) { .postgrid > * { flex-basis: calc((100% - 2 * var(--card-gap)) / 3); } }
@media (min-width: 600px) { .prices { display: flex; flex-wrap: wrap; justify-content: center; } .prices > * { flex: 0 1 calc((100% - var(--card-gap)) / 2); min-width: 0; } }
@media (min-width: 1000px) { .prices > * { flex-basis: calc((100% - 2 * var(--card-gap)) / 3); } }
/* steps: the template's auto-fit rows (4 across at desktop) kept; a stranded step centres at its natural width */
@media (min-width: 769px) { .steps3 { display: flex; flex-wrap: wrap; justify-content: center; } .steps3 > li { flex: 1 1 240px; max-width: 360px; } .steps3.steps3--3col > li { flex-basis: calc((100% - 2 * var(--sp-5)) / 3); max-width: none; flex-grow: 0; } }

/* Skill 6C — legacy blog posts carry markdown blockquotes (photo captions, callouts). */
.article blockquote { margin: var(--sp-4) 0; padding: var(--sp-3) var(--sp-4); border-left: 4px solid var(--teal); background: var(--hair-2); font-style: italic; }
.article blockquote p { margin: 0; }

/* ============================================================
   WEB-704 — full-site QA round (2026-10-06)
   ============================================================ */

/* QA 7 — mobile footer: body already reserves the 64px mobile call bar, so the footer's own
   +64px left a double gap; the bottom row centres. */
@media (max-width: 768px) {
  .footer { padding-bottom: var(--sp-6); }
  .footer-bottom { align-items: center; text-align: center; }
  .powered-by-eb-link .powered-by-eb { margin-left: 0; }
}
@media (min-width: 769px) { .powered-by-eb-link { margin-left: auto; } .powered-by-eb-link .powered-by-eb { margin-left: 0; } }
.powered-by-eb-link { display: inline-flex; }

/* QA 8 — FAQ answers use the accordion's full width (70ch left a gap on the right). */
.faq__a { max-width: none; }

/* QA 14, revised by design QA 2 (2026-10-08) — image + copy splits: the copy starts at the top, not
   centred against the image; the image stays in view (sticky under the 76px nav) while longer copy
   scrolls past it; a flipped split keeps the image in the narrower column. */
.split2 { align-items: start; }
@media (min-width: 900px) {
  .split2 .ph { height: auto; aspect-ratio: 4 / 3; align-self: start; position: sticky; top: calc(76px + var(--sp-5)); }
  .split2--flip { grid-template-columns: minmax(0, .85fr) minmax(0, 1.15fr); }
}
@media (min-width: 960px) { .hubrow .container { align-items: start; } .hubrow__media { position: sticky; top: calc(76px + var(--sp-5)); } }

/* Design QA 2 (industrial-cleaning) — the line after a step grid sat flush under it. */
.steps3 + * { margin-top: var(--sp-6); }

/* QA 19 + design QA "padding after a table" / "between these sections": breathing room after
   tables and lists, and above a sub-heading that follows a list or table. */
.spec-table-wrap { margin-bottom: var(--sp-6); }
.spec-table-wrap + *, .why-list + h3, .feature-list + h3, ul + h3, ol + h3 { margin-top: var(--sp-6); }

/* Design QA (dry-ice-blasting, rope-access-services) — the closing line under a boxed spoke list
   sits in the same box treatment instead of floating loose. */
.spokes + .rich-body { margin-top: var(--sp-4); padding: 12px 16px; border: 1px solid var(--hair-2); border-left: 3px solid var(--primary); background: var(--white); max-width: none; }
.section--cream .spokes + .rich-body { background: var(--white); }
.section:not(.section--cream) .spokes + .rich-body { background: var(--cream); }
/* a spoke-list item without a link (e.g. dry-ice "Fire and smoke restoration") gets the same box */
.spokes > li:not(:has(> a)) { display: flex; align-items: center; min-height: 44px; padding: 8px 12px; border: 1px solid var(--hair-2); border-left: 3px solid var(--primary); background: var(--white); font: 500 15px/1.3 var(--font-body); color: var(--ink); }
/* Design QA (dayton-oh/rope-access-services) — consecutive body paragraphs after a timeline were flush. */
.rich-body + .rich-body { margin-top: var(--sp-4); }

/* QA 29-33 — city pages: the office's own (GBP) number under the hero CTAs; the Call button keeps
   the tracked 800 number (STC_Phone_Number_Rules_PRODUCTION.md). */

/* QA 36/46 + design QA (blogs) — post hero: dark band holding the breadcrumb, eyebrow, H1 and
   meta, with the post's image beside the title (the post thumbnails are 600px, too small to
   run full-bleed behind the copy). */
.hero--post { background: var(--dark); background-image: var(--grain); color: var(--on-dark); }
.hero--post > .breadcrumbs { background: transparent; background-image: none; border-bottom: 1px solid rgba(255, 255, 255, .12); }
.hero--post > .breadcrumbs > .container { padding-top: 0; padding-bottom: 0; }
.hero--post > .container { display: grid; gap: var(--sp-6); align-items: center; padding-top: var(--sp-7); padding-bottom: var(--sp-7); }
@media (min-width: 900px) { .hero--post > .container { grid-template-columns: minmax(0, 1.1fr) minmax(0, .9fr); gap: var(--sp-8); } }
.hero--post h1 { color: var(--white); margin-bottom: var(--sp-4); }
.hero--post .post-meta { display: flex; flex-wrap: wrap; gap: var(--sp-2) var(--sp-4); align-items: center; font-size: 14px; color: #C9C9C9; }
.hero--post .post-meta .inherited { border: 1px solid rgba(255, 255, 255, .3); padding: 2px 8px; font-size: 11px; letter-spacing: .1em; text-transform: uppercase; }
.post-hero__media { margin: 0; }
.post-hero__media .ph { position: relative; aspect-ratio: 3 / 2; border-top: var(--rule) solid var(--teal); overflow: hidden; }
.post-hero__media .ph > img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }

/* QA 41/46 — images inside a post show whole, at their own proportions (the 16:9 cover frame
   cropped diagrams and photos the original posts showed in full). */
.article .fig .ph { aspect-ratio: auto; min-height: 0; background: none; }
.article .fig .ph > img, .article .fig .ph > picture > img { position: static; width: 100%; height: auto; object-fit: contain; }

/* QA 42 — LinkedIn video posts (coil-cleaning) keep LinkedIn's own embed proportions. */
.video-wrap--linkedin { aspect-ratio: 504 / 399; max-width: 504px; background: none; margin-inline: auto; }

/* WEB-704 QA 4: EB standard legal text on /privacy-policy/ and /terms-and-conditions/ */
.legal-body h2 { margin-top: var(--sp-6); }
.legal-body h3 { margin-top: var(--sp-4); font-size: 1.125rem; line-height: 1.3; }
.legal-body ul { padding-left: 1.25em; list-style: disc; }
.legal-notice { background: var(--cream, #f6f2ea); border-left: 4px solid var(--teal, #1a8a8a); padding: var(--sp-4); margin-bottom: var(--sp-5); }
.legal-notice h2 { margin-top: 0; font-size: 1rem; letter-spacing: .03em; }

/* Gallery photos (2026-10-08) — client before/after pairs on /gallery/: portrait tiles, pairs read
   left to right (4 across = 2 pairs per row, 2 across on mobile = 1 pair per row); "After" labels
   take the brand red like the .ba slider tags. */
.gallery--ba li { aspect-ratio: 3 / 4; }
.gallery--ba li.is-after .lbl { background: var(--primary); }
@media (max-width: 639px) { .gallery--ba .lbl__what { display: none; } }
/* QA round 2: inherited-post sign-off (name / title / phone / email, then the logo), as on the live posts */
.article .post-sign { line-height: 1.7; margin-bottom: var(--sp-3); }
.article .post-sign__logo { display: block; width: 160px; height: auto; margin: 0 0 var(--sp-6); }
.article .list-2col { columns: 2 220px; column-gap: var(--sp-7); }
.article .list-2col li { break-inside: avoid; }
/* QA items 13/15: two-up gallery rows; project-card summaries */
.gallery--2 { grid-template-columns: repeat(2, 1fr); max-width: 780px; margin-left: auto; margin-right: auto; }
@media (max-width: 639px) { .gallery--2 { grid-template-columns: 1fr; } }
.postcard .pbody p { margin: 0; font-size: 15px; color: var(--steel); }
/* small inherited photos shown at their native size, as on the live post (QA 3) */
.article .fig--small .ph { max-width: 300px; }
/* GHL forms (2026-10-27): the embed brings its own card, fields and button, so the .cform wrapper
   around it is plain, with no frame, background or padding of its own. */
.cform { border: 0; background: none; padding: 0; }
