/* CLEO Website Core — base stylesheet. Theme-token driven; do not hard-code
   brand colors here. Every generated site loads this file plus the inline
   :root token blocks core/theme.php and core/motion.php produce. Container
   width, section rhythm, shape language, and shadow strength all come from
   the site's Design Profile (see core/design-personalities.php) — this file
   should read as "how tokens are applied", not "what the tokens are". */

*, *::before, *::after { box-sizing: border-box; }
html {
    scroll-behavior: smooth;
    /* .site-header is position:sticky/top:0 (below), so an in-page anchor
       jump (service-grid.php's #service-{slug} links, contact-form.php's
       optional `id`) would otherwise land its target flush under the
       header instead of visible below it. Found 2026-08-26 while wiring
       Move Your Mindset's "Book Now" buttons to /workshops#book-a-spot —
       a real, previously-latent gap affecting every anchor link on any
       site, not just this new one. ~73px measured header height + a
       little breathing room; not tied to a CSS var since header height
       isn't one anywhere in this file.
    */
    scroll-padding-top: 90px;
}
body {
    margin: 0;
    background: var(--cleo-bg);
    color: var(--cleo-text);
    font-family: var(--cleo-font-body);
    line-height: 1.6;
    -webkit-font-smoothing: antialiased;
}
h1, h2, h3, h4 {
    font-family: var(--cleo-font-heading);
    letter-spacing: var(--cleo-heading-tracking, 0);
    line-height: 1.15;
    margin: 0 0 .5em;
    color: var(--cleo-primary);
}
h1 { font-size: clamp(2.1rem, 1.4rem + 3vw, 3.4rem); }
h2 { font-size: clamp(1.6rem, 1.2rem + 1.6vw, 2.3rem); }
h3 { font-size: clamp(1.15rem, 1rem + .6vw, 1.4rem); }
p { margin: 0 0 1em; color: var(--cleo-text); }
p.lead { font-size: clamp(1.05rem, 1rem + .3vw, 1.2rem); color: var(--cleo-muted); }
a { color: var(--cleo-primary); text-decoration: none; }
a:hover { text-decoration: underline; }
img { max-width: 100%; height: auto; display: block; }
.wrap { max-width: var(--cleo-container, 1140px); margin: 0 auto; padding: 0 20px; }

.skip-link { position: absolute; left: -999px; top: 0; background: var(--cleo-primary); color: #fff; padding: 10px 16px; z-index: 100; }
.skip-link:focus { left: 12px; top: 12px; }
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0,0,0,0); }

:where(a, button, input, select, textarea):focus-visible {
    outline: 3px solid var(--cleo-accent);
    outline-offset: 2px;
}

.site-header { border-bottom: 1px solid var(--cleo-border); background: var(--cleo-bg); position: sticky; top: 0; z-index: 20; transition: background-color .4s ease, border-color .4s ease; }

/* Transparent-over-hero navigation (only on pages whose first component is
   an immersive hero — see core/layout.php). The header leaves normal flow
   entirely so the hero can start at the true top of the viewport, reads
   light-on-dark until assets/js/site.js adds `.is-scrolled`, and only then
   becomes the same solid/sticky header every other page already uses. */
body.nav-transparent .site-header {
    position: fixed;
    top: 0; left: 0; right: 0;
    background: transparent;
    border-bottom-color: transparent;
}
body.nav-transparent .site-header .brand,
body.nav-transparent .site-header .primary-nav a { color: #fff; }
body.nav-transparent .site-header .primary-nav a[aria-current="page"] { color: #fff; text-decoration: underline; text-underline-offset: 4px; }
body.nav-transparent .site-header .nav-toggle { border-color: rgba(255,255,255,.6); color: #fff; }
/* No backdrop-filter here on purpose (2026-08-17 scroll-performance pass):
   this header is `position: fixed` once scrolled, so a blur here would
   recompute continuously for the ENTIRE rest of the page's scroll, not a
   bounded moment — by far the most expensive place blur could go. A
   near-solid background reads just as clean without that cost, and now
   matches every other page's plain (never-blurred) header exactly. */
body.nav-transparent .site-header.is-scrolled {
    background: color-mix(in srgb, var(--cleo-bg), transparent 3%);
    border-bottom-color: var(--cleo-border);
}
body.nav-transparent .site-header.is-scrolled .brand,
body.nav-transparent .site-header.is-scrolled .primary-nav a { color: var(--cleo-text); }
body.nav-transparent .site-header.is-scrolled .primary-nav a[aria-current="page"] { color: var(--cleo-primary); }
body.nav-transparent .site-header.is-scrolled .nav-toggle { border-color: var(--cleo-border); color: inherit; }
/* The mobile dropdown panel is always solid regardless of header state
   (readability first) — unaffected by the transparent treatment above. */
body.nav-transparent .primary-nav.open { background: var(--cleo-bg); }
body.nav-transparent .primary-nav.open a { color: var(--cleo-text); }
/* Wider than the shared `.wrap` content column on purpose (overrides its
   max-width via source order, same specificity — both classes sit on the
   same element): a header with several nav destinations needs more room
   than a reading-width body column, and shrinking that column to fit the
   nav was never the right trade either way. Found 2026-08-26 wiring Move
   Your Mindset's nav CTA — several existing nav labels ("The Method",
   "Memberships & Pricing", "Free Intro & Workshops") were already
   wrapping to two lines mid-word inside 980px's worth of space; a real,
   pre-existing gap the new CTA link just made visible, not something the
   CTA itself caused. */
.nav-wrap { display: flex; align-items: center; justify-content: space-between; max-width: 1320px; padding: 16px 20px; gap: 16px; }
.brand { font-family: var(--cleo-font-heading); font-weight: 700; font-size: 1.2rem; color: var(--cleo-primary); }
.nav-toggle { display: none; background: none; border: 1px solid var(--cleo-border); border-radius: var(--cleo-radius-sm); padding: 8px 10px; font-size: 1.1rem; }
.primary-nav { display: flex; gap: 22px; align-items: center; }
.primary-nav a { color: var(--cleo-text); font-weight: 600; font-size: .95rem; }
.primary-nav a[aria-current="page"] { color: var(--cleo-primary); }
.primary-nav a:hover { text-decoration: none; color: var(--cleo-primary); }

/* Discreet nav booking CTA (core/layout.php's cleo_render_nav(), opt-in
   via manifest.nav_cta.enabled) — a small solid pill, deliberately NOT
   just another text link, so it reads as an action rather than a
   destination. Always carries its own solid background/light text —
   unlike the plain nav links, it does NOT switch to white-on-transparent
   over an immersive hero, since a solid pill is exactly what stays
   legible without needing that swap; this is the "discreet" of the
   design brief, not an attention-grabbing button. */
.primary-nav-cta {
    background: var(--cleo-primary) !important;
    color: #fff !important;
    padding: 8px 18px;
    border-radius: 999px;
    font-size: .85rem !important;
    white-space: nowrap;
    flex-shrink: 0;
}
.primary-nav-cta:hover { opacity: .9; color: #fff !important; }
body.nav-transparent .site-header .primary-nav-cta,
body.nav-transparent .site-header.is-scrolled .primary-nav-cta { color: #fff !important; }

main { min-height: 60vh; }
section.cleo-section { padding: var(--cleo-section-space, 64px) 20px; }
section.cleo-section.alt { background: var(--cleo-surface); }
section.cleo-section.alt-2 { background: var(--cleo-surface-alt); }
/* A dedicated, warm-off-white section surface (derived from the brand's
   own secondary color, not the alternating .alt/.alt-2 rhythm) — available
   to any component/client for whom a warm-off-white "moment" matters more
   than the generic alternation, without touching cleo_surface_class(). */
section.cleo-section.cleo-surface-warm { background: var(--cleo-surface-alt); }
section.cleo-section.full-bleed { padding: 0; }
section.cleo-section.full-bleed .section-inner { max-width: none; padding: 0; }
.section-inner { max-width: var(--cleo-container, 1140px); margin: 0 auto; }
.section-inner.narrow { max-width: min(720px, 100%); }
.section-eyebrow { text-transform: uppercase; letter-spacing: .08em; font-size: .75rem; font-weight: 700; color: var(--cleo-accent); }

.button {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 12px 22px;
    border-radius: var(--cleo-radius-lg);
    background: var(--cleo-primary);
    color: #fff;
    font-weight: 700;
    border: 0;
    cursor: pointer;
    box-shadow: var(--cleo-shadow);
}
.button:hover { text-decoration: none; opacity: .92; }
.button.outline { background: transparent; color: var(--cleo-primary); border: 2px solid var(--cleo-primary); box-shadow: none; }
.button.accent { background: var(--cleo-accent); color: #23180a; }

.grid { display: grid; gap: 24px; }
.grid.cols-2 { grid-template-columns: repeat(2, 1fr); }
.grid.cols-3 { grid-template-columns: repeat(3, 1fr); }
.card {
    display: block;
    position: relative;
    background: var(--cleo-bg);
    border: 1px solid var(--cleo-border);
    border-radius: var(--cleo-radius);
    padding: 24px;
    box-shadow: var(--cleo-shadow);
    text-decoration: none;
    color: inherit;
}
/* Marks the Manifest's `is_featured` service/tier — found missing entirely
   (2026-08-25, Move Your Mindset): the data field existed but no card
   layout ever read it, so a client's actual "recommend this tier" business
   decision silently never reached a visitor. */
.card-featured {
    border-color: var(--cleo-accent);
    border-width: 2px;
    box-shadow: 0 8px 24px -8px color-mix(in srgb, var(--cleo-accent), transparent 60%);
}
.card-featured-badge {
    display: inline-block;
    margin-bottom: 8px;
    padding: 3px 10px;
    border-radius: var(--cleo-radius-sm);
    background: var(--cleo-accent);
    color: var(--cleo-bg);
    font-size: .72rem;
    font-weight: 600;
    letter-spacing: .04em;
    text-transform: uppercase;
}

form.cleo-form { display: grid; gap: 14px; max-width: 520px; }
form.cleo-form label { display: grid; gap: 6px; font-weight: 600; font-size: .9rem; }
form.cleo-form input, form.cleo-form textarea, form.cleo-form select {
    padding: 11px 13px; border: 1px solid var(--cleo-border); border-radius: var(--cleo-radius-sm); font: inherit;
}

/* Booking picker (components/contact-form.php's optional booking_tiers/
   booking_days) — a real <fieldset> inside form.cleo-form's own grid, so it
   needs its browser-default border/padding reset; the tab pills themselves
   reuse calendar-visualizer.css's rules unchanged. */
form.cleo-form fieldset.cleo-form-picker { border: 0; padding: 0; margin: 0; display: grid; gap: 8px; }
form.cleo-form fieldset.cleo-form-picker legend {
    font-weight: 600; font-size: .9rem; padding: 0; margin-bottom: 2px;
}
form.cleo-form .calendar-visualizer-toggle { margin: 0; }
.cleo-form-booking-note { font-size: .85rem; color: var(--cleo-muted); margin: -6px 0 4px; max-width: 520px; }

.faq-list { display: grid; gap: 12px; max-width: 760px; }
.faq-item { border: 1px solid var(--cleo-border); border-radius: var(--cleo-radius); padding: 16px 18px; transition: border-color .2s ease; }
.faq-item:hover { border-color: var(--cleo-accent); }
.faq-item summary { cursor: pointer; font-weight: 700; transition: color .2s ease; }
.faq-item summary:hover { color: var(--cleo-accent); }
.faq-item p { margin-top: 10px; margin-bottom: 0; }
/* A bare native <details>/<summary> otherwise snaps open with zero
   transition — real, native accessibility (keyboard/screen-reader) for
   free, but no microinteraction at all. @starting-style is
   progressive enhancement only (older browsers just keep the instant
   native snap, a fully correct fallback, per this file's existing motion
   philosophy) — it can only animate the OPENING transition for a
   details/summary disclosure, not the close (that still snaps natively,
   a widely-accepted asymmetry for accordions: opening is what a visitor
   actually watches). */
@media (prefers-reduced-motion: no-preference) {
    .faq-item p {
        transition: opacity .3s ease, transform .3s ease;
    }
    @starting-style {
        .faq-item[open] p {
            opacity: 0;
            transform: translateY(-4px);
        }
    }
}

.gallery-grid .cleo-media { border-radius: var(--cleo-radius); aspect-ratio: 4/3; object-fit: cover; }

.split-reversed .section-inner { direction: rtl; }
.split-reversed .split-media, .split-reversed .split-text { direction: ltr; }
.split-media { background: var(--cleo-surface); border-radius: var(--cleo-radius-lg); min-height: 200px; overflow: hidden; }
.split-media img { width: 100%; height: 100%; object-fit: cover; }

.team-card img { border-radius: var(--cleo-radius); aspect-ratio: 1; object-fit: cover; margin-bottom: 12px; }

/* Shared "plain numbered list" visual language (docs/DESIGN-SYSTEM.md's
   "Cinematic & immersive" section: card grids are not the default) — used
   by `service-grid`'s optional `layout: 'editorial-list'` and by
   `hotspot-map`'s zone list, so a service breakdown reads the same way
   wherever it appears on a site, without either component depending on
   the other or duplicating this CSS. */
.cleo-editorial-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 2px; }
.cleo-editorial-list-item {
    display: flex;
    gap: 16px;
    padding: 18px 10px;
    border-bottom: 1px solid var(--cleo-border);
    border-radius: var(--cleo-radius-sm);
    transition: background-color .3s ease;
    scroll-margin-top: 90px;
}
/* An item whose only child is itself a padded interactive element (the
   expandable <details>, or the "link elsewhere" <a>) shouldn't ALSO be
   flex/padded at the <li> level — that doubled the padding. The <li>
   becomes a plain wrapper; the child owns the whole row's layout. */
.cleo-editorial-list-item:has(> details),
.cleo-editorial-list-item:has(> a) {
    display: block;
    gap: 0;
    padding: 0;
}
.cleo-editorial-list-item:last-child { border-bottom: 0; }
.cleo-editorial-list-index {
    font-family: var(--cleo-font-heading);
    color: var(--cleo-accent);
    font-weight: 700;
    font-size: .85rem;
    min-width: 1.6em;
    line-height: 1.5;
}
.cleo-editorial-list-label { margin: 0 0 4px; font-size: 1.05rem; }
.cleo-editorial-list-desc { margin: 0; color: var(--cleo-muted); font-size: .92rem; }
.service-grid-editorial .cleo-editorial-list { max-width: 760px; margin-top: 20px; }

/* "A homepage service preview is never a dead end" (2026-08-22): a
   service-grid item with `link_items_to` set renders as this link
   instead of plain text — same flex layout the plain item already had
   (the item <li> itself stops laying anything out once it holds a link),
   plus a small "Learn more" hint so the affordance reads as intentional,
   not an accidental unstyled link. */
.cleo-editorial-list-link {
    display: flex;
    align-items: flex-start;
    gap: 16px;
    padding: 18px 10px;
    border-radius: var(--cleo-radius-sm);
    text-decoration: none;
    color: inherit;
    transition: background-color .3s ease;
}
.cleo-editorial-list-link:hover,
.cleo-editorial-list-link:focus-visible { background-color: var(--cleo-surface); }
.cleo-editorial-list-more,
.card .cleo-editorial-list-more {
    margin-left: auto;
    align-self: center;
    font-size: .82rem;
    font-weight: 600;
    color: var(--cleo-accent);
    white-space: nowrap;
    padding-left: 12px;
}
.cleo-editorial-list-more::after { content: 'Learn more →'; }
.card .cleo-editorial-list-more { display: block; margin: 12px 0 0; padding-left: 0; }

/* Service explorability (docs/DESIGN-SYSTEM.md's "Visual coverage across
   the whole site", 2026-08-22): an editorial-list service with a `detail`
   field renders as a native <details>/<summary> disclosure — the exact
   accessible pattern .faq-item already established, reused rather than
   duplicated. `.service-grid-item-expandable` widens the list's max-width
   slightly (media needs more room than plain text) and owns the border
   the plain .cleo-editorial-list-item rule would otherwise supply. */
.service-grid-item-expandable { border-bottom: 1px solid var(--cleo-border); }
.service-grid-item-expandable:last-child { border-bottom: 0; }
.service-detail-summary {
    display: flex;
    align-items: flex-start;
    gap: 16px;
    padding: 18px 10px;
    border-radius: var(--cleo-radius-sm);
    cursor: pointer;
    list-style: none;
    transition: background-color .3s ease;
}
.service-detail-summary::-webkit-details-marker { display: none; }
.service-detail-summary::marker { content: ''; }
.service-detail-summary:hover { background-color: var(--cleo-surface); }
.service-detail-toggle {
    margin-left: auto;
    align-self: center;
    font-size: .82rem;
    font-weight: 600;
    color: var(--cleo-accent);
    white-space: nowrap;
    padding-left: 12px;
}
.service-detail-toggle::after { content: 'Learn more ↓'; }
.service-detail[open] .service-detail-toggle::after { content: 'Show less ↑'; }
.service-detail-expanded { padding: 4px 10px 24px calc(1.6em + 16px + 10px); display: grid; gap: 16px; max-width: 640px; }
.service-detail-media { width: 100%; max-height: 320px; object-fit: cover; border-radius: var(--cleo-radius); }
.service-detail-copy p { margin: 0 0 12px; color: var(--cleo-muted); }
.service-detail-copy p:last-child { margin-bottom: 0; }
@media (max-width: 640px) {
    .service-detail-expanded { padding-left: 10px; max-width: none; }
}

/* Trust/proof: full-bleed image stage with a floating panel (right, on
   desktop) — the mirror image of hotspot-map's left-floating panel, for
   compositional variety across the two full-bleed/overlay moments on a
   homepage rather than a repeated pattern. */
.trust-proof-stage { position: relative; min-height: min(78vh, 720px); overflow: hidden; }
.trust-proof-media.cleo-media,
.trust-proof-media.hero-immersive-cinematic-fallback {
    position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; z-index: 0; border-radius: 0;
}
.trust-proof-stage::after {
    content: "";
    position: absolute;
    inset: 0;
    background: linear-gradient(260deg, rgba(0,0,0,.35) 0%, rgba(0,0,0,0) 45%);
    pointer-events: none;
}
.trust-proof-panel {
    position: relative;
    z-index: 1;
    background: var(--cleo-bg);
    padding: 40px clamp(20px, 6vw, 48px);
}
@media (min-width: 760px) {
    .trust-proof-panel {
        position: absolute;
        right: 0;
        top: 0;
        bottom: 0;
        display: flex;
        flex-direction: column;
        justify-content: center;
        width: min(440px, 92%);
        background: color-mix(in srgb, var(--cleo-bg), transparent 10%);
        backdrop-filter: blur(16px) saturate(1.1);
        -webkit-backdrop-filter: blur(16px) saturate(1.1);
        padding: 48px clamp(28px, 4vw, 48px);
    }
}
.trust-proof-points { list-style: none; margin: 0; padding: 0; display: grid; gap: 16px; }
.trust-proof-points li { padding-left: 18px; border-left: 2px solid var(--cleo-accent); font-size: 1.02rem; }
.trust-proof-below { max-width: var(--cleo-container, 1140px); margin: 0 auto; padding: var(--cleo-section-space, 64px) 20px 0; }
.trust-proof-preview { margin-top: 8px; }
.trust-proof-preview-grid { margin-bottom: 16px; }
.trust-proof-preview-grid .cleo-media { aspect-ratio: 4/3; border-radius: var(--cleo-radius); }
.trust-proof-preview-link { font-weight: 700; }
.trust-proof-reviews { margin-top: 40px; padding-bottom: var(--cleo-section-space, 64px); }
/* Tighter spacing when there are no real review cards yet — the default
   spacing above is sized for a 3-up card grid and left a single placeholder
   line floating in an oversized gap (found 2026-08-25, Move Your Mindset). */
.trust-proof-reviews-empty { margin-top: 16px; padding-bottom: calc(var(--cleo-section-space, 64px) * 0.4); }
.trust-proof-reviews-placeholder { color: var(--cleo-muted); font-style: italic; margin: 0; }
/* Optional end_cta (components/trust-proof.php V3): closes the section in
   normal typographic flow — a divider and centered text — instead of a
   separate coloured banner block underneath it. */
.trust-proof-end-cta {
    margin-top: 8px;
    padding: 40px 0 var(--cleo-section-space, 64px);
    border-top: 1px solid var(--cleo-border);
    text-align: center;
}
.trust-proof-end-cta h2 { margin-bottom: .3em; font-size: clamp(1.8rem, 1.3rem + 2.4vw, 3rem); }
.trust-proof-end-cta .lead { max-width: 46ch; margin: 0 auto 20px; }

.hero-minimal .lead { max-width: 46ch; }

.hero-editorial-headline { max-width: 16ch; }
.hero-editorial-row { display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: space-between; gap: 24px; margin-top: 20px; padding-top: 20px; border-top: 1px solid var(--cleo-border); }
.hero-editorial-row .lead { margin: 0; max-width: 42ch; }

.hero-split .hero-split-text { display: flex; flex-direction: column; justify-content: center; }
.hero-split-media { min-height: 320px; }

.hero-immersive {
    position: relative;
    background: linear-gradient(135deg, var(--cleo-primary), color-mix(in srgb, var(--cleo-primary), var(--cleo-accent) 45%));
    color: #fff;
    overflow: hidden;
    min-height: min(88vh, 780px);
    display: flex;
    align-items: flex-end;
}
/* Photography-backed variant: the media layer replaces the gradient as the
   visible background; the gradient stays as the loading/fallback color
   behind it via .has-media so nothing ever flashes unstyled. */
.hero-immersive.has-media { background: var(--cleo-primary); }
.hero-immersive-media.cleo-media,
.hero-immersive-media.hero-immersive-video,
.hero-immersive-media.hero-immersive-cinematic-fallback {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    z-index: 0;
    border-radius: 0;
}
/* Tier 3 of the video-forward hierarchy (docs/DESIGN-SYSTEM.md): when a
   hero has neither real/placeholder video nor a real/placeholder image, it
   still isn't a flat static color — a "motion composition built from
   stills" (an animated gradient, see assets/css/motion.css) stands in.
   This rule is the static base (visible even with motion disabled); the
   drift animation itself lives in motion.css so a motion_personality of
   `minimal` ships none of it. */
.hero-immersive-cinematic-fallback {
    background:
        radial-gradient(120% 90% at 20% 15%, color-mix(in srgb, var(--cleo-accent), transparent 72%), transparent 60%),
        linear-gradient(135deg, var(--cleo-primary), color-mix(in srgb, var(--cleo-primary), var(--cleo-accent) 40%));
    background-size: 160% 160%, 100% 100%;
}
/* Even the zero-asset gradient fallback identifies itself as a placeholder
   (docs/DESIGN-SYSTEM.md's placeholder-media policy: never presented as
   final approved content), via the same small corner-badge pattern the
   image placeholder uses. */
.cleo-cinematic-fallback-caption {
    position: absolute;
    top: 16px;
    left: 20px;
    z-index: 1;
    max-width: min(46ch, calc(100% - 40px));
    font-size: .72rem;
    line-height: 1.4;
    color: rgba(255,255,255,.75);
    background: rgba(0,0,0,.35);
    padding: 8px 12px;
    border-radius: var(--cleo-radius-sm);
}
/* Found 2026-08-18 (Fenwick & Rowe Build-Spec stress test): a hero with no
   media at all falls to the zero-asset gradient fallback above, whose
   caption sits at the same fixed top:16px every corner-badge caption uses —
   but an immersive hero's `nav-transparent` header (above) is ALSO fixed at
   the true top of the viewport, so the two collide/overlap illegibly. Every
   real client site so far has always supplied at least a placeholder image
   or video for its hero, so this exact combination (immersive hero + zero
   real/placeholder media + transparent nav) was never previously exercised.
   Scoped narrowly to that one combination — has no effect wherever a hero
   already has media (the current state of every real client site). */
body.nav-transparent .hero-immersive-cinematic-fallback .cleo-cinematic-fallback-caption {
    top: 76px;
}
/* A dark scrim under the text, not just the raw gradient — guarantees readable contrast
   for white text regardless of how light a given brand's primary/accent colors are. */
.hero-immersive::before {
    content: "";
    position: absolute;
    inset: 0;
    background: rgba(0, 0, 0, .45);
    z-index: 1;
}
/* V3: editorial, not centered — a large left-weighted text block near the
   bottom of the frame, so the footage carries most of the composition
   instead of a small centered card of text floating over it. */
.hero-immersive-inner {
    position: relative;
    z-index: 2;
    max-width: var(--cleo-container, 1140px);
    width: 100%;
    margin: 0 auto;
    /* Top padding is load-bearing, not decorative: this page's nav is
       `position: fixed` and transparent over the hero (body.nav-transparent),
       so nothing else reserves this space — without it, a tall wrapped
       headline can grow the section (min-height, not height) enough to
       collide with the nav bar sitting on top of it. */
    padding: 130px 24px calc(var(--cleo-section-space, 64px) * 1.3);
    text-align: left;
}
.hero-immersive h1, .hero-immersive p { color: #fff; }
.hero-immersive-inner h1 {
    max-width: 15ch;
    font-size: clamp(2.3rem, 1.3rem + 4.6vw, 5.4rem);
    margin-bottom: .28em;
}
.hero-immersive .lead { margin: 0 0 28px; max-width: 42ch; opacity: .92; text-align: left; }
.hero-immersive .button:not(.outline) { background: #fff; color: var(--cleo-primary); }
.hero-immersive .button.outline { border-color: rgba(255,255,255,.7); color: #fff; }

/* Ambient scroll parallax on the hero text (assets/js/motion.js), gated
   the same way as every other motion effect — a static `transform: none`
   is the fully correct state whenever JS hasn't set the custom property. */
html.motion-ready .hero-immersive-inner {
    transform: translateY(calc(var(--hero-parallax, 0) * -70px));
    opacity: calc(1 - var(--hero-parallax, 0) * .7);
}

/* Hero -> next-section hand-off: the bottom of the hero fades toward
   near-black so it dissolves into whatever dark-scrimmed full-bleed
   section follows (see `editorial-band`'s matching top fade), instead of
   cutting hard into a new rectangle. Layered above the media, below the
   text (z-index 1, same stacking context as the existing uniform scrim). */
.hero-immersive-handoff {
    position: absolute;
    left: 0; right: 0; bottom: 0;
    height: 38%;
    background: linear-gradient(to bottom, transparent, rgba(0,0,0,.94) 92%);
    z-index: 1;
    pointer-events: none;
}

/* Shared "real photo or clearly-labeled placeholder" media pattern
   (core/helpers.php's cleo_placeholder_media()) — used anywhere a component
   needs to go into a first build before final client photography exists. */
.cleo-media { width: 100%; height: 100%; object-fit: cover; }
.cleo-media-placeholder {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 10px;
    min-height: 160px;
    background: repeating-linear-gradient(135deg, var(--cleo-surface-alt), var(--cleo-surface-alt) 10px, var(--cleo-surface) 10px, var(--cleo-surface) 20px);
    border: 2px dashed var(--cleo-border);
    border-radius: inherit;
    color: var(--cleo-muted);
    text-align: center;
    padding: 20px;
}
.cleo-media-placeholder-icon { font-size: 1.8rem; opacity: .6; }
.cleo-media-placeholder-caption { font-size: .82rem; line-height: 1.4; max-width: 34ch; }
/* Any placeholder used as a full-bleed background BEHIND real overlaid
   text (hero, editorial-band, trust-proof, hotspot-map — anywhere
   `cleo_placeholder_media()` is called with the shared `cleo-media-overlay`
   marker class) needs its caption out of the way of that text, not
   centered in the middle of the box where it would collide with headings,
   body copy, or a floating panel positioned anywhere in the section. This
   pins it to a small, consistent top-left corner badge instead — still
   clearly a placeholder, never mistaken for real content. */
.cleo-media-overlay.cleo-media-placeholder {
    border: 0;
    border-radius: 0;
    background: repeating-linear-gradient(135deg, rgba(255,255,255,.05), rgba(255,255,255,.05) 10px, rgba(255,255,255,.015) 10px, rgba(255,255,255,.015) 20px);
    align-items: flex-start;
    justify-content: flex-start;
}
.cleo-media-overlay .cleo-media-placeholder-icon,
.cleo-media-overlay .cleo-media-placeholder-caption {
    display: inline;
}
.cleo-media-overlay .cleo-media-placeholder-caption,
.cleo-media-overlay .cleo-media-placeholder-icon {
    position: absolute;
    top: 16px;
    left: 20px;
    z-index: 1;
    max-width: min(46ch, calc(100% - 40px));
    font-size: .72rem;
    line-height: 1.4;
    color: rgba(255,255,255,.75);
    background: rgba(0,0,0,.35);
    padding: 8px 12px;
    border-radius: var(--cleo-radius-sm);
}
.cleo-media-overlay .cleo-media-placeholder-icon { padding: 8px 10px; }
.cleo-media-overlay .cleo-media-placeholder-caption { top: 44px; }

/* Editorial band (components/editorial-band.php) — full-bleed connective
   moment between two bigger moments (typically hero -> signature). Text is
   asymmetrically positioned (align-left/center/right), never centered like
   the hero, so the two full-bleed sections read as distinct beats. */
.cleo-editorial-band {
    position: relative;
    min-height: min(62vh, 560px);
    display: flex;
    align-items: center;
    color: #fff;
    overflow: hidden;
    padding: 0;
}
.cleo-editorial-band .editorial-band-media.cleo-media,
.cleo-editorial-band .editorial-band-media.hero-immersive-cinematic-fallback {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    z-index: 0;
    border-radius: 0;
}
.cleo-editorial-band::before {
    content: "";
    position: absolute;
    inset: 0;
    background: linear-gradient(100deg, rgba(0,0,0,.55) 0%, rgba(0,0,0,.2) 55%, rgba(0,0,0,.1) 100%);
    z-index: 1;
}
.cleo-editorial-band.align-right::before { background: linear-gradient(260deg, rgba(0,0,0,.55) 0%, rgba(0,0,0,.2) 55%, rgba(0,0,0,.1) 100%); }
.cleo-editorial-band.align-center::before { background: rgba(0,0,0,.4); }
/* Matches the hero's bottom hand-off fade (.hero-immersive-handoff) so a
   band placed directly after a hero reads as one continuous dissolve
   through black, not a hard cut into a new rectangle. Harmless when a
   band follows something else — it's a small top-edge darkening only. */
.cleo-editorial-band::after {
    content: "";
    position: absolute;
    top: 0; left: 0; right: 0;
    height: 22%;
    background: linear-gradient(to bottom, rgba(0,0,0,.75), transparent);
    z-index: 1;
    pointer-events: none;
}
.editorial-band-inner {
    position: relative;
    z-index: 2;
    max-width: var(--cleo-container, 1140px);
    width: 100%;
    margin: 0 auto;
    padding: 56px 24px;
}
.editorial-band-inner h1, .editorial-band-inner h2, .editorial-band-inner p { color: #fff; }
/* V3: a full-bleed narrative moment earns display-scale type, not the
   default boxed h2 size used inside cards/forms/grids elsewhere. */
.editorial-band-inner h1, .editorial-band-inner h2 { font-size: clamp(2rem, 1.3rem + 3.2vw, 3.8rem); max-width: 16ch; }
.editorial-band-inner .lead { max-width: 46ch; margin: 0; opacity: .92; }
.cleo-editorial-band.align-left .editorial-band-inner { text-align: left; }
.cleo-editorial-band.align-right .editorial-band-inner { text-align: right; margin-left: auto; }
.cleo-editorial-band.align-right .editorial-band-inner .lead,
.cleo-editorial-band.align-right .editorial-band-inner h1,
.cleo-editorial-band.align-right .editorial-band-inner h2 { margin-left: auto; }
.cleo-editorial-band.align-center .editorial-band-inner { text-align: center; }
.cleo-editorial-band.align-center .editorial-band-inner .lead,
.cleo-editorial-band.align-center .editorial-band-inner h1,
.cleo-editorial-band.align-center .editorial-band-inner h2 { margin-left: auto; margin-right: auto; }
.cleo-editorial-band .button { margin-top: 8px; }
.cleo-editorial-band .button:not(.outline) { background: #fff; color: var(--cleo-primary); }
.cleo-editorial-band .button.outline { border-color: rgba(255,255,255,.7); color: #fff; }

/* Media sequence (components/media-sequence.php) — a paced full-bleed
   visual story: one slide per item, alternating left/right, an oversized
   faint index number behind the heading (typography as composition, not
   just a label). See that file's doc comment for why this is deliberately
   NOT scroll-jacked. */
.media-sequence-intro {
    max-width: var(--cleo-container, 1140px);
    margin: 0 auto;
    padding: var(--cleo-section-space, 64px) 20px 8px;
}
.media-sequence-slide {
    position: relative;
    min-height: min(78vh, 720px);
    display: flex;
    align-items: center;
    color: #fff;
    overflow: hidden;
}
.media-sequence-media.cleo-media,
.media-sequence-media.hero-immersive-video,
.media-sequence-media.hero-immersive-cinematic-fallback {
    position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; z-index: 0; border-radius: 0;
}
.media-sequence-slide::before {
    content: "";
    position: absolute;
    inset: 0;
    /* Flat and uniform, not a directional fade (2026-08-23). A gradient
       that fades toward one side left a corner of the frame under-covered
       for whatever media happened to sit there -- found by actually
       rendering a real slide, not from the gradient values alone. A flat
       scrim gives consistent white-text-on-photo contrast everywhere in
       the frame. (A screenshot's own baked-in UI text is a different,
       harder problem no scrim opacity actually solves -- see
       cleo_component_media_sequence()'s 'inset' media style, which
       sidesteps it instead of fighting it with more darkness.) */
    background: rgba(0,0,0,.5);
    z-index: 1;
}
.media-sequence-slide-inner {
    position: relative;
    z-index: 2;
    max-width: var(--cleo-container, 1140px);
    width: 100%;
    margin: 0 auto;
    padding: 48px 24px;
}
.media-sequence-slide.align-left .media-sequence-slide-inner { text-align: left; }
.media-sequence-slide.align-right .media-sequence-slide-inner { text-align: right; margin-left: auto; }
.media-sequence-index {
    display: block;
    font-family: var(--cleo-font-heading);
    font-size: clamp(4.5rem, 3rem + 8vw, 11rem);
    font-weight: 700;
    line-height: .8;
    color: var(--cleo-accent);
    opacity: .5;
    margin-bottom: -.15em;
}
.media-sequence-slide h3 { color: #fff; font-size: clamp(1.8rem, 1.2rem + 3vw, 3.2rem); max-width: 18ch; margin: 0 0 .3em; }
.media-sequence-slide.align-right h3 { margin-left: auto; }
.media-sequence-slide p { color: rgba(255,255,255,.9); max-width: 46ch; font-size: 1.05rem; margin: 0; }
.media-sequence-slide.align-right p { margin-left: auto; }
.media-sequence-slide:not(:last-child) { border-bottom: 1px solid rgba(255,255,255,.08); }

/* 'inset' media style (components/media-sequence.php) — the image sits in
   its own frame next to the text instead of behind it as a full-bleed
   cover. See that file's comment: a scrim can't fix a screenshot's own
   internal text contrast, so this sidesteps the collision instead of
   trying to darken past it. */
.media-sequence-slide.media-inset { background: var(--cleo-primary); padding: 64px 0; }
.media-sequence-slide.media-inset::before { display: none; }
.media-sequence-slide.media-inset .media-sequence-slide-inner { padding: 0 24px; }
.media-sequence-inset-figure { margin: 28px 0 0; max-width: 640px; }
.media-sequence-slide.align-right.media-inset .media-sequence-inset-figure { margin-left: auto; }
.media-sequence-inset-image {
    display: block;
    width: 100%;
    height: auto;
    max-height: 360px;
    object-fit: cover;
    object-position: top;
    border-radius: var(--cleo-radius);
    box-shadow: 0 30px 60px -20px rgba(0,0,0,.6);
}
.media-sequence-inset-figure .hero-immersive-cinematic-fallback { position: static; height: 220px; }

@media (max-width: 760px) {
    .media-sequence-slide { min-height: 62vh; }
    .media-sequence-slide.align-right .media-sequence-slide-inner,
    .media-sequence-slide.align-right h3,
    .media-sequence-slide.align-right p { text-align: left; margin-left: 0; }
}

/* Before/after (components/before-after.php) — a range-input-driven
   transformation reveal. The frame's aspect-ratio is fixed so the layout
   never jumps as the slider moves; both images are absolutely stacked at
   full size, and only the "after" layer is clipped via the --reveal custom
   property the range input writes to.

   V3.1 fix (2026-08-17): the visible handle IS the real <input
   type="range"> now, not a decorative div next to a separate control below
   the frame. The input is stretched to cover the whole frame with a
   transparent track and a custom-styled (but real) thumb, so the entire
   image is the drag surface and mouse/touch/keyboard all come from the one
   native control — no bespoke pointer-event code, nothing for a drag to
   miss. `.before-after-divider`/`.before-after-handle` stay as a purely
   decorative (`pointer-events:none`) visual layer under the input, so the
   thumb's real position and the drawn line/circle always match exactly. */
.cleo-before-after .before-after-demo-note {
    font-size: .85rem;
    color: var(--cleo-muted);
    margin: -8px 0 20px;
}
.before-after-frame {
    position: relative;
    width: 100%;
    aspect-ratio: 16 / 10;
    max-height: 78vh;
    border-radius: var(--cleo-radius, 12px);
    overflow: hidden;
    background: #111;
}
.before-after-img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    border-radius: 0;
}
.before-after-after-wrap {
    position: absolute;
    inset: 0;
    clip-path: inset(0 calc(100% - var(--reveal)) 0 0);
}
.before-after-after-wrap .before-after-img { position: absolute; inset: 0; }
.before-after-tag {
    position: absolute;
    top: 16px;
    z-index: 2;
    pointer-events: none;
    font-size: .75rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .06em;
    color: #fff;
    background: rgba(0,0,0,.45);
    padding: 6px 12px;
    border-radius: var(--cleo-radius-sm, 6px);
}
.before-after-tag-before { left: 16px; }
.before-after-tag-after { right: 16px; }
.before-after-divider {
    position: absolute;
    top: 0;
    bottom: 0;
    left: var(--reveal);
    width: 3px;
    margin-left: -1.5px;
    background: rgba(255,255,255,.9);
    box-shadow: 0 0 0 1px rgba(0,0,0,.25);
    pointer-events: none;
    z-index: 2;
}
.before-after-handle {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 44px;
    height: 44px;
    border-radius: 50%;
    background: #fff;
    color: var(--cleo-primary);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 1.1rem;
    box-shadow: 0 2px 10px rgba(0,0,0,.35);
}
/* The real control: full-frame, transparent track, invisible thumb sized
   to match the decorative handle above so hit-testing feels obvious even
   though nothing about the thumb itself is drawn — the decorative circle
   underneath is what renders, this is what's actually draggable/focusable.

   A custom squeegee-shaped cursor was tried here (Clarity Engine Phase 1,
   2026-08-18) and removed the same day after visual review — at cursor
   size it read as a generic tool/hammer shape rather than a squeegee, so
   it was working against the polish it was meant to add. Plain `ew-resize`
   is the correct, honest cursor for a horizontal drag control. */
.before-after-range {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    margin: 0;
    z-index: 3;
    appearance: none;
    -webkit-appearance: none;
    -moz-appearance: none;
    background: transparent;
    cursor: ew-resize;
}
.before-after-range::-webkit-slider-runnable-track { background: transparent; }
.before-after-range::-webkit-slider-thumb {
    -webkit-appearance: none;
    width: 44px;
    height: 44px;
    border-radius: 50%;
    background: transparent;
    border: 0;
    cursor: ew-resize;
}
.before-after-range::-moz-range-track { background: transparent; border: 0; height: 100%; }
.before-after-range::-moz-range-thumb {
    width: 44px;
    height: 44px;
    border-radius: 50%;
    background: transparent;
    border: 0;
    cursor: ew-resize;
}
.before-after-range:focus-visible { outline: none; }
.before-after-range:focus-visible ~ .before-after-divider .before-after-handle {
    outline: 3px solid var(--cleo-accent);
    outline-offset: 2px;
}

@media (max-width: 760px) {
    .before-after-frame { aspect-ratio: 4 / 5; max-height: none; }
}

/* Breath interaction (components/breath-interaction.php) — a press-and-hold
   micro-experience, first built for Move Your Mindset. A single native
   <button> is the entire control (see the component's own doc comment for
   the accessibility rationale); assets/js/breath-interaction.js drives a
   --breath custom property (0 to 1) via requestAnimationFrame at constant
   velocity, not a CSS transition, so a release mid-hold eases back smoothly
   from wherever it actually was rather than snapping or restarting. The
   visual layer's max growth is a CSS variable so prefers-reduced-motion can
   shrink the delta to something bounded without the JS needing to know
   about it for the visual — see the media query below and
   assets/js/breath-interaction.js's matching near-zero-duration branch (a
   CSS transition-duration override alone can't reach this property, since
   it's written frame-by-frame in JS, never transitioned). */
.cleo-breath-interaction .section-inner { display: flex; flex-direction: column; align-items: center; }
.breath-interaction-ring {
    --breath: 0;
    --breath-max-grow: .9;
    appearance: none;
    -webkit-appearance: none;
    border: 1px solid var(--cleo-border);
    background: var(--cleo-surface);
    border-radius: 50%;
    width: clamp(160px, 22vw, 220px);
    height: clamp(160px, 22vw, 220px);
    margin: 28px auto 14px;
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    touch-action: none;
    padding: 0;
}
.breath-interaction-ring:focus-visible {
    outline: 3px solid var(--cleo-accent);
    outline-offset: 4px;
}
.breath-interaction-visual {
    position: absolute;
    inset: 10%;
    border-radius: 50%;
    background: radial-gradient(circle at 50% 45%, color-mix(in srgb, var(--cleo-accent), #fff 15%), var(--cleo-accent));
    opacity: calc(.35 + var(--breath) * .55);
    transform: scale(calc(1 + var(--breath) * var(--breath-max-grow)));
    box-shadow: 0 0 calc(var(--breath) * 46px) calc(var(--breath) * 10px) color-mix(in srgb, var(--cleo-accent), transparent 55%);
    pointer-events: none;
}
.breath-interaction-label {
    position: relative;
    z-index: 1;
    font-weight: 600;
    letter-spacing: .04em;
    text-transform: uppercase;
    font-size: .8rem;
    text-align: center;
    max-width: 84px;
    line-height: 1.3;
    color: var(--cleo-text);
    pointer-events: none;
}
.breath-interaction-note {
    max-width: 46ch;
    margin: 0 auto;
    color: var(--cleo-muted);
    font-size: .95rem;
    text-align: center;
}

@media (prefers-reduced-motion: reduce) {
    .breath-interaction-ring { --breath-max-grow: .12; }
}

/* Calendar visualizer (components/calendar-visualizer.php) — a membership
   toggle rendered as a real week, not a pricing table. The tier toggle is a
   native radio group; `:has(input:checked)` styles the active tab so no JS
   class-toggling is needed for that part. assets/js/calendar-visualizer.js
   only ever swaps text content and an existing `hidden` attribute on the
   in-person marker — never animates — so toggling looks and behaves
   identically whether or not the visitor has motion reduced, per this
   component's build-spec note that responsiveness matters more than
   ambient pacing here. The "online" markers use a dashed/lighter treatment
   deliberately distinct from the solid in-person marker — see the
   component's own doc comment for why: it's an honesty signal (illustrative
   vs. confirmed data), not a stylistic accent. */
.calendar-visualizer-toggle {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    border: 0;
    padding: 0;
    margin: 24px 0 20px;
}
.calendar-visualizer-tab {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: 12px 20px;
    border: 1px solid var(--cleo-border);
    border-radius: var(--cleo-radius-sm, 6px);
    cursor: pointer;
    background: var(--cleo-surface);
}
.calendar-visualizer-tab input {
    position: absolute;
    inset: 0;
    opacity: 0;
    margin: 0;
    cursor: pointer;
}
.calendar-visualizer-tab-label { font-weight: 600; }
.calendar-visualizer-tab-price { font-size: .85rem; color: var(--cleo-muted); }
.calendar-visualizer-tab:has(input:checked) {
    border-color: var(--cleo-accent);
    background: color-mix(in srgb, var(--cleo-accent), transparent 90%);
}
.calendar-visualizer-tab:has(input:focus-visible) {
    outline: 3px solid var(--cleo-accent);
    outline-offset: 2px;
}
.calendar-visualizer-summary {
    font-size: 1.15rem;
    font-weight: 600;
    margin: 0 0 20px;
}
.calendar-visualizer-grid {
    display: grid;
    grid-template-columns: repeat(7, minmax(96px, 1fr));
    gap: 8px;
    overflow-x: auto;
    padding-bottom: 4px;
}
.calendar-visualizer-day {
    border: 1px solid var(--cleo-border);
    border-radius: var(--cleo-radius-sm, 6px);
    padding: 14px 10px;
    min-height: 92px;
    display: flex;
    flex-direction: column;
    gap: 8px;
}
.calendar-visualizer-day-label {
    font-size: .8rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .04em;
    color: var(--cleo-muted);
}
.calendar-visualizer-marker {
    display: inline-block;
    font-size: .75rem;
    line-height: 1.3;
    padding: 5px 8px;
    border-radius: var(--cleo-radius-sm, 6px);
}
.calendar-visualizer-marker-online {
    border: 1px dashed var(--cleo-border);
    color: var(--cleo-muted);
    background: transparent;
}
.calendar-visualizer-marker-in-person {
    background: var(--cleo-accent);
    color: #fff;
    font-weight: 600;
}
.calendar-visualizer-note {
    font-size: .82rem;
    color: var(--cleo-muted);
    margin: 8px 0 0;
}

@media (max-width: 760px) {
    .calendar-visualizer-grid { grid-template-columns: repeat(7, minmax(84px, 1fr)); }
}

.cta-banner {
    position: relative;
    background: linear-gradient(120deg, var(--cleo-primary), color-mix(in srgb, var(--cleo-primary), var(--cleo-accent) 40%));
    color: #fff;
}
.cta-banner::before { content: ""; position: absolute; inset: 0; background: rgba(0, 0, 0, .45); }
.cta-banner .section-inner { position: relative; }
.cta-banner h2, .cta-banner p { color: #fff; }
.cta-banner .button:not(.outline) { background: #fff; color: var(--cleo-primary); }

@media (max-width: 760px) {
    .hero-editorial-row { flex-direction: column; align-items: flex-start; }
    .hero-split-media { min-height: 220px; order: -1; }
}

/* Ambient audio toggle (core/layout.php's cleo_render_ambient_audio_mount(),
   assets/js/ambient-audio.js) — matches the chatbot launcher's shadow/
   corner-anchoring so the two floating controls read as one design system,
   deliberately mirrored to the opposite corner so they never compete for
   space. Revised 2026-08-26 from an icon-only circle to a labeled pill
   (Danielle: "make it more obvious that the visitor can play or pause
   it") — a real play-triangle/pause-bars icon plus a visible "Music"
   label read as an actionable player at a glance, not an ambiguous dot.
   The two icon SVGs are swapped by CSS alone, driven by the same
   `.is-playing` class the JS already toggles for the audio-element
   control — no extra JS needed for the icon swap itself. A gentle pulse
   on the whole pill while playing is the only animation, and
   prefers-reduced-motion's global `animation-duration: .001ms !important`
   rule (this file, above) already makes it instant rather than removing
   the state entirely, same as every other motion on this site. */
.cleo-ambient-audio-toggle {
    position: fixed;
    left: 20px;
    bottom: 20px;
    z-index: 60;
    display: flex;
    align-items: center;
    gap: 9px;
    padding: 12px 20px 12px 16px;
    border-radius: 999px;
    border: 0;
    cursor: pointer;
    background: var(--cleo-primary);
    box-shadow: var(--cleo-shadow);
}
.cleo-ambient-audio-icon {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    border-radius: 50%;
    background: var(--cleo-accent);
    color: var(--cleo-primary);
    flex-shrink: 0;
}
.cleo-ambient-audio-icon-pause { display: none; }
.cleo-ambient-audio-toggle.is-playing .cleo-ambient-audio-icon-play { display: none; }
.cleo-ambient-audio-toggle.is-playing .cleo-ambient-audio-icon-pause { display: block; }
.cleo-ambient-audio-label {
    color: #fff;
    font-weight: 600;
    font-size: .9rem;
    letter-spacing: .01em;
}
.cleo-ambient-audio-toggle.is-playing {
    animation: cleo-ambient-pulse 2.4s ease-in-out infinite;
}
@keyframes cleo-ambient-pulse {
    0%, 100% { box-shadow: var(--cleo-shadow), 0 0 0 0 color-mix(in srgb, var(--cleo-accent), transparent 60%); }
    50% { box-shadow: var(--cleo-shadow), 0 0 0 8px color-mix(in srgb, var(--cleo-accent), transparent 100%); }
}
@media (max-width: 760px) {
    .cleo-ambient-audio-toggle { left: 12px; bottom: 12px; padding: 10px 16px 10px 12px; }
    .cleo-ambient-audio-icon { width: 26px; height: 26px; }
}

.site-footer { background: var(--cleo-primary); color: #fff; margin-top: 40px; }
.footer-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 24px; padding: 48px 20px; }
.footer-grid h2, .footer-grid h3 { color: #fff; }
.footer-grid p { color: rgba(255,255,255,.85); }
.footer-grid a { color: #fff; display: block; margin-bottom: 6px; }
.footer-bottom { display: flex; justify-content: space-between; padding: 16px 20px; border-top: 1px solid rgba(255,255,255,.15); font-size: .85rem; opacity: .85; }
.footer-credit { opacity: .8; }

@media (prefers-reduced-motion: reduce) {
    html { scroll-behavior: auto; }
    * { animation-duration: .001ms !important; transition-duration: .001ms !important; }
}

@media (max-width: 760px) {
    .nav-toggle { display: inline-flex; }
    .primary-nav { position: absolute; top: 100%; left: 0; right: 0; background: var(--cleo-bg); flex-direction: column; align-items: flex-start; padding: 16px 20px; border-bottom: 1px solid var(--cleo-border); display: none; }
    .primary-nav.open { display: flex; }
    .grid.cols-2, .grid.cols-3 { grid-template-columns: 1fr; }
    .footer-grid { grid-template-columns: 1fr; }
    section.cleo-section { padding: calc(var(--cleo-section-space, 64px) * .65) 18px; }
    /* split-content.php's image has no height cap — fine on desktop, where
       the 2-column grid naturally constrains it, but .grid.cols-2 stacks to
       a single column above (real width) on mobile, so a portrait-source
       photo (several of Move Your Mindset's are — e.g. 867x1300) renders at
       its full intrinsic aspect ratio and can eat most of a phone's
       viewport height before any heading is visible. Found 2026-08-26: on
       Memberships specifically, this pushed the intro paragraph down far
       enough to land directly behind the fixed ambient-audio-toggle at the
       page's natural resting scroll position (0) — a real content/control
       collision on first load, not just a tall-photo aesthetics issue.
       object-fit:cover (already set) crops gracefully to this ratio. */
    .split-media { aspect-ratio: 4 / 3; min-height: 0; }
}
