/* ============================================================
 * Organization Website Theme - Base
 * ============================================================
 * Single customizable theme for standalone org websites.
 * All colors/fonts use CSS custom properties so they can be
 * overridden per-org via OrgWebsiteBrandingHelper.
 *
 * Future: expand to 3 themes (Clean/Bold/Elegant) by overriding
 * the layout/spacing variables below.
 * ============================================================ */

/* ----------------------------------------------------------
 * Website-specific tokens (extend the global design tokens)
 * ---------------------------------------------------------- */

:root {
    --website-nav-height: 72px;
    --website-nav-bg: var(--bg-primary);
    --website-nav-border: var(--border-default);
    --website-nav-link-color: var(--text-primary);
    --website-nav-link-hover: var(--color-primary-600);
    --website-nav-link-hover-bg: var(--color-primary-50);
    --website-nav-link-active: var(--color-primary-700);
    --website-nav-link-active-bg: transparent;
    --website-nav-brand-weight: var(--font-weight-bold);
    --website-nav-brand-size: var(--font-size-lg);

    --website-footer-bg: var(--color-neutral-900);
    --website-footer-text: var(--color-neutral-300);
    --website-footer-heading: var(--color-neutral-50);
    --website-footer-link: var(--color-neutral-400);
    --website-footer-link-hover: var(--color-primary-400);
    --website-footer-border: var(--color-neutral-800);
    --website-footer-padding-y: var(--space-6);
    --website-footer-padding-x: clamp(1.25rem, 4vw, 3rem);
    --website-footer-gutter: var(--space-8);

    --website-section-padding-y: var(--space-20);
    --website-section-gap: 0;

    /* Content spacing (Spacing & Edges "Content (inside)" ring):
       --website-content-gap / --website-card-pad are deliberately NOT
       defined here. A global pick (OrgWebsiteBrandingHelper) defines them on
       :root, a per-section pick inline on .website-section; the `wb-cgap`
       wrapper class (set by views/website/_section.php in either case) is
       what switches the `.wb-grid` overrides on, so every untouched grid
       keeps its own Bootstrap g-* / literal gap byte for byte.
       --website-section-padding-x (side padding) is likewise undefined by
       default so existing sections keep padding-left/right: 0. */

    /* Body-copy text alignment. `inherit` = keep whatever each section already
       sets, so the default is a visual no-op; the global Text Alignment control
       (OrgWebsiteBrandingHelper) overrides this on :root, and a per-section
       inline value on .website-section beats both. */
    --website-text-align: inherit;

    /* Design Theme structural tokens (overridden per-site by
       WebsiteDesignThemeRegistry via OrgWebsiteBrandingHelper). Defaults below
       reproduce the pre-theme look (classic). */
    --website-card-padding: 1.5rem;
    --website-section-divider: none;

    --website-page-max-width: 860px;
    --website-page-padding-y: var(--space-16);

    /* Section Width scale (config[content_width] 'wide'/'narrow' steps). Kept
     * deliberately separate from any --website-wide-max-width name -
     * EntitySpotlightSectionWidget's .es-w-wide relies on an UNDEFINED such var
     * falling back to its own inline 1320px; defining one here would silently
     * resize every existing spotlight section. */
    --website-width-wide: 1600px;
    --website-width-narrow: 960px;
}

[data-theme="dark"] {
    --website-nav-bg: var(--bg-primary);
    --website-nav-border: var(--border-default);
    --website-footer-bg: var(--color-neutral-950);
    --website-footer-border: var(--color-neutral-800);
}

/* ----------------------------------------------------------
 * Navigation
 * ---------------------------------------------------------- */

.website-navbar {
    background-color: var(--website-nav-bg);
    border-bottom: 1px solid var(--website-nav-border);
    min-height: var(--website-nav-height);
    transition: var(--transition-colors);
}

/* When the navbar lives inside a header strip (as a main_menu section),
 * the strip already provides its own background via .website-header-strip-bg-*.
 * Suppress the navbar's own background + border so the strip's bg
 * paints through; otherwise the menu area renders as a dark block on
 * top of an otherwise colored strip.
 *
 * `!important` is required to beat theme.css:20 which declares
 * `.navbar { background-color: var(--bg-secondary) !important; }`
 * for the main-app header. Theme.css loads via ThemeAsset (registered
 * by the theme-switcher in the strip), so it's present on the org
 * website too. Without !important here, the main-app rule wins
 * regardless of specificity. */
.website-header-strip .navbar,
.website-header-strip .website-navbar {
    background-color: transparent !important;
    border-bottom: 0 !important;
    min-height: 0;
}

.website-navbar .navbar-brand {
    font-weight: var(--website-nav-brand-weight);
    font-size: var(--website-nav-brand-size);
    font-family: var(--font-family-brand, var(--font-family-heading));
    color: var(--text-primary);
    text-decoration: none;
}

.website-navbar .navbar-brand:hover {
    color: var(--color-primary-600);
}

.website-nav-logo {
    max-height: var(--website-nav-logo-height, 40px);
    width: auto;
    object-fit: contain;
    flex: 0 0 auto;
}

/* ---------------------------------------------------------------------------
 * Logo set - light/dark theme swap
 *
 * When an org configures a dark-mode logo, the renderer emits two <img>s
 * (website-logo--light + website-logo--dark). We show the one that matches
 * the active theme. Sites with only a primary logo emit a single <img> with
 * neither class, so these rules never apply and markup is unchanged.
 *
 * theme.js always writes an explicit [data-theme] on <html> at load, so the
 * prefers-color-scheme block below only covers the brief pre-hydration / no-JS
 * window.
 * ------------------------------------------------------------------------- */
.website-logo--dark {
    display: none;
}
[data-theme="dark"] .website-logo--light {
    display: none;
}
[data-theme="dark"] .website-logo--dark {
    display: inline-block;
}
/* Footer logo is display:block - keep it block when swapped. */
[data-theme="dark"] .website-footer-logo.website-logo--dark {
    display: block;
}

@media (prefers-color-scheme: dark) {
    html:not([data-theme]) .website-logo--light {
        display: none;
    }
    html:not([data-theme]) .website-logo--dark {
        display: inline-block;
    }
    html:not([data-theme]) .website-footer-logo.website-logo--dark {
        display: block;
    }
}

.website-nav-brand-text {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* ----------------------------------------------------------
 * Navigation - Mobile (< 992px)
 * No header strip - the hero takes the full top of the page.
 * A floating hamburger in the top-right opens the off-canvas
 * menu (wired by web/js/mobile-menu.js via #mobileMenuBtn).
 * ---------------------------------------------------------- */

@media (max-width: 991.98px) {
    .website-navbar {
        display: none;
    }

    .website-nav-toggle {
        position: fixed;
        top: 12px;
        right: 16px;
        z-index: 1031;
        width: 44px;
        height: 44px;
        padding: 0;
        display: inline-flex;
        align-items: center;
        justify-content: center;
        background: var(--bg-primary);
        color: var(--website-nav-link-color);
        border: 1px solid var(--border-default);
        border-radius: var(--radius-md);
        box-shadow: var(--shadow-md);
        font-size: 1.1rem;
        transition: var(--transition-colors);
    }

    .website-nav-toggle:hover,
    .website-nav-toggle:focus {
        background: var(--bg-secondary);
        color: var(--color-primary-600);
    }
}

.website-navbar .nav-link {
    color: var(--website-nav-link-color);
    font-weight: var(--font-weight-medium);
    font-family: var(--font-family-menu-left, inherit);
    padding: var(--space-2) var(--space-4);
    border-radius: var(--radius-md);
    transition: var(--transition-colors);
}

.website-navbar .nav-link:hover,
.website-navbar .nav-link:focus {
    color: var(--website-nav-link-hover);
    background-color: var(--website-nav-link-hover-bg);
}

.website-navbar .nav-link.active {
    color: var(--website-nav-link-active);
    background-color: var(--website-nav-link-active-bg);
    font-weight: var(--font-weight-semibold);
}

/* Dark-theme default for the hover pill. Declared as a variable (not a
   background override) so a custom org "Menu Hover Background" still wins in
   dark mode - an override rule here would out-specify the variable. */
[data-theme="dark"] {
    --website-nav-link-hover-bg: var(--color-neutral-800);
}

.website-navbar .dropdown-menu {
    border: 1px solid var(--border-default);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-lg);
    padding: var(--space-2);
}

.website-navbar .dropdown-item {
    border-radius: var(--radius-md);
    padding: var(--space-2) var(--space-4);
    font-weight: var(--font-weight-normal);
    transition: var(--transition-colors);
}

.website-navbar .dropdown-item:hover {
    background-color: var(--color-primary-50);
    color: var(--color-primary-700);
}

[data-theme="dark"] .website-navbar .dropdown-item:hover {
    background-color: var(--color-neutral-800);
}

/* Active dropdown item - use the variant's primary tint, not Bootstrap blue.
   One shade stronger than hover (-100 vs -50) so active reads as more prominent.
   Cover both .active and :active - Bootstrap colors both. */
.website-navbar .dropdown-item.active,
.website-navbar .dropdown-item:active {
    background-color: var(--color-primary-100);
    color: var(--color-primary-700);
    font-weight: var(--font-weight-medium);
}

[data-theme="dark"] .website-navbar .dropdown-item.active,
[data-theme="dark"] .website-navbar .dropdown-item:active {
    background-color: var(--color-primary-900);
    color: var(--color-primary-300);
}

.website-navbar .nav-divider {
    width: 1px;
    height: 24px;
    background-color: var(--border-default);
    margin: 0 var(--space-2);
    align-self: center;
}

/* Child dividers inside a dropdown menu. Bootstrap's .dropdown-divider
 * already handles the "line" variant; these add the "space" and "dot"
 * variants so all three top-level styles translate cleanly to the
 * vertical stack of a dropdown. */
.nav-dropdown-divider--space {
    height: var(--space-3);
    pointer-events: none;
}
.nav-dropdown-divider--dot {
    text-align: center;
    padding: var(--space-1) 0;
    color: var(--text-tertiary);
    font-size: 0.25rem;
    opacity: 0.6;
    pointer-events: none;
}

/* ----------------------------------------------------------
 * Navbar: Language & Theme widgets
 * ---------------------------------------------------------- */

.website-navbar .language-switcher {
    margin: 0;
}

.website-navbar .language-flags {
    display: flex;
    align-items: center;
    gap: var(--space-1);
}

.website-navbar .language-flag {
    opacity: 0.5;
    transition: var(--transition-all);
    font-size: 1.25rem;
    line-height: 1;
    text-decoration: none;
}

.website-navbar .language-flag:hover,
.website-navbar .language-flag.active {
    opacity: 1;
}

.website-navbar .theme-toggle-switch {
    margin-bottom: 0;
}

.website-navbar .theme-switcher {
    margin: 0;
}

/* ----------------------------------------------------------
 * Main Content Area
 * ---------------------------------------------------------- */

.website-body {
    min-height: 100vh;
}

.website-body main {
    flex: 1;
}

/* Headings inside an org website must follow the org's heading font knob.
 * site.css unconditionally overrides h1 to use --font-family-brand (an
 * Eventure.si design opinion), which leaks into org websites and makes
 * the per-org "Heading font" setting look broken: changing it only moves
 * h2-h6, while the hero h1 stays on the brand font. Re-binding h1-h6
 * here keeps every heading - including widget-emitted h1s like the hero
 * title - on --font-family-heading. The navbar brand keeps its own
 * font via .website-navbar .navbar-brand (higher specificity). */
/* Per-level typography defaults. Each named style (Display / Heading 1-3 /
 * Lead) falls back to the umbrella --font-family-heading (or -tagline/-body
 * for lead) until the org picks a font for that level in Appearance -> Fonts.
 * OrgWebsiteBrandingHelper::getCssOverrides() overrides these on :root when a
 * level is set, so the cascade lets an unset level inherit the heading font. */
.website-body {
    --font-family-h1: var(--font-family-heading);
    --font-family-h2: var(--font-family-heading);
    --font-family-h3: var(--font-family-heading);
    --font-family-display: var(--font-family-heading);
    --font-family-lead: var(--font-family-tagline, var(--font-family-body));
}

/* Bind each heading tag to its own level token so widget-emitted headings
 * (hero h1, cta h2, ...) automatically pick up the per-level font. h4-h6
 * share the Heading 3 font. */
.website-body h1 { font-family: var(--font-family-h1); }
.website-body h2 { font-family: var(--font-family-h2); }
.website-body h3,
.website-body h4,
.website-body h5,
.website-body h6 {
    font-family: var(--font-family-h3);
}

/* Brand display: any element that renders the organisation name as the
 * site's identity (navbar wordmark, auto-hero title, footer brand). Must
 * outrank `.website-body h1-h6` above so the brand h1 in the auto-hero
 * picks up --font-family-brand instead of the heading font. Specificity
 * 0,2,0 (.website-body .website-brand-display) > 0,1,1 (.website-body h1). */
.website-body .website-brand-display {
    font-family: var(--font-family-brand, var(--font-family-heading));
}

/* Tagline / "voice" copy: the lead paragraph under a hero, slider
 * subheadings, section kicker lines, and testimonial sub-titles. These
 * are semantically different from body copy (they're marketing voice,
 * not running text) and historically had no font binding - the
 * --font-family-tagline knob was registered in the helper but read by
 * nothing. The .website-body prefix keeps this rule org-scoped (the
 * main Eventure.si site has its own .brand-tagline / .navbar-brand-tagline
 * consumers in site.css). */
.website-body .lead,
.website-body .hero-slider-subheading,
.website-body .video-feature-kicker,
.website-body .testimonial-subtitle {
    font-family: var(--font-family-tagline, inherit);
}

/* Apply-a-style classes: a section title can opt into a named typography
 * level (Word-style "apply Heading 1") without changing its <h2> tag. Font
 * comes from the level token, size from the global scale token. Used by the
 * per-section "Title style" dropdown (views/website/_section.php). */
.website-body .wb-style-display { font-family: var(--font-family-display); font-size: var(--website-font-size-display, var(--font-size-5xl)); }
.website-body .wb-style-h1 { font-family: var(--font-family-h1); font-size: var(--website-font-size-h1, var(--font-size-4xl)); }
.website-body .wb-style-h2 { font-family: var(--font-family-h2); font-size: var(--website-font-size-h2, var(--font-size-3xl)); }
.website-body .wb-style-h3 { font-family: var(--font-family-h3); font-size: var(--website-font-size-h3, var(--font-size-2xl)); }
.website-body .wb-style-body { font-family: var(--font-family-body); font-size: var(--website-font-size-base, var(--font-size-base)); }
.website-body .wb-style-lead { font-family: var(--font-family-lead); }

/* Body-text wrappers: the per-section "Body text style" dropdown wraps a
 * section's widget output so its running text re-fonts to a chosen level
 * without touching each widget's markup. */
.website-body .wb-bodytext-display { font-family: var(--font-family-display); }
.website-body .wb-bodytext-h1 { font-family: var(--font-family-h1); }
.website-body .wb-bodytext-h2 { font-family: var(--font-family-h2); }
.website-body .wb-bodytext-h3 { font-family: var(--font-family-h3); }
.website-body .wb-bodytext-body { font-family: var(--font-family-body); }
.website-body .wb-bodytext-lead { font-family: var(--font-family-lead); }

/* Per-section font (role) classes: the per-section "Title font" / "Body font"
 * dropdowns re-font a section's title or running text to one of the 5 site
 * fonts (roles). Font-family only - the title keeps its section-title size.
 * See views/website/_section.php. The .wb-style-* / .wb-bodytext-* blocks above
 * are legacy (nothing emits them now that values normalize to roles).
 *
 * Both .website-body and .website-section prefixes are needed, same reason as
 * the --website-text-align rules below: org/community custom-domain sites
 * render inside <body class="website-body"> (layouts/website.php), but the
 * community landing page (a platform page, views/website/_section.php rendered
 * under the platform's main layout) never gets that body class - only
 * .website-section, the per-section wrapper, is guaranteed present there.
 * Without the .website-section fallback, Title/Body font silently no-oped on
 * the landing page even though config[title_style]/[body_style] saved fine. */
.website-body .wb-font-heading, .website-section .wb-font-heading { font-family: var(--font-family-heading); }
.website-body .wb-font-body, .website-section .wb-font-body { font-family: var(--font-family-body); }
.website-body .wb-font-brand, .website-section .wb-font-brand { font-family: var(--font-family-brand, var(--font-family-heading)); }
.website-body .wb-font-menu, .website-section .wb-font-menu { font-family: var(--font-family-menu-left); }
.website-body .wb-font-tagline, .website-section .wb-font-tagline { font-family: var(--font-family-tagline, var(--font-family-body)); }

/* Per-section Title font, wrapper-scoped variant: many section types (hero,
 * cta, split_bio, video_feature, booking, countdown, ...) render their visible
 * headline inside their OWN widget rather than through the shared <h2> in
 * views/website/_section.php, so a class scoped to that <h2> alone (the
 * .wb-font-* rules above) can never reach them. The renderer also pushes
 * .wb-tfont-<role> onto the SECTION WRAPPER, so it reaches every section-level
 * heading regardless of who renders it: the shared h1/h2, or a widget's own
 * headline marked with .wb-section-heading (added only to the handful of
 * widgets whose headline is an h3-h5 - card/tile/member/plan titles are
 * deliberately NOT marked, so they keep following Body font, not Title font).
 * Specificity (0,2,1) beats .website-body h1-h6 (0,1,1, above) and
 * .website-body .website-brand-display (0,2,0) so an explicit Title font also
 * overrides the hero's brand-display font, which is the intended override. */
.website-section.wb-tfont-heading h1, .website-section.wb-tfont-heading h2, .website-section.wb-tfont-heading .wb-section-heading { font-family: var(--font-family-heading); }
.website-section.wb-tfont-body h1, .website-section.wb-tfont-body h2, .website-section.wb-tfont-body .wb-section-heading { font-family: var(--font-family-body); }
.website-section.wb-tfont-brand h1, .website-section.wb-tfont-brand h2, .website-section.wb-tfont-brand .wb-section-heading { font-family: var(--font-family-brand, var(--font-family-heading)); }
.website-section.wb-tfont-menu h1, .website-section.wb-tfont-menu h2, .website-section.wb-tfont-menu .wb-section-heading { font-family: var(--font-family-menu-left); }
.website-section.wb-tfont-tagline h1, .website-section.wb-tfont-tagline h2, .website-section.wb-tfont-tagline .wb-section-heading { font-family: var(--font-family-tagline, var(--font-family-body)); }

/* Per-section Title size (EVC-016), wrapper-scoped exactly like Title font
 * just above (same selector list, same reasoning: many section types draw
 * their headline inside their own widget, never through the shared <h2>).
 * --website-title-size-override is set inline on the .wb-tsize wrapper by
 * views/website/_section.php - no fallback needed here since the class only
 * exists when the var is set. Specificity (0,2,1) beats .website-body h1-h6
 * (0,1,1) for the same reason the Title font rules do. */
.website-section.wb-tsize h1, .website-section.wb-tsize h2, .website-section.wb-tsize .wb-section-heading {
    font-size: var(--website-title-size-override);
}

/* Per-section Body size (EVC-016). The inline font-size on the .wb-bsize
 * wrapper div (views/website/_section.php) is inherited by any descendant
 * with no font-size rule of its own, but .lead / p / li normally carry one
 * (Bootstrap / browser defaults) and would otherwise ignore the wrapper
 * entirely - this explicitly pulls them back to inheriting it. */
.wb-bsize p, .wb-bsize .lead, .wb-bsize li {
    font-size: inherit;
}

/* Per-section Line spacing (Text tab, config[body_line_height]). Rides the
 * same wrapper div as Body font / Body size (views/website/_section.php) as a
 * wb-blh-<key> class; keys are TextStyleRegistry::SPACINGS. Scoped under
 * .website-body / .website-section (see the Text Alignment note below for why
 * both prefixes are needed) and targeting the running-copy elements directly,
 * so it lands at (0,2,1) - deliberately above the legacy per-paragraph
 * .website-page-content .txt-lh-* rules (0,2,0): once the section knob is
 * set it wins, while "Default" leaves any older per-paragraph class alone. */
.website-body .wb-blh-tight p, .website-body .wb-blh-tight li, .website-body .wb-blh-tight .lead, .website-body .wb-blh-tight blockquote,
.website-section .wb-blh-tight p, .website-section .wb-blh-tight li, .website-section .wb-blh-tight .lead, .website-section .wb-blh-tight blockquote {
    line-height: var(--line-height-tight);
}
.website-body .wb-blh-normal p, .website-body .wb-blh-normal li, .website-body .wb-blh-normal .lead, .website-body .wb-blh-normal blockquote,
.website-section .wb-blh-normal p, .website-section .wb-blh-normal li, .website-section .wb-blh-normal .lead, .website-section .wb-blh-normal blockquote {
    line-height: var(--line-height-normal);
}
.website-body .wb-blh-relaxed p, .website-body .wb-blh-relaxed li, .website-body .wb-blh-relaxed .lead, .website-body .wb-blh-relaxed blockquote,
.website-section .wb-blh-relaxed p, .website-section .wb-blh-relaxed li, .website-section .wb-blh-relaxed .lead, .website-section .wb-blh-relaxed blockquote {
    line-height: var(--line-height-relaxed);
}
.website-body .wb-blh-loose p, .website-body .wb-blh-loose li, .website-body .wb-blh-loose .lead, .website-body .wb-blh-loose blockquote,
.website-section .wb-blh-loose p, .website-section .wb-blh-loose li, .website-section .wb-blh-loose .lead, .website-section .wb-blh-loose blockquote {
    line-height: var(--line-height-loose);
}

/* Body-copy text alignment. Scoped to running copy (paragraphs, lead/tagline
 * lines, and the Pell / block-editor rich-text render contexts) so headings and
 * buttons keep their own alignment and "Justify" only ever hits body text. The
 * value comes from --website-text-align, whose :root default is `inherit`, so
 * these rules stay a no-op until the global Text Alignment control or a
 * per-section override sets a real value.
 *
 * Both .website-body and .website-section prefixes are needed: org/community
 * custom-domain sites render inside <body class="website-body"> (layouts/website.php),
 * but the community landing page (a platform page, views/website/_section.php
 * rendered under the platform's main layout) never gets that body class - only
 * .website-section, the per-section wrapper, is guaranteed present there. Without
 * the .website-section fallback, a per-section Text Alignment override silently
 * no-oped on the landing page even though --website-text-align was set correctly.
 *
 * Video Feature's heading/kicker are an exception to the "headings keep their
 * own alignment" rule above: unlike a section's generic title (governed by
 * the separate Title Alignment control), they are widget-local copy with no
 * alignment control of their own, so they follow Text Alignment together with
 * the description - otherwise the copy block would look mismatched. */
.website-body p,
.website-body .lead,
.website-body .split-bio-body,
.website-section p,
.website-section .lead,
.website-section .split-bio-body,
.website-page-content .content-paragraph,
.video-feature-description,
.video-feature-heading,
.video-feature-kicker {
    text-align: var(--website-text-align);
}

/* Page content (for custom pages with block editor content) */
.website-page-content {
    max-width: var(--website-page-max-width);
    margin: 0 auto;
    padding: var(--website-page-padding-y) var(--space-4);
}

.website-page-content .content-heading {
    font-family: var(--font-family-heading);
}

.website-page-content .content-paragraph {
    font-size: var(--font-size-lg);
    line-height: 1.75;
    color: var(--text-secondary);
}

/* Per-paragraph typography presets in the website-page context. The base
 * .txt-* rules (web/css/site.css) lose to the (0,2,0) rule above, so these
 * context-scoped overrides restore the author's choice. The .website-section
 * prefix covers EVERY Pell rich-text render context (split_bio, CTA, video
 * feature, before/after, FAQ answers, team bios, tab bodies) for the same
 * reason; .split-bio-body is kept for the legacy standalone bio render. */
.website-page-content .txt-size-s,  .website-section .txt-size-s,  .split-bio-body .txt-size-s  { font-size: var(--font-size-sm); }
.website-page-content .txt-size-m,  .website-section .txt-size-m,  .split-bio-body .txt-size-m  { font-size: var(--font-size-base); }
.website-page-content .txt-size-l,  .website-section .txt-size-l,  .split-bio-body .txt-size-l  { font-size: var(--font-size-lg); }
.website-page-content .txt-size-xl, .website-section .txt-size-xl, .split-bio-body .txt-size-xl { font-size: var(--font-size-xl); }

.website-page-content .txt-lh-tight,   .website-section .txt-lh-tight,   .split-bio-body .txt-lh-tight   { line-height: var(--line-height-tight); }
.website-page-content .txt-lh-normal,  .website-section .txt-lh-normal,  .split-bio-body .txt-lh-normal  { line-height: var(--line-height-normal); }
.website-page-content .txt-lh-relaxed, .website-section .txt-lh-relaxed, .split-bio-body .txt-lh-relaxed { line-height: var(--line-height-relaxed); }
.website-page-content .txt-lh-loose,   .website-section .txt-lh-loose,   .split-bio-body .txt-lh-loose   { line-height: var(--line-height-loose); }

/* Per-block alignment from the Pell toolbar (TextStyleRegistry ALIGNS), at
 * (0,2,0) so it beats the (0,1,1) `.website-section p { text-align }` rule
 * driven by the section / global Text Alignment knob above. */
.website-page-content .txt-align-left,   .website-section .txt-align-left,   .split-bio-body .txt-align-left   { text-align: left; }
.website-page-content .txt-align-center, .website-section .txt-align-center, .split-bio-body .txt-align-center { text-align: center; }
.website-page-content .txt-align-right,  .website-section .txt-align-right,  .split-bio-body .txt-align-right  { text-align: right; }

/* Responsive scale for the toolbar's "Exact (px)" text sizes. On save,
 * ContentHelper::scaleRichTextPx() stores sizes above 16px as
 * `font-size: calc(NNpx * var(--wb-txt-scale, 1))`, so one variable per
 * breakpoint shrinks every custom size proportionally on tablets and
 * phones (a 22px hero line becomes ~20px / ~18px) without touching the
 * literal small sizes. The builder never defines the variable, so its
 * preview shows the exact px. */
.website-page-content, .website-section, .split-bio-body { --wb-txt-scale: 1; }
@media (max-width: 767.98px) {
    .website-page-content, .website-section, .split-bio-body { --wb-txt-scale: 0.9; }
}
@media (max-width: 575.98px) {
    .website-page-content, .website-section, .split-bio-body { --wb-txt-scale: 0.82; }
}

/* Inline colour / font spans from the Pell toolbar, at the same (0,2,0)
 * specificity so the website-context paragraph rules can't override them. */
.website-page-content .txt-color-primary,   .website-section .txt-color-primary   { color: var(--color-primary-600); }
.website-page-content .txt-color-secondary, .website-section .txt-color-secondary { color: var(--color-secondary-600); }
.website-page-content .txt-color-surface,   .website-section .txt-color-surface   { color: var(--website-bg, var(--bg-primary)); }
.website-page-content .txt-color-text,      .website-section .txt-color-text      { color: var(--website-fg, var(--text-primary)); }
.website-page-content .txt-font-heading, .website-section .txt-font-heading { font-family: var(--font-family-heading); }
.website-page-content .txt-font-body,    .website-section .txt-font-body    { font-family: var(--font-family-body); }
.website-page-content .txt-font-brand,   .website-section .txt-font-brand   { font-family: var(--font-family-brand, var(--font-family-heading)); }
.website-page-content .txt-font-menu,    .website-section .txt-font-menu    { font-family: var(--font-family-menu-left, var(--font-family-body)); }
.website-page-content .txt-font-tagline, .website-section .txt-font-tagline { font-family: var(--font-family-tagline, var(--font-family-body)); }
.website-page-content .txt-hl-marker,    .website-section .txt-hl-marker    { background-color: rgba(255, 213, 0, 0.45); color: inherit; }
.website-page-content .txt-hl-primary,   .website-section .txt-hl-primary   { background-color: rgba(var(--color-primary-600-rgb, 36, 144, 200), var(--hl-a, 0.2)); color: inherit; }
.website-page-content .txt-hl-secondary, .website-section .txt-hl-secondary { background-color: rgba(var(--color-secondary-600-rgb, 168, 98, 37), var(--hl-a, 0.2)); color: inherit; }
.website-page-content .txt-hl-surface,   .website-section .txt-hl-surface   { background-color: color-mix(in srgb, var(--website-bg, var(--bg-primary)) calc(var(--hl-a, 0.2) * 100%), transparent); color: inherit; }
.website-page-content .txt-hl-text,      .website-section .txt-hl-text      { background-color: color-mix(in srgb, var(--website-fg, var(--text-primary)) calc(var(--hl-a, 0.2) * 100%), transparent); color: inherit; }
.website-page-content .txt-hl-strong,    .website-section .txt-hl-strong    { --hl-a: 0.45; }

/* Full-width page layout (no max-width constraint) */
.website-page-full-width .website-page-content {
    max-width: none;
    padding-left: 0;
    padding-right: 0;
}

/* Sidebar layouts */
.website-page-sidebar-left,
.website-page-sidebar-right {
    max-width: 1200px;
    margin: 0 auto;
    padding: var(--website-page-padding-y) var(--space-4);
    display: grid;
    grid-template-columns: 280px 1fr;
    gap: var(--space-8);
}

.website-page-sidebar-right {
    grid-template-columns: 1fr 280px;
}

@media (max-width: 991.98px) {
    .website-page-sidebar-left,
    .website-page-sidebar-right {
        grid-template-columns: 1fr;
    }
}

/* ----------------------------------------------------------
 * Homepage Sections
 * ---------------------------------------------------------- */

.website-section {
    /* Per-side padding so a section can override top and bottom independently
       (config[section_spacing_top] / [_bottom]); each side falls back to the
       linked/global --website-section-padding-y when its override is unset. */
    padding-top: var(--website-section-padding-top, var(--website-section-padding-y));
    padding-bottom: var(--website-section-padding-bottom, var(--website-section-padding-y));
    /* Side padding (config[section_padding_x] family): the left/right inset
       inside the band. Independent vars (WB-003 Both/Separate) - unsplit,
       views/website/_section.php resolves both to the same value, so this
       is byte-identical to the single-var version it replaces. Unset = 0,
       today's look. */
    padding-left: var(--website-section-padding-left, 0);
    padding-right: var(--website-section-padding-right, 0);
    /* WB-002: this alone only shrinks the .container's centering slack (see
       .wb-spadx below for the fix - the inner .container's own max-width has
       to yield too, or the auto-margin centering absorbs the padding with no
       visible effect until it exceeds that slack). */
    /* Margin (config[section_margin] family): the transparent gap OUTSIDE the
       band. Top margin is handled by the sibling / first-child rules below so
       it can fall back to the global --website-section-gap between sections. */
    margin-bottom: var(--website-section-margin-bottom, 0);
    position: relative;
    overflow: hidden;
    /* Anchor-nav jump offset: keep the section top clear of the sticky/overlay
       header. Reuses the header-height var (default matches overlay CSS). */
    scroll-margin-top: var(--website-header-height, 96px);
}

/* Per-section top margin on the very first section (no sibling before it, so
   the `+` rule below never matches). Unset = 0 = today's look. */
.website-section:first-child {
    margin-top: var(--website-section-margin-top, 0);
}

/* Hero banner height (config[hero_height] / [hero_height_vh]), border-box
 * (Bootstrap's reboot sets box-sizing: border-box globally) so the pinned
 * number is the section's TRUE total height, wrapper padding included.
 * views/website/_section.php only ever adds this class with
 * --website-section-min-height set (a bare vh number, no unit), so no
 * fallback is needed here. Flex-centers the content vertically the same way
 * a short section with little copy would otherwise look top-heavy. Scoped to
 * .wb-minh only (currently emitted for Hero alone), so no other section type
 * is affected.
 *
 * --wb-vh-unit: the builder's auto-height preview iframe is sized to the FULL
 * page content height, so inside it 1vh = 1% of the whole page - a "tall"
 * hero would balloon to most of the document. website-preview-frame.js
 * publishes --wb-vh-unit (px per vh of a natural logical viewport) on the
 * iframe's root; on the real site it is unset and the 1vh/1svh fallback keeps
 * today's behavior exactly. */
.website-section.wb-minh {
    min-height: calc(var(--website-section-min-height) * var(--wb-vh-unit, 1vh));
    display: flex;
    flex-direction: column;
    justify-content: center;
}
@supports (min-height: 1svh) {
    /* Small-viewport height: on mobile, `vh` includes the browser chrome
       (URL bar) that then collapses on scroll, making a "Full screen" hero
       visibly grow underneath the visitor. `svh` is pinned to the chrome's
       collapsed size instead, so the banner never jumps. */
    .website-section.wb-minh {
        min-height: calc(var(--website-section-min-height) * var(--wb-vh-unit, 1svh));
    }
}

/* Responsive multiplier for the Spacing & Edges exact-px values (margin, side
 * padding, content gap). views/website/_section.php emits them as
 * `calc(Npx * var(--wb-space-scale, 1))`, so one variable per breakpoint
 * shrinks every hand-set distance proportionally on tablets and phones. The
 * ratios mirror the :root --website-section-padding-y shrink further below
 * (--space-20 -> --space-12 -> --space-8). The builder never defines the
 * variable, so its preview shows the exact px. */
.website-section { --wb-space-scale: 1; }
@media (max-width: 991.98px) {
    .website-section { --wb-space-scale: 0.75; }
}
@media (max-width: 575.98px) {
    .website-section { --wb-space-scale: 0.6; }
}

/* Smooth scrolling for in-page anchor nav links. */
html {
    scroll-behavior: smooth;
}

.website-section + .website-section {
    /* A per-section Margin (top) wins; unset falls back to the global Design
       Theme section gap. Adjacent bottom + top margins collapse to the larger
       one, the same way Wix margins behave. */
    margin-top: var(--website-section-margin-top, var(--website-section-gap));
    /* Design Theme hairline divider between adjacent sections. Default 'none'
       (classic) draws nothing; the 'slab' theme sets a 1px border-default rule. */
    border-top: var(--website-section-divider);
}

/* Section backgrounds */
/* Light/Dark: fixed neutral fills that follow the org's Theme Colors (when
 * set) but NOT the visitor's active mode - a section pinned to "Light" stays
 * light even when the visitor is browsing in dark mode. --website-bg-light/
 * -fg-light and -dark/-fg-dark are the mode-independent pair emitted by
 * OrgWebsiteBrandingHelper::buildThemeColorCss(); the literal hex fallbacks
 * mirror the platform default in variables.css and _theme-colors-pane.php. */
.website-section-light {
    background-color: var(--website-bg-light, #ffffff);
    color: var(--website-fg-light, #18181b);
}

.website-section-light *,
.website-section-light h1,
.website-section-light h2,
.website-section-light h3,
.website-section-light h4,
.website-section-light p,
.website-section-light span,
.website-section-light a:not(.btn) {
    color: inherit;
}

/* Surface: unlike -light/-dark (fixed pair), follows the org's Theme
 * Surface/Text colors AND the visitor's active mode via --website-bg/-fg
 * (see OrgWebsiteBrandingHelper::buildThemeColorCss()) - falls back to the
 * platform bg-primary/text-primary default when the org hasn't set one.
 * Anchors are deliberately excluded from the inherit cascade below (unlike
 * -light/-dark/-primary/-secondary) so a link style preset or brand link
 * color still shows through prose content inside a Surface section. */
.website-section-surface {
    background-color: var(--website-bg, var(--bg-primary));
    color: var(--website-fg, var(--text-primary));
}

.website-section-surface h1,
.website-section-surface h2,
.website-section-surface h3,
.website-section-surface h4,
.website-section-surface p,
.website-section-surface span {
    color: inherit;
}

.website-section-dark {
    background-color: var(--website-bg-dark, #18181b);
    color: var(--website-fg-dark, #fafafa);
}

.website-section-dark *,
.website-section-dark h1,
.website-section-dark h2,
.website-section-dark h3,
.website-section-dark h4,
.website-section-dark p,
.website-section-dark span,
.website-section-dark a:not(.btn) {
    color: inherit;
}

.website-section-primary {
    background-color: var(--color-primary-600);
    color: white;
}

.website-section-primary *,
.website-section-primary h1,
.website-section-primary h2,
.website-section-primary h3,
.website-section-primary h4,
.website-section-primary p,
.website-section-primary span {
    color: inherit;
}

/* Custom brand-hex background. The fill + contrast text colour are set inline on
 * the wrapper by views/website/_section.php (no per-hex class exists); this rule
 * only cascades that colour to headings/text like the token backgrounds do. The
 * solid/animation overlays are colour-agnostic and need nothing here. */
.website-section-custombg *,
.website-section-custombg h1,
.website-section-custombg h2,
.website-section-custombg h3,
.website-section-custombg h4,
.website-section-custombg p,
.website-section-custombg span {
    color: inherit;
}

/* Deep (the base / default gradient): primary-600 deepening to primary-800
 * along a 135deg diagonal. The slider controls WHERE primary-800 reaches
 * its full strength: at slider 0.5 (default) the stop sits at 100% which
 * reproduces the original smooth blend exactly; lower values pull primary-800
 * earlier (more dramatic deepening), higher push it past the viewport edge
 * (softer, more single-toned). */
.website-section-gradient {
    background: linear-gradient(
        135deg,
        var(--color-primary-600),
        var(--color-primary-800) calc(70% + var(--wb-bg-intensity, 0.5) * 60%)
    );
    color: white;
}

.website-section-gradient *,
.website-section-gradient h1,
.website-section-gradient h2,
.website-section-gradient h3,
.website-section-gradient h4,
.website-section-gradient p,
.website-section-gradient span {
    color: inherit;
}

/* Gradient recipe variants. Each overrides only `background` (the base rule
 * supplies color: white and the text-inheritance cascade). Doubled selector
 * `.website-section-gradient.website-section-gradient-{key}` beats the base
 * 1-class specificity. Default 'deep' uses the base rule (no extra class
 * needed) - existing rows keep their look. */

/* Duo: primary -> secondary diagonal. Slider controls the angle:
 *   0 -> 45deg (steep diagonal), 0.5 -> 135deg (current default), 1 -> 225deg. */
.website-section-gradient.website-section-gradient-duo {
    background: linear-gradient(
        calc(45deg + var(--wb-bg-intensity, 0.5) * 180deg),
        var(--color-primary-500),
        var(--color-secondary-500)
    );
}

/* Radial: center-out spotlight. Slider controls the focal point position
 * diagonally across the section: 0 -> top-left (20% 20%), 0.5 -> center
 * (50% 50%, current default), 1 -> bottom-right (80% 80%). */
.website-section-gradient.website-section-gradient-radial {
    background: radial-gradient(
        circle at
            calc(20% + var(--wb-bg-intensity, 0.5) * 60%)
            calc(20% + var(--wb-bg-intensity, 0.5) * 60%),
        var(--color-primary-500),
        var(--color-primary-800) 70%
    );
}

/* Sweep: 3-stop primary -> soft tint -> secondary. Slider controls where
 * the soft tint sits along the diagonal: 0 -> 30%, 0.5 -> 50% (current
 * default), 1 -> 70%. */
.website-section-gradient.website-section-gradient-sweep {
    background: linear-gradient(
        135deg,
        var(--color-primary-500) 0%,
        color-mix(in srgb, var(--bg-secondary, #f8f9fa) 80%, transparent) calc(30% + var(--wb-bg-intensity, 0.5) * 40%),
        var(--color-secondary-500) 100%
    );
}

/* Secondary section: mirror of Primary using the org's secondary brand token.
 * Closes the obvious gap in the matrix - orgs with a rich palette can now
 * lean on their full brand identity without dropping to custom CSS. */
.website-section-secondary {
    background-color: var(--color-secondary-600);
    color: white;
}

.website-section-secondary *,
.website-section-secondary h1,
.website-section-secondary h2,
.website-section-secondary h3,
.website-section-secondary h4,
.website-section-secondary p,
.website-section-secondary span {
    color: inherit;
}

/* Mesh: three overlapping radial-gradient blobs in the org's primary +
 * secondary, with a soft center tone that auto-flips per theme so the
 * page reads cohesively on both light and dark backgrounds. The Stripe /
 * Linear / Vercel "premium without motion" look.
 *
 * Default 'diagonal' composition. The slider controls how far the two
 * brand blobs fly toward their corners:
 *   0   -> blobs at 40% 40% / 60% 60% (soft, centered, almost merged)
 *   0.5 -> blobs at 20% 20% / 80% 80% (current default)
 *   1   -> blobs at 0%  0%  / 100% 100% (full corners, bold separation) */
.website-section-mesh {
    background-color: var(--bg-secondary, #f8f9fa);
    background-image:
        radial-gradient(at calc(40% - var(--wb-bg-intensity, 0.5) * 40%) calc(40% - var(--wb-bg-intensity, 0.5) * 40%), color-mix(in srgb, var(--color-primary-500) 55%, transparent), transparent 55%),
        radial-gradient(at calc(60% + var(--wb-bg-intensity, 0.5) * 40%) calc(60% + var(--wb-bg-intensity, 0.5) * 40%), color-mix(in srgb, var(--color-secondary-500) 55%, transparent), transparent 55%),
        radial-gradient(at 50% 50%, rgba(255, 255, 255, 0.55), transparent 60%);
    color: var(--text-primary);
}

[data-theme="dark"] .website-section-mesh {
    /* --bg-secondary (not --color-neutral-900): the former follows the org's
     * Theme Surface color when set (OrgWebsiteBrandingHelper::buildThemeColorCss()),
     * the latter is the fixed platform neutral and would ignore it. */
    background-color: var(--bg-secondary, #27272a);
    background-image:
        radial-gradient(at calc(40% - var(--wb-bg-intensity, 0.5) * 40%) calc(40% - var(--wb-bg-intensity, 0.5) * 40%), color-mix(in srgb, var(--color-primary-500) 45%, transparent), transparent 55%),
        radial-gradient(at calc(60% + var(--wb-bg-intensity, 0.5) * 40%) calc(60% + var(--wb-bg-intensity, 0.5) * 40%), color-mix(in srgb, var(--color-secondary-500) 45%, transparent), transparent 55%),
        radial-gradient(at 50% 50%, rgba(0, 0, 0, 0.45), transparent 60%);
    color: var(--text-primary, #fff);
}

/* Mesh composition variants. Each variant overrides only the background-image
 * (the base rule supplies background-color + text color, which differ per theme).
 * Selector doubles up `.website-section-mesh.website-section-mesh-{key}` so
 * specificity beats both the base mesh rule and any single-class neighbors.
 * Variants intentionally drop the soft white/dark center band so they work
 * uniformly across light and dark themes without per-theme overrides; the
 * theme-aware background-color underneath supplies the right "base canvas." */

/* Aurora: horizontal bands. Slider controls band thickness:
 *   0 -> 30% (thin / horizon-line whisper)
 *   0.5 -> 60% (current default)
 *   1 -> 90% (thick / fills most of the section). */
.website-section-mesh.website-section-mesh-aurora {
    background-image:
        radial-gradient(ellipse 100% calc(30% + var(--wb-bg-intensity, 0.5) * 60%) at 50% 0%, color-mix(in srgb, var(--color-primary-500) 55%, transparent), transparent 65%),
        radial-gradient(ellipse 100% calc(30% + var(--wb-bg-intensity, 0.5) * 60%) at 50% 100%, color-mix(in srgb, var(--color-secondary-500) 55%, transparent), transparent 65%);
}

/* Spotlight: single primary blob centered with secondary fades from the
 * opposite corners. Slider controls the spotlight RADIUS (where the
 * primary blob fades to transparent):
 *   0 -> 25% (tight, dramatic vignette)
 *   0.5 -> 45% (current default)
 *   1 -> 65% (wide, the primary blob bleeds across most of the section). */
.website-section-mesh.website-section-mesh-spotlight {
    background-image:
        radial-gradient(circle at 50% 50%, color-mix(in srgb, var(--color-primary-500) 65%, transparent) 0%, transparent calc(25% + var(--wb-bg-intensity, 0.5) * 40%)),
        radial-gradient(circle at 0% 100%, color-mix(in srgb, var(--color-secondary-500) 45%, transparent), transparent 50%),
        radial-gradient(circle at 100% 0%, color-mix(in srgb, var(--color-secondary-500) 45%, transparent), transparent 50%);
}

/* Twin: vertical left/right split. Slider controls how SHARPLY the two
 * sides meet (via each ellipse's x-radius - wider ellipses overlap more
 * and produce a blurred blend):
 *   0 -> 85% radius (heavy overlap, soft purple/blended middle)
 *   0.5 -> 65% radius (current default)
 *   1 -> 45% radius (no overlap, hard two-tone split). */
.website-section-mesh.website-section-mesh-twin {
    background-image:
        radial-gradient(ellipse calc(85% - var(--wb-bg-intensity, 0.5) * 40%) 100% at 0% 50%, color-mix(in srgb, var(--color-primary-500) 55%, transparent), transparent 70%),
        radial-gradient(ellipse calc(85% - var(--wb-bg-intensity, 0.5) * 40%) 100% at 100% 50%, color-mix(in srgb, var(--color-secondary-500) 55%, transparent), transparent 70%);
}

/* Solid surface treatments. Apply only to single-tone backgrounds
 * (light/dark/primary/secondary) via .website-section-solid-{soft|vignette|grain}.
 * Each variant uses ::after (animation overlays use ::before, so the two
 * layers compose without colliding - a Primary section can be both Soft
 * and Pulse-animated at the same time). Default 'flat' adds no class,
 * meaning no ::after is generated and existing rows render identically. */
.website-section-solid-soft,
.website-section-solid-vignette,
.website-section-solid-grain {
    position: relative;
    isolation: isolate;
    overflow: hidden;
}
.website-section-solid-soft::after,
.website-section-solid-vignette::after,
.website-section-solid-grain::after {
    content: "";
    position: absolute;
    inset: 0;
    pointer-events: none;
    z-index: 0;
}

/* Soft: gentle radial highlight in upper-center, like ambient room light
 * spilling onto the section. Works on both light and dark themes because
 * white-at-low-alpha reads as "lift" against any base color. */
.website-section-solid-soft::after {
    background: radial-gradient(ellipse 80% 60% at 50% 30%, rgba(255, 255, 255, 0.12), transparent 60%);
}

/* Vignette: darken the corners so the eye is pulled toward whatever
 * content sits in the center. Good for hero / CTA sections. Black-at-
 * low-alpha works on light themes; on dark sections the corners just go
 * a touch deeper - subtle but visible.
 * --wb-vignette-inset-top / -bottom (views/website/_section.php, EVC-009):
 * pull the overlay in by a shape divider's height on that edge, so the
 * vignette never bleeds into the divider's own fill band. Default 0 keeps
 * the historical inset: 0 (full-bleed) when there is no divider. */
.website-section-solid-vignette::after {
    inset: var(--wb-vignette-inset-top, 0) 0 var(--wb-vignette-inset-bottom, 0) 0;
    background: radial-gradient(ellipse at 50% 50%, transparent 50%, rgba(0, 0, 0, 0.22) 100%);
}

/* Grain: faint film-grain noise overlay. SVG fractalNoise inlined as a
 * data URL so no separate request fires. mix-blend-mode: overlay lets
 * the grain ride on top of any color without washing it out. */
.website-section-solid-grain::after {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.55'/%3E%3C/svg%3E");
    background-size: 160px 160px;
    opacity: 0.08;
    mix-blend-mode: overlay;
}

/* Shape dividers. Decorative SVG silhouettes pinned to a section's top and/or
 * bottom edge, rendered as child <svg> elements (NOT ::before/::after, which are
 * already used by animation + solid-surface variants, and because the two edges
 * must be independent). Paths are authored top-filled; the bottom edge flips
 * vertically so one path map serves both. The renderer gates these off image and
 * mesh backgrounds. The path fills with `currentColor`, set by a role class
 * below or an inline `color:` for a Brand Palette hex. preserveAspectRatio="none"
 * lets the 1200x120 viewBox stretch to the element, so height is pure CSS. The
 * section's `overflow: hidden` keeps each divider clipped to its own box; the
 * section gap is 0 so neighbours butt together and the silhouette reads as a
 * transition. */
.website-section-divider {
    position: absolute;
    left: 0;
    width: 100%;
    /* +1px over the nominal height, pulled 1px past the section's own edge
     * below (--top/--bottom) - eliminates a hairline seam of the section's
     * own background-color that Chromium's compositor otherwise leaves
     * between this element and the section box during a sub-pixel CSS
     * transform (e.g. an AOS entrance animation translateY mid-transition -
     * confirmed to happen at specific fractional-pixel offsets). The extra
     * pixel lands inside each shape's own already-solid flat edge (every
     * divider path, including custom-drawn ones, is authored fully filled
     * along that edge), so it's invisible once the transform settles. */
    height: calc(var(--wb-divider-h, 80px) + 1px);
    display: block;
    line-height: 0;
    pointer-events: none;
    /* Sit BELOW the background overlay (.wb-bg-overlay is z-index 1) so a
     * page/section overlay tints the divider exactly like it tints the section
     * background - otherwise the silhouette stays bright while its section
     * darkens in dark mode (or under any overlay), and the fill no longer
     * matches. Still above the section's own solid background (z-index 0 on a
     * positioned child paints over the wrapper's background-color) and below
     * content (.container is lifted to z-index 2). */
    z-index: 0;
}
.website-section-divider--top {
    top: -1px;
}
.website-section-divider--bottom {
    bottom: -1px;
    transform: scaleY(-1);
}
.website-section-divider--flip {
    transform: scaleX(-1);
}
.website-section-divider--bottom.website-section-divider--flip {
    transform: scaleY(-1) scaleX(-1);
}
/* 'Shadow' paint style (divider_{edge}_style = shadow): soft drop-shadow that
 * follows the silhouette's alpha. Offset is in the element's local space, so
 * the bottom edge's scaleY(-1) flips it along with the shape - the shadow
 * always lands on the tip side, i.e. inside the divider's own section, where
 * the section's overflow:hidden cannot clip it. */
.website-divider-style-shadow {
    filter: drop-shadow(0 6px 8px rgb(0 0 0 / 0.28));
}

/* Keep section content above the dividers, which sit in the section's vertical
 * padding band. Content is wrapped in .container (title, contained content,
 * empty states), so lifting it clears any tall divider. */
.website-section > .container {
    position: relative;
    z-index: 2;
}

/* Section Width scale (config[content_width]). 'contained' is plain .container
 * (unchanged 1320px @ xxl); these modifiers narrow (or widen) it further.
 * .container's own max-width has to be overridden - the compound selector's
 * higher specificity (0,2,0 vs 0,1,0) wins regardless of stylesheet order, so
 * this doesn't have to fight Bootstrap's cascade position.
 * 'reading' intentionally reuses --website-page-max-width (860px) - the same
 * value EntitySpotlightSectionWidget's own 'reading' content width already
 * means, so the two width vocabularies agree instead of colliding. */
.container.wb-w-wide {
    max-width: var(--website-width-wide, 1600px);
}
.container.wb-w-narrow {
    max-width: var(--website-width-narrow, 960px);
}
.container.wb-w-reading {
    max-width: var(--website-page-max-width, 860px);
}

/* Side padding (config[section_padding_x] family), WB-002 fix. Without this,
 * the .container's own max-width + centering auto-margins absorb the side
 * padding entirely: as long as the container is narrower than the space the
 * padding leaves available, the browser just re-centers it, so nothing moves
 * on screen until the padding exceeds that natural centering slack (which on
 * a real desktop viewport is roughly 90-100px per side - exactly the reported
 * "no visible change until ~90px" and "0px never reaches the edge").
 *
 * `.wb-spadx` (added by views/website/_section.php only when a side-padding
 * value is actually set) drops the .container's own max-width so the section
 * padding becomes the ONLY horizontal constraint - 0 = flush to the viewport
 * edge, every step up is a real, visible inset. A content-width step
 * (wide/narrow/reading) still applies on top as an additional interior cap;
 * plain 'contained' has no extra cap, matching the tester's stated
 * expectation that padding alone controls the inset in that case. */
.website-section.wb-spadx > .container {
    max-width: none;
    padding-left: 0;
    padding-right: 0;
}
.website-section.wb-spadx > .container.wb-w-wide {
    max-width: var(--website-width-wide, 1600px);
}
.website-section.wb-spadx > .container.wb-w-narrow {
    max-width: var(--website-width-narrow, 960px);
}
.website-section.wb-spadx > .container.wb-w-reading {
    max-width: var(--website-page-max-width, 860px);
}

/* A section widget that emits its own inner .container (Hero, FAQ, Team, Tabs,
 * ...) must not re-cap it back down to 1320px inside a wider wrapper, and
 * must not double the side gutter. */
.wb-w-wide .container,
.wb-w-narrow .container,
.wb-w-reading .container {
    max-width: none;
    padding-left: 0;
    padding-right: 0;
}

/* Content spacing (config[content_gap] / global Content Spacing). Widgets
 * mark their PRIMARY grid with `wb-grid` (the row of cards / columns / icon
 * tiles - never secondary rows like button groups). The overrides below are
 * scoped to `.wb-cgap`, which _section.php adds ONLY when a per-section or
 * site-wide value exists - an untouched grid keeps its own g-* / g-lg-* /
 * literal gap exactly as before (a plain var() fallback could not do that:
 * it would still replace a `g-lg-5`). Bootstrap's .g-4 sets --bs-gutter-x/y
 * ON the row at (0,1,0); the compound selectors are (0,3,0) and win regardless
 * of sheet order. CSS-grid / flex grids read the same var through `gap`. */
.website-section.wb-cgap .wb-grid {
    --bs-gutter-x: var(--website-content-gap, 1.5rem);
    --bs-gutter-y: var(--website-content-gap, 1.5rem);
}
.website-section.wb-cgap .split-bio-grid.wb-grid {
    gap: var(--website-content-gap, var(--space-10, 40px));
}
/* CTA banner rows used Bootstrap `gap-4` (1.5rem !important) before the
 * marker; this base rule keeps that exact default, the scoped one overrides. */
.website-section .cta-banner-inner.wb-grid {
    gap: 1.5rem;
}
.website-section.wb-cgap .cta-banner-inner.wb-grid {
    gap: var(--website-content-gap, 1.5rem);
}
.website-section.wb-cgap .steps-horizontal.wb-grid {
    gap: var(--website-content-gap, 0);
}

/* Preset fill roles -> brand CSS vars. Values mirror the section background
 * colours defined above so a divider can match its neighbour exactly:
 * light = --website-bg-light, dark = --website-bg-dark, surface = --website-bg,
 * primary = --color-primary-600, secondary = --color-secondary-600. */
.website-divider-fill-primary {
    color: var(--color-primary-600);
}
.website-divider-fill-secondary {
    color: var(--color-secondary-600);
}
.website-divider-fill-light {
    color: var(--website-bg-light, #ffffff);
}
.website-divider-fill-dark {
    color: var(--website-bg-dark, #18181b);
}
.website-divider-fill-surface {
    color: var(--website-bg, var(--bg-primary));
}
.website-divider-fill-white {
    color: #fff;
}

/* Shorter on small screens so a tall wave doesn't swallow the viewport while
 * keeping full width (preserveAspectRatio="none"). */
@media (max-width: 767.98px) {
    .website-section-divider {
        height: clamp(28px, calc(var(--wb-divider-h, 80px) * 0.6), var(--wb-divider-h, 80px));
    }
}

/* Buttons inside dark/primary/secondary/gradient/mesh sections keep their
 * own colors. `color: revert` here used to fall through to the UA link-blue
 * for <a class="btn">, which is what made CTAs render as ugly Bootstrap blue
 * on the public site. `inherit` keeps the section's text color for plain
 * link-style buttons; explicit .btn-* classes below override per variant.
 * Exclude .btn-light / .btn-white: their near-white background needs the
 * Bootstrap-default dark text, otherwise inheriting the section's white text
 * would render the label invisible. */
.website-section-dark .btn:not(.btn-light):not(.btn-white),
.website-section-primary .btn:not(.btn-light):not(.btn-white),
.website-section-secondary .btn:not(.btn-light):not(.btn-white),
.website-section-gradient .btn:not(.btn-light):not(.btn-white),
.website-section-mesh .btn:not(.btn-light):not(.btn-white) {
    color: inherit;
}

/* The rule above only fixes text color, not border-color, so an outline button's
 * border stayed the raw brand color (var(--color-primary/secondary-500)) even after
 * its text switched to the section's ambient color - on a background close to that
 * brand hue the border (and on custombg, the untouched text too, since its own
 * `* { color: inherit }` rule below loses specificity to the base outline rule)
 * could match the backdrop closely enough to look invisible. Also extends coverage
 * to custombg, which the rule above doesn't reach at all. `border-color: currentColor`
 * ties the border to whatever `color` resolves to, so text and border are always the
 * same (already-correct) hue. Placed before the base outline rules below so equal-
 * specificity hover/focus states there still win via source order. */
.website-section-dark .btn.btn-outline-brand-primary,
.website-section-dark .btn.btn-outline-brand-secondary,
.website-section-primary .btn.btn-outline-brand-primary,
.website-section-primary .btn.btn-outline-brand-secondary,
.website-section-secondary .btn.btn-outline-brand-primary,
.website-section-secondary .btn.btn-outline-brand-secondary,
.website-section-gradient .btn.btn-outline-brand-primary,
.website-section-gradient .btn.btn-outline-brand-secondary,
.website-section-mesh .btn.btn-outline-brand-primary,
.website-section-mesh .btn.btn-outline-brand-secondary,
.website-section-custombg .btn.btn-outline-brand-primary,
.website-section-custombg .btn.btn-outline-brand-secondary {
    color: inherit;
    border-color: currentColor;
}

/* Brand-primary CTA buttons on primary / gradient / mesh sections would
 * otherwise fill with the section's own primary color (invisible button).
 * Swap to the org's secondary brand token so the CTA visibly pops against
 * the primary background, regardless of how pastel or saturated the org's
 * primary is. Secondary section keeps the default brand-primary button -
 * the colors don't collide so no swap needed there. Routed through the same
 * --wb-btn- / --website-btn-primary- tiers as the base rule below it, just
 * with the swapped secondary-token innermost default. */
.website-section-primary .btn-brand-primary,
.website-section-gradient .btn-brand-primary,
.website-section-mesh .btn-brand-primary {
    background-color: var(--wb-btn-bg, var(--website-btn-primary-bg, var(--website-button-bg-color, var(--color-secondary-500))));
    border-color: var(--wb-btn-bg, var(--website-btn-primary-bg, var(--website-button-bg-color, var(--color-secondary-500))));
    color: var(--wb-btn-text, var(--website-btn-primary-text, var(--website-button-text-color, #fff)));
}
.website-section-primary .btn-brand-primary:hover,
.website-section-primary .btn-brand-primary:focus,
.website-section-gradient .btn-brand-primary:hover,
.website-section-gradient .btn-brand-primary:focus,
.website-section-mesh .btn-brand-primary:hover,
.website-section-mesh .btn-brand-primary:focus {
    background-color: var(--wb-btn-hover-bg, var(--website-btn-primary-hover-bg, var(--website-button-hover-bg-color, var(--color-secondary-600))));
    border-color: var(--wb-btn-hover-bg, var(--website-btn-primary-hover-bg, var(--website-button-hover-bg-color, var(--color-secondary-600))));
    color: var(--wb-btn-hover-text, var(--website-btn-primary-hover-text, var(--website-button-hover-text-color, #fff)));
}
.website-section-primary .btn-brand-primary:active,
.website-section-gradient .btn-brand-primary:active,
.website-section-mesh .btn-brand-primary:active {
    background-color: var(--wb-btn-hover-bg, var(--website-btn-primary-hover-bg, var(--website-button-hover-bg-color, var(--color-secondary-700))));
    border-color: var(--wb-btn-hover-bg, var(--website-btn-primary-hover-bg, var(--website-button-hover-bg-color, var(--color-secondary-700))));
    color: var(--wb-btn-hover-text, var(--website-btn-primary-hover-text, var(--website-button-hover-text-color, #fff)));
}

/* Base brand-button classes. These live in web/css/theme.css, which is only
 * loaded by the main platform layout (ThemeAsset). Org websites and the builder
 * preview render through the website layout (views/layouts/website-minimal.php),
 * which loads THIS file but not theme.css - so without these rules the section
 * "Button Style" presets (btn-brand-primary / -secondary / outline-*) fell back
 * to a bare Bootstrap .btn (transparent, no border) and every option looked
 * identical (text only). Ported here so brand buttons render on org sites too.
 *
 * Compound `.btn.btn-brand-*` selector (specificity 0-2-0) is deliberate, not
 * decorative: Bootstrap's own base `.btn` rule sets the SAME properties
 * (background-color/border-color/color, all via --bs-btn-* custom props
 * defaulting to transparent) at the SAME specificity (0-1-0) as a bare
 * `.btn-brand-primary` would have. Two equal-specificity rules resolve by
 * source order, and on the website layout bootstrap.css loads AFTER this
 * file - so a single-class selector here would silently lose to Bootstrap's
 * transparent default (exactly the bug this block fixes). The compound
 * selector always outweighs Bootstrap's `.btn`, regardless of load order.
 *
 * Filled variants take their label color from the org's contrast token
 * (--website-on-primary / --website-on-secondary, emitted by
 * OrgWebsiteBrandingHelper::getCssOverrides()) so a near-white brand color still
 * yields legible text; the #fff fallback preserves the platform default.
 *
 * Four-tier button color cascade (button-roles round). Every property below
 * is a nested var() chain, innermost first:
 *   1. --color-primary-500 etc.       - the original palette default
 *   2. --website-button-*             - the Appearance tab's "All" knobs (WB-008,
 *                                        unchanged keys/behavior)
 *   3. --website-btn-{role}-*         - the Appearance tab's per-role tabs
 *                                        (Primary/Secondary/Outline), :root-scoped
 *   4. --wb-btn-*                     - a single button's own override, set
 *                                        inline by OrgWebsiteSection::buttonOverrideAttrs()
 * An unset tier is simply absent (no CSS declaration), so var() falls straight
 * through to the next - a site that only ever used the old global knobs
 * renders byte-identical. Applies uniformly to brand-primary/-secondary and to
 * the outline variants (resting AND hover, since --wb-btn-bg/-text now also
 * cover the outline's transparent resting fill and border/label color, not
 * just its hover fill as before). */
.btn.btn-brand-primary {
    background-color: var(--wb-btn-bg, var(--website-btn-primary-bg, var(--website-button-bg-color, var(--color-primary-500))));
    border-color: var(--wb-btn-bg, var(--website-btn-primary-bg, var(--website-button-bg-color, var(--color-primary-500))));
    color: var(--wb-btn-text, var(--website-btn-primary-text, var(--website-button-text-color, var(--website-on-primary, #fff))));
    transition: all var(--duration-200) var(--ease-in-out);
}
.btn.btn-brand-primary:hover,
.btn.btn-brand-primary:focus {
    background-color: var(--wb-btn-hover-bg, var(--website-btn-primary-hover-bg, var(--website-button-hover-bg-color, var(--color-primary-600))));
    border-color: var(--wb-btn-hover-bg, var(--website-btn-primary-hover-bg, var(--website-button-hover-bg-color, var(--color-primary-600))));
    color: var(--wb-btn-hover-text, var(--website-btn-primary-hover-text, var(--website-button-hover-text-color, var(--website-on-primary, #fff))));
}
.btn.btn-brand-primary:active {
    background-color: var(--wb-btn-hover-bg, var(--website-btn-primary-hover-bg, var(--website-button-hover-bg-color, var(--color-primary-700))));
    border-color: var(--wb-btn-hover-bg, var(--website-btn-primary-hover-bg, var(--website-button-hover-bg-color, var(--color-primary-700))));
    color: var(--wb-btn-hover-text, var(--website-btn-primary-hover-text, var(--website-button-hover-text-color, var(--website-on-primary, #fff))));
}
.btn.btn-brand-primary:focus-visible {
    box-shadow: var(--focus-ring-shadow);
}

/* Outline resting state has no palette background to override, so its own
 * tier-3/tier-2 knobs (Border & Text / Background) are distinct from the
 * filled variants' - see --website-btn-outline-* below, shared by BOTH
 * outline-primary and outline-secondary (one Outline tab, not two). */
.btn.btn-outline-brand-primary {
    color: var(--wb-btn-text, var(--website-btn-outline-color, var(--color-primary-500)));
    border-color: var(--wb-btn-text, var(--website-btn-outline-color, var(--color-primary-500)));
    background-color: var(--wb-btn-bg, var(--website-btn-outline-bg, transparent));
    transition: all var(--duration-200) var(--ease-in-out);
}
.btn.btn-outline-brand-primary:hover,
.btn.btn-outline-brand-primary:focus {
    background-color: var(--wb-btn-hover-bg, var(--website-btn-outline-hover-bg, var(--website-button-hover-bg-color, var(--color-primary-500))));
    border-color: var(--wb-btn-hover-bg, var(--website-btn-outline-hover-bg, var(--website-button-hover-bg-color, var(--color-primary-500))));
    color: var(--wb-btn-hover-text, var(--website-btn-outline-hover-text, var(--website-button-hover-text-color, var(--website-on-primary, #fff))));
}

.btn.btn-brand-secondary {
    background-color: var(--wb-btn-bg, var(--website-btn-secondary-bg, var(--website-button-bg-color, var(--color-secondary-500))));
    border-color: var(--wb-btn-bg, var(--website-btn-secondary-bg, var(--website-button-bg-color, var(--color-secondary-500))));
    color: var(--wb-btn-text, var(--website-btn-secondary-text, var(--website-button-text-color, var(--website-on-secondary, #fff))));
    transition: all var(--duration-200) var(--ease-in-out);
}
.btn.btn-brand-secondary:hover,
.btn.btn-brand-secondary:focus {
    background-color: var(--wb-btn-hover-bg, var(--website-btn-secondary-hover-bg, var(--website-button-hover-bg-color, var(--color-secondary-600))));
    border-color: var(--wb-btn-hover-bg, var(--website-btn-secondary-hover-bg, var(--website-button-hover-bg-color, var(--color-secondary-600))));
    color: var(--wb-btn-hover-text, var(--website-btn-secondary-hover-text, var(--website-button-hover-text-color, var(--website-on-secondary, #fff))));
}

.btn.btn-outline-brand-secondary {
    color: var(--wb-btn-text, var(--website-btn-outline-color, var(--color-secondary-500)));
    border-color: var(--wb-btn-text, var(--website-btn-outline-color, var(--color-secondary-500)));
    background-color: var(--wb-btn-bg, var(--website-btn-outline-bg, transparent));
    transition: all var(--duration-200) var(--ease-in-out);
}
.btn.btn-outline-brand-secondary:hover,
.btn.btn-outline-brand-secondary:focus {
    background-color: var(--wb-btn-hover-bg, var(--website-btn-outline-hover-bg, var(--website-button-hover-bg-color, var(--color-secondary-500))));
    border-color: var(--wb-btn-hover-bg, var(--website-btn-outline-hover-bg, var(--website-button-hover-bg-color, var(--color-secondary-500))));
    color: var(--wb-btn-hover-text, var(--website-btn-outline-hover-text, var(--website-button-hover-text-color, var(--website-on-secondary, #fff))));
}

/* Tier-4 safety net: a per-button override still needs to land on a button
 * whose Button Style preset fell back to a plain (non-brand) Bootstrap class
 * (e.g. CtaBannerWidget's secondary button before a style is chosen -
 * OrgWebsiteSection::buttonStyleClass()'s $default is 'btn btn-outline-secondary').
 * This class is added ALONGSIDE the original Bootstrap variant class, never
 * replacing it, so Bootstrap's own --bs-btn-* custom properties (declared by
 * that variant class, consumed by Bootstrap's base .btn rule) are still
 * present on the element - falling back to them (instead of an unfallbacked
 * var()) means an unset --wb-btn-* here reproduces the plain Bootstrap look
 * exactly, rather than resolving to CSS's invalid-at-computed-value default
 * (transparent/inherit) the way a bare var() would. Reads the same --wb-btn-*
 * custom props OrgWebsiteSection::buttonOverrideAttrs() emits inline. */
.btn.wb-btn-custom {
    background-color: var(--wb-btn-bg, var(--bs-btn-bg));
    border-color: var(--wb-btn-bg, var(--bs-btn-border-color));
    color: var(--wb-btn-text, var(--bs-btn-color));
}
.btn.wb-btn-custom:hover,
.btn.wb-btn-custom:focus {
    background-color: var(--wb-btn-hover-bg, var(--bs-btn-hover-bg));
    border-color: var(--wb-btn-hover-bg, var(--bs-btn-hover-border-color));
    color: var(--wb-btn-hover-text, var(--bs-btn-hover-color));
}

/* Fix text visibility inside dark-variant widgets (HeroSectionWidget bg-dark, etc.) */
.website-section .bg-dark,
.website-section .bg-primary {
    color: white;
}

.website-section .bg-dark *,
.website-section .bg-dark h1,
.website-section .bg-dark h2,
.website-section .bg-dark h3,
.website-section .bg-dark p,
.website-section .bg-dark span,
.website-section .bg-primary *,
.website-section .bg-primary h1,
.website-section .bg-primary h2,
.website-section .bg-primary h3,
.website-section .bg-primary p,
.website-section .bg-primary span {
    color: white !important;
}

.website-section .bg-dark .text-muted,
.website-section .bg-primary .text-muted,
.website-section .bg-dark .lead.text-muted,
.website-section .bg-primary .lead.text-muted {
    color: rgba(255, 255, 255, 0.7) !important;
}

.website-section .bg-dark .btn,
.website-section .bg-primary .btn {
    color: revert !important;
}

/* Image background base. `position: relative` + `isolation: isolate`
 * provide a stacking context for the Ken Burns inner frame and overlay
 * pseudos. The auto-50%-black overlay that used to live here has been
 * replaced by the Phase 2 .website-section-image-overlay-* variants -
 * each section now explicitly opts into a darken/lighten/tint overlay
 * via the admin's Image sub-row. */
.website-section-image {
    background-size: cover;
    background-position: center;
    background-repeat: no-repeat;
    position: relative;
    isolation: isolate;
    overflow: hidden;
}

.website-section-image > * {
    position: relative;
    z-index: 1;
}

/* Section title */
.website-section-title {
    font-family: var(--font-family-heading);
    /* Title size (EVC-016) moved to the wrapper-scoped .wb-tsize rule below
       (same shape as .wb-tfont-*), so it can also reach a widget-drawn
       headline - this selector alone could never win against .website-body h2
       (higher specificity, later in the cascade). Plain --font-size-3xl here,
       same as before the knob existed. */
    font-size: var(--font-size-3xl);
    font-weight: var(--font-weight-bold);
    text-align: center;
    /* --wb-delim-gap-bottom: per-section Delimiter Spacing knob (views/website/_section.php).
       Only ever set inline on a builder section title; listing headers and other
       accent headings never carry it and keep this literal fallback. */
    margin-bottom: var(--wb-delim-gap-bottom, var(--space-12));
}

/* Alignable section title. .wb-title-align is added (in place of the old fixed
   --center modifier) only to the builder section <h2> in views/website/_section.php,
   so ONLY those headings follow the Title Alignment control - listing headers and
   other .website-section-title uses keep the centered base above untouched.
   --website-title-align is set on :root by the global Title Alignment (Appearance
   -> Layout & Type) or inline on the section wrapper by a per-section override;
   unset = centered. Placed after .website-section-title so it wins by source order
   (equal specificity). The delimiter-bar counterpart is .wb-title-align::after below. */
.wb-title-align {
    text-align: var(--website-title-align, center);
}

/* Alignable body copy opt-in for widget markup that isn't already covered by
   the fixed .website-body p/.lead/etc selector list (web/css/website-theme.css
   ~line 437). --website-text-align's :root default is the literal `inherit`
   (line 45 above), so this is only safe on elements with no prior hardcoded
   alignment - a widget that needs a non-left default resolves it in PHP via
   OrgWebsiteSection::textAlignClass() instead of this class. */
.wb-text-align {
    text-align: var(--website-text-align);
}

/* --- Customizable listing-page header (views/website/_listing-header.php) ---
   A menu item can override a listing route's title / subtitle and add a live
   search box; --left flips the block (and its accent bar) to the left. The
   title keeps its own margin-bottom via .website-section-title, but when a
   subtitle / search follow it we tighten that so the header reads as one unit. */
.website-listing-header {
    margin-bottom: var(--space-12);
}
.website-listing-header .website-section-title {
    margin-bottom: var(--space-4, 1rem);
}
.website-listing-header--left {
    text-align: left;
}
.website-listing-header--left .website-section-title {
    text-align: left;
}
.website-listing-header--center {
    text-align: center;
}
.website-listing-header--right {
    text-align: right;
}
.website-listing-header--right .website-section-title {
    text-align: right;
}
/* A banner ('items' / 'image' / 'color' mode) renders inside the page's own
   .container (see views/website/_listing-header.php) - restructuring every
   listing view to host it outside the container was not worth it for one
   rule, so break the band out to full viewport width here instead. The
   band's OWN content stays centered via its nested .container
   (widgets/views/listing-hero.php), so only the background bleeds. */
.website-listing-header--bleed {
    width: 100vw;
    margin-left: calc(50% - 50vw);
    margin-right: calc(50% - 50vw);
}
.website-listing-subtitle {
    max-width: 720px;
    margin-bottom: var(--space-4, 1rem);
}
.website-listing-header--center .website-listing-subtitle {
    margin-left: auto;
    margin-right: auto;
}
.website-listing-search {
    max-width: 480px;
    margin-top: var(--space-4, 1rem);
}
.website-listing-header--center .website-listing-search {
    margin-left: auto;
    margin-right: auto;
}
.website-listing-header--right .website-listing-subtitle,
.website-listing-header--right .website-listing-search {
    margin-left: auto;
    margin-right: 0;
}
/* The listing header renders in BOTH chrome contexts (org-site layouts and
   the platform layout via embedded community routes - see the dual-context
   note in views/website/_listing-header.php), so its per-title font override
   cannot rely on the .website-body scope the section rules use. */
.website-listing-header .wb-font-heading { font-family: var(--font-family-heading); }
.website-listing-header .wb-font-body { font-family: var(--font-family-body); }
.website-listing-header .wb-font-brand { font-family: var(--font-family-brand, var(--font-family-heading)); }
.website-listing-header .wb-font-menu { font-family: var(--font-family-menu-left); }
.website-listing-header .wb-font-tagline { font-family: var(--font-family-tagline, var(--font-family-body)); }
.website-listing-count {
    margin-top: var(--space-3, 0.75rem);
    font-size: var(--font-size-sm, 0.875rem);
    opacity: 0.75;
}

/* ----------------------------------------------------------
 * Footer
 * ---------------------------------------------------------- */

.website-footer {
    background-color: var(--website-footer-bg);
    color: var(--website-footer-text);
    /* --website-footer-padding-top/-bottom (per-side px override, set inline
     * by the builder's Vertical Spacing sliders) win when present; otherwise
     * both sides fall back to the density preset's --website-footer-padding-y. */
    padding-top: var(--website-footer-padding-top, var(--website-footer-padding-y));
    padding-bottom: var(--website-footer-padding-bottom, var(--website-footer-padding-y));
    margin-top: auto;
    /* Frame (Footer tab's "Top edge & frame" card) - rounded top corners +
     * side inset, both zero by default so an untouched org keeps today's
     * square, edge-to-edge footer exactly. A configurable border-top-width
     * is deliberately NOT here: every org site already carries a permanent
     * 1px secondary-tinted top accent border (the unconditional
     * ".website-footer { border-top: ... }" rule further down, under
     * "Footer accents") as part of the theme's decorative language, and a
     * second competing border-top declaration would either fight that rule
     * silently or require reproducing its exact default to avoid a visual
     * regression on every existing site. Not worth the risk for this pass. */
    border-radius: var(--website-footer-frame-radius, 0) var(--website-footer-frame-radius, 0) 0 0;
    margin-inline: var(--website-footer-frame-inset, 0);
}

/* .wb-bg-layer already clips its own content (overflow: hidden, see
 * web/css/website-background.css) - inheriting the radius keeps a footer
 * background image/video rounded off with the frame instead of bleeding
 * past its corners. */
.website-footer > .wb-bg-layer {
    border-radius: inherit;
}

/* Horizontal breathing room for footer content. The base rule pads the
 * footer vertically only, so left/right spacing came from the inner
 * Bootstrap container gutter (~0.75rem) alone - too tight, especially in
 * the "wide" (container-fluid) layout. Padding the inner content wrappers
 * (not the footer itself) keeps the full-bleed .wb-bg-layer background
 * edge-to-edge while insetting the columns/strips. */
.website-footer > .container,
.website-footer > .container-fluid,
.website-footer > [data-web="footer-pre-strip"],
.website-footer > [data-web="footer-post-strip"] {
    padding-inline: var(--website-footer-padding-x);
}

/* Loosen the column gutter natively (org info / sitemap / content /
 * newsletter) - g-4's 1.5rem reads tight for a footer. */
.website-footer .row {
    --bs-gutter-x: var(--website-footer-gutter);
    --bs-gutter-y: var(--website-footer-gutter);
}

/* Nudge the stacked below-column blocks (downloads / social / legal /
 * custom text) from mt-4 (1.5rem). The 0,2,0 selector beats the mt-4
 * utility (0,1,0) without !important. */
.website-footer [data-web="footer-downloads"],
.website-footer [data-web="footer-social-row"],
.website-footer [data-web="footer-legal"],
.website-footer [data-web="footer-text"] {
    margin-top: var(--website-footer-gutter);
}

/* Footer spacing density (org_website_footer_padding). Normal = the :root
 * defaults above, so no rule is needed for it. Compact/Spacious re-scale
 * both the horizontal padding and the inter-item gutter; the custom props
 * cascade to the inner container / row / blocks that reference them. */
.website-footer[data-footer-padding="compact"] {
    --website-footer-padding-y: var(--space-3);
    --website-footer-padding-x: clamp(0.75rem, 2vw, 1.25rem);
    --website-footer-gutter: var(--space-6);
}
.website-footer[data-footer-padding="spacious"] {
    --website-footer-padding-y: var(--space-12);
    --website-footer-padding-x: clamp(2rem, 6vw, 5rem);
    --website-footer-gutter: var(--space-12);
}

/* Layout & typography (Footer tab). Attribute-gated like [data-footer-padding]
 * above - absent when unset, so an untouched org keeps left-aligned, normal-
 * size, unconstrained-width footer text exactly as today. */
.website-footer[data-footer-align="center"] {
    text-align: center;
}
.website-footer[data-footer-align="right"] {
    text-align: right;
}
.website-footer[data-footer-text-scale="small"] {
    --website-footer-text-scale: 0.9;
}
.website-footer[data-footer-text-scale="large"] {
    --website-footer-text-scale: 1.15;
}
/* Max width caps + centers the SAME inner wrappers the horizontal padding
 * rule already targets, so it composes with both the fluid and wide
 * .container(-fluid) choice instead of fighting it. Gated on the attribute
 * (not a bare var() fallback) - .container already carries Bootstrap's own
 * responsive max-width steps, and a fallback value here would override
 * those unconditionally for every footer, not just ones that set a cap. */
.website-footer[data-footer-max-width] > .container,
.website-footer[data-footer-max-width] > .container-fluid {
    max-width: var(--website-footer-max-width);
    margin-inline: auto;
}

.website-footer-grid {
    display: grid;
    grid-template-columns: 2fr 1fr 1fr;
    gap: var(--space-10);
}

@media (max-width: 767.98px) {
    .website-footer-grid {
        grid-template-columns: 1fr;
        gap: var(--space-8);
    }
}

.website-footer h5 {
    color: var(--website-footer-heading);
    font-family: var(--font-family-heading);
    font-weight: var(--font-weight-semibold);
    font-size: calc(var(--font-size-base) * var(--website-footer-text-scale, 1));
    margin-bottom: var(--space-4);
}

/* Column titles (Sitemap, Upcoming Events, newsletter heading, Downloads, ...)
 * render as unclassed h6 in views/layouts/_website_footer.php - color-only so
 * their existing size/spacing (set per-element or by the accordion CSS) is
 * untouched; without this they fell through to the global h1-h6 rule and
 * went invisible on the Dark/Primary footer presets. */
.website-footer h6 {
    color: var(--website-footer-heading);
}

.website-footer p {
    color: var(--website-footer-text);
    margin-bottom: var(--space-2);
    font-size: calc(var(--font-size-sm) * var(--website-footer-text-scale, 1));
}

/* Bootstrap's .text-muted carries its own !important color, which is dark
 * and unreadable on the Dark/Primary footer presets (e.g. the newsletter
 * sub-message in _website_footer.php). Re-anchor it to the footer text
 * token instead of the page's muted-text token. */
.website-footer .text-muted {
    color: var(--website-footer-text) !important;
    opacity: 0.85;
}

.website-footer a {
    color: var(--website-footer-link);
    text-decoration: none;
    transition: var(--transition-colors);
}

.website-footer a:hover {
    color: var(--website-footer-link-hover);
}

/* `.website-body` prefix bumps specificity to 0,2,0 so this beats the
 * `.website-body h6` heading-font rule above; the footer brand is an
 * h6 element and would otherwise stay on --font-family-heading. */
.website-body .website-footer-brand {
    color: var(--website-footer-heading);
    font-family: var(--font-family-brand, var(--font-family-heading));
    font-weight: var(--font-weight-semibold);
}

.website-footer-logo {
    max-height: 56px;
    max-width: 100%;
    width: auto;
    display: block;
}

.website-footer-eventure-logo {
    height: 12px;
    width: auto;
    vertical-align: middle;
    opacity: 0.7;
}

.website-footer-powered-by {
    color: var(--website-footer-text, inherit);
    font-size: 0.7rem;
    font-weight: 400;
    letter-spacing: 0.02em;
    opacity: 0.45;
    text-decoration: none;
    transition: opacity 0.2s ease;
}

.website-footer-powered-by:hover,
.website-footer-powered-by:focus {
    opacity: 0.85;
    color: inherit;
    text-decoration: none;
}

.website-footer-text {
    color: var(--website-footer-text);
    font-size: calc(var(--font-size-sm) * var(--website-footer-text-scale, 1));
}

.website-footer-social {
    display: flex;
    gap: var(--space-3);
    margin-top: var(--space-4);
}

.website-footer-social a {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    border-radius: var(--radius-full);
    background-color: var(--color-neutral-800);
    color: var(--website-footer-text);
    font-size: var(--font-size-base);
    transition: var(--transition-all);
}

/* Size + shape (Footer tab's Social card). Attribute-gated on the wrapper -
 * absent when unset, so an untouched org keeps today's 36px circle exactly. */
.website-footer-social[data-social-size="sm"] a {
    width: 28px;
    height: 28px;
    font-size: var(--font-size-sm);
}
.website-footer-social[data-social-size="lg"] a {
    width: 44px;
    height: 44px;
    font-size: var(--font-size-lg);
}
.website-footer-social[data-social-shape="square"] a {
    border-radius: var(--radius-md, 6px);
}
.website-footer-social[data-social-shape="plain"] a {
    border-radius: 0;
    background-color: transparent;
}

.website-footer-social a:hover {
    background-color: var(--color-primary-600);
    color: white;
    transform: translateY(-2px);
}

.website-footer-bottom {
    border-top: 1px solid var(--website-footer-border);
    margin-top: var(--space-10);
    padding-top: var(--space-6);
    display: flex;
    justify-content: space-between;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-4);
}

.website-footer-bottom p {
    margin: 0;
}

.website-footer-powered {
    font-size: var(--font-size-xs);
    opacity: 0.7;
}

.website-footer-powered:hover {
    opacity: 1;
}

/* ----------------------------------------------------------
 * Blog listing on website
 * ---------------------------------------------------------- */

.website-blog-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
    gap: var(--space-8);
}

.website-blog-card {
    border: 1px solid var(--border-default);
    border-radius: var(--radius-xl);
    overflow: hidden;
    transition: var(--transition-shadow);
    background-color: var(--bg-primary);
}

.website-blog-card:hover {
    box-shadow: var(--shadow-lg);
}

.website-blog-card img {
    width: 100%;
    height: 200px;
    object-fit: cover;
}

.website-blog-card-body {
    padding: var(--space-6);
}

.website-blog-card-body h3 {
    font-family: var(--font-family-heading);
    font-size: var(--font-size-lg);
    font-weight: var(--font-weight-semibold);
    margin-bottom: var(--space-2);
}

.website-blog-card-body h3 a {
    color: var(--text-primary);
    text-decoration: none;
}

.website-blog-card-body h3 a:hover {
    color: var(--color-primary-600);
}

.website-blog-card-meta {
    font-size: var(--font-size-sm);
    color: var(--text-muted);
    margin-bottom: var(--space-3);
}

/* ----------------------------------------------------------
 * Events listing on website
 * ---------------------------------------------------------- */

.website-events-list {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
}

/* ----------------------------------------------------------
 * Contact page
 * ---------------------------------------------------------- */

.website-contact-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--space-10);
    max-width: 1000px;
    margin: 0 auto;
    padding: var(--space-12) var(--space-4);
}

@media (max-width: 767.98px) {
    .website-contact-grid {
        grid-template-columns: 1fr;
    }
}

/* Info column is a flex column so the map can be pushed to the bottom and
 * line up with the foot of the form card in the adjacent grid cell. */
.website-contact-info {
    display: flex;
    flex-direction: column;
}

.website-contact-info h2 {
    font-family: var(--font-family-heading);
    margin-bottom: var(--space-2);
}

.website-contact-intro {
    max-width: 42ch;
}

.website-contact-items {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}

/* Contact detail as a tile: subtle surface, circular tinted icon, hover lift. */
.website-contact-item {
    display: flex;
    align-items: center;
    gap: var(--space-4);
    padding: var(--space-4);
    border-radius: var(--radius-lg, 0.75rem);
    background: var(--bs-tertiary-bg, rgba(127, 127, 127, 0.08));
    border: 1px solid var(--bs-border-color, rgba(127, 127, 127, 0.15));
    transition: transform 0.15s ease, box-shadow 0.15s ease, border-color 0.15s ease;
}

.website-contact-item:hover {
    transform: translateY(-2px);
    box-shadow: 0 6px 18px rgba(0, 0, 0, 0.12);
    border-color: var(--color-primary-600);
}

.website-contact-item i {
    flex: 0 0 auto;
    width: 44px;
    height: 44px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    background: color-mix(in srgb, var(--color-primary-600) 16%, transparent);
    color: var(--color-primary-600);
    font-size: 1.05rem;
    margin: 0;
}

.website-contact-item-label {
    display: block;
    font-weight: 600;
    margin-bottom: 2px;
}

.website-contact-item-value,
.website-contact-item-value a {
    color: var(--bs-body-color, inherit);
    line-height: 1.5;
    text-decoration: none;
}

.website-contact-item-value a:hover {
    color: var(--color-primary-600);
    text-decoration: underline;
}

/* ----------------------------------------------------------
 * Responsive adjustments
 * ---------------------------------------------------------- */

@media (max-width: 991.98px) {
    :root {
        --website-section-padding-y: var(--space-12);
        --website-page-padding-y: var(--space-8);
    }

    .website-section-title {
        font-size: var(--font-size-2xl);
    }
}

@media (max-width: 575.98px) {
    :root {
        --website-section-padding-y: var(--space-8);
    }

    .website-footer-bottom {
        flex-direction: column;
        text-align: center;
    }
}

/* =============================================================================
 * Header effects: sticky, glass, shrink-on-scroll.
 * Toggled by OrgWebsiteNavWidget via classes on the <nav> element.
 * =========================================================================== */

.website-navbar-sticky {
    position: sticky;
    top: 0;
    z-index: 1030;
}

.website-navbar-glass {
    background-color: rgba(255, 255, 255, 0.65);
    backdrop-filter: blur(12px) saturate(150%);
    -webkit-backdrop-filter: blur(12px) saturate(150%);
    border-bottom-color: rgba(255, 255, 255, 0.2);
}

[data-theme="dark"] .website-navbar-glass {
    background-color: rgba(17, 17, 17, 0.55);
    border-bottom-color: rgba(255, 255, 255, 0.08);
}

.website-navbar-shrinkable {
    transition: min-height 0.25s ease, padding 0.25s ease, box-shadow 0.25s ease;
}

.website-navbar-shrinkable .website-nav-logo {
    transition: max-height 0.25s ease;
}

.website-navbar-shrunk {
    min-height: 52px;
    box-shadow: var(--shadow-sm);
}

.website-navbar-shrunk .navbar-brand {
    font-size: var(--font-size-base);
}

.website-navbar-shrunk .website-nav-logo {
    max-height: calc(var(--website-nav-logo-height, 40px) * 0.7);
}

/* =============================================================================
 * Footer style variants. Default .website-footer is dark - variants re-map the
 * --website-footer-* custom properties so existing rules keep working.
 * =========================================================================== */

.website-footer-light {
    --website-footer-bg: var(--color-neutral-100);
    --website-footer-text: var(--color-neutral-700);
    --website-footer-heading: var(--color-neutral-900);
    --website-footer-link: var(--color-neutral-700);
    --website-footer-link-hover: var(--color-primary-600);
    --website-footer-border: var(--color-neutral-300);
}

[data-theme="dark"] .website-footer-light {
    --website-footer-bg: var(--color-neutral-100);
    --website-footer-text: var(--color-neutral-700);
    --website-footer-heading: var(--color-neutral-900);
    --website-footer-border: var(--color-neutral-300);
}

.website-footer-primary {
    --website-footer-bg: var(--color-primary-600);
    --website-footer-text: rgba(255, 255, 255, 0.85);
    --website-footer-heading: #ffffff;
    --website-footer-link: rgba(255, 255, 255, 0.85);
    --website-footer-link-hover: #ffffff;
    --website-footer-border: rgba(255, 255, 255, 0.2);
}

.website-footer-transparent {
    --website-footer-bg: transparent;
    --website-footer-text: var(--text-secondary);
    --website-footer-heading: var(--text-primary);
    --website-footer-link: var(--text-secondary);
    --website-footer-link-hover: var(--color-primary-600);
    --website-footer-border: var(--border-default);
}

.website-footer-legal {
    text-align: center;
}

.website-footer-legal a {
    text-decoration: none;
}

/* =============================================================================
 * Secondary color accents (opt-in)
 *
 * The --color-secondary-* palette is emitted by OrgWebsiteBrandingHelper using
 * the explicit secondary color, or an analogous +30° fallback derived from
 * primary. Rules below are opt-in: existing markup is untouched unless it
 * carries one of these variant classes. Keep the secondary color to 10-20%
 * of the visual field - it is an accent, not a co-primary.
 * =========================================================================== */

/* --- Buttons (outline only; solid .btn-secondary intentionally not styled) - */
.website-body .btn-outline-secondary,
.website-navbar .btn-outline-secondary {
    color: var(--color-secondary-600);
    border-color: var(--color-secondary-600);
    background-color: transparent;
    transition: background-color var(--duration-150, 150ms) var(--ease-in-out), color var(--duration-150, 150ms) var(--ease-in-out), border-color var(--duration-150, 150ms) var(--ease-in-out);
}

.website-body .btn-outline-secondary:hover,
.website-navbar .btn-outline-secondary:hover {
    color: var(--color-secondary-700);
    border-color: var(--color-secondary-700);
    background-color: color-mix(in srgb, var(--color-secondary-500) 12%, transparent);
}

.website-body .btn-outline-secondary:focus,
.website-navbar .btn-outline-secondary:focus {
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-secondary-500) 25%, transparent);
}

[data-bs-theme="dark"] .website-body .btn-outline-secondary,
[data-bs-theme="dark"] .website-navbar .btn-outline-secondary {
    color: var(--color-secondary-300);
    border-color: var(--color-secondary-400);
}

[data-bs-theme="dark"] .website-body .btn-outline-secondary:hover,
[data-bs-theme="dark"] .website-navbar .btn-outline-secondary:hover {
    color: var(--color-secondary-200, var(--color-secondary-300));
    border-color: var(--color-secondary-300);
    background-color: color-mix(in srgb, var(--color-secondary-500) 18%, transparent);
}

/* --- Badges / tags / chips ------------------------------------------------- */
.website-body .badge.bg-secondary,
.website-body .website-chip-secondary {
    background-color: var(--color-secondary-50) !important;
    color: var(--color-secondary-700);
    border: 1px solid var(--color-secondary-200, var(--color-secondary-300));
}

[data-bs-theme="dark"] .website-body .badge.bg-secondary,
[data-bs-theme="dark"] .website-body .website-chip-secondary {
    background-color: rgba(var(--color-secondary-500-rgb), 0.15) !important;
    color: var(--color-secondary-200, var(--color-secondary-300));
    border-color: rgba(var(--color-secondary-500-rgb), 0.25);
}

.website-chip-secondary {
    display: inline-flex;
    align-items: center;
    padding: 0.15rem 0.55rem;
    border-radius: var(--radius-full, 999px);
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-medium);
    line-height: 1.4;
}

/* --- Links & decorative icons --------------------------------------------- */
.website-link-accent {
    color: var(--website-link-color, var(--color-secondary-600));
    text-decoration: none;
    transition: color var(--duration-150, 150ms) var(--ease-in-out);
}

.website-link-accent:hover {
    color: var(--website-link-hover-color, var(--color-secondary-700));
    text-decoration: underline;
}

.website-icon-accent {
    color: var(--color-secondary-500);
}

[data-bs-theme="dark"] .website-link-accent {
    color: var(--website-link-color, var(--color-secondary-300));
}

[data-bs-theme="dark"] .website-link-accent:hover {
    color: var(--website-link-hover-color, var(--color-secondary-200, var(--color-secondary-300)));
}

[data-bs-theme="dark"] .website-icon-accent {
    color: var(--color-secondary-300);
}

/* --- Heading underline (48px bar below h2/h3) ----------------------------- */
.website-heading-accent {
    display: block;
    position: relative;
    /* --wb-delim-gap-top: per-section Delimiter Spacing knob (views/website/_section.php).
       Only ever set inline on a builder section title; every other accent heading
       leaves it unset and keeps this literal fallback (the historical gap). */
    padding-bottom: var(--wb-delim-gap-top, calc(var(--space-3, 0.75rem) + 4px));
}

.website-heading-accent::after {
    content: "";
    position: absolute;
    left: 0;
    bottom: 0;
    /* Per-section delimiter knobs (views/website/_section.php). The vars are
       only ever set on a configured section title; every other accent heading
       leaves them unset and falls back to the historical 48px x 3px bar.
       --wb-delim-resolved is the single colour source every style reads: a
       custom picked colour, else the theme default (--wb-delim-default, swapped
       in dark mode below), else the light secondary. Routing all styles through
       one variable - and NEVER overriding background-color per-theme - keeps the
       textured styles (dashed/dotted/gradient/dots) transparent in their gaps. */
    --wb-delim-resolved: var(--wb-delim-color, var(--wb-delim-default, var(--color-secondary-500)));
    width: var(--wb-delim-w, 48px);
    height: var(--wb-delim-h, 3px);
    border-radius: 2px;
    background-color: var(--wb-delim-resolved);
}

.text-center > .website-heading-accent::after,
.website-heading-accent.text-center::after,
.website-heading-accent--center::after {
    left: 50%;
    transform: translateX(-50%);
}

.website-heading-accent--right::after {
    left: auto;
    right: 0;
    transform: none;
}

/* Var-driven delimiter-bar position for the alignable section title
   (views/website/_section.php adds .wb-title-align in place of the old fixed
   --center modifier). The bar follows the same --wb-delim-* recipe that
   WebsiteDesignThemeRegistry::titleAlignCssVars() emits for the title text -
   set on :root (global Title Alignment) or inline on the section wrapper (a
   per-section override). Unset vars fall back to CENTER, reproducing the
   historical centered bar exactly. Placed after the --center rule so it wins by
   source order for the section title (equal specificity); other accent headings
   (listing headers) never carry .wb-title-align, so they keep their own rules. */
.wb-title-align::after {
    left: var(--wb-delim-left, 50%);
    right: var(--wb-delim-right, auto);
    transform: var(--wb-delim-tx, translateX(-50%));
}

/* Dark mode: only swap the DEFAULT colour (a CSS variable on the heading, which
   inherits into ::after). We do NOT touch background-color here - doing so would
   win on specificity over the textured styles below and paint a solid fill
   behind their transparent gaps. A custom --wb-delim-color still wins. */
[data-bs-theme="dark"] .website-heading-accent {
    --wb-delim-default: var(--color-secondary-300);
}

/* ---- Per-section title delimiter styles --------------------------------- */
/* These classes only ever land on a configured section <h2>, so retexturing
   the ::after bar here never touches the other .website-heading-accent
   headings. 'bar' is the base ::after above and needs no rule. Each style
   reads --wb-delim-resolved (custom colour -> theme default -> secondary) so the
   colour picker and dark mode both compose with every style. Keys are the
   same OrgWebsiteSection::getDelimiterStyles() values; the builder picker
   previews these recipes via getDelimiterPreviewStyles() (currentColor in
   place of --wb-delim-resolved) - keep both copies in sync. */
.website-delim-none::after {
    display: none;
}

/* Square-ended hairline that spans the full content width. */
.website-delim-line::after {
    width: 100%;
    border-radius: 0;
}

/* Two stacked thin lines (top + bottom band, transparent gap between). */
.website-delim-double::after {
    border-radius: 0;
    background-color: transparent;
    background-image: linear-gradient(
        to bottom,
        var(--wb-delim-resolved) 0 35%,
        transparent 35% 65%,
        var(--wb-delim-resolved) 65% 100%
    );
    min-height: 5px;
}

/* Repeating dashes. */
.website-delim-dashed::after {
    border-radius: 0;
    background-color: transparent;
    background-image: repeating-linear-gradient(
        to right,
        var(--wb-delim-resolved) 0 8px,
        transparent 8px 14px
    );
}

/* Repeating dots (tight square stops). */
.website-delim-dotted::after {
    background-color: transparent;
    background-image: repeating-linear-gradient(
        to right,
        var(--wb-delim-resolved) 0 3px,
        transparent 3px 9px
    );
}

/* Solid bar fading out to transparent on the right. */
.website-delim-gradient::after {
    background-color: transparent;
    background-image: linear-gradient(
        to right,
        var(--wb-delim-resolved),
        transparent
    );
}

/* Solid bar fading out to transparent on the left. */
.website-delim-gradient_left::after {
    background-color: transparent;
    background-image: linear-gradient(
        to right,
        transparent,
        var(--wb-delim-resolved)
    );
}

/* Solid centre, fading out to transparent on both ends. */
.website-delim-gradient_both::after {
    background-color: transparent;
    background-image: linear-gradient(
        to right,
        transparent,
        var(--wb-delim-resolved) 35% 65%,
        transparent
    );
}

/* Three evenly spaced dots. Each cell holds one centered disc. */
.website-delim-dots::after {
    background-color: transparent;
    background-image: radial-gradient(
        circle,
        var(--wb-delim-resolved) 40%,
        transparent 45%
    );
    background-size: 33.33% 100%;
    background-repeat: repeat-x;
}

/* --- Hero / section corner accent shape ----------------------------------- */
.website-section-accent-corner {
    position: relative;
    overflow: hidden;
}

.website-section-accent-corner::before {
    content: "";
    position: absolute;
    top: -80px;
    right: -80px;
    width: 240px;
    height: 240px;
    border-radius: 50%;
    background-color: var(--color-secondary-500);
    opacity: 0.12;
    filter: blur(40px);
    pointer-events: none;
    z-index: 0;
}

.website-section-accent-corner.website-section-accent-corner-left::before {
    right: auto;
    left: -80px;
}

.website-section-accent-corner > * {
    position: relative;
    z-index: 1;
}

[data-bs-theme="dark"] .website-section-accent-corner::before {
    opacity: 0.18;
    background-color: var(--color-secondary-400);
}

/* --- Card left-border accent (opt-in on .website-blog-card or .card) ----- */
.website-card-accent-secondary {
    border-left: 3px solid var(--color-secondary-500);
}

[data-bs-theme="dark"] .website-card-accent-secondary {
    border-left-color: var(--color-secondary-300);
}

/* --- Card hover: lifted shadow with secondary tint ----------------------- */
.website-card-hover-accent {
    transition: box-shadow 200ms var(--ease-in-out, ease), transform 200ms var(--ease-in-out, ease);
}

.website-card-hover-accent:hover {
    box-shadow: 0 8px 24px color-mix(in srgb, var(--color-secondary-500) 22%, transparent);
    transform: translateY(-2px);
}

[data-bs-theme="dark"] .website-card-hover-accent:hover {
    box-shadow: 0 8px 24px color-mix(in srgb, var(--color-secondary-500) 32%, transparent);
}

/* --- Site-wide text selection + form focus ring (subtle) ----------------- */
.website-body ::selection {
    background-color: var(--color-secondary-100, var(--color-secondary-200));
    color: var(--color-secondary-900, var(--color-secondary-800));
}

[data-bs-theme="dark"] .website-body ::selection {
    background-color: var(--color-secondary-800, var(--color-secondary-700));
    color: var(--color-secondary-50);
}

.website-body .form-control:focus,
.website-body .form-select:focus,
.website-body .form-check-input:focus {
    border-color: var(--color-secondary-500);
    box-shadow: 0 0 0 2px color-mix(in srgb, var(--color-secondary-500) 15%, transparent);
}

/* --- Footer accents ------------------------------------------------------ */
.website-footer {
    border-top: 1px solid color-mix(in srgb, var(--color-secondary-500) 25%, transparent);
}

.website-footer-social-link {
    transition: color var(--duration-150, 150ms) var(--ease-in-out, ease);
}

.website-footer-social-link:hover {
    color: var(--color-secondary-500);
}

.website-footer-legal a {
    transition: color var(--duration-150, 150ms) var(--ease-in-out, ease);
}

.website-footer-legal a:hover {
    color: var(--color-secondary-500);
}

[data-bs-theme="dark"] .website-footer-social-link:hover,
[data-bs-theme="dark"] .website-footer-legal a:hover {
    color: var(--color-secondary-300);
}

/* --- Breadcrumbs (utility; markup opt-in) -------------------------------- */
.website-breadcrumbs {
    color: var(--text-muted);
    font-size: var(--font-size-sm);
}

.website-breadcrumbs a {
    color: var(--text-muted);
    text-decoration: none;
    transition: color var(--duration-150, 150ms) var(--ease-in-out, ease);
}

.website-breadcrumbs a:hover {
    color: var(--color-secondary-600);
}

.website-breadcrumbs .active {
    color: var(--color-secondary-600);
    font-weight: var(--font-weight-medium);
}

[data-bs-theme="dark"] .website-breadcrumbs a:hover,
[data-bs-theme="dark"] .website-breadcrumbs .active {
    color: var(--color-secondary-300);
}

/* --- Pagination ---------------------------------------------------------- */
.website-body .pagination .page-link {
    color: var(--color-secondary-700);
    transition: background-color var(--duration-150, 150ms) var(--ease-in-out, ease), color var(--duration-150, 150ms) var(--ease-in-out, ease);
}

.website-body .pagination .page-link:hover {
    background-color: var(--color-secondary-50);
    color: var(--color-secondary-800);
}

.website-body .pagination .page-item.active .page-link {
    background-color: var(--color-secondary-500);
    border-color: var(--color-secondary-500);
    color: #fff;
}

[data-bs-theme="dark"] .website-body .pagination .page-link {
    color: var(--color-secondary-300);
}

[data-bs-theme="dark"] .website-body .pagination .page-link:hover {
    background-color: rgba(var(--color-secondary-500-rgb), 0.15);
    color: var(--color-secondary-200, var(--color-secondary-300));
}

[data-bs-theme="dark"] .website-body .pagination .page-item.active .page-link {
    background-color: var(--color-secondary-400);
    border-color: var(--color-secondary-400);
    color: var(--color-neutral-950);
}

/* --- Prose links (inside .website-page-content) -------------------------- */
.website-page-content a:not(.btn):not(.website-chip-secondary):not(.website-link-accent) {
    color: var(--website-link-color, var(--color-secondary-600));
    text-decoration-line: underline;
    text-decoration-color: var(--website-link-decoration-color, color-mix(in srgb, var(--color-secondary-500) 40%, transparent));
    text-decoration-thickness: 1px;
    text-underline-offset: 3px;
    transition: color var(--duration-150, 150ms) var(--ease-in-out, ease), text-decoration-color var(--duration-150, 150ms) var(--ease-in-out, ease);
}

.website-page-content a:not(.btn):not(.website-chip-secondary):not(.website-link-accent):hover {
    color: var(--website-link-hover-color, var(--color-secondary-700));
    text-decoration-color: var(--website-link-decoration-color, var(--color-secondary-500));
}

[data-bs-theme="dark"] .website-page-content a:not(.btn):not(.website-chip-secondary):not(.website-link-accent) {
    color: var(--website-link-color, var(--color-secondary-300));
}

[data-bs-theme="dark"] .website-page-content a:not(.btn):not(.website-chip-secondary):not(.website-link-accent):hover {
    color: var(--website-link-hover-color, var(--color-secondary-200, var(--color-secondary-300)));
}

/* =============================================================================
 * Layout & Type presets
 *
 * Admins choose presets in the Appearance tab (Corner Radius, Card Elevation,
 * Button Weight/Uppercase, Base Font Size, Heading Scale). Each preset emits
 * scoped --website-* custom properties from OrgWebsiteBrandingHelper, which
 * the rules below consume with fallbacks to the global design tokens.
 * =========================================================================== */

/* Buttons: weight / text-transform / tracking / shape */
.website-body .btn,
.website-navbar .btn,
.website-footer .btn {
    font-weight: var(--website-button-weight, var(--font-weight-medium));
    text-transform: var(--website-button-transform, none);
    letter-spacing: var(--website-button-tracking, 0);
    border-radius: var(--website-button-radius, var(--radius-md));
}


/* Card elevation + radius (listings across blog / events / shop, plus
 * the standalone .website-blog-card). Hover accent from
 * .website-card-hover-accent still layers on top. */
.website-body .card,
.website-body .website-blog-card {
    box-shadow: var(--website-card-shadow, var(--shadow-sm));
    border: var(--website-card-border, none);
    border-radius: var(--website-radius-lg, var(--radius-lg));
}

/* Inputs inherit the global radius too */
.website-body .form-control,
.website-body .form-select {
    border-radius: var(--website-radius-md, var(--radius-md));
}

/* Typography scale */
.website-body {
    font-size: var(--website-font-size-base, var(--font-size-base));
}

.website-body h1 {
    font-size: var(--website-font-size-h1, var(--font-size-4xl));
}

.website-body h2 {
    font-size: var(--website-font-size-h2, var(--font-size-3xl));
}

.website-body h3 {
    font-size: var(--website-font-size-h3, var(--font-size-2xl));
}

.website-body .display-1,
.website-body .display-2,
.website-body .display-3,
.website-body .display-4,
.website-body .display-5,
.website-body .display-6 {
    font-size: var(--website-font-size-display, var(--font-size-5xl));
}

/* =============================================================================
 * Announcement bar
 *
 * Thin strip rendered above the navbar. Four style variants (primary / secondary
 * / dark / light). Dismissible by default; close state persists via cookie.
 * =========================================================================== */

.website-announcement {
    padding: 0.5rem 2.5rem 0.5rem 1rem;
    text-align: center;
    font-size: var(--font-size-sm);
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-3);
    position: relative;
    line-height: 1.4;
}

.website-announcement-primary {
    background-color: var(--color-primary-600);
    color: #fff;
}

.website-announcement-secondary {
    background-color: var(--color-secondary-600);
    color: #fff;
}

.website-announcement-dark {
    background-color: var(--color-neutral-900);
    color: var(--color-neutral-100);
}

.website-announcement-light {
    background-color: var(--color-neutral-100);
    color: var(--color-neutral-900);
    border-bottom: 1px solid var(--border-default);
}

.website-announcement a {
    color: inherit;
    text-decoration: underline;
}

.website-announcement .website-announcement-cta {
    color: inherit;
    border-color: currentColor;
    padding: 0.15rem 0.75rem;
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-medium);
    text-decoration: none;
    border-radius: var(--website-button-radius, var(--radius-md));
    border: 1px solid currentColor;
    transition: background-color var(--duration-150, 150ms) var(--ease-in-out, ease);
}

.website-announcement .website-announcement-cta:hover {
    background-color: color-mix(in srgb, currentColor 12%, transparent);
}

.website-announcement-dismiss {
    position: absolute;
    right: 0.5rem;
    top: 50%;
    transform: translateY(-50%);
    background: transparent;
    border: 0;
    color: inherit;
    opacity: 0.7;
    cursor: pointer;
    padding: 0.25rem 0.5rem;
    line-height: 1;
    font-size: 1rem;
}

.website-announcement-dismiss:hover {
    opacity: 1;
}

/* =======================================================================
 * New widget styles - inspired by tahliastanton.com
 * ======================================================================= */

/* ----------------------------------------------------------------------
 * Header: double-layer mode (utility row above main navbar)
 * Activated by .header-double-layer on the <header> element.
 * ---------------------------------------------------------------------- */
.header-double-layer .header-top-bar {
    width: 100%;
    padding: 0.5rem 0;
    border-bottom: 1px solid var(--color-neutral-200, rgba(0, 0, 0, 0.06));
    background-color: inherit;
    font-size: var(--font-size-sm, 14px);
}
.header-double-layer .header-top-bar-inner {
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    align-items: center;
    gap: 1rem;
    min-height: 36px;
}
.header-double-layer.header-top-bar-logo-left .header-top-bar-inner {
    grid-template-columns: auto 1fr 1fr;
}
.header-top-bar-left { justify-self: start; display: flex; align-items: center; gap: 0.75rem; }
.header-top-bar-logo { justify-self: center; display: flex; align-items: center; justify-content: center; }
.header-double-layer.header-top-bar-logo-left .header-top-bar-logo { justify-self: start; }
.header-top-bar-right { justify-self: end; display: flex; align-items: center; gap: 0.75rem; }
.header-top-bar-item { display: inline-flex; align-items: center; }
.header-top-bar-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    border-radius: 50%;
    color: inherit;
    text-decoration: none;
    transition: background-color 0.2s var(--ease-out, ease);
}
.header-top-bar-icon:hover { background-color: rgba(0, 0, 0, 0.05); }
.header-top-bar-logo-img { max-height: 32px; width: auto; }
.header-top-bar-logo-link { text-decoration: none; color: inherit; display: inline-flex; align-items: center; }
/* Hide the navbar brand when the top bar already shows the logo */
.header-double-layer .navbar-brand { display: none; }
@media (max-width: 767.98px) {
    .header-double-layer .header-top-bar-inner { grid-template-columns: auto 1fr auto; gap: 0.5rem; }
    .header-top-bar-right { gap: 0.25rem; }
}

/* ----------------------------------------------------------------------
 * Marquee (infinite horizontal scroll)
 * ---------------------------------------------------------------------- */
.marquee-widget {
    width: 100%;
    overflow: hidden;
    position: relative;
}
.marquee-track {
    display: flex;
    flex-wrap: nowrap;
    width: max-content;
    gap: var(--space-8, 32px);
    align-items: center;
    animation: marquee-scroll-left var(--marquee-duration, 40s) linear infinite;
    will-change: transform;
}
.marquee-track[data-direction="right"] { animation-name: marquee-scroll-right; }
.marquee-widget[data-pause-on-hover="1"]:hover .marquee-track { animation-play-state: paused; }
@keyframes marquee-scroll-left {
    from { transform: translateX(0); }
    to { transform: translateX(-50%); }
}
@keyframes marquee-scroll-right {
    from { transform: translateX(-50%); }
    to { transform: translateX(0); }
}
.marquee-item { flex: 0 0 auto; display: flex; align-items: center; justify-content: center; }
.marquee-mode-image-strip .marquee-item { min-width: 120px; }
.marquee-mode-image-strip .marquee-item-img {
    max-height: 60px;
    width: auto;
    object-fit: contain;
    filter: grayscale(30%);
    opacity: 0.8;
    transition: filter 0.3s, opacity 0.3s;
}
.marquee-mode-image-strip .marquee-item:hover .marquee-item-img { filter: none; opacity: 1; }
.marquee-mode-card-strip .marquee-item { min-width: 280px; max-width: 280px; }
.marquee-mode-card-strip .marquee-card-item > * { width: 100%; }
@media (prefers-reduced-motion: reduce) {
    .marquee-track { animation: none; }
    .marquee-widget { overflow-x: auto; scroll-snap-type: x mandatory; }
}

/* ----------------------------------------------------------------------
 * Media Grid (preset layouts for image / video / text tiles)
 * ---------------------------------------------------------------------- */
.media-grid { display: grid; width: 100%; }
.media-grid-gap-none { gap: 0; }
.media-grid-gap-sm { gap: var(--space-2, 8px); }
.media-grid-gap-md { gap: var(--space-4, 16px); }
.media-grid-gap-lg { gap: var(--space-6, 24px); }
.media-grid-2x2-mosaic { grid-template-columns: 1fr 1fr; grid-template-rows: auto auto; }
.media-grid-3-col-strip { grid-template-columns: 1fr 1fr 1fr; }
.media-grid-hero-plus-4 { grid-template-columns: 2fr 1fr 1fr; grid-template-rows: 1fr 1fr; }
.media-grid-hero-plus-4 > .media-grid-tile:first-child { grid-row: span 2; }
.media-grid-tile {
    position: relative;
    overflow: hidden;
    display: block;
    background: var(--color-neutral-100, #f5f5f5);
    min-height: 200px;
    text-decoration: none;
    color: inherit;
}
.media-grid-rounded .media-grid-tile { border-radius: var(--radius-lg, 12px); }
.media-grid-tile-img,
.media-grid-tile-video {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: transform 0.4s var(--ease-out, ease);
}
.media-grid-tile:hover .media-grid-tile-img,
.media-grid-tile:hover .media-grid-tile-video { transform: scale(1.03); }
.media-grid-tile-caption {
    position: absolute;
    bottom: 0; left: 0; right: 0;
    padding: 1rem;
    background: linear-gradient(to top, rgba(0,0,0,0.6), transparent);
    color: #fff;
    font-size: var(--font-size-sm, 14px);
}
.media-grid-tile-text {
    padding: 2rem;
    display: flex;
    flex-direction: column;
    justify-content: center;
    height: 100%;
    background: var(--color-neutral-50, #fafafa);
}
.media-grid-tile-heading { margin: 0 0 0.5rem; font-size: var(--font-size-xl, 20px); }
.media-grid-tile-body { margin: 0; color: var(--color-neutral-600, #666); }
.media-grid-tile-empty { background: transparent; min-height: 0; }
@media (max-width: 767.98px) {
    .media-grid-2x2-mosaic,
    .media-grid-3-col-strip,
    .media-grid-hero-plus-4 {
        grid-template-columns: 1fr;
        grid-template-rows: none;
    }
    .media-grid-hero-plus-4 > .media-grid-tile:first-child { grid-row: auto; }
}

/* ----------------------------------------------------------------------
 * Image & Text (2-col image + text; internal name "split-bio")
 * ---------------------------------------------------------------------- */
.split-bio { width: 100%; }
.split-bio-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--space-10, 40px);
    align-items: center;
}
/* Vertical alignment of the image against the text column (columns layout).
   Base rule above keeps center as the fallback for sections saved before the
   knob existed; these modifiers override it. */
.split-bio-valign-top .split-bio-grid { align-items: start; }
.split-bio-valign-center .split-bio-grid { align-items: center; }
.split-bio-valign-bottom .split-bio-grid { align-items: end; }
.split-bio-image-right .split-bio-grid {
    grid-template-columns: 1fr 1fr;
    direction: rtl;
}
/* No image uploaded: one full-width column instead of a half-empty 2-col grid. */
.split-bio-no-image .split-bio-grid {
    grid-template-columns: 1fr;
    direction: ltr;
}
.split-bio-no-image .split-bio-text { max-width: none; }
.split-bio-image-right .split-bio-grid > * { direction: ltr; }
.split-bio-image { display: flex; justify-content: center; }
.split-bio-image-img { display: block; width: 100%; height: auto; object-fit: cover; }
.split-bio-shape-rectangle .split-bio-image-img { border-radius: 0; }
.split-bio-shape-rounded .split-bio-image-img { border-radius: var(--radius-xl, 16px); }
.split-bio-shape-circle .split-bio-image-img {
    border-radius: 50%;
    aspect-ratio: 1 / 1;
    max-width: 440px;
    margin: 0 auto;
}
.split-bio-shape-full-bleed .split-bio-image-img {
    border-radius: 0;
    aspect-ratio: 4 / 5;
    width: 100%;
}
.split-bio-text { max-width: 560px; }
.split-bio-heading { font-size: var(--font-size-4xl, 36px); margin: 0 0 1rem; line-height: 1.15; }
.split-bio-body { color: var(--color-neutral-700, #4a4a4a); line-height: 1.65; margin-bottom: 1.5rem; }
.split-bio-button { display: inline-block; }
/* Wrap layout: the image floats and the body text flows around it (Word-style).
   Drops the grid to a block flow so the text is a normal sibling of the float. */
.split-bio-wrap .split-bio-grid {
    display: block;
    direction: ltr;
}
.split-bio-wrap .split-bio-image {
    float: left;
    width: 42%;
    max-width: 420px;
    margin: 0 var(--space-10, 40px) var(--space-6, 24px) 0;
}
.split-bio-wrap.split-bio-image-right .split-bio-image {
    float: right;
    margin: 0 0 var(--space-6, 24px) var(--space-10, 40px);
}
.split-bio-wrap .split-bio-text { max-width: none; }
.split-bio-wrap .split-bio-grid::after { content: ""; display: block; clear: both; }
@media (max-width: 767.98px) {
    .split-bio-grid,
    .split-bio-image-right .split-bio-grid {
        grid-template-columns: 1fr;
        direction: ltr;
        gap: var(--space-6, 24px);
    }
    /* Un-float on mobile so the image stacks above the text instead of
       squeezing a narrow column beside a few cramped words. */
    .split-bio-wrap .split-bio-image {
        float: none;
        width: 100%;
        max-width: none;
        margin: 0 0 var(--space-6, 24px) 0;
    }
}

/* ----------------------------------------------------------------------
 * Promo Trio (2-4 tall tiles with image + overlay text + CTA)
 * ---------------------------------------------------------------------- */
.promo-trio { display: grid; width: 100%; gap: var(--space-4, 16px); }
.promo-trio-count-2 { grid-template-columns: repeat(2, 1fr); }
.promo-trio-count-3 { grid-template-columns: repeat(3, 1fr); }
.promo-trio-count-4 { grid-template-columns: repeat(4, 1fr); }
.promo-trio-tile {
    position: relative;
    display: block;
    overflow: hidden;
    background-color: var(--color-neutral-200, #e5e5e5);
    background-size: cover;
    background-position: center;
    text-decoration: none;
    color: #fff;
    border-radius: var(--radius-lg, 12px);
    transition: transform 0.3s var(--ease-out, ease);
}
.promo-trio-tile:hover { transform: translateY(-4px); }
.promo-trio-height-short .promo-trio-tile { aspect-ratio: 4 / 3; }
.promo-trio-height-medium .promo-trio-tile { aspect-ratio: 3 / 4; }
.promo-trio-height-tall .promo-trio-tile { aspect-ratio: 2 / 3; }
.promo-trio-tile-overlay {
    position: absolute;
    inset: 0;
    display: flex;
    padding: 2rem;
    color: inherit;
}
.promo-trio-tile-overlay::before {
    content: "";
    position: absolute;
    inset: 0;
    background: rgba(0, 0, 0, var(--promo-trio-overlay-opacity, 0.4));
    z-index: 0;
}
.promo-trio-pos-top .promo-trio-tile-overlay { align-items: flex-start; }
.promo-trio-pos-center .promo-trio-tile-overlay { align-items: center; }
.promo-trio-pos-bottom .promo-trio-tile-overlay { align-items: flex-end; }
.promo-trio-tile-content { position: relative; z-index: 1; width: 100%; }
.promo-trio-tile-heading { margin: 0 0 0.5rem; font-size: var(--font-size-2xl, 24px); line-height: 1.2; color: inherit; }
.promo-trio-tile-subheading { margin: 0 0 1rem; opacity: 0.9; line-height: 1.5; color: inherit; }
.promo-trio-tile-cta {
    display: inline-block;
    padding: 0.5rem 1rem;
    border: 1px solid currentColor;
    border-radius: var(--radius-md, 8px);
    font-size: var(--font-size-sm, 14px);
    font-weight: var(--font-weight-medium, 500);
    transition: background-color 0.2s var(--ease-out, ease);
}
.promo-trio-tile:hover .promo-trio-tile-cta { background-color: rgba(255, 255, 255, 0.15); }
@media (max-width: 767.98px) {
    .promo-trio-count-2,
    .promo-trio-count-3,
    .promo-trio-count-4 { grid-template-columns: 1fr; }
    .promo-trio-height-short .promo-trio-tile,
    .promo-trio-height-medium .promo-trio-tile,
    .promo-trio-height-tall .promo-trio-tile { aspect-ratio: 16 / 9; }
}

/* ----------------------------------------------------------------------
 * Hero compositional variants (split-media / minimal-left / overlay-center)
 * ---------------------------------------------------------------------- */
/* Split media - copy beside a tall image panel. */
.hero-variant-split-media .hero-split-image {
    width: 100%;
    min-height: 320px;
    border-radius: var(--website-radius-lg, 0.875rem);
    box-shadow: var(--website-card-shadow, var(--shadow-md));
}
.hero-variant-split-media .hero-split-copy p {
    margin-left: 0;
    margin-right: 0;
}
@media (max-width: 991.98px) {
    .hero-variant-split-media .hero-split-media {
        margin-top: 1.5rem;
    }
    .hero-variant-split-media .hero-split-image {
        min-height: 220px;
    }
}

/* Minimal left - a single left-aligned headline column with whitespace. */
.hero-variant-minimal-left .container {
    max-width: 760px;
    margin-left: 0;
}
.hero-variant-minimal-left h1 {
    margin-left: 0;
}
.hero-variant-minimal-left p {
    margin-left: 0 !important;
    margin-right: 0;
}

/* Overlay center - text over a full-bleed image with a dark scrim (scrim and
   light text are emitted by the widget; nothing extra needed here, but keep a
   hook for future tuning). */
.hero-variant-overlay-center {
    position: relative;
}

/* ----------------------------------------------------------------------
 * Hero Slider (Bootstrap fade-carousel mode on HeroSectionWidget)
 * ---------------------------------------------------------------------- */
.hero-slider { position: relative; overflow: hidden; }
.hero-slider-item {
    /* 60vh is the historical default (Banner height on Auto). When the
       Banner height knob is set, views/website/_section.php overrides
       --wb-hero-slide-min-h to 0 so the wrapper's own .wb-minh min-height
       (which counts the true total, wrapper padding included) governs
       instead of the smaller of the two winning by accident. --wb-vh-unit
       rebases the vh basis inside the builder's auto-height preview iframe
       (see .wb-minh above); unset on the real site. */
    min-height: var(--wb-hero-slide-min-h, calc(60 * var(--wb-vh-unit, 1vh)));
    background-size: cover;
    background-position: center;
    display: flex;
    align-items: center;
    justify-content: center;
    color: #fff;
}
.hero-slider-overlay {
    position: absolute;
    inset: 0;
    background: rgba(0, 0, 0, 0.35);
    z-index: 1;
}
.hero-slider-content {
    position: relative;
    z-index: 2;
    text-align: center;
    max-width: 800px;
}
.hero-slider-heading {
    font-size: var(--font-size-5xl, 48px);
    margin: 0 0 1rem;
    color: inherit;
    line-height: 1.1;
}
.hero-slider-subheading {
    font-size: var(--font-size-xl, 20px);
    margin: 0 0 1.5rem;
    color: inherit;
    opacity: 0.95;
}
.hero-slider .carousel-indicators button { background-color: rgba(255, 255, 255, 0.6); }
.hero-slider .carousel-indicators button.active { background-color: #fff; }

/* Dual-image hover overlay (.card-img-hover) now lives in site.css so it
 * applies on every layout, not just org-website pages. */

/* ----------------------------------------------------------------------
 * Org website navbar - brand alignment + double-layer mode
 * ---------------------------------------------------------------------- */

/* Brand alignment in single-row mode */
.website-navbar.website-navbar-brand-center:not(.website-navbar-double) > .container {
    position: relative;
}
.website-navbar.website-navbar-brand-center:not(.website-navbar-double) > .container > .navbar-brand {
    position: absolute;
    left: 50%;
    transform: translateX(-50%);
}
/* Keep nav items right-aligned; brand absolutely centered overlays visually */

/* Two-row mode */
.website-navbar.website-navbar-double {
    flex-direction: column;
    padding: 0;
}
.website-navbar-double .website-navbar-row {
    width: 100%;
    padding: 0.5rem 0;
}
.website-navbar-double .website-navbar-row-brand {
    border-bottom: 1px solid var(--color-neutral-200, rgba(0, 0, 0, 0.08));
}
.website-navbar-double .website-navbar-row-brand > .container {
    display: flex;
    align-items: center;
}
.website-navbar-double .website-navbar-row-nav > .container {
    display: flex;
    align-items: center;
}
/* Brand alignment inside the top row */
.website-navbar-double.website-navbar-brand-left  .website-navbar-row-brand > .container { justify-content: flex-start; }
.website-navbar-double.website-navbar-brand-center .website-navbar-row-brand > .container { justify-content: center; }
/* Menu in the second row: center the nav list when brand is centered,
   otherwise keep the existing right alignment via ms-auto on the <ul>. */
.website-navbar-double.website-navbar-brand-center .website-navbar-row-nav .navbar-nav { margin: 0 auto !important; }
.website-navbar-double .website-navbar-row-nav .navbar-brand { display: none; }

/* Mobile: always collapse to single row regardless of mode */
@media (max-width: 991.98px) {
    .website-navbar.website-navbar-double {
        flex-direction: row;
        padding: 0.5rem 0;
    }
    .website-navbar-double .website-navbar-row {
        padding: 0;
        border: 0;
    }
    .website-navbar-double .website-navbar-row-brand > .container,
    .website-navbar-double .website-navbar-row-nav > .container {
        display: contents;
    }
}

/* Row 1 in double-layer mode: three equal columns.
   Left slot stays empty (reserved for future search icon), center holds the
   brand when Brand Alignment = Center, right always holds the extras row.
   When Brand Alignment = Left the brand snaps to the left slot instead. */
.website-navbar-double .website-navbar-row-brand > .container {
    display: grid;
    grid-template-columns: 1fr 1fr 1fr;
    align-items: center;
    gap: 1rem;
}
.website-navbar-double .website-navbar-row-brand .navbar-brand {
    margin: 0;
}
.website-navbar-double.website-navbar-brand-left .website-navbar-row-brand .navbar-brand {
    grid-column: 1;
    justify-self: start;
}
.website-navbar-double.website-navbar-brand-center .website-navbar-row-brand .navbar-brand {
    grid-column: 2;
    justify-self: center;
}
.website-navbar-double .website-navbar-row-brand .website-navbar-extras {
    grid-column: 3;
    justify-self: end;
    margin: 0 !important;
}
.website-navbar-double .website-navbar-extras {
    display: flex;
    align-items: center;
    gap: 0.75rem;
}
.website-navbar-double .website-navbar-extras-item {
    display: inline-flex;
    align-items: center;
}
@media (max-width: 991.98px) {
    .website-navbar-double .website-navbar-row-brand > .container {
        display: flex;
        justify-content: space-between;
    }
    .website-navbar-double .website-navbar-extras { display: none !important; }
}

/* ============================================================================
 * Section background animations
 *
 * Opt-in per section via the renderer-only `bg_animation` config key, which
 * adds a `.website-section-anim-{key}` class to the section wrapper. All
 * three animations target a ::before pseudo so the section's base background
 * stays untouched and motion composes with any solid color. Glow's highlight
 * opacity caps at 0.12 so saturated brand colors (electric blue, neon pink)
 * still feel like a gentle highlight rather than a flashlight orbiting the
 * section. `prefers-reduced-motion: reduce` disables all three visually
 * while the selected value stays in DB - flipping the OS preference back
 * restores the animation without any user action.
 * ============================================================================ */

.website-section-anim-pulse,
.website-section-anim-glow,
.website-section-anim-shimmer {
    position: relative;
    isolation: isolate;
    overflow: hidden;
}

.website-section-anim-pulse::before,
.website-section-anim-glow::before,
.website-section-anim-shimmer::before {
    content: "";
    position: absolute;
    inset: 0;
    pointer-events: none;
    mix-blend-mode: overlay;
    z-index: 0;
}

/* Pulse: slow radial breath from the section center. 6s ease-in-out infinite,
 * 0% to 8% opacity peak. The most "alive but unobtrusive" of the three. */
@keyframes wb-section-pulse {
    0%, 100% { opacity: 0; }
    50%      { opacity: 0.08; }
}
/* Speed controlled by --wb-bg-intensity. 0 -> 9s (slow), 1 -> 3s (fast),
 * default 0.5 -> 6s (matches pre-slider behavior exactly). */
.website-section-anim-pulse::before {
    background: radial-gradient(circle at 50% 50%, #fff, transparent 65%);
    animation: wb-section-pulse calc(9s - var(--wb-bg-intensity, 0.5) * 6s) ease-in-out infinite;
}

/* Glow: subtle highlight orbiting the section over 30s. Opacity capped at
 * 0.12 (peak) - any higher and saturated brand colors read as a flashlight. */
@keyframes wb-section-glow {
    0%   { transform: translate(-20%, -20%); opacity: 0.06; }
    25%  { transform: translate( 30%, -10%); opacity: 0.12; }
    50%  { transform: translate( 25%,  25%); opacity: 0.10; }
    75%  { transform: translate(-15%,  20%); opacity: 0.12; }
    100% { transform: translate(-20%, -20%); opacity: 0.06; }
}
/* Speed controlled by --wb-bg-intensity. 0 -> 50s (slow), 1 -> 10s (fast),
 * default 0.5 -> 30s (matches pre-slider behavior exactly). */
.website-section-anim-glow::before {
    background: radial-gradient(circle at 50% 50%, #fff, transparent 45%);
    width: 60%;
    height: 60%;
    left: 20%;
    top: 20%;
    inset: auto;
    animation: wb-section-glow calc(50s - var(--wb-bg-intensity, 0.5) * 40s) ease-in-out infinite;
}

/* Shimmer: 30deg gloss sheen sweeping across the section every 8s. A 25%
 * keyframe (sweep complete) plus a long dwell at 100% gives a ~6s pause
 * between sweeps so the eye gets a rest instead of a constant gloss. */
@keyframes wb-section-shimmer {
    0%   { transform: translateX(-120%) skewX(-30deg); opacity: 0; }
    10%  { opacity: 0.18; }
    25%  { transform: translateX( 220%) skewX(-30deg); opacity: 0; }
    100% { transform: translateX( 220%) skewX(-30deg); opacity: 0; }
}
/* Speed controlled by --wb-bg-intensity. 0 -> 12s (slow), 1 -> 4s (fast),
 * default 0.5 -> 8s (matches pre-slider behavior exactly). */
.website-section-anim-shimmer::before {
    background: linear-gradient(
        90deg,
        transparent 0%,
        rgba(255, 255, 255, 0.0) 30%,
        rgba(255, 255, 255, 0.55) 50%,
        rgba(255, 255, 255, 0.0) 70%,
        transparent 100%
    );
    width: 50%;
    animation: wb-section-shimmer calc(12s - var(--wb-bg-intensity, 0.5) * 8s) ease-out infinite;
}

@media (prefers-reduced-motion: reduce) {
    .website-section-anim-pulse::before,
    .website-section-anim-glow::before,
    .website-section-anim-shimmer::before {
        animation: none;
        display: none;
    }
}

/* ============================================================
 * Divider section (icon/line separator) - motion (Phase 1).
 * Idle icon animation + hover reactions. Duration is driven by the inline
 * --wb-divider-speed var (slow 5s / medium 3.2s / fast 1.8s) set by the widget.
 * Everything is disabled under prefers-reduced-motion at the bottom.
 * ============================================================ */
.wb-divider-icon { display: inline-block; }

@keyframes wb-divider-pulse {
    0%, 100% { transform: scale(1); }
    50%      { transform: scale(1.18); }
}
@keyframes wb-divider-float {
    0%, 100% { transform: translateY(0); }
    50%      { transform: translateY(-22%); }
}
@keyframes wb-divider-spin {
    from { transform: rotate(0); }
    to   { transform: rotate(360deg); }
}
@keyframes wb-divider-glow {
    0%, 100% { filter: drop-shadow(0 0 0 currentColor); opacity: 0.85; }
    50%      { filter: drop-shadow(0 0 6px currentColor); opacity: 1; }
}
@keyframes wb-divider-wiggle {
    0%, 100% { transform: rotate(0); }
    25%      { transform: rotate(-9deg); }
    75%      { transform: rotate(9deg); }
}

.wb-divider-icon-anim-pulse  { animation: wb-divider-pulse  var(--wb-divider-speed, 3.2s) ease-in-out infinite; }
.wb-divider-icon-anim-float  { animation: wb-divider-float  var(--wb-divider-speed, 3.2s) ease-in-out infinite; }
.wb-divider-icon-anim-spin   { animation: wb-divider-spin   calc(var(--wb-divider-speed, 3.2s) * 2.4) linear infinite; }
.wb-divider-icon-anim-glow   { animation: wb-divider-glow   var(--wb-divider-speed, 3.2s) ease-in-out infinite; }
.wb-divider-icon-anim-wiggle { animation: wb-divider-wiggle var(--wb-divider-speed, 3.2s) ease-in-out infinite; }

/* Hover reactions - triggered by hovering the whole divider. On hover the idle
 * icon animation is paused off (animation: none) so the transform-based effects
 * (grow / spin) win instead of being overwritten by a running keyframe. */
.wb-divider--hover-grow .wb-divider-icon,
.wb-divider--hover-spin .wb-divider-icon,
.wb-divider--hover-brighten .wb-divider-icon { transition: transform 0.25s ease, filter 0.25s ease; }
.wb-divider--hover-brighten .wb-divider-rule { transition: filter 0.25s ease; }
.wb-divider--hover-lift .wb-divider-inner { transition: transform 0.25s ease; }

.wb-divider--hover-grow:hover .wb-divider-icon     { animation: none; transform: scale(1.25); }
.wb-divider--hover-spin:hover .wb-divider-icon     { animation: none; transform: rotate(180deg); }
.wb-divider--hover-lift:hover .wb-divider-inner    { transform: translateY(-5px); }
.wb-divider--hover-brighten:hover .wb-divider-icon { filter: brightness(1.4); }
.wb-divider--hover-brighten:hover .wb-divider-rule { filter: brightness(1.6); }

/* ---- Line motion (Phase 2) ---------------------------------------------- */
/* Draw: the rule grows out from the center once as the section appears. */
@keyframes wb-divider-draw { from { transform: scaleX(0); } to { transform: scaleX(1); } }
.wb-divider-line-draw {
    transform-origin: center;
    animation: wb-divider-draw calc(var(--wb-divider-speed, 3.2s) * 0.35) ease-out both;
}
/* Flow: slide the (gradient) fill along the rule. */
@keyframes wb-divider-flow { 0% { background-position: 0% 50%; } 100% { background-position: 200% 50%; } }
.wb-divider-line-flow {
    background-size: 200% 100%;
    animation: wb-divider-flow var(--wb-divider-speed, 3.2s) linear infinite;
}
/* March: travel the dashes/dots along the rule. */
@keyframes wb-divider-march { from { background-position: 0 0; } to { background-position: 16px 0; } }
.wb-divider-line-march {
    animation: wb-divider-march calc(var(--wb-divider-speed, 3.2s) * 0.25) linear infinite;
}
/* Shimmer: a highlight sweeps along the rule. */
.wb-divider-line-shimmer { position: relative; overflow: hidden; }
.wb-divider-line-shimmer::before {
    content: ''; position: absolute; top: 0; left: 0; height: 100%; width: 40%;
    background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.85), transparent);
    animation: wb-divider-line-sweep var(--wb-divider-speed, 3.2s) ease-in-out infinite;
}
@keyframes wb-divider-line-sweep {
    0%       { transform: translateX(-150%); }
    60%, 100% { transform: translateX(350%); }
}

/* Glitch: the icon flickers through the pool (JS-driven); this is the momentary
 * distortion the script toggles on each flip. */
.wb-divider-icon.wb-divider-glitching {
    filter: hue-rotate(90deg) saturate(1.8);
    transform: skewX(9deg) scale(1.06);
}

@media (prefers-reduced-motion: reduce) {
    .wb-divider-icon-anim-pulse,
    .wb-divider-icon-anim-float,
    .wb-divider-icon-anim-spin,
    .wb-divider-icon-anim-glow,
    .wb-divider-icon-anim-wiggle,
    .wb-divider-line-draw,
    .wb-divider-line-flow,
    .wb-divider-line-march { animation: none; }
    .wb-divider-line-shimmer::before { animation: none; display: none; }
    .wb-divider-icon.wb-divider-glitching { filter: none; transform: none; }
    .wb-divider--hover-grow .wb-divider-icon,
    .wb-divider--hover-spin .wb-divider-icon,
    .wb-divider--hover-brighten .wb-divider-icon,
    .wb-divider--hover-brighten .wb-divider-rule,
    .wb-divider--hover-lift .wb-divider-inner { transition: none; }
    .wb-divider--hover-grow:hover .wb-divider-icon,
    .wb-divider--hover-spin:hover .wb-divider-icon,
    .wb-divider--hover-lift:hover .wb-divider-inner { transform: none; }
    .wb-divider--hover-brighten:hover .wb-divider-icon,
    .wb-divider--hover-brighten:hover .wb-divider-rule { filter: none; }
}

/* ============================================================================
 * Phase 2 - Image overlay + Ken Burns, Gradient pan + rotate, Mesh drift
 *
 * Picks up where Phase 1 left off: solids already have pulse/glow/shimmer
 * via ::before pseudos; here we extend motion to Gradient, Mesh and Image,
 * plus add Image overlay variants that compose with Ken Burns / parallax.
 * Each animation has a `prefers-reduced-motion: reduce` disable at the end.
 * ============================================================================ */

/* ---- Image overlay variants ----
 * `::before` pseudo sits above the background image and below content.
 * Opacity reads `--wb-bg-intensity` (the per-bg slider) so admins dial in
 * exactly how heavy the overlay should be. */
.website-section-image-overlay-darken::before,
.website-section-image-overlay-lighten::before,
.website-section-image-overlay-tint_primary::before,
.website-section-image-overlay-tint_secondary::before {
    content: "";
    position: absolute;
    inset: 0;
    pointer-events: none;
    z-index: 0;
    opacity: var(--wb-bg-intensity, 0.3);
}
.website-section-image-overlay-darken::before          { background: #000; }
.website-section-image-overlay-lighten::before         { background: #fff; }
.website-section-image-overlay-tint_primary::before    { background: var(--color-primary-500); }
.website-section-image-overlay-tint_secondary::before  { background: var(--color-secondary-500); }

/* Dark theme inverts the lighten/darken wash so contrast intent is preserved:
 * a white wash chosen for dark text becomes a black wash for the now-light text
 * (and vice-versa). Opacity (--wb-bg-intensity) is unchanged. Tints are
 * theme-independent and stay as-is. */
[data-theme="dark"] .website-section-image-overlay-lighten::before { background: #000; }
[data-theme="dark"] .website-section-image-overlay-darken::before  { background: #fff; }

/* Children of image-bg sections need to sit above the overlay. The base
 * `.website-section-image > *` rule already handles `position: relative; z-index: 1`,
 * which keeps content above any ::before. */

/* A darken / tint overlay implies light content sitting on a darkened image, so
 * the text must read white - mirroring how .website-section-dark forces white
 * text. Scoped to HERO image sections only (the wrapper carries both the overlay
 * class and data-web-section-type, see views/website/_section.php), so the
 * one-click cover hero stays legible while existing non-hero image sections are
 * left untouched. The 'lighten' and 'none' overlays keep the default dark text. */
.website-section-image-overlay-darken[data-web-section-type="hero"],
.website-section-image-overlay-tint_primary[data-web-section-type="hero"],
.website-section-image-overlay-tint_secondary[data-web-section-type="hero"] {
    color: #fff;
}
.website-section-image-overlay-darken[data-web-section-type="hero"] *,
.website-section-image-overlay-darken[data-web-section-type="hero"] h1,
.website-section-image-overlay-darken[data-web-section-type="hero"] h2,
.website-section-image-overlay-darken[data-web-section-type="hero"] h3,
.website-section-image-overlay-darken[data-web-section-type="hero"] h4,
.website-section-image-overlay-darken[data-web-section-type="hero"] p,
.website-section-image-overlay-darken[data-web-section-type="hero"] span,
.website-section-image-overlay-darken[data-web-section-type="hero"] a:not(.btn),
.website-section-image-overlay-tint_primary[data-web-section-type="hero"] *,
.website-section-image-overlay-tint_primary[data-web-section-type="hero"] h1,
.website-section-image-overlay-tint_primary[data-web-section-type="hero"] h2,
.website-section-image-overlay-tint_primary[data-web-section-type="hero"] h3,
.website-section-image-overlay-tint_primary[data-web-section-type="hero"] h4,
.website-section-image-overlay-tint_primary[data-web-section-type="hero"] p,
.website-section-image-overlay-tint_primary[data-web-section-type="hero"] span,
.website-section-image-overlay-tint_primary[data-web-section-type="hero"] a:not(.btn),
.website-section-image-overlay-tint_secondary[data-web-section-type="hero"] *,
.website-section-image-overlay-tint_secondary[data-web-section-type="hero"] h1,
.website-section-image-overlay-tint_secondary[data-web-section-type="hero"] h2,
.website-section-image-overlay-tint_secondary[data-web-section-type="hero"] h3,
.website-section-image-overlay-tint_secondary[data-web-section-type="hero"] h4,
.website-section-image-overlay-tint_secondary[data-web-section-type="hero"] p,
.website-section-image-overlay-tint_secondary[data-web-section-type="hero"] span,
.website-section-image-overlay-tint_secondary[data-web-section-type="hero"] a:not(.btn) {
    color: inherit;
}

/* ---- Image Ken Burns ----
 * The image-frame is an absolutely-positioned inner div the renderer emits
 * when image_animation === 'ken_burns'. Slight over-scale at rest (1.05)
 * hides edges that would otherwise peek out during the pan, and a 30s
 * ease-in-out cycle keeps the motion calm. */
.website-section-image-frame {
    position: absolute;
    inset: 0;
    background-size: cover;
    background-position: center;
    background-repeat: no-repeat;
    pointer-events: none;
    z-index: -1;
    transform: scale(1.05);
    will-change: transform;
}
@keyframes wb-ken-burns {
    0%   { transform: scale(1.05) translate(0%, 0%); }
    50%  { transform: scale(1.14) translate(-2%, 1%); }
    100% { transform: scale(1.05) translate(0%, 0%); }
}
.website-section-image-anim-ken_burns .website-section-image-frame {
    animation: wb-ken-burns 30s ease-in-out infinite;
}

/* ---- Image parallax ----
 * Pin the section image while the page scrolls over it. The renderer paints
 * the image on the .website-section-image-frame inner box (same frame Ken
 * Burns uses, see above) rather than directly on the wrapper, so a wrapper-
 * level transform (e.g. the Entrance-animation AOS class) can't create a new
 * containing block and silently downgrade `fixed` back to `scroll`. It's
 * janky/unsupported on touch, so fall back to normal scroll there. Mirrors
 * the Image Divider .image-divider--parallax rule.
 *
 * The frame's Ken Burns rules above (scale + will-change: transform) would
 * defeat `fixed` the same way, so this override resets both. The wrapper-
 * level rule below is kept for any cached/legacy markup that still paints
 * the image directly on .website-section-image; it is a no-op for current
 * renders since the frame carries the image instead. */
.website-section-image-anim-parallax .website-section-image-frame {
    background-attachment: fixed;
    background-size: cover;
    transform: none;
    will-change: auto;
}
@media (hover: none), (max-width: 768px) {
    .website-section-image-anim-parallax .website-section-image-frame { background-attachment: scroll; }
}
.website-section-image.website-section-image-anim-parallax {
    background-attachment: fixed;
}
@media (hover: none), (max-width: 768px) {
    .website-section-image.website-section-image-anim-parallax { background-attachment: scroll; }
}

/* ---- Gradient pan ----
 * `background-size: 200% 200%` makes the gradient twice as wide as the
 * section; animating `background-position` slides the visible window
 * across, producing a smooth pan. Slider controls speed: 0 -> 30s,
 * 0.5 -> 20s (default), 1 -> 10s. */
.website-section-gradient-anim-pan {
    background-size: 200% 200%;
    animation: wb-gradient-pan calc(30s - var(--wb-bg-intensity, 0.5) * 20s) linear infinite;
    will-change: background-position;
}
@keyframes wb-gradient-pan {
    0%   { background-position: 0% 50%; }
    50%  { background-position: 100% 50%; }
    100% { background-position: 0% 50%; }
}

/* ---- Gradient rotate ----
 * Uses `@property --wb-grad-angle` so the angle interpolates smoothly.
 * Safari 16.4+ (March 2023), all modern Chrome/Firefox - older Safari
 * silently keeps the gradient at its initial angle (no error, no flicker).
 * Rotate overrides each variant's `background` so the angle is taken from
 * the animatable variable. Radial gradient has no angle so it's not in
 * the override list - selecting Rotate with the Radial variant is a no-op. */
@property --wb-grad-angle {
    syntax: '<angle>';
    initial-value: 135deg;
    inherits: false;
}
.website-section-gradient-anim-rotate {
    --wb-grad-angle: 135deg;
    animation: wb-grad-rotate calc(40s - var(--wb-bg-intensity, 0.5) * 30s) linear infinite;
}
@keyframes wb-grad-rotate {
    to { --wb-grad-angle: 495deg; }
}
/* Deep (base gradient): swap the fixed 135deg for the animatable angle. */
.website-section-gradient-anim-rotate.website-section-gradient {
    background: linear-gradient(
        var(--wb-grad-angle),
        var(--color-primary-600),
        var(--color-primary-800) calc(70% + var(--wb-bg-intensity, 0.5) * 60%)
    );
}
/* Duo */
.website-section-gradient-anim-rotate.website-section-gradient-duo {
    background: linear-gradient(
        var(--wb-grad-angle),
        var(--color-primary-500),
        var(--color-secondary-500)
    );
}
/* Sweep */
.website-section-gradient-anim-rotate.website-section-gradient-sweep {
    background: linear-gradient(
        var(--wb-grad-angle),
        var(--color-primary-500) 0%,
        color-mix(in srgb, var(--bg-secondary, #f8f9fa) 80%, transparent) calc(30% + var(--wb-bg-intensity, 0.5) * 40%),
        var(--color-secondary-500) 100%
    );
}

/* ---- Mesh drift ----
 * Each mesh variant has its own per-variant keyframes so Diagonal feels
 * different from Aurora etc. The technique is the same across all four:
 * `background-size: 110%` extends the gradient slightly beyond the section,
 * and `background-position` keyframes shift the visible window subtly.
 * Variant identity comes through via the SHAPE of the keyframe path
 * (diagonal, vertical-only, circular, horizontal-only). */
.website-section-mesh-anim-drift {
    background-size: 110% 110%;
    will-change: background-position;
}

/* Diagonal is the default mesh - the wrapper has .website-section-mesh
 * but no .website-section-mesh-* variant class. Use :not() to scope. */
.website-section-mesh-anim-drift.website-section-mesh:not(.website-section-mesh-aurora):not(.website-section-mesh-spotlight):not(.website-section-mesh-twin) {
    animation: wb-mesh-drift-diagonal calc(60s - var(--wb-bg-intensity, 0.5) * 40s) ease-in-out infinite;
}
.website-section-mesh-anim-drift.website-section-mesh-aurora {
    animation: wb-mesh-drift-aurora calc(50s - var(--wb-bg-intensity, 0.5) * 30s) ease-in-out infinite;
}
.website-section-mesh-anim-drift.website-section-mesh-spotlight {
    animation: wb-mesh-drift-spotlight calc(70s - var(--wb-bg-intensity, 0.5) * 40s) ease-in-out infinite;
}
.website-section-mesh-anim-drift.website-section-mesh-twin {
    animation: wb-mesh-drift-twin calc(55s - var(--wb-bg-intensity, 0.5) * 35s) ease-in-out infinite;
}

/* Diagonal: drift along the primary diagonal. */
@keyframes wb-mesh-drift-diagonal {
    0%, 100% { background-position: 0% 0%; }
    50%      { background-position: 5% 5%; }
}
/* Aurora: bands sway vertically (horizontal stays put). */
@keyframes wb-mesh-drift-aurora {
    0%, 100% { background-position: 50% 0%; }
    50%      { background-position: 50% 5%; }
}
/* Spotlight: small circular wander around center, four-stop path. */
@keyframes wb-mesh-drift-spotlight {
    0%, 100% { background-position: 50% 50%; }
    25%      { background-position: 52% 48%; }
    50%      { background-position: 50% 52%; }
    75%      { background-position: 48% 50%; }
}
/* Twin: breathe horizontally between the two halves. */
@keyframes wb-mesh-drift-twin {
    0%, 100% { background-position: 0% 50%; }
    50%      { background-position: 5% 50%; }
}

/* ---- Phase 2 reduced-motion guard ---- */
@media (prefers-reduced-motion: reduce) {
    .website-section-image-anim-ken_burns .website-section-image-frame,
    .website-section-gradient-anim-pan,
    .website-section-gradient-anim-rotate,
    .website-section-mesh-anim-drift {
        animation: none;
    }
}

/* ====================================================================
 * CtaBannerWidget - compact end-of-page call-to-action strip.
 * Visually distinct from HeroSectionWidget: tighter vertical rhythm,
 * smaller heading, supports both split and centered layouts.
 * ==================================================================== */
.cta-banner-widget {
    padding: 1.5rem 0;
}
.cta-banner-inner {
    padding: 1.25rem 1.5rem;
    border-radius: 0.75rem;
    background: var(--bs-tertiary-bg, rgba(0, 0, 0, 0.03));
    color: var(--text-primary);
}
.website-section-primary .cta-banner-inner,
.website-section-secondary .cta-banner-inner,
.website-section-dark .cta-banner-inner {
    background: rgba(255, 255, 255, 0.08);
}
.cta-banner-heading {
    font-size: 1.5rem;
    font-weight: 600;
    line-height: 1.25;
}
.cta-banner-body {
    font-size: 0.95rem;
    line-height: 1.45;
}
.cta-banner-centered .cta-banner-copy {
    max-width: 36rem;
}
.cta-banner-actions .btn {
    max-width: 100%;
    white-space: normal;
    overflow-wrap: break-word;
}
@media (min-width: 768px) {
    .cta-banner-split .cta-banner-inner {
        padding: 1.5rem 2rem;
    }
    .cta-banner-split .cta-banner-heading {
        font-size: 1.75rem;
    }
    .cta-banner-split .cta-banner-actions .btn,
    .cta-banner-banner .cta-banner-actions .btn {
        white-space: nowrap;
    }
}
/* On colored section backgrounds, mute the body text contrast so the
 * heading + CTA stay the visual centerpiece. */
.website-section-primary .cta-banner-body,
.website-section-secondary .cta-banner-body,
.website-section-dark .cta-banner-body {
    color: rgba(255, 255, 255, 0.85) !important;
}

/* Stacked - left-aligned copy with full-width stacked buttons on the tinted card. */
.cta-banner-stacked .cta-banner-inner {
    padding: 1.75rem 2rem;
}
.cta-banner-actions-stacked {
    flex-direction: column;
    align-items: stretch;
}
.cta-banner-actions-stacked .btn {
    width: 100%;
}
@media (min-width: 768px) {
    .cta-banner-actions-stacked {
        flex-direction: row;
    }
    .cta-banner-actions-stacked .btn {
        width: auto;
    }
}

/* Banner - thin full-bleed strip: drop the inner card so it reads as a rule. */
.cta-banner-banner {
    padding: 0.75rem 0;
}
.cta-banner-banner .cta-banner-inner {
    background: transparent;
    border-radius: 0;
    padding: 0.5rem 0;
    border-top: 1px solid var(--border-default);
    border-bottom: 1px solid var(--border-default);
}
.cta-banner-banner .cta-banner-heading {
    font-size: 1.25rem;
}

/* Boxed - a prominent floating card, centered and shadowed. */
.cta-banner-boxed .cta-banner-inner {
    max-width: 48rem;
    margin: 0 auto;
    padding: 2.5rem 2rem;
    border-radius: 1.25rem;
    box-shadow: var(--shadow-lg);
    background: var(--bg-primary);
    color: var(--text-primary);
}
.website-section-primary .cta-banner-boxed .cta-banner-inner,
.website-section-secondary .cta-banner-boxed .cta-banner-inner,
.website-section-dark .cta-banner-boxed .cta-banner-inner {
    background: rgba(255, 255, 255, 0.1);
    color: #ffffff;
}

/* ====================================================================
 * LogoCloudWidget - static grid of partner / press / client logos.
 * ==================================================================== */
.logo-cloud-widget .logo-cloud-img {
    width: auto;
    object-fit: contain;
    transition: filter 0.2s ease, opacity 0.2s ease, transform 0.2s ease;
    opacity: 0.85;
}
.logo-cloud-grayscale .logo-cloud-img {
    filter: grayscale(100%);
    opacity: 0.6;
}
.logo-cloud-widget .logo-cloud-link:hover .logo-cloud-img,
.logo-cloud-widget .logo-cloud-img:hover {
    filter: grayscale(0);
    opacity: 1;
    transform: scale(1.04);
}
/* On dark / primary section backgrounds, invert grayscale logos so the
 * dark marks become readable on the dark surface. Brand colors win on
 * hover regardless. */
.website-section-dark .logo-cloud-grayscale .logo-cloud-img,
.website-section-primary .logo-cloud-grayscale .logo-cloud-img,
.website-section-secondary .logo-cloud-grayscale .logo-cloud-img {
    filter: grayscale(100%) brightness(0) invert(1);
    opacity: 0.75;
}
.website-section-dark .logo-cloud-grayscale .logo-cloud-link:hover .logo-cloud-img,
.website-section-primary .logo-cloud-grayscale .logo-cloud-link:hover .logo-cloud-img,
.website-section-secondary .logo-cloud-grayscale .logo-cloud-link:hover .logo-cloud-img {
    filter: none;
    opacity: 1;
}

/* ====================================================================
 * SponsorTiersWidget - partner / sponsor logos grouped into ranked tiers.
 * ==================================================================== */
.sponsor-tiers-widget .sponsor-tier {
    margin-bottom: 2.5rem;
}
.sponsor-tiers-widget .sponsor-tier:last-child {
    margin-bottom: 0;
}
.sponsor-tiers-widget .sponsor-tier-label {
    font-size: 0.875rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    opacity: 0.7;
    margin-bottom: 1.25rem;
}
.sponsor-tiers-widget .sponsor-tier-logos {
    gap: 2.5rem;
}
.sponsor-tiers-widget .sponsor-logo {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    text-decoration: none;
    color: inherit;
}
.sponsor-tiers-widget .sponsor-logo-img {
    width: auto;
    object-fit: contain;
    transition: filter 0.2s ease, opacity 0.2s ease, transform 0.2s ease;
    opacity: 0.9;
}
.sponsor-tiers-widget .sponsor-logo-text {
    font-size: 1.25rem;
    font-weight: 600;
    opacity: 0.85;
}
.sponsor-tiers-grayscale .sponsor-logo-img {
    filter: grayscale(100%);
    opacity: 0.6;
}
.sponsor-tiers-widget .sponsor-logo:hover .sponsor-logo-img {
    filter: grayscale(0);
    opacity: 1;
    transform: scale(1.04);
}
/* Smaller tiers get progressively tighter spacing. */
.sponsor-tiers-widget .sponsor-tier-silver .sponsor-tier-logos,
.sponsor-tiers-widget .sponsor-tier-bronze .sponsor-tier-logos,
.sponsor-tiers-widget .sponsor-tier-partner .sponsor-tier-logos {
    gap: 2rem;
}
/* Invert grayscale marks on dark / primary section surfaces so dark logos
 * stay visible; full brand color returns on hover. */
.website-section-dark .sponsor-tiers-grayscale .sponsor-logo-img,
.website-section-primary .sponsor-tiers-grayscale .sponsor-logo-img,
.website-section-secondary .sponsor-tiers-grayscale .sponsor-logo-img {
    filter: grayscale(100%) brightness(0) invert(1);
    opacity: 0.75;
}
.website-section-dark .sponsor-tiers-grayscale .sponsor-logo:hover .sponsor-logo-img,
.website-section-primary .sponsor-tiers-grayscale .sponsor-logo:hover .sponsor-logo-img,
.website-section-secondary .sponsor-tiers-grayscale .sponsor-logo:hover .sponsor-logo-img {
    filter: none;
    opacity: 1;
}

/* ====================================================================
 * EventAgendaWidget - single-event session timetable (vertical timeline).
 * ==================================================================== */
.event-agenda-timeline {
    max-width: 760px;
}
.event-agenda-event-link {
    display: inline-flex;
    align-items: center;
    font-weight: 600;
    text-decoration: none;
    color: var(--website-primary, #0d6efd);
}
.event-agenda-event-link:hover {
    text-decoration: underline;
}
.event-agenda-track {
    margin-bottom: 2.5rem;
}
.event-agenda-track:last-child {
    margin-bottom: 0;
}
.event-agenda-track-label {
    font-size: 1rem;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    opacity: 0.8;
    margin-bottom: 1rem;
}
.event-agenda-row {
    gap: 1.25rem;
    padding: 1.1rem 0;
    border-bottom: 1px solid var(--border-default, rgba(0, 0, 0, 0.08));
}
.event-agenda-row:last-child {
    border-bottom: 0;
}
.event-agenda-time {
    flex: 0 0 6.5rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    color: var(--website-primary, #0d6efd);
    padding-top: 0.1rem;
}
.event-agenda-title {
    font-size: 1.0625rem;
    font-weight: 600;
}
.event-agenda-badge {
    display: inline-block;
    font-size: 0.7rem;
    font-weight: 600;
    letter-spacing: 0.03em;
    text-transform: uppercase;
    padding: 0.15rem 0.5rem;
    border-radius: 999px;
    background: var(--bg-secondary, rgba(0, 0, 0, 0.06));
    opacity: 0.85;
}
.event-agenda-speaker {
    font-size: 0.9rem;
    opacity: 0.85;
    margin-top: 0.25rem;
}
.event-agenda-desc {
    font-size: 0.9rem;
    opacity: 0.75;
    margin-top: 0.35rem;
}
@media (max-width: 575.98px) {
    .event-agenda-row {
        flex-direction: column;
        gap: 0.25rem;
    }
    .event-agenda-time {
        flex-basis: auto;
    }
}

/* ====================================================================
 * DonationThermometerWidget - progress-to-goal fundraising bar.
 * ==================================================================== */
.donation-thermometer {
    max-width: 640px;
}
.donation-thermo-heading {
    font-weight: 700;
    margin-bottom: 0.5rem;
}
.donation-thermo-desc {
    opacity: 0.8;
    margin-bottom: 1.5rem;
}
.donation-thermo-track {
    position: relative;
    height: 2.25rem;
    border-radius: 999px;
    background: var(--bg-secondary, rgba(0, 0, 0, 0.08));
    overflow: hidden;
}
.donation-thermo-fill {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    height: 100%;
    width: var(--thermo-fill, 0%);
    min-width: 2.5rem;
    border-radius: 999px;
    background: linear-gradient(90deg, var(--website-primary, #0d6efd), var(--website-secondary, var(--website-primary, #0d6efd)));
    animation: donation-thermo-grow 1.1s cubic-bezier(0.22, 1, 0.36, 1) both;
}
@keyframes donation-thermo-grow {
    from { width: 0; }
    to   { width: var(--thermo-fill, 0%); }
}
.donation-thermo-pct {
    color: #fff;
    font-size: 0.8125rem;
    font-weight: 700;
    padding: 0 0.75rem;
    white-space: nowrap;
}
.donation-thermo-amounts {
    margin-top: 0.75rem;
    font-size: 0.95rem;
    opacity: 0.9;
}
.donation-thermo-goal {
    opacity: 0.75;
}
/* Respect reduced-motion: snap to the final fill instead of animating. */
@media (prefers-reduced-motion: reduce) {
    .donation-thermo-fill {
        animation: none;
    }
}

/* Donate CTA - fully self-contained so it renders as a real button even
 * where Bootstrap's .btn base and theme.css's .btn-brand-* fills are not
 * loaded (the website layout omits theme.css). Variants key off the
 * buttonStyleClass() classes already on the <a>. Author's inline text
 * color (buttonColor) still wins via the element's style attribute. */
.donation-thermo-cta {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0.7rem 1.75rem;
    border: 1px solid transparent;
    border-radius: var(--website-button-radius, var(--radius-md, 0.5rem));
    font-weight: 600;
    line-height: 1.2;
    text-decoration: none;
    cursor: pointer;
    transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease, transform 0.15s ease;
}
.donation-thermo-cta:hover {
    transform: translateY(-1px);
    text-decoration: none;
}
.donation-thermo-cta.btn-brand-primary {
    background-color: var(--color-primary-600);
    border-color: var(--color-primary-600);
    color: #fff;
}
.donation-thermo-cta.btn-brand-primary:hover {
    background-color: var(--color-primary-700, var(--color-primary-600));
    border-color: var(--color-primary-700, var(--color-primary-600));
}
.donation-thermo-cta.btn-brand-secondary {
    background-color: var(--color-secondary-600);
    border-color: var(--color-secondary-600);
    color: #fff;
}
.donation-thermo-cta.btn-brand-secondary:hover {
    background-color: var(--color-secondary-700, var(--color-secondary-600));
    border-color: var(--color-secondary-700, var(--color-secondary-600));
}
.donation-thermo-cta.btn-outline-brand-primary {
    background-color: transparent;
    border-color: var(--color-primary-600);
    color: var(--color-primary-600);
}
.donation-thermo-cta.btn-outline-brand-primary:hover {
    background-color: var(--color-primary-600);
    color: #fff;
}
.donation-thermo-cta.btn-outline-brand-secondary {
    background-color: transparent;
    border-color: var(--color-secondary-600);
    color: var(--color-secondary-600);
}
.donation-thermo-cta.btn-outline-brand-secondary:hover {
    background-color: var(--color-secondary-600);
    color: #fff;
}

/* Logo Cloud layouts (grid is the default markup above; these add the
 * cards / strip / row / carousel variants chosen via the Layout picker). */

/* Cards - each logo boxed in a bordered tile that lifts on hover. Whole tile
 * is clickable when a logo has a link (LogoCloudWidget::renderLogo() stretches
 * the anchor over this position:relative box - see .logo-cloud-link below). */
.logo-cloud-cards .logo-cloud-cell {
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    /* Card padding follows the section's Content spacing when set. */
    padding: var(--website-card-pad, 1.25rem) calc(var(--website-card-pad, 1.25rem) * 0.8);
    background: var(--bg-primary, #fff);
    border: 1px solid var(--border-default, #dee2e6);
    border-radius: var(--radius-lg, 0.75rem);
    transition: transform 0.2s ease, box-shadow 0.2s ease, border-color 0.2s ease;
    position: relative;
}
.logo-cloud-cards .logo-cloud-link {
    cursor: pointer;
}
.logo-cloud-cards .logo-cloud-cell:hover {
    transform: translateY(-4px);
    box-shadow: var(--shadow-md, 0 6px 18px rgba(0, 0, 0, 0.08));
    border-color: var(--color-primary-300, #b9c6ff);
}
[data-theme="dark"] .logo-cloud-cards .logo-cloud-cell {
    background: var(--bg-secondary);
}

/* Strip - seamless auto-scroll. Reuses the global @keyframes marquee-scroll-*. */
.logo-cloud-strip {
    width: 100%;
    overflow: hidden;
    position: relative;
}
.logo-cloud-strip-track {
    display: flex;
    flex-wrap: nowrap;
    width: max-content;
    align-items: center;
    gap: var(--space-8, 2.5rem);
    animation: marquee-scroll-left var(--lc-duration, 40s) linear infinite;
    will-change: transform;
}
.logo-cloud-strip-dup {
    display: contents;
}
.logo-cloud-strip-item {
    flex: 0 0 auto;
}
.logo-cloud-strip[data-pause-on-hover="1"]:hover .logo-cloud-strip-track {
    animation-play-state: paused;
}
@media (prefers-reduced-motion: reduce) {
    .logo-cloud-strip-track {
        animation: none;
    }
    .logo-cloud-strip {
        overflow-x: auto;
        scroll-snap-type: x proximity;
    }
}

/* Row - one centered line of logos with hairline dividers. */
.logo-cloud-row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
}
.logo-cloud-row .logo-cloud-row-item {
    display: flex;
    align-items: center;
    padding: 0.5rem 1.75rem;
}
.logo-cloud-row .logo-cloud-row-item:not(:last-child) {
    border-right: 1px solid var(--border-default, #dee2e6);
}
@media (max-width: 575.98px) {
    .logo-cloud-row .logo-cloud-row-item:not(:last-child) {
        border-right: none;
    }
}

/* Carousel - horizontal scroll with arrow nav + optional autoplay (JS). */
.logo-cloud-carousel-wrap {
    position: relative;
    display: flex;
    align-items: center;
    gap: 0.5rem;
}
.logo-cloud-carousel-track {
    flex: 1 1 auto;
    display: flex;
    flex-wrap: nowrap;
    align-items: center;
    gap: var(--space-8, 2.5rem);
    padding: 0.5rem 0;
    overflow-x: auto;
    scroll-snap-type: x proximity;
    scroll-behavior: smooth;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
}
.logo-cloud-carousel-track::-webkit-scrollbar {
    display: none;
}
.logo-cloud-carousel-item {
    flex: 0 0 auto;
    scroll-snap-align: start;
}
.logo-cloud-carousel-nav {
    flex: 0 0 auto;
    width: 38px;
    height: 38px;
    border-radius: 50%;
    border: 1px solid var(--border-default, #dee2e6);
    background: var(--bg-primary, #fff);
    color: var(--text-primary, #212529);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    transition: background 0.15s, color 0.15s, border-color 0.15s;
}
.logo-cloud-carousel-nav:hover {
    background: var(--color-primary-600, #0d6efd);
    border-color: var(--color-primary-600, #0d6efd);
    color: #fff;
}
[data-theme="dark"] .logo-cloud-carousel-nav {
    background: var(--bg-secondary);
}

/* ====================================================================
 * VideoFeatureWidget - featured video with click-to-play facade.
 * The facade keeps third-party YouTube/Vimeo iframes off the page
 * until the visitor clicks play; only then is the real iframe injected.
 * ==================================================================== */
.video-feature-widget {
    padding: 1.5rem 0;
}
.video-feature-embed {
    border-radius: 0.75rem;
    overflow: hidden;
    box-shadow: 0 8px 30px rgba(0, 0, 0, 0.12);
    background: #000;
}
.video-feature-facade {
    position: relative;
    cursor: pointer;
    background-size: cover;
    background-position: center;
    background-color: #111;
}
/* Gradient overlay lives on ::after so Bootstrap's `.ratio::before`
 * (which provides aspect-ratio height via padding-top) is not clobbered
 * when both classes sit on the same element. ::before with position:absolute
 * removes the pseudo from flow and the parent collapses to zero height,
 * making the facade invisible. */
.video-feature-facade::after {
    content: '';
    position: absolute;
    inset: 0;
    background: linear-gradient(180deg, rgba(0,0,0,0.10) 0%, rgba(0,0,0,0.45) 100%);
    transition: background 0.2s ease;
    z-index: 1;
    pointer-events: none;
}
.video-feature-facade:hover::after,
.video-feature-facade:focus-visible::after {
    background: linear-gradient(180deg, rgba(0,0,0,0.05) 0%, rgba(0,0,0,0.55) 100%);
}
.video-feature-facade:focus-visible {
    outline: 3px solid var(--bs-primary, #0d6efd);
    outline-offset: 2px;
}
.video-feature-play {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 72px;
    height: 72px;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.95);
    color: var(--bs-primary, #0d6efd);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 1.75rem;
    z-index: 2;
    transition: transform 0.2s ease, box-shadow 0.2s ease;
    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
}
.video-feature-facade:hover .video-feature-play {
    transform: translate(-50%, -50%) scale(1.08);
    box-shadow: 0 6px 28px rgba(0, 0, 0, 0.4);
}
.video-feature-play i {
    margin-left: 4px; /* Optical centering for the play triangle */
}
.video-feature-kicker {
    letter-spacing: 0.05em;
}
.video-feature-heading {
    font-size: 1.75rem;
    font-weight: 600;
    line-height: 1.25;
}
@media (min-width: 768px) {
    .video-feature-heading {
        font-size: 2.25rem;
    }
}

/* ====================================================================
 * FaqSectionWidget - minimal accordion override so it sits well inside
 * a website section without fighting other Bootstrap accordions.
 * ==================================================================== */
.faq-section-widget .accordion-button {
    font-weight: 600;
    background: var(--bg-primary, #fff);
}
.faq-section-widget .accordion-button:not(.collapsed) {
    background: var(--bg-secondary, #f8f9fa);
    color: inherit;
    box-shadow: none;
}
.faq-section-widget .accordion-item {
    border-color: var(--bs-border-color, #dee2e6);
    background: transparent;
}
.faq-section-widget .accordion-body {
    line-height: 1.6;
}
.website-section-dark .faq-section-widget .accordion-button,
.website-section-primary .faq-section-widget .accordion-button,
.website-section-secondary .faq-section-widget .accordion-button {
    background: rgba(255, 255, 255, 0.08);
    color: inherit;
}
.website-section-dark .faq-section-widget .accordion-button:not(.collapsed),
.website-section-primary .faq-section-widget .accordion-button:not(.collapsed),
.website-section-secondary .faq-section-widget .accordion-button:not(.collapsed) {
    background: rgba(255, 255, 255, 0.14);
}

/* --------------------------------------------------------------------
 * Open-header style presets (shared vocabulary with Tabs buttons).
 * Applied via a `.wb-btnstyle-*` class on `.faq-section-widget`; all
 * read `--wb-accent` (set inline from the Brand Palette accent picker).
 *
 * `soft` is the DEFAULT: it intentionally references `var(--wb-accent)`
 * WITHOUT a fallback inside color-mix, so when no accent is chosen the
 * whole declaration is invalid and the cascade falls back to the
 * existing neutral open-header rules above - preserving the historic
 * look on every background. The other presets are explicit user picks,
 * so they fall back to the brand primary when no accent is set.
 * ------------------------------------------------------------------ */
.faq-section-widget.wb-btnstyle-soft .accordion-button:not(.collapsed) {
    background: color-mix(in srgb, var(--wb-accent) 16%, var(--bg-secondary, #f8f9fa));
    color: var(--wb-accent, inherit);
}
.faq-section-widget.wb-btnstyle-solid .accordion-button:not(.collapsed) {
    background: var(--wb-accent, var(--bs-primary, #0d6efd));
    color: #fff;
}
.faq-section-widget.wb-btnstyle-outline .accordion-button:not(.collapsed) {
    background: transparent;
    box-shadow: inset 0 0 0 1px var(--wb-accent, var(--bs-primary, #0d6efd));
    color: var(--wb-accent, var(--bs-primary, #0d6efd));
}
.faq-section-widget.wb-btnstyle-bar .accordion-button:not(.collapsed) {
    background: transparent;
    box-shadow: inset 3px 0 0 0 var(--wb-accent, var(--bs-primary, #0d6efd));
    color: var(--wb-accent, var(--bs-primary, #0d6efd));
}
.faq-section-widget.wb-btnstyle-minimal .accordion-button:not(.collapsed) {
    background: transparent;
    color: var(--wb-accent, var(--bs-primary, #0d6efd));
}

/* ====================================================================
 * Accordion section - expand/collapse indicator styles.
 * Non-chevron indicators repurpose Bootstrap's .accordion-button::after
 * pseudo-element, swapping the glyph on the .collapsed state. FontAwesome 6
 * Free (weight 900) is loaded site-wide.
 * ==================================================================== */
.faq-section-widget.acc-icon-plusminus .accordion-button::after,
.faq-section-widget.acc-icon-caret .accordion-button::after,
.faq-section-widget.acc-icon-arrow .accordion-button::after,
.faq-section-widget.acc-icon-angle .accordion-button::after,
.faq-section-widget.acc-icon-toggle .accordion-button::after,
.faq-section-widget.acc-icon-pluscircle .accordion-button::after {
    font-family: "Font Awesome 6 Free";
    font-weight: 900;
    background-image: none;
    width: auto;
    height: auto;
    transition: transform 0.2s ease-in-out;
}

/* Plus / Minus */
.faq-section-widget.acc-icon-plusminus .accordion-button::after { content: "\f068"; }
.faq-section-widget.acc-icon-plusminus .accordion-button.collapsed::after { content: "\f067"; }
.faq-section-widget.acc-icon-plusminus .accordion-button:not(.collapsed)::after { transform: none; }

/* Caret */
.faq-section-widget.acc-icon-caret .accordion-button::after { content: "\f0d7"; }
.faq-section-widget.acc-icon-caret .accordion-button.collapsed::after { content: "\f0da"; }
.faq-section-widget.acc-icon-caret .accordion-button:not(.collapsed)::after { transform: none; }

/* Arrow - single glyph that rotates from right (closed) to down (open) */
.faq-section-widget.acc-icon-arrow .accordion-button::after { content: "\f063"; }
.faq-section-widget.acc-icon-arrow .accordion-button.collapsed::after { transform: rotate(-90deg); }
.faq-section-widget.acc-icon-arrow .accordion-button:not(.collapsed)::after { transform: none; }

/* Eye - Tabler eye (open) / eye-closed (collapsed); no strikeout */
.faq-section-widget.acc-icon-eye .accordion-button::after {
    font-family: "tabler-icons";
    font-weight: 400;
    background-image: none;
    width: auto;
    height: auto;
    transition: transform 0.2s ease-in-out;
    content: "\ea9a"; /* ti-eye (open) */
}
.faq-section-widget.acc-icon-eye .accordion-button.collapsed::after { content: "\f7ec"; } /* ti-eye-closed */
.faq-section-widget.acc-icon-eye .accordion-button:not(.collapsed)::after { transform: none; }

/* Angle - thin single-line chevron that rotates from right (closed) to down (open) */
.faq-section-widget.acc-icon-angle .accordion-button::after { content: "\f107"; } /* fa-angle-down */
.faq-section-widget.acc-icon-angle .accordion-button.collapsed::after { transform: rotate(-90deg); }
.faq-section-widget.acc-icon-angle .accordion-button:not(.collapsed)::after { transform: none; }

/* Toggle - switch off (closed) / on (open) */
.faq-section-widget.acc-icon-toggle .accordion-button::after { content: "\f205"; } /* fa-toggle-on */
.faq-section-widget.acc-icon-toggle .accordion-button.collapsed::after { content: "\f204"; } /* fa-toggle-off */
.faq-section-widget.acc-icon-toggle .accordion-button:not(.collapsed)::after { transform: none; }

/* Plus circle - circle-plus (closed) / circle-minus (open) */
.faq-section-widget.acc-icon-pluscircle .accordion-button::after { content: "\f056"; } /* fa-circle-minus */
.faq-section-widget.acc-icon-pluscircle .accordion-button.collapsed::after { content: "\f055"; } /* fa-circle-plus */
.faq-section-widget.acc-icon-pluscircle .accordion-button:not(.collapsed)::after { transform: none; }

/* Custom - two real <i> icons emitted by the widget, toggled by .collapsed.
 * Suppress the default chevron and push the visible icon to the far end. */
.faq-section-widget.acc-icon-custom .accordion-button::after { display: none; }
.faq-section-widget.acc-icon-custom .accordion-button .acc-label { margin-right: auto; }
.faq-section-widget.acc-icon-custom .accordion-button .acc-ci { transition: transform 0.2s ease-in-out; }
.faq-section-widget.acc-icon-custom .accordion-button.collapsed .acc-ci-open { display: none; }
.faq-section-widget.acc-icon-custom .accordion-button.collapsed .acc-ci-closed { display: inline-block; }
.faq-section-widget.acc-icon-custom .accordion-button:not(.collapsed) .acc-ci-open { display: inline-block; }
.faq-section-widget.acc-icon-custom .accordion-button:not(.collapsed) .acc-ci-closed { display: none; }

/* None */
.faq-section-widget.acc-icon-none .accordion-button::after { display: none; }

/* ====================================================================
 * Accordion section - container visual variants.
 * "bordered" is the default look (rules at the top of this block).
 * ==================================================================== */
/* Separated - each item a gapped, rounded, shadowed card */
.faq-section-widget.acc-variant-separated .accordion-item {
    border: 1px solid var(--bs-border-color, #dee2e6);
    border-radius: var(--bs-border-radius, 0.5rem);
    margin-bottom: 0.75rem;
    overflow: hidden;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06);
}
.faq-section-widget.acc-variant-separated .accordion-item:last-child {
    margin-bottom: 0;
}

/* Flush - borderless except divider lines between items */
.faq-section-widget.acc-variant-flush .accordion-item {
    border-left: 0;
    border-right: 0;
    border-radius: 0;
}
.faq-section-widget.acc-variant-flush .accordion-item:first-child {
    border-top: 0;
}
.faq-section-widget.acc-variant-flush .accordion-button,
.faq-section-widget.acc-variant-flush .accordion-button:not(.collapsed) {
    background: transparent;
}

/* Minimal - no box; header underline + generous spacing */
.faq-section-widget.acc-variant-minimal .accordion-item {
    border: 0;
    border-bottom: 1px solid var(--bs-border-color, #dee2e6);
    background: transparent;
}
.faq-section-widget.acc-variant-minimal .accordion-button,
.faq-section-widget.acc-variant-minimal .accordion-button:not(.collapsed) {
    background: transparent;
    padding-left: 0;
    padding-right: 0;
    padding-top: 1.1rem;
    padding-bottom: 1.1rem;
}
.faq-section-widget.acc-variant-minimal .accordion-body {
    padding-left: 0;
    padding-right: 0;
}

/* ====================================================================
 * TeamSectionWidget - card grid for people.
 * ==================================================================== */
.team-section-widget .team-card {
    padding: 0.5rem 0.25rem;
}
.team-photo {
    display: inline-block;
    width: 100%;
    max-width: 160px;
    aspect-ratio: 1 / 1;
    object-fit: cover;
}
.team-photo-circle {
    border-radius: 50%;
}
.team-photo-square {
    border-radius: 0.75rem;
}
.team-photo-placeholder {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: var(--bs-tertiary-bg, #e9ecef);
    color: var(--bs-secondary-color, #6c757d);
    font-size: 3rem;
    font-weight: 600;
}
.team-name {
    font-size: 1.1rem;
    font-weight: 600;
}
.team-role {
    text-transform: uppercase;
    letter-spacing: 0.04em;
}
.team-bio {
    color: var(--bs-secondary-color, #6c757d);
    line-height: 1.55;
}
.team-social {
    width: 32px;
    height: 32px;
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: var(--bg-secondary, #f8f9fa);
    color: var(--bs-body-color, #212529);
    transition: background-color 0.15s ease, color 0.15s ease, transform 0.15s ease;
    text-decoration: none;
    font-size: 0.85rem;
}
.team-social:hover {
    background: var(--bs-primary, #0d6efd);
    color: #fff;
    transform: translateY(-2px);
}
.team-compact .team-photo {
    max-width: 96px;
}
.team-compact .team-name {
    font-size: 0.9rem;
    margin-top: 0.5rem !important;
}

/* Circles - larger centered round avatars, name + role only. */
.team-circles .team-photo {
    max-width: 120px;
}
.team-circles .team-card {
    padding: 0.75rem 0.25rem;
}

/* List - editorial photo-left rows. */
.team-list .team-card-list {
    border-bottom: 1px solid var(--border-default);
}
.team-list .team-card-list:last-child {
    border-bottom: none;
}
.team-photo-list {
    width: 88px;
    max-width: 88px;
    height: 88px;
}

/* Spotlight - oversized lead portrait. */
.team-photo-spotlight {
    max-width: 200px;
}
.team-spotlight .team-card-spotlight .team-name {
    font-size: 1.5rem;
}
.team-spotlight .team-card-spotlight .team-role {
    font-size: 0.95rem;
}

/* ====================================================================
 * ContactMapWidget - address + hours + Leaflet OSM map.
 * ==================================================================== */
.contact-map-widget {
    padding: 1rem 0;
}
.contact-map-canvas {
    width: 100%;
    min-height: 360px;
    height: 100%;
    border-radius: 0.75rem;
    overflow: hidden;
    border: 1px solid var(--bs-border-color, #dee2e6);
    background: var(--bs-tertiary-bg, #f8f9fa);
}
.contact-info-label {
    letter-spacing: 0.05em;
}
.contact-info-value {
    line-height: 1.5;
}
a.contact-info-value:hover {
    color: var(--bs-primary, #0d6efd) !important;
}
.contact-hours td {
    padding: 0.25rem 0.5rem;
    border-color: transparent;
}
.contact-hours tr:nth-child(odd) td {
    background: var(--bs-tertiary-bg, #f8f9fa);
}
.website-section-dark .contact-hours tr:nth-child(odd) td,
.website-section-primary .contact-hours tr:nth-child(odd) td,
.website-section-secondary .contact-hours tr:nth-child(odd) td {
    background: rgba(255, 255, 255, 0.05);
}
/* Leaflet's default control colors don't match our theme - reduce its weight. */
.contact-map-canvas .leaflet-control-attribution {
    font-size: 0.7rem;
}

/* Footer map: the base canvas min-height (360px) is too tall for a footer, so
 * override to a compact fixed height. The full-width band variant is a touch
 * taller for legibility across the page width. */
.website-footer-map {
    margin-top: 1rem;
}
.website-footer-map .contact-map-canvas {
    min-height: 0;
    height: 160px;
    border-radius: 0.5rem;
}
.website-footer-map--band .contact-map-canvas {
    height: 200px;
}

/* Contact page map: lives at the foot of the info column. margin-top:auto
 * pushes it down so it aligns with the bottom of the form card; a fixed
 * compact height keeps the column balanced rather than dominating it. */
.website-contact-map {
    margin-top: auto;
    padding-top: var(--space-6);
}
.website-contact-map .contact-map-canvas {
    min-height: 0;
    height: 260px;
}
@media (max-width: 767.98px) {
    /* Stacked layout: no column to align to, so just give it normal spacing. */
    .website-contact-map {
        margin-top: var(--space-6);
    }
}

/* Equal-height columns: the grid stretches both cells to the taller one (the
 * info column with its map). Make the form card fill that height and let the
 * message textarea grow to absorb the slack, so the form bottom lines up with
 * the map bottom instead of leaving dead space. */
.website-contact-form .card {
    height: 100%;
}
.website-contact-form .card-body {
    display: flex;
    flex-direction: column;
}
.website-contact-form form {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
}
.website-contact-msg {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
}
.website-contact-msg textarea {
    flex: 1 1 auto;
    min-height: 140px;
    resize: vertical;
}
@media (max-width: 767.98px) {
    /* Stacked: nothing to match, keep the textarea at its natural size. */
    .website-contact-msg textarea {
        flex: 0 1 auto;
    }
}

/* ====================================================================
 * ChartSectionWidget - Chart.js canvas wrapper.
 * ==================================================================== */
.chart-section-widget {
    padding: 1rem 0;
}
.chart-section-title {
    font-size: 1.5rem;
    font-weight: 600;
}
.chart-section-subtitle {
    font-size: 0.95rem;
}
.chart-section-canvas-wrap {
    position: relative;
    width: 100%;
}
.chart-section-canvas {
    width: 100% !important;
    height: 100% !important;
}

/* ====================================================================
 * ComparisonTableWidget - feature comparison grid.
 * ==================================================================== */
.comparison-table-widget .comparison-table {
    margin-bottom: 0;
    border-collapse: separate;
    border-spacing: 0;
}
.comparison-table .comparison-col-header {
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    font-size: 0.85rem;
    padding: 1rem 0.75rem;
    border-bottom: 2px solid var(--bs-border-color, #dee2e6);
}
.comparison-table .comparison-row-header {
    border-bottom: 2px solid var(--bs-border-color, #dee2e6);
    background: transparent;
}
.comparison-table .comparison-row-label {
    font-weight: 500;
    color: var(--bs-body-color, #212529);
    background: transparent;
}
.comparison-table .comparison-cell {
    padding: 0.85rem 0.75rem;
    vertical-align: middle;
}
.comparison-table .comparison-col-highlight {
    background: rgba(13, 110, 253, 0.08);
    border-top: 3px solid var(--bs-primary, #0d6efd);
    color: var(--bs-primary, #0d6efd);
}
.comparison-table .comparison-cell-highlight {
    background: rgba(13, 110, 253, 0.05);
    border-left: 1px solid rgba(13, 110, 253, 0.15);
    border-right: 1px solid rgba(13, 110, 253, 0.15);
}
.comparison-table tbody tr:last-child .comparison-cell-highlight {
    border-bottom: 1px solid rgba(13, 110, 253, 0.15);
}
.website-section-dark .comparison-col-highlight,
.website-section-primary .comparison-col-highlight,
.website-section-secondary .comparison-col-highlight {
    background: rgba(255, 255, 255, 0.10);
    color: inherit;
    border-top-color: rgba(255, 255, 255, 0.6);
}

/* ====================================================================
 * BeforeAfterSliderWidget - drag-divider image comparison.
 * ==================================================================== */
.ba-slider-widget {
    padding: 1rem 0;
}
.ba-slider-heading {
    font-size: 1.5rem;
    font-weight: 600;
}
.ba-slider {
    position: relative;
    width: 100%;
    overflow: hidden;
    border-radius: 0.75rem;
    box-shadow: 0 8px 30px rgba(0, 0, 0, 0.12);
    user-select: none;
    touch-action: none;
}
.ba-slider-img {
    display: block;
    width: 100%;
    height: auto;
    pointer-events: none;
}
.ba-slider-img-after {
    width: 100%;
}
.ba-slider-clip {
    position: absolute;
    top: 0;
    left: 0;
    height: 100%;
    overflow: hidden;
    will-change: width;
}
.ba-slider-clip .ba-slider-img-before {
    width: 100vw; /* clipped by the parent */
    max-width: none;
    height: 100%;
    object-fit: cover;
}
.ba-slider-dragging {
    cursor: grabbing;
}
.ba-slider-dragging .ba-slider-clip {
    transition: none;
}
.ba-slider-handle {
    position: absolute;
    top: 0;
    bottom: 0;
    width: 4px;
    background: transparent;
    transform: translateX(-50%);
    cursor: ew-resize;
    will-change: left;
    z-index: 2;
}
.ba-slider-handle:focus-visible {
    outline: none;
}
.ba-slider-handle-line {
    position: absolute;
    top: 0;
    bottom: 0;
    left: 50%;
    width: 3px;
    background: #fff;
    transform: translateX(-50%);
    box-shadow: 0 0 12px rgba(0, 0, 0, 0.5);
}
.ba-slider-handle-knob {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 44px;
    height: 44px;
    border-radius: 50%;
    background: #fff;
    color: var(--bs-primary, #0d6efd);
    display: flex;
    align-items: center;
    justify-content: center;
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.4);
    transition: transform 0.15s ease;
    font-size: 0.85rem;
}
.ba-slider-handle:hover .ba-slider-handle-knob,
.ba-slider-handle:focus-visible .ba-slider-handle-knob {
    transform: translate(-50%, -50%) scale(1.1);
}
.ba-slider-label {
    position: absolute;
    top: 1rem;
    padding: 0.25rem 0.75rem;
    background: rgba(0, 0, 0, 0.6);
    color: #fff;
    border-radius: 2rem;
    font-size: 0.75rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    z-index: 3;
    pointer-events: none;
}
.ba-slider-label-before { left: 1rem; }
.ba-slider-label-after  { right: 1rem; }

/* ====================================================================
 * TabsSectionWidget - polished nav-pills overrides.
 * ==================================================================== */
.tabs-section-widget .nav-pills .nav-link {
    color: var(--bs-body-color, #212529);
    background: transparent;
    border-radius: 2rem;
    padding: 0.5rem 1.1rem;
    font-weight: 500;
}
.tabs-section-widget .nav-pills .nav-link:hover {
    background: var(--bg-secondary, #f8f9fa);
}
.tabs-section-widget .nav-pills .nav-link.active {
    background: var(--wb-accent, var(--bs-primary, #0d6efd));
    color: #fff;
}
.tabs-section-widget .tabs-section-content {
    line-height: 1.65;
}

/* Per-tab icon size override (config[items.*.iconSize] / config[iconSize]).
 * No 'xl' here - an extra-large glyph in a pill button isn't a real option. */
.tabs-section-widget .nav-link .tab-icon-sm {
    font-size: 0.8125rem;
}
.tabs-section-widget .nav-link .tab-icon-md {
    font-size: 1rem;
}
.tabs-section-widget .nav-link .tab-icon-lg {
    font-size: 1.25rem;
}

/* --------------------------------------------------------------------
 * Active-tab button style presets. Applied via a `.wb-btnstyle-*`
 * modifier class on `.tabs-section-widget`; all read `--wb-accent`
 * (set inline from the Brand Palette accent picker) and fall back to
 * the brand primary. `solid` reproduces the historic filled pill.
 * Rules target `.nav-link` generally so they apply to pills AND tabs.
 * ------------------------------------------------------------------ */
.tabs-section-widget.wb-btnstyle-soft .nav-link.active {
    background: color-mix(in srgb, var(--wb-accent, var(--bs-primary, #0d6efd)) 16%, transparent);
    color: var(--wb-accent, var(--bs-primary, #0d6efd));
}
.tabs-section-widget.wb-btnstyle-outline .nav-link {
    border: 1px solid transparent;
}
.tabs-section-widget.wb-btnstyle-outline .nav-link.active {
    background: transparent;
    border-color: var(--wb-accent, var(--bs-primary, #0d6efd));
    color: var(--wb-accent, var(--bs-primary, #0d6efd));
}
.tabs-section-widget.wb-btnstyle-bar .nav-link {
    border-radius: 0;
    border-bottom: 2px solid transparent;
    background: transparent;
}
.tabs-section-widget.wb-btnstyle-bar .nav-link.active {
    background: transparent;
    color: var(--wb-accent, var(--bs-primary, #0d6efd));
    border-bottom-color: var(--wb-accent, var(--bs-primary, #0d6efd));
}
.tabs-section-widget.wb-btnstyle-minimal .nav-link.active {
    background: transparent;
    color: var(--wb-accent, var(--bs-primary, #0d6efd));
    font-weight: 700;
}

/* ====================================================================
 * EmbeddedSurveyGameWidget - call-out card for surveys / games.
 * ==================================================================== */
.embed-survey-game-widget {
    padding: 1rem 0;
}
.embed-sg-card {
    background: var(--bg-primary, #fff);
    border: 1px solid var(--bs-border-color, #dee2e6);
    border-radius: 1rem;
    overflow: hidden;
    box-shadow: 0 6px 24px rgba(0, 0, 0, 0.08);
    transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.embed-sg-card:hover {
    transform: translateY(-3px);
    box-shadow: 0 10px 32px rgba(0, 0, 0, 0.12);
}
.embed-sg-image {
    width: 100%;
    height: 240px;
    object-fit: cover;
    display: block;
}
.embed-sg-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    border-radius: 50%;
    background: rgba(13, 110, 253, 0.1);
    color: var(--bs-primary, #0d6efd);
    font-size: 1.1rem;
}
.embed-sg-icon-lg {
    width: 64px;
    height: 64px;
    font-size: 1.5rem;
}
.embed-sg-title {
    font-size: 1.35rem;
    font-weight: 600;
}
.embed-sg-compact {
    background: var(--bg-secondary, #f8f9fa);
    border-radius: 0.75rem;
    padding: 0.9rem 1.25rem;
    border-left: 4px solid var(--bs-primary, #0d6efd);
}
.website-section-dark .embed-sg-compact,
.website-section-primary .embed-sg-compact,
.website-section-secondary .embed-sg-compact {
    background: rgba(255, 255, 255, 0.08);
}

/* ====================================================================
 * CalendarGridWidget - month grid of org events.
 * ==================================================================== */
.calendar-grid-widget {
    padding: 1rem 0;
}
/* Suppress focus ring/glow on prev/next month buttons. Covers both the
 * mouse-click focus ring AND the post-reload focus flash caused by the
 * #fragment navigation re-applying focus to the targeted element. */
.calendar-grid-header .btn,
.calendar-grid-header .btn:focus,
.calendar-grid-header .btn:focus-visible,
.calendar-grid-header .btn:active {
    outline: none !important;
    box-shadow: none !important;
}
.calendar-grid-month-label {
    font-size: 1.5rem;
    font-weight: 600;
}
.calendar-grid {
    display: grid;
    grid-template-columns: repeat(7, 1fr);
    gap: 1px;
    background: var(--bs-border-color, #dee2e6);
    border: 1px solid var(--bs-border-color, #dee2e6);
    border-radius: 0.5rem;
    overflow: hidden;
}
.calendar-grid-dow {
    background: var(--bg-secondary, #f8f9fa);
    padding: 0.5rem;
    text-align: center;
    font-weight: 600;
    font-size: 0.75rem;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: var(--bs-secondary-color, #6c757d);
}
.calendar-grid-cell {
    background: var(--bg-primary, #fff);
    min-height: 92px;
    padding: 0.4rem;
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
    overflow: hidden;
}
.calendar-grid-cell-muted .calendar-grid-daynum {
    opacity: 0.35;
}
.calendar-grid-cell-muted {
    background: var(--bg-secondary, #f8f9fa);
}
.calendar-grid-cell-today .calendar-grid-daynum {
    background: var(--bs-primary, #0d6efd);
    color: #fff;
    border-radius: 50%;
    width: 24px;
    height: 24px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-weight: 600;
}
.calendar-grid-daynum {
    font-size: 0.85rem;
    font-weight: 500;
    margin-bottom: 0.15rem;
}
.calendar-grid-chip {
    display: flex;
    align-items: center;
    gap: 0.3rem;
    background: rgba(13, 110, 253, 0.12);
    color: var(--bs-primary, #0d6efd);
    text-decoration: none;
    padding: 0.15rem 0.4rem;
    border-radius: 0.25rem;
    font-size: 0.75rem;
    line-height: 1.25;
    transition: background-color 0.15s ease;
}
.calendar-grid-chip:hover {
    background: var(--bs-primary, #0d6efd);
    color: #fff;
}
.calendar-chip-label {
    flex: 1 1 auto;
    min-width: 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
/* Facebook-style registration-count badge (org staff only). */
.calendar-chip-badge {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 1.2rem;
    height: 1.2rem;
    padding: 0 0.35rem;
    border-radius: 999px;
    background: var(--bs-danger, #dc3545);
    color: #fff;
    font-size: 0.65rem;
    font-weight: 700;
    line-height: 1;
}
.calendar-grid-chip:hover .calendar-chip-badge {
    background: #fff;
    color: var(--bs-danger, #dc3545);
}
.calendar-agenda-event .calendar-chip-badge {
    margin-left: auto;
}
.calendar-grid-more {
    font-size: 0.7rem;
    color: var(--bs-secondary-color, #6c757d);
    font-style: italic;
}
@media (max-width: 575.98px) {
    .calendar-grid-cell {
        min-height: 64px;
        padding: 0.25rem;
    }
    .calendar-grid-chip {
        font-size: 0.65rem;
    }
}
.website-section-dark .calendar-grid,
.website-section-primary .calendar-grid,
.website-section-secondary .calendar-grid {
    background: rgba(255, 255, 255, 0.15);
    border-color: rgba(255, 255, 255, 0.2);
}
.website-section-dark .calendar-grid-cell,
.website-section-primary .calendar-grid-cell,
.website-section-secondary .calendar-grid-cell {
    background: rgba(255, 255, 255, 0.05);
    color: inherit;
}
.website-section-dark .calendar-grid-cell-muted,
.website-section-primary .calendar-grid-cell-muted,
.website-section-secondary .calendar-grid-cell-muted {
    background: rgba(0, 0, 0, 0.15);
}
.website-section-dark .calendar-grid-dow,
.website-section-primary .calendar-grid-dow,
.website-section-secondary .calendar-grid-dow {
    background: rgba(0, 0, 0, 0.2);
    color: inherit;
}

/* Size variants (grid layout only). cozy = current defaults, no rules. */
.calendar-grid-size-compact .calendar-grid-cell {
    min-height: 64px;
    padding: 0.25rem;
}
.calendar-grid-size-compact .calendar-grid-chip {
    font-size: 0.7rem;
    padding: 0.1rem 0.3rem;
}
.calendar-grid-size-compact .calendar-grid-daynum {
    font-size: 0.7rem;
}
.calendar-grid-size-spacious .calendar-grid-cell {
    min-height: 128px;
    padding: 0.7rem;
}
.calendar-grid-size-spacious .calendar-grid-chip {
    font-size: 0.875rem;
    padding: 0.3rem 0.55rem;
}
.calendar-grid-size-spacious .calendar-grid-daynum {
    font-size: 1rem;
}

/* Agenda layout - vertical list of days-with-events. */
.calendar-agenda {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
}
.calendar-agenda-day {
    background: var(--bg-primary, #fff);
    border: 1px solid var(--bs-border-color, #dee2e6);
    border-radius: 0.5rem;
    padding: 0.75rem 1rem;
}
.calendar-agenda-day-today {
    border-color: var(--bs-primary, #0d6efd);
    border-width: 2px;
}
.calendar-agenda-day-header {
    display: flex;
    align-items: baseline;
    gap: 0.5rem;
    margin-bottom: 0.5rem;
}
.calendar-agenda-day-num {
    font-size: 1.5rem;
    font-weight: 700;
    color: var(--bs-primary, #0d6efd);
}
.calendar-agenda-day-name {
    font-size: 0.8rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--bs-secondary-color, #6c757d);
}
.calendar-agenda-events {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
}
.calendar-agenda-event {
    display: flex;
    gap: 1rem;
    padding: 0.4rem 0.5rem;
    border-radius: 0.25rem;
    text-decoration: none;
    color: inherit;
    transition: background 0.15s;
}
.calendar-agenda-event:hover {
    background: var(--bg-secondary, #f8f9fa);
}
.calendar-agenda-event-time {
    min-width: 4em;
    font-weight: 600;
    color: var(--bs-secondary-color, #6c757d);
}
.calendar-agenda-empty {
    text-align: center;
    padding: 2rem;
    color: var(--bs-secondary-color, #6c757d);
}

/* Week layout - 7-column horizontal strip. */
.calendar-week {
    display: grid;
    grid-template-columns: repeat(7, 1fr);
    gap: 0.5rem;
}
.calendar-week-day {
    background: var(--bg-primary, #fff);
    border: 1px solid var(--bs-border-color, #dee2e6);
    border-radius: 0.5rem;
    padding: 0.5rem;
    min-height: 140px;
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
}
.calendar-week-day-today {
    border-color: var(--bs-primary, #0d6efd);
    border-width: 2px;
}
.calendar-week-day-name {
    font-size: 0.7rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--bs-secondary-color, #6c757d);
}
.calendar-week-day-num {
    font-size: 1.25rem;
    font-weight: 700;
    line-height: 1;
    margin-bottom: 0.25rem;
}
@media (max-width: 575.98px) {
    .calendar-week {
        grid-template-columns: repeat(2, 1fr);
    }
}

/* Dark / primary / secondary section overrides for agenda + week. */
.website-section-dark .calendar-agenda-day,
.website-section-primary .calendar-agenda-day,
.website-section-secondary .calendar-agenda-day,
.website-section-dark .calendar-week-day,
.website-section-primary .calendar-week-day,
.website-section-secondary .calendar-week-day {
    background: rgba(255, 255, 255, 0.08);
    border-color: rgba(255, 255, 255, 0.2);
    color: inherit;
}
.website-section-dark .calendar-agenda-day-num,
.website-section-primary .calendar-agenda-day-num,
.website-section-secondary .calendar-agenda-day-num {
    color: inherit;
}
.website-section-dark .calendar-agenda-event:hover,
.website-section-primary .calendar-agenda-event:hover,
.website-section-secondary .calendar-agenda-event:hover {
    background: rgba(255, 255, 255, 0.1);
}
.website-section-dark .calendar-agenda-event-time,
.website-section-primary .calendar-agenda-event-time,
.website-section-secondary .calendar-agenda-event-time,
.website-section-dark .calendar-week-day-name,
.website-section-primary .calendar-week-day-name,
.website-section-secondary .calendar-week-day-name,
.website-section-dark .calendar-agenda-day-name,
.website-section-primary .calendar-agenda-day-name,
.website-section-secondary .calendar-agenda-day-name {
    color: inherit;
    opacity: 0.85;
}

/* ============================================================
 * Image Divider section (ImageDividerWidget)
 * Full-bleed image band used as a visual break between sections.
 * ============================================================ */

/* Drop the section's vertical padding so the band sits flush with its
 * neighbours (opt-in via _section.php for section_type=image_divider). */
.website-section-flush {
    padding-top: 0;
    padding-bottom: 0;
}

/* EVC-017: Text & Media (custom_blocks) column flow. Wrapper only exists
 * when config[text_columns] > 1 (models/OrgWebsiteSection.php render()), so
 * a section left at the default 1 column emits no wrapper and renders
 * byte-identical to before this feature. CSS column-count lets the block
 * editor's own content (headings, paragraphs, images, ...) flow between
 * columns without the author having to split it into separate blocks -
 * column-break-inside:avoid keeps a single block from being torn across a
 * column boundary. Steps down at the same breakpoints the rest of the
 * builder's responsive content uses (tablet/phone), so 4 columns never
 * squeezes to unreadable width. */
/* Text & Media rich-text body. The old block-editor render stamped
 * .content-heading / .content-paragraph on every element and got its vertical
 * rhythm from web/css/site.css. The rich-text store emits bare tags (purify
 * only keeps TextStyleRegistry preset classes), so the same rhythm is restored
 * here, scoped to the section body. Kept at (0,1,1) so the .website-section
 * .txt-size-* / .txt-lh-* presets (0,2,0) still win where an author set one. */
.wb-cb-body > :first-child {
    margin-top: 0;
}
.wb-cb-body > :last-child {
    margin-bottom: 0;
}
.wb-cb-body h2,
.wb-cb-body h3,
.wb-cb-body h4 {
    margin-top: var(--space-5);
    margin-bottom: var(--space-3);
    font-family: var(--font-family-heading);
    font-weight: 600;
}
.wb-cb-body p,
.wb-cb-body ul,
.wb-cb-body ol {
    margin-bottom: var(--space-4);
    line-height: 1.8;
}
.wb-cb-body blockquote {
    margin: var(--space-4) 0;
    padding-left: var(--space-4);
    border-left: 3px solid var(--color-primary-600, currentColor);
}
.wb-cb-body hr {
    margin: var(--space-5) 0;
    border: 0;
    border-top: 1px solid var(--border-color, currentColor);
    opacity: 0.35;
}

.wb-cb-columns {
    column-gap: var(--space-8, 2rem);
    orphans: 2;
    widows: 2;
}
.wb-cb-columns > h2,
.wb-cb-columns > h3,
.wb-cb-columns > h4,
.wb-cb-columns > figure,
.wb-cb-columns > img,
.wb-cb-columns > table,
.wb-cb-columns > blockquote,
.wb-cb-columns > pre {
    break-inside: avoid;
}
.wb-cb-columns-2 { column-count: 2; }
.wb-cb-columns-3 { column-count: 3; }
.wb-cb-columns-4 { column-count: 4; }
@media (max-width: 991.98px) {
    .wb-cb-columns-3,
    .wb-cb-columns-4 { column-count: 2; }
}
@media (max-width: 575.98px) {
    .wb-cb-columns-2,
    .wb-cb-columns-3,
    .wb-cb-columns-4 { column-count: 1; }
}

.image-divider {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    overflow: hidden;
    background-size: cover;
    background-position: center;
    background-repeat: no-repeat;
    text-decoration: none; /* when rendered as <a> */
}

/* Height presets - desktop min-heights, scaled down on small screens. */
.image-divider--slim   { min-height: 180px; }
.image-divider--medium { min-height: 340px; }
.image-divider--tall   { min-height: 520px; }
@media (max-width: 768px) {
    .image-divider--slim   { min-height: 120px; }
    .image-divider--medium { min-height: 220px; }
    .image-divider--tall   { min-height: 320px; }
}

/* Ken Burns: animate an inner frame so the band's layout box stays put.
 * Reuses the @keyframes wb-ken-burns defined for image backgrounds above. */
.image-divider-frame {
    position: absolute;
    inset: 0;
    background-size: cover;
    background-position: center;
    background-repeat: no-repeat;
    z-index: 0;
    transform: scale(1.05);
    will-change: transform;
}
/* EVC-004: 16s (not the general background Ken Burns's 30s, left alone at
 * web/css/website-theme.css:3095 - a separate declaration, same shared
 * @keyframes) - an Image Divider band is small and usually glanced at
 * briefly, so 30s read as motionless in practice even though the CSS itself
 * was already correct. */
.image-divider--ken-burns .image-divider-frame {
    animation: wb-ken-burns 16s ease-in-out infinite;
}
@media (prefers-reduced-motion: reduce) {
    .image-divider--ken-burns .image-divider-frame { animation: none; }
}

/* Parallax: pin the image while the page scrolls. ImageDividerWidget paints
 * it on the same inner frame Ken Burns uses (mirrors .website-section-image-
 * anim-parallax .website-section-image-frame) rather than the band itself,
 * so the frame's Ken Burns scale/will-change (above) don't defeat `fixed`
 * and the builder preview has a box it can reposition (see the "Preview
 * parallax pinning" block in views/website/_wb_edit_mode.php).
 * background-attachment:fixed is janky/unsupported on touch, so fall back to
 * a normal scroll there. */
.image-divider--parallax .image-divider-frame {
    background-attachment: fixed;
    transform: none;
    will-change: auto;
}
@media (hover: none), (max-width: 768px) {
    .image-divider--parallax .image-divider-frame { background-attachment: scroll; }
}
/* Legacy/no-op: kept for any cached markup that still paints the image
 * directly on the band (mirrors .website-section-image.website-section-
 * image-anim-parallax above); current renders always use the frame instead. */
.image-divider--parallax {
    background-attachment: fixed;
}
@media (hover: none), (max-width: 768px) {
    .image-divider--parallax { background-attachment: scroll; }
}

/* Auto scrim - only present when the widget rendered overlay text/button.
 * A vertical gradient keeps text legible without flattening the image. */
.image-divider-scrim {
    position: absolute;
    inset: 0;
    z-index: 1;
    pointer-events: none;
    background: linear-gradient(180deg, rgba(0, 0, 0, 0.15) 0%, rgba(0, 0, 0, 0.45) 100%);
}

/* Overlay content sits above the image + scrim. */
.image-divider-content {
    position: relative;
    z-index: 2;
    max-width: 720px;
    padding: 1.5rem;
    text-align: center;
    color: #fff;
}
.image-divider-heading {
    margin: 0 0 0.5rem;
    color: #fff;
    font-weight: 700;
    text-shadow: 0 1px 12px rgba(0, 0, 0, 0.35);
}
.image-divider-subtext {
    margin: 0 0 1rem;
    color: rgba(255, 255, 255, 0.92);
    text-shadow: 0 1px 8px rgba(0, 0, 0, 0.35);
}
.image-divider-button {
    margin-top: 0.25rem;
}

/* Whole-band link: subtle hover feedback. */
.image-divider--linked {
    cursor: pointer;
    transition: filter 0.2s ease;
}
.image-divider--linked:hover {
    filter: brightness(1.06);
}

/* ============================================================
   Downloads section (FilesSectionWidget)
   ============================================================ */
.downloads-list .downloads-item + .downloads-item {
    margin-top: 0.5rem;
}
.downloads-link {
    padding: 0.7rem 0.9rem;
    border: 1px solid var(--border-default);
    border-radius: var(--radius-md, 0.5rem);
    background: var(--bg-primary);
    color: var(--text-primary);
    transition: border-color 0.18s ease, box-shadow 0.18s ease, transform 0.18s ease;
}
.downloads-link:hover {
    border-color: var(--color-primary-400);
    box-shadow: 0 4px 14px rgba(0, 0, 0, 0.07);
    color: var(--text-primary);
    transform: translateY(-1px);
}
.downloads-icon {
    font-size: 1.4rem;
    color: var(--color-primary-600);
    width: 1.6rem;
    text-align: center;
    flex: 0 0 auto;
}
.downloads-cue {
    color: var(--text-muted);
    flex: 0 0 auto;
}
.downloads-compact .downloads-link {
    padding: 0.45rem 0.65rem;
}
.downloads-compact .downloads-icon {
    font-size: 1.1rem;
}

/* Cards variant */
.downloads-card {
    border: 1px solid var(--border-default);
    border-radius: var(--radius-md, 0.5rem);
    background: var(--bg-primary);
    color: var(--text-primary);
    transition: border-color 0.18s ease, box-shadow 0.18s ease, transform 0.18s ease;
}
.downloads-card:hover {
    border-color: var(--color-primary-400);
    box-shadow: 0 6px 18px rgba(0, 0, 0, 0.08);
    color: var(--text-primary);
    transform: translateY(-2px);
}
.downloads-card-icon {
    font-size: 1.9rem;
    color: var(--color-primary-600);
}
.downloads-card-foot {
    border-top: 1px solid var(--border-default);
}

/* Footer downloads column */
.website-footer-downloads {
    list-style: none;
    padding: 0;
    margin: 0;
}
.website-footer-downloads li + li {
    margin-top: 0.35rem;
}
.website-footer-downloads a {
    color: var(--website-footer-link);
    text-decoration: none;
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
}
.website-footer-downloads a:hover {
    color: var(--website-footer-link-hover);
}

/* ---------- Toastr notifications (cart add/remove, etc.) ----------------- *
 * Re-skin the toastr library to the org's brand so the "Item added to cart"
 * popup matches the site instead of toastr's default green. Scoped to
 * body[data-web="body"] (unique to the website layout) so platform pages keep
 * their normal toasts. Success uses the brand colour; error/warning stay
 * semantic so failures are still obvious. !important + the id-selector
 * specificity beat toastr.min.css / toastr-theme.css regardless of load order. */
body[data-web="body"] #toast-container > div {
    border-radius: var(--radius-xl, 0.75rem) !important;
    box-shadow: var(--shadow-lg, 0 10px 25px rgba(0, 0, 0, 0.15)) !important;
    opacity: 1 !important;
    font-family: inherit !important;
    color: #fff !important;
    padding: 0.95rem 1.25rem 0.95rem 3.1rem !important;
}
body[data-web="body"] #toast-container > div:hover {
    box-shadow: var(--shadow-xl, 0 16px 32px rgba(0, 0, 0, 0.22)) !important;
}
body[data-web="body"] #toast-container > .toast-success {
    background-color: var(--bs-primary, var(--color-primary-600, #2490c8)) !important;
}
body[data-web="body"] #toast-container > .toast-info {
    background-color: var(--color-primary-500, #3aa8e0) !important;
}
body[data-web="body"] #toast-container > .toast-error {
    background-color: var(--color-error-600, #dc2626) !important;
}
body[data-web="body"] #toast-container > .toast-warning {
    background-color: var(--color-warning-600, #d97706) !important;
}
/* Toast title/message + the close "x" all read as white on the brand fill. */
body[data-web="body"] #toast-container > div .toast-title,
body[data-web="body"] #toast-container > div .toast-message {
    color: #fff !important;
}
body[data-web="body"] #toast-container > div .toast-close-button {
    color: #fff !important;
    opacity: 0.9 !important;
    text-shadow: none !important;
}
body[data-web="body"] #toast-container > div .toast-close-button:hover {
    opacity: 1 !important;
}
/* Progress bar tinted to a translucent white so it reads on any brand fill. */
body[data-web="body"] #toast-container > div .toast-progress {
    background-color: rgba(255, 255, 255, 0.5) !important;
    opacity: 1 !important;
}

/* ============================================================
   Lottie animation section (LottieSectionWidget)
   A single lightweight vector animation. The stage is sized by
   the `--sm|md|lg|full` modifier; lottie-web's SVG fills it and
   preserves the animation's aspect ratio (letterboxing portrait
   animations cleanly). Horizontal placement comes from text-align
   on the wrapper, so the inline-block stage shifts left/center/right -
   driven only by the section's own Animation Position pill.
   Heading/caption read the shared --website-text-align variable
   instead (the section's generic Text Alignment control), which
   defaults to `inherit` at :root - so with no override they still
   follow the stage's own alignment, but an explicit Text Alignment
   choice moves them independently of the animation.
   ============================================================ */
.website-lottie { width: 100%; }
.website-lottie--left { text-align: left; }
.website-lottie--center { text-align: center; }
.website-lottie--right { text-align: right; }
.website-lottie-heading { text-align: var(--website-text-align); }
.website-lottie-stage {
    display: inline-block;
    width: 240px;
    max-width: 100%;
    aspect-ratio: 1 / 1;
    line-height: 0;
}
.website-lottie--sm .website-lottie-stage { width: 120px; }
.website-lottie--md .website-lottie-stage { width: 240px; }
.website-lottie--lg .website-lottie-stage { width: 400px; }
.website-lottie--full .website-lottie-stage { width: 100%; max-width: 640px; }
.website-lottie-stage svg {
    display: block;
    width: 100% !important;
    height: 100% !important;
}
.website-lottie-caption { text-align: var(--website-text-align); }
