/* ---------------------------------------------------------------------------
 * site.css — first-party styles.
 *
 * public/css/app.min.css is a FROZEN vendor Tailwind build (v4.1.18, 14 Jul) with
 * no source in this repo. Classes that are not already baked into it simply do not
 * exist — `sr-only`, `visually-hidden`, `line-clamp-2` and `aspect-video` are all
 * absent. Anything new belongs here, not in a class you hope Tailwind will emit.
 * ------------------------------------------------------------------------- */

/* --- Accessibility helpers (absent from the frozen build) ---------------- */

/* Visible to screen readers, invisible on screen. */
.visually-hidden {
    position: absolute !important;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

/* Skip link: off-screen until focused, then pinned top-left. */
.skip-link {
    position: absolute;
    top: -100px;
    left: 8px;
    z-index: 10000;
    padding: 12px 20px;
    background: #066ccb;
    color: #fff;
    font-weight: 600;
    border-radius: 0 0 8px 8px;
    text-decoration: none;
    transition: top 0.15s ease-in-out;
}

.skip-link:focus {
    top: 0;
    color: #fff;
}

/* Never remove a focus ring without replacing it. */
:focus-visible {
    outline: 3px solid #066ccb;
    outline-offset: 2px;
}

/* --- Tap targets --------------------------------------------------------- */
/*
 * Pointer targets should be ~44px (WCAG 2.2 SC 2.5.5); 24×24 is the AA floor
 * (SC 2.5.8). Measured with `npm run tap-target-check`, which reports both.
 *
 * Everything here is mobile-only, deliberately. These are phone-sized problems,
 * and confining the fix to the width where it matters keeps the desktop layout
 * pixel-identical — which is the only width `npm run layout-parity` measures.
 *
 * Links inside running prose are NOT inflated: WCAG exempts them precisely
 * because you cannot grow a word mid-sentence without wrecking the paragraph.
 * The check honours that exception too, so what is listed below is the
 * standalone stuff — icon buttons, social links, contact rows, filter controls.
 */
@media (max-width: 991px) {
    .footer-item__list .social-list__link,
    .bottom-footer .footer-links a,
    .breadcrumb__list a,
    .pagination .page-link,
    /* 24×32 — the social icons in the header bar and footer columns. */
    .social-list__item > a,
    .mobile-menu__socials-link,
    /* 28×28 — closes the mobile menu, and easy to miss one-handed. */
    .mobile-menu .close-button,
    /* 20×29 — toggles the category search on /courses. The smallest control on the site. */
    .categories_search_toggle,
    /* 67×24 — back out of the mobile inquiry drawer. */
    .mobile-nav-back-btn {
        min-width: 44px;
        min-height: 44px;
        display: inline-flex;
        align-items: center;
        justify-content: center;
    }

    /* 135×23 — the mail and phone links in the mobile menu. Full-width rows, so
       they only need height; `inline-flex` is what lets min-height apply at all. */
    .mobile-menu__contact-item > a {
        min-height: 44px;
        display: inline-flex;
        align-items: center;
    }

    /* 100×15 — the `tel:` link in the "Call / WhatsApp" card, set in text-xs.
       A phone number is exactly the thing someone taps on a phone. Its siblings
       in the card are spans, so only the anchor is targeted. */
    .three_cards_col > a {
        min-height: 44px;
        display: inline-flex;
        align-items: center;
        justify-content: center;
    }

    /*
     * The /courses filter checkboxes and radios render at 15–16px, which is what
     * a native control is — the browser will not grow it, and forcing a size on
     * one looks wrong on every platform at once.
     *
     * It does not need to. Each input has a real `<label for>`, so the label is
     * part of the target: clicking it toggles the control. Giving the LABEL the
     * height makes the row comfortably hittable while the control keeps its
     * native appearance.
     */
    .form-check .form-check-label,
    .form-check-label.checkbox-style {
        min-height: 44px;
        display: inline-flex;
        align-items: center;
    }
}

/* --- Course card price --------------------------------------------------- */
/* The struck-through original price was #94a3b8 on white = 2.56:1. */
.ec-price-original,
.course-price__original {
    color: #475569;
}

/* --- Courses grid error state -------------------------------------------- */
.course-fetch-error {
    grid-column: 1 / -1;
    padding: 48px 24px;
    text-align: center;
}

.course-fetch-error p {
    margin-bottom: 16px;
    color: #475569;
}

/* --- Mobile bottom nav ---------------------------------------------------- */
/* Moved out of components/mobile-bottom-nav.blade.php: that component renders
 * inside <body>, so its @push('styles') was dropped once the styles stack moved
 * into <head>. */

.mobile-bottom-nav {
    display: none;
    position: fixed;
    bottom: 0;
    left: 0;
    width: 100%;
    z-index: 999;
    box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.1);
    padding-bottom: env(safe-area-inset-bottom);
}

@media (max-width: 991px) {
    .mobile-bottom-nav {
        display: flex;
        justify-content: space-around;
        align-items: center;
    }

    /* Add padding to body so content isn't hidden behind the fixed nav */
    body {
        padding-bottom: 60px !important;
    }
}

.mobile-bottom-nav__item {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    color: rgba(255, 255, 255, 0.7);
    text-decoration: none;
    padding: 10px 0 6px 0;
    flex: 1;
    position: relative;
    transition: color 0.3s ease;
    border: none;
    background: transparent;
}

.mobile-bottom-nav__item.active {
    color: #ffffff;
    font-weight: 600;
}

.mobile-bottom-nav__item.active::after {
    content: '';
    position: absolute;
    bottom: 0;
    left: 50%;
    transform: translateX(-50%);
    width: 32px;
    height: 3px;
    background-color: #ffffff;
    border-radius: 4px 4px 0 0;
}

.mobile-bottom-nav__icon {
    font-size: 22px;
    margin-bottom: 2px;
}

.mobile-bottom-nav__text {
    font-size: 11px;
}

.mobile-bottom-nav__item:hover,
.mobile-bottom-nav__item:focus {
    color: #ffffff;
}

.mobile-bottom-nav__item:hover .mobile-bottom-nav__text {
    text-decoration: none;
}


/* --- Mobile inquiry modal ------------------------------------------------ */
/* Moved out of components/mobileInquiryModal.blade.php. That partial is included
 * from components/mobile-bottom-nav.blade.php, which renders inside <body> — so its
 * @push('styles') fired after the styles stack had already been emitted in <head>
 * and the whole block was silently dropped. */

        /* Scoped styles for the mobile inquiry modal */
        .mobile-nav-inquiry-drawer {
            position: fixed;
            top: 0;
            left: 0;
            width: 100vw;
            height: 100vh;
            height: 100dvh;
            background: #fff;
            z-index: 2000;
            transform: translateX(-100%);
            transition: transform 0.4s cubic-bezier(0.4, 0, 0.2, 1);
            display: flex;
            flex-direction: column;
            overflow: hidden;
        }

        .mobile-nav-inquiry-drawer.active {
            transform: translateX(0);
        }

        .mobile-nav-inquiry-header {
            background: #f8f9fa;
            border-bottom: 1px solid #e5e7eb;
            padding: 16px 20px;
            display: flex;
            align-items: center;
            gap: 16px;
            position: sticky;
            top: 0;
            z-index: 10;
        }

        .mobile-nav-back-btn {
            background: none;
            border: none;
            font-size: 20px;
            display: flex;
            align-items: center;
            color: #374151;
        }

        .mobile-nav-inquiry-body {
            flex: 1;
            overflow-y: auto;
            -webkit-overflow-scrolling: touch;
            /* smooth momentum scroll on iOS */
            overscroll-behavior: contain;
            /* prevent scroll from bleeding to page */
            padding: 20px;
            padding-bottom: 60px;
        }

        .cart-item-card {
            background: #f8f9fa;
            border: 1px solid #e5e7eb;
            border-radius: 8px;
            padding: 12px;
            margin-bottom: 12px;
            display: flex;
            justify-content: space-between;
            align-items: flex-start;
        }

        .cart-item-info {
            flex: 1;
        }

        .cart-item-course {
            font-weight: 700;
            font-size: 14px;
            color: #1f2937;
            margin-bottom: 4px;
        }

        .cart-item-schedule {
            font-size: 13px;
            color: #4b5563;
            display: flex;
            align-items: center;
            gap: 6px;
            margin-bottom: 2px;
        }

        .cart-item-delete {
            background: none;
            border: none;
            color: #ef4444;
            font-size: 18px;
            padding: 4px;
            cursor: pointer;
        }

        .mobile-nav-schedule-drawer {
            position: fixed;
            top: 0;
            right: -130%;
            width: 100vw;
            height: 100vh;
            height: 100dvh;
            background: #fff;
            z-index: 2001;
            display: flex;
            flex-direction: column;
            transition: right 0.4s cubic-bezier(0.4, 0, 0.2, 1);
        }

        .mobile-nav-schedule-drawer.active {
            right: 0;
        }

        .mn-schedule-item-date {
            font-weight: 600;
            margin-bottom: 8px;
            display: flex;
            align-items: center;
            gap: 8px;
            color: #1f2937;
        }

        .mn-schedule-time-grid {
            display: grid;
            grid-template-columns: 1fr;
            gap: 8px;
            margin-bottom: 16px;
        }

        .mn-schedule-time-card {
            display: flex;
            align-items: center;
            gap: 8px;
            padding: 8px 12px;
            background: #fff;
            border: 1px solid #e5e7eb;
            border-radius: 6px;
        }

        .mn-schedule-time-card input[type="checkbox"] {
            accent-color: #3d5ee1;
            width: 16px;
            height: 16px;
        }

        /* ── Course Dropdown (mirrors .ec-dropdown-wrap from coursesGrid.php) ── */
        .mn-course-dropdown-wrap {
            position: relative;
            display: block;
        }

        .mn-course-trigger {
            width: 100%;
            display: flex;
            align-items: center;
            justify-content: space-between;
            gap: 8px;
            padding: 10px 14px;
            background: #fff;
            border: 1px solid #dee2e6;
            border-radius: 8px;
            font-size: 1rem;
            color: #6b7280;
            cursor: pointer;
            transition: border-color 0.2s, box-shadow 0.2s;
            text-align: left;
        }

        .mn-course-trigger:hover {
            border-color: #3d5ee1;
        }

        .mn-course-trigger.selected {
            color: #0f172a;
            font-weight: 600;
            border-color: #3d5ee1;
        }

        .mn-course-trigger .mn-course-chevron {
            flex-shrink: 0;
            font-size: 0.85rem;
            color: #6b7280;
            transition: transform 0.2s ease;
        }

        .mn-course-trigger.open .mn-course-chevron {
            transform: rotate(180deg);
        }

        .mn-course-panel {
            display: none;
            position: fixed;
            min-width: 240px;
            background: #fff;
            border-radius: 10px;
            box-shadow: 0 8px 36px rgba(0, 0, 0, 0.18);
            border: 1px solid #e2e8f0;
            z-index: 3000;
            overflow: hidden;
            animation: mnDropFade 0.18s ease;
        }

        .mn-course-panel.open {
            display: block;
        }

        @keyframes mnDropFade {
            from {
                opacity: 0;
                transform: translateY(-8px);
            }

            to {
                opacity: 1;
                transform: translateY(0);
            }
        }

        .mn-drop-search {
            display: flex;
            align-items: center;
            gap: 8px;
            padding: 10px 14px;
            border-bottom: 1px solid #f1f5f9;
            background: #f8fafc;
            position: sticky;
            top: 0;
            z-index: 2;
        }

        .mn-drop-search i {
            color: #94a3b8;
            font-size: 0.95rem;
            flex-shrink: 0;
        }

        .mn-drop-search input {
            border: none;
            background: transparent;
            outline: none;
            width: 100%;
            font-size: 0.9rem;
            color: #0f172a;
        }

        .mn-drop-search input::placeholder {
            color: #94a3b8;
        }

        .mn-drop-list {
            list-style: none;
            margin: 0;
            padding: 6px 0;
            max-height: 240px;
            overflow-y: auto;
        }

        .mn-drop-list li button {
            width: 100%;
            text-align: left;
            background: transparent;
            border: none;
            padding: 9px 16px;
            font-size: 0.9rem;
            font-weight: 500;
            color: #334155;
            display: flex;
            align-items: center;
            gap: 8px;
            cursor: pointer;
            transition: background 0.15s, color 0.15s;
        }

        .mn-drop-list li button:hover {
            background: #eff6ff;
            color: #066ccb;
        }

        .mn-drop-list li button.active {
            background: #eff6ff;
            color: #066ccb;
            font-weight: 700;
        }

        .mn-drop-no-results {
            padding: 10px 16px;
            color: #94a3b8;
            font-size: 0.85rem;
            display: none;
        }

        /* ── Phone input group: mirrors .country-code-group from course_modal.php ── */
        #mnCountryCodeGroup {
            display: flex;
            align-items: stretch;
            border: 1px solid #eee;
            border-radius: 8px;
            transition: border-color 0.3s ease, box-shadow 0.3s ease;
        }

        #mnCountryCodeGroup .dropdown {
            position: static !important;
        }

        #mnCountryCodeGroup .country-dropdown-btn {
            border: none;
            border-radius: 8px 0 0 8px;
            background: #e9ecef;
        }

        #mnCountryCodeGroup .country-dropdown-btn:focus,
        #mnCountryCodeGroup .country-dropdown-btn:active {
            outline: none;
            box-shadow: none;
        }

        /* Blue focus ring on the group when phone input is focused */
        #mnCountryCodeGroup.focused {
            border-color: #3d5ee1;
            box-shadow: 0 0 0 4px rgba(61, 94, 225, 0.1);
        }

        /* Error state — same as .country-code-group.is-invalid in course_modal.php */
        #mnCountryCodeGroup.mn-phone-invalid {
            border-color: #ea4335 !important;
            box-shadow: 0 0 0 4px rgba(234, 67, 53, 0.15) !important;
        }

        /* Suppress Bootstrap's own is-invalid styles on the raw input — group owns the visual */
        #mnPhone.is-invalid {
            box-shadow: none !important;
            border-color: transparent !important;
        }

        /* ── Premium Toast (mirrors #inquiryToast from course_modal.php) ── */
        #mnInquiryToast {
            position: fixed !important;
            top: 24px !important;
            left: 50% !important;
            z-index: 999999 !important;
            background: #ffffff !important;
            border: 1px solid rgba(0, 0, 0, 0.08) !important;
            border-radius: 12px !important;
            box-shadow: 0 10px 30px rgba(0, 0, 0, 0.12) !important;
            min-width: 320px !important;
            max-width: 380px !important;
            pointer-events: none !important;
            opacity: 0 !important;
            visibility: hidden !important;
            transform: translateY(20px) translateX(-50%) scale(0.95) !important;
            transition: opacity 0.35s cubic-bezier(0.175, 0.885, 0.32, 1.275),
                transform 0.35s cubic-bezier(0.175, 0.885, 0.32, 1.275),
                visibility 0.35s !important;
        }

        #mnInquiryToast.show {
            opacity: 1 !important;
            visibility: visible !important;
            pointer-events: auto !important;
            transform: translateY(0) translateX(-50%) scale(1) !important;
        }

        #mnInquiryToast.bg-success-toast .mn-toast-icon-wrapper {
            background-color: #2ecc71 !important;
            box-shadow: 0 4px 10px rgba(46, 204, 113, 0.3) !important;
        }

        #mnInquiryToast.bg-danger-toast .mn-toast-icon-wrapper {
            background-color: #e74c3c !important;
            box-shadow: 0 4px 10px rgba(231, 76, 60, 0.3) !important;
        }

        .mn-toast-icon-wrapper {
            width: 36px !important;
            height: 36px !important;
            display: inline-flex !important;
            align-items: center !important;
            justify-content: center !important;
            border-radius: 50% !important;
        }

/* --- Nav triggers are <button>, not <a> ---------------------------------- */
/* The mega-menu triggers, the mobile bottom-nav actions and the two country
   pickers used to be `<a href="javascript:void(0)">`: focusable elements a
   screen reader announces as links, which go nowhere. They are now buttons.

   A <button> does not inherit font-family, and picks up the UA's buttonface
   background, a border and centred text — so the classes that styled them as
   anchors are no longer sufficient on their own. `all: unset` is deliberately
   NOT used: it would also drop the cursor and the box model these classes rely
   on. Reset only what the UA adds.

   This lives here rather than in app.min.css, which is a frozen vendor build
   with no source in the repo — see DECISIONS.md 001.

   Scoped to `button`, and deliberately NOT resetting colour or padding.
   Both were mistakes worth spelling out, because the selector list looked
   harmless: it matched the *anchors* too, and it sits later in the file than
   the rules that style them, so `color: inherit` and `padding: inherit` beat
   the design on every element carrying these classes — not just the buttons
   this block was written for.

   The mobile bottom nav is where that showed. `.mobile-bottom-nav__item` sets
   `color: rgba(255,255,255,.7)` and `padding: 10px 0 6px 0`; the reset turned
   those into the page's inherited slate (#576070) on a blue bar, and no
   padding at all. Only the active item stayed white, because `.active` outranks
   a single class.

   Neither declaration is needed: every class here sets its own colour —
   .nav-menu__link #222e48, .nav-submenu__link #066ccb, .mobile-bottom-nav__item
   translucent white — and its own padding. The UA's buttonface background,
   border, font and centred text are the only things a <button> actually adds,
   so those are the only things reset. */
button.nav-menu__link,
button.nav-submenu__link,
button.mobile-bottom-nav__item {
    background: none;
    border: 0;
    font: inherit;
    text-align: inherit;
    cursor: pointer;
}

/* button elements do not fill their parent the way a block <a> did. */
button.nav-menu__link,
button.nav-submenu__link {
    width: 100%;
}

/* Bootstrap styles .dropdown-item for <a>; as a <button> it needs the width and
   alignment back, or each country row shrink-wraps and centres. */
button.dropdown-item {
    width: 100%;
    text-align: left;
}

/* The bottom-nav items are flex columns in the original anchor markup. */
button.mobile-bottom-nav__item {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
}

/* The caret the a11y change silently took off every submenu trigger.
 *
 * app.min.css draws it with `.has-submenu > a::before` — a Phosphor glyph
 * ("\e136" is ph-caret-down, still the same codepoint in the self-hosted
 * @phosphor-icons/web the bundle split moved us to), absolutely positioned at
 * the trigger's inline end and rotated 180° on hover and while active.
 *
 * The selector says `a`. When the triggers became <button> — the same change
 * this whole block exists for — those three rules stopped matching and the
 * arrow disappeared from "Courses" in the header and from every nested
 * category row. Nothing failed; the markup was valid and the block above made
 * the buttons *look* like the anchors they replaced, which is exactly why it
 * went unnoticed: the one thing it did not carry over was a pseudo-element.
 *
 * Mirrored rather than reworked, so the arrow matches the rest of the vendor
 * design. Two deliberate departures: `translate` is written as `0 -50%` rather
 * than reusing `--tw-translate-x`, which is not set in this context and would
 * make the shorthand invalid; and `font-weight` is the literal 900 rather than
 * `var(--font-weight-black)`, so this rule does not depend on a vendor custom
 * property staying defined. app.min.css is a frozen vendor build and is never
 * edited — DECISIONS.md 001.
 */
.has-submenu > button::before {
    position: absolute;
    inset-inline-end: 0;
    inset-block-start: 50%;
    translate: 0 -50%;
    font-family: "Phosphor";
    font-weight: 900;
    color: #222e48;
    content: "\e136";
    transition: 0.2s linear;
}

.has-submenu:hover > button::before {
    rotate: 180deg;
    color: #066ccb;
}

.has-submenu.active > button,
.has-submenu.active > button::before {
    color: #066ccb;
}

.has-submenu.active > button::before {
    rotate: 180deg;
}

/* --- Partner logo strip, replacing slick-carousel (Phase 6.3) ------------
 *
 * `.brand-slider` was the site's ONLY slick carousel — 10 KB gzipped of
 * jQuery plugin, and jQuery itself behind it, for one row of partner logos.
 * It is now a CSS marquee; `theme.js` wraps the items in a track and clones
 * the set once so the loop is seamless.
 *
 * The frozen app.min.css still carries slick's own rules, but they key off
 * `.slick-*` classes that nothing adds any more, so they are simply inert.
 *
 * Height is load-bearing: the strip measured 38px with slick and must stay
 * 38px, or `npm run layout-parity` fails the whole page. Items keep their
 * natural width and never wrap.
 */
.brand-slider {
    display: flex;
    overflow: hidden;
}

.brand-slider__track {
    /* `flex: 0 0 auto` is load-bearing with `max-content`: as a flex item the track defaults to
       `flex-shrink: 1` and is squeezed back to the container's width, so `translateX(-50%)` would
       move it half a *container* instead of half its contents and the loop would visibly jump.
       Measured while getting this wrong: width 1296px against a 3238px scrollWidth. */
    flex: 0 0 auto;
    width: max-content;
    white-space: nowrap;
    animation: brand-marquee 46s linear infinite;
}

.brand-slider__track > * {
    display: inline-block;
}

/* Pause on hover, matching slick's `pauseOnHover: true`. */
.brand-slider:hover .brand-slider__track {
    animation-play-state: paused;
}

@keyframes brand-marquee {
    from {
        transform: translateX(0);
    }
    to {
        transform: translateX(-50%);
    }
}

/* An endlessly moving strip is exactly what this media query is for. The logos
   stay readable and in place; nothing is lost but the motion. */
@media (prefers-reduced-motion: reduce) {
    .brand-slider__track {
        animation: none;
    }
}

/* --- Preloader failsafe (Phase 6.5) --------------------------------------
 *
 * `.preloader` is an opaque white overlay — position: fixed, inset: 0,
 * z-index: 9999 — and its ONLY removal path is a `window.load` handler in the
 * site bundle. If that bundle 404s, is blocked by a network or an extension, or
 * `load` never fires because one resource hangs, the overlay covers the entire
 * site permanently: every page, no content, no way past it.
 *
 * That risk grew in Phase 6.2. The bundle is now a hashed Vite build under
 * public/build, which is gitignored and produced by `npm run build` — one
 * skipped deploy step and every visitor gets a blank white screen.
 *
 * So the removal cannot depend on JavaScript. This hides the overlay on a pure
 * CSS timer, and `forwards` keeps it hidden. The normal path is unaffected:
 * the bundle hides it on load, long before this fires.
 *
 * 10s is deliberately generous — longer than any legitimate load, so a slow
 * connection never has the page snatched out from under it, but bounded, so a
 * broken one recovers. `visibility: hidden` is what does the real work; it
 * stops the overlay swallowing clicks as well as hiding it.
 *
 * Verified by `npm run preloader-check`, which loads the site with JavaScript
 * disabled — the closest faithful simulation of "the bundle never ran".
 */
.preloader {
    animation: preloader-failsafe 400ms ease 10s forwards;
}

@keyframes preloader-failsafe {
    to {
        opacity: 0;
        visibility: hidden;
    }
}

/* Reduced motion must not disable the failsafe — that would leave exactly the
   users who opted out staring at a white screen. Keep the timer, drop the fade. */
@media (prefers-reduced-motion: reduce) {
    .preloader {
        animation-duration: 1ms;
    }
}

/* --- WhatsApp call-to-action -------------------------------------------- */
/* Used by the "Want to talk in-person?" card on the course detail page.
 *
 * It was `btn-outline-main`, so the border, the label and the WhatsApp mark were
 * all #066ccb — the WhatsApp glyph in the site's blue reads as a generic button
 * rather than as WhatsApp, which is the one thing that makes this CTA obvious.
 *
 * #25D366 is WhatsApp's own green, on both the glyph and the label, at the
 * owner's request.
 *
 * ⚠️ CONTRAST: #25D366 on #ffffff is 1.98:1. WCAG 2.2 SC 1.4.3 wants 4.5:1 for
 * normal text and 3:1 for large; this clears neither, and it is the label, not
 * decoration. The button is still reachable and its accessible name is intact,
 * so nothing is unusable — but it is the least legible text on the page, and it
 * is the only deliberate contrast failure in this stylesheet. #128C7E, also a
 * WhatsApp brand green, measures 4.14:1 and reads as the same button; see
 * PROGRESS 6.13 if this is revisited.
 *
 * Not applied to the WhatsApp icon in the share row further down that page —
 * those sit in a set with LinkedIn, Facebook and email and are deliberately
 * uniform in brand blue. */
/* !important throughout, matching how the vendor build writes its own button
 * variants: `.btn` in app.min.css ends with `color: #ffffff !important`, so
 * `.btn-outline-main`, `.btn-white` and the rest all have to shout back. Without
 * it the label here rendered white on a white background — invisible, and the
 * button measured as `rgb(255,255,255)` on `rgb(255,255,255)`. */
.btn-whatsapp {
    background-color: #fff !important;
    border: 1px solid #dbe3ef !important;
    color: #25d366 !important;
}

.btn-whatsapp .ph-whatsapp-logo {
    color: #25d366;
}

.btn-whatsapp:hover,
.btn-whatsapp:focus-visible {
    background-color: #f2fdf6 !important;
    border-color: #25d366 !important;
    color: #25d366 !important;
}
