/*
Theme Name:   Divi Child (Teckel)
Theme URI:    https://teckel.io
Description:  Divi child theme for teckel.io. Houses custom code so it survives Divi parent updates and lives under version control.
Author:       Teckel Labs
Author URI:   https://teckel.io
Template:     Divi
Version:      0.9.253
License:      GNU General Public License v2 or later
License URI:  http://www.gnu.org/licenses/gpl-2.0.html
Text Domain:  divi-child
*/

/* ==========================================================================
   V1 — Popup Maker default-hidden CSS (popup-as-footer fix)
   --------------------------------------------------------------------------
   Symptom: popup popmake-10109 renders inline at the end of the page on
   every staging page, looking like a second footer.

   Root cause: on production (Divi 4) the Popup Maker plugin CSS rules are
   inlined inside WP Rocket's <style id="wpr-usedcss"> blob. On staging
   (Divi 5) the inline CSS pipeline is Divi 5's new <style id="et-critical-
   inline-css"> instead, and it does NOT include the Popup Maker rules.
   Without them, .pum-overlay has no display:none / position:fixed defaults,
   so the popup container renders as a normal block at body-end (which is
   where Popup Maker emits it — verified between main-footer and </body> on
   both prod and staging).

   Fix: re-declare the minimum Popup Maker layout CSS needed for default-
   hidden + fixed-positioned behaviour. Copied from production's inlined
   rules (Popup Maker version 1.22.0). If WP Rocket / Divi 5's critical CSS
   is later configured to include popup-maker styles, this whole block
   becomes redundant and can be removed.

   Visual confirmation pending child theme activation.
   ========================================================================== */
.pum-overlay {
    display: none;
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    width: 100%;
    height: 100%;
    overflow: hidden;
    transition: all 0.15s ease-in-out;
    z-index: 1999999999;
}

.pum-overlay,
.pum-overlay *,
.pum-overlay:before,
.pum-overlay:after,
.pum-overlay *:before,
.pum-overlay *:after {
    box-sizing: border-box;
}

.pum-overlay.pum-active {
    overflow-y: scroll;
    -webkit-overflow-scrolling: touch;
}

.pum-overlay.pum-overlay-disabled {
    visibility: hidden;
}

.pum-overlay.pum-overlay-disabled .pum-container {
    visibility: visible;
}

.pum-overlay.pum-click-to-close {
    cursor: pointer;
}

.pum-container {
    position: absolute;
    top: 100px;
    margin-bottom: 3em;
    z-index: 1999999999;
}

.pum-container.pum-responsive {
    left: 50%;
    width: 95%;
    height: auto;
    margin-left: -47.5%;
    overflow: visible;
}

.pum-container.pum-responsive img {
    height: auto;
    max-width: 100%;
}

.pum-container.pum-responsive.pum-responsive-normal {
    width: 70%;
    margin-left: -30%;
}

.pum-container.pum-responsive.pum-position-fixed {
    position: fixed;
}

.pum-container .pum-content:focus {
    outline: 0;
}

.pum-container .pum-content + .pum-close {
    position: absolute;
    z-index: 2;
    min-width: 1em;
    line-height: 1;
    background-color: transparent;
    text-align: center;
    text-decoration: none;
    cursor: pointer;
}

/* ==========================================================================
   V2 — Vertical-nav menu alignment to logo nose tip
   --------------------------------------------------------------------------
   Symptom: site-wide, the vertical-right nav menu items do not align to
   the tip of the teckel (dachshund) logo's nose.

   Root cause: Divi 5 introduced new defaults that shift things relative
   to Divi 4:
     .logo_container          { padding-left: 30px }   -- shifts logo right
     #top-menu > li > a       { margin-left: -40px }   -- shifts menu left
                              { padding-right: 20px }  -- shrinks text area;
                                                          made "NFT Marketplace"
                                                          wrap (added 2026-05-16)
   Production (Divi 4) did not emit those defaults; staging (Divi 5) does.

   Existing custom CSS in et_divi.divi_custom_css already sets:
     .et_vertical_nav #main-header #top-menu > li > a { padding-left: 40px !important }
     #main-header .logo_container                     { margin-left: 35px }
   In Divi 4 these alone produced the intended alignment (logo at
   margin-left 35, menu items shifted right by 40 to land on the nose).
   In Divi 5 they don't, because the new defaults cancel them: the
   negative margin-left wipes out the padding-left visually, and the
   added padding-left on the logo container pushes the logo further
   right of the math.

   Fix: in the desktop vertical-nav viewport, zero out Divi 5's two new
   defaults so the existing custom math takes effect again.

   Selector mapping (Divi 4 → Divi 5): unchanged. Every selector below
   still matches in Divi 5 — confirmed by curl + grep on staging-home.
   The failure mode here is "selectors match but the underlying box-model
   defaults changed," not "selectors gone."

   Visual confirmation pending child theme activation.
   ========================================================================== */
/* V61c (2026-07-01): 980 -> 981 so these custom DESKTOP rules partition at the SAME
   line as Divi's vertical-nav (min-width:981) and stop bleeding into the (980,981) gap
   (where they set logo_container margin-left:35/padding-left:0, part of the horizontal
   navbar corruption). Mobile is <=980, desktop is >=981, the sliver between is the gap block. */
@media (min-width: 981px) {
    .logo_container {
        padding-left: 0 !important;
    }

    /*
     * padding-right: 0 added 2026-05-16. Divi 5's default
     * #top-menu>li>a {padding-right:20px} shrank the menu items' text
     * area by 20px relative to Divi 4 and caused "NFT Marketplace" (the
     * longest single label) to wrap onto a second line. Production
     * (Divi 4) renders it on one line; zeroing this padding restores
     * the same available width.
     */
    .et_vertical_nav #main-header #top-menu > li > a {
        margin-left: 0 !important;
        padding-right: 0 !important;
    }
}

/* ==========================================================================
   V5 — Divi toggle (FAQ + any .et_pb_toggle) — MATCH PRODUCTION exactly
   --------------------------------------------------------------------------
   v0.4.0 (2026-05-17) styled toggles per the LOCKED design brief
   (09-design-system.md §1: #e1e3e7 light surface, #011431 ink). Steven's
   visual review found that styling unfamiliar and asked to match the
   production look instead, AND reported jittering on open/close caused by
   the v0.4.0 padding/margin/min-height overrides fighting Divi's
   slideToggle inline-height animation.

   v0.4.1 (this version): PRODUCTION-PARITY rewrite. Generalised the
   production page-3623 Divi-computed toggle styles (which target
   .et_pb_toggle_0..14 by instance) to apply via .et_pb_toggle so all
   pages — FAQ on /faq/, Bio toggles on /about/, future toggles — get
   the same visual. Captured by curling
   /wp-content/et-cache/3623/et-core-unified-deferred-3623.min.css and
   cross-verified via Playwright getComputedStyle() on every prod toggle.

   Deviation from 09-design-system.md §1 is intentional and documented
   in decisions.md. The companion `teckel_toggle_title_placeholder_fix`
   JS in functions.php (placeholder injection for the 11 migration-
   regressed toggles) is unchanged from v0.4.0.

   Jitter fix: no padding/margin/min-height overrides. The earlier
   v0.4.0 padding (16px 20px !important) and min-height (1.5em on
   title) shifted the toggle's natural box mid-animation. v0.4.1 keeps
   Divi's default `padding: 20px` plus only the production instance
   override `padding-left: 10px` — no other dimension overrides.

   Known §4 motion-brief deviation, retained: Divi 5's built-in toggle
   handler animates via jQuery slideToggle(700ms) — exceeds the brief's
   250ms ceiling and animates `height` (a layout property). Out of
   scope for V5; flagged for Phase 5 motion-compliance pass.
   ========================================================================== */

/* Container — both states share these */
.et_pb_toggle {
    border: 0px solid #002349 !important;
    box-shadow: 6px 6px 6px 0px rgba(0, 35, 73, 0.4) !important;
    padding-left: 10px !important;
    color: #a1520f !important; /* default text colour — cascades into content (prod parity) */
    font-size: 18px;
}

/* Container — closed state */
.et_pb_toggle.et_pb_toggle_close {
    background-color: #002349 !important;
}

/* Container — open state */
.et_pb_toggle.et_pb_toggle_open {
    background-color: rgba(179, 185, 194, 0.4) !important;
}

/* Container hover — orange border */
.et_pb_module.et_pb_toggle:hover {
    border-color: #a1520f !important;
}

/* Title — closed state (white, 20px) */
.et_pb_toggle.et_pb_toggle_close .et_pb_toggle_title,
.et_pb_toggle.et_pb_toggle_close h1.et_pb_toggle_title,
.et_pb_toggle.et_pb_toggle_close h2.et_pb_toggle_title,
.et_pb_toggle.et_pb_toggle_close h3.et_pb_toggle_title,
.et_pb_toggle.et_pb_toggle_close h4.et_pb_toggle_title,
.et_pb_toggle.et_pb_toggle_close h5.et_pb_toggle_title,
.et_pb_toggle.et_pb_toggle_close h6.et_pb_toggle_title {
    color: #ffffff !important;
    font-size: 20px;
}

/* Title — open state (navy)
   v0.4.3: also locks font-size: 20px (matches closed) so font-size
   doesn't animate; the prior absence of font-size here meant opening
   the toggle removed the 20px override and the title fell back to
   Divi's default h3 size (~24px). The transition then animated
   font-size, which reflows the title on every frame and — paired
   with Divi's slideToggle inline-height animation — produced the
   open/close jitter Steven flagged. The intentional title-enlarges-
   on-open effect that Steven likes is now produced via
   `transform: scale(1.1)` (see below) — transform doesn't reflow.

   v0.4.5: the transform: scale(1.1) is split out into a
   `@media (min-width: 1200px)` rule below — on mobile (Samsung
   S21 ~360px viewport in Steven's report) and narrow tablet /
   desktop viewports the scaled title pushed the +/- icon (a
   ::before pseudo-element of the title, positioned `right: -6px`)
   off the right edge of the toggle card. Below 1200px, no scale
   is applied — the title and icon look like production. */
.et_pb_toggle.et_pb_toggle_open .et_pb_toggle_title,
.et_pb_toggle.et_pb_toggle_open h1.et_pb_toggle_title,
.et_pb_toggle.et_pb_toggle_open h2.et_pb_toggle_title,
.et_pb_toggle.et_pb_toggle_open h3.et_pb_toggle_title,
.et_pb_toggle.et_pb_toggle_open h4.et_pb_toggle_title,
.et_pb_toggle.et_pb_toggle_open h5.et_pb_toggle_title,
.et_pb_toggle.et_pb_toggle_open h6.et_pb_toggle_title {
    color: #011431 !important;
    font-size: 20px;
}

/* Title — open-state enlargement, comfortable-desktop only.
   Gated at 1200px because the vertical-right nav steals ~225px of
   horizontal space on desktop, leaving the toggle card actually
   narrower than the viewport. Below 1200px the scaled title's
   icon-pseudo can overflow the card's right edge. */
@media (min-width: 1200px) {
    .et_pb_toggle.et_pb_toggle_open .et_pb_toggle_title,
    .et_pb_toggle.et_pb_toggle_open h1.et_pb_toggle_title,
    .et_pb_toggle.et_pb_toggle_open h2.et_pb_toggle_title,
    .et_pb_toggle.et_pb_toggle_open h3.et_pb_toggle_title,
    .et_pb_toggle.et_pb_toggle_open h4.et_pb_toggle_title,
    .et_pb_toggle.et_pb_toggle_open h5.et_pb_toggle_title,
    .et_pb_toggle.et_pb_toggle_open h6.et_pb_toggle_title {
        transform: scale(1.1);
    }
}

/* Title — hover (orange, both states) */
.et_pb_toggle .et_pb_toggle_title:hover,
.et_pb_toggle h1.et_pb_toggle_title:hover,
.et_pb_toggle h2.et_pb_toggle_title:hover,
.et_pb_toggle h3.et_pb_toggle_title:hover,
.et_pb_toggle h4.et_pb_toggle_title:hover,
.et_pb_toggle h5.et_pb_toggle_title:hover,
.et_pb_toggle h6.et_pb_toggle_title:hover {
    color: #a1520f !important;
}

/* Title — transition.
   v0.4.3: swapped `font-size` for `transform` in the list — title
   font-size is now locked at 20px in both states (see open-state rule
   above) and the enlargement effect on open uses `transform: scale()`
   instead, which is GPU-cheap and doesn't trigger reflow. The
   `transform-origin` is set so the title scales toward the right
   (anchored on its left edge) — keeps the left edge of the title
   aligned with the left edge of the toggle box during the scale. */
.et_pb_toggle .et_pb_toggle_title,
.et_pb_toggle h1.et_pb_toggle_title,
.et_pb_toggle h2.et_pb_toggle_title,
.et_pb_toggle h3.et_pb_toggle_title,
.et_pb_toggle h4.et_pb_toggle_title,
.et_pb_toggle h5.et_pb_toggle_title,
.et_pb_toggle h6.et_pb_toggle_title {
    transform-origin: left center;
    transition: color 300ms ease 0ms, transform 300ms ease 0ms,
                margin-top 300ms ease 0ms, right 300ms ease 0ms;
}

/* prefers-reduced-motion: no scale on open — matches §4 brief rule
   (honor reduced-motion everywhere). Title still changes color
   instantly to the open-state navy; no enlargement animation.

   v0.4.4 fix: ALSO disable the span color transition (added below
   in v0.4.2) under reduced-motion. v0.4.3 disabled only the title
   h-tag transition and left the span transition active, which
   meant that under reduced-motion the title color jumped
   instantly to its hover/open color while the "teckel" span
   faded over 300ms — visibly desynced. The whole point of
   reduced-motion is "no motion"; both elements should change
   instantly together, not one fading and one jumping. */
@media (prefers-reduced-motion: reduce) {
    .et_pb_toggle .et_pb_toggle_title,
    .et_pb_toggle h1.et_pb_toggle_title,
    .et_pb_toggle h2.et_pb_toggle_title,
    .et_pb_toggle h3.et_pb_toggle_title,
    .et_pb_toggle h4.et_pb_toggle_title,
    .et_pb_toggle h5.et_pb_toggle_title,
    .et_pb_toggle h6.et_pb_toggle_title,
    .et_pb_toggle .et_pb_toggle_title span {
        transition: none !important;
    }
    .et_pb_toggle.et_pb_toggle_open .et_pb_toggle_title,
    .et_pb_toggle.et_pb_toggle_open h1.et_pb_toggle_title,
    .et_pb_toggle.et_pb_toggle_open h2.et_pb_toggle_title,
    .et_pb_toggle.et_pb_toggle_open h3.et_pb_toggle_title,
    .et_pb_toggle.et_pb_toggle_open h4.et_pb_toggle_title,
    .et_pb_toggle.et_pb_toggle_open h5.et_pb_toggle_title,
    .et_pb_toggle.et_pb_toggle_open h6.et_pb_toggle_title {
        transform: none !important;
    }
}

/* +/- icon — closed (orange, 28px, right:-6px) */
.et_pb_toggle.et_pb_toggle_close .et_pb_toggle_title:before {
    font-size: 28px;
    right: -6px;
    color: #a1520f;
}

/* +/- icon — open (navy, 28px, right:-6px) */
.et_pb_toggle.et_pb_toggle_open .et_pb_toggle_title:before {
    font-size: 28px;
    right: -6px;
    color: #011431;
}

/* +/- icon — hover (grows to 36px, shifts further right -10px) */
.et_pb_toggle.et_pb_toggle_close .et_pb_toggle_title:hover:before {
    font-size: 36px;
    right: -10px;
}

/* Accessible focus ring on the clickable title.
   v0.4.2 fix: was `:focus, :focus-visible` in v0.4.1 — the `:focus`
   selector caused a rectangular outline to appear around the title +
   icon on mouse click (Steven 2026-05-17 report; production doesn't
   show this). `:focus-visible` is the modern standard: fires only when
   the browser determines focus should be visibly indicated (i.e.
   keyboard navigation), NOT on mouse click. Dropping `:focus` keeps
   keyboard a11y while removing the click-outline. */
.et_pb_toggle .et_pb_toggle_title:focus-visible {
    outline: 2px solid #a1520f;
    outline-offset: 2px;
}

/* Inner <span> in titles (where the integration_body title-rewrite JS
   wraps "teckel" so it can be bolded via .cus-span styling):
   the production divi_custom_css already provides the COLOR rules —
       .cus-span .et_pb_toggle_title span { color:#ffffff!important; font-weight:700!important }
       #page-container .cus-span.et_pb_toggle_open .et_pb_toggle_title span { color:#011431!important }
       #page-container .cus-span .et_pb_toggle_title:hover span,
       #page-container .cus-span.et_pb_toggle_open .et_pb_toggle_title:hover span { color:#A1520F!important }
   and the same custom CSS is on staging — no need to re-declare here.

   v0.4.2 fix: add the same color-transition the parent <h3> has, so
   the span (e.g. the bold "teckel") fades to its hover color in sync
   with the rest of the title text. Without this transition, the h3's
   non-span text fades over 300ms while the span jumps instantly,
   causing the split-second timing offset Steven flagged. Same
   transition list as production sets on the title h-tags. */
.et_pb_toggle .et_pb_toggle_title span {
    transition: color 300ms ease 0ms;
}

/* ==========================================================================
   V3 + V4 — Divi 5 parallax overlay removal (strict production-parity)
   --------------------------------------------------------------------------
   Symptoms reported:
     V3: home page bottom parallax has an unwanted orange overlay.
     V4: every other parallax page's bottom parallax image appears
         to be "missing".

   ROOT CAUSE — ONE, not two: Divi 5 emits inline
       background-color: <color>
       background-blend-mode: soft-light
   on the `.et-pb-parallax-background` span for bottom parallax
   sections. The color varies by page (whatever was configured per
   Divi-4 section module and carried across in the migration):
     home                              → #a1520f (brand orange)
     about, pricing, teckel-ai,        → #FFFFFF (white)
     web3-services, ipfs,
     nft-bartering, faq
   Production (Divi 4) emits ZERO background-color and ZERO
   background-blend-mode on any parallax background span — verified
   by curl + grep across all 8 affected pages (prod count = 0 on
   every page; staging count = 3 per page, one for each of the
   desktop/tablet/phone variants of the same module).

   With background-blend-mode: soft-light applied between an inline
   <span> background image and the inline background color:
     - orange overlay tints the image orange  → V3's "unwanted overlay"
     - white overlay washes the image out     → V4's "missing image"
   Both symptoms are presentations of the same underlying Divi-5
   inline-style emission that production does not do.

   Per the 2026-05-17 V-items-are-parity LOCKED principle
   (decisions.md), the fix is the minimum CSS that removes what
   Divi 5 wrongly adds so staging matches production. `!important`
   is required to override the inline style. The selector matches
   all three variants (desktop / `_tablet` / `_phone`) because all
   three share the `et-pb-parallax-background--css` class.

   No new styling or motion introduced; this only cancels two
   inline declarations that don't exist on production.

   Pending Steven's visual confirmation: load any parallax page —
   most useful are home (was orange) and any non-home parallax
   page like /about/ or /pricing/ (was image-missing) — and check
   that the bottom parallax now shows its image cleanly with no
   color overlay.
   ========================================================================== */
.et-pb-parallax-background.et-pb-parallax-background--css {
    background-color: transparent !important;
    background-blend-mode: normal !important;
}

/* ==========================================================================
   V8 — nft-ticketing post-slider min-height (strict production-parity)
   --------------------------------------------------------------------------
   AMENDMENT 2026-05-17 (v0.9.2 → v0.9.3): mobile media query extended
   to include the slider CONTAINER selector, not just the slide. Steven
   flagged on S21 mobile that the slider sits in a background container
   "too long" vs prod mobile. Root cause: at mobile breakpoint, Divi 5
   emits an EMPTY `min-height:` value for `.et_pb_post_slider_0` (the
   container), so the desktop 815px sticks instead of resetting; prod
   resets both container AND slide to `auto`. Same selector-omission
   family as the original V8 desktop bug, just the mobile equivalent.

   Symptom: post-slider on /nft-ticketing/ appears "misplaced" — the
   slide image visibly overflows ABOVE the slide boundary, the slide
   shrinks to ~half its intended height, and the description sits
   stacked rather than beside the image.

   ROOT CAUSE — NOT the V3/V4 inline-injection pattern. Curl-diff
   confirmed: the parallax background spans on this slider carry
   only `background-image`, no `background-color`, no
   `background-blend-mode`. The v0.5.0 V3/V4 rule already
   neutralizes any inline injections on this page's bottom-
   parallax sections (the slider itself is in section_2 and has
   none).

   This is a DISTINCT Divi-5 regression — a **selector-omission**
   bug in Divi 5's page-builder CSS generator. The author-
   configured rule for THIS slider on PROD (Divi 4) is emitted as:
       .et_pb_post_slider_0,.et_pb_post_slider_0 .et_pb_slide
           { min-height: 815px }
   targeting BOTH the slider container AND each individual slide.
   On STAGING (Divi 5) the equivalent rule is emitted as:
       .et_pb_post_slider_0 { ...; min-height: 815px; ... }
   targeting ONLY the slider container — the second selector is
   dropped.

   Net effect: the slider container retains the 815px min-height,
   but each `.et_pb_slide` collapses to its natural content
   height (~369px, since the slider is author-configured to hide
   titles and buttons — `display: none !important` on
   `.et_pb_slide_title` and `opacity: 0 !important` on
   `.et_pb_more_button`, both present identically on prod and
   staging). The slide image (positioned to fill the slider's
   815px) then overflows the collapsed slide's 369px box by
   ~140px on a 1440px viewport. Confirmed via Playwright
   `getBoundingClientRect()`: prod slide rect height = 815,
   staging = 369; prod image y=1376 sits inside slide y=1294-2109;
   staging image y=1153 sits ABOVE the slide y=1294-1663.

   Fix: restore the missing selector. PROD pairs the 815px
   desktop rule with a mobile media query setting min-height
   to auto so the slide can shrink on narrow viewports; both
   are mirrored.

   `!important` is required because Divi 5 emits its CSS as
   inline `<style>` blocks AFTER the child theme link in <head>,
   so the child theme's plain rules would lose the cascade
   despite same specificity.

   Scoped to `.page-id-2904` so the fix applies only to this
   page's slider — other pages may legitimately host post-
   sliders with different author-configured heights, and a
   global rule forcing 815px would override them.

   Pending Steven's visual confirmation: load
   /nft-ticketing/ on a hard-refresh / private window. The
   post-slider in section 2 should display each slide at full
   height with the image fitting inside the slide boundary
   (not overflowing above), and the description sitting beside
   the image as on production.
   ========================================================================== */
.page-id-2904 .et_pb_post_slider_0 .et_pb_slide {
    min-height: 815px !important;
}
@media (max-width: 980px) {
    .page-id-2904 .et_pb_post_slider_0,
    .page-id-2904 .et_pb_post_slider_0 .et_pb_slide {
        min-height: auto !important;
    }
}

/* ==========================================================================
   R1 — Mobile parallax: force background-attachment: scroll
   --------------------------------------------------------------------------
   Migrated 2026-05-17 from et_divi.divi_integration_head (the
   original <style>@media(max-width:980px){span.et_parallax_bg.et_pb_parallax_css{
   background-attachment:scroll!important}}</style> block at the top of
   the integration_head).

   Why this matters (Steven flagged 2026-05-17 visual diff on S21):
   Divi 5's parallax CSS sets `background-attachment: fixed` on every
   `.et-pb-parallax-background--css` span. On mobile, fixed-attachment
   anchors the image to the VIEWPORT, not to the parallax span. The
   section becomes a "window" through to whichever portion of the image
   happens to be at the viewport position — producing visibly different
   cropping/zoom from production, even when the image FILE is the same.

   Side-by-side Playwright at 360 px viewport, home bottom parallax:
     PROD     : background-attachment: scroll  (image fills the span)
     STAGING  : background-attachment: fixed   (image anchored to viewport)

   Production (Divi 4) had this fix in the divi_integration_head
   <style> block targeting `span.et_parallax_bg.et_pb_parallax_css`.
   That selector matches zero elements in Divi 5 (R1 in rebuild plan;
   class renamed `et_parallax_bg` → `et-pb-parallax-background`).
   This rule re-applies the fix using the Divi 5 selector.

   The original Divi-4 fix was site-wide for max-width 980 px (tablet +
   phone). Mirrored exactly to match production behaviour at both
   breakpoints. !important is required to beat Divi 5's core rule.

   Note: the old integration_head block can stay live for now — the
   Divi-4 selector matches nothing in Divi 5, so it's a no-op already.
   Mark as safe to decommission alongside the rest of the
   integration_head decommission pass.
   ========================================================================== */
@media (max-width: 980px) {
    .et-pb-parallax-background.et-pb-parallax-background--css {
        background-attachment: scroll !important;
    }
}

/* ==========================================================================
   R11 — reCAPTCHA badge hide
   --------------------------------------------------------------------------
   Migrated 2026-05-17 from et_divi.divi_custom_css (top of file).
   Hides the floating Google reCAPTCHA v3 badge in the bottom-right
   corner. Required because the reCAPTCHA terms acknowledgement is
   surfaced elsewhere in the page text (Divi email opt-in module
   includes the required notice inline). Production parity:
   identical CSS already live on prod via the same custom-CSS
   option; this is a verbatim move. Source in divi_custom_css is
   safe to delete once the full Phase-3 source-decommission step
   runs.
   ========================================================================== */
.grecaptcha-badge {
    visibility: hidden;
}

/* ==========================================================================
   R12 — Divi inside-divider gap fix (mobile)
   --------------------------------------------------------------------------
   Migrated 2026-05-17 from et_divi.divi_custom_css. Closes a
   known Divi rendering gap between sections when top/bottom
   "inside dividers" are used on certain mobile screens (per
   Divi support). Production parity: identical rule already
   live on prod. Source in divi_custom_css safe to decommission.
   ========================================================================== */
.et_pb_bottom_inside_divider {
    bottom: -1px !important;
}
.et_pb_top_inside_divider {
    top: -1px !important;
}

/* ==========================================================================
   R13 — Nav customizations (the non-alignment rules)
   + R13a source — vertical-nav alignment math (logo margin + menu
                    item padding) — kept here so the V2 zero-outs
                    above have something to anchor to once the
                    divi_custom_css source is decommissioned.
   --------------------------------------------------------------------------
   Migrated 2026-05-17 from et_divi.divi_custom_css. The V2 block
   higher up zeroes out Divi 5's new defaults that broke alignment
   (logo_container padding-left: 30px and #top-menu>li>a
   margin-left: -40px + padding-right: 20px). With those zero-outs
   applied, the alignment then comes from the original Divi-4
   custom math captured below.

   R13 non-alignment rules: select_page hide, hamburger color +
   size, mobile-only logo max-height and hamburger vertical
   position, mobile menu dropdown brand divider line.

   Inline-injection heuristic confirmed clean (R7-R21 audit
   2026-05-17): 0 inline styles on any of these elements on either
   prod or staging.

   Source in divi_custom_css is safe to decommission once Phase-3
   source-decommission runs. NOTE: the divi_custom_css still
   contains several other nav-adjacent rules that were NOT in the
   R7-R21 LIKELY-OK bundle (logo rotation on mobile, padding-top
   between logo and site top, distance between logo and menu
   items) — those stay in divi_custom_css for now and are tracked
   for a later migration pass.
   ========================================================================== */

/* R13a source — vertical-nav alignment math (desktop only)
   V61c (2026-07-01): 980 -> 981. logo_container margin-left:35 here was bleeding into the
   (980,981) gap (and applying at exactly 980, where it beat mobile's margin-left:-10 on
   #main-header id-specificity) = a horizontal logo shift. Now desktop-only, matching Divi. */
@media all and (min-width: 981px) {
    .et_vertical_nav #main-header .container {
        margin-left: 0px;
    }
    .et_vertical_nav #main-header #top-menu > li > a {
        padding-left: 40px !important;
    }
    #main-header .logo_container {
        margin-left: 35px;
    }
}

/* Hide the "Select Page" label that Divi shows next to mobile-menu trigger */
span.select_page {
    display: none !important;
}

/* Hamburger icon color (white on the navy nav background) */
.mobile_menu_bar.mobile_menu_bar_toggle::before {
    color: #ffffff;
}

/* Hamburger icon size + line thickness */
.mobile_menu_bar:before {
    font-size: 32px;
    font-weight: 400;
}

/* Mobile-only logo + hamburger position fixes */
@media (max-width: 980px) {
    .et_header_style_left #logo {
        max-height: 85%;
    }
    .et_header_style_left #et-top-navigation .mobile_menu_bar {
        top: 12px;
    }
}

/* Brand-orange divider line at the top of the mobile dropdown menu */
#et-top-navigation #mobile_menu {
    border-top: 3px solid #a1520f;
}

/* ==========================================================================
   R14 — Footer info layout
   --------------------------------------------------------------------------
   Migrated 2026-05-17 from et_divi.divi_custom_css.
   Centers the #footer-info text and stretches it to full width.
   Production parity: identical rule already live on prod via the
   same custom-CSS option. Source safe to decommission later.
   ========================================================================== */
#footer-info {
    text-align: center;
    width: 100%;
}

/* ==========================================================================
   R15 — H1-H6 typography + small-mobile size + word-wrap
   --------------------------------------------------------------------------
   Migrated 2026-05-17 from et_divi.divi_custom_css.

   Verbatim production-parity rules. Sets Jost throughout, brand
   navy #011431 for heading ink, weights and per-level sizes that
   Steven chose for Divi 4 production. H5 has font-style: italic
   per the prod source (kept as-is — design brief might change
   that in Phase 5).

   The original CSS used Steven's verbose tutorial-style inline
   comments (e.g. "Controls font size"); those are stripped for
   readability. All values are unchanged.

   Heading-link hover colors mirrored from the original block
   (orange default, navy on hover).

   Small-mobile (≤360 px) clamp() overrides for body + heading
   font sizes carry across verbatim — they originated in the same
   divi_custom_css section to keep ultra-narrow phone layouts
   readable. The `* word-wrap: normal !important` override
   that follows in the source is the same author's mobile-wrap
   fix; kept together for cohesion.

   Per the 2026-05-17 V-items-are-production-parity LOCKED
   principle: this is a behavior-neutral move, not a re-style.
   The 09-design-system.md §2 clamp-based responsive type scale
   is Phase-5 new-build work and explicitly NOT applied here.

   Inline-injection heuristic confirmed clean: 0 inline styles
   on h1..h6 on either prod or staging.

   Source in divi_custom_css is safe to decommission later.
   ========================================================================== */
h1 {
    font-size: 35px;
    color: #011431;
    font-weight: 500;
    font-style: normal;
    text-decoration: none;
    text-transform: none;
    line-height: 1.2;
    letter-spacing: 0px;
    text-align: left;
    font-family: "Jost", sans-serif;
}

h2 {
    font-size: 25px;
    color: #011431;
    font-weight: 500;
    font-style: normal;
    text-decoration: none;
    text-transform: none;
    line-height: 1.2;
    letter-spacing: 0px;
    text-align: left;
    font-family: "Jost", sans-serif;
}

h3 {
    font-size: 22px;
    color: #011431;
    font-weight: 500;
    font-style: normal;
    text-decoration: none;
    text-transform: none;
    line-height: 1.2;
    letter-spacing: 0px;
    text-align: left;
    font-family: "Jost", sans-serif;
}

h4 {
    font-size: 20px;
    color: #011431;
    font-weight: 500;
    font-style: normal;
    text-decoration: none;
    text-transform: none;
    line-height: 1.2;
    letter-spacing: 0px;
    text-align: left;
    font-family: "Jost", sans-serif;
}

h5 {
    font-size: 18px;
    color: #011431;
    font-weight: 500;
    font-style: italic;
    text-decoration: none;
    text-transform: none;
    line-height: 1.2;
    letter-spacing: 0px;
    text-align: left;
    font-family: "Jost", sans-serif;
}

h6 {
    font-size: 12px;
    color: #011431;
    font-weight: 500;
    font-style: normal;
    text-decoration: none;
    text-transform: none;
    line-height: 1.2;
    letter-spacing: 0px;
    text-align: left;
    font-family: "Jost", sans-serif;
}

h1 a, h2 a, h3 a, h4 a, h5 a, h6 a {
    color: #a1520f;
    text-decoration: none;
}

h1 a:hover, h2 a:hover, h3 a:hover, h4 a:hover, h5 a:hover, h6 a:hover {
    color: #011431;
    text-decoration: none;
}

@media (max-width: 360px) {
    p {
        font-size: clamp(1rem, 4.5vw, 1.4rem) !important;
    }
    h1, h2 {
        font-size: clamp(1.5rem, 6vw, 2rem) !important;
    }
    h3, h4, h5, h6 {
        font-size: clamp(1.2rem, 5vw, 1.7rem) !important;
    }
}

@media (max-width: 360px) {
    * {
        word-wrap: normal !important;
    }
}

/* ==========================================================================
   V9 — Fullwidth-header title padding-bottom (Divi 5 reset/re-add asymmetry)
   --------------------------------------------------------------------------
   Symptom (Steven 2026-05-17): the fullwidth-header module title sits
   at a slightly different height than production on every page.

   Inline-injection heuristic: clean (0 inline styles on the section,
   the container, or the h1 on either prod or staging).

   ROOT CAUSE — same V2-pattern as the navbar (Divi 5 introduces a
   default that conditionally cancels itself). Divi 5 core CSS has
   these two rules:

       .et_pb_fullwidth_header .et_pb_module_header,
       .et_pb_fullwidth_header p { padding-bottom: 0 }

       .et_pb_fullwidth_header.et_block_module .et_pb_module_header
           { padding-bottom: 10px }

   The first rule resets heading padding-bottom inside any
   .et_pb_fullwidth_header to 0. The second rule adds 10 px back —
   but ONLY when the section also carries the `.et_block_module`
   marker class.

   On staging, the fullscreen-mode fullwidth-header renders with the
   `.et_flex_module` marker class, NOT `.et_block_module` (verified
   via Playwright on / at 1440 px:
   `et_pb_fullwidth_header_0 et_pb_fullwidth_header et_pb_fullscreen
    et_pb_bg_layout_dark et_pb_text_align_center et_animated
    et_pb_module et_flex_module`).
   So the re-add never matches → h1 stays at padding-bottom: 0.

   Production (Divi 4) has neither rule — the Divi-4 generic
   `h1,h2,h3,h4,h5,h6 { padding-bottom: 10px }` default applies
   unconditionally. Per-page CSS doesn't override.

   Computed-style diff at 1440 px on home hero:
     PROD    h1 padding-bottom: 10px,  rect y=382 h=136
     STAGING h1 padding-bottom:  0px,  rect y=377 h=126
   (10 px shorter on staging, 5 px higher because the flex container
   centres its contents vertically — losing 10 px box height moves the
   centre up by 5.)

   Fix: mirror Divi 5's `.et_block_module`-gated re-add to also cover
   the `.et_flex_module` rendering path used by fullscreen-mode
   headers. Production-parity by definition — restores the 10 px the
   Divi-4 generic rule provided unconditionally, without introducing
   any new styling.

   No `!important` needed: this selector has higher specificity than
   Divi 5's `.et_pb_fullwidth_header .et_pb_module_header { padding-
   bottom: 0 }` reset (one extra class on the same compound), matches
   Divi 5's own re-add pattern exactly.
   ========================================================================== */
.et_pb_fullwidth_header.et_flex_module .et_pb_module_header {
    padding-bottom: 10px;
}

/* ==========================================================================
   V9 follow-up — collapse empty button wrapper inside the fullwidth header
   --------------------------------------------------------------------------
   Symptom (continuation of V9): after fixing the h1 padding-bottom, the
   h1 still sat ~20 px higher on staging than on production because the
   .header-content (which is `display: flex` with `row-gap: 20px` via
   the `--vertical-gap` CSS variable Divi 5 sets on it) contains a
   trailing `<div class="et_pb_header_button_wrapper">` that is EMPTY
   (no button configured for these pages). An empty flex child still
   participates in flex layout, so Divi's `row-gap: 20px` adds a 20 px
   gap between the h1 and the empty wrapper, making the .header-content
   20 px taller and pushing the h1 upward when the content-container
   aligns to flex-end at the bottom of the section container.

   PROD has the same module markup but `.header-content` renders as
   `display: block` there (Divi 4 default) — flex `row-gap` doesn't
   apply, so the empty wrapper contributes no height. Net: prod h1
   sits 20 px lower than staging (verified on /about/ at 1280 px:
   prod h1 y=578, staging h1 y=558 after the padding fix).

   Surgical fix: collapse the empty button wrapper out of the flex
   flow via the `:empty` pseudo-class so it has no height AND
   participates only as a zero-content flex item, with no gap
   neighbours. The `:empty` selector matches only when the wrapper
   has no children — pages that legitimately configure a header
   button still render that button normally (the `:empty` rule
   stops matching as soon as the button is added).

   No `!important` needed: `:empty` adds specificity beyond Divi's
   generic display rule.
   ========================================================================== */
.et_pb_fullwidth_header .et_pb_header_button_wrapper:empty {
    display: none;
}

/* ==========================================================================
   V10 — reverted 2026-05-18 (v0.9.10)
   --------------------------------------------------------------------------
   The opacity:1 override killed the entrance animations on the hero (the
   overlay fade-in and the home H1 zoom-in that Steven confirmed are
   intentional, per-prod). Replaced with a targeted exclusion of
   `script-library-animation` from WP Rocket's `delay_js_exclusions` (DB-
   only setting, applied alongside this version bump). That single
   exclusion lets the animation script fire on page load while leaving
   the other 10 `script-library-*` scripts delayed — best of both worlds:
   animations work AND TBT stays low.

   No CSS rule remains here. Divi 5 emits the .et_animated CSS
   (`opacity: 0; animation-duration: 1s; animation-fill-mode: both
   !important`) and the animation JS adds `.fade` / `.fadeBottom` /
   `.zoom` etc. via JS to trigger the keyframe — same pattern as prod.
   ========================================================================== */

/* ==========================================================================
   V12 — REVERTED 2026-05-19 (v0.9.17)
   --------------------------------------------------------------------------
   Initial v0.9.16 attempt: add an opacity:0 → opacity:1 fade-in for
   #main-header to match prod's pattern, with an inline DOMContentLoaded
   script that adds `.et_vertical_menu_set` class to trigger the
   fade-in.

   Why reverted:
   1. WP Rocket Delay JS rewrote the inline script to
      `type="text/rocketlazyloadscript"` (it delays inline scripts
      too, not just src-loaded ones, contrary to the assumption).
      The class therefore wasn't added on DOMContentLoaded —
      navbar stayed at opacity:0 (invisible) until user interaction.
   2. Steven reported 2026-05-19 that the original flash he was
      describing actually appears on production too, and may be
      specific to /teckel-ai/ and /web3-services/ — i.e., NOT a
      site-wide prod-vs-staging difference, so the prod-parity
      premise of V12 was wrong.

   The V12 opacity:0 rule is removed. Re-investigation needed before
   any follow-up fix attempt. See lessons-learned 2026-05-19 entry on
   the WP Rocket Delay JS inline-script trap.
   ========================================================================== */

/* ==========================================================================
   V11 — /contact/ mobile fixes (2026-05-19, v0.9.14)
   --------------------------------------------------------------------------
   Three independent mobile-only regressions vs production behavior on
   /contact/, all surfaced by Steven 2026-05-19 after the v0.9.13 H1
   injection.

   (a) Form stacking. Divi 5 emits contact-field classes that include
       `et_flex_column_12_24_phone` and `et_flex_column_12_24_tablet`
       — explicitly preserving half-width fields on mobile/tablet.
       Divi 4's `et_pb_contact_field_half` carried a media query that
       collapsed half-width to full-width below 980px (stacks the form
       vertically). Divi 5 dropped that behavior. Restore it by forcing
       the half-width flex columns to 100% width below 980px so the
       name + email fields stack on mobile.

   (b) /contact/ H1 mobile size. The H1 added in v0.9.13 has an inline
       `font-size: 35px` which is too large on mobile (was reasonable
       on desktop, dominates on phone). Override with `!important` at
       max-width 980 to bring it down to 24px on mobile (mirrors prod's
       responsive H1 scaling).

   (c) Hero parallax whitespace on mobile. Steven 2026-05-19: "place
       more white space border around it so it effectively shrinks in
       size, only for the mobile view (similar to the case of that one
       lower parallax brand image with the navy overlay)." Default
       Divi 5 parallax uses `background-size: cover` which fills and
       crops the section aggressively. Switch to a sized non-cover
       value with a white background-color to create the whitespace
       border effect on mobile only. Desktop unaffected.

   /contact/ is post ID 2755 — body.page-id-2755 scopes everything
   below to that single page.
   ========================================================================== */
@media (max-width: 980px) {
    /* (a) Stack name + email contact fields on tablet & phone */
    .et_pb_contact_form .et_flex_column_12_24_tablet,
    .et_pb_contact_form .et_flex_column_12_24_phone {
        flex-basis: 100% !important;
        max-width: 100% !important;
        width: 100% !important;
    }

    /* (b) /contact/ H1 smaller on mobile (overrides inline 35px).
       ★ SUPERSEDED 2026-07-24 by V122's fluid clamp (bottom of file), which
       produces this same 24px at ≤980 and then ramps to 35px by 1440. Kept
       here (commented) only as the origin of the 24px figure.
    body.page-id-2755 .et_pb_text_inner h1 {
        font-size: 24px !important;
    } */

    /* (c) /contact/ hero parallax — contain-style whitespace border */
    body.page-id-2755 .et-pb-parallax-background-module--divi-section-1 {
        background-size: 70% auto !important;
        background-repeat: no-repeat !important;
        background-position: center !important;
        background-color: #FFFFFF !important;
    }
}

/* ==========================================================================
   V13 — `.teckel-cta` button utility (2026-05-19, v0.9.18)
   --------------------------------------------------------------------------
   Standardised CTA button class for HTML anchors authored in Divi text
   modules (where the Divi visual builder's button module isn't being
   used). Reproduces the site-wide Divi button look:
     - background #a1520f (brand orange) / hover #002349 (secondary navy)
     - text #FFFFFF, weight 700
     - border-radius 0 (square corners — matches existing site buttons)
     - box-shadow drop (preset2 equivalent)

   First use: /how-it-works/ "Book a 15-minute call" CTA. Use again on
   any HTML-authored CTA so all buttons match.

   All colors palette-compliant per 09-design-system.md §1.
   ========================================================================== */
.teckel-cta {
    display: inline-block;
    background-color: #a1520f;
    color: #FFFFFF !important;
    padding: 12px 28px;
    text-decoration: none;
    font-weight: 700;
    border: 0;
    border-radius: 0;
    box-shadow: 6px 6px 6px 0px rgba(0, 35, 73, 0.4);
    transition: background-color 300ms ease;
}
.teckel-cta:hover {
    background-color: #002349;
    color: #FFFFFF !important;
}

/* ==========================================================================
   V14 — Ethera ElevenLabs voice widget styling (homepage-only, 2026-05-20)
   --------------------------------------------------------------------------
   Pairs with the wp_footer hook in functions.php that emits the
   <elevenlabs-convai> custom element + loader script.

   This is a verbatim copy of production's CSS rule (per Steven
   2026-05-20 — "I would just copy PRODUCTION to start with"). The
   widget's horizontal layout is controlled in the ElevenLabs
   dashboard (currently CENTER TOP); these rules anchor the host
   element top-right and pin it above all other stacking contexts. */
elevenlabs-convai {
    position: fixed !important;
    top: 20px !important;
    right: 20px !important;
    z-index: 9999 !important;
    opacity: 0;
    transform: translateY(10px);
    animation: fadeInUp 1s ease-out 0.5s forwards;
}
@keyframes fadeInUp {
    0%   { opacity: 0; transform: translateY(10px); }
    100% { opacity: 1; transform: translateY(0); }
}
@media only screen and (max-width: 980px) {
    elevenlabs-convai {
        top: 30px !important;
        right: 10px !important;
    }
}

/* ==========================================================================
   V16 — Inline SVG navbar logo (replaces <img id="logo"> via PHP filter)
   --------------------------------------------------------------------------
   The PHP side (V16 in functions.php) replaces Divi's <img id="logo"> with
   the inline SVG content of assets/branding/teckel-logo.svg, keeping the
   #logo selector + adding .teckel-svg-logo class.

   Sizing: inherit Divi's existing #logo width/max-width rules. The SVG
   has no intrinsic width/height attributes (stripped by SVGO), so it
   sizes to its container.

   Mobile/tablet (max-width 980px) mirror behavior: production rotates the
   logo 180° about the vertical axis. CSS equivalent is scaleX(-1) — a
   horizontal flip. This makes the dog face the OTHER way on mobile so it
   "looks toward" the hamburger menu instead of away from it.
   ========================================================================== */
/* Match production's #logo dimensions. Prod renders at 146×94 px desktop
   (vertical nav layout). Our SVG viewBox is wider (460×245 ≈ 1.88 aspect),
   so we set height and let width auto-scale via aspect ratio. !important
   needed to override Divi's vertical-nav `max-height:none` rule. */
html #logo.teckel-svg-logo {
    height: 80px !important;
    width: auto !important;
    max-height: none !important;
    max-width: none !important;
    vertical-align: middle;
    display: inline-block !important;
    margin-right: 0 !important;
}
/* Push the logo container down so there's breathing room before the first
   menu item. Targets .logo_container directly because margin on the inline-
   block SVG doesn't move siblings in Divi's vertical-nav layout. */
.et_vertical_nav .logo_container,
.et_header_style_left .logo_container {
    margin-top: 16px !important;
    margin-bottom: 24px !important;
    padding-bottom: 12px !important;
}
@media only screen and (max-width: 980px) {
    html #logo.teckel-svg-logo {
        transform: scaleX(-1);
        height: 43px !important;
    }
    .et_vertical_nav .logo_container,
    .et_header_style_left .logo_container {
        padding-left: 5px;
        padding-top: 0 !important;
        margin-top: 0 !important;
        margin-left: -10px !important;
        margin-bottom: 0 !important;
        padding-bottom: 0 !important;
    }
}

/* ==========================================================================
   V17 — Tighter H2 line-height + roomier numbered-list line-spacing
   --------------------------------------------------------------------------
   Per Steven 2026-05-21:
   (a) Section H2s inside Divi text modules had too much line-height — looked
       loose when text wrapped on narrow viewports.
   (b) Ordered-list items had too LITTLE vertical separation between items.
   ========================================================================== */
body .et_pb_text h2 {
    line-height: 1.05 !important;
    margin-bottom: 10px !important;
}

/* ==========================================================================
   V18 — Home-page-only H1 styling matched to production (teckel.io)
   --------------------------------------------------------------------------
   Scoped to .home body class so it only applies on the home page (post 2741).
   Replicates prod's text-shadow + vertical centering of the H1 inside the
   fullwidth-header hero. Font specs (Jost 35px/weight-500/lh-42px desktop,
   28px tablet, 26px mobile) already inherit from Divi defaults; the override
   here is just the text-shadow + container alignment.

   Why .home #home-custom-headline: both prod and staging give the home page's
   fullwidth-header section a custom id of `home-custom-headline` so we can
   target it without affecting other pages' headers.
   ========================================================================== */
/* Anchored to the stable #home-custom-headline id only — the old
   `.et_pb_fullwidth_header_0` ordinal selector was dropped 2026-06-07 (Divi 5.7
   renumbered it to _1; the id selector already carries this rule). */
.home #home-custom-headline .header-content h1 {
    text-shadow: rgba(0, 35, 73, 0.65) 0.08em 0.08em 0.08em !important;
}
/* Vertically center the H1 content within the hero (prod-matching layout).
   `.header-content-container` ships with `margin-bottom: 80px` from Divi which
   pushes the H1 down toward the bottom of the hero. Forcing auto-both centers
   the flex item vertically within its parent flex row. */
.home #home-custom-headline .header-content-container {
    margin-top: auto !important;
    margin-bottom: auto !important;
}
.home #home-custom-headline .et_pb_fullwidth_header_container {
    align-items: center !important;
}

/* ==========================================================================
   V19 — Home-page hero overlay fade-in (Divi 5 port of Divi 4 Custom CSS)
   --------------------------------------------------------------------------
   Divi 4 version (lived in Section Settings > Custom CSS on prod):
     selector::before { ...overlay... animation: fadeIn 3939ms; }
   where `selector` = `.et_pb_section_0` (auto-generated Divi class).

   Ported to child theme + scoped to .home so only the home page hero gets
   this fading dark overlay. Decoupled from H1 animation (H1 has its own
   zoom-right via Divi 5 editor settings).

   2026-06-07 — RE-ANCHORED after the Divi 5.6.0->5.7.0 update. 5.7 changed the
   auto-generated section ordinal: the hero section is now `.et_pb_section_3`,
   not `.et_pb_section_0`, so the old selector matched nothing and the overlay
   silently disappeared. Now anchored to the hero structurally — the FIRST
   section under `.et_builder_inner_content` (verified: it's the literal
   first-child AND the page's only `.et_pb_fullwidth_section`) — which survives
   any future ordinal renumbering. Both matchers are grouped for resilience.
   ========================================================================== */
.home .et_builder_inner_content > .et_pb_section:first-child,
.home .et_pb_fullwidth_section {
    position: relative;
}
.home .et_builder_inner_content > .et_pb_section:first-child::before,
.home .et_pb_fullwidth_section::before {
    content: "";
    display: block;
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background-color: rgba(0, 35, 73, 0.65);
    z-index: 1;
    animation: teckelHeroOverlayFadeIn 2000ms; /* 2026-06-13 F4: was 3939ms; accent standard */
    pointer-events: none;
}
@keyframes teckelHeroOverlayFadeIn {
    /* 2026-06-13 F4 site-wide standard (Steven): accent fade, NEVER from zero
       (static H1 needs tint behind it from frame one). 0.429 element-opacity
       = effective 0.28 on the 0.65 navy overlay. Was from{opacity:0}/3939ms. */
    from { opacity: 0.429; }
    to   { opacity: 1; }
}
/* Lift the section's content above the overlay so the H1 remains visible.
   (The parallax bg wrapper is intentionally NOT lifted, so it stays below the tint.) */
.home .et_builder_inner_content > .et_pb_section:first-child > .et_pb_module,
.home .et_builder_inner_content > .et_pb_section:first-child > .et_pb_row,
.home .et_builder_inner_content > .et_pb_section:first-child > .et_pb_fullwidth_header,
.home .et_pb_fullwidth_section > .et_pb_module,
.home .et_pb_fullwidth_section > .et_pb_row,
.home .et_pb_fullwidth_section > .et_pb_fullwidth_header {
    position: relative;
    z-index: 2;
}
.et_pb_text ol li {
    margin-bottom: 12px;
    line-height: 1.2;     /* matches paragraph line-height (1.2 ratio); was Divi's tighter ~1.04 default for OL li */
}
.et_pb_text ol li:last-child {
    margin-bottom: 0;
}

/* ==========================================================================
   V20 — Mobile/tablet sticky navbar (≤980px only)
   --------------------------------------------------------------------------
   Per Steven 2026-05-21: navbar should stay visible while user scrolls.
   Mobile dropdown animation is already provided by Divi's built-in
   slideToggle (no work needed there).

   Padding-top on #page-container prevents content from jumping under the
   now-fixed header. 56px = current mobile header height.
   ========================================================================== */
@media only screen and (max-width: 980px) {
    #main-header {
        position: fixed !important;
        top: 0;
        left: 0;
        right: 0;
    }
    #page-container {
        padding-top: 56px;
    }
}

/* ==========================================================================
   V21 — Site-wide mobile row gutter standardization
   --------------------------------------------------------------------------
   Some rows lost their default ~10% mobile margins during Divi 4 → Divi 5
   migration (e.g. /about/ team_member + toggle rows). This forces all rows
   to have the standard ~41px (10%) horizontal margin on mobile/tablet, so
   content doesn't go edge-to-edge.

   Excludes intentionally-fullwidth rows (`.et_pb_row_fullwidth`) so any
   row that's MEANT to span edge-to-edge (e.g. an image divider) still does.
   ========================================================================== */
@media only screen and (max-width: 980px) {
    .et_pb_section > .et_pb_row:not(.et_pb_row_fullwidth),
    .et_pb_section .et_pb_row_inner:not(.et_pb_row_fullwidth) {
        /* 2026-06-13 overflow fix: the 41px fixed margins below were stacking
           ON TOP OF a Divi-generated `width:90%!important` (90% + 41 + 41 =
           ~406px on a 360 viewport → ~5-16px horizontal scroll on S21, e.g.
           /newsletter/ + /scheduling/). Divi started emitting that row width%
           when 5.7.4 regenerated each page's CSS during the 2026-06-13 F4
           cache-clear, so the latent conflict surfaced then. `width:auto`
           makes the 41px margins the SOLE width determinant (content fills
           viewport − 82px), immune to whatever width% Divi emits; max-width
           is belt-and-suspenders. Verified overflow → 0 on both pages. */
        width: auto !important;
        max-width: calc(100% - 82px) !important;
        margin-left: 41px !important;
        margin-right: 41px !important;
    }
    /* V21b — exception for the HubSpot meetings calendar (/scheduling/): its
       iframe has a hard min-width:312px, but the 41px gutters above squeeze
       the row to 278px → the calendar overflowed its own box and scrolled
       internally (couldn't see the full week on S21). Give the calendar row a
       near-full-width 8px gutter on mobile so the 312px week view fits with
       room (row 344 / container ~334 @ 360vw). Higher specificity than the
       rule above (extra :has) + later source order so it wins. Scoped to any
       row containing the embed, so it's correct wherever the calendar appears.
       (:has supported on modern mobile Chrome/Safari; older browsers harmlessly
       fall back to the 278px behaviour.) */
    .et_pb_section > .et_pb_row:not(.et_pb_row_fullwidth):has(.meetings-iframe-container) {
        max-width: calc(100% - 16px) !important;
        margin-left: 8px !important;
        margin-right: 8px !important;
    }
    /* V21c — same near-full-width treatment for rows holding a toolkit/RPC
       chart (Steven 2026-06-13). The 41px gutters squeezed the multi-column
       charts to 278px, forcing heavy hyphenation/word-wrap in the headers
       (e.g. header cells 137px tall). 8px gutters → ~344px gives the columns
       ~24% more width and noticeably less wrapping (headers ~113px) with zero
       page overflow. Scoped to chart rows only via :has. */
    .et_pb_section > .et_pb_row:not(.et_pb_row_fullwidth):has(.toolkit-table),
    .et_pb_section > .et_pb_row:not(.et_pb_row_fullwidth):has(.responsive-table) {
        max-width: calc(100% - 16px) !important;
        margin-left: 8px !important;
        margin-right: 8px !important;
    }
    /* V21c-narrow (Steven 2026-06-23) — the wide chart row above also stretched
       the surrounding intro/cards/notes/headings. Only the CHART TABLE itself
       should be near-full-width (to reduce header word-wrap); push everything
       else in the toolkit-pricing module back to the normal ~41px gutter
       (8px row gutter + 33px = 41px). Keeps paragraphs/cards readable. */
    .toolkit-pricing > *:not(.toolkit-table) {
        margin-left: 33px !important;
        margin-right: 33px !important;
    }
    /* V21d — give code-block ROWS the same near-full-width treatment so the code
       wraps less on mobile (Steven 2026-06-23); then re-narrow any TEXT module
       sharing that row (a caption/intro like the "MCP JSON Configuration (n8n)"
       label) back to the normal 41px gutter, so ONLY the code block is wide. */
    .et_pb_section > .et_pb_row:not(.et_pb_row_fullwidth):has(.call-snippet-wrapper) {
        max-width: calc(100% - 16px) !important;
        margin-left: 8px !important;
        margin-right: 8px !important;
    }
    .et_pb_section > .et_pb_row:not(.et_pb_row_fullwidth):has(.call-snippet-wrapper) .et_pb_text {
        margin-left: 33px !important;
        margin-right: 33px !important;
    }
}

/* Team-member social icon alignment — standardize to left across all cards.
   Migration from Divi 4 left some cards (e.g. Yusuf's) with text-align:center
   on the social links UL. */
.et_pb_team_member .et_pb_member_social_links {
    text-align: left !important;
}

/* ==========================================================================
   V22 — Footer blocks: Get the App + Follow Us
   Two-column block above the existing #footer-bottom copyright row.
   App badges left, social icons right; stacks on mobile.
   ========================================================================== */
#footer-blocks {
    background-color: #002349;
    padding: 30px 0 25px;
    border-bottom: 1px solid rgba(255, 255, 255, 0.08);
}
#footer-blocks .container {
    display: flex;
    flex-wrap: wrap;
    gap: 40px;
    justify-content: space-between;
    align-items: flex-start;
}
#footer-blocks .footer-block {
    flex: 0 1 auto;
}
#footer-blocks .footer-block-follow {
    text-align: right;
}
#footer-blocks .footer-block-title {
    color: #ffffff;
    font-size: 14px;
    font-weight: 600;
    margin: 0 0 12px;
    text-transform: uppercase;
    letter-spacing: 0.8px;
}
#footer-blocks .footer-app-badges {
    display: flex;
    gap: 12px;
    flex-wrap: wrap;
    align-items: center;
}
#footer-blocks .footer-app-badges img {
    height: 48px;
    width: auto;
    display: block;
    transition: transform 0.15s ease;
}
#footer-blocks .footer-app-badges a:hover img {
    transform: translateY(-2px);
}
#footer-blocks .footer-icons {
    display: inline-flex;
    gap: 16px;
    flex-wrap: wrap;
    align-items: center;
    justify-content: flex-end;
}
#footer-blocks .footer-icon {
    color: #ffffff;
    display: inline-flex;
    transition: color 0.15s ease, transform 0.15s ease;
}
#footer-blocks .footer-icon:hover {
    color: #a1520f;
    transform: translateY(-2px);
}
#footer-blocks .footer-icon svg {
    width: 26px;
    height: 26px;
    fill: currentColor;
    display: block;
}

@media (max-width: 768px) {
    #footer-blocks .container {
        flex-direction: column;
        gap: 25px;
    }
    #footer-blocks .footer-block-follow {
        text-align: left;
    }
    #footer-blocks .footer-icons {
        justify-content: flex-start;
    }
}

/* ==========================================================================
   V23 — Link-card hover: drop shadow disappears on mouseover (UX affordance).
   Targets cards that are THEMSELVES links — a div carrying the standard card
   shadow that DIRECTLY wraps a block-level <a>. The `:has(> a[...display:block])`
   guard excludes info-only cards (no <a> child) and cards whose links are
   attached only to inline text. !important is required to beat the inline
   box-shadow set on each card.
   ========================================================================== */
div[style*="box-shadow:6px 6px 6px"]:has(> a[style*="display:block"]) {
    transition: box-shadow 0.2s ease;
}
div[style*="box-shadow:6px 6px 6px"]:has(> a[style*="display:block"]):hover {
    box-shadow: none !important;
}

/* ==========================================================================
   V24 — Mobile menu internal scroll (fixes the V20 sticky-navbar overflow).
   The open hamburger menu is anchored to the fixed #main-header, so it's
   locked to the viewport and long menus ran off the bottom with no way to
   reach the last items (page scroll moves content BEHIND the fixed menu, not
   the menu itself). Give the menu its own scroll. dvh accounts for mobile
   browser URL-bar chrome; vh is the fallback for older browsers. 56px matches
   V20's #page-container padding-top (the navbar height).
   ========================================================================== */
@media only screen and (max-width: 980px) {
    .et_mobile_menu {
        max-height: calc(100vh - 56px);
        max-height: calc(100dvh - 56px);
        overflow-y: auto;
        -webkit-overflow-scrolling: touch;
    }
}

/* ==========================================================================
   V25 — Responsive STACKING tables (no horizontal scrollbar).
   Pricing tables (.teckel-rtable) collapse on narrow viewports: the header row
   is hidden and each body row becomes a labelled card — the first cell is the
   card title, every other cell shows its column header (via data-label) beside
   its value. Reflows vertically; never scrolls sideways. Scoped to
   .teckel-rtable so the per-service charts keep their own responsive behaviour.
   (Supersedes the earlier horizontal-scroll V25 — h-scrollbars are poor UX.)
   ========================================================================== */
@media only screen and (max-width: 768px) {
    .teckel-rtable,
    .teckel-rtable thead,
    .teckel-rtable tbody,
    .teckel-rtable tr,
    .teckel-rtable td {
        display: block;
        width: 100%;
    }
    .teckel-rtable thead {
        position: absolute;
        left: -9999px;
        top: -9999px;
    }
    .teckel-rtable tr {
        margin-bottom: 14px;
        border: 1px solid #b3b9c2;
        border-radius: 4px;
        overflow: hidden;
    }
    .teckel-rtable td {
        text-align: left;
        padding: 10px 14px;
        border-bottom: 1px solid #e1e3e7 !important;
    }
    /* Label sits ABOVE the value (both left-aligned) so long/multi-line values
       read cleanly and never get squeezed into a narrow right column + clipped. */
    .teckel-rtable td::before {
        content: attr(data-label);
        display: block;
        font-weight: 600;
        color: #011431;
        margin-bottom: 3px;
    }
    .teckel-rtable td:first-child {
        background: #e1e3e7;
        font-weight: 700;
        color: #011431;
    }
    .teckel-rtable td:first-child::before { content: none; }
    .teckel-rtable td[data-label=""]::before { content: none; }
    .teckel-rtable td:last-child { border-bottom: none !important; }
}

/* ==========================================================================
   V26 — Anchor deep-links land below the fixed navbar (pure-CSS, replaces the
   old prevent-flicker scroll script). scroll-padding-top offsets in-page AND
   cross-page anchor jumps (e.g. /teckel-ai/#rpc-pricing-table-prices) so the
   fixed mobile navbar doesn't cover the target.
   NOTE: scroll-behavior:smooth was intentionally REMOVED — on heavy pages it
   animated toward a target that kept moving as content reflowed, causing the
   flicker Steven reported. An instant anchor jump is cleaner.
   ========================================================================== */
html {
    scroll-padding-top: 70px;
}

/* ==========================================================================
   V27 — Pricing pages: mobile breathing room between the hero image and the
   first content. The content section's padding-top is 0, so on mobile the
   intro/chart butts right against the hero (Steven 2026-05-31). Scoped via
   :has() to the section holding the toolkit-pricing / RPC-pricing-intro
   content, so it only touches /teckel-ai-pricing/ + /ethereum-rpc-pricing/.
   ========================================================================== */
@media only screen and (max-width: 980px) {
    .et_pb_section:has(.toolkit-pricing),
    .et_pb_section:has(.rpc-pricing-intro) {
        padding-top: 28px !important;
    }
}

/* ==========================================================================
   V28 — Normalise Divi-core's default #eee content-table borders to the
   palette UI-neutral (#b3b9c2). Divi injects, via an inline <style> block,
   `.entry-content table:not(.variations){border:1px solid #eee}` and
   `.entry-content tr td{border-top:1px solid #eee}` — leaking an off-palette
   grey into the OUTER FRAME and the CELL-TOP of every custom table (the
   /teckel-ai-pricing/ + /ethereum-rpc-pricing/ toolkit charts, the /pricing/
   .teckel-rtable tables, and any future content table). #eee is not in the
   locked palette; #b3b9c2 is the design-system border/hairline token (and the
   param-hr divider weight). Only border-COLOR is changed (1px solid kept).
   Also unifies the two pricing charts: /teckel-ai-pricing/ cells were the
   lighter #e1e3e7 → now #b3b9c2 to match /ethereum-rpc-pricing/.
   (Steven 2026-06-06 — confirmed weight #b3b9c2.)
   ========================================================================== */
.entry-content table:not(.variations),
.entry-content table:not(.variations) tr td {
    border-color: #b3b9c2;
}
/* Pricing toolkit charts: force the whole cell grid to the UI-neutral,
   overriding the per-page inline `.toolkit-table` cell-border CSS (which still
   emits #e1e3e7 on /teckel-ai-pricing/ and loads after this stylesheet). */
.toolkit-table table td,
.toolkit-table table th {
    border-color: #b3b9c2 !important;
}

/* ==========================================================================
   V29 — Footer "Company" link column (Contact · Support · Report Abuse).
   Adds a third block to the V22 footer-blocks row (space-between handles 3).
   White-on-navy text links per design-system §3 (orange on #002349 fails AA);
   hover -> #b3b9c2 + underline. The two orphaned-but-maintained pages
   (Support, Report Abuse) get a home here instead of the Resources dropdown
   (Steven 2026-06-07 — utility/trust links belong in the footer).
   ========================================================================== */
#footer-blocks .footer-links {
    list-style: none;
    margin: 0;
    padding: 0;
}
#footer-blocks .footer-links li {
    margin: 0 0 8px;
}
#footer-blocks .footer-links a {
    color: #ffffff;
    text-decoration: none;
    font-size: 14px;
    transition: color 0.15s ease;
}
#footer-blocks .footer-links a:hover {
    color: #b3b9c2;
    text-decoration: underline;
}
#footer-blocks .footer-links a:focus-visible {
    outline: 2px solid #a1520f;
    outline-offset: 2px;
}

/* ==========================================================================
   V30 — About-page lead/intro paragraph. The opening statement on /about/ was
   an <h2> (wrong: it's intro prose, not a section heading — broke the H1->H2
   ("Our founders")->H3 outline). Converted to a styled lead <p class="about-lead">
   2026-06-07 for correct SEO/AEO/GEO hierarchy. Scoped + !important to beat
   Divi's .et_pb_text p rules (which set line-height !important). "teckel" stays
   bold via the inline <strong>. (Steven 2026-06-07 — approved after live preview.)
   ========================================================================== */
.et_pb_text p.about-lead {
    font-size: 20px !important;
    font-weight: 400 !important;
    line-height: 1.65 !important;
    color: #011431;
    margin: 0 0 1em;
}

/* ==========================================================================
   V31 — Link contrast inside coloured body text (Steven 2026-06-08).
   GENERAL RULE: a link sitting inside ORANGE (#a1520f) body text renders NAVY
   (#002349) so it stays distinct from the surrounding orange; navy-text links
   stay orange (the site default — design-system §3). Targets elements whose
   INLINE style sets the text colour to orange (matches "color: #a1520f", not
   border-/background-color), so it is safe + general. The .et_pb_toggle_content
   selector guarantees the FAQ answers (whose text is orange via .et_pb_toggle
   line-215 cascade). Underline appears on hover (design-system §3), colour
   unchanged. (Links opening in a new tab is handled in the content markup —
   target="_blank" rel="noopener noreferrer".)
   ========================================================================== */
[style*="color: #a1520f"] a,
[style*="color:#a1520f"] a,
[style*="color: #A1520F"] a,
[style*="color:#A1520F"] a,
.et_pb_toggle_content a {
    color: #002349 !important;
}
[style*="color: #a1520f"] a:hover,
[style*="color:#a1520f"] a:hover,
[style*="color: #A1520F"] a:hover,
[style*="color:#A1520F"] a:hover,
.et_pb_toggle_content a:hover {
    color: #002349 !important;
    text-decoration: underline;
}

/* ==========================================================================
   V32 — /faq/ footer-hero band height (Steven 2026-06-08). The footer-hero
   section (the parallax engraving above the footer) carries height 575/550/525px
   in its Divi data, but a leftover Divi-5-alpha `wp:divi/placeholder` module
   stops the height applying, so the band collapsed to ~84px and crowded the
   footer. Force the intended responsive height back on the last section of the
   page (stable: last child of .et_builder_inner_content) — the restored band is
   also the breathing room between the FAQs and the footer. Scoped to the FAQ
   page; generalise if the same collapse shows on other pages.
   ========================================================================== */
body.page-id-3623 .et_builder_inner_content > .et_pb_section:last-child {
    min-height: 575px !important;
}
@media (max-width: 980px) {
    body.page-id-3623 .et_builder_inner_content > .et_pb_section:last-child {
        min-height: 550px !important;
    }
}
@media (max-width: 767px) {
    body.page-id-3623 .et_builder_inner_content > .et_pb_section:last-child {
        min-height: 525px !important;
    }
}

/* ==========================================================================
   V33 — "Opens in a new tab" indicator (Steven 2026-06-08; the accessibility
   half of the industry-standard link behaviour). Content text links that open
   in a new tab (external links + downloadable files — set as target="_blank" in
   the content markup) get a small ↗ after them so the new-tab behaviour is
   signalled (WCAG 3.2.5 / G201). Scoped to content text links; image links
   (footer badges, banners) are excluded via :not(:has(img)).
   ========================================================================== */
.et_pb_text a[target="_blank"]:not(:has(img))::after,
.et_pb_toggle_content a[target="_blank"]:not(:has(img))::after,
.et_pb_blurb a[target="_blank"]:not(:has(img))::after {
    content: "\00A0\2197";   /* nbsp + north-east arrow */
    font-size: 0.85em;
    font-style: normal;
    text-decoration: none;
    line-height: 1;
}

/* ==========================================================================
   V34 — pricing chart polish (Steven 2026-06-08):
   - square corners (no border-radius on the stacked cards);
   - on mobile, drop the redundant V28 outer TABLE border so each card carries a
     single clean outline (was a double / "connected" outline: table border +
     per-card border);
   - mobile card labels -> secondary navy #002349 (matches the header recolour);
   - long unbroken <code> tokens (e.g. get_teckel_credit_balance_for_apikey) wrap
     instead of overflowing the card.
   (The header CELL background recolour #011431 -> #002349 is in the page content,
   inline on the chart <th>/<td> cells.)
   ========================================================================== */
.teckel-rtable tr { border-radius: 0 !important; }
@media only screen and (max-width: 768px) {
    .teckel-rtable { border: 0 !important; }
    .teckel-rtable td::before,
    .teckel-rtable td:first-child { color: #002349 !important; }
}
.entry-content p code,
.responsive-table code,
.toolkit-table code,
.teckel-rtable code { overflow-wrap: anywhere; }

/* ==========================================================================
   V35/V36 — toolkit/RPC chart header hyphenation (Steven 2026-06-09).
   Symptom: in the toolkit charts the col-2 header label "Underlying method
   (RESTful API)" encroached the narrow column's right border on very narrow
   viewports (and on narrow desktop in particular).

   REAL ROOT CAUSE (diagnosed 2026-06-09, headless + cascade dump): NOT a missing
   browser hyphenation dictionary. The toolkit PAGE's own inline <style> (post
   10896) had accumulated a graveyard of contradictory `.hyph` rules from prior
   fix attempts; the last-winning ones set `hyphens:none` + `word-break:break-all`
   on `.toolkit-table thead th .hyph` (specificity 0,2,2). That BEAT V35's broad
   `.toolkit-table .hyph` (0,2,0), so V35 never reached the span — hyphenation was
   force-disabled and the word char-broke/encroached. (First V36 pass tried
   break-word->anywhere; reverted — `anywhere` greedily char-fills and DEFEATS the
   hyphenation point, so it never produced a clean break either.)

   FIX (two parts, both verified headlessly at 360px → clean "Under-lying"):
   1. A soft hyphen is baked into the markup (`Under&shy;lying`, post 10896) — a
      grammatical break that does NOT need a browser dictionary (so it also fixes
      desktop Chrome/Linux where `hyphens:auto` is a no-op; the S21 has a dict).
   2. The override below, at specificity (0,2,3) (`... th span.hyph`), out-weighs
      the page's (0,2,2) cruft and restores `hyphens:auto` + `word-break:normal`,
      so the soft hyphen / auto-hyphenation is honoured. `overflow-wrap:break-word`
      (NOT anywhere) is the gentle last-resort that lets the hyphen win.
   Tech debt: the page's <style> graveyard (the contradictory `.hyph` overrides)
   should be cleaned in the toolkit page's Phase-5 rewrite; this override neutralises
   it for now. Needs <html lang> (present: en-US).
   ========================================== */
.responsive-table .hyph,
.toolkit-table .hyph,
.responsive-table th,
.toolkit-table th {
    hyphens: auto !important;
    -webkit-hyphens: auto !important;
    -ms-hyphens: auto !important;
    overflow-wrap: break-word !important;
}
/* The real fix — beat the page's `hyphens:none`/`word-break:break-all` cruft on the
   header label span (page rules top out at 0,2,2; this is 0,2,3). */
.toolkit-table thead th span.hyph,
.responsive-table thead th span.hyph {
    hyphens: auto !important;
    -webkit-hyphens: auto !important;
    -ms-hyphens: auto !important;
    word-break: normal !important;
    overflow-wrap: break-word !important;
    white-space: normal !important;
}

/* ==========================================================================
   V37 — toolkit-chart cell padding: match PRODUCTION (Steven 2026-06-09).
   Measured on teckel.io (#rpc-pricing-table) — production padding is RESPONSIVE:
   desktop (>768px) = 10px 12px, mobile (<=768px) = 8px 10px (both th + td). The
   staging rebuild flattened it to 8px 10px at all widths (and a prior pass here
   briefly used 6px 7px — reverted in post 10896 to 8px 10px).
   Why this must force BOTH breakpoints with !important: Divi 5 injects padding
   defaults for BOTH `.entry-content thead th{9px 24px}` AND `.entry-content tr
   td{6px 24px}` at (0,1,2). Staging's `.toolkit-table` rules are class selectors
   (0,1,1) that LOSE to those defaults (production wins only because it uses an ID
   selector, `#rpc-pricing-table`, at (1,0,1)). So every cell — th and td, at every
   width — needs an override at higher specificity. (0,2,2)+!important does it, and
   also beats the page <style>'s own padding rules. Production's exact responsive
   values, replicated. Tech debt: fold the page <style>'s padding into this during
   the toolkit page's Phase-5 rewrite.
   ========================================== */
@media (min-width: 769px) {
    .entry-content .toolkit-table thead th,
    .entry-content .toolkit-table td,
    .entry-content .toolkit-table th {
        padding: 10px 12px !important;
    }
}
@media (max-width: 768px) {
    .entry-content .toolkit-table thead th,
    .entry-content .toolkit-table td,
    .entry-content .toolkit-table th {
        padding: 8px 10px !important;
    }
}

/* ==========================================================================
   V38 — variable identifiers wrap at sensible boundaries, not mid-character
   (Steven 2026-06-09; chose "break at _ and caps"). Production used break-all,
   which breaks identifiers mid-character ("get_ethereum_pri / ce_summary") and
   fills tight to the border — Steven wanted better than production. Fix in two
   parts: <wbr> word-break opportunities are inserted into the markup at every
   underscore + camelCase hump (scripts/toolkit-wbr-urls-2026-06-09.php), and the
   variable cells are flipped here from the page <style>'s break-all to
   word-break:normal so the breaks land on those <wbr> boundaries. overflow-wrap:
   break-word is a char-break safety net ONLY if a single boundary-segment is still
   wider than the column (pathological narrowness — better than overflowing). Higher
   specificity (incl. tbody) than the page's per-column break-all rules. Applies to
   both toolkit charts (10896) and the RPC chart (10897); both use .toolkit-table.
   ========================================== */
.entry-content .toolkit-table tbody td code,
.entry-content .toolkit-table tbody td .endpoint-name,
.entry-content .toolkit-table tbody td .param-key,
.entry-content .toolkit-table tbody td:nth-child(2),
/* description prose: identifiers mentioned in it (with <wbr>) must be allowed to
   wrap — the page default is word-break:keep-all + overflow-wrap:normal, so a
   spaceless identifier can't break at all and overflows. */
.entry-content .toolkit-table tbody td .endpoint-desc,
.entry-content .toolkit-table tbody td .param-desc {
    word-break: normal !important;
    overflow-wrap: break-word !important;
    -webkit-hyphens: none !important;
    hyphens: none !important;
    white-space: normal !important;
}
/* URLs linkified in the chart cells (e.g. the OpenAIP link) wrap anywhere */
.entry-content .toolkit-table .urlwrap {
    overflow-wrap: anywhere !important;
    word-break: break-word !important;
}
/* Chart links read as links: orange (contrasts the navy chart text per the site
   link standard — V31's rule is scoped to text/toggle modules, not this code
   module), underline on hover. */
.entry-content .toolkit-table a {
    color: #a1520f !important;
}
.entry-content .toolkit-table a:hover {
    text-decoration: underline !important;
}

/* ==========================================================================
   V39 — restore section dividers inside PARALLAX sections (Divi 5.7.3
   regression; Steven 2026-06-12 "dividers corrupted across the entire site").
   --------------------------------------------------------------------------
   Divi 5.7.3's script-library frontend-parallax.css ships
     .et_pb_section_parallax > :not(.et-pb-parallax-wrapper):not(...)
       { position: relative; z-index: 1; }
   which catches the divider overlay divs (they require position:absolute
   from Divi's own base rule) and out-specifies (0,3,0) the divider rules
   (0,2,0). Result: dividers render IN-FLOW as solid 50-100px bands inset by
   the section padding instead of overlaying the section edge — 90 of 97
   dividers site-wide sat in parallax sections (survey 2026-06-12). Only
   non-parallax sections (e.g. the blue #002349 contact-page dividers) were
   unaffected. Production (Divi 4) has no such rule.

   Fix: restore absolute positioning for dividers in parallax sections, and
   restore z-index:10 for the fullwidth hero bottom dividers (Divi's
   generated per-section CSS wants 10 there, 1 everywhere else — the
   parallax rule's z-index:1 is already correct for the rest). Semantic
   anchors only (V19 lesson: ordinal section classes shift between Divi
   versions). Harmless redundancy if a future Divi fixes the regression.
   ========================================================================== */
.et_pb_section_parallax > .et_pb_top_inside_divider,
.et_pb_section_parallax > .et_pb_bottom_inside_divider {
    position: absolute !important;
}
.et_pb_fullwidth_section.et_pb_section_parallax > .et_pb_bottom_inside_divider {
    z-index: 10 !important;
}

/* ==========================================================================
   V41 — F4 HYBRID SITE-WIDE (2026-06-13; was V40 = the About-only pilot,
   Steven-approved for rollout with the 0.30->end / 2000ms accent fade).
   --------------------------------------------------------------------------
   Companion to the builder-level change of the same date: the entrance
   animation attr was REMOVED from every hero fullwidth-header's Divi JSON
   (script f4-hero-anim-removal-2026-06-13.php; backups in
   archive/f4-pre-anim-2026-06-13/), so heroes render statically from first
   paint and et_animated never appears on them (Divi's animation JS no longer
   touches heroes — the sim-LCP attribution fix). Below-fold modules keep
   their scroll-up entrances untouched. Home's H1 zoom-left was part of its
   header animation and is also gone (flagged to Steven; restore = re-add the
   attr from archive/f4-pre-anim-2026-06-13/post-2741.txt).

   1) Overlay accent fade for ALL hero overlays (Divi native module overlays:
      orange rgba(161,82,15,.7) x8 pages, navy rgba(0,35,73,.65) x19 — audit
      2026-06-12). Element-opacity 0.429 -> 1 over 2000ms = effective tint
      0.30->0.70 (orange) / 0.28->0.65 (navy). NEVER from zero: the static
      white H1 needs tint behind it from frame one. (Home's hero overlay is
      our V19 ::before — same parameters applied there, see V19 keyframes.)
   2) Site-wide H1 navy drop shadow (V18 home spec) so the lettering holds
      during the lighter first frames; approved "for now" on orange overlays
      too (Steven 2026-06-12; swap colour per-family here if he revisits).
   ========================================================================== */
.et_pb_fullwidth_header .et_pb_fullwidth_header_overlay {
    animation: teckelHeroOverlayAccent 2000ms;
}
@keyframes teckelHeroOverlayAccent {
    from { opacity: 0.429; }
    to   { opacity: 1; }
}
.et_pb_fullwidth_header h1.et_pb_module_header {
    text-shadow: rgba(0, 35, 73, 0.65) 0.08em 0.08em 0.08em !important;
}

/* ==========================================================================
   V42 — Toolkit-chart sticky-header ghosting fix (Steven 2026-06-13).
   --------------------------------------------------------------------------
   The toolkit charts' own inline chart CSS gives the header cells
   position:sticky + top:0 + a light background, but a higher-specificity
   Divi/entry-content rule overrides that background to TRANSPARENT. On scroll
   the header labels then pin to the top with no backing and "ghost" over the
   scrolling rows (e.g. only the wrapped tails like "(for MCP clients) and
   Pricing" or "method (RESTful API)" appear stuck). Seen on
   /ethereum-rpc-pricing/ + /teckel-ai-pricing/, mobile AND desktop.
   Pre-existing (chart CSS from the V35-38 era), unrelated to the font pass.
   Fix = drop the sticky behaviour so the headers scroll normally (Steven's
   expectation). If sticky headers are wanted later, do it deliberately with a
   solid opaque background. Covers both chart class variants.
   NOTE: do NOT quote comment-open/comment-close sequences or literal CSS rules
   inside this comment — a nested close would terminate it early (the original
   V42 attempt did exactly that and re-asserted sticky).
   ========================================================================== */
.toolkit-table thead th,
.responsive-table thead th {
    position: static !important;
}

/* ==========================================================================
   V44 - Technical-page body typography normalization (Steven 2026-06-22).
   --------------------------------------------------------------------------
   The Divi-4 migration left /web3-services/ + /teckel-ai/ with body text,
   lists and example prompts wrapped in heading tags, and the body font-size
   INHERITED from the section (25px / line-height 1.2) rather than the brand
   body scale. As those blocks are re-tagged to semantic paragraphs / list
   items (DB content edits, module by module), this PAGE-SCOPED rule brings
   body copy to the chosen technical-page standard (Steven 2026-06-22): 18px /
   line-height 1.6 / weight 400. (The brand-guide's "16px" was never actually
   deployed - the live site body is 25px; 18px is the readable size picked for
   these dense pages.)
   Scoped to the two page ids so the rest of the site is untouched; an intro
   lead keeps its larger size via the more-specific .about-lead rule.
   ========================================================================== */
body.page-id-2914 .et_pb_text_inner p,
body.page-id-2914 .et_pb_text_inner li,
body.page-id-9464 .et_pb_text_inner p,
body.page-id-9464 .et_pb_text_inner li {
    font-size: 18px;
    line-height: 1.6;
    font-weight: 400;
}

/* ==========================================================================
   V45 - Homepage body line-height 1.5 (Steven 2026-06-22).
   The homepage body is a large 25px set with a cramped 1.2 line-height; 1.5
   reads far better at that size (and meets the WCAG text-spacing guideline).
   Page-scoped to the front page so nothing else is affected. (If the homepage
   body later drops toward ~20px, 1.6 becomes ideal.)
   ========================================================================== */
body.home .et_pb_text_inner p {
    line-height: 1.5;
}

/* ==========================================================================
   V46 - Code-block caption labels (Steven 2026-06-22).
   The little labels above code snippets ("Call:", "Response:", "HTTP via curl
   (on linux):", etc.) were <h3> (22px headings) - oversized for captions and
   polluting the heading hierarchy. Re-tagged to <p class="code-label"> across
   the dev pages; this is the compact bold caption style. Specificity matches
   the V44 body rule and wins by later source order.
   ========================================================================== */
p.code-label {
    font-size: 15px !important;   /* beats the V44 body rule + the snippet-wrapper inherited 25px */
    font-weight: 600 !important;
    line-height: 1.4;
    margin: 0 0 6px;
}

/* ==========================================================================
   V47 - Code-snippet copy-icon clearance (Steven 2026-06-22).
   The V46 smaller code-labels let the code block creep up under the
   absolutely-positioned copy/check icon (top:6px in .call-snippet-wrapper),
   so the icon overlapped the code. Restore bottom space on the in-wrapper
   label so the code block starts below the 29px icon again.
   ========================================================================== */
.call-snippet-wrapper .code-label {
    margin-bottom: 18px !important;
}

/* ==========================================================================
   V48 - /teckel-ai/ vertical-rhythm normalization (Steven 2026-06-23).
   --------------------------------------------------------------------------
   The Divi-4 migration spaced content with EMPTY heading/paragraph "spacer"
   lines (inconsistent ~18px / ~47px tall) instead of margins, so body text
   rendered flush (0px) with random gaps. The empty spacer paragraphs were
   removed from the content (DB); this gives the remaining elements a uniform
   margin rhythm: a tight ~18px between paragraphs, a slightly larger space
   around in-flow headings. CRITICAL: it must NOT compound with Divi's between-
   module/row spacing, so (a) the first/last child of a text block has its
   outer margin zeroed (the row gap already separates modules), and (b) the
   code/image MODULES get no extra margin (their separation is the row gap).
   Page-scoped to BOTH technical pages (9464 + 2914 - same migration pattern);
   code-labels (V46/V47) keep their tight caption spacing; the bordered
   marketing-callout keeps its own inline margins (inline wins).
   ========================================================================== */
body.page-id-9464 .et_pb_text_inner p:not(.code-label),
body.page-id-2914 .et_pb_text_inner p:not(.code-label) {
    margin: 0 0 1em;                 /* uniform paragraph spacing (~18px) */
}
body.page-id-9464 .et_pb_text_inner ul,
body.page-id-9464 .et_pb_text_inner ol,
body.page-id-2914 .et_pb_text_inner ul,
body.page-id-2914 .et_pb_text_inner ol {
    margin: 0 0 1em;
}
body.page-id-9464 .et_pb_text_inner li,
body.page-id-2914 .et_pb_text_inner li {
    margin: 0 0 0.35em;
}
body.page-id-9464 .et_pb_text_inner h2,
body.page-id-2914 .et_pb_text_inner h2 {
    margin: 1.2em 0 0.4em;           /* in-flow heading: space above, bound to body below */
}
body.page-id-9464 .et_pb_text_inner h3,
body.page-id-2914 .et_pb_text_inner h3 {
    margin: 1em 0 0.3em;
}
/* don't let the first/last element push past the module edge (avoids doubling
   the Divi row gap into 60-100px boundary gaps) */
body.page-id-9464 .et_pb_text_inner > *:first-child,
body.page-id-2914 .et_pb_text_inner > *:first-child { margin-top: 0; }
body.page-id-9464 .et_pb_text_inner > *:last-child,
body.page-id-2914 .et_pb_text_inner > *:last-child  { margin-bottom: 0; }
/* safety net for any future empty paragraph */
body.page-id-9464 .et_pb_text_inner p:empty,
body.page-id-2914 .et_pb_text_inner p:empty { display: none; }

/* ==========================================================================
   V49 - Notes/captions inside a CODE module (Steven 2026-06-23). A note such
   as the HTTP-vs-SSE caveat under the first MCP config lives in an .et_pb_code
   module, not a text module, so it escaped the V44 18px rule and rendered at
   the 25px section size. Bring code-module paragraphs to body size with a small
   top gap. (That note was ALSO moved out of the bordered call-snippet-wrapper
   so the first code block matches the others - no stray text inside the box.)
   ========================================================================== */
body.page-id-9464 .et_pb_code_inner > p,
body.page-id-2914 .et_pb_code_inner > p {
    font-size: 18px;
    line-height: 1.6;
    margin: 0.6em 0 0;
    /* align the note's text with the actual code-block's left border (the 3px
       brown line) rather than the thin outer module border - matches the
       call-snippet-wrapper's 20px inner padding (Steven 2026-06-23). */
    padding: 0 20px;
    box-sizing: border-box;
}

/* ==========================================================================
   V50 - How-It-Works mobile hero: shorten the band (Steven 2026-06-23).
   The fullwidth-header is full-viewport (100vh) on every device; on a phone
   that tall portrait band cover-crops the wide engraving down to a vertical
   slice (just the professor). Shortening it to ~square lets the mobile crop
   show the professor AND the "HOW TO USE" chalkboard, and roughly halves the
   mobile scroll. Phone only; tablet/desktop keep the full-height hero.
   ========================================================================== */
@media (max-width: 767px) {
    body.page-id-10868 .et_pb_fullwidth_header,
    body.page-id-10868 .et_pb_fullwidth_header .et_pb_fullwidth_header_container {
        min-height: 110vw !important;   /* ~429px @ 390 (the inner container is the real height driver) */
        height: auto !important;
    }
    /* the fullscreen hero starts at viewport top, UNDER the fixed 56px mobile
       navbar, which clipped the professor's head. Start it below the navbar so
       the image's top is revealed (head moves down; students sit a touch lower).
       (Steven 2026-06-23) */
    body.page-id-10868 .et_pb_section:has(.et_pb_fullwidth_header) {
        margin-top: 56px !important;
    }
}

/* ==========================================================================
   V51 - SPACING-SCALE PILOT (Steven 2026-06-23). An 8px-grid vertical rhythm,
   page-scoped to the two technical pages (9464 + 2914) for on-screen review
   BEFORE codifying in brand-guide §12 and rolling out page-by-page. Values are
   tunable. Builds on V44 (18px body) + V48 (within-module paragraph/list
   rhythm); the inter-row gaps are left as-is ("rows already flush"). The
   fullwidth hero section keeps its 0 padding.
     - paragraphs ...... 18px  (V48, unchanged)
     - above h3 ........ 24px
     - above h2 ........ 32px
     - section padding . 64px top/bottom (standardises the current 42/70/100)
   NOTE: section-leading headings are the first child of their text module, so
   V48 zeroes their own margin-top and their air comes from the 64px section
   padding above; the 32/24 heading margins below govern MID-FLOW headings.
   ========================================================================== */
body.page-id-9464 .et_pb_section:not(.et_pb_fullwidth_section),
body.page-id-2914 .et_pb_section:not(.et_pb_fullwidth_section) {
    padding-top: 64px !important;     /* !important to beat Divi's per-section generated padding */
    padding-bottom: 64px !important;
}
body.page-id-9464 .et_pb_text_inner h2,
body.page-id-2914 .et_pb_text_inner h2 {
    margin: 32px 0 8px;              /* above h2 = 32px (grid) */
}
body.page-id-9464 .et_pb_text_inner h3,
body.page-id-2914 .et_pb_text_inner h3 {
    margin: 24px 0 8px;              /* above h3 / between blocks = 24px (grid) */
}
/* Tame two Divi-4 migration artefacts that V48 didn't fully reach and that left
   localised over-gaps once the rest of the rhythm tightened (Steven 2026-06-23):
   (a) lists carried a 25px padding-bottom + 25px margin-bottom -> e.g. the
       "LLM prompt examples:" list ran ~68px into the example prompt after it;
   (b) empty heading spacers (e.g. an empty <h2> between "Errors" and its body on
       2914) rendered ~50px - hide them like V48 hides empty <p> spacers. */
body.page-id-9464 .et_pb_text_inner ul,
body.page-id-9464 .et_pb_text_inner ol,
body.page-id-2914 .et_pb_text_inner ul,
body.page-id-2914 .et_pb_text_inner ol {
    padding-bottom: 0 !important;    /* kill the 25px Divi-4 list padding */
    margin-bottom: 18px !important;  /* uniform with the paragraph rhythm */
}
body.page-id-9464 .et_pb_text_inner :is(h1,h2,h3,h4,h5,h6):empty,
body.page-id-2914 .et_pb_text_inner :is(h1,h2,h3,h4,h5,h6):empty {
    display: none;
}

/* ==========================================================================
   V52 - SPACING-SCALE ROLLOUT (Steven 2026-06-23). The brand-guide §12 scale,
   rolled out page-by-page to the navbar + footer pages (each measured, verified
   computed, and eyeballed before the next). The 64px non-hero section rhythm is
   the universal piece every rolled-out page gets; the within-module cleanups
   (paragraph/heading/list/empty rhythm) are added per page ONLY where a page
   carries the Divi-4 migration artefacts (so clean pages aren't disturbed).
   Body SIZE stays page-type-specific (V44/V45); the 2 technical pages keep
   their own V44+V48+V51 and are not listed here. Hero sections keep 0 padding.
   To roll out a page: append its .page-id-NNNN to the relevant :is() list.

   --- Section rhythm (64px non-hero). Rolled out: 3025 About, 2741 Home,
       10887 Account & Identity; batch: 10881 Get Started, 10884 Resources,
       10888 Other Tools, 7072 Support, 2755 Contact, 8169 Report Abuse. ------- */
body:is(.page-id-3025, .page-id-2741, .page-id-10887, .page-id-10881, .page-id-10884, .page-id-10888, .page-id-6860) .et_pb_section:not(.et_pb_fullwidth_section) {
    padding-top: 64px !important;
    padding-bottom: 64px !important;
}
/* About: the intro paragraph is a lead-in to "Our founders", so tighten THAT
   junction only (Steven 2026-06-23) - drop the facing padding of the intro
   section (_5) + the founders section (_6) 64->24px, so the gap reads ~98px
   (~45% less) instead of a full section break. Other About gaps keep 64px.
   (Targets Divi order-classes; revisit if the section order changes.) */
body.page-id-3025 .et_pb_section.et_pb_section_5 { padding-bottom: 24px !important; }
body.page-id-3025 .et_pb_section.et_pb_section_6 { padding-top: 24px !important; }
/* About: the intro was pinned to a 20px "lead" - now SMALLER than the 25px global
   body, so it read smaller than home on desktop (Steven's vision/readability).
   Bump it to the readable responsive default: 25px desktop / 20px mobile, lh 1.5
   (matches home + the global body so it gets the larger-on-desktop benefit). */
body.page-id-3025 .about-lead { font-size: 25px !important; line-height: 1.5 !important; }  /* beats V30's 20px !important */
@media (max-width: 767px) { body.page-id-3025 .about-lead { font-size: 20px !important; } }
/* other-tools (10888) + resources (10884): the intro <p> + the link-cards live
   in the SAME text module (et_pb_text_3) - the cards are HTML right after the
   intro - so the intro sat only ~40px above them (Steven 2026-06-23: "a little
   more space"). Bump the intro <p>'s bottom margin so the cards breathe. ----- */
body:is(.page-id-10888, .page-id-10884) .et_pb_text_3 .et_pb_text_inner > p:first-child { margin-bottom: 44px !important; }
/* NOTE: Support 7072, Contact 2755, Report Abuse 8169 were REVERTED from V52
   (the rhythm/section treatment disturbed their form fine-print + spacing; they
   have no body prose to benefit). Form-layout issues there are pre-existing. */

/* --- Within-module rhythm: fix flush (touching) paragraphs + list/empty spacers.
   Rolled out: 2741 Home, 10887 Account & Identity (e.g. home's intro, "teckel/
   security blocks had paragraphs at margin:0 = touching). 1em is proportional
   to the page's body size (25px on home). first/last-child resets keep the
   paragraph margins from compounding with the section/row spacing. ----------- */
body:is(.page-id-2741, .page-id-10887, .page-id-10881, .page-id-10884, .page-id-10888) .et_pb_text_inner p:not(.code-label),
body:is(.page-id-2741, .page-id-10887, .page-id-10881, .page-id-10884, .page-id-10888) .et_pb_text_inner ul,
body:is(.page-id-2741, .page-id-10887, .page-id-10881, .page-id-10884, .page-id-10888) .et_pb_text_inner ol {
    margin: 0 0 1em;
}
body:is(.page-id-2741, .page-id-10887, .page-id-10881, .page-id-10884, .page-id-10888) .et_pb_text_inner ul,
body:is(.page-id-2741, .page-id-10887, .page-id-10881, .page-id-10884, .page-id-10888) .et_pb_text_inner ol {
    padding-bottom: 0 !important;
}
body:is(.page-id-2741, .page-id-10887, .page-id-10881, .page-id-10884, .page-id-10888) .et_pb_text_inner li { margin: 0 0 0.35em; }
/* a paragraph that directly introduces a list hugs it (label->content) instead of
   the full 1em gap (Steven 2026-06-23: "Two credentials:" sat 25px above its list) */
body:is(.page-id-2741, .page-id-10887, .page-id-10881, .page-id-10884, .page-id-10888) .et_pb_text_inner p:not(.code-label):has(+ ul),
body:is(.page-id-2741, .page-id-10887, .page-id-10881, .page-id-10884, .page-id-10888) .et_pb_text_inner p:not(.code-label):has(+ ol) {
    margin-bottom: 8px;
}
body:is(.page-id-2741, .page-id-10887, .page-id-10881, .page-id-10884, .page-id-10888) .et_pb_text_inner > *:first-child { margin-top: 0; }
body:is(.page-id-2741, .page-id-10887, .page-id-10881, .page-id-10884, .page-id-10888) .et_pb_text_inner > *:last-child  { margin-bottom: 0; }
body:is(.page-id-2741, .page-id-10887, .page-id-10881, .page-id-10884, .page-id-10888) .et_pb_text_inner :is(h1,h2,h3,h4,h5,h6):empty,
body:is(.page-id-2741, .page-id-10887, .page-id-10881, .page-id-10884, .page-id-10888) .et_pb_text_inner p:empty { display: none; }

/* ============================================================================
   V53 — Fullscreen-hero height, FIREFOX fix  (2026-06-24, robust v3)
   Steven (Firefox) saw the hero collapse to a short band (cutting the mascot) above
   980px, and FLASH it on fast resize. Two compounding causes:
     1. Divi gives the hero CONTAINER `height:100%` — a percentage of an indefinite-height
        parent above 980px (the per-page freeForm only forces a definite height <=980).
        Chrome honors the container's min-height:100vh; Firefox collapses the % instead.
     2. Divi's fullscreen JS computes the height from screen.avail*, which Firefox's
        "resist fingerprinting" spoofs -> the JS transiently sets inline min-height:15px,
        which flashes through during a fast resize wherever no CSS forces the height.
   Fix (covers BOTH, all widths >=980, no upper boundary, no exact height so the desktop
   hero still grows and never head-crops): drop the container's height:100% (-> auto) and
   pin a min-height:100vh that out-!importants the JS's bad inline value. min-width:980
   OVERLAPS the freeForm's max-width:980 so no fractional hi-DPI width slips between them.
   Verified in real Firefox: full 760px (=100vh+pad) flat across 985–1400, no collapse. */
@media (min-width: 980px) {
  .et_pb_fullwidth_header.et_pb_fullscreen,
  .et_pb_fullwidth_header.et_pb_fullscreen .et_pb_fullwidth_header_container {
    height: auto !important;
    min-height: 100vh !important;
  }
}

/* ============================================================================
   V54 — Pricing (6860) marketing-prose: readable line-height + §12 rhythm
   (Steven 2026-06-26, "option 1, full treatment"). The Pricing prose shipped at
   the OLD cramped 25px / line-height 1.2 with margin:0 paragraphs (flush) — below
   the marketing standard the homepage already runs (1.5, V45). Bring it to 1.5 +
   the §12 1em paragraph/list rhythm. (The 64px non-hero SECTION rhythm comes from
   the V52 :is() list above — page-id-6860 appended there.) A table-cell guard +
   the p:not(:has(.teckel-cta)) carve-out keep the pricing TABLE / per-service
   CHARTS (the density exception) and the CTA buttons exactly as they are.
   p-scoped, so plain table <td> text is never touched either way. =========== */
body.page-id-6860 .et_pb_text_inner p { line-height: 1.5 !important; }   /* was 25px/1.2 inherited */
body.page-id-6860 .et_pb_text_inner p:not(:has(.teckel-cta)) { margin: 0 0 1em !important; }  /* §12 rhythm (was margin:0 = flush); CTA buttons keep their inline spacing */
body.page-id-6860 .et_pb_text_inner ul,
body.page-id-6860 .et_pb_text_inner ol { margin: 0 0 1em !important; }
body.page-id-6860 .et_pb_text_inner li { margin: 0 0 0.35em !important; line-height: 1.5 !important; }
/* a paragraph that directly introduces a list hugs it (label -> content) */
body.page-id-6860 .et_pb_text_inner p:has(+ ul),
body.page-id-6860 .et_pb_text_inner p:has(+ ol) { margin-bottom: 8px !important; }
/* heading -> its body = 8px (§12); the section-leading H2's top air comes from the 64px section padding */
body.page-id-6860 .et_pb_text_inner h2 { margin-bottom: 8px !important; }
body.page-id-6860 .et_pb_text_inner > *:first-child { margin-top: 0 !important; }
body.page-id-6860 .et_pb_text_inner > *:last-child  { margin-bottom: 0 !important; }
body.page-id-6860 .et_pb_text_inner p:empty { display: none !important; }
/* density exception: never let the prose rhythm leak into table / chart cells */
body.page-id-6860 :is(.teckel-rtable, .toolkit-table, .responsive-table, table) p {
    line-height: inherit !important;
    margin: 0 !important;
}

/* ============================================================================
   V55 — Mobile chart-card cascade (Steven 2026-06-26). On mobile (<=768px) each
   .teckel-rtable stacks into labelled row-cards (V25); those cards now rise in
   INDEPENDENTLY on scroll (custom IntersectionObserver in functions.php R22 adds
   .in, staggering same-batch entries) — matching the site's card-cascade
   signature, since on mobile the chart IS a stack of cards. The chart's whole-row
   block-slide is suppressed on mobile (scoped to rows containing a .teckel-rtable)
   so the CARDS carry the motion, not block-slide + cards. The hidden state only
   applies once JS adds .tc-cascade (graceful if JS off/blocked). Reduce-motion is
   intentionally NOT honored here — it matches the rest of the site (Divi entrances
   ignore it too; Firefox RFP forces it permanently on), keeping the cascade
   consistent with the prose. Desktop/tablet (>=769px) are untouched — there the
   table is a normal table and keeps its row slide-up. ===================== */
@media only screen and (max-width: 768px) {
  /* suppress the chart row's whole-block Divi entrance so the cards carry the motion */
  body.page-id-6860 .et_pb_row:has(.teckel-rtable) {
    opacity: 1 !important;
    transform: none !important;
    animation: none !important;
  }
  /* per-card: hidden until armed (.tc-cascade) + revealed (.in) by the observer */
  .teckel-rtable tbody tr.tc-cascade {
    opacity: 0;
    transform: translateY(16px);
    transition: opacity .55s ease, transform .55s ease;
  }
  .teckel-rtable tbody tr.tc-cascade.in {
    opacity: 1;
    transform: none;
  }
}

/* ============================================================================
   V56 — Pricing (6860) hero: clear the fixed mobile/tablet navbar (Steven
   2026-06-26). The hero is a FULLSCREEN fullwidth-header (100vh) whose section
   starts at viewport y=0; under the V20 sticky navbar (position:fixed, 56px,
   <=980px) the navbar overlays the top 56px of the hero — exactly where the
   accountant-teckel's ears/head sit — so the head was clipped on mobile AND
   tablet (seen on the S21 + Firefox desktop). PRODUCTION never hits this: there
   the navbar is position:relative (in normal flow) so the hero naturally begins
   at y=56 with the head clear. Reproduce that exact framing by starting the hero
   56px below the viewport top across the fixed-navbar range. Same proven fix as
   V50 (How-It-Works hero), here extended to the whole <=980px sticky range (the
   clip exists wherever the navbar is fixed) and page-scoped to Pricing. Pure CSS,
   zero added bytes, no image re-encode, content unchanged — speed/SEO/AEO/GEO-
   neutral. Desktop (>980px, vertical navbar, no overlap) is untouched. ======= */
@media only screen and (max-width: 980px) {
  body.page-id-6860 .et_pb_section:has(.et_pb_fullwidth_header) {
    margin-top: 56px !important;
  }
}

/* ============================================================================
   V57 — How It Works (10868) marketing spacing + prose readability (Steven
   2026-06-26). Mirrors what Pricing got (V52 section rhythm + V54 prose): the
   body shipped at the OLD cramped 25px / line-height 1.2 with margin:0 (flush)
   paragraphs. Bring the prose to 1.5 + the §12 1em paragraph/list rhythm, and
   the body CONTENT section to the 64/64 non-hero rhythm. Scoped with
   :has(.et_pb_row) so ONLY the content section is touched — the decorative
   parallax image-band (section 2, no rows) keeps its 70/70 per Steven, and the
   fullscreen hero keeps 0 (V50, already tuned; above-fold hero confirmed fine on
   mobile/tablet/desktop). CTA buttons + the Supported-forms cards (which use
   <div>, not <p>) are untouched. ===================================== */
body.page-id-10868 .et_pb_section:not(.et_pb_fullwidth_section):has(.et_pb_row) {
    padding-top: 64px !important;
    padding-bottom: 64px !important;
}
body.page-id-10868 .et_pb_text_inner p { line-height: 1.5 !important; }   /* was 25px/1.2 inherited */
body.page-id-10868 .et_pb_text_inner p:not(:has(.teckel-cta)) { margin: 0 0 1em !important; }  /* §12 rhythm (was flush); CTA buttons keep their inline spacing */
body.page-id-10868 .et_pb_text_inner ul,
body.page-id-10868 .et_pb_text_inner ol { margin: 0 0 1em !important; }
body.page-id-10868 .et_pb_text_inner li { margin: 0 0 0.35em !important; line-height: 1.5 !important; }
/* a paragraph that directly introduces a list hugs it (label -> content) */
body.page-id-10868 .et_pb_text_inner p:has(+ ul),
body.page-id-10868 .et_pb_text_inner p:has(+ ol) { margin-bottom: 8px !important; }
/* heading -> its body = 8px (§12); each step's H2 is first-child so its top air comes from the row/section rhythm */
body.page-id-10868 .et_pb_text_inner h2 { margin-bottom: 8px !important; }
body.page-id-10868 .et_pb_text_inner > *:first-child { margin-top: 0 !important; }
body.page-id-10868 .et_pb_text_inner > *:last-child  { margin-bottom: 0 !important; }
body.page-id-10868 .et_pb_text_inner p:empty { display: none !important; }

/* ============================================================================
   V58 — How It Works (10868) "Supported forms" card cascade (Steven 2026-06-26).
   The 7 form cards live in a CSS auto-fit grid that reflows 3->2->1 columns by
   viewport (Steven likes the reflow). Make them rise in INDEPENDENTLY on scroll
   at ALL widths, reflow-agnostic: a per-CARD IntersectionObserver (functions.php
   R23) arms each card (.tc-cascade) + reveals it (.in) with a DOM-order (reading-
   order) stagger, so 1/2/3 columns all just work — it animates the CARDS, never
   the rows (which is the trick: the grid can reflow however it likes). The
   block's whole-row Divi slide is suppressed (else block-slide + card-cascade =
   double motion) so the CARDS carry the motion. Hidden state only applies once JS
   adds .tc-cascade (graceful if JS off/blocked). Hooked on the grid's stable
   auto-fit style signature (grid + cards are inline-styled, no classes). Reduce-
   motion NOT honored, consistent with the site (see V55/R22). ============= */
body.page-id-10868 .et_pb_row:has(.et_pb_text_inner div[style*="repeat(auto-fit"]) {
    opacity: 1 !important;
    transform: none !important;
    animation: none !important;
}
body.page-id-10868 .et_pb_text_inner div[style*="repeat(auto-fit"] > div.tc-cascade {
    opacity: 0;
    transform: translateY(16px);
    transition: opacity .55s ease, transform .55s ease;
}
body.page-id-10868 .et_pb_text_inner div[style*="repeat(auto-fit"] > div.tc-cascade.in {
    opacity: 1;
    transform: none;
}

/* ============================================================================
   V59 — How It Works (10868) hero H1 reposition (Steven 2026-06-26). Same nudge
   as the /other-tools/ + /resources/ heroes: move the H1 DOWN on mobile and UP on
   tablet to the established ~51% / ~69% spots. The lever is the HERO CONTAINER
   (.et_pb_fullwidth_header_container), NOT the section — so the V50 mobile band
   crop (110vw) is preserved (section padding-top would grow the band). On mobile
   (≤767) the container is flex-centered → padding-top shifts the H1 down (→51%);
   on tablet (768–980) the container is 100vh bottom-pinned → padding-bottom lifts
   the H1 up (→69%). Magnitudes are per-page (this H1 starts the lowest yet — 36%
   mobile / 90% tablet — so 150 / 250px). Desktop (>980) untouched. ======= */
@media only screen and (max-width: 767px) {
  body.page-id-10868 .et_pb_fullwidth_header_container { padding-top: 150px !important; }
}
@media only screen and (min-width: 768px) and (max-width: 980px) {
  body.page-id-10868 .et_pb_fullwidth_header_container { padding-bottom: 250px !important; }
}

/* ============================================================================
   V60 — site-wide brand scrollbars (Steven 2026-06-29; subtlety pass same day).
   The Timetics widget's slot scrollbar was #556374 (= its --tt-secondary-color-50,
   NOT a brand colour). Standardize ALL scrollbars incl. the browser's own: thumb =
   navy-ink scrim with THREE states (rest 0.42 / hover 0.58 / drag 0.72), transparent
   track, slim 11px. Alphas kept low for subtlety per Steven ("a little more subtle…
   across the board"). Dark sections (the Timetics booking widget slot list + its
   timezone dropdown) override the thumb to brand grey #b3b9c2 so it stays visible on
   navy — that override lives in the Timetics mu-plugin. All colours are brand (navy
   ink #011431 / UI grey #b3b9c2) at reduced alpha = compliant per brand-guide §6
   opacity principle. Firefox (scrollbar-color) auto-derives its own hover/drag from
   the rest colour; webkit gets all three explicitly. ===================== */
/* V109 (2026-07-24): the Gecko root-scrollbar styling is scoped to FINE-pointer
   (desktop) devices. On Firefox ANDROID a styled root scrollbar can flip from
   OVERLAY to CLASSIC and RESERVE a right-edge gutter — Steven's S21 full-length
   thin white bar (+ its horizontal twin), Firefox-only (Chromium ignores these
   props on Android), absent on prod (which predates V60). V60's own comment
   says mobile keeps overlay scrollbars — this makes that literal. */
@media (hover: hover) and (pointer: fine) {
  html { scrollbar-width: thin; scrollbar-color: rgba(1,20,49,0.42) transparent; }
}
/* V110 (2026-07-24): the ::-webkit-scrollbar family is ALSO scoped to fine-
   pointer devices. PROVEN on Steven's S21 by on-device CSS bisection (rule
   #267 of the minified sheet): current Firefox Android honors
   ::-webkit-scrollbar for web-compat, and `*::-webkit-scrollbar{width:11px}`
   flips its root scrollbar to CLASSIC — reserving the right-edge gutter that
   V109 (which scoped only the Gecko props) could not remove. Chromium
   ANDROID ignores root scrollbar styling (always overlay) → was never
   affected; desktop Chromium keeps the branded 11px bars via this media. */
@media (hover: hover) and (pointer: fine) {
  *::-webkit-scrollbar { width: 11px; height: 11px; }
  *::-webkit-scrollbar-track { background: transparent; }
  *::-webkit-scrollbar-thumb {
      background: rgba(1,20,49,0.42);
      border-radius: 8px;
      border: 3px solid transparent;
      background-clip: padding-box;
  }
  *::-webkit-scrollbar-thumb:hover {
      background: rgba(1,20,49,0.58);
      border: 3px solid transparent;
      background-clip: padding-box;
  }
  *::-webkit-scrollbar-thumb:active {
      background: rgba(1,20,49,0.72);
      border: 3px solid transparent;
      background-clip: padding-box;
  }
  *::-webkit-scrollbar-corner { background: transparent; }
}
/* V60b (2026-06-29 PM, Steven): give the track a faint navy tint on TABLET + DESKTOP so the
   scrollbar gutter is delineated from the white page; MOBILE keeps a transparent track (its
   scrollbars overlay anyway). `scrollbar-width:thin` (above) slims Firefox — webkit's 11px
   doesn't apply there, so Firefox was rendering its default ~14-17px. */
@media (min-width: 768px) and (hover: hover) and (pointer: fine) {
    /* V109: same fine-pointer guard for the V60b tablet/desktop Gecko tint */
    html { scrollbar-color: rgba(1,20,49,0.42) rgba(1,20,49,0.08); }
}
@media (min-width: 768px) and (hover: hover) and (pointer: fine) {
    /* V110: fine-pointer guard on the webkit tint too */
    *::-webkit-scrollbar-track { background: rgba(1,20,49,0.08); }
}

/* ============================================================================
   V61 — fix the navbar breakpoint "dead zone" (Steven 2026-07-01). Divi's mobile
   header rules stop at @media (max-width:980px) and its vertical-nav (desktop) rules
   start at @media (min-width:981px), leaving the FRACTIONAL viewport band strictly
   between 980 and 981 matching NEITHER. On displays with non-integer CSS pixels
   (Windows display scaling / HiDPI DPR) a window can sit at e.g. 980.4px CSS and land
   in that gap, where the header falls back to Divi's un-mediated base layout = oversized
   logo + the full horizontal menu wrapping (Steven's "corruptednavbar" — PERSISTENT
   across reload, at 100% zoom; seen ~980px in Chrome, ~981px in Firefox). Headless
   Playwright only uses integer CSS widths so it steps over the crack — which is why it
   reproduced only on a real, scaled display.
   Fix: fill the gap with Divi's own mobile (hamburger) treatment. The band is kept
   STRICTLY below 981 (max-width:980.999) so it never overlaps the vertical-nav range —
   overlapping it left the 225px full-height sidebar in place under the hamburger (a
   sidebar+hamburger hybrid). Below 981 the vertical-nav rules don't apply, so these
   overrides land on the plain base header and yield a clean hamburger bar. 980 itself is
   already mobile (Divi), 981+ stays the vertical nav — both untouched. Global header ⇒
   site-wide. Verify by parking the window at ~980.5px CSS in Chrome/Firefox. ========= */
/* Use CSS Media Queries L4 RANGE syntax. LEFT-INCLUSIVE band [980, 981): `980px <= width < 981px`.
   V61d (2026-07-01): the lower bound is now INCLUSIVE (was strict `<`). Reason — DIVI'S OWN core CSS
   has `.et_vertical_nav #main-header .container { margin-left:0 }` at `@media (min-width:980px)`, which
   fires ONE PIXEL EARLIER than Divi's hamburger toggle (`max-width:980`). So at EXACTLY 980px (and all
   through the gap) Divi collapses `.container` to full-width x=0 while still in mobile-hamburger mode,
   which yanks the absolutely-positioned logo to x=-12 (measured). Our old OPEN interval (980,981) did
   NOT cover 980.0, so exactly-980 stayed broken. Including 980 lets our `.container{margin-left:auto}`
   override beat Divi's min-width:980 bleed there too. 981.0 stays Divi-vertical (desktop). Verified: at
   980 with our container-centering, logo returns to x=85 (mobile mechanism); without it, x=-12. */
@media (980px <= width < 981px) {
  /* Replicate the EXACT computed mobile (<=980px) header so the gap matches the real navbar —
     height, positioning AND the logo's horizontal-flip transform (Steven: the gap logo rendered
     "rotated + lowered" because it inherited the DESKTOP logo layout — matrix(1)/80px/relative/y31
     — instead of mobile's matrix(-1)/43px/absolute/y7). Every value measured live: 900px vs 1000px. */
  #main-header                      { position: fixed !important; top: 0 !important; } /* mobile nav is FIXED; the gap's base #main-header is position:relative, which drops the absolute logo's anchor ~16px (Steven's "lowered" logo — console dump: gap #main-header pos=relative + logo y16 vs mobile fixed + logo y7). */
  #main-header                      { height: 56px !important; min-height: 56px !important; }
  /* V61c: pin .container to mobile's EXACT centered geometry (measured at 900: position:relative,
     width:80%, max-width:1080, margin auto => x=90). This is the logo_container's offsetParent, so
     making it deterministic here means left:0 tracks it exactly like mobile — independent of whatever
     base/Divi rules do (or don't) reach this 1px gap. Without this the container collapsed to x=0. */
  #main-header .container           { height: 56px !important; min-height: 56px !important; position: relative !important; width: 80% !important; max-width: 1080px !important; margin-left: auto !important; margin-right: auto !important; }
  #main-header #et-top-navigation   { height: 56px !important; min-height: 56px !important; padding-top: 0 !important; float: right !important; margin-right: 0 !important; }
  #main-header .logo_container      { height: 56px !important; position: absolute !important; top: 0 !important; margin-left: -10px !important;
                                      /* V61b (2026-07-01): zero the base breathing-room margins (line ~1136 .logo_container{margin-top:16px} is UN-mediated, so it leaks into this gap and, on an absolutely-positioned box, top:0+margin-top:16px = the logo dropping to y16). Real mobile <=980 zeroes these at line ~1149; the gap never did. */
                                      margin-top: 0 !important; margin-bottom: 0 !important; padding-bottom: 0 !important;
                                      /* V61c (2026-07-01): left:0/right:10px are EXACTLY mobile's values — they were never wrong. The HORIZONTAL corruption (Steven: logo x=-25 vs mobile x=77.5) came from the offsetParent: mobile's `.container` is centered (x=90) so left:0 => x=80, but the desktop-bleed rule `@media(min-width:980) .container{margin-left:0}` (moved to 981 in V61c) collapsed `.container` to x=0 in the gap => left:0 => x=-10. With that bleed gone, `.container` re-centers in the gap and left:0 tracks it like mobile. padding-left:5px matches mobile exactly. */
                                      left: 0 !important; right: 10px !important; padding-left: 5px !important; }
  #main-header #top-menu            { display: none !important; }   /* hide the horizontal menu */
  #main-header #et_mobile_nav_menu  { display: block !important; float: right !important; }  /* show the hamburger */
  #main-header .mobile_menu_bar     { position: relative !important; top: 12px !important; } /* mobile hamburger position */
  #main-header #logo,
  #main-header .logo_container svg,
  #main-header .logo_container img  { max-height: 43px !important; max-width: 50% !important; margin-left: -15px !important;
                                      transform: matrix(-1, 0, 0, 1, 0, 0) !important; } /* mobile flips the logo */
}

/* V62 (2026-07-02): REVERTED same day — the orange "Schedule Call" accent in the
   mobile/tablet menu lacked adequate contrast on the navy menu (Steven). Item is
   back to the standard white; number kept for history. */

/* V63 (2026-07-02, Steven): desktop vertical-nav submenu flyout narrower —
   Divi default 240px → 216px (−10%), then → 206px (−10px more, same day).
   The flyout anchors to the nav's left edge (opens leftward), so narrowing
   the width keeps it attached. Desktop menu only (#top-menu) — the mobile
   menu is a different structure, untouched. */
body.et_vertical_nav #main-header #top-menu li ul { width: 206px !important; }

/* V64 (2026-07-03, Steven): FAQ (3623) — equal air above/below the mid-page
   "Developer and technical" group heading. The structural row gaps are 27px
   on BOTH sides; the h2's default 10px margin-bottom made it read 27/37.
   5px top + 5px bottom margins land both sides on 32px = the §12 above-h2
   step. Scoped to the page's only .et_pb_text h2 (verified single). */
body.page-id-3623 .et_pb_text h2 { margin-top: 5px !important; margin-bottom: 5px !important; }

/* V65 (2026-07-09): /merch storefront brand pass — Woo shop archive, single product,
   cart/checkout basics. Scope: .woocommerce / .woocommerce-page only (the scope-guard
   mu-plugin keeps Woo off every other page). Cards: white bg (product photos are
   white-field JPGs), hairline #b3b9c2, orange left border, 6px shadow with V23-style
   hover-drop; buttons = the single .teckel-cta style (§10); rhythm per §12. The shop
   H1 + intro (.tkl-shop-head) is injected by teckel-woo-scope.php v0.6.0 — the Divi
   shop template renders NO H1 of its own. SKU row hidden (Printful hash noise). */

/* archive header (injected) */
.tkl-shop-head                        { margin: 0 0 32px; }
.tkl-shop-head h1                     { font-size: 35px; font-weight: 500; line-height: 1.2; color: #011431; margin: 0 0 8px; }
.tkl-shop-head p                      { font-size: 20px; line-height: 1.5; color: #011431; margin: 0; }

/* product grid */
.woocommerce-page ul.products         { display: grid !important; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 24px; margin: 0 0 64px !important; }
/* V128 (2026-08-21, Steven "squished" screenshot): the 4-col track was `1fr`, which is
   `minmax(AUTO, 1fr)` — the auto floor is the item's MIN-CONTENT width, so a card whose
   title has a long unbreakable word claims a wider track and the others are squeezed.
   Measured in FIREFOX across the band (Chromium hides it — CLAUDE.md's own warning):
     981–1024  → 160,146,161, 99,160  (spread 62px; card 4 at 99px vs 160)
     1050      → 160,146,161,121,160  (40)
     1080      → 160,146,161,145,160  (16)
     1100      → 160,153,161,153,160  (8)
     ≥1130     → equal (0)
   `minmax(0, 1fr)` removes the content floor so all four tracks are genuinely equal at
   every width. The ≤980 rule already uses an explicit `minmax(240px, 1fr)` and the
   related-products grid `minmax(240px, 1fr)`, so both are already immune — only the
   base 4-col rule carried the bare `1fr`. */
.woocommerce-page ul.products li.product { width: auto !important; float: none !important; margin: 0 !important; padding: 16px !important;
                                        background: #fff; border: 1px solid #b3b9c2; border-left: 4px solid #a1520f;
                                        box-shadow: 6px 6px 6px rgba(0,35,73,0.4); transition: box-shadow 150ms ease; }
.woocommerce-page ul.products li.product:hover { box-shadow: none; }
.woocommerce-page ul.products li.product img { width: 100%; height: auto; margin: 0 0 12px; }
.woocommerce-page .woocommerce-loop-product__title { font-size: 20px !important; font-weight: 500; color: #011431; padding: 0 !important; }
.woocommerce-page ul.products li.product .price { font-size: 18px; font-weight: 700; color: #011431; margin: 4px 0 12px; display: block; }

/* buttons — the single CTA style (§10), woo pages only */
.woocommerce a.button, .woocommerce button.button, .woocommerce input.button,
.woocommerce button.single_add_to_cart_button, .woocommerce-page .checkout-button,
.woocommerce #place_order             { background: #a1520f !important; color: #fff !important; font-weight: 700 !important;
                                        border: 0 !important; border-radius: 0 !important;
                                        box-shadow: 6px 6px 6px rgba(0,35,73,0.4) !important; transition: background 150ms ease !important; }
.woocommerce a.button:hover, .woocommerce button.button:hover, .woocommerce input.button:hover,
.woocommerce button.single_add_to_cart_button:hover, .woocommerce #place_order:hover
                                      { background: #002349 !important; color: #fff !important; }

/* single product */
.woocommerce div.product .product_title { font-size: 35px; font-weight: 500; color: #011431; line-height: 1.2; }
.woocommerce div.product p.price      { font-size: 25px; color: #011431; font-weight: 700; }
.woocommerce div.product .woocommerce-product-details__short-description { font-size: 20px; line-height: 1.5; }
.woocommerce div.product form.cart .variations select,
.woocommerce div.product form.cart .quantity .qty
                                      { border: 1px solid #b3b9c2; padding: 8px 12px; font-size: 18px; color: #011431; border-radius: 0; }
.woocommerce div.product form.cart .variations select:focus,
.woocommerce div.product form.cart .quantity .qty:focus { outline: 2px solid #a1520f; }
.woocommerce div.product .product_meta .sku_wrapper { display: none; }
.woocommerce div.product .woocommerce-tabs .panel { font-size: 18px; line-height: 1.6; }

/* cart / checkout basics */
.woocommerce table.shop_table         { border: 1px solid #b3b9c2 !important; border-radius: 0 !important; }
.woocommerce table.shop_table th      { background: #002349; color: #fff; }
.woocommerce table.shop_table td      { border-color: #b3b9c2 !important; }
.woocommerce form .form-row input.input-text, .woocommerce form .form-row textarea
                                      { border: 1px solid #b3b9c2; padding: 10px; border-radius: 0; }
.woocommerce form .form-row input.input-text:focus, .woocommerce form .form-row textarea:focus
                                      { outline: 2px solid #a1520f; }

/* breadcrumb: the site has none elsewhere — hide for consistency */
.woocommerce .woocommerce-breadcrumb  { display: none; }

/* responsive
   (V71 2026-07-11): the fixed 2-col band squished cards to ~200-250px between 481 and
   ~600px (Steven's responsive-mode "mobile" widths — the S21 at 384 was always 1-col
   and fine) → auto-fill with a 240px floor: columns derive from available width, cards
   never render below 240px. Same results as before at the approved sizes (384 → 1 col,
   768-980 → 2 cols); the squish band now gets 1 col. Desktop (>980) keeps the base
   4-col rule. The ≤480 1-col rule stays as a redundant floor. */
@media (max-width: 980px) {
  .woocommerce-page ul.products       { grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 16px; }
  .woocommerce-page #left-area        { padding-left: 20px; padding-right: 20px; }
}
@media (max-width: 480px) {
  .woocommerce-page ul.products       { grid-template-columns: 1fr; }
}

/* V66 (2026-07-10): /merch design-review round (Steven) + product-page brand pass.
   (1) BLANK FIRST GRID CELL: Woo's clearfix ::before/::after on ul.products become
       ANONYMOUS GRID ITEMS under display:grid — the ::before ("content:' ';display:table",
       woocommerce-layout.css) occupied cell 1 and pushed every product one cell right on
       all breakpoints → content:none on both.
   (2) PRODUCT CARDS (Steven): bg white → #e1e3e7 (the site's plain-card grey, §10),
       resting 1px #b3b9c2 hairline REMOVED; 4px orange left border + brand shadow +
       V23-style hover shadow-drop kept. The framed product image (its 5px
       rgba(0,35,73,0.65) border = the site image treatment — brand-derived) now drops
       ITS shadow together with the card's on hover, and Divi's .et_overlay (a 1px
       #e5e5e5 border that faded in on image hover — off-brand, the "extra thin line")
       is removed entirely.
   (3) LOOP TITLE + GRID PRICE → ink #011431. The 2026-07-09 "upstream rule" is now
       IDENTIFIED: the shop MODULE PRESET (preset--module--divi-shop--default, in
       et-critical-inline-css) sets li.product h1–h6 AND .price to #002349 with
       !important at specificity (0,5,2) — so the override needs ≥(0,6,x) + !important
       (a bare class chain with !important loses). The same preset supplies the 5px
       rgba(0,35,73,0.65) image frame — that one is brand-derived and KEPT.
   (4) SINGLE PRODUCT brand pass: price + variation-select border lose to the (re-
       generated) et-divi-customizer sheet → !important; Woo tab chrome stripped
       (square, #b3b9c2 hairline base, active tab = ink + 2px orange underline,
       inactive = orange links per link-contrast V31); related-products h2 onto the
       type scale (25/500 ink); DISABLED add-to-cart reads deliberate (#b3b9c2 grey,
       full opacity — was 50%-opacity washed orange); product_meta links orange.
   NOTE: the .tkl-shop-head h1 rule above (V65) is now inert — the /merch H1 lives in
   the TB-8551 hero (fullwidth-header) as of 2026-07-10; the injected intro <p> remains. */

/* (1) grid clearfix → anonymous-grid-item fix */
.woocommerce-page ul.products::before,
.woocommerce-page ul.products::after   { content: none !important; }

/* (2) cards: grey bg, no resting hairline; hover drops the image shadow too; no overlay */
.woocommerce-page ul.products li.product          { background: #e1e3e7; border: 0; border-left: 4px solid #a1520f; }
.woocommerce-page ul.products li.product img      { transition: box-shadow 150ms ease; }
.woocommerce-page ul.products li.product:hover img { box-shadow: none !important; }
.woocommerce-page ul.products li.product .et_overlay { display: none !important; }

/* (3) loop title + grid price = heading ink — (0,6,2) to beat the module preset's (0,5,2)+!important */
.woocommerce-page .et_pb_shop .woocommerce ul.products li.product .woocommerce-loop-product__title { color: #011431 !important; }
.woocommerce-page .et_pb_shop .woocommerce ul.products li.product .price,
.woocommerce-page .et_pb_shop .woocommerce ul.products li.product .price .amount { color: #011431 !important; }

/* (4) single product */
.woocommerce div.product p.price       { color: #011431 !important; }
.woocommerce div.product form.cart .variations select { border-color: #b3b9c2 !important; color: #011431 !important; }
.woocommerce div.product .product_meta a       { color: #a1520f; }
.woocommerce div.product .product_meta a:hover { color: #002349; }
/* tabs: strip Woo chrome → square brand tabs */
.woocommerce div.product .woocommerce-tabs ul.tabs            { padding: 0 !important; margin: 0 0 24px !important; border-bottom: 1px solid #b3b9c2; }
.woocommerce div.product .woocommerce-tabs ul.tabs::before,
.woocommerce div.product .woocommerce-tabs ul.tabs li::before,
.woocommerce div.product .woocommerce-tabs ul.tabs li::after  { display: none !important; border: 0 !important; }
.woocommerce div.product .woocommerce-tabs ul.tabs li         { background: transparent !important; border: 0 !important; border-radius: 0 !important; margin: 0 !important; padding: 0 !important; }
.woocommerce div.product .woocommerce-tabs ul.tabs li a       { padding: 10px 16px !important; font-weight: 500; color: #a1520f; }
.woocommerce div.product .woocommerce-tabs ul.tabs li a:hover { color: #002349; }
.woocommerce div.product .woocommerce-tabs ul.tabs li.active  { border-bottom: 2px solid #a1520f !important; }
.woocommerce div.product .woocommerce-tabs ul.tabs li.active a { color: #011431; }
/* tab link colors: Divi's dynamic css sets #666/#000 with !important — and its rule
   group includes a `#content-area` ID variant that outranks every class chain, so the
   override needs the same ID; the class-only variants cover ID-less layouts and the
   tie (same selector, child theme loads later) resolves our way */
body.woocommerce div.product .woocommerce-tabs ul.tabs li a,
body.woocommerce #content-area div.product .woocommerce-tabs ul.tabs li a        { color: #a1520f !important; }
body.woocommerce div.product .woocommerce-tabs ul.tabs li a:hover,
body.woocommerce #content-area div.product .woocommerce-tabs ul.tabs li a:hover  { color: #002349 !important; }
body.woocommerce div.product .woocommerce-tabs ul.tabs li.active a,
body.woocommerce #content-area div.product .woocommerce-tabs ul.tabs li.active a { color: #011431 !important; }
/* classic (non-module) product loops — the Related grid: Divi dynamic css greys the
   price (#666 !important); the .et_pb_shop-scoped rules above don't reach here */
body.woocommerce ul.products li.product .price,
body.woocommerce ul.products li.product .price .amount { color: #011431 !important; }
/* no sidebar (scope-guard v0.7.0 filter) → let the content column use the page width,
   and drop Divi's sidebar-divider line ghost */
body.single-product #left-area { width: 100% !important; padding-right: 0 !important; }
body.single-product #main-content .container::before { display: none !important; }
/* related products heading onto the scale */
.woocommerce div.product .related.products > h2 { font-size: 25px; font-weight: 500; color: #011431; margin: 0 0 24px; }
/* disabled add-to-cart: deliberate grey, not washed orange */
.woocommerce div.product button.single_add_to_cart_button.disabled,
.woocommerce div.product button.single_add_to_cart_button:disabled {
  background: #b3b9c2 !important; opacity: 1 !important; cursor: not-allowed !important; }

/* V67 (2026-07-11): S21 mobile pass (Steven).
   (a) /merch cards rendered ~48% of their grid track on mobile and hugged the left —
       the Divi shop MODULE's responsive CSS re-imposes Woo's two-up width on
       li.product below 768px (higher-specificity !important) even inside our grid →
       force width:100% of the track at (0,6,2). The 1-col track already spans the
       row = ~79% of the screen, centred by the V21 41px gutters — which is Steven's
       "cards ≈80% of screen width, centred". Desktop unaffected (100% of a 4-col
       track = the previous auto).
   (b) product-page Related grid + the description/tabs box sat at ~70% of the screen
       (Divi's 80% mobile container MINUS V65's 20px #left-area paddings) and read
       narrow/off-centre → drop those paddings ≤767px so both span the full centred
       80% container, matching /merch. Tablets (768–980) keep the 20px. */
.woocommerce-page .et_pb_shop .woocommerce ul.products li.product { width: 100% !important; }
@media (max-width: 767px) {
  .woocommerce-page #left-area { padding-left: 0; padding-right: 0; }
}

/* V68 (2026-07-11): product-page section dividers + related-grid image frames (Steven).
   (a) Product pages render classic (no Divi sections) so they carried no slant
       dividers — recreate the site framing: TOP slant2 #002349 50px (the /contact/
       reference divider, verbatim SVG) + BOTTOM slant2 #a1520f 50px (as /merch and
       the standard content→footer transition), painted as #main-content
       ::before/::after using Divi's own generated slant2 SVGs (double layer with the
       .5 fill-opacity underlay; background-size 100% 50px, repeat-x). Container
       paddings 58/0 → 88/88 so content clears each 50px slant by 38px.
   (b) Related-products card images: the 5px rgba(0,35,73,.65) frame + 6px brand
       shadow come from the shop-module PRESET, which classic loops (Related) never
       receive → replicated for every classic product loop (Divi's .et_shop_image
       loop-thumbnail wrapper is site-wide). V66's generic hover shadow-drop and
       .et_overlay kill already cover these cards. */
body.single-product #main-content { position: relative; }
body.single-product #main-content::before,
body.single-product #main-content::after {
  content: ""; position: absolute; left: 0; right: 0; height: 50px;
  background-size: 100% 50px; background-repeat: repeat-x; pointer-events: none; z-index: 1;
}
body.single-product #main-content::before { top: 0; background-image: url("data:image/svg+xml;utf8,%3Csvg preserveAspectRatio='none' width='100%25' height='140px' viewBox='0 0 1280 140' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='%23002349'%3E%3Cpath d='M1280 140V0H0l1280 140z' fill-opacity='.5' /%3E%3Cpath d='M1280 98V0H0l1280 98z' /%3E%3C/g%3E%3C/svg%3E"); }
body.single-product #main-content::after { bottom: 0; background-image: url("data:image/svg+xml;utf8,%3Csvg preserveAspectRatio='none' width='100%25' height='140px' viewBox='0 0 1280 140' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='%23A1520F'%3E%3Cpath d='M0 0v140h1280L0 0z' fill-opacity='.5' /%3E%3Cpath d='M0 42v98h1280L0 42z' /%3E%3C/g%3E%3C/svg%3E"); }
body.single-product #main-content .container { padding-top: 88px; padding-bottom: 88px; }
/* related / classic-loop image frames (match the shop-module preset; Woo general css
   sets li.product a img box-shadow:none → !important) */
body.woocommerce ul.products li.product .et_shop_image > img {
  border: 5px solid rgba(0,35,73,0.65) !important;
  box-shadow: 6px 6px 6px rgba(0,35,73,0.4) !important; }
/* keep V66's hover shadow-drop winning over the frame shadow */
body.woocommerce ul.products li.product:hover .et_shop_image > img { box-shadow: none !important; }

/* V69 (2026-07-11): /merch mobile — the intro paragraph started at the exact pixel the
   hero section ends (measured gap 0px at 384; every layer between them is zeroed and
   the section's white 50px top slant paints over the text zone) → 32px above the intro
   on mobile (§12 above-h2 step). Desktop keeps its current spacing (Steven's report
   was mobile-specific). */
@media (max-width: 767px) {
  body.woocommerce-shop .tkl-shop-head { margin-top: 32px; }
}

/* V70 (2026-07-11): product-page detail round 2 (Steven).
   (a) price → short-description gap measured 0px (price margin-bottom 0) → 16px, all
       breakpoints (8-grid).
   (b) review-form Submit was the raw Divi default (navy bg, #2ea3f2 text + 2px blue
       border, 3px radius, weight 500) → the single §10 CTA style: orange/white/700,
       square, brand shadow, hover #002349.
   (c) related products rendered 4 × 193px columns on desktop — too narrow (Steven) →
       3 columns ≥981px (~265px cards); the count drops 4→3 server-side (scope-guard
       v0.7.2) so desktop shows one clean row; tablet keeps V65's 2-col, mobile 1-col. */
.woocommerce div.product p.price { margin-bottom: 16px !important; }
.woocommerce #review_form #submit,
.woocommerce #review_form #respond input#submit {  /* (3,1,1) — the customizer styles #respond input#submit at (2,2,1) !important */
  background: #a1520f !important; color: #fff !important; font-weight: 700 !important;
  border: 0 !important; border-radius: 0 !important; padding: 10px 24px !important;
  box-shadow: 6px 6px 6px rgba(0,35,73,0.4) !important; transition: background 150ms ease !important; }
.woocommerce #review_form #submit:hover,
.woocommerce #review_form #respond input#submit:hover { background: #002349 !important; color: #fff !important; }
/* V71 (2026-07-11): related grid = width-driven auto-fill at EVERY breakpoint (Steven:
   "one row of three is ideal; wrapping is fine when they'd squish"). 240px floor →
   desktop (844px content) 3 × 265px as approved; tablet 2-up; the 481-767 band that
   used to cram two ~230px cards now gives 1-2 comfortable columns; ≤480 stays 1-col.
   Replaces the V70 ≥981 3-column rule (this one is unconditional and out-specifies
   the V65/V71 shop-grid media rules). */
body.woocommerce div.product .related.products ul.products { grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); }
/* Divi's dynamic css sets PER-BAND li widths with !important and an :nth-child(n)
   specificity booster (768-980: 28.333% · ≤767: 45.25% · ≤479: 100%) — V65's
   width:auto!important at (0,2,2) loses to their (0,4,1); this is why cards shrank
   inside their grid tracks between 480 and 980px (the S21 at 384 fell in Divi's own
   100% band and always looked right). (0,4,2) + !important wins everywhere; the grid
   tracks govern actual sizing. */
body.woocommerce-page ul.products li.product:nth-child(n) {
  width: 100% !important; margin-left: 0 !important; margin-right: 0 !important; }

/* V72 (2026-07-11): Woo notices + cart/checkout brand pass (Steven's review).
   (a) NOTICE BAR ("...has been added to your cart"): Woo floats the button right and
       lets the text flow around it — top-aligned text, luck-based wrap clearance.
       → flexbox: text vertically centred, firm 24px gap, button never crowded; the
       markup order (button first) is flipped visually with order:2.
   (b) CART REMOVE ✕: Woo red #a00 → brand pink #c9529d; the hover circle centred the
       glyph via line-height, which Jost's metrics skew → true flex centring.
   (c) INPUTS: Divi defaults gave grey #eee fields with #999 text (coupon had NO
       border); select2 country/state had a maroon border, grey fill and a 0-height
       (invisible) arrow → white fields, ink text, #b3b9c2 borders, square, orange
       focus, brand-navy placeholders; select2 dropdown branded (orange highlight).
   (d) RADIOS/CHECKBOXES: default blue accent → orange; shipping-method radios get
       breathing room (flex li, 8px gap — Steven: cramped on mobile in cart totals).
   (e) required asterisk #a00 → brand pink. (f) disabled Woo buttons (Update cart)
       read deliberate grey at full opacity, extending the V66 convention. */
/* (a) notices */
.woocommerce-message, .woocommerce-info {
  display: flex !important; align-items: center; gap: 24px; justify-content: space-between; }
.woocommerce-message::before, .woocommerce-info::before { display: none !important; }
.woocommerce-message > .button, .woocommerce-info > .button {
  order: 2; flex-shrink: 0; float: none !important; margin: 0 !important; white-space: nowrap; }
/* (b) remove ✕  (V73: the × INK sits 3px low in the 38px circle — Jost places the
   glyph low in its line box, which flex centring can't see; measured via hover
   screenshot pixel analysis → 0.16em bottom bias re-centres the ink exactly) */
.woocommerce a.remove {
  color: #c9529d !important; display: inline-flex !important;
  align-items: center; justify-content: center; line-height: 1 !important;
  padding-bottom: 0.16em !important; }
.woocommerce a.remove:hover { background: #c9529d !important; color: #fff !important; }
/* (c) fields (V73: textarea.input-text — the order-notes box — folded in) */
.woocommerce input.input-text, .woocommerce textarea.input-text, .woocommerce .quantity .qty, .woocommerce #coupon_code {
  background: #fff !important; color: #011431 !important;
  border: 1px solid #b3b9c2 !important; border-radius: 0 !important; }
.woocommerce input.input-text::placeholder, .woocommerce textarea.input-text::placeholder, .woocommerce #coupon_code::placeholder { color: rgba(1,20,49,0.4); opacity: 1; }
.woocommerce input.input-text:focus, .woocommerce textarea.input-text:focus, .woocommerce .quantity .qty:focus, .woocommerce #coupon_code:focus { outline: 2px solid #a1520f; }
.woocommerce .select2-container .select2-selection {
  background: #fff !important; border: 1px solid #b3b9c2 !important; border-radius: 0 !important;
  height: auto !important; display: flex; align-items: center; }
.woocommerce .select2-container .select2-selection__rendered {
  color: #011431 !important; line-height: 1.4 !important; padding: 14px 40px 14px 14px !important; }
.woocommerce .select2-container .select2-selection__arrow { height: 100% !important; top: 0 !important; right: 10px !important; }
.select2-dropdown { border: 1px solid #b3b9c2 !important; border-radius: 0 !important; }
.select2-container .select2-results__option--highlighted[aria-selected],
.select2-container .select2-results__option--highlighted[data-selected] { background: #a1520f !important; color: #fff !important; }
.select2-search--dropdown .select2-search__field { border: 1px solid #b3b9c2 !important; outline: none; }
/* (d) radios / checkboxes (V73 added 8px above the list; V76 fixes the REAL geometry
   Steven screenshotted — in Woo's stacked mobile table the "Shipping:" data-title
   FLOATS LEFT with the option list flowing beside it right-aligned, so the first
   dial sat against the colon mid-line → on mobile the label becomes a block on its
   own line and the whole shipping cell left-aligns; dials line up cleanly under it) */
.woocommerce input[type=radio], .woocommerce input[type=checkbox] { accent-color: #a1520f; }
.woocommerce ul#shipping_method { margin-top: 8px !important; }
.woocommerce ul#shipping_method li { display: flex; align-items: baseline; gap: 8px; margin-bottom: 10px; }
@media (max-width: 767px) {
  .woocommerce table.shop_table_responsive tr.woocommerce-shipping-totals td { text-align: left !important; }
  .woocommerce table.shop_table_responsive tr.woocommerce-shipping-totals td::before {
    float: none !important; display: block !important; margin-bottom: 8px; }
  .woocommerce ul#shipping_method li, .woocommerce ul#shipping_method li label { text-align: left; }
}
.woocommerce ul#shipping_method li input { margin: 0; flex-shrink: 0; position: relative; top: 2px; }
.woocommerce ul#shipping_method li label { flex: 1; }
/* (e) required asterisk */
.woocommerce .form-row .required { color: #c9529d !important; }
/* (f) disabled woo buttons */
.woocommerce button.button:disabled, .woocommerce button.button.disabled {
  background: #b3b9c2 !important; color: #fff !important; opacity: 1 !important; cursor: not-allowed !important; }

/* V74 (2026-07-11): spinners + error notices + mobile checkout-button air (Steven).
   (a) SPINNERS: Woo's blockUI/loader ::before is a GREY SVG background-image
       (loader.svg — colour baked into the bytes, immune to CSS color; the Timetics
       chevron lesson) → background killed, spinner re-drawn as a CSS arc: faint
       navy-ink ring + brand-orange top arc, Woo's own spin animation retained.
   (b) ERROR NOTICES ("Please enter a coupon code."): Divi's dynamic css paints ALL
       notices its default blue #2ea3f2; the customizer override that turns
       message/info navy does NOT cover .woocommerce-error → navy bar + 4px brand-pink
       left border (§6 error colour as the accent), white text, red default icon off.
   (c) mobile: 32px below .wc-proceed-to-checkout so the button clears the section's
       orange slant divider (visible gap was ~20px). */
.woocommerce .blockUI.blockOverlay::before, .woocommerce .loader::before {
  background: none !important;
  border: 3px solid rgba(1,20,49,0.15) !important;
  border-top-color: #a1520f !important;
  border-radius: 50% !important; }
.woocommerce .woocommerce-error, .woocommerce-error {
  background: #002349 !important; color: #fff !important;
  border-top: 0 !important; border-left: 4px solid #c9529d !important; }
.woocommerce-error li { color: #fff !important; }
.woocommerce-error::before { display: none !important; }
.woocommerce-error a { color: #fff !important; text-decoration: underline; }
@media (max-width: 767px) {
  .woocommerce-cart .wc-proceed-to-checkout { margin-bottom: 32px !important; }
}

/* V77 (2026-07-12): product purchase-area cleanup, all breakpoints (Steven's
   sizing.jpg — the variations TABLE wraps unpredictably at narrow widths [the select
   landed ABOVE its "Size" label], the Printful Size Guide is an unstyled classless
   <a> in secondary navy, and the qty box + Add-to-cart sat unaligned).
   New layout: "Size" label over a full-width select → Size Guide as a proper orange
   link with 16px air → qty + button as one flex row, equal heights. */
.woocommerce div.product form.cart table.variations,
.woocommerce div.product form.cart table.variations tbody,
.woocommerce div.product form.cart table.variations tr,
.woocommerce div.product form.cart table.variations th.label,
.woocommerce div.product form.cart table.variations td.value {
  display: block !important; width: 100% !important; padding: 0 !important;
  margin: 0 !important; border: 0 !important; text-align: left !important; }
.woocommerce div.product form.cart table.variations { margin-bottom: 20px !important; }  /* V77e: gaps 8->20 (Steven) */
/* V77c (2026-07-12, Steven's 4-screenshot set): UNIFORM spacing at every width, matched
   to the Size→dropdown step (~10px). The width-varying "too close/too far" mystery was
   the hidden "Clear" reset anchor — Woo hides it with an inline visibility:hidden,
   which KEEPS its box (33px + margin) inside the variations table below the select →
   collapse it while hidden (attribute-substring match; it reappears normally once a
   size is chosen). Rhythm: table-mb 8 + row-mt 0 (+ guide 8/8) → ~10px steps
   everywhere, matching the label→select gap. */
.woocommerce div.product form.cart .reset_variations[style*="visibility: hidden"],
.woocommerce div.product form.cart .reset_variations[style*="visibility:hidden"] { display: none !important; }
.woocommerce div.product form.cart table.variations th.label {
  font-size: 18px; font-weight: 500; color: #011431; margin-bottom: 20px !important;
  line-height: 1; }  /* V77d: line-height 1 → label→select gap is exactly the 8px margin */
.woocommerce div.product form.cart table.variations td.value select {
  width: 100% !important; max-width: 420px; padding: 10px 12px;
  display: block; }  /* V77d: block kills the 2px inline line-box leading above the select — label→select becomes exactly 8px */
.woocommerce div.product form.cart .reset_variations { display: inline-block; margin-top: 8px; }
.woocommerce div.product form.cart .reset_variations:hover { color: #002349 !important; }  /* V77f: Clear link hover -> secondary navy (Steven) */
/* the Printful Size Guide link (classless <a>, first child of .single_variation_wrap) */
.woocommerce div.product form.cart .single_variation_wrap > a:first-of-type {
  display: inline-block; margin: 0 0 20px; font-size: 18px;  /* V77e: 20px steps */
  color: #a1520f !important; text-decoration: underline; }
.woocommerce div.product form.cart .single_variation_wrap > a:first-of-type:hover { color: #002349 !important; }
/* qty + add-to-cart: one aligned row (variable AND simple products) */
.woocommerce div.product form.cart .woocommerce-variation-add-to-cart {
  display: flex !important; align-items: stretch; gap: 16px; margin-top: 0; }
.woocommerce div.product form.cart:not(.variations_form) {
  display: flex !important; align-items: stretch; gap: 16px; margin-top: 16px; }
.woocommerce div.product form.cart div.quantity { float: none !important; margin: 0 !important; }
.woocommerce div.product form.cart .quantity .qty { height: 100% !important; min-height: 51px; box-sizing: border-box; }
.woocommerce div.product form.cart .single_add_to_cart_button { margin: 0 !important; }

/* V75 (2026-07-12): coupon errors, banner notices, button hover-shrink (Steven).
   (a) Woo 10 renders coupon errors INLINE under the field (.coupon-error-notice,
       default #a00 red — NOT a .woocommerce-error notice, which is why V74 didn't
       catch "Please enter a coupon code." / "Coupon ... does not exist") → brand
       pink, incl. the has-error field state. Belt: Woo's block notice-banners
       (used by some flows) → navy bar, pink accent for errors / orange otherwise.
   (b) EVERY Woo button shrank on hover (51px → 37px): Divi's dynamic css swaps
       hover padding to its icon-button pattern (0.3em 2em 0.3em 1em) and paints a
       hover arrow → padding locked to the resting 12px 28px in BOTH states across
       the Woo button set, Divi's hover ::after arrow suppressed. */
.woocommerce .coupon-error-notice, .woocommerce .coupon-error-notice a { color: #c9529d !important; }
.woocommerce input.input-text.has-error, .woocommerce #coupon_code.has-error { border-color: #c9529d !important; }
.woocommerce input.input-text.has-error:focus, .woocommerce #coupon_code.has-error:focus { outline-color: #c9529d !important; }
.wc-block-components-notice-banner.is-error,
.wc-block-components-notice-banner.is-success,
.wc-block-components-notice-banner.is-info {
  background: #002349 !important; color: #fff !important; border: 0 !important; border-radius: 0 !important; }
.wc-block-components-notice-banner.is-error { border-left: 4px solid #c9529d !important; }
.wc-block-components-notice-banner.is-success, .wc-block-components-notice-banner.is-info { border-left: 4px solid #a1520f !important; }
.wc-block-components-notice-banner svg { fill: #fff !important; }
.wc-block-components-notice-banner a { color: #fff !important; }
.woocommerce a.button, .woocommerce button.button, .woocommerce input.button,
.woocommerce button.single_add_to_cart_button, .woocommerce-page .checkout-button,
.woocommerce #place_order, .woocommerce #review_form #respond input#submit,
.woocommerce a.button:hover, .woocommerce button.button:hover, .woocommerce input.button:hover,
.woocommerce button.single_add_to_cart_button:hover, .woocommerce-page .checkout-button:hover,
.woocommerce #place_order:hover, .woocommerce #review_form #respond input#submit:hover {
  padding: 12px 28px !important; }
.woocommerce a.button::after, .woocommerce button.button::after, .woocommerce input.button::after,
.woocommerce-page .checkout-button::after, .woocommerce #place_order::after {
  display: none !important; content: none !important; }

/* V73 (2026-07-11): cart thumbnails at USABLE sizes (Steven). Woo hard-codes
   table.cart img to 32px (tiny everywhere, worse near 980) and its small-screen
   stylesheet HIDES .product-thumbnail entirely in the stacked mobile table →
   80px fixed on desktop/tablet; on mobile the cell is shown again, centred, at
   96px, with the stacked-row data-title label suppressed. */
.woocommerce table.cart img { width: 80px !important; height: auto !important; }
@media (max-width: 768px) {
  .woocommerce table.shop_table_responsive tr td.product-thumbnail { display: block !important; text-align: center !important; }
  .woocommerce table.shop_table_responsive tr td.product-thumbnail::before { display: none !important; }
  .woocommerce table.shop_table_responsive tr td.product-thumbnail img { width: 96px !important; margin: 0 auto; float: none !important; }
}

/* V78 (2026-07-19) — brand native checkboxes/radios SITE-WIDE: orange accent + orange keyboard focus ring
   + no stray hover outline. Kills the non-brand blue the browser (e.g. Opera desktop) paints on hover/focus
   of native form controls. Newsletter form keeps its own higher-specificity .tkl-nl rules. */
input[type="checkbox"], input[type="radio"] { accent-color: #a1520f; }
input[type="checkbox"]:hover, input[type="radio"]:hover { outline: none; }
input[type="checkbox"]:focus-visible, input[type="radio"]:focus-visible { outline: 2px solid #a1520f !important; outline-offset: 2px; }

/* ============================================================================
   V79 (2026-07-21) — /newsletter/ (4900) hero clip + hero zoom + form width on
   mobile/tablet (Steven, from the S21 + Firefox responsive modes).
   (a) HERO CLIP: the fullscreen hero section starts at viewport y=0 under the
       fixed 56px mobile/tablet navbar (V20), which sliced the top of the
       newspaper-teckel's flat cap. The hero image is a CSS-mode parallax bg on
       the SECTION (attachment:scroll, position 50% 0% = top-anchored to the
       section), so shifting the section shifts the image with it. Same proven
       fix as V56 (Pricing) / V50 (How-It-Works): start the section 56px down
       across the whole fixed-navbar range (<=980). Desktop >980 (vertical
       navbar, no overlap) untouched.
   (b) HERO ZOOM ("shrink the image a little"): at 100vh the 800x800 art
       cover-crops to a zoomed slice — a 360x800 phone band renders it at
       natural scale showing only ~45% of its width; tablet 768x1024 over-zooms
       to 128%. Shorten the band so `cover` scales the art down: phone
       min(130vw,100vh) => ~0.66 scale @360 (whole bike + basket in frame;
       min() leaves landscape phones at their current 100vh); tablet
       min(100vw,100vh) => a square band that fits the full square art
       (~0.96 @768). height:auto lets content win if it ever outgrows the
       band; !important beats the module's own <=980 `height:100vh!important`
       (V50 precedent). H1 stays flex-centered in the shorter band, clear of
       the bottom divider (verified 256px top @360, divider starts 485).
   (c) FORM WIDTH (phone only — Steven's "90-95%" ask): the V21 41px mobile
       gutters left the form row at 278px/77% @360. Mirror the V21b calendar
       treatment — 8px gutters => 344px/95.6% @360 — scoped to any row holding
       the form card (:has(.tkl-nl-card)), later source order + :has beats the
       V21 base rule. Tablet keeps the standard 41px gutters (rule is <=767).
   Pure CSS, zero added bytes/requests, content unchanged — speed/SEO/AEO/GEO-
   neutral. Verified pre-deploy via a route-intercepted fresh Firefox load
   (mobile 360x800 + tablet 768x1024): cap fully visible, no divider bleed,
   row 344px. ============================================================== */
@media only screen and (max-width: 980px) {
  body.page-id-4900 .et_pb_section:has(.et_pb_fullwidth_header) {
    margin-top: 56px !important;
  }
}
@media only screen and (max-width: 767px) {
  body.page-id-4900 .et_pb_fullwidth_header,
  body.page-id-4900 .et_pb_fullwidth_header .et_pb_fullwidth_header_container {
    min-height: min(130vw, 100vh) !important;
    height: auto !important;
  }
  .et_pb_section > .et_pb_row:not(.et_pb_row_fullwidth):has(.tkl-nl-card) {
    max-width: calc(100% - 16px) !important;
    margin-left: 8px !important;
    margin-right: 8px !important;
  }
}
@media only screen and (min-width: 768px) and (max-width: 980px) {
  body.page-id-4900 .et_pb_fullwidth_header,
  body.page-id-4900 .et_pb_fullwidth_header .et_pb_fullwidth_header_container {
    min-height: min(100vw, 100vh) !important;
    height: auto !important;
  }
}

/* ============================================================================
   V80→V82 (2026-07-21) — /account-identity/ (10887) hero: Steven's Account-
   Identity GRID art (20 engraved teckel portraits with 0x-address plaques,
   5x4 tiles) replaces the teckel_footer_2 placeholder. The image half is a
   page-10887 DB edit (section bg device slots + the header overlay →
   rgba(161,82,15,0.7), the /about/ ORANGE wash, was navy 0.65); this block is
   the geometry half. V81 round (same day, Steven's S21/Firefox review):
   3-col variant added for a smoother 2→4-col transition, 4-col right edge
   recropped (v1's x=1208 cut showed col5's left frames — clean gutter zone is
   1185..1211, now cut at 1190; 3-col cut at 895 in zone 877..916), a UNIFORM
   110px baked TOP strip on every variant ("move the image down a little" —
   also armour for fixed-navbar-over-desktop-CSS states like Steven's RFP
   Firefox, where a top bar can overlay the art: it covers paper, not heads),
   and narrow desktop 981-1279 swaps the 5-col for the 4-col (5-col tiles got
   tiny beside the 225px vertical nav; Steven's call).
   V82 same-day: v3 files — SYMMETRIC 40px side margins composited (v2 kept
   the source's 40px left paper but cut mid-gutter right => tile block sat
   left-shifted wherever the art fills the width; desktop full image was
   already symmetric) + right frame lines INCLUDED (frame anatomy measured at
   threshold<190: col2 ends x=606, col3 x=897 [v2's 895 cut EXCLUDED it —
   Steven's report], col4 x=1187; crops now frame+6px sliver, beige-extended
   to 40px pads: 2col 646x1054 / 3col 937x1304 / 4col 1227x1304, ids 11145-47,
   ratios 163.2/139.2/106.3vw; 2col bottom cut 749=>754 — row3's bottom frame
   at y=746-748 was 1px from the edge). 5col_v2 (id 11141) unchanged.
   Variants (all: tile-gutter crops, baked #f1dcc0 top 110px + bottom strips
   sized for their range's worst-case scale so the ~100px slant2 divider always
   lands on paper): 5col_v2 1536x1354 (bottom 220, 265KB) · 4col_v2 1190x1304
   (170, 213KB) · 3col_v2 895x1304 (170, 160KB, CSS-only — Divi has only 3
   device slots) · 2col_v2 607x1049 (190, 83KB). Attachment ids 11141-44
   (v1 11138-40 deleted). Rendering: size:contain + position center top +
   #f1dcc0 base (DB attrs; desktop parallax/fixed stays OFF).
   Width map: <=550 2-col (phone slot) · 551-767 3-col (CSS override below;
   selector (0,2,2) out-specifies the et-cache `.et_pb_section_9` (0,1,0) so
   file order vs the deferred unified CSS is irrelevant) · 768-980 4-col
   (tablet slot) · 981-1279 4-col (CSS override of the desktop slot) ·
   >=1280 5-col (desktop slot). Bands = padded-ratio min()'d vs 100vh;
   desktop stays fullscreen 100vh. margin-top 56px <=980 = V56 navbar-clip.
   ========================================================================== */
@media only screen and (max-width: 980px) {
  body.page-id-10887 .et_pb_section:has(.et_pb_fullwidth_header) {
    margin-top: 56px !important;
  }
}
@media only screen and (max-width: 550px) {
  body.page-id-10887 .et_pb_fullwidth_header,
  body.page-id-10887 .et_pb_fullwidth_header .et_pb_fullwidth_header_container {
    min-height: min(163.2vw, 100vh) !important;
    height: auto !important;
  }
}
@media only screen and (min-width: 551px) and (max-width: 767px) {
  body.page-id-10887 .et_pb_section:has(.et_pb_fullwidth_header) {
    background-image: url('/wp-content/uploads/2026/07/teckel_account_identity_3col_v3.webp') !important;
  }
  body.page-id-10887 .et_pb_fullwidth_header,
  body.page-id-10887 .et_pb_fullwidth_header .et_pb_fullwidth_header_container {
    min-height: min(139.2vw, 100vh) !important;
    height: auto !important;
  }
}
@media only screen and (min-width: 768px) and (max-width: 980px) {
  body.page-id-10887 .et_pb_fullwidth_header,
  body.page-id-10887 .et_pb_fullwidth_header .et_pb_fullwidth_header_container {
    min-height: min(106.3vw, 100vh) !important;
    height: auto !important;
  }
}
@media only screen and (min-width: 981px) and (max-width: 1279px) {
  body.page-id-10887 .et_pb_section:has(.et_pb_fullwidth_header) {
    background-image: url('/wp-content/uploads/2026/07/teckel_account_identity_4col_v3.webp') !important;
  }
}

/* ============================================================================
   V83 (2026-07-22) — /contact/ (2755) hero de-zoom (the standing backlog
   "contact hero shrink"; Steven: "shrink the hero a little so more of the
   teckel can be seen"). The hero is a CONTENT-TALL section (the Divi contact
   form lives inside it) with a section-level CSS-parallax bg
   (Teckel_Contact_Page.webp, 800x774 standing teckel on WHITE, all 3 device
   slots) — `cover` against that tall box rendered the dog at 1.8x on desktop
   (head-to-tail crop, no legs) and a 35%-width fur sliver on phones.
   Fix: `background-size:contain` on the page's parallax spans — the art's own
   white ground makes the letterboxing invisible on the white section, so the
   ENTIRE dog (nose to paws) shows at every width: desktop 1.16x (fixed
   parallax kept; sizes against the viewport), tablet ~0.89x, phone width-fit
   0.45x behind the H1 block. Companion fix ≤980: the section carried fixed
   height attrs (tablet 1280 / phone 1000) that `cover`'s fur zoom used to
   fill — with contain they became a big blank band under the form, so the
   section drops to height:auto (content-hugging; tablet 784, phone 697; the
   bottom divider rides up with it). Desktop keeps its 900px — the full dog
   fills it by design. Scoped to the page's ONLY parallax section via
   :has(> .et-pb-parallax-wrapper). Route-injected fresh-load previews at
   1440/768/360 before deploy. ========================================== */
body.page-id-2755 .et-pb-parallax-background {
  background-size: contain !important;
}
@media only screen and (max-width: 980px) {
  body.page-id-2755 .et_pb_section:has(> .et-pb-parallax-wrapper) {
    height: auto !important;
  }
}
/* V84→V85 (2026-07-22) — /contact/ hero placement round 2 (Steven, after
   V83): phone: dog moves DOWN 150px, eased to 100px in V85 (Steven's call
   from the live 150 version) — the H1/phone/*Required* block gets clean
   white, the dog sits behind the translucent Name/Email/Company fields
   (image 348px + 150 offset = 498, inside the ~697 content-hugged section).
   tablet: dog shrinks contain(100%)→85% width (768→653) + 25px down for
   headroom; face clears between the H1 and the Email field. Later source
   order than V83's contain rule = the size override wins at its range. */
@media only screen and (max-width: 767px) {
  body.page-id-2755 .et-pb-parallax-background {
    background-position: center 100px !important;
  }
}
@media only screen and (min-width: 768px) and (max-width: 980px) {
  body.page-id-2755 .et-pb-parallax-background {
    background-size: 85% auto !important;
    background-position: center 25px !important;
  }
}

/* V86 (2026-07-22) — V85's math-captcha recolor REVERTED same day (Steven):
   orange + white drop shadow read WORSE than the module's own white + navy
   glow wherever the hero image sits behind the equation (the /contact/
   desktop dog fur). Rule removed — the et-cache module styling (white text,
   navy 0 0 6.3px glow, orange answer input) is the standing treatment; do
   not re-brand this element without testing it OVER the hero art. */

/* ============================================================================
   V87 (2026-07-22) — SITE-WIDE keyboard-focus uniformity + /contact/ error
   growth + skip-link branding (Steven's 6-screenshot tab-through audit).
   The site runs a Divi accessibility helper ("da11y": the skip-link + a
   .keyboard-outline class on focused links) whose MIXED palette (teal skip
   ring, orange logo ring, white nav rings) + Divi's #2ea3f2 field ring +
   browser defaults = Steven's "tab highlight boxes not uniform".
   ONE brand system, two inks (the newsletter form's established convention,
   now enforced globally): ORANGE rings on light surfaces · WHITE rings on
   navy/orange surfaces. WCAG note: single-colour-everywhere fails non-text
   contrast (orange on navy ≈ 2.3:1) — two-tone is the accessible uniform.
   ========================================================================== */
/* (a) /contact/ desktop: grow with Divi validation errors (the section is
   100vh-designed and CLIPPED at that height — errors pushed the form under
   the footer; ≤980 already height:auto per V83). V88 corrected min-height
   900px→100vh (900 was my 900px-viewport test reading — at taller screens a
   px floor would have SHRUNK the hero). */
@media only screen and (min-width: 981px) {
  body.page-id-2755 .et_pb_section:has(> .et-pb-parallax-wrapper) {
    height: auto !important;
    min-height: 100vh;
  }
}
/* V88 (2026-07-22) — same growth fix for the OTHER two form pages (Steven:
   "they do not auto-grow" — correct; my earlier static grep missed their
   heights because all three form sections are `height:100vh`, not px).
   All widths (their sections are 100vh at every breakpoint). */
body.page-id-7072 .et_pb_section:has(.et_pb_contact_form_container),
body.page-id-8169 .et_pb_section:has(.et_pb_contact_form_container) {
  height: auto !important;
  min-height: 100vh;
}
/* (b) the uniform rings. Fields: kills Divi's keyboard-focus #2ea3f2 (mouse
   :focus keeps each module's own navy/brand styling — those are fine). */
body input:focus-visible, body textarea:focus-visible, body select:focus-visible {
  outline: 2px solid #a1520f !important;
  outline-offset: 2px !important;
}
body a:focus-visible, body button:focus-visible, body [tabindex]:focus-visible,
body a.keyboard-outline:focus, body button.keyboard-outline:focus {
  outline: 2px solid #a1520f !important;
  outline-offset: 2px !important;
}
/* navy surfaces → white rings (V94: + the hamburger toggle — a SPAN[tabindex],
   not an anchor, so it fell through to the global orange rule) */
#main-header [tabindex]:focus-visible,
#main-header a:focus-visible, #main-header a.keyboard-outline:focus,
#main-footer a:focus-visible, #main-footer a.keyboard-outline:focus,
#et-footer-nav a:focus-visible, .et_mobile_menu a:focus-visible {
  outline-color: #ffffff !important;
}
/* orange-surface controls → white rings */
body .et_pb_button:focus-visible, body input[type="submit"]:focus-visible,
body .et_pb_contact_submit:focus-visible, body .woocommerce a.button:focus-visible,
body .woocommerce button.button:focus-visible {
  outline-color: #ffffff !important;
}
/* (c) V93 REVERTED the anchor display/font-size/line-height collapse that was
   here — it CORRUPTED the mobile/tablet logo (tiny dog + exposed buffer img).
   The keyboard focus ring keeps the white colour below; the multi-fragment
   outline quirk on the logo is accepted. */
#main-header a:has(> svg#logo):focus-visible,
#main-header a.keyboard-outline:has(> svg#logo):focus {
  outline: 2px solid #ffffff !important;
  outline-offset: 6px !important;
}
/* (d) skip-link: KEPT deliberately — it is the WCAG 2.4.1 bypass that lets
   keyboard/screen-reader users jump past the nav; Lighthouse a11y checks it.
   Branded as a tooltip-style chip (was a default white box + teal ring). */
body .skip-link.da11y-screen-reader-text:focus {
  background: #002349 !important;
  color: #ffffff !important;
  border: 2px solid #a1520f !important;
  outline: none !important;
  box-shadow: 6px 6px 6px rgba(0, 35, 73, 0.4) !important;
  padding: 14px 22px !important;
  font-weight: 600 !important;
  border-radius: 0 !important;
}

/* ============================================================================
   V89→V90 (2026-07-22) — /support/ + /report-abuse/ hero de-zoom + form-
   feedback readability. V90 same-day corrections (Steven, 7-10.jpg):
   (a) SECTION BG matches each art's own paper so the art box is seamless —
       support #FAFBF8 (Steven's sample confirmed) · report-abuse #EFE9D9
       (its police art is a warmer cream — sampled corners; NOT #FAFBF8) ·
       contact's art is pure white on a white section, already seamless.
   (b) heroes: `auto 85%` height-lock (phone 75% — V90 "shrink a bit more"),
       CENTRED IN THE SECTION — background-attachment:scroll kills the
       viewport-fixed positioning that pulled the art right of content-centre
       on desktop — and 40px down at every width (V89's 20px ≤980 wasn't
       enough: the headset touched the top divider/navbar).
   (c) error/success lines: WHITE PER-LINE highlights (width:fit-content on
       each p/li, bullets inside) — V89's container-wide card read as "a whole
       big white block" AND, being always-in-DOM, rendered an empty white BAR
       above the fields when there were no errors. Container fully reset.
   (d) captcha chip: inline-FLEX (align-items:center) — V89's inline-block let
       the answer input overflow the navy chip bottom. Input margin zeroed.
   Chip + error styling GLOBAL for the 3 cloned forms.
   ========================================================================== */
body.page-id-7072 .et-l--post > .et_builder_inner_content .et_pb_section:has(.et_pb_contact_form_container) {
  background-color: #FAFBF8 !important;
}
body.page-id-8169 .et-l--post > .et_builder_inner_content .et_pb_section:has(.et_pb_contact_form_container) {
  /* V113 (2026-07-24): #EFE9D9 → #EBE6D8 to match police_teckel.webp's ACTUAL
     top-edge paper (Steven: the top strip bordering the navbar). #EFE9D9 was a
     bright mis-sample; the art paper at the exposed top edge is ~(235,230,216),
     so the section-paper strip read brighter than the art = a visible band.
     Chips follow to the same base @82% (below) so hero paper == chip. */
  background-color: #EFE9DB !important;
}
body.page-id-7072 .et_pb_section:has(.et_pb_contact_form_container) .et-pb-parallax-background,
body.page-id-8169 .et_pb_section:has(.et_pb_contact_form_container) .et-pb-parallax-background {
  /* V105: 85% → 85vh — same error-state-growth immunity as mobile; on
     desktop ≥981 the V100 fixed-attachment sizes against the viewport
     anyway, so this changes tablet behaviour only (same normal-state size). */
  background-size: auto 85vh !important;
  background-position: center 40px !important;
}
/* V100 (2026-07-24) — Steven: desktop hero back in PARALLAX like production
   (prod uses Divi CSS parallax = attachment:fixed). V90 had forced scroll at
   ALL widths because a viewport-fixed background centres against the VIEWPORT
   while the desktop layout has the 225px right vertical nav — the art sat
   ~112px right of the 1215px content column's centre. Restore fixed ≥981 WITH
   the compensation: calc(50% − 112.5px) = half the (constant-width) nav.
   ≤980 stays scroll — fixed there (a) re-clips the art under the top navbar
   (the V56 margin-top fix can't move a viewport-anchored image), (b) makes
   the %-based de-zoom sizes resolve against the viewport instead of the
   section, and (c) mobile browsers (iOS especially) fake or ignore
   attachment:fixed anyway. */
@media only screen and (min-width: 981px) {
  body.page-id-7072 .et_pb_section:has(.et_pb_contact_form_container) .et-pb-parallax-background,
  body.page-id-8169 .et_pb_section:has(.et_pb_contact_form_container) .et-pb-parallax-background {
    background-attachment: fixed !important;
    background-position: calc(50% - 112.5px) 40px !important;
  }
}
@media only screen and (max-width: 980px) {
  body.page-id-7072 .et_pb_section:has(.et_pb_contact_form_container) .et-pb-parallax-background,
  body.page-id-8169 .et_pb_section:has(.et_pb_contact_form_container) .et-pb-parallax-background {
    background-attachment: scroll !important;
  }
}
@media only screen and (max-width: 767px) {
  body.page-id-7072 .et_pb_section:has(.et_pb_contact_form_container) .et-pb-parallax-background,
  body.page-id-8169 .et_pb_section:has(.et_pb_contact_form_container) .et-pb-parallax-background {
    /* V105 (2026-07-24): 75% → 75vh (V104's 62% shrink withdrawn — Steven:
       size was fine; the REAL bug was the art ENLARGING in the error state:
       a %-size tracks the SECTION box, which GROWS with validation errors
       (V88 height:auto). vh pins the art to the VIEWPORT — identical when
       the section is exactly 100vh (the normal state), immune to growth —
       matching how the desktop fixed-parallax already sizes. */
    /* V108 (2026-07-24): 75vh → 67.5vh — Steven's S21 "still a little too
       big, shrink 10% on mobile only". */
    background-size: auto 67.5vh !important;
    /* V106 (2026-07-24): art down 35px on phones (Steven) — 40 → 75px.
       background-position moves the PAINT only; the form never shifts. */
    background-position: center 75px !important;
  }
}
/* V107 (2026-07-24): art down 35px on TABLET too (Steven) — 40 → 75px.
   Paint-only, same as V106; desktop keeps the V100 compensated position. */
@media only screen and (min-width: 768px) and (max-width: 980px) {
  body.page-id-7072 .et_pb_section:has(.et_pb_contact_form_container) .et-pb-parallax-background,
  body.page-id-8169 .et_pb_section:has(.et_pb_contact_form_container) .et-pb-parallax-background {
    background-position: center 75px !important;
  }
}

/* ============================================================================
   V115 (2026-07-24) — /report-abuse/ hero BLEED fix (Steven's colorcollage.jpg).
   The square police_teckel.webp had only ~16-76px of paper margin, so on DESKTOP
   its 765px rectangle sat inside the 1215px section, exposing 3-4 mismatched
   creams (section-bg + the art's own gradient rectangle). No flat CSS colour can
   beat a non-uniform art paper. Fix = give the ART more bleed: police_teckel_
   bleed.webp is the SAME dog centred in a 2048² canvas with the paper edge-
   extended + blurred to fill (colour-continuous, boundary seam pixel-verified
   ≤1/channel). The dog is now HALF the image, so DOUBLE the background-size to
   keep its rendered size; the image then COVERS the hero → no exposed section-bg
   rectangle at all. Dog is centred in the canvas → background-position:center
   centres the dog (the V100 −112.5 nav offset is dropped — no rectangle to
   off-centre now). Scoped to page 8169 ONLY. */
body.page-id-8169 .et_pb_section:has(.et_pb_contact_form_container) .et-pb-parallax-background {
  background-image: url("/wp-content/uploads/2025/06/police_teckel_bleed2.webp") !important;
  background-size: auto 170vh !important;       /* 2× the V105 85vh (2× canvas) */
  background-position: center center !important;
}
@media only screen and (min-width: 981px) {
  body.page-id-8169 .et_pb_section:has(.et_pb_contact_form_container) .et-pb-parallax-background {
    background-position: center center !important; /* drops V100's calc(50%−112.5px) */
  }
}
@media only screen and (min-width: 768px) and (max-width: 980px) {
  body.page-id-8169 .et_pb_section:has(.et_pb_contact_form_container) .et-pb-parallax-background {
    background-position: center center !important;
  }
}
@media only screen and (max-width: 767px) {
  body.page-id-8169 .et_pb_section:has(.et_pb_contact_form_container) .et-pb-parallax-background {
    background-size: auto 135vh !important;      /* 2× the V108 67.5vh */
    background-position: center center !important;
  }
}

/* V102 (2026-07-24) — Steven (topcrowding/bottomcrowding.jpg): more breathing
   room top+bottom on desktop+tablet, /support/ + /report-abuse/. PADDING on
   the section, NEVER margin (the V92 revert: margin moved the section and
   exposed the slant behind it; padding is internal and safe). Section's own
   padding was 54/54 (50 bottom on tablet): top air read as ~20px at ≤980
   because the FIXED 56px navbar overlays the section's first 56px — tablet
   padding-top compensates it (+56). Bottom must clear the 50px divider slant
   with real air even in the ERROR state (was 76px desktop / 135 tablet above
   the slant). Phones (≤767) deliberately untouched. */
@media only screen and (min-width: 981px) {
  body.page-id-7072 .et_pb_section:has(.et_pb_contact_form_container),
  body.page-id-8169 .et_pb_section:has(.et_pb_contact_form_container) {
    padding-top: 96px !important;
    padding-bottom: 128px !important;
  }
}
@media only screen and (min-width: 768px) and (max-width: 980px) {
  body.page-id-7072 .et_pb_section:has(.et_pb_contact_form_container),
  body.page-id-8169 .et_pb_section:has(.et_pb_contact_form_container) {
    padding-top: 120px !important;
    padding-bottom: 128px !important;
  }
}
/* V103 (2026-07-24) — Steven: mobile too (error state showed no change).
   Same padding-not-margin mechanism; section padding was 0/0 on phones, the
   56px fixed navbar ate the top, and the ERROR state's Submit overlapped the
   divider slant by ~13px (pre-existing). 96 top ≈ tablet's visible air scaled
   down; 128 bottom clears the 50px slant by ~78px even when the section is
   content-grown. */
@media only screen and (max-width: 767px) {
  body.page-id-7072 .et_pb_section:has(.et_pb_contact_form_container),
  body.page-id-8169 .et_pb_section:has(.et_pb_contact_form_container) {
    padding-top: 96px !important;
    padding-bottom: 128px !important;
  }
}

/* V116 (2026-07-24) — Steven, /report-abuse/ hero position tuning (page 8169):
   (1) *Required 30px closer to the navbar, mobile+tablet — section padding-top
       −30 (mobile 96→66, tablet 120→90); constant so it holds in the error state.
   (2) mobile: the teckel's hat ~40px closer to the navbar — hero bg-position up
       (padding change lifts it ~15px; bg-position adds the rest, tuned to −40).
   (3) desktop: re-centre the hero in the CONTENT column — V115's plain `center`
       centred the FIXED bg on the VIEWPORT (720) but the content centre is 608
       (225px right nav) → the dog sat ~112px right; restore the offset. */
@media only screen and (min-width: 981px) {
  body.page-id-8169 .et_pb_section:has(.et_pb_contact_form_container) .et-pb-parallax-background {
    background-position: calc(50% - 112.5px) center !important;
  }
}
@media only screen and (min-width: 768px) and (max-width: 980px) {
  body.page-id-8169 .et_pb_section:has(.et_pb_contact_form_container) {
    padding-top: 90px !important;
  }
}
@media only screen and (max-width: 767px) {
  body.page-id-8169 .et_pb_section:has(.et_pb_contact_form_container) {
    padding-top: 66px !important;
  }
  body.page-id-8169 .et_pb_section:has(.et_pb_contact_form_container) .et-pb-parallax-background {
    background-position: center calc(50% - 37px) !important;
  }
}

/* V101 (2026-07-24) — EXPERIMENT (Steven, comparison look): /support/ form-
   section BOTTOM divider white → brand orange #A1520F. Same Divi slant2 SVG
   (half-opacity slant + solid slant), only the g-fill token swapped. Scoped
   to page 7072 ONLY; delete this block to revert to white. */
body.page-id-7072 .et_pb_section:has(.et_pb_contact_form_container) .et_pb_bottom_inside_divider {
  background-image: url("data:image/svg+xml;utf8,%3Csvg preserveAspectRatio='none' width='100%25' height='140px' viewBox='0 0 1280 140' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='%23A1520F'%3E%3Cpath d='M0 0v140h1280L0 0z' fill-opacity='.5' /%3E%3Cpath d='M0 42v98h1280L0 42z' /%3E%3C/g%3E%3C/svg%3E") !important;
}
/* V113 (2026-07-24) — Steven approved the orange divider for /report-abuse/ too
   (was the support-only V101 experiment). Identical slant2 SVG, orange fill,
   scoped to page 8169. */
body.page-id-8169 .et_pb_section:has(.et_pb_contact_form_container) .et_pb_bottom_inside_divider {
  background-image: url("data:image/svg+xml;utf8,%3Csvg preserveAspectRatio='none' width='100%25' height='140px' viewBox='0 0 1280 140' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='%23A1520F'%3E%3Cpath d='M0 0v140h1280L0 0z' fill-opacity='.5' /%3E%3Cpath d='M0 42v98h1280L0 42z' /%3E%3C/g%3E%3C/svg%3E") !important;
}
body .et_pb_contact_form_container .et-pb-contact-message {
  background: transparent !important;
  padding: 0 !important;
  box-shadow: none;
}
body .et_pb_contact_form_container .et-pb-contact-message p,
body .et_pb_contact_form_container .et-pb-contact-message li {
  /* V111→V112 (2026-07-24): chips = the hero-paper colour at the FIELD opacity
     (82%), per page (Steven). V111 used white-82% everywhere, but a white-82%
     chip on a NON-white hero paper (#FAFBF8 support / #EFE9D9 report-abuse)
     renders brighter than the paper = a faint visible rectangle; the paper-
     toned-82% chip dissolves into the paper where there's no art behind it and
     only shows as a scrim over the dog. Base = white-82% (contact's paper IS
     white); support + report-abuse get their own paper below. The data-field
     fill is intentionally left white-82% (Steven) — only the chips are paper-
     toned. */
  background: rgba(255, 255, 255, 0.82);
  width: fit-content;
  padding: 3px 10px;
  margin-bottom: 4px;
}
body.page-id-7072 .et_pb_contact_form_container .et-pb-contact-message p,
body.page-id-7072 .et_pb_contact_form_container .et-pb-contact-message li {
  background: rgba(250, 251, 248, 0.82); /* support hero paper #FAFBF8 @82% */
}
body.page-id-8169 .et_pb_contact_form_container .et-pb-contact-message p,
body.page-id-8169 .et_pb_contact_form_container .et-pb-contact-message li {
  background: rgba(239, 233, 219, 0.82); /* V115: report-abuse bleed-image paper #EFE9DB @82% */
}
body .et_pb_contact_form_container .et-pb-contact-message ul {
  list-style-position: inside;
  padding-left: 0;
}
body .et_pb_contact_form .et_pb_contact_right p {
  background: #002349;
  display: inline-flex;
  align-items: center;
  gap: 12px;
  padding: 10px 14px;
  box-shadow: 6px 6px 6px rgba(0, 35, 73, 0.4);
}
body .et_pb_contact_form .et_pb_contact_right p .et_pb_contact_captcha {
  margin: 0 !important;
}

/* V91 (2026-07-22) — mobile "*Required." left-justified + paper chip (Steven).
   Support's module was centred; contact/report-abuse already left (included
   for uniformity). Chip colour = the page's art paper (report-abuse cream).
   ★ V119 (2026-07-24) RE-ANCHORED off Divi's order classes. Adding the hero H1
   module above renumbered this module on two of the three pages (support
   .et_pb_text_2 → _3, report-abuse .et_pb_text_0 → _1), which would have
   silently dropped the chip. `.et_pb_text:has(+ .et_pb_contact_form_container)`
   = "the text module immediately before the form" — positional, so it survives
   any future module insert (verified: exactly 1 match on each of the 3 pages,
   and it is the *Required module). */
@media only screen and (max-width: 767px) {
  body.page-id-2755 .et_pb_text:has(+ .et_pb_contact_form_container) .et_pb_text_inner,
  body.page-id-7072 .et_pb_text:has(+ .et_pb_contact_form_container) .et_pb_text_inner,
  body.page-id-8169 .et_pb_text:has(+ .et_pb_contact_form_container) .et_pb_text_inner {
    text-align: left !important;
  }
  body.page-id-2755 .et_pb_text:has(+ .et_pb_contact_form_container) .et_pb_text_inner p,
  body.page-id-7072 .et_pb_text:has(+ .et_pb_contact_form_container) .et_pb_text_inner p,
  body.page-id-8169 .et_pb_text:has(+ .et_pb_contact_form_container) .et_pb_text_inner p {
    /* V111→V112: hero-paper colour @82% per page (base = contact white) */
    background: rgba(255, 255, 255, 0.82);
    width: fit-content;
    padding: 3px 10px;
  }
  body.page-id-7072 .et_pb_text:has(+ .et_pb_contact_form_container) .et_pb_text_inner p {
    background: rgba(250, 251, 248, 0.82); /* support #FAFBF8 @82% */
  }
  body.page-id-8169 .et_pb_text:has(+ .et_pb_contact_form_container) .et_pb_text_inner p {
    background: rgba(239, 233, 219, 0.82); /* V115: #EFE9DB @82% */
  }
}

/* V118 (2026-07-24) — Steven: the /report-abuse/ *Required chip was styled ONLY
   inside the ≤767 mobile block, so on TABLET + DESKTOP its background was
   transparent (the error-message chips were already #EFE9DB @82% at all widths).
   Extend the same #EFE9DB @82% chip to tablet+desktop so *Required matches the
   error chips and the mobile *Required. (Invisible over the bleed paper on
   desktop; a scrim wherever it overlaps the dog.) Page 8169 only. */
@media only screen and (min-width: 768px) {
  /* V119 (2026-07-24): re-anchored index-free, same reason as V91 above. */
  body.page-id-8169 .et_pb_text:has(+ .et_pb_contact_form_container) .et_pb_text_inner p {
    background: rgba(239, 233, 219, 0.82);
    width: fit-content;
    padding: 3px 10px;
  }
}

/* ============================================================================
   V95 (2026-07-24) — S21 captcha equation/answer stacking, isolated re-attempt
   of the reverted V92.1 (bugs.md 2026-07-22 known-open). Divi wraps the
   equation span + answer input in NESTED <label>s inside the chip's p, so the
   flex row lays the label out as ONE item and the wrap (stack) happens INSIDE
   it on narrow phones. display:contents dissolves the wrappers so the span,
   the "=" text and the input become the flex items of the (default nowrap)
   row — the stack becomes impossible at any width. Global: same cloned form
   on /contact/ /support/ /report-abuse/. NOTHING else from the V92 round
   (no margins, no centering, no logo-anchor changes).
   ========================================================================== */
body .et_pb_contact_form .et_pb_contact_right p label {
  display: contents;
}
body .et_pb_contact_form .et_pb_contact_right p .et_pb_contact_captcha_question {
  white-space: nowrap;
}
body .et_pb_contact_form .et_pb_contact_right p .et_pb_contact_captcha {
  flex-shrink: 0;
}

/* ============================================================================
   V96 (2026-07-24) — Steven: captcha + Submit = the email field's exact
   vertical height. The fields are 58px border-box (16px pad + 18px text) at
   every breakpoint, and the chip's answer input shares .input = 58px too —
   so ZERO vertical chip padding makes the navy chip exactly input-height
   (was 68px: 10px top / 0 bottom). The Submit button is the chip's stretch-
   aligned row-mate (its own content is only ~46px; it stretches to the row =
   the chip) → chip 58px pulls the button to 58px with no button rule. All
   three controls now self-synchronize to the field height — no fixed px that
   could drift if Divi's field padding/font ever changes.
   ========================================================================== */
body .et_pb_contact_form .et_pb_contact_right p {
  padding-top: 0;
  padding-bottom: 0;
}

/* V97 (2026-07-24) — Steven: remove the navy strip right of the answer input.
   The input now sits flush with the chip's right edge — the navy left section
   holds the equation, the grey input IS the right section. TWO sources of the
   strip: the chip's 14px padding-right AND the p's .clearfix ::after box —
   inside the flex row that zero-width pseudo becomes a trailing flex item and
   drags one 12px gap after the input (floats don't exist in flex; the
   clearfix is inert here, safe to remove). */
body .et_pb_contact_form .et_pb_contact_right p {
  padding-right: 0;
}
body .et_pb_contact_form .et_pb_contact_right p::after {
  content: none;
}

/* V98 (2026-07-24) — Steven: the captcha answer input's focus ring INSIDE the
   field. The V87 ring (+2px outside) crossed the chip edge and sat on the
   drop shadow now that the input is flush (V96/V97). -4px mirrors the outside
   ring's 2px gap inward: 2px grey margin, then the 2px orange ring. Colour/
   width inherit from the V87 system rule — only the offset flips. */
body .et_pb_contact_form .et_pb_contact_right p .et_pb_contact_captcha:focus-visible {
  outline-offset: -4px !important;
}

/* V99 (2026-07-24) — Steven: "the drop shadow is not uniform". Root cause:
   Divi's form module gives EVERY field the brand shadow (6px 6px 6px
   rgba(0,35,73,0.4)) — including the answer input. While the input sat inside
   the chip's padding that shadow was invisible against the navy; flush
   (V96/V97) it escaped the chip and STACKED on the chip's own shadow = a
   doubled darker patch right of the grey box. The composite control casts ONE
   brand shadow (the chip's, identical to the Submit button's token) — the
   input inside casts none. Other fields keep theirs (standalone controls). */
body .et_pb_contact_form .et_pb_contact_right p .et_pb_contact_captcha {
  box-shadow: none !important;
}


/* ============================================================================
   V114 (2026-07-24) — ★ CRITICAL: content invisible under prefers-reduced-motion.
   Steven reported "content missing on many pages, Firefox only, Chrome fine."
   Root cause: his Firefox runs resistFingerprinting which FORCES
   prefers-reduced-motion:reduce (and ANY visitor with the OS reduce-motion
   accessibility setting hits it too — hence Firefox-only for him, fine in
   Chrome). Divi's scroll-entrance holds every module at `.et_animated{opacity:0}`
   and reveals it on scroll; under reduce-motion that reveal never fires, so
   20/21 modules stay at opacity:0 = blank content SITE-WIDE. Reproduced with
   emulateMedia({reducedMotion:'reduce'}) → 20/20 hidden; this rule → 0/20.
   Fix = force the FINAL (visible) state under reduce-motion — the correct a11y
   behaviour: show the content, just skip the motion. Covers the custom
   .tc-cascade reveal too (belt-and-suspenders; it has its own observer). */
@media (prefers-reduced-motion: reduce) {
  .et_animated,
  .tc-cascade {
    opacity: 1 !important;
    transform: none !important;
    animation: none !important;
  }
}

/* ============================================================================
   V119 (2026-07-24) — hero H1 on /support/ (7072) + /report-abuse/ (8169).
   Steven: "Like the contact page, let's put a similar H1 on both." Both pages
   had NO <h1> at all (content + SEO + a11y gap). The H1 itself ships in the
   PAGE CONTENT as a clone of /contact/'s text_0 module (navy #002349, 35px/600,
   margin-bottom 20px, left, zoom-900ms entrance — script add-hero-h1-7072-8169-
   2026-07-24.php), carrying its own inline styles, so the only CSS needed here
   is /contact/'s existing responsive step-down (V12b) extended to the two new
   pages: 35px dominates a phone column. Kept as a separate rule rather than
   widening V12b because that block is contact-scoped hero tuning.
   ★ See also the V91 + V118 re-anchors above — the new module renumbers the
     *Required module and index selectors would have dropped its paper chip.
   ★ SUPERSEDED by V122's fluid ramp (bottom of file): the ≤980 step-down that
     lived here produced 24px, which is exactly what the V122 clamp produces at
     ≤980 — the rule was removed so there is ONE H1 size rule to reason about.
   ========================================================================== */

/* V119b (2026-07-24) — hero "breathing room" for the new H1 on /support/ +
   /report-abuse/ ("you may need to adjust the hero image a little bit for more
   breathing room depending on the page and the mode" — Steven). The art drops
   just far enough that the H1 sits on CLEAN PAPER at every width, like
   /contact/'s does; nothing else about the art (size, desktop position) changes.

   ★ Method note — the first attempt got this wrong and it is worth remembering:
   I predicted the H1's y-band from the SECTION's padding-top. Divi's ROW adds
   another ~55-58px above the first module, so the real H1 box is ~58px lower
   than the section padding suggests (support@360: predicted 96→132, actual
   151→190). Measure the RENDERED rect, then photograph the art behind it with
   the H1 set to visibility:hidden — that isolates art ink from the H1's own
   navy glyphs. Values below were then chosen by a browser-INJECTED position
   sweep (inline !important on .et-pb-parallax-background — a page-scoped
   stylesheet rule outranks an injected one) measuring dark-pixel % inside the
   real H1 box, and are the SMALLEST move that reaches a clean box:
       support @360  120px → 175px   (was 19.3% dark → 0.0%)
       support @768   75px → 120px   ( 5.3% → 0.0%)
       report-abuse @360  calc(50%−37px) → calc(50%+20px)  (28.8% → 0.0%)
       report-abuse @768  center        → calc(50%+40px)   ( 2.6% → 0.0%)
   Desktop (≥981) measured 0.0% on both pages already — deliberately untouched,
   so V100's parallax + V116's content-column centring stand.
   ★ This supersedes V106/V107's phone+tablet offsets on /support/ and V115/V116's
   phone+tablet offsets on /report-abuse/ (same specificity, later source order).
   The report-abuse bleed image still COVERS the hero at both offsets (checked:
   1053px art in an 855px section at +20 → top −79, bottom 974; 1740.8 in 1024
   at +40 → top −318, bottom 1422), so no section-bg rectangle is exposed. */
@media only screen and (max-width: 767px) {
  body.page-id-7072 .et_pb_section:has(.et_pb_contact_form_container) .et-pb-parallax-background {
    background-position: center 175px !important;
  }
  body.page-id-8169 .et_pb_section:has(.et_pb_contact_form_container) .et-pb-parallax-background {
    background-position: center calc(50% + 20px) !important;
  }
}
@media only screen and (min-width: 768px) and (max-width: 980px) {
  body.page-id-7072 .et_pb_section:has(.et_pb_contact_form_container) .et-pb-parallax-background {
    background-position: center 120px !important;
  }
  body.page-id-8169 .et_pb_section:has(.et_pb_contact_form_container) .et-pb-parallax-background {
    background-position: center calc(50% + 40px) !important;
  }
}

/* ============================================================================
   V120 (2026-07-24) — /contact/ bottom divider white → brand orange #A1520F.
   Steven: "the contact page is missing the lower orange section divider" —
   closing the option left open by V101 (support) / V113 (report-abuse); all
   three form pages now share the treatment. Identical Divi slant2 SVG (half-
   opacity slant + solid slant), only the g-fill token swapped, scoped to page
   2755. Delete this block to revert to white.
   ========================================================================== */
body.page-id-2755 .et_pb_section:has(.et_pb_contact_form_container) .et_pb_bottom_inside_divider {
  background-image: url("data:image/svg+xml;utf8,%3Csvg preserveAspectRatio='none' width='100%25' height='140px' viewBox='0 0 1280 140' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='%23A1520F'%3E%3Cpath d='M0 0v140h1280L0 0z' fill-opacity='.5' /%3E%3Cpath d='M0 42v98h1280L0 42z' /%3E%3C/g%3E%3C/svg%3E") !important;
}

/* V121 (2026-07-24) — /contact/ bottom breathing room ≤980, shipped WITH V120
   because the orange divider makes a pre-existing overlap visible. Measured on
   the live page before this change: at 360 the Submit's bottom edge OVERLAPPED
   the divider by 19px (submit ends 667, divider starts 648 — invisible only
   because white-on-white), and at 768 it cleared by just 31px. This is the same
   defect V103 fixed on the other two pages; same mechanism — section PADDING,
   never margin (V92: margin moves the section and exposes the slant behind it).
   128px matches V103 and lands both breakpoints at ~108px of clear paper.
   Safe against the V105 growable-section trap: contact's art is WIDTH-
   constrained (`contain` ≤767 → width-fit at 360; `85% auto` at 768-980), so a
   taller section box does not re-zoom it. Desktop (≥981) already clears by
   207px and is untouched. */
@media only screen and (max-width: 980px) {
  body.page-id-2755 .et_pb_section:has(.et_pb_contact_form_container) {
    padding-bottom: 128px !important;
  }
}

/* ============================================================================
   V122 (2026-07-24) — THE FORM-PAGE HERO TITLE STANDARD.
   Steven: "create some H1 uniformity or standardization across the three
   webform pages … adjust sizing and position of the H1 … and possibly the
   positioning of the hero image in order to produce no interference between
   the H1 and the hero image regardless of browser viewport geometry", with an
   explicit NO to putting a background chip behind the H1 ("unprofessional").

   THE STANDARD — /contact/ 2755 · /support/ 7072 · /report-abuse/ 8169:

   (1) TYPE: ONE CONTINUOUS RAMP, replacing the 24px→35px STEP at 981px.
         font-size: clamp(24px, calc(24px + 11 * (100vw - 980px) / 460), 35px)
       = 24px through phone + tablet, then linear to 35px at 1440 and above.
       ★ The step WAS the bug. At 981–1366 the H1 snapped to its full 35px
       (242px wide on support, 332px on report-abuse) exactly where the
       viewport-HEIGHT-sized hero art is widest relative to the content column
       — so up to 41% of the H1's glyph box sat on dark ink. The ramp keeps the
       H1 narrow while the column is narrow. Supersedes V119's ≤980 rule and
       V12(b)'s contact rule (both were "24px ≤980" = identical output there).

   (2) CLEARANCE — the invariant this standard guarantees:
       THE HERO ART PAINTS NO INK INSIDE THE TITLE BLOCK'S TEXT BOX, at any
       viewport geometry. The ART moves; the H1 never gets a background chip.
       Per page, the smallest offset that achieves it:
         contact  ≤767   center 100px → 150px   (its Office-number line, not
                  the H1, was the casualty — 32.8% dark at 320, 20.5% at 360;
                  150px restores V84's position, which V85 had eased to 100)
         support  ≥981   40px → 150px           (V100's fixed/parallax and the
                  calc(50% − 112.5px) content-column compensation are KEPT —
                  only the vertical offset changes)
         report-abuse ≥981  center → calc(50% + 95px)   (same; the bleed image
                  still covers the hero — 1530px art, 900px section → −220px)
         support  768–980  background-size auto min(85vh, 113vw)
                  — a pure-vh art grows without bound on a TALL, NARROW
                  viewport: at 768×1600 the headset arc spread far enough to
                  clip the H1's box corner (1.3%). The vw term caps it at what
                  it already is on a normal 768×1024 tablet (868 vs 870px, a
                  2px no-op there) and only bites when the viewport is tall.

   (3) VERTICAL ALIGNMENT: deliberately NOT changed. The title block's BOTTOM
       — where the form starts, which is what the eye actually compares — was
       already aligned across the three pages: 248/248/250 desktop, 237/249/229
       tablet, 192/210/205 phone. Contact's title starts higher only because
       its block carries a second line (the Office number). Forcing equal TOPS
       would have pushed contact's title down into its own art and broken V83's
       "the ENTIRE dog, nose to paws, shows at every width".

   MEASURED, NOT EYEBALLED — 213 viewport geometries (19 widths × 2 heights,
   plus 11 widths × 3 extreme heights; 320→1920 wide, 500→1600 tall; all three
   pages). Each cell renders the page, hides the title text, photographs the
   art through the H1's own glyph box and scores dark pixels.
       BEFORE: 15 of 114 cells collided, worst 41.4% (support 1024×900).
       AFTER:  0 of 213, worst 0.0%.
   ★ Re-run that harness before changing any hero art value on these pages.
   ========================================================================== */
body.page-id-2755 .et_pb_text_inner h1,
body.page-id-7072 .et_pb_text_inner h1,
body.page-id-8169 .et_pb_text_inner h1 {
  font-size: clamp(24px, calc(24px + 11 * (100vw - 980px) / 460), 35px) !important;
}
@media only screen and (max-width: 767px) {
  body.page-id-2755 .et_pb_section:has(.et_pb_contact_form_container) .et-pb-parallax-background {
    background-position: center 150px !important;
  }
}
@media only screen and (min-width: 768px) and (max-width: 980px) {
  body.page-id-7072 .et_pb_section:has(.et_pb_contact_form_container) .et-pb-parallax-background {
    background-size: auto min(85vh, 113vw) !important;
  }
}
@media only screen and (min-width: 981px) {
  body.page-id-7072 .et_pb_section:has(.et_pb_contact_form_container) .et-pb-parallax-background {
    background-position: calc(50% - 112.5px) 150px !important;
  }
  body.page-id-8169 .et_pb_section:has(.et_pb_contact_form_container) .et-pb-parallax-background {
    background-position: calc(50% - 112.5px) calc(50% + 95px) !important;
  }
}

/* ============================================================================
   V123 (2026-07-24) — Steven, two asks on /support/ (7072) + /report-abuse/
   (8169) only:

   (a) MOBILE: move the whole "H1 + hero-image + webform complex" UP 20px.
       Moving the complex means content AND art together, so it is two paired
       edits per page — section PADDING-TOP (never margin — V92) and the art's
       own offset by the same 20px:
         support       padding-top 96 → 76   ·  art  center 175px → center 155px
         report-abuse  padding-top 66 → 46   ·  art  calc(50%+20px) → calc(50%+10px)
       Verified by measurement at 320/360/414 × 640/780/900: H1, *Required and
       the form all move exactly −20px, the submit→divider gap is unchanged at
       109px, and the section shrinks 860→840 / 855→835.
       ★ report-abuse's art is CENTRE-anchored (its bleed image is taller than
       the section), so its offset resolves against the section height: −10px of
       the shift comes free from the section getting 20px shorter, hence +20→+10.
       On a viewport tall enough to pin the section at min-height:100vh (≈900+
       CSS px, e.g. an iPhone 14 Pro Max at 932) the section does NOT shrink, so
       the art moves −10 there while the content still moves −20. That drift is
       harmless BY DIRECTION — it can only lower the art relative to the H1, i.e.
       add clearance, never take it. (Support's art is top-anchored and moves a
       clean −20 at every height.)
       V122's clearance invariant re-verified after this change: 0 collisions in
       76 cells (2 pages × 19 widths × 2 heights).

   (b) "*Required." font-size on these two pages = /contact/'s.
       Contact's is an <h6> and computes 19.2px ≤767 / 12px ≥768. Support and
       report-abuse author theirs as a <p> whose inner <span> carries an INLINE
       font-size:16px, so it read 16px at every width — bigger than contact on
       tablet/desktop, smaller on phones. The rule below overrides the p AND the
       inline span (inline styles need !important) with contact's two values.
       ★ Only the SIZE was asked for and only the size was changed: the weight
       (400 vs contact's 500), the line-height (24/30px vs 23.03/14.4px) and the
       p-vs-h6 element still differ. Consequence worth knowing: with the line
       box unchanged at 30px, report-abuse's *Required paper chip is now taller
       relative to its 12px text. Matching line-height too would tighten that
       chip but also lift the form ~16px on tablet/desktop — say the word.

   ★★ V124 (2026-07-24, same day) — CORRECTION to (b)'s breakpoint. Steven:
       "I think you misunderstood me … I want the font size to match on all
       three pages and it should be the same font size as what it is currently
       on the /contact/ page." He was right: I had spot-checked contact at 360
       and 768 only and assumed its 19.2px→12px switch happened at the usual
       767 breakpoint. It does NOT. Contact's *Required is an <h6>, and the
       19.2px comes from THIS FILE's small-phone heading rule at line ~841 —
       `@media (max-width: 360px){ h3,h4,h5,h6 { font-size: clamp(1.2rem, 5vw,
       1.7rem) } }` — so contact is 19.2px only at ≤360px and 12px at EVERY
       width above it. A width sweep (19 widths × 3 pages) showed the two pages
       matching at ≤360 and ≥768 but oversized against contact across the whole
       414→767 band. Fixed by mirroring contact's ACTUAL breakpoint: the phone
       rule below is now `max-width: 360px` and reuses the SAME clamp
       expression (not a hardcoded 19.2px) so it tracks that global rule if it
       ever changes. Lesson: when told to "match" a value, find the RULE that
       produces it and mirror the rule — a two-width spot-check will infer the
       wrong breakpoint.
   ========================================================================== */
@media only screen and (max-width: 767px) {
  body.page-id-7072 .et_pb_section:has(.et_pb_contact_form_container) {
    padding-top: 76px !important;
  }
  body.page-id-8169 .et_pb_section:has(.et_pb_contact_form_container) {
    padding-top: 46px !important;
  }
  body.page-id-7072 .et_pb_section:has(.et_pb_contact_form_container) .et-pb-parallax-background {
    background-position: center 155px !important;
  }
  body.page-id-8169 .et_pb_section:has(.et_pb_contact_form_container) .et-pb-parallax-background {
    background-position: center calc(50% + 10px) !important;
  }
}
body.page-id-7072 .et_pb_text:has(+ .et_pb_contact_form_container) .et_pb_text_inner p,
body.page-id-7072 .et_pb_text:has(+ .et_pb_contact_form_container) .et_pb_text_inner p span,
body.page-id-8169 .et_pb_text:has(+ .et_pb_contact_form_container) .et_pb_text_inner p,
body.page-id-8169 .et_pb_text:has(+ .et_pb_contact_form_container) .et_pb_text_inner p span {
  font-size: 12px !important;
}
/* V124: contact's <h6> only gets the small-phone bump at ≤360 (line ~841), so
   this mirrors that exact media query AND that exact clamp — not 19.2px baked
   in, and NOT the 767 breakpoint V123 wrongly assumed. */
@media (max-width: 360px) {
  body.page-id-7072 .et_pb_text:has(+ .et_pb_contact_form_container) .et_pb_text_inner p,
  body.page-id-7072 .et_pb_text:has(+ .et_pb_contact_form_container) .et_pb_text_inner p span,
  body.page-id-8169 .et_pb_text:has(+ .et_pb_contact_form_container) .et_pb_text_inner p,
  body.page-id-8169 .et_pb_text:has(+ .et_pb_contact_form_container) .et_pb_text_inner p span {
    font-size: clamp(1.2rem, 5vw, 1.7rem) !important;
  }
}

/* ============================================================================
   V125 (2026-07-25) — finish matching "*Required." to /contact/ on /support/
   (7072) + /report-abuse/ (8169). V123/V124 matched the SIZE; Steven then asked
   for the weight and line-height too, so the three pages are now typographically
   identical for this element.
     contact  <h6>: weight 500 · line-height 1.2 (23.03px @19.2 · 14.4px @12)
     the two others <p>: weight 400 · line-height 24px phone / 30px tablet+
   line-height is set as the RATIO 1.2, not px, so it tracks the size ramp
   (19.2px ≤360 → 12px above) exactly the way contact's does.
   ★ Layout consequence, expected and verified: the line box shrinks (30px →
   14.4px on tablet/desktop, 24px → 14.4px at 414-767, 24px → 23px at ≤360), so
   everything below *Required — the form, the Submit, the captcha chip — rises
   by that difference, and report-abuse's *Required paper chip (which is sized
   by the line box) tightens around its text. The H1 is ABOVE this element, so
   V122's clearance invariant is untouched; the submit→divider gap only grows.
   ★ Still deliberately different: the ELEMENT (p vs h6). Converting would need a
   DB edit on both pages AND would silently drop the V91/V118 paper chips, which
   target `p` — the same reason contact's h6 has never had one (decisions 07-24).
   ========================================================================== */
body.page-id-7072 .et_pb_text:has(+ .et_pb_contact_form_container) .et_pb_text_inner p,
body.page-id-7072 .et_pb_text:has(+ .et_pb_contact_form_container) .et_pb_text_inner p span,
body.page-id-8169 .et_pb_text:has(+ .et_pb_contact_form_container) .et_pb_text_inner p,
body.page-id-8169 .et_pb_text:has(+ .et_pb_contact_form_container) .et_pb_text_inner p span {
  font-weight: 500 !important;
  line-height: 1.2 !important;
}

/* ============================================================================
   V126 (2026-07-25) — /onboarding/ (10881) hero H1 vertical nudge (Steven,
   after the Grand Prix art landed): "on mobile move the H1 vertically down by
   50px. on tablet move the H1 vertically up by 50px." Desktop unchanged.

   Mechanism: `position:relative; top:±50px` on the H1 only — NOT margin and NOT
   transform. Margin would push the fullwidth-header's flow (and the empty
   button wrapper below it) and could re-settle the centring; transform is the
   axis Divi's entrance animations use elsewhere, so it is left free. Probed
   first: this H1 computes `animation:none`, `transform:none`, `position:static`
   at every breakpoint, so a relative offset is inert apart from the paint.
   Measured before: H1 top y=328 @360 · 333 @414 · 840 @768 · 882 @900 (the
   section is 780/800/1024 tall respectively) — both nudges stay well inside the
   hero, and the tablet one moves the H1 AWAY from the bottom divider.
   Breakpoints follow the project convention: phone ≤767, tablet 768-980.
   ========================================================================== */
/* V128 (2026-07-25) — Steven, after seeing V126 live: "on mobile, push the H1
   vertically down another 50px" → phone offset 50px → 100px (cumulative from
   the H1's natural position). Tablet's −50px is unchanged. Bounds re-checked
   before shipping: at 360 the H1 lands y=428/bottom 472 against a divider top
   of 681; at 414, 433/487 vs 701; at 767, 483/537 vs 801 — still clear at every
   phone width. */
@media only screen and (max-width: 767px) {
  body.page-id-10881 .et_pb_fullwidth_header h1.et_pb_module_header {
    position: relative;
    top: 100px;
  }
}
@media only screen and (min-width: 768px) and (max-width: 980px) {
  body.page-id-10881 .et_pb_fullwidth_header h1.et_pb_module_header {
    position: relative;
    top: -50px;
  }
}

/* ============================================================================
   V127 (2026-07-25) — /onboarding/ (10881): on phone + tablet, pull the copy up
   15px, tightening the gap between the hero art and the first content block
   (Steven, same round as V126). Desktop keeps the full V52 rhythm.

   The gap is the first content section's V52 64px padding-top (line ~2166 gives
   every non-fullwidth section on this page 64/64); 64 − 15 = 49px at ≤980.
   Measured before: the first module sat 94px below the hero (64 section padding
   + 30 row padding) at every width.
   ★ Selector is POSITIONAL — `.et_pb_fullwidth_section + .et_pb_section` = "the
   section immediately after the hero" (verified: exactly 1 match at 360/414/
   768/900/1440). Divi order classes renumber whenever a module or section is
   inserted (see V119's chip near-miss), so anything anchored to
   `.et_pb_section_10` here would be a future silent breakage.
   Specificity ties V52's rule and wins on source order; both use !important.
   ========================================================================== */
@media only screen and (max-width: 980px) {
  body.page-id-10881 .et_pb_fullwidth_section + .et_pb_section {
    padding-top: 49px !important;
  }
}

/* ============================================================================
   V129 (2026-07-25) — /resources/ (10884) hero H1 down 35px on PHONE only
   (Steven, after the Resource Depot art landed). Tablet + desktop untouched.
   Same mechanism as V126/V128 on /onboarding/: `position:relative; top` on the
   H1 alone — not margin (pushes the fullwidth-header's flow) and not transform
   (left free for Divi's entrance animations). Probed first: this H1 computes
   animation:none / transform:none / position:static at 320-767.
   Measured before: y=403 @320+360, 408 @414, 458 @767 against divider tops of
   681/701/801 — after +35 the H1 bottom is 482/497/547, still ~200px clear.
   ========================================================================== */
/* V130 (2026-07-25) — Steven, after seeing V129 live: "push it down another
   10px on mobile only" → 35px → 45px (cumulative from the H1's natural
   position). Re-checked: H1 lands y=448/bottom 492 @320+360, 453/507 @414,
   503/557 @767, against divider tops of 681/701/801 — still ~190px clear. */
@media only screen and (max-width: 767px) {
  body.page-id-10884 .et_pb_fullwidth_header h1.et_pb_module_header {
    position: relative;
    top: 45px;
  }
}

/* ============================================================================
   V132 (2026-07-27) — V131 REVERTED (Steven's call). V131 de-zoomed the
   /web3-services/ (2914) desktop hero (cover → auto 110vh, content-centred);
   it deployed and rendered correctly (verified in the served bundle + computed
   at 1440/1024/1920, incl. under reduce-motion), but a SQUARE 800² art in a
   wide ~100vh hero can only show more of itself by floating with side bands
   and cut art edges — Steven judged the rendered result not working. Agreed
   root fix: OUTPAINT THE ART ITSELF to landscape (extend the station scene
   left/right), then swap the DESKTOP image slot only — phone/tablet keep the
   square via the per-slot mechanism (CLAUDE.md §Hero art). Do NOT re-attempt a
   CSS-only shrink here. Evidence + candidate renders:
   archive/screenshots-2026-07-27-w3s-hero/. Hero is back on Divi defaults
   (cover, 50% 0%, attachment:fixed).
   ========================================================================== */

/* ============================================================================
   V133 (2026-07-27) — /web3-services/ (2914) hero H1 nudges (Steven: "on
   mobile please move the H1 vertically down by 100px and on tablet move it up
   by 75px"), same round as the desktop hero-art swap to
   teckel_web3_services_2026.webp (attachment 11152; swap script
   agent_docs/scripts/web3-services-hero-swap-2026-07-27.php — ★ this page's
   slot order is tablet, PHONE, desktop, like /newsletter/).
   Mechanism = V126/V129: `position:relative; top` on the H1 alone — not margin
   (pushes the fullwidth-header's flow) and not transform (left free for Divi's
   entrance axis). Probed first: exactly 1 matching H1, computes animation:none
   / transform:none / position:static at 360/767/768/980.
   Bounds re-checked before shipping: phone y 288→388 (360) / 271→371 (767),
   H1 bottom 532/549 vs section bottom 800 (~250px clear); tablet y 840→765
   (768+980), bottom 859 vs section bottom 1024. Desktop untouched.
   ========================================================================== */
@media only screen and (max-width: 767px) {
  body.page-id-2914 .et_pb_fullwidth_header h1.et_pb_module_header {
    position: relative;
    top: 100px;
  }
}
@media only screen and (min-width: 768px) and (max-width: 980px) {
  body.page-id-2914 .et_pb_fullwidth_header h1.et_pb_module_header {
    position: relative;
    top: -75px;
  }
}

/* ============================================================================
   V134 (2026-07-27) — Popup Maker panels: no focus ring on the panel itself
   (Steven's S21 FIREFOX: "an inner orange focus border … is automatically
   showing on the popup … causing crowding of the text"; not in other browsers).
   Root cause: on open, Popup Maker moves focus to `.pum-content[tabindex=0]`
   for screen readers; FIREFOX's :focus-visible heuristic treats that script
   focus as visible (Chromium doesn't) → the V87 system rule
   `body [tabindex]:focus-visible` painted its 2px orange ring 2px inside the
   popup's own orange border = a second frame crowding the content. Reproduced
   headless (activeElement=.pum-content, outline 2px rgb(161,82,15)).
   Fix: the panel is a focus TARGET, not an operable control — suppress the
   ring on the PM containers only; the close button and links INSIDE keep the
   V87 rings (a11y intact). Selectors tie the V87 rule's specificity (0,2,1)
   and win on source order. Applies to ALL PM popups, current + future
   (popup 10894 "Dentistry Show London" is the live one, site-wide auto-open).
   ========================================================================== */
body .pum-overlay:focus-visible, body .pum-overlay:focus,
body .pum-container:focus-visible, body .pum-container:focus,
body .pum-content:focus-visible, body .pum-content:focus {
  outline: none !important;
}

/* ============================================================================
   V135 (2026-07-29) — /about/ (3025) hero H1 nudges (Steven: "push the H1 down
   vertically by 100px on mobile and up vertically by 100px on tablet. Desktop
   does not need changing.").
   Mechanism = V126/V129/V133: `position:relative; top` on the H1 alone — not
   margin (pushes the fullwidth-header's flow) and not transform (left free for
   Divi's entrance axis). Probed first: exactly 1 matching H1, computes
   animation:none / transform:none / position:static at 360/767/768/980.
   Bounds re-checked before shipping: phone y 338→438 (360) / 334→434 (767),
   H1 bottom 482/486 vs section bottom 800 (~315px clear); tablet y 882→782
   (768+980), bottom 834 vs section bottom 1024. Desktop untouched.
   ========================================================================== */
@media only screen and (max-width: 767px) {
  body.page-id-3025 .et_pb_fullwidth_header h1.et_pb_module_header {
    position: relative;
    top: 100px;
  }
}
@media only screen and (min-width: 768px) and (max-width: 980px) {
  body.page-id-3025 .et_pb_fullwidth_header h1.et_pb_module_header {
    position: relative;
    top: -100px;
  }
}

/* ============================================================================
   V136 (2026-07-29) — /podcast/ (2903) hero H1 down 100px on BOTH mobile and
   tablet (Steven; desktop untouched — same round as the desktop hero-art
   widening to teckel_podcast_wide.webp, attachment 11153, swap script
   agent_docs/scripts/podcast-hero-swap-2026-07-29.php).
   Mechanism = V126/V133/V135. Probed first: exactly 1 matching H1; this one
   already computes position:relative from Divi's own styling with effective
   top 0 (the inline +100px probe moved it exactly +100), animation:none /
   transform:none. Bounds: phone y 378→478 (360) / 373→473 (767), bottoms
   522/527 vs section 800; tablet y 465→565 (768) / 486→586 (980), bottoms
   659/638 vs section 1024. One block ≤980 since both bands take the same
   value (V127 precedent).
   ========================================================================== */
/* V137 (2026-07-29) — Steven, after seeing V136 + the wide desktop art live:
   "center the new hero image on desktop … push the H1 vertically down 100px on
   desktop and 50px more on tablet … on mobile, let's also do a similar hero
   image shrink/reduction by altering the bleed/canvas."
   (a) DESKTOP ART CENTRING. The desktop span is `attachment: fixed`, so the
       background positions against the VIEWPORT — but the content column stops
       at the 225px right vertical nav (constant 981→1920, measured), putting
       the viewport centre 112.5px RIGHT of the column centre. `calc(50% -
       112.5px)` puts the image centre exactly on the column centre (1440: image
       centre lands on 607.5 = span centre; the speech bubble measures 13px
       right of that because it sits slightly right of centre in the ARTWORK —
       verified by bbox: bubble centre 732 → 620 vs span centre 607).
   (b) H1 BANDS, split from V136's single ≤980 rule: phone keeps 100px, tablet
       goes to 150px (Steven's "50px more"), desktop joins at 100px. Desktop
       bounds re-checked at 5 sizes incl. short viewports — worst clearance to
       the bottom divider is 134px at 981×640 (1024×768: 198 · 1280×800: 235 ·
       1440×900: 285 · 1920×1080: 375).
   (c) PHONE ART CENTRED VERTICALLY — required by the new tall canvas
       (teckel_podcast_tall.webp, 800×1600, attachment 11154; swap script
       podcast-phone-hero-swap-2026-07-29.php). `cover` on a narrow 100vh
       section scales by the width/height ratio, so a TALLER canvas renders the
       art SMALLER and reveals more of it (360: 45% → ~90% of the art's width;
       767: 100%). The canvas fits exactly only at ~360 wide; above that the
       rendered image is taller than the section and Divi's default `top`
       anchoring would show the empty upper band — centring keeps the art
       mid-section at every phone width (a no-op at 360 where the fit is exact).
   ★ Both art rules target the per-breakpoint span classes; the tablet span is
   deliberately untouched (still the square, Steven scoped the shrink to
   mobile), so this page now serves three DIFFERENT files, one per slot.
   ========================================================================== */
@media only screen and (max-width: 767px) {
  body.page-id-2903 .et_pb_fullwidth_header h1.et_pb_module_header {
    position: relative;
    top: 100px;
  }
  /* ★ the phone art rule that lived here is DEAD and is SUPERSEDED by V144:
     it targeted --divi-section-4; the hero section's index is now 0. */
}
@media only screen and (min-width: 768px) and (max-width: 980px) {
  body.page-id-2903 .et_pb_fullwidth_header h1.et_pb_module_header {
    position: relative;
    top: 150px;
  }
}
@media only screen and (min-width: 981px) {
  body.page-id-2903 .et_pb_fullwidth_header h1.et_pb_module_header {
    position: relative;
    top: 100px;
  }
  /* ★ the desktop centring rule that lived here is DEAD and is SUPERSEDED by
     V144: it targeted --divi-section-4; the hero section's index is now 0. */
}

/* ============================================================================
   V138 (2026-07-29) — /podcast/ (2903) PHONE: trim the empty space around the
   hero art by SHORTENING THE HERO, not by zooming the art (Steven, measured on
   his S21: "too much space above and below the hero image, especially above …
   remove 100px from the top and about 50px from the bottom").

   ★★ WHY THE SECTION HAD TO SHRINK (the geometry is forced, not a preference).
   Measured on the real S21 via a viewport probe: **378 × 766 CSS px** (100vh =
   766; only 703 visible — Firefox Android's toolbar takes 63px; DPR 20/7).
   With the V137 tall canvas (800×1600) at that box, `cover` resolves
   HEIGHT-driven and the image fills the section height EXACTLY — which means
   `background-position`'s vertical component is INERT there (a position-only
   change measures identical, verified). And a square art can be at most
   378×378 if its full width is to stay visible, so in a 766-tall section the
   leftover 383px MUST sit above/below it. Removing that space while keeping the
   whole illustration is therefore only possible by making the section shorter.
   80vh (613px on the S21) + `50% 65%` lands within ~5px of Steven's numbers:
   gap above the ink 156 → 60 (−96) · gap below 191 → 139 (−52) · and the art
   now shows 100% of its width (was 98.7%).
   ★ The rejected alternative is archived: zooming the art to close the same
   gaps (`background-size: auto 139%`) crops it to 71% of its width — both dogs
   lose their outer bodies, undoing V136/V137's whole point. See
   archive/screenshots-2026-07-29-podcast-hero/v138-*.
   ★ Consequence to know: the hero no longer fills the phone screen — the next
   (white) section peeks in ~90px above the fold on the S21. Deliberate.

   ★ Scoped `≤480px AND ≥640px tall` = phones held portrait. Wider phones
   (481–767, e.g. foldables) and short/landscape geometries keep the V137 100vh
   framing, because there the same rule crowds the art under the fixed 56px
   navbar (measured: ink only 3px below the navbar at both 320×568 and 767×800).
   ★ Beats the PAGE-LEVEL Divi rule `.et_pb_fullwidth_header_1.et_pb_fullwidth
   _header{height:100vh!important;min-height:100vh!important}` (inside its own
   ≤980 query) — which is why BOTH `height` and `min-height` are set, on BOTH
   the module and its container. Overriding only the container moves the H1 but
   leaves the section at 766 (verified).
   ★ H1 needs no change: it rides the shorter section up to 357..456, still over
   the art's lower half, 58px clear of the divider (V137's +100px offset kept).
   ========================================================================== */
/* ★ V138's 80vh band is SUPERSEDED by V145, which derives the phone section
   height from the art (100vw + 201px, capped at 100vh) so the two gaps Steven
   specified hold at every phone width instead of only at his S21's aspect. */
@media only screen and (max-width: 480px) and (min-height: 640px) {
  /* ★ the 50% 65% phone rule that lived here is DEAD and is SUPERSEDED by
     V144 (which uses 35% = Steven's -50px). Same --divi-section-4 cause. */
}


/* ============================================================================
   V144 (2026-08-22) — /podcast/ (2903) hero: REPAIR three DEAD rules, then fix
   the tablet band. Steven: "on my s21 remove about 50px between the top of the
   image and the navbar … on desktop the image needs to be centered WITHIN the
   image viewable area … on tablet we have a mess: depending on the viewport
   width the image is either clipped by the navbar OR too far down and clipped
   badly by the divider."

   ★★ ROOT CAUSE of the desktop and phone reports — NOT a design problem.
   V137(a), V137(c) and V138 all targeted `…-module--divi-section-4`. The hero
   section's module index is now **0**, so all three rules were deployed and
   matched NOTHING. Verified three ways: `[class*="divi-section-4"]` returns 0
   elements; the live span is `…-module--divi-section-0`; and the minified
   bundle still carries the three orphaned selectors. The rules that SURVIVED
   are exactly the ones that never used the numbered class (the H1 offsets and
   V138's 80vh height) — which is why the H1 still sat correctly while the art
   did not, and why this read as a fresh design bug rather than a regression.
   ★★ RULE: never use the positional `--divi-section-N` class. It is an INDEX
   and it renumbers whenever the page's sections change. Identify the hero by
   CONTENT instead — `.et_pb_section:has(.et_pb_fullwidth_header)` — which
   cannot be renumbered. Specificity (0,5,1) beats et-cache's (0,1,0).

   (a) PHONE — Steven's −50px. At 378x766 (his S21) the tall canvas renders
       378x756 in the 613px band (V138's 80vh), so overflowY = 143px and the
       gap navbar→ink measured 153px. 50/143 = 35%, so `50% 35%` removes
       exactly 50px → 103px. MEASURED after: navGap 103, divider clearance 10.
       ★ V138's July value was 65% (gap 60px) — Steven approved that on the
       same device, so if he wants it tighter, 65% is the known-good stop.
       Phones outside V138's `≤480 AND ≥640 tall` scope keep V137(c)'s 50%
       (they run the full 100vh band, where 50% is the right centring).

   (b) TABLET — the mess, and why it is structural. The tablet slot still
       serves the ORIGINAL SQUARE `Teckel-Podcast.webp` (800x800); it never got
       a bleed canvas. In a 100vh band, `cover` FLIPS ITS DRIVER as the
       viewport aspect crosses 1.0 — and the tablet band spans 0.56→1.40:
         · 768x1024 (0.75) → HEIGHT-driven → art 1024x1024, 25% cropped off the
           SIDES and the top runs UNDER the navbar   ← "clipped by the navbar"
         · 900x700 (1.29) → WIDTH-driven → art 900x900 top-anchored in a 700
           band, 200px falls off the BOTTOM          ← "clipped by the divider"
       Both of Steven's tablet symptoms are the SAME bug seen either side of
       the 1:1 pivot. No `background-position` can fix it — position only
       chooses WHICH part is lost.
       ★ FIX = `contain` inside a span INSET past both obstructions (top 56px
       for the fixed navbar, bottom 100px for the slant divider). The whole
       drawing then fits at EVERY aspect, always centred, and the art scales
       itself down as the band gets shorter — which is Steven's "shrink it a
       little for tablet", achieved without a new asset.
       ★ WHY `contain` IS SAFE HERE (it usually is not — exposed section ground
       normally mismatches the art's paper): this art is a WHITE-ground line
       drawing (paper 254–255) and the section's own background is #FFFFFF, and
       the `rgba(161,82,15,0.7)` overlay covers the WHOLE section uniformly. So
       the exposed ground and the art's paper both render (189,134,87).
       MEASURED across the boundary on clean ground: max channel delta **0** on
       the left, right and bottom edges — byte-identical, no seam.
       Verified 7 tablet geometries (768x1024, 800x1280, 820x1180, 900x700,
       980x800, 980x700, 800x600): zero clipping, centring error ≤4px.

   (c) DESKTOP — restore V137(a)'s centring with a stable selector. The desktop
       span is `attachment: fixed`, so the background positions against the
       VIEWPORT while the content column stops at the 225px right nav rail
       (constant 981→1920, re-measured), putting the viewport centre 112.5px
       right of the column centre. With the rule dead the art sat 112.5px RIGHT
       — measured margins L253/R32 at 1440, i.e. Steven's "not centered" AND
       his older "too much empty space at the LEFT" in one. After: L170/R173.
       ★ Vertical position is INERT on desktop (cover is height-driven, so
       overflowY = 0); the art's bottom hatching overlapping the slant divider
       by ~8px is pre-existing and unchanged by this block.
       ★ Known limit, ACCEPTED: below ~1058px wide (at vh 800) the ink is wider
       than the column, so 981x800 clips ~10px each side. That is far better
       than the broken state, which clipped 150px off ONE side.

   Verified in FIREFOX across 17 geometries incl. the 981/1000/1060/1150 band.
   Element screenshots: hero-BEFORE-... and hero-AFTER-... (archived).
   ★ NEVER write the sequence star-slash inside a CSS comment (a glob like
   hero-BEFORE-<star>/hero-AFTER-<star> does exactly that): it CLOSES the comment
   early, and the parser then swallows the next rule during error recovery.
   ========================================================================== */
/* ★ V144's two phone background-position rules lived here. Both are SUPERSEDED
   by V145 below, which replaces cover+position with contain+inset because
   position-based framing clipped 18 of 36 geometries in the 620-767 band. */
@media only screen and (min-width: 768px) and (max-width: 980px) {
  body.page-id-2903 .et_pb_section:has(.et_pb_fullwidth_header) .et-pb-parallax-background_tablet {
    top: 56px !important;
    bottom: 100px !important;
    height: auto !important;
    background-size: contain !important;
    background-position: 50% 50% !important;
    background-repeat: no-repeat !important;
  }
}
@media only screen and (min-width: 981px) {
  body.page-id-2903 .et_pb_section:has(.et_pb_fullwidth_header) .et-pb-parallax-background:not(.et-pb-parallax-background_tablet):not(.et-pb-parallax-background_phone) {
    background-position: calc(50% - 112.5px) 0% !important;
  }
}


/* ============================================================================
   V145 (2026-08-22) — /podcast/ (2903) PHONE: make the vertical framing
   DETERMINISTIC, and hit Steven's spacing numbers. Supersedes V138's 80vh band
   and V144(a)'s two phone background-position rules.

   ★★ THE BUG V144 LEFT BEHIND (Steven: "check the 625px to 750px viewport range
   on chrome"). Measured in Chromium across 36 geometries in 620-767 x 700-1000:
   **18 of 36 CLIPPED.** Worst case 700x700 — ink 18px UNDER the navbar and 75px
   PAST the divider, simultaneously. Cause: the phone slot serves the TALL canvas
   (800x1600) with `cover`, so the art is width-driven and its height is 2x the
   viewport width. Overflow = 2W - H, and `50% 50%` splits that overflow evenly,
   pushing the ink out of BOTH ends as the window gets wider or shorter. This is
   exactly the ANCHOR DOCTRINE failure already on the record from 2026-07-30
   ("50% 50% is NOT the safe default"); V144 inherited the value from the dead
   V137(c) rule and I only checked five tall-phone geometries, all of which pass.

   ★ FIX = the same mechanism that made the tablet band deterministic: the SQUARE
   art at `contain` inside a span inset past both obstructions. Then the whole
   drawing always fits and nothing can clip at any phone geometry.
   ★ THE ART DOES NOT GET SMALLER. The ink is 98% of the canvas WIDTH in both
   files (783 of 800), so at a given phone width the rendered ink is the same size
   as before — only the vertical behaviour changes, from unpredictable to exact.
   ★ The image swap is done in CSS, not the DB, so the module keeps its own value.
   A root-relative URL is used so it survives the production domain change. Only
   the winning background-image declaration is fetched, so the tall file is no
   longer downloaded on phones (99KB saved on the devices that care most).

   ★ SPACING — Steven, measured on his S21 (378x766): "remove about 50px vertical
   space between the top of the image and the navbar and 25px vert space between
   the bottom of the image and the section divider."
   Solving for the two insets with the band set to exactly the art size
   (band = 100vw, so the art fills it with no centring slack):
       navGap = T + 0.05375*W - 56      divGap = 0.035*W + B - 100
   At W=378, targeting navGap 53 and divGap 25 gives **T = 89, B = 112**, and a
   section height of `100vw + 201px`. Holds across the phone range: navGap
   50/52/53/71 and divGap 23/25/25/37 at W = 320/360/378/700.
   ★ The height is capped at `100vh` so a short landscape phone never gets a hero
   taller than its screen; when the cap bites, `contain` simply scales the art
   down and the gaps stay positive (700x700 -> navGap 60, divGap 29).
   ★ `min()` + `calc()` here, and BOTH `height` and `min-height` on BOTH the module
   and its container — that is what it takes to beat Divi's page-level
   `height:100vh!important` (V138's finding, still true).
   ========================================================================== */
@media only screen and (max-width: 767px) {
  body.page-id-2903 .et_pb_fullwidth_header.et_pb_fullscreen,
  body.page-id-2903 .et_pb_fullwidth_header.et_pb_fullscreen .et_pb_fullwidth_header_container {
    height: min(calc(100vw + 201px), 100vh) !important;
    min-height: min(calc(100vw + 201px), 100vh) !important;
  }
  body.page-id-2903 .et_pb_section:has(.et_pb_fullwidth_header) .et-pb-parallax-background_phone {
    background-image: url("/wp-content/uploads/2024/11/Teckel-Podcast.webp") !important;
    background-size: contain !important;
    background-position: 50% 50% !important;
    background-repeat: no-repeat !important;
    top: 89px !important;
    bottom: 112px !important;
    height: auto !important;
  }
}

/* ============================================================================
   V139 (2026-07-29) — /teckel-ai/ (9464) DESKTOP hero: centre the widened art
   on the content column (Steven: "reduce/shrink the hero image on desktop so
   that more of the image is seen … work the bleed/canvas angle … keep the image
   centered"). The de-zoom itself needed NO CSS — it is the canvas widening
   (teckel_ai_toolkits_wide.webp, 2048×1024, attachment 11155, DESKTOP slot only;
   script agent_docs/scripts/teckel-ai-hero-swap-2026-07-29.php). At 2:1 `cover`
   on a ~100vh desktop shows the WHOLE portrait — helmet, both ears, lace bow
   tie, coat — where the 1024² square showed ~62% of its height (goggles only).
   Only the centring is CSS: the span is `attachment: fixed`, so it centres on
   the VIEWPORT while the content column stops at the 225px right vertical nav
   (constant 981→1920, measured) — without compensation the portrait sits
   112.5px right of the column centre. Same token as V131/V137.
   Tablet + phone keep the square art and are untouched.
   ========================================================================== */
@media only screen and (min-width: 981px) {
  body.page-id-9464 .et-pb-parallax-background-module--divi-section-3 {
    background-position: calc(50% - 112.5px) 0% !important;
  }
}

/* ============================================================================
   V140 (2026-07-29) — /teckel-ai/ (9464) TABLET + PHONE: centre the taller art
   vertically (Steven: "on second thought, let's also similarly slightly reduce
   the size of the hero image on both tablet and mobile").
   The reduction itself is the canvas again, not CSS: teckel_ai_toolkits_tall.
   webp (1024×1400, attachment 11156, BOTH the tablet and phone slots; script
   agent_docs/scripts/teckel-ai-hero-swap-mobile-2026-07-29.php). Mirror of the
   desktop fix — these sections are NARROW and ~100vh, so `cover` scales the
   square by HEIGHT and crops the width (75% visible at 768, only ~45% at 360:
   ears and bow tie gone). A TALLER canvas scales the art DOWN: full width at
   768–980, ~62-68% at 360–378, so the ears and lace bow tie come into frame.
   This rule is REQUIRED, not cosmetic: at 768–980 the taller canvas renders
   TALLER than the section (at 980×1024 the art would run to y=1160 in a 1024
   box), so Divi's default `top` anchoring would cut the bow tie and coat off
   the bottom. Centring keeps the portrait whole across the whole band; at
   ~360-wide the fit is near-exact so it is a no-op there.
   ★ Both spans in one rule — each is `display:none` outside its own breakpoint,
   so there is no cross-talk. Desktop keeps V139's wide art + its own centring.
   ========================================================================== */
/* ★ V141 (2026-07-29) — CORRECTION to V140, caught by Steven: "you accidentally
   made the tablet hero image slightly BIGGER rather than slightly smaller since
   the top of the teckel's head is now more clipped?" He was right, and the cause
   was V140's `50% 50%` above, not the canvas size.
   REPRODUCED across a tablet matrix: real tablet PORTRAITS were fine (768×1024,
   820×1180, 980×1024 → head ok), but at WIDE-BUT-SHORT tablet-band windows —
   900×700 and 800×600, i.e. exactly what a laptop responsive-mode "tablet" view
   is — the 1400 canvas overflows the section by ~500px and CENTRING splits that
   crop between top and bottom, cutting **100px off the top of the head**. Before
   V140 the square art was TOP-anchored (Divi's default), so the head was always
   safe and only the coat was trimmed.
   FIX, two parts: (a) the tablet slot gets its OWN milder canvas —
   `teckel_ai_toolkits_tablet.webp` (1024×1200, attachment 11157; script
   teckel-ai-hero-tablet-fix-2026-07-29.php) sized for tablet ASPECTS rather than
   phone ones; (b) both spans are explicitly TOP-anchored, which cannot clip the
   head by construction (the canvas's own paper band is what comes first).
   Verified analytically across 9 tablet geometries: head never clipped, always a
   66–100px paper band above it, and the art still renders ~15% smaller than
   pre-V140 on real tablets (874 vs 1024 at 768×1024; 1007 vs 1180 at 820×1180).
   ★ The phone slot keeps the 1400 canvas: at every real phone geometry the
   vertical fit is EXACT (overflow 0), so anchoring is inert there — but stating
   `0%` also protects the phone band's own wide-short windows (a 700×500 window
   would have clipped the head by 100px under centring too).
   ★ Lesson (decisions.md): a per-axis canvas extension needs a position that
   protects the SUBJECT, and for a portrait that means the top — `50% 50%` is
   only safe when the extension can never exceed the section. Pair the canvas
   with the anchor, and test WIDE-BUT-SHORT windows, not just device portraits.
   ========================================================================== */
@media only screen and (max-width: 980px) {
  body.page-id-9464 .et-pb-parallax-background_tablet-module--divi-section-3,
  body.page-id-9464 .et-pb-parallax-background_phone-module--divi-section-3 {
    background-position: 50% 0% !important;
  }
}

/* ============================================================================
   V142 (2026-07-29) — /teckel-ai/ (9464) TABLET: shrink the hero further + move
   the H1 up 100px (Steven: "on tablet let's shrink the hero some more and move
   the H1 vertically up by 100px").
   ★ THE SHRINK NEEDED A DUAL-AXIS CANVAS. V141's tablet file was extended
   VERTICALLY only (1024×1200), and vertical extension alone bottoms out: once
   the canvas is tall enough that `cover` becomes WIDTH-driven, the art renders
   exactly box-width tall (768px at a 768 viewport) and further height changes
   only add empty band — they cannot shrink it. So the new tablet file is
   extended on BOTH axes: `teckel_ai_toolkits_tablet2.webp` (**1200×1600**,
   attachment 11158; 88px flanks then 288px bands, per-ROW then per-COLUMN
   continuation so the corners inherit continuity too; all four seams verified
   within 2/255). Art now renders 656px tall at 768×1024 — 25% smaller than
   V141's 874 — with paper margin on all four sides. Script:
   agent_docs/scripts/teckel-ai-hero-tablet-shrink-2026-07-29.php.
   ★ ANCHOR 25%, NOT 0% (refines V141 for this bigger canvas): at real tablet
   portraits (768×1024, 820×1180, 768×1366) the fit is EXACT so the anchor is
   inert. It only matters at wide-but-short windows, and there V141's `0%` let
   the now-much-larger top band (216px) push the subject down the screen — at
   900×700 only the helmet stayed visible. A 25% bias keeps the head high
   (measured ink at 127px vs the 56px navbar) and cuts the bottom trim from
   284→159px; at 980×1024 it removes the trim entirely (47→0). Checked across 8
   geometries incl. 900×500: the head is never clipped and the finial ink never
   reaches the navbar. ★ The PHONE span deliberately stays at `0%` (V141) — its
   1400 canvas is exact-fit at every real phone geometry, and 0% is the safer
   choice for the odd short window there.
   ========================================================================== */
@media only screen and (min-width: 768px) and (max-width: 980px) {
  body.page-id-9464 .et-pb-parallax-background_tablet-module--divi-section-3 {
    background-position: 50% 25% !important;
  }
  /* H1 up 100px — V126/V133/V135 mechanism; probed: 1 match, animation:none /
     transform:none / position:static. Clearance to the bottom divider stays
     91px at 768×1024, 820×1180, 900×700 and 980×1024 (H1 bottom 834/990/510/834
     vs divider tops 925/1081/601/925). */
  body.page-id-9464 .et_pb_fullwidth_header h1.et_pb_module_header {
    position: relative;
    top: -100px;
  }
}

/* ============================================================================
   V143 (2026-07-30) — /faq/ (3623) hero POSITION (Steven, after the 07-30 canvas
   swap: "on desktop, please center the hero image … on tablet please push the
   hero image vertically up by 200px").
   (a) DESKTOP ≥981 — the same fixed-attachment compensation as V131/V137/V139:
       the span is `attachment: fixed`, so it centres on the VIEWPORT while the
       content column stops at the 225px right vertical nav (constant 981→1920),
       leaving the art 112.5px right of the column centre. `calc(50% - 112.5px)`
       cancels it EXACTLY — computed art-centre vs column-centre delta is +0px at
       981/1280/1440/1920 (the art is centred in its own 1200×800 canvas, so
       centring the image centres the art).
   (b) TABLET 768–980 — art up 200px, expressed as a negative length (the tablet
       span is `attachment: scroll`, so the offset is relative to the section box
       and `-200px` means exactly that). The art's top is clipped by 20–60px
       depending on geometry — that is the visible consequence of the ask, and it
       eats the art's own white margin first.
   ★ Moving a `cover` image up EXPOSES the section background at the bottom
     (200px at 768×1024 and 820×1180, 97px at 980×1024, none at short windows).
     Harmless HERE and only here: this art's ground is 253,253,253 and the
     section bg is 255,255,255, both sit under the same orange 0.7 scrim, so the
     seam is imperceptible (verified in render). On a page whose hero art has a
     TINTED/paper ground this same rule would show a visible band — check the
     ground vs section-bg before reusing this trick.
   ========================================================================== */
@media only screen and (min-width: 981px) {
  body.page-id-3623 .et-pb-parallax-background-module--divi-section-9 {
    background-position: calc(50% - 112.5px) 0% !important;
  }
}
@media only screen and (min-width: 768px) and (max-width: 980px) {
  body.page-id-3623 .et-pb-parallax-background_tablet-module--divi-section-9 {
    background-position: 50% -200px !important;
  }
}

/* ─────────────────────────────────────────────────────────────────────────────
   V126 (2026-08-20, Steven): product CATEGORY / TAG archives get the product-page
   chrome. Reported on /product-category/apparel/: (a) the "Apparel" H1 sat 2px under
   the fixed 56px mobile/tablet navbar, (b) the legacy prod BLOG SIDEBAR (search /
   categories / archives / recent ticketing posts) rendered beside the grid and on
   desktop OVERLAPPED it, clipping the 4th product card.

   Why the existing fixes did not cover this surface: the v0.7.0 scope-guard filter
   forces `_et_pb_page_layout = et_full_width_page`, but Divi's sidebar.php honours
   that meta ONLY for is_single()/is_page() — an archive falls through to
   `is_active_sidebar('sidebar-1')`. The sidebar itself is now removed in PHP
   (teckel-woo-scope v0.7.4, sidebars_widgets filter → no #sidebar markup at all);
   these rules supply the layout half, mirroring the `body.single-product` block above.

   88px container padding-top is copied from the product page measured at BOTH 834px
   and 1440px (yielding the same 72px visible gap under the fixed navbar) — matching
   the neighbouring surface rather than inventing a value. The ::before kill removes
   Divi's sidebar-divider line ghost, exactly as single-product does.
   ───────────────────────────────────────────────────────────────────────────── */
body.tax-product_cat #main-content .container,
body.tax-product_tag #main-content .container   { padding-top: 88px; }
body.tax-product_cat #left-area,
body.tax-product_tag #left-area                 { width: 100% !important; padding-right: 0 !important; }
body.tax-product_cat #main-content .container::before,
body.tax-product_tag #main-content .container::before { display: none !important; }
/* belt-and-braces: if any context slips past the PHP filter, never show the blog widgets here */
body.tax-product_cat #sidebar,
body.tax-product_tag #sidebar                   { display: none !important; }

/* V127 (2026-08-20, Steven: "the dividers … should show up on the category pages too").
   ★ This SUPERSEDES V126b, which padded the archive to 128px below 981px to fake the
   air a divider would have provided. Root cause found: V68 gives product pages slant
   dividers as #main-content::before/::after and states its 88px container padding
   exists "so content clears each 50px slant by 38px". V126 copied the 88px WITHOUT the
   slants — padding clearing nothing. Extending V68 verbatim to the product taxonomy
   archives restores the intent: same navy top slant, same orange bottom slant, same
   88/88 rhythm, so an archive is framed exactly like the product pages it links to.
   The SVGs are byte-identical to V68's (Divi's own generated slant2 shapes). */
body.tax-product_cat #main-content,
body.tax-product_tag #main-content { position: relative; }
body.tax-product_cat #main-content::before,
body.tax-product_tag #main-content::before,
body.tax-product_cat #main-content::after,
body.tax-product_tag #main-content::after {
  content: ""; position: absolute; left: 0; right: 0; height: 50px;
  background-size: 100% 50px; background-repeat: repeat-x; pointer-events: none; z-index: 1;
}
body.tax-product_cat #main-content::before,
body.tax-product_tag #main-content::before { top: 0; background-image: url("data:image/svg+xml;utf8,%3Csvg preserveAspectRatio='none' width='100%25' height='140px' viewBox='0 0 1280 140' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='%23002349'%3E%3Cpath d='M1280 140V0H0l1280 140z' fill-opacity='.5' /%3E%3Cpath d='M1280 98V0H0l1280 98z' /%3E%3C/g%3E%3C/svg%3E"); }
body.tax-product_cat #main-content::after,
body.tax-product_tag #main-content::after { bottom: 0; background-image: url("data:image/svg+xml;utf8,%3Csvg preserveAspectRatio='none' width='100%25' height='140px' viewBox='0 0 1280 140' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='%23A1520F'%3E%3Cpath d='M0 0v140h1280L0 0z' fill-opacity='.5' /%3E%3Cpath d='M0 42v98h1280L0 42z' /%3E%3C/g%3E%3C/svg%3E"); }
body.tax-product_cat #main-content .container,
body.tax-product_tag #main-content .container { padding-top: 88px; padding-bottom: 88px; }

/* ─────────────────────────────────────────────────────────────────────────────
   V130 (2026-08-21, Steven) — CART page: totals table clipped by the nav rail,
   "Subtotal" stacked one-letter-per-line, product thumbnail 15px.
   ★ THIS REPLACES V129, WHICH MADE IT WORSE. V129 put `overflow-wrap: anywhere`
   on the totals TH; that lowers the cell's min-content, so the table algorithm
   was free to squeeze the label column to a single character and stack
   S/u/b/t/o/t/a/l vertically. Never put `anywhere` on a LABEL cell.

   Real cause (measured, Firefox): in the 981–1150px band the `.cart_totals`
   column is only **290px** — the page already gives 225px to the vertical nav
   rail — while the totals table's min-content is 254px and its natural width
   332px. No amount of text-breaking makes 2 columns comfortable in 290px; the
   column itself is too narrow. So: **stack the totals under the items table in
   that band** (290px → 605px at 981) instead of hacking the text.
   Separately the thumbnail column was being starved to 15px from a 300×300
   source — given an explicit width.

   Verified in FIREFOX at 981/1000/1024/1060/1100/1200/1440/1920 — all PASS:
   totals overflow 0, items overflow 0, label never stacks (th height 56px),
   thumbnail 48px in the tightest band and 64px above it, no page h-overflow.
   ───────────────────────────────────────────────────────────────────────────── */
/* label cell: never break mid-word (this is what V129 got wrong) */
.woocommerce-page .cart_totals table.shop_table th {
  overflow-wrap: normal !important; word-break: normal !important; hyphens: none !important; white-space: nowrap; }
.woocommerce-page .cart_totals table.shop_table { width: 100% !important; max-width: 100% !important; }
.woocommerce-page .cart_totals table.shop_table td { overflow-wrap: break-word !important; }
/* the actual fix: give the totals the full content width where the column is too narrow */
@media (min-width: 981px) and (max-width: 1150px) {
  .woocommerce-page .cart-collaterals,
  .woocommerce-page .cart-collaterals .cart_totals { width: 100% !important; float: none !important; }
}
/* items table: the thumbnail column must not be starved (was 15px from a 300×300 file) */
.woocommerce-page table.shop_table.cart { width: 100% !important; max-width: 100% !important; }
.woocommerce-page table.shop_table.cart td.product-thumbnail { width: 72px; }
.woocommerce-page table.shop_table.cart td.product-thumbnail img {
  width: 64px !important; max-width: 64px !important; height: auto !important; }
.woocommerce-page table.shop_table.cart td.product-name,
.woocommerce-page table.shop_table.cart td.product-name a { overflow-wrap: anywhere !important; }
/* narrowest desktop: six columns in ~620px — tighten gutters, thumb and qty */
@media (min-width: 981px) and (max-width: 1060px) {
  .woocommerce-page table.shop_table.cart th,
  .woocommerce-page table.shop_table.cart td { padding-left: 8px !important; padding-right: 8px !important; }
  .woocommerce-page table.shop_table.cart td.product-thumbnail { width: 56px; }
  .woocommerce-page table.shop_table.cart td.product-thumbnail img { width: 48px !important; max-width: 48px !important; }
  .woocommerce-page table.shop_table.cart td.product-quantity .quantity input.qty { width: 48px !important; min-width: 0 !important; }
}


/* V131 (2026-08-21, Steven: "an odd line appears above the product image" + "do you think
   the image should be centered and larger?"). ROOT CAUSE — V130 regressed V73: V130's
   desktop sizing rules (.woocommerce-page table.shop_table.cart td.product-thumbnail
   {width:72px} and its img {width:64px!important}) carry NO max-width guard, and they
   out-specify V73's ≤768 stacked rules (4 classes vs 3 — and !important loses to higher
   specificity). Two visible symptoms, one cause:
     · the thumbnail CELL stayed 72px wide instead of filling the stacked row. Every
       stacked cell paints a 1px border-top across its OWN width, so at 72px that divider
       renders as a short stray LINE floating above the image — Steven's "odd line".
     · the image stayed at the desktop 64px instead of V73's intended 96px, so "centred"
       inside a 72px cell read as small-and-left-aligned on the page.
   Fix: re-assert the stacked geometry at ≤768 using V130-EQUAL specificity (so it wins on
   source order rather than another !important escalation), and take the image to 140px —
   96px was sized against a 72px cell, not a full-width row.
   NB: the empty band ABOVE the image is td.product-remove rendering as a full-width block
   with only the × in it. Left alone deliberately — that is a layout decision, not a bug. */
@media (max-width: 768px) {
  .woocommerce-page table.shop_table.cart td.product-thumbnail,
  .woocommerce table.shop_table_responsive tr td.product-thumbnail {
    width: auto !important;
    display: block !important;
    text-align: center !important;
  }
  .woocommerce-page table.shop_table.cart td.product-thumbnail img,
  .woocommerce table.shop_table_responsive tr td.product-thumbnail img {
    width: 140px !important;
    max-width: 140px !important;
    height: auto !important;
    margin: 0 auto !important;
    float: none !important;
    display: block !important;
  }
}


/* V132 (2026-08-21, Steven, checkout1.jpg + checkout2.jpg): three cart asks.
   (a) "the scrims where the two red x's reside should be the same" — they were not:
       WooCommerce zebra-stripes the stacked table via
       `table.shop_table_responsive tr:nth-child(2n) td {background: rgba(0,0,0,.025)}`,
       so item 1's remove band rendered TRANSPARENT (white) and item 2's GREY. Same
       element, two looks, purely because of row parity.
   (b) "they should be our brand navy scrim" — #002349, the secondary navy the guide
       assigns to surface/chrome (backgrounds, footer blocks, popups), not #011431 (ink).
   (c) "they probably don't need to be that particular vertical size since they only
       house the x" — vertical padding 17.14px → 8px takes the band ~65px → ~46px.
   ★ SCOPED TO ≤768 ON PURPOSE. The "scrim" only exists in the STACKED table, where the
   remove cell is a full-width band. On desktop the same cell is a ~54px column inside a
   white row — painting that navy would drop a navy block into the middle of the table.
   ★ The ✕ itself stays #c9529d. That is not a stray colour: it is the palette's ERROR
   token, and V-rule (line ~2792) deliberately mapped Woo's #a00 onto it for destructive
   actions. On #002349 it measures ~3.9:1 — AA PASS for large text (the ✕ is 30px, so the
   3:1 threshold applies, not 4.5:1). If it is ever reduced below 24px, re-check that. */
@media (max-width: 768px) {
  .woocommerce-page table.shop_table.cart tr.cart_item td.product-remove,
  .woocommerce table.shop_table_responsive tr.cart_item:nth-child(2n) td.product-remove {
    background-color: #002349 !important;
    padding-top: 8px !important;
    padding-bottom: 8px !important;
  }
}

/* V132b — "a little more space between the paypal button and the lower orange divider".
   Measured: PayPal button bottom 1947, divider top 1980 = a 33px gap against a 50px slant,
   and .cart-collaterals actually overlapped the divider's top edge by 19px. The section's
   padding-bottom is 0 and the divider is bottom-inside, so the air has to come from the
   collaterals themselves. 48px = 6 × the V52 8px grid, taking the gap to ~81px. */
.woocommerce-page .cart-collaterals { padding-bottom: 48px; }


/* ============================================================================
   V134 (2026-08-22) — SITE-WIDE VIDEO FRAME (the brand standard for embeds).
   Steven: "update the display of the video on the home page to match the same
   border/animation treatment of the video on /podcast/ — that treatment is sort
   of our brand standard for displaying videos."

   Lifted setting-for-setting from the /podcast/ player, which documents itself as
   an exact copy of the original video rows:
     · STAGE (outer): #002349 ground, 10px navy mat top/bottom, a 10px #a1520f
       stripe down the RIGHT edge only, and the 6/6/6 rgba(0,35,73,.4) brand shadow.
     · FRAME (inner, holds the video): 16:9, black ground, 10px #002349 borders on
       LEFT and RIGHT only.
   ★ The navy L/R borders belong to the FRAME on purpose, so they ride WITH the
   video as it slides horizontally, travelling over the stage's static orange right
   stripe until the two align. That compounding is the effect — do not "simplify" it
   by moving the borders onto the stage.

   TWO-AXIS ENTRANCE, both 3000ms ease, both fading from 0:
     · stage slides UP    (translateY 5% -> 0)
     · frame slides RIGHT (translateX 5% -> 0)
   5% rather than the original rows' 3% because this player is smaller, so 3% of its
   box travels too few px — same speed, comparable absolute travel.

   ★ Class names are deliberately NOT .tk-stage/.tk-frame: those are bare selectors
   inside /podcast/'s page-local <style>, and reusing them here (site-wide) would
   collide on that page.
   ★ REDUCE-MOTION: V114's guard lists only .et_animated and .tc-cascade, so this
   component carries its own. Same doctrine — show the content, skip the motion.
   ========================================================================== */
.tk-video { --tk-slide: 5%; max-width: 780px; margin: 20px auto; }
.tk-video * { box-sizing: border-box; }
.tk-video-stage {
  background: #002349;
  padding: 10px 0;
  border-right: 10px solid #a1520f;
  box-shadow: 6px 6px 6px 0 rgba(0, 35, 73, .4);
}
.tk-video-frame {
  position: relative;
  aspect-ratio: 16 / 9;
  background: #000;
  overflow: hidden;
  border-left: 10px solid #002349;
  border-right: 10px solid #002349;
}
/* the WP Rocket facade, and the real iframe it swaps in on click, both fill the frame */
.tk-video-frame > .rll-youtube-player,
.tk-video-frame > iframe {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  border: 0; margin: 0; padding: 0;
}
/* ★ THE HIDDEN STATE IS ARMED BY JS, NEVER BY CSS ALONE.
   First cut put opacity:0 in the base rule and relied on JS adding .in to reveal it.
   WP Rocket's delay-JS holds this observer until the first user interaction, so on a
   fresh load .in never landed and the video was INVISIBLE — the exact failure mode
   V114 was written for. Now the script adds .tk-armed (which hides), then .in (which
   reveals): if the script is delayed, blocked or absent, nothing is ever hidden and
   the video simply shows without the entrance. Same pattern as the theme's
   .tc-cascade observers. The delay-JS exclusion in functions.php is what restores
   the animation; this is the safety net under it. */
.tk-video.tk-armed .tk-video-stage { opacity: 0; transform: translateY(var(--tk-slide)); }
.tk-video.tk-armed .tk-video-frame { opacity: 0; transform: translateX(var(--tk-slide)); }
.tk-video.tk-armed.in .tk-video-stage { animation: tk-video-up 3000ms ease both; }
.tk-video.tk-armed.in .tk-video-frame { animation: tk-video-in 3000ms ease both; }
@keyframes tk-video-up { from { opacity: 0; transform: translateY(var(--tk-slide)); } to { opacity: 1; transform: translateY(0); } }
@keyframes tk-video-in { from { opacity: 0; transform: translateX(var(--tk-slide)); } to { opacity: 1; transform: translateX(0); } }
@media (prefers-reduced-motion: reduce) {
  .tk-video .tk-video-stage,
  .tk-video .tk-video-frame,
  .tk-video.tk-armed .tk-video-stage,
  .tk-video.tk-armed .tk-video-frame {
    opacity: 1 !important;
    transform: none !important;
    animation: none !important;
  }
}

/* ===== V146 (2026-08-22) — cart rows are WHITE at phone/tablet widths too. WooCommerce's own
   woocommerce-smallscreen.css zebra-stripes every EVEN row of a stacked (.shop_table_responsive, <=768px)
   table with rgba(0,0,0,.025) — Steven's cartbug.jpg: the second item's cells rendered light grey while
   the first stayed white. Desktop is never striped, so neither is this. The navy remove cell (V132) keeps
   its own background via :not(). Same specificity as Woo's rule (0,3,1) + !important, later in cascade. ===== */
@media only screen and (max-width: 768px) {
  .woocommerce table.shop_table_responsive tr:nth-child(2n) td:not(.product-remove),
  .woocommerce-page table.shop_table_responsive tr:nth-child(2n) td:not(.product-remove) {
    background-color: transparent !important;
  }
}

/* ===== V147 (2026-08-22) — /checkout/ (Steven's review). (a) Field titles sat ON the fields: Divi's Woo checkout
   modules render the fields outside any form element, labels inline at line-height 30px, the 58px input overlapping
   the label box by 3px, and the V72 focus ring (2px + 2px offset) then painted 7px INTO the label. Labels become
   block with 8px below; the ring now clears the label by 4px. Checkbox labels (terms, ship-to-a-different-address)
   stay inline. (b) The inline terms viewer embedded the WHOLE terms page — hero, dividers, 80% rows, 25px body —
   flush under the privacy paragraph. Now: hero + dividers hidden, rows full-width, 18px/1.5 body, 20px headings,
   soft-surface box with 16px above / 24px below, 320px tall. The layout-level fixes (top navy + bottom orange
   dividers, 64px section padding) live in the TB body layout 8605, not here. ===== */
.woocommerce-checkout .et_pb_module .form-row label:not(.checkbox):not(.woocommerce-form__label-for-checkbox) {
  display: block !important; margin-bottom: 8px !important; line-height: 1.3 !important;
}
.woocommerce-checkout .woocommerce-terms-and-conditions {
  margin: 16px 0 24px !important; padding: 20px 24px !important; max-height: 320px !important;
  background: #F6F8FB !important; border: 1px solid #b3b9c2 !important;
}
.woocommerce-checkout .woocommerce-terms-and-conditions .et_pb_fullwidth_section,
.woocommerce-checkout .woocommerce-terms-and-conditions [class*="inside_divider"] { display: none !important; }
.woocommerce-checkout .woocommerce-terms-and-conditions .et_pb_section,
.woocommerce-checkout .woocommerce-terms-and-conditions .et_pb_row {
  padding: 0 !important; width: 100% !important; max-width: 100% !important; margin: 0 !important; background: transparent !important;
}
.woocommerce-checkout .woocommerce-terms-and-conditions .et_pb_module { opacity: 1 !important; animation: none !important; transform: none !important; }
.woocommerce-checkout .woocommerce-terms-and-conditions,
.woocommerce-checkout .woocommerce-terms-and-conditions p,
.woocommerce-checkout .woocommerce-terms-and-conditions li { font-size: 18px !important; line-height: 1.5 !important; color: #011431 !important; }
.woocommerce-checkout .woocommerce-terms-and-conditions h1,
.woocommerce-checkout .woocommerce-terms-and-conditions h2,
.woocommerce-checkout .woocommerce-terms-and-conditions h3 { font-size: 20px !important; line-height: 1.2 !important; margin: 0 0 8px !important; }
/* V147b — the embedded terms page's heading row is a 100vh-style row (1000px tall inside the viewer), so the body text
   started a screen below the heading. Heights reset inside the viewer; modules flush; empty spacer paragraphs hidden. */
.woocommerce-checkout .woocommerce-terms-and-conditions .et_pb_section,
.woocommerce-checkout .woocommerce-terms-and-conditions .et_pb_row,
.woocommerce-checkout .woocommerce-terms-and-conditions .et_pb_column { height: auto !important; min-height: 0 !important; }
.woocommerce-checkout .woocommerce-terms-and-conditions .et_pb_column { padding: 0 !important; margin: 0 !important; }
.woocommerce-checkout .woocommerce-terms-and-conditions .et_pb_module { margin: 0 0 12px !important; padding: 0 !important; }
.woocommerce-checkout .woocommerce-terms-and-conditions .et_pb_text_inner { padding: 0 !important; }
.woocommerce-checkout .woocommerce-terms-and-conditions p:empty { display: none !important; }
