/* <editor-fold desc="A11Y TOOLBAR | Header trigger"> */
.a11y-widget { position: relative; }

.header-icon-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    width: 40px;
    height: 40px;
    padding: 4px;
    border: none;
    border-radius: var(--radius-6);
    cursor: pointer;
}
.header-icon-btn > * { width: 24px; height: 24px; }

header .a11y-widget .a11y-toggle { background: var(--color-grey-20); }
header .a11y-widget .a11y-toggle:hover { background: var(--color-grey-40); }
header .a11y-widget .a11y-toggle:active { background: var(--color-grey-60); }
/* aria-expanded, not a .opened class check, since it's the one thing the JS
   already keeps correctly in sync on every open/close path — desktop dropdown
   AND mobile popup alike (the JS only toggles an `.opened` class for the
   desktop dropdown case). */
header .a11y-widget .a11y-toggle[aria-expanded="true"] { background: var(--color-grey-60); }
header .a11y-widget .a11y-toggle-icon {
    width: 24px;
    height: 24px;
    background: var(--color-black-100);
    mask-image: url(../images/a11y-toolbar/icon-inclusivity.svg);
    -webkit-mask-image: url(../images/a11y-toolbar/icon-inclusivity.svg);
    mask-repeat: no-repeat;
    -webkit-mask-repeat: no-repeat;
    mask-position: center;
    -webkit-mask-position: center;
    mask-size: contain;
    -webkit-mask-size: contain;
    pointer-events: none;
}
/* </editor-fold> */

/* <editor-fold desc="A11Y TOOLBAR | Desktop panel"> */
.a11y-panel-desktop {
    display: none;
    position: absolute;
    top: calc(100% + 7px);
    left: 0;
    width: 367px;
    background: var(--color-white);
    border-radius: var(--radius-6);
    box-shadow: 0px 8px 12px 0px rgba(225, 225, 225, 0.5), 0px 0px 1px 0px #ccc;
    z-index: 9;
}
.a11y-panel-desktop .a11y-options { padding: 24px; }
/* </editor-fold> */

/* <editor-fold desc="A11Y TOOLBAR | Shared options content (rendered twice — desktop dropdown + mobile popup) "> */
.a11y-options {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 16px;
}
.a11y-section-label {
    width: 100%;
    margin: 0;
    color: var(--color-black-80);
    font-size: var(--font-size-16);
    font-weight: var(--font-weight-regular);
    line-height: var(--line-height-22);
}
.a11y-options-row {
    display: flex;
    align-items: flex-start;
    gap: 32px;
}
.a11y-option {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 12px;
    width: 85px;
    padding: 0;
    background: none;
    border: none;
    cursor: pointer;
}
.a11y-swatch {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 80px;
    height: 80px;
    padding: 9.6px;
    background: var(--color-white);
    border: 1px solid var(--color-grey-60);
    border-radius: var(--radius-16);
    pointer-events: none;
}
.a11y-swatch .a11y-icon-font-size {
    background: var(--color-black-100);
    mask-repeat: no-repeat;
    -webkit-mask-repeat: no-repeat;
    mask-position: center;
    -webkit-mask-position: center;
    mask-size: contain;
    -webkit-mask-size: contain;
}
/* Figma specs a different glyph size per option (24/32/40px) inside the same
   80px swatch, not one size stretched to fill — matches the "Aa" growing
   visibly bigger across Звичайний/Середній/Великий. */
.a11y-option[data-a11y-font-size="regular"] .a11y-icon-font-size { width: 24px; height: 24px; mask-image: url(../images/a11y-toolbar/icon-font-size-regular.svg); -webkit-mask-image: url(../images/a11y-toolbar/icon-font-size-regular.svg); }
.a11y-option[data-a11y-font-size="medium"] .a11y-icon-font-size { width: 32px; height: 32px; mask-image: url(../images/a11y-toolbar/icon-font-size-medium.svg); -webkit-mask-image: url(../images/a11y-toolbar/icon-font-size-medium.svg); }
.a11y-option[data-a11y-font-size="large"] .a11y-icon-font-size { width: 40px; height: 40px; mask-image: url(../images/a11y-toolbar/icon-font-size-large.svg); -webkit-mask-image: url(../images/a11y-toolbar/icon-font-size-large.svg); }

.a11y-swatch .a11y-icon-contrast {
    width: 26px;
    height: 26px;
    background: var(--color-black-100);
    mask-repeat: no-repeat;
    -webkit-mask-repeat: no-repeat;
    mask-position: center;
    -webkit-mask-position: center;
    mask-size: contain;
    -webkit-mask-size: contain;
}
.a11y-option[data-a11y-contrast="normal"] .a11y-icon-contrast { mask-image: url(../images/a11y-toolbar/icon-contrast-normal.svg); -webkit-mask-image: url(../images/a11y-toolbar/icon-contrast-normal.svg); }
.a11y-option[data-a11y-contrast="bw"] .a11y-icon-contrast { mask-image: url(../images/a11y-toolbar/icon-contrast-bw.svg); -webkit-mask-image: url(../images/a11y-toolbar/icon-contrast-bw.svg); }
.a11y-option[data-a11y-contrast="wb"] .a11y-icon-contrast { mask-image: url(../images/a11y-toolbar/icon-contrast-wb.svg); -webkit-mask-image: url(../images/a11y-toolbar/icon-contrast-wb.svg); }

/* Біло-Чорна's own swatch previews as a solid black tile with a white glyph (matches
   the Figma at-rest state) instead of the shared white/grey-border/dark-glyph look —
   overridden back to the shared look once selected, see below. */
.a11y-option[data-a11y-contrast="wb"] .a11y-swatch {
    background: var(--color-black-100);
}
.a11y-option[data-a11y-contrast="wb"] .a11y-icon-contrast { background: var(--color-white); }

.a11y-option-label {
    margin: 0;
    color: var(--color-black-100);
    font-size: var(--font-size-16);
    font-weight: var(--font-weight-regular);
    line-height: var(--line-height-22);
    text-align: center;
    pointer-events: none;
}

/* Selected state — one consistent green treatment across all 6 option buttons,
   including Біло-Чорна (overrides its own black "preview" styling above; the Figma
   file doesn't spec this state, see the a11y build plan's addendum on this). */
.a11y-option[aria-pressed="true"] .a11y-swatch {
    background: var(--color-green-10);
    border-color: var(--color-grey-60);
}
.a11y-option[aria-pressed="true"] .a11y-icon-font-size,
.a11y-option[aria-pressed="true"] .a11y-icon-contrast {
    background: var(--color-green-100);
}

.a11y-reset {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    width: 100%;
    height: 52px;
    padding: 8px;
    background: var(--color-white);
    border: 1px solid var(--color-black-60);
    border-radius: var(--radius-6);
    cursor: pointer;
    transition: background-color .3s, border-color .3s;
}
/* "Something to reset" state — toggled by JS (.-active class, syncA11yState())
   whenever any font-size/contrast option is off its default, independent of
   hover/press. Rest state otherwise stays grey/muted (Figma-accurate); this is
   what actually signals the button does something right now. */
.a11y-reset.-active {
    border-color: var(--color-black-80);
}
.a11y-reset.-active .a11y-reset-label { color: var(--color-black-100); }
.a11y-reset.-active .a11y-icon-reset { background: var(--color-black-100); }

/* Figma's static export has no hover/active state for this button — its rest
   state (grey border + grey text, no accent color) reads as disabled with no
   feedback at all. Added a hover/active treatment matching this codebase's
   existing .btn-white outlined-button pattern (style.css) rather than
   inventing a new one. */
.a11y-reset:hover {
    background: var(--color-black-10);
    border-color: var(--color-black-100);
}
.a11y-reset:hover .a11y-reset-label { color: var(--color-black-100); }
.a11y-reset:hover .a11y-icon-reset { background: var(--color-black-100); }
.a11y-reset:active {
    background: var(--color-black-20);
    border-color: var(--color-black-100);
}
.a11y-reset .a11y-icon-reset {
    width: 24px;
    height: 24px;
    background: var(--color-grey-400);
    mask-image: url(../images/a11y-toolbar/icon-reset.svg);
    -webkit-mask-image: url(../images/a11y-toolbar/icon-reset.svg);
    mask-repeat: no-repeat;
    -webkit-mask-repeat: no-repeat;
    mask-position: center;
    -webkit-mask-position: center;
    mask-size: contain;
    -webkit-mask-size: contain;
    pointer-events: none;
}
.a11y-reset-label {
    color: var(--color-black-60);
    font-size: var(--font-size-18);
    font-weight: var(--font-weight-bold);
    line-height: var(--line-height-24);
    pointer-events: none;
}
/* </editor-fold> */

/* <editor-fold desc="A11Y TOOLBAR | Mobile popup"> */
#popup-a11y.popup {
    display: none;
    padding: 18px 16px;
}
#popup-a11y .a11y-mobile-title-row {
    display: flex;
    align-items: center;
    gap: 12px;
    width: 100%;
}
#popup-a11y .a11y-mobile-title {
    flex: 1 0 0;
    margin: 0;
    color: var(--color-black-100);
    font-family: var(--font-family-base);
    font-weight: var(--font-weight-black);
    font-size: var(--font-size-18);
    line-height: var(--line-height-24);
}
/* .a11y-options itself is align-items:flex-start (shared with the desktop dropdown,
   where the 367px panel width already exactly fits the options-row's own width —
   three 85px swatches + two 32px gaps = 319px, plus the panel's 24px×2 padding =
   367px — so flex-start there never left any visible slack). The mobile popup is
   full viewport width instead, so the same fixed-width row+reset-button block sits
   flush left with a variable-width gap on the right depending on the phone. Center
   it here instead; .a11y-section-label defaults to left-aligned text, so it's
   centered too — otherwise the label would float left over a now-centered row. */
#popup-a11y .a11y-options {
    margin-top: 16px;
    align-items: center;
}
#popup-a11y .a11y-section-label { text-align: center; }

/* the shared full-screen popup breakpoint is 719px (style.css), but the header's own
   mobile breakpoint (where the trigger becomes reachable outside the desktop dropdown)
   is 1180px — without this override there's a 720-1180px gap where the trigger shows but
   the popup isn't full-screen yet. */
@media (max-width: 1180px) {
    #popup-a11y.popup {
        width: 100%;
        height: 100%;
        padding: 18px 16px;
        border-radius: 0;
    }
}
/* </editor-fold> */

/* <editor-fold desc="A11Y TOOLBAR | Font-size mechanism"> */
html.a11y-font-medium { --a11y-font-scale: 1.15; }
html.a11y-font-large { --a11y-font-scale: 1.3; }
/* </editor-fold> */

/* <editor-fold desc="A11Y TOOLBAR | Contrast mechanism"> */
/* Token overrides, not just filter:grayscale(1) — a plain filter only strips
   saturation, it doesn't compensate for the fact that removing saturation from
   a mid-lightness accent color makes it look washed out (real problem: our own
   --color-green-100 has just 2.57:1 contrast against white even in full
   color — grayscale alone doesn't fix that, since it preserves raw luminance).
   Values below were derived the same way a reference site's black-on-white
   scheme does it (checked their light-mode + bw palettes side by side, ran
   the actual WCAG contrast math): near-neutral tokens are left untouched
   (already low-saturation, nothing to fix), pale background tints map to an
   equally pale existing grey token, and saturated accent colors get mapped to
   a grey DARKER than their raw luminance would suggest — boosting contrast
   past the original rather than just matching it — reusing an existing grey
   token wherever one is genuinely close enough, only two new one-off hex
   values (green-80/green-60) where nothing already in the palette fit.
   Relative ordering is preserved (green-100 darkest/strongest down to
   green-60 lightest, matching the original resting → hover progression).
   These are pure R=G=B greys, so the filter: grayscale(1) below is a no-op on
   them — it's still needed as a catch-all for the handful of colors this
   theme's token pass deliberately left as literals (box-shadow rgba, a few
   decorative one-offs). */
html.a11y-contrast-bw {
    --color-green-100: var(--color-grey-400);      /* #707070, 4.95:1 vs white (was 2.57:1) */
    --color-green-80: #808080;                     /* .btn:active — 3.95:1 */
    --color-green-60: #949494;                     /* .btn:hover — 3.03:1 */
    --color-green-10: var(--color-grey-100);        /* #f5f5f5 — pale tint stays pale */
    --color-green-20-light: var(--color-grey-200);  /* #eeeeee — pale tint stays pale */
    --color-red-700: var(--color-black-80);         /* #4e4c4c, 8.54:1 vs white (was 4.19:1) */
    --color-link: var(--color-black-60);            /* #7a7979, 4.34:1 vs white (was 3.43:1) */
    --color-link-active: var(--color-grey-500);     /* #9a9a9a — brief :active flash, lower bar ok */
    filter: grayscale(1);
}
/* Neither `html` nor `body` has an explicit background anywhere in this theme
   (assets/css/style.css) — the page's visible white is just the browser's own
   default canvas showing through a transparent root, not a painted pixel.
   filter can only act on what's actually painted, so without this the "white"
   page background stayed white under Біло-Чорна.

   A dedicated reversed palette, not filter:invert() — matches how a
   reference site's own white-on-black scheme does it (checked their
   light-mode neutral scale against their white-on-black one: lightest↔darkest
   are swapped end-to-end, e.g. their light neutral-0 #ffffff pairs with their
   wb neutral-360 #ffffff — same value, opposite end of the scale — confirmed
   across the whole 31-step scale, not just the ends). invert() was tried
   first and reverted: it touches every painted pixel uniformly including
   photos, which produces a real photo-negative look, and a token approach
   doesn't have that problem since it only touches things actually styled
   through these variables.

   Every base neutral/grey/black token below was ordered by real WCAG
   luminance (not by name) and mirrored end-to-end around the middle of that
   list, e.g. --color-white (lightest) gets --color-black's value and vice
   versa, --color-grey-20 (2nd lightest) gets --color-black-100's value (2nd
   darkest), and so on — the same mirroring technique confirmed in the
   reference. --color-grey-300 sits exactly in the middle of the ordered list
   so it has no override (mirrors to itself).

   The 8 accent tokens (green/red/link) get fresh values suited to a dark
   background specifically, not just their [[a11y-contrast-bw]] values
   reused backwards — a color that reads well on white doesn't automatically
   read well on black. Same principle as bw though: pick something that
   actually contrasts well against the (now dark) page rather than just
   desaturating in place, reuse existing token values where one already fits.

   filter: grayscale(1) is kept even though nothing here should still be
   saturated — same catch-all reasoning as bw, for box-shadow rgba and the
   handful of decorative one-off colors this theme's token pass didn't cover.
   It does NOT fully solve real photos: grayscale removes color but doesn't
   re-invert lightness, so a genuinely multi-tone photo stays dark-on-now-dark
   -page — the same tradeoff the reference itself accepts (their own
   white-on-black block has no invert() either), not something fixable without
   a dedicated dark-mode asset for that specific photo. (The header/footer logo
   used to be lumped in with this caveat too, but turned out to be a flat
   single-color mark once actually sampled — see its own rule further down,
   which inverts it same as any other flat icon instead.) */
html.a11y-contrast-wb {
    /* base neutral/grey/black scale, full end-to-end mirror by luminance */
    --color-white: #000000;
    --color-black: #ffffff;
    --color-black-100: #f6f8fa;
    --color-black-80: #f5f5f5;
    --color-black-60: #ebedf2;
    --color-black-40: #d1d5dc;
    --color-black-20: #cad3da;
    --color-black-10: #9a9a9a;
    --color-grey-20: #221f1f;
    --color-grey-40: #7a7979;
    --color-grey-60: #d3d2d2;
    --color-grey-100: #4e4c4c;
    --color-grey-200: #707070;
    --color-grey-400: #eeeeee;
    --color-grey-500: #e9e9e9;
    --color-grey-border: #a7a5a5;
    /* --color-grey-300 (#d2d2d2) is the scale's own midpoint — no override */

    /* accent tokens, picked for contrast against the new dark background,
       not reused from the bw mapping (bw's values target contrast vs white) */
    --color-green-100: #9a9a9a;      /* 7.47:1 vs black — primary accent */
    --color-green-80: #7a7979;       /* .btn:active — 4.84:1 */
    --color-green-60: #707070;       /* .btn:hover — 4.24:1 */
    --color-green-10: #4e4c4c;       /* pale bg tint → dark bg tint (style.css use) */
    --color-green-20-light: #4e4c4c; /* currently unused by any live rule, kept
       consistent with green-10's dark-tint treatment in case that changes */
    --color-red-700: #f5f5f5;        /* errors need max legibility regardless of theme */
    --color-link: #a7a5a5;           /* 8.63:1 vs black */
    --color-link-active: #cad3da;    /* brief :active flash, lighter than resting link */

    background: var(--color-white);
    filter: grayscale(1);
}
/* Scoped overrides for the SELECTED swatch, under WB mode specifically. The
   selected-state rule's background actually reads --color-green-10 (not
   --color-green-20-light, as an earlier pass here wrongly assumed) — and
   green-10 is also used on regular pages as a pale section-background tint
   (style.css), where it correctly needs to stay dark/subtle against the new
   dark page. That's the opposite of what the SELECTED SWATCH itself needs
   (must stand out against the panel, not blend in) — same category of
   two-roles-want-opposite-lightness conflict as green-100 below, same fix:
   a scoped override here instead of forcing the shared token to serve both. */
html.a11y-contrast-wb .a11y-option[aria-pressed="true"] .a11y-swatch {
    background: var(--color-grey-60);       /* #d3d2d2 */
    border-color: var(--color-grey-border); /* #a7a5a5 */
}
/* --color-green-100 (the selected-icon color, set above) can't just flip
   light either — it's also used as light-on-black TEXT elsewhere (e.g. the
   search "see more" link), which needs to stay light to read against the
   page. But that same light value sitting on the now-light selected-swatch
   background (right above) would have barely any contrast against its own
   swatch. */
html.a11y-contrast-wb .a11y-option[aria-pressed="true"] .a11y-icon-font-size,
html.a11y-contrast-wb .a11y-option[aria-pressed="true"] .a11y-icon-contrast {
    background: var(--color-grey-20); /* #221f1f */
}
/* Same two-roles-want-opposite-lightness conflict as the selected swatch above,
   this time on the header trigger button itself (.a11y-toggle-icon uses
   --color-black-100 for its fill everywhere — header trigger section, top of
   this file). At rest the button's own background is --color-grey-20, which
   mirrors DARK under wb, so a near-white icon reads fine there with no override
   needed. But the :active / [aria-expanded="true"] states switch the button
   background to --color-grey-60, which mirrors LIGHT (#d3d2d2) — pairing it
   with the still-near-white icon collapses to ~1.4:1 contrast, i.e. the icon
   all but disappears exactly when the panel is open. Pin the icon dark for
   just those two light-background states, same fix as the swatch above. */
html.a11y-contrast-wb header .a11y-widget .a11y-toggle:active .a11y-toggle-icon,
html.a11y-contrast-wb header .a11y-widget .a11y-toggle[aria-expanded="true"] .a11y-toggle-icon {
    background: var(--color-grey-20); /* #221f1f */
}
/* Inline <svg> icons pasted straight from Figma exports (header search, footer
   socials, popup close buttons, docs/legal notice icons, etc. — audited
   sitewide 2026-08-24) hardcode their own fill/stroke ("#221F1F" almost
   everywhere, since that IS --color-black-100's normal value, plus a "white"
   counter-fill on two-tone icons like the popup close X). None of that is a
   token, so nothing above can reach it, and these icons' containers (search
   field, footer, popup) all flip dark under this scheme — dark-on-dark.

   Rather than override fill/stroke per icon (the previous approach here, and
   the reason a plain path[fill] audit doesn't scale: every future icon export
   would need its own copy of this rule), invert the icon's rendered pixels
   wholesale. A plain 2-color icon (any dark mark, incl. on a transparent
   background) survives filter:invert(1) perfectly — it just becomes the same
   icon in light-on-dark instead of dark-on-light, and the existing
   filter:grayscale(1) above already handles anything invert() alone wouldn't
   (a stray saturated color slipping into a "should be neutral" icon). This is
   the same invert() that was tried and reverted for the *whole page* early on
   (see the wb rationale above it) — the problem there was photos and the logo
   going photo-negative; scoped to plain vector icons only, that problem
   doesn't apply, and this is exactly the workaround that avoids having to
   hand-edit every SVG a designer exports going forward.

   Default is invert *everything* under svg, then carve out the known
   exceptions below — icons/graphics where inverting is wrong, not missing:
     - .post-meta / .author-name (single-post.php) already use fill="currentColor"
       and inherit the page's own (already-correctly-flipping) token text color —
       inverting on top would flip them a second time, right back to broken.
     - .share-buttons (single-post.php) are brand-colored social share icons
       (Telegram/Facebook/LinkedIn/X) — inverting turns official brand colors
       into nonsense hues.
     - .page-404 is the 404 mascot illustration — a decorative graphic, same
       "can't touch it without a dedicated dark asset" category as the logo.
     - .notice-icon (single-rp_knowledge_base.php, single-rp_legal.php) is the
       orange warning-triangle icon — its color is semantic (warning = orange),
       not decorative, and orange keeps working on both light and dark.
     - .payment-page .branding-block is a self-contained "customize your
       checkout branding" demo with its OWN light/dark toggle already wired up
       (svg.colorable path.c-b/.c-w, style.css) plus real payment-brand logos
       (Google Pay, Apple Pay, Mastercard, etc.) — inverting would fight its
       existing mechanism and mangle the brand marks.

   New icons need nothing extra to work under wb. Only a future brand logo or
   illustration needs an explicit `.no-a11y-invert` escape hatch, same as the
   exceptions above. */
html.a11y-contrast-wb svg:not(.no-a11y-invert) {
    filter: invert(1);
}
html.a11y-contrast-wb .post-meta svg,
html.a11y-contrast-wb .author-name svg,
html.a11y-contrast-wb .share-buttons svg,
html.a11y-contrast-wb .page-404 svg,
html.a11y-contrast-wb .notice-icon,
html.a11y-contrast-wb .payment-page .branding-block svg {
    filter: none;
}

/* Same underlying problem as the svg invert above, but for ACF icon-picker glyphs —
   a recurring "small icon centered in its own tinted square" card pattern reused
   sitewide under many different names (mission-block, audience-block,
   solutions-block, payment-methods-block, cards-block, forwhom-cards,
   contacts-v4-item, cost-block, step-header, kb-cards, search-state, etc. —
   template-parts/feature-card-block.php plus several hand-rolled lookalikes that
   copy its exact .icon-wrapper/img structure), sitting in a
   var(--color-grey-40)/--color-grey-20/--color-green-20-light box, all of which
   correctly flip dark under wb per the mirror table above. But
   wp_get_attachment_image() (lazy_get_attachment_image(), helpers.php) always
   renders an <img>, never inline <svg> markup even for .svg attachments, so none
   of these reach the svg-invert rule above and stay their original color on
   what's now a dark box.

   Not every image in this family is actually a flat glyph though — audited every
   .feature-card icon sitewide (about-us-v4, acquiring, business-breakfast,
   buy-with-rpay-v4, ecommerce, fiscalization-v4, fop-from-zero-v4, front-page_v4,
   horoshop, invoicing-v4, payment-installments-v4, rates-page, webinar-single-v4)
   by fetching each file: every single genuine icon in this codebase — regardless
   of hue, e.g. installments-v4-conditions' icon-internet.svg is light blue, not
   the usual #221F1F/#4E4C4C — is an actual .svg upload, while every case that
   broke under a blanket invert (acquiring's container-1/2/3.png and
   benefit-icon-manual-work.png, horoshop's benefit-icon-*.png/previewcrm*.png,
   ecommerce's quick-start-block folder illustration, business-breakfast/
   webinar-single-v4's real speaker headshot photos) is a raster upload — despite
   several of those filenames also containing "icon". brightness(0) first (not a
   plain invert(1)) is what makes hue irrelevant for the genuine SVGs: it forces
   true black regardless of the exact source color before inverting to white — the
   same idiom this codebase's own .kb-card/.legal-card hover states already use —
   so any flat-color icon lands on a clean white glyph. That same brightness(0)
   is exactly what wrecks a raster illustration instead: crushed to a solid black
   silhouette (destroying its actual gradients/photo detail) and inverted to a
   blank white block.

   [src$=".svg"] is therefore the actual distinguishing signal, not filename or
   color — restricting the selector to it means every current raster case is
   excluded automatically, and any future icon upload only needs to actually BE
   an .svg to get this treatment for free, no manual .no-a11y-invert-style
   escape hatch needed (unlike the inline-<svg> rule above, where a colored
   brand mark still needs one, since inline <svg> has no equivalent "wrong
   format" tell to filter on).

   Bonus/CTA-hero icons (.get-guide-block, .cta-banner-block and siblings fixed
   above, .bonuses-block .bonus-card — spot-checked one, already pre-colored white
   in the source SVG) are a different, illustration-flavored family and out of
   scope here; only the small-icon-in-a-tinted-square "feature card" pattern is
   covered by this rule. */
html.a11y-contrast-wb .feature-card .icon-wrapper img[src$=".svg"],
html.a11y-contrast-wb .about-us-v4 .values-block .value-card .icon-wrapper img[src$=".svg"],
html.a11y-contrast-wb .contacts-v4-item .icon-wrapper img[src$=".svg"],
html.a11y-contrast-wb .fiscalization-v4 .cost-block .card .icon-wrapper img[src$=".svg"],
html.a11y-contrast-wb .installments-v4-conditions .step-header .icon-wrapper img[src$=".svg"],
html.a11y-contrast-wb .kb-cards .kb-card .icon-wrapper img[src$=".svg"],
html.a11y-contrast-wb .search-page .search-state .icon-wrapper img[src$=".svg"] {
    filter: brightness(0) invert(1);
}

/* Same "ACF/theme-asset icon rendered as <img>, never reaches the svg-invert rule"
   problem as the feature-card family above, just for hero-v4.css's own icon
   pattern — .hero-v4-stat-icon (template-parts/hero-v4.php, reused by the
   homepage/acquiring/fiscalization-v4/horoshop/invoicing-v4/business-breakfast/
   single-rp_webinars hero + business-breakfast's "Де і коли" section, which
   reuses the same hero-v4-stats markup a second time per its own comment in
   template_business-breakfast.php) sits in its own var(--color-grey-40) box,
   same as everywhere else. Checked every icon across every page that uses this
   markup (homepage, acquiring, horoshop, business-breakfast incl. its "Де і
   коли" reuse) — all .svg, all consistently #221F1F. [src$=".svg"] added
   anyway, same defensive reasoning as the feature-card family above: costs
   nothing against the current all-SVG reality, and stops a future raster
   upload here from silently repeating the container-1.png-style breakage
   found (and excluded via this exact same guard) in that family. */
html.a11y-contrast-wb .hero-v4-stat-icon img[src$=".svg"] {
    filter: brightness(0) invert(1);
}

/* Same img-not-svg gap again, this time in the main header nav — every dropdown
   submenu item's icon (helpers.php's get_header_submenu(), used by both the
   regular header menu and the rp_documentation header menu, ACF-driven via
   $options_fields['header_menu']/['documentation_header_menu']) is rendered
   through the same img-wrapper structure sitewide, sitting in a
   var(--color-grey-40) box at rest and var(--color-green-20-light) on
   hover/.current — both flip dark under wb same as elsewhere. Checked every
   icon in the main header menu (all 19, from two different pages) — all .svg,
   all #221F1F; didn't have a reachable rp_documentation post to check its
   separate documentation_header_menu the same way, but it renders through this
   identical selector via the same get_header_submenu(), so [src$=".svg"] covers
   it too the moment it's checked — same defense-in-depth reasoning as above. */
html.a11y-contrast-wb header .header-menu ul li.has-submenu .submenu ul li a .img-wrapper img[src$=".svg"] {
    filter: brightness(0) invert(1);
}

/* A third rendering pattern for the same "icon never reaches the svg-invert
   rule" family — a plain CSS background: url(file.svg) on a pseudo-element,
   not an <img> and not an inline <svg> element, so neither of the two fixes
   above can reach it either. submenu-icon-2.svg (fill="#221F1F", checked the
   file directly) is reused for both of the main header nav's own chevrons:
   the small arrow that fades in on hover inside a submenu item (span:after),
   and the mobile/tablet accordion's expand/collapse chevron (top-level
   > a:before, style.css's own @media block). filter works the same way on a
   background-image as it does on an <img>, so the fix is identical — it just
   has to target the element/pseudo-element carrying the background directly,
   since there's no separate child node to select. */
html.a11y-contrast-wb header .header-menu ul li.has-submenu .submenu ul li a span:after,
html.a11y-contrast-wb header .header-menu > ul > li > a:before {
    filter: brightness(0) invert(1);
}

/* The header/footer brand logo (header.php/footer.php, wp_get_attachment_image()/
   lazy_get_attachment_image() off the same custom_logo attachment, two different
   registered image sizes of the one .svg) is the "naturally dark logo" the wb
   mirror-table comment above says grayscale(1) alone can't fix without "a
   dedicated dark-mode logo asset" — true in general (a real multi-tone photo/
   illustration logo can't be safely recolored), but this specific logo turns out
   to be a flat single fill throughout ("ROZETKA Pay", #06BA52 — sampled every
   pixel of the actual file via canvas to confirm there's no second color hiding
   in it, despite how it can look at small/compressed sizes). That makes it no
   different from the plain single-color icon families already handled by
   brightness(0) invert(1) elsewhere in this file — no dedicated asset needed
   after all, at least for as long as the logo stays this simple. */
html.a11y-contrast-wb .header-logo img,
html.a11y-contrast-wb .footer-logo img {
    filter: brightness(0) invert(1);
}

/* Same img-not-svg gap once more, for the knowledgebase.css sidebar accordion and
   its own search results (.kb-cards, above, was already covered — these are its
   two siblings in the same file: the left-hand category nav and the AJAX search
   dropdown). Correction to the note left on the feature-card fix above ("KB/legal
   sidebar-nav and search-result icon-wrappers... unflipped raw-hex background,
   a separate bug") — that was true for legal-pages.css (.legal-sidebar/
   .legal-search-results, still unfixed, still a separate bug) but wrong for
   knowledgebase.css: re-checked here and .kb-sidebar/.kb-search-results .icon-wrapper
   both already use var(--color-grey-40) (checked live: #221F1F icon on a
   correctly-wb-flipped #7a7979 box), the same safe token-driven pattern as
   everywhere else in this file.
   .kb-search-results .kb-empty .icon-wrapper img is deliberately excluded — unlike
   its dark, flat siblings this one (kb-search-empty-icon.svg) is a multi-color
   "no results" illustration, already fill="white" plus its own internal linear
   gradient, checked live — inverting it would wreck both. */
html.a11y-contrast-wb .kb-sidebar .nav-list .item .icon-wrapper img,
html.a11y-contrast-wb .kb-search-results .kb-result-item .icon-wrapper img {
    filter: brightness(0) invert(1);
}

/* Same third pattern as the main header nav's own chevrons above — a plain
   background: url("data:image/svg+xml,...fill='%23221F1F'...") on the
   has-child expand/collapse pseudo-element, not an <img> or inline <svg>, so
   it's invisible to both invert rules elsewhere in this file. This one gap
   exists even though the rest of knowledgebase.css is already correctly
   tokenized — a data-URI's fill can't reference a CSS custom property at
   all, so this was never a "should've used a token" oversight like the rest
   of this file's colors, just a different technique that needed a different
   fix. filter still works on it the same way. */
html.a11y-contrast-wb .kb-sidebar .nav-list li.has-child > a:after {
    filter: brightness(0) invert(1);
}

/* legal-pages.css's hub (.legal-sidebar/.legal-hub/.legal-search/.legal-cards) is
   the pre-token original that knowledgebase.css's hub (.kb-sidebar/.kb-hub-content/
   .kb-search/.kb-cards, both fixed above) was later split off from and tokenized —
   its own top comment says so ("Split off from legal-pages.css... Legal Info stays
   untouched"). Every single value below is still the literal hex the equivalent
   knowledgebase.css rule replaced with a var() — confirmed by diffing the two
   files rule-by-rule, not guessed — so each override here just plugs in the same
   token knowledgebase.css already proved correct for that exact spot.

   This is bigger than "the icons": inverting only the icons without also flipping
   their containing boxes+text would have made things worse, not better — before
   this, .legal-cards/.legal-search-results/.legal-hub .hero-icon were self-
   consistent light islands (light box, dark icon, dark hardcoded text, all
   unmoved by wb) that actually read fine as-is; only .legal-sidebar's icon-wrapper
   (already var(--color-grey-40), like the KB sidebar) and .legal-hub .hero-title/
   .hero-subtitle (color:#221f1f hardcoded, sitting directly on the page's own
   background which DOES flip to black) were genuinely broken already. Moving the
   rest of the hub to match now makes every piece move together instead of leaving
   some pieces flipped and others not.

   .legal-hub .hero-icon img and .legal-search-results .legal-empty .icon-wrapper
   img are deliberately excluded from the invert, same reasoning as their
   knowledgebase.css counterparts: legal-hero-icon.svg is a two-tone illustration
   (#DFFEDD + white fills, checked live), and the "no results" icon is literally
   the same shared kb-search-empty-icon.svg asset (white + internal gradient) used
   by the KB empty state above — neither is a flat glyph. */
html.a11y-contrast-wb .legal-sidebar .nav-list .item .icon-wrapper img {
    filter: brightness(0) invert(1);
}
html.a11y-contrast-wb .legal-hub .hero-icon { background: var(--color-green-20-light); }
html.a11y-contrast-wb .legal-hub .hero-title,
html.a11y-contrast-wb .legal-hub .hero-subtitle { color: var(--color-black-100) !important; }
html.a11y-contrast-wb .legal-search .legal-search-input {
    background: var(--color-white);
    border-color: var(--color-grey-60);
}
html.a11y-contrast-wb .legal-search .legal-search-input:focus-within { border-color: var(--color-black-100); }
html.a11y-contrast-wb .legal-search .legal-search-input .legal-search-spinner { border-color: var(--color-black-80); border-right-color: transparent; }
html.a11y-contrast-wb .legal-search .legal-search-input input { color: var(--color-black-100); }
html.a11y-contrast-wb .legal-search .legal-search-input input::placeholder { color: var(--color-black-80); }
html.a11y-contrast-wb .legal-search-results { background: var(--color-white); }
html.a11y-contrast-wb .legal-search-results .legal-result-item { color: var(--color-black-100); }
html.a11y-contrast-wb .legal-search-results .legal-result-item .icon-wrapper { background: var(--color-grey-40); }
html.a11y-contrast-wb .legal-search-results .legal-result-item:hover .icon-wrapper { background: var(--color-green-20-light); }
html.a11y-contrast-wb .legal-search-results .legal-result-item .icon-wrapper img { filter: brightness(0) invert(1); }
html.a11y-contrast-wb .legal-search-results .legal-result-item .result-title { color: var(--color-black-100); }
html.a11y-contrast-wb .legal-search-results .legal-result-item .result-snippet { color: var(--color-black-80); }
html.a11y-contrast-wb .legal-search-results .legal-empty .icon-wrapper { background: var(--color-grey-20); }
html.a11y-contrast-wb .legal-search-results .legal-empty .empty-title { color: var(--color-black-100); }
html.a11y-contrast-wb .legal-search-results .legal-empty .empty-subtitle { color: var(--color-black-80); }
html.a11y-contrast-wb .legal-cards .legal-card { background: var(--color-grey-20); }
html.a11y-contrast-wb .legal-cards .legal-card:hover { background: var(--color-green-20-light); }
html.a11y-contrast-wb .legal-cards .legal-card .icon-wrapper { background: var(--color-grey-40); }
html.a11y-contrast-wb .legal-cards .legal-card:hover .icon-wrapper { background: var(--color-green-100); }
html.a11y-contrast-wb .legal-cards .legal-card .icon-wrapper img { filter: brightness(0) invert(1); }
html.a11y-contrast-wb .legal-cards .legal-card .card-title,
html.a11y-contrast-wb .legal-cards .legal-card .card-desc { color: var(--color-black-100); }

/* .tarif-card-header (template-parts/tarif-cards-block.php, shared by the Тарифи
   page, Головна v4, Інвойсинг and Internet Acquiring) sets its background from a
   raw hex value straight out of an ACF color-picker field via an inline `style`
   attribute — not a token, so nothing above can flip it. Every value editors have
   actually picked is a light/pastel tint (it's a header band sitting on top of an
   otherwise-white card), and grayscale(1) only desaturates it in place without a
   lightness flip, so it stays light here too. The title/description text inside,
   though, isn't styled locally — it inherits the page's ordinary body text color
   (--color-black-100), which correctly flips to near-white for the (now dark)
   page elsewhere, leaving near-white text on this still-light header band.
   Arbitrary backend colors can't be reliably auto-inverted, so rather than fight
   the inline background, pin just the header's own text back to its normal dark
   value — it was always going to sit on a light tint regardless of contrast mode. */
html.a11y-contrast-wb .tarif-card-title,
html.a11y-contrast-wb .tarif-card-desc {
    color: var(--color-grey-20) !important; /* #221f1f */
}

/* Same pattern again, found while auditing the svg invert exception above:
   .page-404's mascot illustration (style.css) is a fixed pale mint (#E0F6EF)
   decorative graphic — excluded from the invert above like any other
   illustration, so it stays light under wb. Its "Oops! 404" title sits on
   top of it but, like tarif-card-title, isn't styled locally — it inherits
   --color-black-100, which flips to near-white for the rest of the (now
   dark) page and goes invisible against this one deliberately-still-light
   background. Same fix: pin the title back to dark, it was always going to
   render over pale mint regardless of contrast mode. */
html.a11y-contrast-wb .page-404 .title {
    color: var(--color-grey-20) !important; /* #221f1f */
}

/* Same pattern again: .btn-black.btn-border (style.css) is a glassmorphism
   variant — background: rgba(255,255,255,.5), a raw rgba value, not a token —
   used on the 404 mascot illustration above (404.php, sits on the same fixed
   pale mint background) and on rp_documentation's doc-head (single-rp_documentation.php,
   sits on .doc-head-background's own fixed #fafafa — documentation.css). Its
   text/icon color is --color-black-100, which flips to near-white under wb same
   as everywhere else, but the background never flips dark, so the button text
   goes invisible (white-on-white). Pin it back to dark — like tarif-card-title
   and the 404 title above, it was always going to sit on a fixed light
   background regardless of contrast mode. */
html.a11y-contrast-wb .btn-black.btn-border {
    color: var(--color-grey-20); /* #221f1f */
}

/* A whole family of pages share one "gradient CTA card" recipe — always the
   same two-stop diagonal gradient, var(--color-green-20-light) into a raw
   #fcfffc/#FCFFFC literal (only the angle and stop percentages vary a little
   page to page), just under a different wrapper class each time because each
   page's own component got its own name when it was copied:
     - .get-guide-block .block-wrapper       (fop-from-zero-v4, fiscalization-v4,
                                                acquiring, guides-v4)
     - .care-banner-container                 (front-page_v4)
     - .vacancies-cta-block .cta-card         (about-us-v4)
     - .cta-banner-block .block-wrapper       (ecommerce, and acquiring's own
                                                *second* CTA further down its file)
     - .final-cta-block .block-wrapper        (business-breakfast)
     - .webinar-page .last-block .block-wrapper (webinar-single-v4)
     - .installments-v4-plate .plate-wrapper  (payment-installments-v4)
   In every case the first stop is a token and flips dark under wb same as
   everywhere else, but the raw literal stop never flips, so the card ends up
   half dark / half still-near-white. The heading/.desc/.subtitle text inside
   is never styled locally in any of these — it inherits the ordinary
   --color-black-100 body-text color, which flips to near-white for the
   (correctly dark) half and goes invisible for the (still light) half —
   readability depends entirely on which half of the diagonal a given line of
   text happens to land on. A single fixed background side-steps that: drop
   the gradient and pin the whole card to the same dark grey the first stop
   already flips to, so every line of text reads consistently regardless of
   position. One rule listing every wrapper class (no page-specific prefix
   needed, none of these names are used for anything else) covers every
   caller, same reasoning as the slick-dots fix above — and covers any future
   page that copies this same recipe under yet another wrapper name only if
   that name gets added here too. */
html.a11y-contrast-wb .get-guide-block .block-wrapper,
html.a11y-contrast-wb .care-banner-container,
html.a11y-contrast-wb .vacancies-cta-block .cta-card,
html.a11y-contrast-wb .cta-banner-block .block-wrapper,
html.a11y-contrast-wb .final-cta-block .block-wrapper,
html.a11y-contrast-wb .webinar-page .last-block .block-wrapper,
html.a11y-contrast-wb .installments-v4-plate .plate-wrapper {
    background: var(--color-green-20-light); /* #4e4c4c under wb */
}

/* .slick-dots active-state indicator — the identical
   background: var(--color-grey-border) [inactive] / var(--color-green-100) [active]
   pair is repeated verbatim in style.css (.customers-reviews-block) and every
   slick-carousel page CSS (about-us-page, acquiring, buy-with-rpay-v4, ecommerce,
   front-page_v4, horoshop, invoicing-v4, payment-installments-v4, rates-page).
   Under wb, --color-grey-border (#a7a5a5) and --color-green-100 (#9a9a9a) land
   within a few % of each other in lightness — both were tuned against bw's still-
   white page, not against wb's now-dark one, so the active dot stops reading as
   "the accent color standing out" and reads as "the same grey as the rest, barely."
   Pin it to a flat white instead of hunting for a better grey; one selector here
   covers every caller since they all share this exact
   `.slick-dots li.slick-active button` structure, instead of duplicating the
   override in each page's own CSS file. Deliberately a literal, not
   var(--color-black) (which also holds #ffffff under wb, above) — the point
   here is an unconditional pure white regardless of what the mirrored palette
   does, not "whatever --color-black currently resolves to". */
html.a11y-contrast-wb .slick-dots li.slick-active button {
    background: #ffffff !important;
}

/* .popup (style.css) has no border in any mode — it separates itself from the page
   purely with a soft rgba(0,0,0,...) drop shadow, which is exactly the one thing
   grayscale(1) can't fix (it desaturates, it doesn't relight): under wb the popup's
   own background is --color-white, which flips to black same as the page behind
   it, so a *black* shadow against a now-black page is completely invisible — the
   popup reads as a plain black rectangle floating with no edge at all. Every
   .popup instance (get-consultation, thank-you, individual-rate, the a11y mobile
   popup, etc.) shares this one base class, so one override fixes all of them.
   Mirrors the original two-layer shadow (soft ambient glow + tight edge line) with
   white instead of black — same technique as .select-gr .select-list below, which
   has the identical background-flips-to-match-the-page problem. */
html.a11y-contrast-wb .popup {
    box-shadow: 0 0 96px 0 rgba(255, 255, 255, 0.1), 0 0 2px 0 rgba(255, 255, 255, 0.2);
}
html.a11y-contrast-wb .select-gr .select-list {
    box-shadow: 0 8px 12px 0 rgba(255, 255, 255, 0.15);
}

/* Sitewide sweep (grepped every assets/css/*.css file for raw hex matching an
   existing token's value — the same "should be a token, isn't" signal that
   found legal-pages.css) turned up a few more spots outside any single page:

   header .mobile-nav (style.css) — the tablet/mobile hamburger toggle, present
   in the header on every page below ~1180px. Its own background is a raw
   #F6F8FA/#EBEDF2/#D3D2D2 trio (rest/hover/open, none of them tokens) that
   never flips, while the hamburger bars themselves (.nav-icon span) already use
   var(--color-black) and DO flip to white — so under wb the bars turn white
   while sitting on a background that's still near-white, and the toggle goes
   completely invisible. Checked live at 1100px: confirmed, the button was a
   blank box with no visible icon at all. Pinning the three background states
   to their exact token equivalents (confirmed by matching hex, same technique
   as legal-pages.css) fixes it without touching the bars, which were already
   correct. */
html.a11y-contrast-wb header .mobile-nav { background: var(--color-grey-20); }
html.a11y-contrast-wb header .mobile-nav:hover { background: var(--color-grey-40); }
html.a11y-contrast-wb body.mobile-menu header .mobile-nav { background: var(--color-black-20); }

/* .btn's default --btn-pulse-color (style.css) is a raw #06BA52 — every other
   variant (.btn-black/.btn-white, style.css) already sets this custom property
   from a token, this one spot was just missed. Under wb the button's own
   background (var(--color-green-100)) correctly mutes to grey, but the pulse
   ring around it (box-shadow using this variable, style.css's @keyframes
   btn-pulse) would still flash raw saturated green — a minor mismatch, not an
   invisibility bug like the ones above, but the same fix either way. */
html.a11y-contrast-wb .btn { --btn-pulse-color: var(--color-green-100); }

/* Pagination hover/active states, copy-pasted with the same raw-hex drift into
   both blog-pages-v2.css and search-page.css (the .pag/.pag-btn structure is
   shared, per the "reused sitewide pagination() helper" — but each page's own
   CSS file re-declares these interaction states by hand, and only the rest/
   hover states in search-page.css happened to already use tokens). Transient
   states (only visible mid-click or mid-hover), so lower impact than the
   mobile-nav toggle above, but the same category of bug and the same fix. */
html.a11y-contrast-wb .blog-archive .latest-posts-section .pagination-container .pagination-list .pag:not(.current):hover,
html.a11y-contrast-wb .blog-archive .latest-posts-section .pagination-container .pagination-list .pag:not(.current):active,
html.a11y-contrast-wb .search-page .pagination-list .pag:not(.current):active {
    color: var(--color-black-100);
    border-color: var(--color-black-100);
}
html.a11y-contrast-wb .blog-archive .latest-posts-section .pagination-container .pagination-list .pag:not(.current):hover { background: var(--color-black-10); }
html.a11y-contrast-wb .blog-archive .latest-posts-section .pagination-container .pagination-list .pag:not(.current):active,
html.a11y-contrast-wb .search-page .pagination-list .pag:not(.current):active { background: var(--color-black-20); }
html.a11y-contrast-wb .blog-archive .latest-posts-section .pagination-container .pagination-list .pag-btn:not([disabled]):hover,
html.a11y-contrast-wb .search-page .pagination-list .pag-btn:not([disabled]):hover { background: var(--color-black-60); }
html.a11y-contrast-wb .blog-archive .latest-posts-section .pagination-container .pagination-list .pag-btn:not([disabled]):active,
html.a11y-contrast-wb .search-page .pagination-list .pag-btn:not([disabled]):active { background: var(--color-black-80); }

/* .pag-btn (the prev/next arrow, all three pagination() callers — blog, search,
   webinar-archive-v4 — one shared PHP helper, includes/helpers.php) is the
   opposite mismatch from everything else in this file so far: its icon
   (blog/icon_pagination.svg, checked directly — fill="white") is authored
   light on purpose, since the button's own background is var(--color-black-100)
   — always dark, in every prior mode. But that token DOES flip under wb (by
   design, elsewhere it's exactly the fix we want), so here it flips the one
   background that was never supposed to move, and a white icon on a now-
   near-white button disappears. Plain invert(1) (not brightness(0) invert(1),
   which would force it white — the opposite of what's needed here) turns the
   already-flat-white icon black, matching the button's own new light
   background. One bare `.pag-btn img` selector covers all three callers,
   since the class isn't used for anything else. */
html.a11y-contrast-wb .pag-btn img {
    filter: invert(1);
}

/* Leftover spots in legal-pages.css outside the hub section already fixed
   above: the mobile sidebar's own bottom border (raw #ebedf2, stays light
   against the now-dark sidebar below 992px), the misconduct-report form's
   "reset" link color (raw #06ba52 — barely readable was fine on white, but
   under wb everywhere else this exact accent is muted to grey specifically
   because raw green-on-black falls short of the contrast the muted grey
   reaches, per the wb token table's own comment above), and — found after a
   user report, missed in the earlier sweep because it's nested two levels
   deeper than the sidebar's top-level .icon-wrapper items already fixed — the
   accordion's own sub-items (.children ul li a): raw #221f1f base color
   sitting directly on the page's own background (no box of its own, unlike
   the top-level items), so under wb it went dark-on-now-black, and its
   current/hover state has the identical raw-green-on-black problem as the
   reset-form-btn above. */
html.a11y-contrast-wb .legal-sidebar { border-bottom-color: var(--color-grey-40); }
html.a11y-contrast-wb .legal-page article .form-unacceptable-behavior .reset-form-btn { color: var(--color-green-100); }
html.a11y-contrast-wb .legal-sidebar .nav-list .children ul li a { color: var(--color-black-100); }
html.a11y-contrast-wb .legal-sidebar .nav-list .children ul li a.current,
html.a11y-contrast-wb .legal-sidebar .nav-list .children ul li a:hover { color: var(--color-green-100); }
/* Same data-URI has-child chevron gap as .kb-sidebar's identical pattern above —
   fill='%23221F1F' baked into the background: url("data:image/svg+xml,...")
   value itself, unreachable by a token no matter how tokenized the rest of a
   file is. */
html.a11y-contrast-wb .legal-sidebar .nav-list li.has-child > a:after {
    filter: brightness(0) invert(1);
}

/* /contacts/'s (template_contacts-v4.php) need-support form submit button is a
   plain .btn with no color modifier — green bg / white text in bw, via
   style.css's base .btn rule. Under wb the accent-token flip (--color-green-100
   → #9a9a9a) turns it into a mid-grey button, which sits legibly enough on the
   panel's own now-black background (.contacts-v4-form's --color-white flips to
   black same as everywhere else) but no longer reads as a clear white CTA the
   way the rest of the panel's now-inverted-to-black-and-white treatment implies.
   Pin it to the panel's own already-flipped pair instead of the accent grey —
   var(--color-black)/var(--color-white) are the base tokens' literal invert
   (#ffffff/#000000 under wb), not the hand-tuned accent scale, so this reads as
   a true white button with black text regardless of contrast mode. */
html.a11y-contrast-wb .contacts-v4-form .submit-btn {
    background: var(--color-black);
    border-color: var(--color-black);
    color: var(--color-white);
}
html.a11y-contrast-wb .contacts-v4-form .submit-btn:hover {
    background: var(--color-black-60);
    border-color: var(--color-black-60);
}
html.a11y-contrast-wb .contacts-v4-form .submit-btn:active {
    background: var(--color-black-40);
    border-color: var(--color-black-40);
}
/* </editor-fold> */
