/* ----------------------------------------------------
   ROOT THEMES
---------------------------------------------------- */
:root {
    --primary: #CC3399;
    --primary-rgb: 204, 51, 153; /* Added this */
    /* Retargets Bootstrap 5.3's OWN "primary" variables to this site's actual brand pink, since
       bootstrap.min.css is used prebuilt (not recompiled from Sass with a custom $primary) - found
       while fixing the testimonial card's border-primary accent, which was rendering Bootstrap's
       stock blue (#0d6efd) instead of pink. Bootstrap's utilities (.text-primary, .border-primary,
       .bg-primary) and .btn-outline-primary all reference --bs-primary/--bs-primary-rgb via var(),
       so this one change corrects every bare use of them site-wide, not just this one card. Doesn't
       touch .btn-primary or the .bg-primary-subtle custom class below - those were already
       separately, correctly overridden to this same pink beforehand. (".text-primary-dark", used
       throughout this codebase, looks like a sibling custom class but isn't actually one - no such
       rule exists; every "pink dark heading" it appears to produce actually comes from the plain
       `h1, h2, h3, h4 { color: var(--primary-dark); }` element rule further down matching the
       heading tag itself. That's harmless on a heading, but it doesn't help a plain <a> - found
       when a new Services.razor card-title link rendered in Bootstrap's default link blue despite
       carrying "text-primary-dark", which lower down fixed by retargeting --bs-link-color(-rgb)/
       --bs-link-hover-color(-rgb) the same way.) */
    --bs-primary: #CC3399;
    --bs-primary-rgb: 204, 51, 153;
    /* a's own color comes from --bs-link-color-rgb (not -color) since Bootstrap 5.3 composes it
       with an opacity variable; :hover reads the -hover- pair. See the long comment above. */
    --bs-link-color: #A52A7A;
    --bs-link-color-rgb: 165, 42, 122;
    --bs-link-hover-color: #CC3399;
    --bs-link-hover-color-rgb: 204, 51, 153;
    --primary-light: #c7b7ff;
    --primary-dark: #A52A7A;
    --bg: #f9f7ff;
    --text: #333;
    --card-bg: #ffffff;
    --glow: 0 0 20px rgba(var(--primary-rgb), 0.6);
    --radius: 12px;
    --gradient: linear-gradient(135deg, #ffdd99, #cc3399);
    --color-light: #fefefe;
    --color-dark: #f0f4f8;
    --gradient-energy: linear-gradient(135deg, #f3f8ff 0%, #e0f7ff 100%);
}

/* Dark Theme */
[data-theme="dark"] {
    --bg: #1c1529;
    --text: #f0eaff;
    --card-bg: #291e3a;
    --glow: 0 0 20px rgba(200, 168, 255, 0.7);
    --gradient: linear-gradient(135deg, #3d2a63, #5f3ea8, #8e54c9);
}

/* ----------------------------------------------------
   FONTS
---------------------------------------------------- */
/* Self-hosted (wwwroot/lib/fonts, not fonts.googleapis.com/fonts.gstatic.com) for the same reason
   Bootstrap Icons and the Bootstrap JS bundle are self-hosted rather than CDN-loaded (see
   App.razor's remarks on that): Google's own domains are commonly blocked or throttled in
   mainland China, which would silently drop this site's chosen brand typeface back to the system
   default specifically for its zh-Hans audience - the one case where that'd be worst to lose.
   Both fonts are variable fonts (a single file covers a weight range, not one file per weight),
   hence `font-weight: 400 500`/`600 700` rather than a fixed number - matches how Google's own
   CSS serves them. Two @font-face blocks per family (not one) because the latin and latin-ext
   Unicode ranges are two separate files - browsers fetch whichever one a given piece of text
   actually needs. CJK text (zh-Hans) isn't covered by either range and isn't meant to be: it
   falls through to each rule's own `sans-serif`/`serif` fallback below, which resolves to the
   browser's own system CJK font - these are Latin-script-only display faces for en/ms headings
   and body text. */
@font-face {
    font-family: 'Nunito';
    font-style: normal;
    font-weight: 400 500;
    font-display: swap;
    src: url('/lib/fonts/nunito-latin.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
    font-family: 'Nunito';
    font-style: normal;
    font-weight: 400 500;
    font-display: swap;
    src: url('/lib/fonts/nunito-latin-ext.woff2') format('woff2');
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
    font-family: 'Quicksand';
    font-style: normal;
    font-weight: 600 700;
    font-display: swap;
    src: url('/lib/fonts/quicksand-latin.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
    font-family: 'Quicksand';
    font-style: normal;
    font-weight: 600 700;
    font-display: swap;
    src: url('/lib/fonts/quicksand-latin-ext.woff2') format('woff2');
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* ----------------------------------------------------
   GLOBAL
---------------------------------------------------- */
html {
    scroll-behavior: smooth;
/*    scroll-padding-top: 100px;*/
}

body {
    background: var(--bg);
    color: var(--text);
    font-family: 'Nunito', sans-serif;
    transition: background .4s, color .4s;
}

h1, h2, h3, h4 {
    font-family: 'Quicksand', sans-serif;
}

/*body[data-theme="light"] {
        --bg: var(--color-light);
        --gradient: var(--gradient-energy);
        color: #333;
    }

    body[data-theme="dark"] {
        --bg: #111;
        --gradient: linear-gradient(135deg, #222 0%, #333 100%);
        color: #eee;
    }*/

h1, h2, h3, h4 {
    font-weight: 600;
    color: var(--primary-dark);
}

.btn-primary {
    /* Bootstrap's generic .btn:hover/:active rules (background-color/border-color: var(--bs-btn-
       hover-bg) etc.) have higher specificity than this single .btn-primary class - two
       selectors (.btn + :hover) beat one - so they win over the plain `background: var(--primary)`
       below on hover/active regardless of source order, unless these per-state custom properties
       (which .btn:hover/:active actually read from) are set here too. Without this, Bootstrap's
       own hardcoded --bs-btn-hover-bg/--bs-btn-active-bg (#0b5ed7/#0a58ca, its default blue) shows
       through on hover/active even though the resting background above is correctly pink. */
    --bs-btn-hover-bg: var(--primary-dark);
    --bs-btn-hover-border-color: var(--primary-dark);
    --bs-btn-active-bg: var(--primary-dark);
    --bs-btn-active-border-color: var(--primary-dark);
    --bs-btn-disabled-bg: var(--primary);
    --bs-btn-disabled-border-color: var(--primary);
    background: var(--primary);
    border: none;
    border-radius: var(--radius);
    padding: 12px 24px;
    box-shadow: var(--glow);
    transition: transform .2s, box-shadow .3s;
}

    .btn-primary:hover {
        transform: translateY(-3px);
        /* Was rgba(142, 142, 246, 0.8) - a blue-purple glow left over from some earlier color
           scheme, clashing with this site's pink theme. --primary-rgb matches --glow's own resting
           box-shadow above, just brighter/wider for the hover state. */
        box-shadow: 0 0 25px rgba(var(--primary-rgb), 0.8);
    }

/* Bootstrap's compiled CSS bakes its button colors into hardcoded hex values on each
   .btn-outline-primary's own --bs-btn-* custom properties at build time (unlike .text-primary/
   .border-primary/.bg-primary, which reference the root --bs-primary variable directly) - so
   retargeting --bs-primary above doesn't reach outline buttons on its own; they need the same
   explicit override .btn-primary already gets below. */
.btn-outline-primary {
    padding-bottom: 10px;
    padding-top: 10px;
    --bs-btn-color: var(--primary);
    --bs-btn-border-color: var(--primary);
    --bs-btn-hover-color: #fff;
    --bs-btn-hover-bg: var(--primary);
    --bs-btn-hover-border-color: var(--primary);
    --bs-btn-active-color: #fff;
    --bs-btn-active-bg: var(--primary);
    --bs-btn-active-border-color: var(--primary);
    --bs-btn-disabled-color: var(--primary);
    --bs-btn-disabled-border-color: var(--primary);
}

/* Same class of bug as .btn-outline-primary above: Bootstrap's compiled CSS bakes its form
   control focus/checked colors into hardcoded hex (#86b7fe/#0d6efd, its default blue) rather than
   deriving them from --bs-primary/--bs-primary-rgb, so every InputText/InputSelect/InputDate/
   checkbox site-wide (Booking.razor's form is the highest-traffic example) shows a blue focus
   ring and blue checkboxes despite the pink theme everywhere else. */
.form-control:focus,
.form-select:focus {
    border-color: var(--primary);
    box-shadow: 0 0 0 0.25rem rgba(var(--primary-rgb), 0.25);
}

/* NOT reachable, tested directly: an open native <select>'s own popup list (the browser's
   dropdown showing all options) highlights the currently-selected row using the OS's system
   highlight color - confirmed empirically that neither `option:checked { background-color }` nor
   any other CSS reaches it here (this is the same in effectively every browser engine; it's
   drawn as OS chrome, outside the page's own rendering). Same story for <input type="date">'s
   actively-edited segment (e.g. the "09" in "09/28/2026" while typing) and its native calendar
   popup - `accent-color` and `::-webkit-datetime-edit-fields-wrapper` overrides were both tried
   and neither changed anything. The only way to fully theme those specific interactions is to
   replace the native <select>/<input type="date"> with a custom-built JS component - a real
   redesign, not a CSS fix, and one that trades away the native mobile date-wheel/OS picker UX. */

.form-check-input:checked {
    background-color: var(--primary);
    border-color: var(--primary);
}

.form-check-input:focus {
    border-color: var(--primary);
    box-shadow: 0 0 0 0.25rem rgba(var(--primary-rgb), 0.25);
}

.section {
    padding: 80px 0;
    transition: all 1s ease;
}

/* 80px was tuned for desktop; stacked with a preceding element's own bottom margin (e.g. the
   Home hero's mb-5), it reads as a disproportionately large empty band on a narrow phone screen
   where vertical space is scarce. */
@media (max-width: 768px) {
    .section {
        padding: 40px 0;
    }
}

.section-light {
    background: var(--bg);
}

.section-dark {
    background: var(--color-dark);
}

.section-gradient {
    background: var(--gradient);
    color: #fff;
}

    .section-gradient .card-energy {
        background-color: white;
        color: #333; /* Dark text for contrast */
    }

/* ----------------------------------------------------
   BACKGROUNDS
---------------------------------------------------- */
.energy-mesh-bg {
    background-color: #ffffff;
    /* A soft blend of rose, lavender, and pale blue */
    background-image: radial-gradient(at 80% 0%, hsla(289, 100%, 96%, 1) 0px, transparent 50%), radial-gradient(at 0% 20%, hsla(255, 100%, 94%, 1) 0px, transparent 50%), radial-gradient(at 80% 50%, hsla(340, 100%, 96%, 1) 0px, transparent 50%), radial-gradient(at 0% 100%, hsla(22, 100%, 96%, 1) 0px, transparent 50%);
    background-attachment: fixed; /* Keeps the background still while you scroll */
    background-size: cover;
}

/* Ensure text remains readable on this new background */
.section-transparent {
    background: rgba(255, 255, 255, 0.6);
    backdrop-filter: blur(10px); /* Frosted glass effect */
    border-radius: 20px;
    border: 1px solid rgba(255, 255, 255, 0.5);
}

/* Custom Brand Backgrounds */
.bg-primary-light {
    background-color: var(--primary-light) !important;
}

/* Subtle Backgrounds for Avatars & Badges */
.bg-primary-subtle {
    background-color: rgba(var(--primary-rgb), 0.15) !important;
}

.bg-info-subtle {
    background-color: #e0f7ff !important;
}

.bg-success-subtle {
    background-color: #e6fffa !important;
}

.bg-warning-subtle {
    background-color: #fff9db !important;
}

/* Ensure text inside subtle backgrounds remains readable */
.text-info {
    color: #0891b2 !important;
}

.text-success {
    color: #059669 !important;
}

.text-warning {
    color: #d97706 !important;
}

/* ----------------------------------------------------
   HOVER EFFECTS
---------------------------------------------------- */
/* Ensures smooth transition for the hover effect */
.group-hover-effect {
    transition: transform 0.3s ease, box-shadow 0.3s ease;
    cursor: pointer; /* Visual cue that the whole box is clickable */
}

    /* On hover, lift the card and increase the glow */
    .group-hover-effect:hover {
        transform: translateY(-5px);
        box-shadow: 0 10px 25px rgba(204, 51, 153, 0.4); /* Stronger magenta glow */
        border-color: var(--primary);
    }

        /* Optional: Make the button look active when hovering the card */
        .group-hover-effect:hover .btn-outline-primary {
            background-color: var(--primary);
            color: white;
            box-shadow: 0 0 10px var(--primary);
        }

/* ----------------------------------------------------
   ANIMATIONS
---------------------------------------------------- */
/* Fade/slide in on paint. A previous attempt made this genuinely scroll-gated (opacity:0 until
   scroll-effects.js added .visible), which fixed the "outrun the animation, see a blank gap"
   race below - but on an @rendermode InteractiveServer page (Booking, the recommendation quiz),
   the static-prerendered DOM gets replaced once the SignalR circuit connects, and that swap can
   happen in a way that leaves the element stuck at its pre-.visible style permanently (verified:
   .visible was present in classList, yet opacity/transform stayed at their pre-reveal values
   indefinitely - not merely a timing race, content genuinely never recovered). Given that failure
   mode - permanently invisible content on the site's own booking form - is worse than the mobile
   gap it was meant to fix, and the gap itself turned out to be caused by .section's fixed 80px
   padding (see the @media rule on that class below), not by this animation, this stays back on
   the original unconditional animation: on-paint and independent of any JS/circuit timing. */
.fade-in {
    opacity: 0;
    transform: translateY(30px);
    animation: fadeInUp 1s forwards;
}

    .fade-in.visible {
        opacity: 1;
        transform: translateY(0);
    }

@keyframes fadeInUp {
    to {
        opacity: 1;
        transform: translateY(0);
    }
}

@keyframes fadeIn {
    to {
        opacity: 1;
    }
}

.slide-up {
    opacity: 0;
    transform: translateY(40px);
    animation: slideUp 1s forwards;
}

@keyframes slideUp {
    to {
        opacity: 1;
        transform: translateY(0);
    }
}

/* Same leftover blue-purple glow bug as .btn-primary:hover above, and more widespread - used
   alongside .btn-primary on ~24 buttons site-wide (Home, Services, Products, Booking, Contact,
   the recommendation quiz). Also matters for .btn-primary itself: this rule is defined LATER in
   this file than .btn-primary:hover's own box-shadow fix, so on any element carrying both classes
   (the common case - e.g. "btn btn-primary glow-hover"), this one wins the box-shadow property at
   equal specificity, silently undoing that fix wherever the two are combined. */
.glow-hover:hover {
    box-shadow: 0 0 35px rgba(var(--primary-rgb), 0.8);
}

/* ----------------------------------------------------
   CARDS
---------------------------------------------------- */
.card-energy {
    background: var(--card-bg);
    border-radius: var(--radius);
    padding: 20px;
    box-shadow: var(--glow);
    transition: transform .2s;
}

    .card-energy:hover {
        transform: translateY(-6px);
    }

    .card-energy img {
        border-radius: var(--radius);
        box-shadow: var(--glow);
    }

/* ----------------------------------------------------
   TESTIMONIALS (For Pages.zip/Testimonials.razor)
---------------------------------------------------- */
.card-testimonial {
    background: var(--card-bg);
    border-radius: var(--radius);
    padding: 30px;
    box-shadow: var(--glow);
    position: relative;
    border-left: 5px solid var(--primary);
}

    .card-testimonial .quote-icon {
        font-size: 2.5rem;
        color: var(--primary);
        margin-bottom: 15px;
    }

    .card-testimonial .quote-text {
        font-style: italic;
        font-size: 1.05rem;
        margin-bottom: 15px;
    }

    .card-testimonial .client-info strong {
        color: var(--primary-dark);
        display: block;
        margin-top: 5px;
    }

/* FOOTER */
.footer {
    padding: 25px;
    text-align: center;
    background: #1e1e2f;
    color: #f0f0f0;
}

    .footer a {
        color: #ffdd99; /* Soft accent for links */
        text-decoration: none;
    }

        .footer a:hover {
            text-decoration: underline;
        }

/* a.footer-link (element + class), not just .footer-link - .footer a above is ALSO one class
   plus the element selector (same specificity), and it was defined first: without matching that
   specificity here, .footer a's text-decoration: none silently won regardless of source order,
   and this whole rule's underline never actually rendered. */
a.footer-link {
    color: rgba(255,255,255,0.7);
    /* Was text-decoration: none, underlined only on :hover - indistinguishable at rest from the
       plain (non-link) text around it in this column (headings, copyright, address), and hover
       doesn't exist on a touchscreen at all. A permanent, subtler underline (dotted, low-opacity)
       keeps the resting state calm while still reading as clickable; :hover below still switches
       to a solid one for the usual stronger feedback. */
    text-decoration: underline;
    text-decoration-style: dotted;
    text-decoration-color: rgba(255,255,255,0.35);
    font-size: 0.9rem;
    transition: color 0.3s ease;
    margin-bottom: 8px;
    display: inline-block;
}

    a.footer-link:hover {
        color: var(--primary);
        text-decoration: underline;
        text-decoration-style: solid;
        text-decoration-color: currentColor;
    }

footer {
    padding: 40px 0;
}

    footer .app-footer-dark {
        background: linear-gradient(135deg, #1e1e2f, #2a2a3f);
        color: #f0f0f0; /* Light gray text */
    }

.disclaimer-box {
    border-top: 1px solid #333;
    padding-top: 0.5rem;
}

/* Live Status Pulse Dot */
.status-pulse {
    width: 8px;
    height: 8px;
    background-color: #22c55e;
    border-radius: 50%;
    display: inline-block;
    box-shadow: 0 0 0 0 rgba(34, 197, 94, 0.7);
    animation: status-ring 1.5s infinite;
}

@keyframes status-ring {
    0% {
        transform: scale(0.95);
        box-shadow: 0 0 0 0 rgba(34, 197, 94, 0.7);
    }

    70% {
        transform: scale(1);
        box-shadow: 0 0 0 6px rgba(34, 197, 94, 0);
    }

    100% {
        transform: scale(0.95);
        box-shadow: 0 0 0 0 rgba(34, 197, 94, 0);
    }
}

/* Contact Icon Buttons */
.contact-icon-btn {
    width: 45px;
    height: 45px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    color: white;
    font-size: 1.25rem;
    transition: all 0.3s ease;
    text-decoration: none;
}

    .contact-icon-btn:hover {
        transform: translateY(-3px);
        box-shadow: 0 5px 15px rgba(0,0,0,0.1);
        color: white;
        filter: brightness(1.1);
    }

.email {
    background-color: var(--primary);
}

.facebook {
    background-color: #1877F2;
}

.instagram {
    background: linear-gradient( 45deg, #feda75, /* yellow */
    #fa7e1e, /* orange */
    #d62976, /* pink */
    #962fbf, /* purple */
    #4f5bd5 /* blue */
    );
}

.telegram {
    background-color: #0088cc;
}

.whatsapp {
    background-color: #25D366;
}

/* Brand-accurate icon GLYPH colors (as opposed to the filled circle badges above) - for contexts
   like Contact.razor's icon list, which previously used generic Bootstrap semantic classes
   (.text-primary/.text-danger/.text-info) as a rough color approximation. That was already
   inexact (Bootstrap's info cyan isn't quite Telegram's blue), and became flatly wrong for
   Facebook once --bs-primary was retargeted to this site's own pink brand color elsewhere in
   this file - the Facebook icon started rendering pink instead of Facebook's actual blue. These
   reuse the exact same hex values as the filled badges above, so both representations of each
   brand stay in sync. */
.text-facebook {
    color: #1877F2 !important;
}

.text-telegram {
    color: #0088cc !important;
}

.text-whatsapp {
    color: #25D366 !important;
}

/* Instagram has no single brand color (its real mark is the gradient above) - clipping that same
   gradient to the icon glyph's text shape reproduces it accurately, rather than picking one flat
   color that's only ever an approximation. */
.text-instagram {
    background: linear-gradient(45deg, #feda75, #fa7e1e, #d62976, #962fbf, #4f5bd5);
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
}

/* Contact.razor's social buttons (.btn.btn-outline-primary + this class) carry real, externally-
   branded icon colors (Facebook blue, Instagram's gradient, Telegram blue) - .btn-outline-primary's
   normal hover state is a solid, saturated pink fill, which makes some of those hard to see
   against it (Instagram's own pink gradient segment in particular nearly disappears into an
   identically-hued background). A light pink tint keeps the hover feedback clearly on-brand while
   keeping every icon's real color legible against it. Overrides via the same --bs-btn-hover-*
   custom properties .btn-outline-primary itself sets (see that rule's own comment) rather than
   raw properties + !important - same specificity, later in this file, so it wins on source order
   alone, no !important tug-of-war needed. Scoped to this one class rather than changed on
   .btn-outline-primary itself, since every other outline-primary button on the site doesn't have
   this problem and its current solid-pink hover is fine for them. */
.btn-outline-primary.social-link-btn {
    --bs-btn-hover-bg: rgba(var(--primary-rgb), 0.12);
    --bs-btn-hover-color: var(--primary-dark);
    --bs-btn-hover-border-color: var(--primary);
}

.footer-links li a:hover {
    color: var(--primary) !important;
    padding-left: 5px;
    transition: all 0.2s ease;
}

/* ----------------------------------------------------
   GRID
---------------------------------------------------- */
.grid-3 {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
    gap: 2rem;
}

/* ----------------------------------------------------
   Testimonial
---------------------------------------------------- */
.card-testimonial {
    background: #ffffff;
    transition: transform 0.3s ease, box-shadow 0.3s ease;
    /* No border here (previously a `border: ... !important` shorthand) - every caller already
       carries Bootstrap's own border-0 + border-top border-4 border-primary utility classes to
       get a 4px primary-colored top accent, but this rule's !important shorthand set all four
       sides and silently beat those utilities, leaving every testimonial card with a flat, plain
       1px grey border instead of the intended accent. */
}

    .card-testimonial:hover {
        transform: translateY(-5px);
        box-shadow: 0 1rem 3rem rgba(0,0,0,0.1) !important;
    }

.italic {
    font-style: italic;
}

/* Avatar Base Style */
.avatar-circle, .avatar-circle-sm {
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    font-weight: bold;
    border-radius: 50%;
}

/* Pulse Animation for Video Play Button */
.pulse-button {
    animation: pulse-ring 2s cubic-bezier(0.455, 0.03, 0.515, 0.955) infinite;
    background-color: white;
    transition: transform 0.2s ease;
}

    .pulse-button:hover {
        transform: scale(1.1);
        background-color: var(--primary-light);
    }

@keyframes pulse-ring {
    0% {
        box-shadow: 0 0 0 0 rgba(var(--primary-rgb), 0.7);
    }

    70% {
        box-shadow: 0 0 0 20px rgba(var(--primary-rgb), 0);
    }

    100% {
        box-shadow: 0 0 0 0 rgba(var(--primary-rgb), 0);
    }
}

/* Responsive Video Container */
.ratio {
    position: relative;
    width: 100%;
}

    .ratio::before {
        display: block;
        padding-top: 56.25%; /* 16:9 Aspect Ratio */
        content: "";
    }

    .ratio > * {
        position: absolute;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
    }

/* Ensure the card keeps a good height on mobile */
@media (max-width: 768px) {
    .col-md-6.bg-dark {
        min-height: 250px !important;
    }
}

/* GDPR Compliance */
.cookie-banner {
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    background: rgba(255, 255, 255, 0.98);
    backdrop-filter: blur(8px);
    border-top: 1px solid var(--primary-light);
    z-index: 10000; /* Higher than footer and nav */
    padding: 8px 0;
    box-shadow: 0 -5px 20px rgba(0,0,0,0.05);
}

/* --cookie-banner-height is set by App.razor's updateCookieBannerHeightVar() from the banner's
   actual offsetHeight the moment it's shown - it wraps to a much taller stacked layout below
   Bootstrap's md breakpoint, and text length differs per language, so a single guessed constant
   here couldn't track either. Falls back to 60px (this banner's typical single-line desktop
   height) for the brief window before JS runs. This is the page-level fallback for pages with no
   sticky booking bar (/booking, the only one where MainLayout doesn't render it) - everywhere
   else, body.has-cookie-banner .has-sticky-booking-bar below (Footer's own dark section) already
   reserves enough space to clear the combined cookie-banner+sticky-bar stack on its own, so this
   rule backs off entirely there instead of adding a second, redundant reservation on top of it -
   the two stacking together (one on <body>, one inside it) is what made the gap at the bottom of
   the page far bigger than intended. */
body.has-cookie-banner {
    padding-bottom: calc(var(--cookie-banner-height, 60px) + 10px);
}

body.has-cookie-banner:has(.has-sticky-booking-bar) {
    padding-bottom: 0;
}

.cookie-banner.d-none {
    display: none !important;
}

/* ----------------------------------------------------
   FEATURED PRODUCT STYLES
---------------------------------------------------- */
.card-featured {
    border: 2px solid var(--primary-light) !important;
    box-shadow: var(--glow) !important;
    transform: scale(1.02);
}

.featured-badge {
    position: absolute;
    top: 15px;
    right: 15px;
    background: var(--gradient);
    color: white;
    padding: 5px 15px;
    border-radius: 50px;
    font-size: 0.8rem;
    font-weight: bold;
    z-index: 5;
    box-shadow: 0 4px 10px rgba(204, 51, 153, 0.3);
}

.featured-reason {
    background-color: var(--bg);
    border-left: 4px solid var(--primary);
    padding: 10px 15px;
    border-radius: 0 8px 8px 0;
    margin: 1rem 0;
    font-size: 0.9rem;
}

.card-content-body ul {
    list-style: none;
    padding-left: 0;
}

.card-content-body li::before {
    content: "�";
    color: var(--primary);
    font-weight: bold;
    display: inline-block;
    width: 1em;
    margin-left: -1em;
}

.category-block {
    scroll-margin-top: 100px; /* Prevents the header from covering the title when jumping to a category */
}

.product-feature-list {
    list-style: none;
    padding-left: 0;
}

    .product-feature-list li {
        position: relative;
        padding-left: 1.5rem; /* Space for the icon */
        margin-bottom: 0.5rem;
    }

        .product-feature-list li::before {
            content: "";
            position: absolute;
            left: 0;
            top: 3px; /* Centers with first line of text */
            width: 16px;
            height: 16px;
            background-color: var(--primary);
            /* Using a Bootstrap Check Circle as a mask */
            -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='currentColor' class='bi bi-check-circle-fill' viewBox='0 0 16 16'%3E%3Cpath d='M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0m-3.97-3.03a.75.75 0 0 0-1.08.022L7.477 9.417 5.384 7.323a.75.75 0 0 0-1.06 1.06L6.97 11.03a.75.75 0 0 0 1.079-.02l3.992-4.99a.75.75 0 0 0-.01-1.05z'/%3E%3C/svg%3E");
            mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='currentColor' class='bi bi-check-circle-fill' viewBox='0 0 16 16'%3E%3Cpath d='M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0m-3.97-3.03a.75.75 0 0 0-1.08.022L7.477 9.417 5.384 7.323a.75.75 0 0 0-1.06 1.06L6.97 11.03a.75.75 0 0 0 1.079-.02l3.992-4.99a.75.75 0 0 0-.01-1.05z'/%3E%3C/svg%3E");
            -webkit-mask-repeat: no-repeat;
            mask-repeat: no-repeat;
            -webkit-mask-size: contain;
            mask-size: contain;
        }

/* ----------------------------------------------------
   Products Overview
---------------------------------------------------- */

/* Healy Comparison Table Styles */
/* Ensure the table scrolls smoothly on mobile */
.table-responsive {
    scrollbar-width: thin;
    scrollbar-color: var(--primary-light) transparent;
}

/* Same class of bug as .btn-outline-primary/.form-select's chevron elsewhere in this file:
   Bootstrap's .table-hover row highlight reads --bs-table-hover-bg, which derives from
   --bs-emphasis-color-rgb (a neutral grey/black), not --bs-primary-rgb - so every .table-hover
   sitewide (HealyComparisonTable.razor, Services.razor, ProductRecommendation.razor) highlighted
   rows in grey regardless of the pink theme everywhere else. */
.table-hover > tbody > tr:hover > * {
    --bs-table-hover-bg: rgba(var(--primary-rgb), 0.12);
}

/* Custom shadow for the PDF section */
.btn-primary.glow-hover:hover {
    box-shadow: var(--glow);
    transform: translateY(-2px);
    transition: all 0.3s ease;
}

/* Make Obsidian Edition stand out slightly */
.product-col:last-child {
    background-color: rgba(0, 0, 0, 0.03) !important;
    border-left: 1px solid rgba(0, 0, 0, 0.05);
}

.healy-comparison-table .table {
    border-collapse: separate;
    border-spacing: 0;
}

/* Feature column stays left-aligned */
.feature-col {
    text-align: left;
    background-color: #f8f9fa;
    width: 30%;
}

/* Vertical alignment for all cells */
.healy-comparison-table td,
.healy-comparison-table th {
    vertical-align: middle;
}

/* Add a slight hover effect to rows */
.healy-comparison-table tbody tr:hover {
    background-color: rgba(var(--primary-rgb), 0.02);
}

/* Sticky header fix for better UX */
.healy-comparison-table thead {
    position: sticky;
    top: 0;
    z-index: 10;
}

.accordion-button {
    background-color: white !important;
    border: 1px solid rgba(var(--primary-rgb), 0.1) !important;
    color: var(--primary) !important;
}

    .accordion-button:not(.collapsed) {
        box-shadow: none;
        background-color: var(--primary) !important;
        color: white !important;
    }

        .accordion-button:not(.collapsed)::after {
            filter: brightness(0) invert(1); /* Turns the arrow white when expanded */
        }

.accordion-item {
    transition: all 0.3s ease;
}

    /* Give the expanded accordion a slight "lift" effect */
    .accordion-item:has(.show) {
        box-shadow: 0 1rem 3rem rgba(0,0,0,0.1) !important;
    }

/* Ensure the table inside the accordion handles overflow correctly */
.accordion-body {
    overflow-x: auto;
}

    .accordion-body.bg-light {
        background-color: #f8f9fa !important; /* Light grey backdrop for the table */
    }

    /* Ensure table looks sharp inside the light background */
    .accordion-body .healy-comparison-table .table {
        border: 1px solid rgba(0,0,0,0.05);
    }

.bg-primary-dark {
    background-color: #1a1a1a; /* Matches your footer */
}

.rounded-5 {
    border-radius: 2.5rem !important;
}

.btn-lg {
    font-size: 1.1rem;
    letter-spacing: 0.5px;
    transition: all 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
}

    .btn-lg:hover {
        transform: scale(1.05);
    }

/* ----------------------------------------------------
   Products Details
---------------------------------------------------- */

/* Custom styling for the program accordion in details */
.custom-program-accordion .accordion-item {
    border: 1px solid rgba(0,0,0,0.08) !important;
}

.custom-program-accordion .accordion-button::after {
    margin-left: initial;
}

.custom-program-accordion .accordion-button:not(.collapsed) {
    background-color: var(--primary);
    color: white;
}

    .custom-program-accordion .accordion-button:not(.collapsed) small {
        color: rgba(255,255,255,0.8) !important;
    }

    .custom-program-accordion .accordion-button:not(.collapsed) .badge {
        background-color: var(--primary-light);
    }

.custom-program-accordion .accordion-button.collapsed .badge {
    background-color: rgba(var(--primary-rgb), 0.15);
}

/* Breadcrumb styling */
.breadcrumb-item + .breadcrumb-item::before {
    /* Was a corrupted replacement-character glyph (U+FFFD) - likely an encoding mismatch from a
       past save - rendering as a visible tofu box in every breadcrumb sitewide. */
    content: "\203A";
    font-size: 1.2rem;
    vertical-align: middle;
    line-height: 1;
}

.breadcrumb a {
    text-decoration: none;
    color: var(--text-muted);
    transition: color 0.2s;
}

    .breadcrumb a:hover {
        color: var(--primary);
    }

.line-clamp-2 {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.product-card-hover {
    transition: transform 0.3s ease, box-shadow 0.3s ease;
}

    .product-card-hover:hover {
        transform: translateY(-5px);
        box-shadow: 0 10px 20px rgba(0,0,0,0.1) !important;
    }

/* ----------------------------------------------------
   Anchor-target highlight (Services.razor's #healing/#aura/#coaching cards)
---------------------------------------------------- */
/* Now that the testimonials/Home "path" cards link straight to each service's own dedicated
   page, nothing on the site currently lands here via the #anchor - but Services.razor's three
   cards render side by side on wider screens, all at the same vertical position, so arriving via
   any future #healing/#aura/#coaching link would otherwise give no visual sign of which one you
   were sent to. This is left in defensively rather than relied on. */
#healing:target, #aura:target, #coaching:target {
    box-shadow: 0 0 0 4px rgba(var(--primary-rgb), 0.6) !important;
    transition: box-shadow 0.6s ease-out;
}

/* ----------------------------------------------------
   Product Recommendation
---------------------------------------------------- */

/* --- Floating Animation for Product Images --- */
.floating-anim {
    animation: floating 3s ease-in-out infinite;
}

@keyframes floating {
    0% {
        transform: translateY(0px);
    }

    50% {
        transform: translateY(-15px);
    }

    100% {
        transform: translateY(0px);
    }
}

/* --- Progress Bar Polish --- */
.progress {
    background-color: #e9ecef;
    overflow: visible; /* Allows the glow of the bar to show */
}

.progress-bar {
    box-shadow: 0 0 10px var(--primary);
}

@media print {
    /* Hide everything except the result card. .whatsapp-float and #cookieBanner both live in
       MainLayout.razor as siblings of <main>, not inside it - so neither this list nor the
       "main:has(.product-recommendation) > *:not(.product-recommendation)" rule further down
       (which only reaches <main>'s own children) ever caught them; both rendered right on top of
       a printed report until added here explicitly. #backToTop is already handled via its own
       no-print class instead of being listed here. */
    nav, footer, .btn, .btn-link, .progress, .quiz-header, .breadcrumb, .no-print,
    .whatsapp-float, #cookieBanner {
        display: none !important;
    }

    /* Reset layout for paper */
    body {
        background: white !important;
        font-size: 12pt;
    }

    .container {
        width: 100% !important;
        max-width: none !important;
        margin: 0 !important;
        padding: 0 !important;
    }

    /* Professional Card Styling */
    .card {
        border: 1px solid #eee !important;
        box-shadow: none !important;
    }

    .card-energy {
        box-shadow: none !important;
        border: 1px solid #eee !important;
    }

    .bg-primary-subtle {
        background-color: #f0f7ff !important;
        -webkit-print-color-adjust: exact; /* Forces background color in Chrome/Safari */
    }

    /* The result card's right-hand column keeps its on-screen p-4 p-md-5 padding (measured: ~120px
       of it goes completely unused here) since the buttons that padding used to give breathing
       room around (.btn, .btn-link - Shop/Save PDF/Discovery Chat/Back/Start New) are all hidden
       above. Left as-is, that reads as a large unexplained blank gap before "Next Steps" starts -
       tightened for print specifically, not changed on-screen where the buttons still need it. */
    .product-recommendation .col-lg-7 {
        padding: 0.5rem 0.5rem 0 !important;
    }

    .product-recommendation .d-print-block {
        margin-top: 0.5rem !important;
        padding-top: 0.5rem !important;
    }

    /* Sized for screen (a big, breathing-room product photo) - measured at ~276px tall on a
       report where every other section is print-tuned, this alone was the single largest
       contributor to spilling onto a second page. The on-screen size/padding are untouched. */
    .product-recommendation .col-lg-5.bg-light {
        padding: 0.25rem !important;
    }

    .product-recommendation img {
        max-height: 90px !important;
    }

    .product-recommendation h1.display-5 {
        font-size: 16pt !important;
        margin-bottom: 0.4rem !important;
    }

    .product-recommendation .bg-primary-subtle.mb-4 {
        margin-bottom: 0.4rem !important;
        padding: 0.4rem 0.6rem !important;
    }

    .product-recommendation h2.h1 {
        font-size: 14pt !important;
        margin-bottom: 0.25rem !important;
    }

    .product-recommendation .col-lg-7 p.text-muted {
        margin-bottom: 0 !important;
    }

    /* Ensure table is legible */
    .table {
        border: 1px solid #dee2e6 !important;
    }

    th {
        background-color: #f8f9fa !important;
        -webkit-print-color-adjust: exact;
    }

    main:has(.product-recommendation) > *:not(.product-recommendation) {
        display: none;
    }

    .product-recommendation {
        margin-bottom: 0 !important;
        margin-top: 0 !important;
        padding-bottom: 0 !important;
        padding-top: 0 !important;
    }

        /* Report header - was a CSS ::before pseudo-element with the text hardcoded directly
           into content: (and, having no connection to IStringLocalizer, a fixed English string
           regardless of the active site language - it also said "Frequency & Wellness", not
           this site's actual name). Replaced by a real, localized element in the markup itself
           (ProductRecommendation.razor's own d-print-block header) - this just styles it. */
        .print-report-header {
            display: block;
            text-align: center;
            font-weight: bold;
            font-size: 14pt;
            margin-bottom: 8px;
            color: #1a3a5f;
            border-bottom: 2px solid #1a3a5f;
            padding-bottom: 4px;
        }

        .print-report-header small {
            display: block;
            font-weight: normal;
            font-size: 10pt;
            color: #666;
            margin-top: 4px;
        }

        .product-recommendation img {
            max-height: 180px;
        }
}

/* ----------------------------------------------------
   WhatsApp floating button
---------------------------------------------------- */

/* Floating WhatsApp Button. Default bottom offset assumes no other bottom-anchored bar is
   present. .raise-for-sticky-bar (added in MainLayout.razor only when ShowStickyBookingBar is
   true - it's hidden on /booking itself) raises it clear of .sticky-booking-bar instead. */
.whatsapp-float {
    position: fixed;
    bottom: 24px;
    right: 30px;
    background-color: #25d366;
    color: #FFF;
    border-radius: 50px;
    text-align: center;
    font-size: 24px; /* Icon size */
    box-shadow: 0px 4px 15px rgba(0,0,0,0.2);
    z-index: 1000;
    display: flex;
    align-items: center;
    padding: 12px 20px;
    text-decoration: none;
    transition: all 0.3s ease;
}

.whatsapp-float.raise-for-sticky-bar {
    bottom: 72px; /* clears .sticky-booking-bar (~55px tall) - see that rule's own comment */
}

/* Hide text on mobile, show only icon */
.whatsapp-text {
    font-size: 16px;
    font-weight: 600;
    margin-left: 10px;
    font-family: sans-serif;
}

.whatsapp-float:hover {
    background-color: #128c7e;
    color: #FFF;
    transform: translateY(-5px);
}

/* #backToTop mirrors .whatsapp-float's default/raised split above and for the same reason
   (/booking has no sticky booking bar to clear). Its bottom offset used to live in an inline
   style in MainLayout.razor; moved into these classes so it can vary with ShowStickyBookingBar
   the same way .whatsapp-float does. */
#backToTop {
    bottom: 24px;
}

#backToTop.raise-for-sticky-bar {
    bottom: 90px;
}

/* Both the WhatsApp float and #backToTop need to clear whichever bottom-anchored bar is
   currently tallest. When the sticky booking bar is present (.raise-for-sticky-bar), showing the
   cookie banner stacks the sticky booking bar on top of itself (see body.has-cookie-banner
   .sticky-booking-bar below) rather than replacing it, so this needs to clear that combined
   height - hence var(--cookie-banner-height) (see App.razor's updateCookieBannerHeightVar) plus
   the sticky bar's own ~55px and a small margin. When the sticky bar is absent (e.g. /booking),
   there's nothing to stack on top of - just clear the cookie banner itself, matching the same
   "+10px" buffer body.has-cookie-banner already uses for its own reserved space (see below). */
body.has-cookie-banner .whatsapp-float.raise-for-sticky-bar,
body.has-cookie-banner #backToTop.raise-for-sticky-bar {
    bottom: calc(var(--cookie-banner-height, 60px) + 70px) !important;
}

body.has-cookie-banner .whatsapp-float:not(.raise-for-sticky-bar),
body.has-cookie-banner #backToTop:not(.raise-for-sticky-bar) {
    bottom: calc(var(--cookie-banner-height, 60px) + 10px) !important;
}

/* Pulse Animation */
.whatsapp-float {
    animation: whatsapp-pulse 2s infinite;
}

@keyframes whatsapp-pulse {
    0% {
        box-shadow: 0 0 0 0 rgba(37, 211, 102, 0.7);
    }

    70% {
        box-shadow: 0 0 0 15px rgba(37, 211, 102, 0);
    }

    100% {
        box-shadow: 0 0 0 0 rgba(37, 211, 102, 0);
    }
}

@media screen and (max-width: 768px) {
    .whatsapp-float {
        bottom: 20px;
        right: 20px;
        /* Force a perfect circle */
        padding: 0;
        width: 60px;
        height: 60px;
        border-radius: 50%;
        /* Center the icon perfectly */
        display: flex;
        justify-content: center;
        align-items: center;
    }

    .whatsapp-float.raise-for-sticky-bar {
        bottom: 68px; /* raised to clear .sticky-booking-bar */
    }

    .whatsapp-text {
        display: none; /* Icon only on mobile to save space */
    }

    .whatsapp-float i {
        margin: 0;
        font-size: 30px; /* Slightly larger icon for thumb-tapping */
    }

    #backToTop {
        bottom: 20px;
    }

    #backToTop.raise-for-sticky-bar {
        bottom: 68px; /* raised to clear .sticky-booking-bar, matching .whatsapp-float */
    }
}

/* ----------------------------------------------------
   Sticky booking bar
---------------------------------------------------- */
/* A persistent, low-friction "Book Now" affordance - this is a lead-gen site whose one real
   conversion goal is a booked session, but previously the only persistent CTA was the WhatsApp
   button (a chat channel, not a direct path to booking). Kept slim and bottom-anchored rather
   than another floating circular button so it doesn't compete for the same corner as WhatsApp/
   back-to-top - those two just get their bottom offset raised instead (see above) so nothing
   overlaps. .has-sticky-booking-bar (applied to Footer's own dark disclaimer section, not the
   page's outer wrapper - see Footer.razor) reserves matching space at the end of the page so this
   fixed bar never covers the footer's own last line once a visitor scrolls all the way down -
   same problem, same fix, as body.has-cookie-banner already solves for the cookie banner below. */
.sticky-booking-bar {
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    z-index: 98;
    background: var(--primary);
    padding: 12px 16px;
    box-shadow: 0 -4px 15px rgba(0, 0, 0, 0.15);
}

/* 64px covers .sticky-booking-bar's own ~55px at its default bottom:0 position, plus a small
   buffer. When the cookie banner is also shown, the bar moves much higher (see below) - this
   static value doesn't follow it, so the footer's reserved space is no longer big enough and its
   last line can scroll in behind the (now higher) bar. body.has-cookie-banner overrides it below
   with the same math used for the bar's own position, kept in sync deliberately rather than
   computed from one shared value, since the two properties (a fixed element's `bottom` vs. a
   flow element's `padding-bottom`) aren't expressible as the same calc() safely. !important is
   load-bearing here, not defensive: this element also carries Bootstrap's .py-4 utility class,
   which sets its own padding-bottom marked !important by Bootstrap itself (utilities are meant to
   always win regardless of source order) - without matching it, this rule silently loses to
   .py-4's 24px and the reserved space never actually applies at all. Verified this the hard way:
   it "looked" fine at 24px only by luck (a paragraph's own line-height leaves a little natural
   buffer past its last character), until the much larger cookie-banner-shown gap below exposed a
   real, severe text/bar overlap that pointed straight back to this override never having taken
   effect in the first place. */
.has-sticky-booking-bar {
    padding-bottom: 64px !important;
}

/* The cookie banner (z-index 10000) sits well above this bar's own z-index:98 and spans the same
   full-width bottom:0 strip, so left alone it would simply cover the booking bar completely
   instead of the two coexisting. Stacking this bar flush against the cookie banner's own real
   height (var(--cookie-banner-height), set by App.razor's updateCookieBannerHeightVar - a fixed
   guess here previously undershot the banner's actual height once it wrapped to its taller
   stacked-on-narrow-widths layout, which is what let the two visually overlap instead of
   stacking) keeps both visible at once with no gap between them; it collapses back to bottom:0
   automatically once the banner is dismissed, since that just removes the body class this
   selector depends on. */
body.has-cookie-banner .sticky-booking-bar {
    bottom: var(--cookie-banner-height, 60px);
}

/* Matches the rule above: the bar's height (~55px) plus this same buffer, on top of wherever the
   bar now sits once the cookie banner pushed it up. !important for the same reason as the base
   rule above - this still needs to beat Bootstrap's .py-4. */
body.has-cookie-banner .has-sticky-booking-bar {
    padding-bottom: calc(var(--cookie-banner-height, 60px) + 64px) !important;
}
