/* Minification failed. Returning unminified contents.
(43,36): run-time error CSS1019: Unexpected token, found ' '
(43,36): run-time error CSS1019: Unexpected token, found ' '
(43,36): run-time error CSS1042: Expected function, found ' '
(43,36): run-time error CSS1062: Expected semicolon or closing curly-brace, found ' '
(50,36): run-time error CSS1019: Unexpected token, found ' '
(50,36): run-time error CSS1019: Unexpected token, found ' '
(50,36): run-time error CSS1042: Expected function, found ' '
(50,36): run-time error CSS1062: Expected semicolon or closing curly-brace, found ' '
(52,17): run-time error CSS1039: Token not allowed after unary operator: '-bs-secondary-color'
(60,21): run-time error CSS1039: Token not allowed after unary operator: '-bs-gutter-x'
(127,23): run-time error CSS1039: Token not allowed after unary operator: '-loc-navbar-pad-y'
(128,26): run-time error CSS1039: Token not allowed after unary operator: '-loc-navbar-pad-y'
(146,5): run-time error CSS1062: Expected semicolon or closing curly-brace, found '-'
(147,5): run-time error CSS1062: Expected semicolon or closing curly-brace, found '-'
(148,5): run-time error CSS1062: Expected semicolon or closing curly-brace, found '-'
(149,5): run-time error CSS1062: Expected semicolon or closing curly-brace, found '-'
(150,5): run-time error CSS1062: Expected semicolon or closing curly-brace, found '-'
(151,5): run-time error CSS1062: Expected semicolon or closing curly-brace, found '-'
(152,22): run-time error CSS1039: Token not allowed after unary operator: '-loc-navbar-bg'
(152,43): run-time error CSS1039: Token not allowed after unary operator: '-bs-primary'
(153,25): run-time error CSS1039: Token not allowed after unary operator: '-loc-navbar-border-bottom'
(154,22): run-time error CSS1039: Token not allowed after unary operator: '-loc-navbar-shadow'
(155,35): run-time error CSS1039: Token not allowed after unary operator: '-loc-navbar-backdrop'
(156,27): run-time error CSS1039: Token not allowed after unary operator: '-loc-navbar-backdrop'
(160,23): run-time error CSS1039: Token not allowed after unary operator: '-loc-navbar-link-weight'
(161,26): run-time error CSS1039: Token not allowed after unary operator: '-loc-navbar-link-transform'
(162,26): run-time error CSS1039: Token not allowed after unary operator: '-loc-navbar-link-spacing'
(170,18): run-time error CSS1039: Token not allowed after unary operator: '-loc-navbar-logo-h'
(172,21): run-time error CSS1039: Token not allowed after unary operator: '-loc-navbar-logo-maxw'
(179,17): run-time error CSS1039: Token not allowed after unary operator: '-loc-navbar-color'
(186,28): run-time error CSS1039: Token not allowed after unary operator: '-loc-navbar-color'
(196,26): run-time error CSS1039: Token not allowed after unary operator: '-loc-navbar-bg-mobile'
(197,9): run-time error CSS1062: Expected semicolon or closing curly-brace, found '-'
(198,9): run-time error CSS1062: Expected semicolon or closing curly-brace, found '-'
(202,32): run-time error CSS1039: Token not allowed after unary operator: '-loc-navbar-color-mobile'
(202,63): run-time error CSS1039: Token not allowed after unary operator: '-loc-navbar-color'
(216,15): run-time error CSS1039: Token not allowed after unary operator: '-row-gap'
(220,35): run-time error CSS1039: Token not allowed after unary operator: '-bs-gutter-x'
(221,36): run-time error CSS1039: Token not allowed after unary operator: '-bs-gutter-x'
(222,19): run-time error CSS1039: Token not allowed after unary operator: '-page-pad-top'
(222,45): run-time error CSS1039: Token not allowed after unary operator: '-page-pad-side'
(222,72): run-time error CSS1039: Token not allowed after unary operator: '-page-pad-bottom'
(227,24): run-time error CSS1039: Token not allowed after unary operator: '-row-gap'
(228,28): run-time error CSS1039: Token not allowed after unary operator: '-page-pad-top'
(228,66): run-time error CSS1039: Token not allowed after unary operator: '-page-pad-side'
(228,105): run-time error CSS1039: Token not allowed after unary operator: '-page-pad-bottom'
(259,28): run-time error CSS1039: Token not allowed after unary operator: '-bs-secondary-bg'
(296,40): run-time error CSS1039: Token not allowed after unary operator: '-bs-primary-rgb'
(748,22): run-time error CSS1039: Token not allowed after unary operator: '-bs-primary'
(789,30): run-time error CSS1039: Token not allowed after unary operator: '-loc-divider-space-after'
(789,69): run-time error CSS1039: Token not allowed after unary operator: '-row-gap'
(793,17): run-time error CSS1039: Token not allowed after unary operator: '-loc-divider-width'
(794,22): run-time error CSS1039: Token not allowed after unary operator: '-loc-divider-thickness'
(794,56): run-time error CSS1039: Token not allowed after unary operator: '-loc-divider-style'
(794,88): run-time error CSS1039: Token not allowed after unary operator: '-loc-divider-color'
(794,113): run-time error CSS1039: Token not allowed after unary operator: '-bs-border-color'
(873,28): run-time error CSS1039: Token not allowed after unary operator: '-bs-border-color'
(879,22): run-time error CSS1039: Token not allowed after unary operator: '-bs-primary'
(880,24): run-time error CSS1039: Token not allowed after unary operator: '-bs-primary'
(890,35): run-time error CSS1039: Token not allowed after unary operator: '-bs-border-color'
(992,22): run-time error CSS1039: Token not allowed after unary operator: '-bs-box-shadow'
(993,24): run-time error CSS1039: Token not allowed after unary operator: '-loc-card-border-width'
(994,25): run-time error CSS1039: Token not allowed after unary operator: '-bs-border-radius'
(1000,22): run-time error CSS1039: Token not allowed after unary operator: '-loc-card-hover-shadow'
(1000,51): run-time error CSS1039: Token not allowed after unary operator: '-bs-box-shadow'
(1001,21): run-time error CSS1039: Token not allowed after unary operator: '-loc-card-hover-transform'
(1171,25): run-time error CSS1039: Token not allowed after unary operator: '-bs-border-radius'
(1200,17): run-time error CSS1062: Expected semicolon or closing curly-brace, found '-'
(1201,21): run-time error CSS1062: Expected semicolon or closing curly-brace, found '-'
(1202,19): run-time error CSS1062: Expected semicolon or closing curly-brace, found '-'
(1203,20): run-time error CSS1062: Expected semicolon or closing curly-brace, found '-'
(1204,19): run-time error CSS1062: Expected semicolon or closing curly-brace, found '-'
(1207,24): run-time error CSS1039: Token not allowed after unary operator: '-imgw-ar'
(1217,24): run-time error CSS1039: Token not allowed after unary operator: '-imgw-ar'
(1243,10): run-time error CSS1030: Expected identifier, found '.'
(1243,60): run-time error CSS1031: Expected selector, found ')'
(1243,60): run-time error CSS1025: Expected comma or open brace, found ')'
(1262,28): run-time error CSS1039: Token not allowed after unary operator: '-loc-rowbg-color'
(1263,28): run-time error CSS1039: Token not allowed after unary operator: '-loc-rowbg-image'
(1311,5): run-time error CSS1030: Expected identifier, found '.'
(1311,38): run-time error CSS1031: Expected selector, found ')'
(1311,38): run-time error CSS1025: Expected comma or open brace, found ')'
(1329,40): run-time error CSS1030: Expected identifier, found '.'
(1329,55): run-time error CSS1031: Expected selector, found ')'
(1329,55): run-time error CSS1025: Expected comma or open brace, found ')'
(1336,40): run-time error CSS1030: Expected identifier, found '.'
(1336,71): run-time error CSS1031: Expected selector, found ')'
(1336,71): run-time error CSS1025: Expected comma or open brace, found ')'
(1341,28): run-time error CSS1039: Token not allowed after unary operator: '-loc-navbar-h'
(1476,17): run-time error CSS1039: Token not allowed after unary operator: '-bs-emphasis-color'
(1477,35): run-time error CSS1039: Token not allowed after unary operator: '-bs-primary'
(1496,17): run-time error CSS1039: Token not allowed after unary operator: '-bs-body-color'
(1497,28): run-time error CSS1039: Token not allowed after unary operator: '-bs-body-bg'
(1498,18): run-time error CSS1039: Token not allowed after unary operator: '-bs-border-width'
(1498,52): run-time error CSS1039: Token not allowed after unary operator: '-bs-border-color'
(1499,25): run-time error CSS1039: Token not allowed after unary operator: '-bs-border-radius'
(1504,17): run-time error CSS1039: Token not allowed after unary operator: '-bs-body-color'
(1507,17): run-time error CSS1039: Token not allowed after unary operator: '-bs-secondary-color'
(1519,24): run-time error CSS1039: Token not allowed after unary operator: '-bs-primary'
(1520,41): run-time error CSS1039: Token not allowed after unary operator: '-bs-primary-rgb'
(1532,17): run-time error CSS1039: Token not allowed after unary operator: '-bs-body-color'
(1533,28): run-time error CSS1039: Token not allowed after unary operator: '-bs-body-bg'
(1534,18): run-time error CSS1039: Token not allowed after unary operator: '-bs-border-width'
(1534,52): run-time error CSS1039: Token not allowed after unary operator: '-bs-border-color'
(1535,25): run-time error CSS1039: Token not allowed after unary operator: '-bs-border-radius'
(1538,25): run-time error CSS1039: Token not allowed after unary operator: '-bs-border-radius-sm'
(1543,17): run-time error CSS1039: Token not allowed after unary operator: '-bs-body-color'
(1544,28): run-time error CSS1039: Token not allowed after unary operator: '-bs-body-bg'
(1545,24): run-time error CSS1039: Token not allowed after unary operator: '-bs-border-color'
(1546,25): run-time error CSS1039: Token not allowed after unary operator: '-bs-border-radius'
(1549,17): run-time error CSS1039: Token not allowed after unary operator: '-bs-body-color'
(1550,28): run-time error CSS1039: Token not allowed after unary operator: '-bs-body-bg'
(1551,18): run-time error CSS1039: Token not allowed after unary operator: '-bs-border-width'
(1551,52): run-time error CSS1039: Token not allowed after unary operator: '-bs-border-color'
(1552,25): run-time error CSS1039: Token not allowed after unary operator: '-bs-border-radius-sm'
(1555,28): run-time error CSS1039: Token not allowed after unary operator: '-bs-primary'
(1598,24): run-time error CSS1039: Token not allowed after unary operator: '-bs-primary'
(1664,17): run-time error CSS1039: Token not allowed after unary operator: '-bs-secondary-color'
(1672,25): run-time error CSS1039: Token not allowed after unary operator: '-bs-border-radius'
(1680,28): run-time error CSS1039: Token not allowed after unary operator: '-bs-primary'
(1681,17): run-time error CSS1039: Token not allowed after unary operator: '-bs-body-color'
(1689,28): run-time error CSS1039: Token not allowed after unary operator: '-bs-secondary-bg'
(1697,28): run-time error CSS1039: Token not allowed after unary operator: '-bs-primary'
(1698,17): run-time error CSS1039: Token not allowed after unary operator: '-bs-white'
(1776,5): run-time error CSS1062: Expected semicolon or closing curly-brace, found '-'
(1780,23): run-time error CSS1039: Token not allowed after unary operator: '-loc-navbar-h'
(1799,23): run-time error CSS1039: Token not allowed after unary operator: '-loc-navbar-h'
(1821,52): run-time error CSS1030: Expected identifier, found '.'
(1821,53): run-time error CSS1030: Expected identifier, found 'modal-body'
(1821,63): run-time error CSS1031: Expected selector, found ')'
(1821,63): run-time error CSS1025: Expected comma or open brace, found ')'
(1832,5): run-time error CSS1062: Expected semicolon or closing curly-brace, found '-'
(1833,5): run-time error CSS1062: Expected semicolon or closing curly-brace, found '-'
(1834,5): run-time error CSS1062: Expected semicolon or closing curly-brace, found '-'
(1841,25): run-time error CSS1039: Token not allowed after unary operator: '-bs-border-radius'
(1901,40): run-time error CSS1039: Token not allowed after unary operator: '-loc-gallery-cols'
(1902,15): run-time error CSS1039: Token not allowed after unary operator: '-loc-gallery-gap'
(1906,24): run-time error CSS1039: Token not allowed after unary operator: '-loc-gallery-ratio'
(1911,24): run-time error CSS1039: Token not allowed after unary operator: '-loc-gallery-cols'
(1912,22): run-time error CSS1039: Token not allowed after unary operator: '-loc-gallery-gap'
(1917,25): run-time error CSS1039: Token not allowed after unary operator: '-loc-gallery-gap'
(1931,15): run-time error CSS1039: Token not allowed after unary operator: '-loc-gallery-gap'
(1944,34): run-time error CSS1039: Token not allowed after unary operator: '-loc-gallery-cols'
(1944,65): run-time error CSS1039: Token not allowed after unary operator: '-loc-gallery-gap'
(1944,91): run-time error CSS1039: Token not allowed after unary operator: '-loc-gallery-cols'
(1946,24): run-time error CSS1039: Token not allowed after unary operator: '-loc-gallery-ratio'
(2001,22): run-time error CSS1039: Token not allowed after unary operator: '-bs-primary'
(2009,9): run-time error CSS1062: Expected semicolon or closing curly-brace, found '-'
(2013,9): run-time error CSS1062: Expected semicolon or closing curly-brace, found '-'
(2139,28): run-time error CSS1039: Token not allowed after unary operator: '-bs-border-color'
(2143,29): run-time error CSS1039: Token not allowed after unary operator: '-bs-primary'
(2161,17): run-time error CSS1039: Token not allowed after unary operator: '-bs-body-color'
(2188,25): run-time error CSS1039: Token not allowed after unary operator: '-bs-border-radius'
(2191,22): run-time error CSS1039: Token not allowed after unary operator: '-bs-body-bg'
(2275,28): run-time error CSS1039: Token not allowed after unary operator: '-bs-border-color'
(2291,22): run-time error CSS1039: Token not allowed after unary operator: '-bs-primary'
(2292,24): run-time error CSS1039: Token not allowed after unary operator: '-bs-primary'
(2470,25): run-time error CSS1039: Token not allowed after unary operator: '-bs-border-radius'
(2504,25): run-time error CSS1039: Token not allowed after unary operator: '-bs-border-radius'
(2535,28): run-time error CSS1039: Token not allowed after unary operator: '-bs-border-color'
(2540,29): run-time error CSS1039: Token not allowed after unary operator: '-bs-primary'
(2545,29): run-time error CSS1039: Token not allowed after unary operator: '-bs-primary'
(2556,28): run-time error CSS1039: Token not allowed after unary operator: '-bs-card-bg'
(2557,32): run-time error CSS1039: Token not allowed after unary operator: '-bs-border-color'
(2939,24): run-time error CSS1039: Token not allowed after unary operator: '-bs-primary'
(2941,17): run-time error CSS1039: Token not allowed after unary operator: '-bs-primary'
 */
/* =========================================
   LOVEOURCLUB - BOOTSTRAP 5 CLEANED VERSION
   ========================================= */

/* -----------------------------------------
   FONTS - self-hosted Inter (the default theme's body font; themes can still override).
   Uses Inter's single variable font file (all weights 100-900). Drop the files into
   /Content/fonts/ (see below); until then the font-family gracefully falls back to system-ui.
     - InterVariable.woff2         (upright)
     - InterVariable-Italic.woff2  (italic)
   Source: https://github.com/rsms/inter/releases (the "Inter-*.zip" -> "web" folder).
   ----------------------------------------- */
@font-face {
    font-family: 'Inter';
    font-style: normal;
    font-weight: 100 900;
    font-display: swap;
    src: url('fonts/InterVariable.woff2') format('woff2');
}

@font-face {
    font-family: 'Inter';
    font-style: italic;
    font-weight: 100 900;
    font-display: swap;
    src: url('fonts/InterVariable-Italic.woff2') format('woff2');
}

/* A little typographic personality for website headings: slightly heavier + tighter tracking than the
   Bootstrap default, so titles read as "designed" rather than templated. Scoped to .website content. */
.website h1, .website h2, .website h3,
.website h4, .website h5, .website h6 {
    font-weight: 600;
    letter-spacing: -0.01em;
}

/* -----------------------------------------
   MARKETING (SaaS) PAGES - the public Home controller pages (_Layout). One fluid page title that scales
   with the viewport (replaces the old server-side mobile/desktop h2/h3 branch), and a centered, readable
   content column (replaces the per-row "margin: 2% 2%" inline styles).
   ----------------------------------------- */
.loc-page-title {
    font-size: clamp(1.6rem, 1rem + 2.4vw, 2.5rem);
    font-weight: 600;
    line-height: 1.2;
    margin-bottom: 0.5rem;
}

.loc-page-subtitle {
    font-size: clamp(1rem, 0.9rem + 0.6vw, 1.25rem);
    font-weight: 400;
    color: var(--bs-secondary-color, #6c757d);
    margin-bottom: 0;
}

/* Match the Bootstrap .container widths so marketing sections line up with the home page. */
.loc-marketing-section {
    width: 100%;
    margin: 1.5rem auto 0;
    padding: 0 var(--bs-gutter-x, 1.5rem);
}

@media (min-width: 576px) {
    .loc-marketing-section {
        max-width: 540px;
    }
}

@media (min-width: 768px) {
    .loc-marketing-section {
        max-width: 720px;
    }
}

@media (min-width: 992px) {
    .loc-marketing-section {
        max-width: 960px;
    }
}

@media (min-width: 1200px) {
    .loc-marketing-section {
        max-width: 1140px;
    }
}

@media (min-width: 1400px) {
    .loc-marketing-section {
        max-width: 1320px;
    }
}

/* -----------------------------------------
   NAVBAR (mobile scroll fix)
   ----------------------------------------- */
@media (max-width: 1199px) {
    .navbar {
        overflow-y: auto;
        max-height: 85vh;
        align-items: flex-start;
    }

    #navbar-title {
        display: block;
    }
}

@media (min-width: 1200px) {
    #navbar-title {
        display: none;
    }
}

/* -----------------------------------------
   NAVBAR DENSITY
   Bootstrap 5's default nav-link padding is taller/wider than the previous theme, which
   made the top menu wrap to extra rows. Because the content's top offset is set in JS from
   the navbar height ($("#navbar").outerHeight()), a taller navbar pushed content + footer
   past 100vh and produced page scrollbars. Tighten the spacing back down.
   ----------------------------------------- */
/* Doubled/descendant selectors raise specificity so these win over loc-theme-modern.css,
   which is linked after this file. Horizontal padding is left at the BS5 default (0 inside
   the navbar) — adding it would widen items and cause more wrapping. The vertical padding is
   the club theme's navbar height token (--loc-navbar-pad-y), falling back to the old compact
   value when no theme is loaded. */
.navbar.navbar {
    padding-top: var(--loc-navbar-pad-y, 0.25rem);
    padding-bottom: var(--loc-navbar-pad-y, 0.25rem);
}

.navbar .navbar-nav .nav-link {
    padding-top: 0.3rem;
    padding-bottom: 0.3rem;
}

/* -----------------------------------------
   NAVBAR (theme-driven style)
   The website navbar's appearance is a Club Theme token set, emitted as --loc-navbar-*
   variables by /ClubTheme.css (see ThemeController) and consumed here. The layouts add the
   .loc-navbar class and no longer bake in navbar-light/dark or bg-* utilities, so background,
   text/hover/active colour, height, logo size, border, shadow and link typography all come
   from the selected theme. Bootstrap's own --bs-navbar-* vars are set from ours so the brand,
   links and dropdown toggles pick up the colours without needing the light/dark classes.
   ----------------------------------------- */
.loc-navbar {
    --bs-navbar-color: var(--loc-navbar-color, #fff);
    --bs-navbar-hover-color: var(--loc-navbar-hover-color, rgba(255, 255, 255, 0.8));
    --bs-navbar-active-color: var(--loc-navbar-active-color, #fff);
    --bs-navbar-brand-color: var(--loc-navbar-color, #fff);
    --bs-navbar-brand-hover-color: var(--loc-navbar-hover-color, rgba(255, 255, 255, 0.8));
    --bs-navbar-toggler-border-color: transparent;
    background: var(--loc-navbar-bg, var(--bs-primary, #2e7d32));
    border-bottom: var(--loc-navbar-border-bottom, none);
    box-shadow: var(--loc-navbar-shadow, none);
    -webkit-backdrop-filter: var(--loc-navbar-backdrop, none);
    backdrop-filter: var(--loc-navbar-backdrop, none);
}

.loc-navbar .navbar-nav .nav-link {
    font-weight: var(--loc-navbar-link-weight, 400);
    text-transform: var(--loc-navbar-link-transform, none);
    letter-spacing: var(--loc-navbar-link-spacing, normal);
    /* Nav links inherit the theme's --bs-body-line-height; a Relaxed/Spacious body setting makes them
       look oddly tall stacked in the bar. Pin a compact navbar line-height so the bar stays tidy
       regardless of the body text setting. */
    line-height: 1.2;
}

.loc-navbar .loc-navbar-logo {
    height: var(--loc-navbar-logo-h, 40px);
    width: auto;
    max-width: var(--loc-navbar-logo-maxw, 200px);
    object-fit: contain;
    float: left;
    position: relative;
}

.loc-navbar #navbar-title {
    color: var(--loc-navbar-color, #fff);
}

/* Recolour the hamburger to match the navbar text colour by masking the icon instead of relying
   on Bootstrap's fixed light/dark background-image. */
.loc-navbar .navbar-toggler-icon {
    background-image: none;
    background-color: var(--loc-navbar-color, #fff);
    -webkit-mask: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='%23000' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e") center / 100% 100% no-repeat;
    mask: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='%23000' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e") center / 100% 100% no-repeat;
}

/* When the bar collapses (navbar-expand-md → below 768px) it expands into a tall vertical menu.
   A transparent theme is unreadable there, so fall back to the solid mobile background + a dark
   text colour (both resolved server-side into the -mobile variables). */
@media (max-width: 767.98px) {
    .loc-navbar {
        background: var(--loc-navbar-bg-mobile, #fff);
        --bs-navbar-color: var(--loc-navbar-color-mobile, var(--loc-navbar-color, #fff));
        --bs-navbar-brand-color: var(--loc-navbar-color-mobile, var(--loc-navbar-color, #fff));
    }

    .loc-navbar .navbar-toggler-icon {
        background-color: var(--loc-navbar-color-mobile, var(--loc-navbar-color, #fff));
    }
}

/* -----------------------------------------
   PAGE FRAME (theme-driven spacing)
   The website content area owns its own frame: outer padding + the gap between rows, both site-wide from
   the club theme (emitted as CSS variables by _PageSpacingVars). Rows stack in a flex column so --row-gap
   spaces them evenly (top row sits below the top padding, bottom row above the bottom padding). Values are
   rem; on phones they auto-scale down. Fallbacks (1rem) keep it sane if the theme vars are ever missing.
   ----------------------------------------- */
.website {
    display: flex;
    flex-direction: column;
    gap: var(--row-gap, 1rem);
    /* The site always sits inside a .container-fluid, which adds Bootstrap's default gutter on each side.
       Negate it with the SAME inherited --bs-gutter-x so it cancels exactly (any gutter value/breakpoint),
       making the Club Theme's page padding the sole horizontal frame - page spacing 0 = truly edge-to-edge. */
    margin-left: calc(-0.5 * var(--bs-gutter-x, 1.5rem));
    margin-right: calc(-0.5 * var(--bs-gutter-x, 1.5rem));
    padding: var(--page-pad-top, 1rem) var(--page-pad-side, 1rem) var(--page-pad-bottom, 1rem);
}

@media (max-width: 767.98px) {
    .website {
        gap: calc(var(--row-gap, 1rem) * 0.6);
        padding: calc(var(--page-pad-top, 1rem) * 0.6) calc(var(--page-pad-side, 1rem) * 0.6) calc(var(--page-pad-bottom, 1rem) * 0.6);
    }
}

/* -----------------------------------------
   GLOBAL UTILITIES
   ----------------------------------------- */

.content-image {
    margin-inline: 5px;
}

.show-white-space {
    white-space: pre-wrap;
}

.cursor-wait {
    cursor: wait;
}

/* -----------------------------------------
   FORMS (SAFE MODERN APPROACH)
   ----------------------------------------- */

/* Replace global override with opt-in */
.form-control-fixed {
    max-width: 300px;
    min-width: 200px;
}

.form-control:disabled {
    background-color: var(--bs-secondary-bg);
}

/* Smaller variants */
/* For 1-2 digit numeric inputs (day, month) sitting inline with a wider field. */
.form-control-xxsmall {
    max-width: 80px;
    min-width: 50px;
}

.form-control-xsmall {
    max-width: 200px;
    min-width: 50px;
}

.form-control-small {
    max-width: 300px;
    min-width: 200px;
}

.form-control-large {
    max-width: 300px;
    min-width: 300px;
}

.form-control-xlarge {
    max-width: 100%;
    min-width: 200px;
}

.form-control-date {
    width: 270px;
    min-width: 270px;
}

/* Better focus handling */
.form-control:focus {
    box-shadow: 0 0 0 0.2rem rgba(var(--bs-primary-rgb), 0.25);
}

/* Field labels sit on their own line ABOVE the control. A plain <label> is display:inline,
   so it only ends up "above" the field because a block .form-control drops onto the next
   line. Controls whose rendered markup is inline-block - notably Select2's
   .select2-container - would otherwise sit BESIDE the label. Making the label block keeps
   the label-on-top layout consistent no matter what control follows. */
.control-label {
    display: block;
}

/* Alphabet filter buttons (booking player selector): fix the width so every button is the
   same size regardless of the letter's glyph width ("I" vs "W"). */
.btn-letter {
    width: 30px;
    padding-left: 0;
    padding-right: 0;
    text-align: center;
}

/* Website builder: a row/column toggled to hidden (Active = false) stays visible in the editor
   so it can be toggled back, but is dimmed to signal it won't show to real viewers. */
.builder-row-hidden {
    opacity: 0.45;
}

/* Builder selection indicator: outlines the element the open toolbar is editing, colour-coded by level
   (row / column / widget) with a corner label, so it's obvious what's selected. Uses outline (no layout
   shift) and is added by website.js only in edit mode - never part of the saved markup. */
.builder-selected-row,
.builder-selected-column,
.builder-selected-widget {
    position: relative;
    outline-offset: -2px;
}

.builder-selected-row {
    outline: 2px dashed #0d6efd;
}

.builder-selected-column {
    outline: 2px dashed #20c997;
}

.builder-selected-widget {
    outline: 2px dashed #fd7e14;
}

.builder-selected-row::before,
.builder-selected-column::before {
    position: absolute;
    top: 0;
    left: 0;
    z-index: 5;
    padding: 2px 6px;
    font-size: 0.7rem;
    line-height: 1;
    color: #fff;
    white-space: nowrap;
    border-bottom-right-radius: 4px;
    pointer-events: none;
}

.builder-selected-row::before {
    content: "Row";
    background: #0d6efd;
}

.builder-selected-column::before {
    content: "Column";
    background: #20c997;
}

/* A widget's label is always shown (.columncontent::before); selecting it just recolours that same label
   to orange - nothing moves, so selection reads clearly without the layout shifting. */
.builder-selected-widget::before {
    z-index: 6;
    background: #fd7e14;
    font-weight: 700;
}

/* Settings-toolbar heading naming what's being edited; colour matches the selection outline. */
.toolbar-edit-label {
    margin: 0 0.75rem 0.5rem;
    padding: 4px 10px;
    font-weight: 600;
    color: #fff;
    border-radius: 4px;
}

.toolbar-edit-label-row {
    background: #0d6efd;
}

.toolbar-edit-label-column {
    background: #20c997;
}

.toolbar-edit-label-widget {
    background: #fd7e14;
}

/* Builder structure chrome: always-on subtle inset outlines so the row/column hierarchy is legible at a
   glance - blue = row, teal = column (matching the selection colours) - emphasised on hover, with a small
   corner label revealed on hover. Inset box-shadow (not outline) so it never fights the selection outline.
   Scoped to .website-builder so published pages are unaffected. */
.website-builder .rowcontent {
    position: relative;
    box-shadow: inset 0 0 0 1px rgba(13, 110, 253, 0.25);
}

.website-builder .rowcontent:hover {
    box-shadow: inset 0 0 0 1px rgba(13, 110, 253, 0.6);
}

.columncolumn {
    position: relative;
    min-height: 42px;
    box-shadow: inset 0 0 0 1px rgba(32, 201, 151, 0.35);
}

.columncolumn:hover {
    box-shadow: inset 0 0 0 1px rgba(32, 201, 151, 0.85);
}

/* Every widget carries a stable "Row X - Col Y - Type" label (set by website.js from the live DOM order),
   always visible so the layout reads at a glance with nothing moving on hover. Hover just bolds it;
   selection turns it orange (see .builder-selected-widget::before). The column keeps its outline (above)
   but no longer needs its own text label - which also removes the teal sliver behind the widget label. */
.columncontent {
    position: relative;
}

.columncontent:not(.parentPageColumn)::before {
    content: attr(data-widget-label);
    position: absolute;
    top: 0;
    left: 0;
    z-index: 4;
    padding: 2px 6px;
    font-size: 0.68rem;
    line-height: 1;
    color: #fff;
    white-space: nowrap;
    background: rgba(33, 37, 41, 0.6);
    border-bottom-right-radius: 4px;
    pointer-events: none;
}

.columncontent:not(.parentPageColumn):hover::before {
    font-weight: 700;
    background: rgba(33, 37, 41, 0.82);
}

/* Website builder toolbox: the widget-type tiles you drag onto the canvas. Uniform icon-over-label
   buttons in a two-column grid, with a hover lift to read as draggable. */
.toolbox-grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 8px;
    padding: 8px;
}

.toolbox-item {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 6px;
    padding: 12px 8px;
    text-align: center;
    font-size: 0.8rem;
    font-weight: 500;
    color: #333;
    background: #fff;
    border: 1px solid #dee2e6;
    border-radius: 8px;
    cursor: move;
    user-select: none;
    transition: color 0.12s ease, border-color 0.12s ease, background 0.12s ease, box-shadow 0.12s ease, transform 0.12s ease;
}

.toolbox-item i {
    font-size: 1.25rem;
    color: #0d6efd;
}

.toolbox-item:hover {
    color: #0d6efd;
    border-color: #0d6efd;
    background: #f0f6ff;
    box-shadow: 0 2px 6px rgba(13, 110, 253, 0.15);
    transform: translateY(-1px);
}

/* Column drop zones (Droppable.cshtml): inert and invisible at rest (z-index:-100, behind content). While
   a column or toolbox widget is being dragged (.dragging-column set by website.js), all four zones surface
   above the content as quiet target regions, and the zone under the cursor gets a bold, labelled highlight
   - so the drop target is obvious even when the column is full of content. */
.website-builder.dragging-column .droppable-wrapper > div {
    z-index: 60 !important;
    background: rgba(13, 110, 253, 0.06);
    border: 2px dashed rgba(13, 110, 253, 0.35);
    border-radius: 4px;
}

.website-builder.dragging-column .droppable-wrapper > div.ui-state-hover {
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 0.75rem;
    font-weight: 600;
    color: #fff;
    text-align: center;
    background: rgba(13, 110, 253, 0.82);
    border-style: solid;
    border-color: #0d6efd;
    box-shadow: 0 0 0 2px #0d6efd;
}

.website-builder.dragging-column .droppable-top.ui-state-hover::after { content: "Row above"; }
.website-builder.dragging-column .droppable-bottom.ui-state-hover::after { content: "Row below"; }
.website-builder.dragging-column .droppable-left.ui-state-hover::after { content: "Column left"; }
.website-builder.dragging-column .droppable-right.ui-state-hover::after { content: "Column right"; }

/* Type picker popped from the "Add Widget to Column" context-menu action. */
.add-widget-menu {
    position: absolute;
    z-index: 1500;
    min-width: 150px;
    overflow: hidden;
    background: #fff;
    border: 1px solid #ccc;
    border-radius: 6px;
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
}

.add-widget-option {
    padding: 6px 12px;
    font-size: 0.9rem;
    cursor: pointer;
}

.add-widget-option:hover {
    background: #0d6efd;
    color: #fff;
}

/* Member summary widget: modern horizontal tiles. (Under BS5 the old .row layout stacked vertically
   because .row > * forces width:100% on non-column children; this uses a flex-wrap tile row instead.) */
.summary-dashboard {
    padding: 1rem;
}

.summary-greeting {
    margin: 0.5rem 0 1.5rem;
    font-weight: 600;
    text-align: center;
}

.summary-tiles {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 1rem;
}

.summary-tile {
    display: flex;
    flex-direction: column;
    align-items: center;
    width: 190px;
    padding: 1.25rem 1rem;
    background: #fff;
    border-radius: 14px;
    box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
    transition: transform 0.15s ease, box-shadow 0.15s ease;
}

.summary-tile:hover {
    transform: translateY(-4px);
    box-shadow: 0 10px 24px rgba(0, 0, 0, 0.13);
}

.summary-tile-icon {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 58px;
    height: 58px;
    margin-bottom: 0.85rem;
    font-size: 1.5rem;
    color: #fff;
    border-radius: 50%;
    cursor: pointer;
}

.summary-tile-text {
    flex: 1 1 auto;
    display: flex;
    flex-direction: column;
    justify-content: center;
    min-height: 2.75rem;
    margin-bottom: 0.85rem;
    text-align: center;
}

.summary-tile-primary {
    font-weight: 600;
    line-height: 1.3;
}

.summary-tile-secondary {
    color: #6c757d;
    font-size: 0.9rem;
    line-height: 1.3;
}

.summary-tile-btn {
    min-width: 130px;
    border-radius: 999px;
}

.summary-icon-profile {
    background: #0d6efd;
}

.summary-icon-bookings {
    background: #20c997;
}

.summary-icon-events {
    background: #fd7e14;
}

.summary-icon-news {
    background: #6f42c1;
}

.summary-icon-membership {
    background: #d63384;
}

.summary-icon-balance {
    background: #198754;
}

/* --- Summary: List format (compact rows) --- */
.summary-list {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    max-width: 520px;
    margin: 0 auto;
}

.summary-row {
    display: flex;
    align-items: center;
    gap: 0.9rem;
    padding: 0.7rem 0.9rem;
    background: #fff;
    border-radius: 12px;
    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.07);
    cursor: pointer;
    transition: transform 0.12s ease, box-shadow 0.12s ease;
}

.summary-row:hover {
    transform: translateX(3px);
    box-shadow: 0 6px 16px rgba(0, 0, 0, 0.12);
}

.summary-row-icon {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    font-size: 1.15rem;
    color: #fff;
    border-radius: 50%;
}

.summary-row-text {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
}

.summary-row-primary {
    font-weight: 600;
    line-height: 1.25;
}

.summary-row-secondary {
    color: #6c757d;
    font-size: 0.88rem;
    line-height: 1.25;
}

.summary-row-chevron {
    flex: 0 0 auto;
    color: #b0b7c0;
    font-size: 0.85rem;
}

/* --- Summary: Compact format (icon chips) --- */
.summary-compact {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 0.6rem;
}

.summary-chip {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.4rem 0.8rem 0.4rem 0.4rem;
    background: #fff;
    border-radius: 999px;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
    cursor: pointer;
    transition: transform 0.12s ease, box-shadow 0.12s ease;
}

.summary-chip:hover {
    transform: translateY(-2px);
    box-shadow: 0 6px 14px rgba(0, 0, 0, 0.13);
}

.summary-chip-icon {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    font-size: 0.95rem;
    color: #fff;
    border-radius: 50%;
}

.summary-chip-label {
    font-weight: 600;
    font-size: 0.9rem;
}

.summary-chip-value {
    background: var(--bs-primary, #0d6efd);
    color: #fff;
    font-size: 0.75rem;
    font-weight: 700;
    min-width: 1.4rem;
    text-align: center;
    padding: 0.05rem 0.45rem;
    border-radius: 999px;
}

@media (prefers-color-scheme: dark) {
    .summary-row,
    .summary-chip { background: #2b3035; }
}

/* Divider / Spacer widget. The container reserves the widget's vertical space (min-height set inline
   from the Height field) and centres the optional rule; when the line is off it is simply whitespace.
   The rule itself is drawn with a top border so LineStyle maps straight to CSS (solid/dashed/dotted). */
.loc-divider {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
}

.loc-divider-line {
    margin: 0;
    opacity: 1;
    box-sizing: border-box;
}

/* Themed section divider: a row shows this below itself via "Show divider". Its look comes entirely from the
   Club Theme (emitted as --loc-divider-* by /ClubTheme.css), so one theme change restyles every divider on
   every page. It sits between rows in the .website flex column, centered at the theme's chosen width. */
.loc-row-divider {
    display: flex;
    justify-content: center;
    width: 100%;
    /* The .website flex gap already puts a normal row gap ABOVE the line (so it sits where the row would
       normally end). The space AFTER the line is the theme's Space-after: we adjust the bottom margin by the
       difference from the row gap so the total below the line equals Space-after (can be tighter or wider). */
    margin-bottom: calc(var(--loc-divider-space-after, 1rem) - var(--row-gap, 1rem));
}

.loc-row-divider .loc-row-divider-line {
    width: var(--loc-divider-width, 100%);
    border-top: var(--loc-divider-thickness, 1px) var(--loc-divider-style, solid) var(--loc-divider-color, var(--bs-border-color, #dee2e6));
}

/* Full-width SVG shape (wave/slant/curve/zigzag/triangle). Block so it fills the divider's width/height. */
.loc-divider-shape {
    display: block;
}

/* Line with a centered ornament: two flexible line segments either side of the ornament, all vertically
   centered. The ornament inherits the line colour via currentColor. */
.loc-divider-accentline {
    display: flex;
    align-items: center;
    gap: 0.6rem;
}

.loc-divider-accentline .loc-divider-seg {
    flex: 1 1 auto;
    height: 0;
}

.loc-divider-ornament {
    flex: 0 0 auto;
    color: currentColor;
}

/* Diamond: a small rotated square. */
.loc-divider-ornament-diamond {
    width: 0.55rem;
    height: 0.55rem;
    background: currentColor;
    transform: rotate(45deg);
}

/* Circle: a small filled dot. */
.loc-divider-ornament-circle {
    width: 0.6rem;
    height: 0.6rem;
    background: currentColor;
    border-radius: 50%;
}

/* Dots: three small filled dots. The element is the middle dot; box-shadow paints the outer two, and the
   side margins reserve room for them so they don't overlap the line segments. */
.loc-divider-ornament-dots {
    width: 0.35rem;
    height: 0.35rem;
    background: currentColor;
    border-radius: 50%;
    margin: 0 0.65rem;
    box-shadow: -0.65rem 0 0 currentColor, 0.65rem 0 0 currentColor;
}

/* Content List widget: the accordion / tabs markup is Bootstrap's (styled by the theme); these rules
   cover the widget's own chrome - the title, the visitor format toggle, the empty state, and the plain
   "list" format which is not a Bootstrap component. */
.loc-contentlist {
    width: 100%;
}

.loc-cl-title {
    margin-bottom: 0.75rem;
}

.loc-cl-empty {
    padding: 1rem;
    text-align: center;
    color: #888;
    font-style: italic;
}

.loc-cl-toggle {
    display: flex;
    justify-content: flex-end;
    gap: 0;
    margin-bottom: 0.5rem;
}

.loc-cl-toggle-btn {
    border: 1px solid var(--bs-border-color, #dee2e6);
    background: transparent;
    color: inherit;
}

.loc-cl-toggle-btn.active {
    background: var(--bs-primary, #0d6efd);
    border-color: var(--bs-primary, #0d6efd);
    color: #fff;
}

.loc-cl-tab-body {
    padding: 1rem 0.25rem;
}

.loc-cl-list-item {
    padding: 0.75rem 0;
    border-bottom: 1px solid var(--bs-border-color, #dee2e6);
}

.loc-cl-list-item:last-child {
    border-bottom: 0;
}

.loc-cl-list-header {
    margin-bottom: 0.35rem;
}

/* Custom HTML widget: the block renders in a sandboxed iframe. In the builder a transparent overlay sits
   over the frame so the widget stays selectable/draggable; published pages have no .columncontent ancestor,
   so the overlay is hidden and the iframe is interactive. */
.loc-customhtml {
    position: relative;
    width: 100%;
}

.loc-customhtml-frame {
    width: 100%;
    border: 0;
    display: block;
}

.loc-customhtml-overlay {
    display: none;
}

.columncontent .loc-customhtml-overlay {
    display: block;
    position: absolute;
    inset: 0;
    z-index: 2;
    cursor: move;
}

.loc-customhtml-empty {
    padding: 1rem;
    text-align: center;
    color: #888;
    font-style: italic;
}

/* Structured image widget: image + caption arrangement is driven by CSS classes (imgw-pos-*), composed
   server-side (ShowImage.cshtml). Responsive - side-by-side positions stack on narrow screens. */
.imgw-img {
    max-width: 100%;
    height: auto;
    display: block;
}

/* "Rounded" shape: a clearly-visible radius - Bootstrap's .rounded (~6px) is too subtle on a large image. */
.imgw-rounded {
    border-radius: 1rem;
}

/* Builder-only: empty editable regions (image title/caption, card header/body/footer) are otherwise
   invisible and near-impossible to click into. Frame them with a dashed border + a "click to add..."
   placeholder so the region's bounds are obvious and easy to target. Never shown on the published site
   (there is no .website-builder there) or once the region has content (:empty stops matching). */
.website-builder .editable-content:empty {
    min-height: 2rem;
    border: 1px dashed #b0b7c0;
    border-radius: 4px;
    background: rgba(0, 0, 0, 0.015);
}

.website-builder .editable-content:empty::before {
    content: "Click to edit";
    color: #9aa2ac;
    font-size: 0.85rem;
    font-style: italic;
    pointer-events: none;
}

.website-builder .editable-content.title:empty::before { content: "Click to add a title"; }
.website-builder .editable-content.text:empty::before { content: "Click to add text"; }
.website-builder .editable-content.description:empty::before { content: "Click to add a description"; }
.website-builder .editable-content[name="Header"]:empty::before { content: "Click to add a header"; }
.website-builder .editable-content[name="Body"]:empty::before { content: "Click to add body content"; }
.website-builder .editable-content[name="Footer"]:empty::before { content: "Click to add a footer"; }

/* Builder-only: the overlay text block on a background/hero image sits on top of the photo, so when its
   colour is close to the image (e.g. white text on a light photo) it's invisible and the user can't tell
   where to double-click to edit it. Outline the editable block even when it already has text, and give it a
   targetable min-size so an empty one is still easy to hit. Scoped to .website-builder - published pages
   show nothing. */
.website-builder .imgw-pos-bg .imgw-textblock {
    outline: 2px dashed rgba(13, 110, 253, 0.85);
    outline-offset: 2px;
    min-width: 2.5rem;
    min-height: 1.4rem;
}

/* Card widgets: rounding and shadow come from the SAME site-wide Club Theme tokens as buttons, inputs and
   the rest of the UI (--bs-border-radius / --bs-box-shadow, set by /ClubTheme.css from the theme's Corner
   Rounding + Shadow Depth), so the whole website shares one consistent look. Only the border on/off and the
   lift-on-hover remain card-specific (--loc-card-* from _PageSpacingVars). Scoped to .website so admin/member
   dashboard cards are unaffected. overflow:hidden clips the header/footer corners to the card radius so
   rounding looks right without touching each card's markup; the shadow sits outside, so it isn't clipped. */
.website .card {
    box-shadow: var(--bs-box-shadow, none);
    border-width: var(--loc-card-border-width, 1px);
    border-radius: var(--bs-border-radius, 0.375rem);
    overflow: hidden;
    transition: box-shadow 0.15s ease, transform 0.15s ease;
}

.website .card:hover {
    box-shadow: var(--loc-card-hover-shadow, var(--bs-box-shadow, none));
    transform: var(--loc-card-hover-transform, none);
}

/* Card header text contrast: when a header uses a colour preset, give its text a readable colour so it's
   visible on dark backgrounds (e.g. a dark/black theme primary) without the user hand-setting it - matching
   how Bootstrap's .text-bg-* utilities contrast the default palette. Dark-family presets get white text,
   light-family get dark text. A colour set explicitly in the editor still wins. */
.website .card-header.bg-primary,
.website .card-header.bg-secondary,
.website .card-header.bg-success,
.website .card-header.bg-danger,
.website .card-header.bg-dark {
    color: #fff;
}

.website .card-header.bg-info,
.website .card-header.bg-warning,
.website .card-header.bg-light {
    color: #212529;
}

/* Toolbar size editors (margin/padding, border radius, box shadow): a tidy 2-column grid of labelled px
   inputs with consistent widths and top-aligned labels. Replaces the old unstyled floating-label markup
   (.dynamic-form-group had a JS handler but no CSS), where the inline label text pushed each input to a
   different size and left the labels misaligned. */
.loc-size-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 0.5rem;
    margin-bottom: 0.5rem;
}

.loc-size-field {
    min-width: 0;
}

.loc-size-field > label {
    display: block;
    margin-bottom: 0.15rem;
    font-size: 0.72rem;
    color: #6c757d;
    white-space: nowrap;
}

.loc-size-field .input-group-text {
    font-size: 0.72rem;
    padding: 0.15rem 0.4rem;
}

/* Drop the leading/trailing margins that CKEditor's <p>/<h2> add inside the title & caption, so the
   Gap control (not stray content margins) is what sets the space between the image and the text. */
.imgw .editable-content > :first-child {
    margin-top: 0;
}

.imgw .editable-content > :last-child {
    margin-bottom: 0;
}

/* Above / Below - stacked, image centered */
.imgw-pos-above .imgw-media,
.imgw-pos-below .imgw-media {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
}

.imgw-pos-below .imgw-media {
    flex-direction: column-reverse;
}

/* The image is centered to its own width, but the caption should fill the widget width instead of
   shrinking to its content - so there's room to read it, and to use CKEditor when editing it. */
.imgw-pos-above .imgw-caption,
.imgw-pos-below .imgw-caption {
    align-self: stretch;
}

/* Left / Right - image beside text (wraps/stacks when narrow) */
.imgw-pos-left .imgw-media,
.imgw-pos-right .imgw-media {
    display: flex;
    flex-wrap: wrap;
}

.imgw-pos-left .imgw-media {
    flex-direction: row;
}

.imgw-pos-right .imgw-media {
    flex-direction: row-reverse;
}

.imgw-pos-left .imgw-img,
.imgw-pos-right .imgw-img {
    flex: 0 0 auto;
}

.imgw-pos-left .imgw-caption,
.imgw-pos-right .imgw-caption {
    flex: 1 1 0;
    min-width: 0;
}

/* Vertical alignment of the image row (Left/Right) and of overlay text (Background) */
.imgw-valign-start .imgw-media {
    align-items: flex-start;
}

.imgw-valign-center .imgw-media {
    align-items: center;
}

.imgw-valign-end .imgw-media {
    align-items: flex-end;
}

/* Gap 0-5 between image and text */
.imgw-gap-1 .imgw-media { gap: 0.25rem; }
.imgw-gap-2 .imgw-media { gap: 0.5rem; }
.imgw-gap-3 .imgw-media { gap: 1rem; }
.imgw-gap-4 .imgw-media { gap: 1.5rem; }
.imgw-gap-5 .imgw-media { gap: 3rem; }

/* Background - image fills, caption overlaid */
.imgw-pos-bg .imgw-media {
    position: relative;
}

.imgw-pos-bg .imgw-img {
    width: 100% !important;
}

.imgw-pos-bg .imgw-caption {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    padding: 1rem;
}

.imgw-pos-bg.imgw-valign-start .imgw-caption { justify-content: flex-start; }
.imgw-pos-bg.imgw-valign-center .imgw-caption { justify-content: center; }
.imgw-pos-bg.imgw-valign-end .imgw-caption { justify-content: flex-end; }
.imgw-pos-bg.imgw-halign-start .imgw-caption { text-align: left; align-items: flex-start; }
.imgw-pos-bg.imgw-halign-center .imgw-caption { text-align: center; align-items: center; }
.imgw-pos-bg.imgw-halign-end .imgw-caption { text-align: right; align-items: flex-end; }

/* Optional dark overlay behind background text for legibility */
.imgw-pos-bg.imgw-overlay .imgw-caption::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: 0;
    background: rgba(0, 0, 0, 0.4);
}

.imgw-pos-bg .imgw-caption > * {
    position: relative;
    z-index: 1;
}

/* Optional semi-transparent plate behind the caption text, so it stays legible over any image without
   darkening the whole picture the way the full overlay does. The plate is on the single inner text block
   (imgw-textblock), which the flex alignment shrinks to its content - so the WHOLE caption, however many
   lines, sits on ONE rounded panel rather than one highlight per line. Dark plate pairs with light text;
   light plate pairs with dark text. */
.imgw-pos-bg .imgw-textblock.imgw-textplate {
    padding: 0.5em 0.85em;
    border-radius: var(--bs-border-radius, 0.375rem);
}

.imgw-pos-bg .imgw-textblock.imgw-textplate-dark {
    background: rgba(0, 0, 0, 0.5);
}

.imgw-pos-bg .imgw-textblock.imgw-textplate-light {
    background: rgba(255, 255, 255, 0.6);
}

/* Edge inset: space between the overlay caption and the image edges. This is the caption's padding (it
   overrides the default 1rem above); the flex alignment then positions the text block within what's left. */
.imgw-pos-bg .imgw-caption.imgw-inset-none { padding: 0; }
.imgw-pos-bg .imgw-caption.imgw-inset-small { padding: 0.75rem; }
.imgw-pos-bg .imgw-caption.imgw-inset-medium { padding: 1.5rem; }
.imgw-pos-bg .imgw-caption.imgw-inset-large { padding: 3rem; }

/* Max text width: cap the caption block so a long line wraps into a tidy column instead of stretching the
   whole banner. The block still shrinks below the cap for short text, and below the cap on narrow phones
   (max-width never forces it wider than the space available), so it stays responsive. Full = no cap. */
.imgw-pos-bg .imgw-textblock.imgw-tw-wide { max-width: 48rem; }
.imgw-pos-bg .imgw-textblock.imgw-tw-medium { max-width: 32rem; }
.imgw-pos-bg .imgw-textblock.imgw-tw-narrow { max-width: 20rem; }

/* Fixed aspect ratio: the height scales with the width at every screen size (responsive), and the image
   fills it via object-fit:cover. For a background/banner the media box holds the ratio (so the caption can
   overlay it); for other positions the image itself is cropped to the ratio. The focal point below chooses
   which part of the photo stays in frame. */
.imgw-ar-wide { --imgw-ar: 21 / 9; }
.imgw-ar-standard { --imgw-ar: 16 / 9; }
.imgw-ar-banner { --imgw-ar: 3 / 1; }
.imgw-ar-classic { --imgw-ar: 4 / 3; }
.imgw-ar-square { --imgw-ar: 1 / 1; }

.imgw-ar.imgw-pos-bg .imgw-media {
    aspect-ratio: var(--imgw-ar);
}

.imgw-ar.imgw-pos-bg .imgw-img {
    width: 100% !important;
    height: 100% !important;
    object-fit: cover;
}

.imgw-ar:not(.imgw-pos-bg) .imgw-img {
    aspect-ratio: var(--imgw-ar);
    height: auto;
    object-fit: cover;
}

/* Focal point - which part of a cropped (object-fit:cover) image stays visible. */
.imgw-focal-top .imgw-img { object-position: top; }
.imgw-focal-bottom .imgw-img { object-position: bottom; }
.imgw-focal-left .imgw-img { object-position: left; }
.imgw-focal-right .imgw-img { object-position: right; }

/* Full-bleed banner: break a background/hero image out of the page's max-width + side padding so it spans
   the full viewport width. Works when the banner is alone (centred) in its row - which is how the Banner
   preset drops it. Goes truly edge-to-edge on full-width sites (Maximum Width = 0); on a max-width site it
   fills the content width. The negative top/bottom margins pull it flush past the theme's row gap. */
.imgw-fullbleed {
    width: 100vw;
    max-width: 100vw;
    margin-left: calc(50% - 50vw);
    margin-right: calc(50% - 50vw);
}

/* 100vw is a hair wider than the viewport whenever a vertical scrollbar is present - just enough to add a
   horizontal scrollbar, most visible when the caption is right-aligned and sits at that overflowing edge.
   Clip the horizontal overflow at the page level, but only on pages that actually carry a full-bleed banner,
   and only on the x-axis (clip, not hidden) so vertical page scroll and a behind-navbar pull-up still work. */
body:has(.imgw-fullbleed, .loc-row-band, .loc-row-fullbleed) {
    overflow-x: clip;
}

/* Full-width section band: the row stays boxed (content keeps the page's content width), but its background
   is painted edge-to-edge by a ::before layer behind the content. The colour/image arrive as CSS vars so the
   boxed row carries no background of its own. The pseudo is absolutely positioned, so it is NOT a flex item
   and never disturbs the row's columns. */
.rowcontent.loc-row-band {
    position: relative;
}

.rowcontent.loc-row-band::before {
    content: "";
    position: absolute;
    top: 0;
    bottom: 0;
    left: calc(50% - 50vw);
    width: 100vw;
    background-color: var(--loc-rowbg-color, transparent);
    background-image: var(--loc-rowbg-image, none);
    background-size: cover;
    background-position: center;
    z-index: 0;
}

.rowcontent.loc-row-band > * {
    position: relative;
    z-index: 1;
}

/* Full-width band with "stretch content": the whole row goes edge-to-edge - background inline on the row and
   the columns fill the viewport width. */
.rowcontent.loc-row-fullbleed {
    width: 100vw;
    max-width: 100vw;
    margin-left: calc(50% - 50vw);
    margin-right: calc(50% - 50vw);
    background-size: cover;
    background-position: center;
}

/* In the builder the canvas is inset, so mirror the banner handling: fill the column instead of the viewport
   so the 100vw math doesn't overshoot and scroll. The true edge-to-edge band still shows on the published page. */
.website-builder .rowcontent.loc-row-fullbleed {
    width: 100%;
    max-width: 100%;
    margin-left: 0;
    margin-right: 0;
}

.website-builder .rowcontent.loc-row-band::before {
    left: 0;
    width: 100%;
}

/* Full-width bands own their vertical rhythm: a comfortable default top/bottom padding so content isn't
   flush to the band edges. A per-row box padding overrides it (those p-* utilities are !important). No
   horizontal padding - a boxed band keeps its content width, a stretched band stays edge-to-edge. */
.rowcontent.loc-row-band,
.rowcontent.loc-row-fullbleed {
    padding-top: 2.5rem;
    padding-bottom: 2.5rem;
}

/* Two full-width bands in a row butt together, so a background change reads as a real section break instead
   of showing a strip of body background between them. The negative top margin cancels the .website row gap
   for band-after-band only; a band next to a normal row keeps its normal gap. */
:is(.loc-row-band, .loc-row-fullbleed) + :is(.loc-row-band, .loc-row-fullbleed) {
    margin-top: calc(-1 * var(--row-gap, 1rem));
}

/* In the builder the canvas is inset (a toolbar column sits to its right) and isn't centred in the viewport,
   so the 100vw full-bleed math overshoots and adds a horizontal scrollbar. In the builder, just let the
   banner fill its column - the true edge-to-edge bleed still applies on the published page. Aspect ratio then
   only changes the banner's height, never its width, so no aspect choice can bring the scrollbar back. */
.website-builder .imgw-fullbleed {
    width: 100%;
    max-width: 100%;
    margin-left: 0;
    margin-right: 0;
}

/* A full-width banner as the page's FIRST row sits flush against the top of the content area (right under
   the navbar) - the page's top padding above it is removed so there's no gap. :has scopes it to the first
   row only, so a full-width band lower down keeps its normal spacing. */
.website > .rowcontent:first-child:has(.imgw-fullbleed) {
    margin-top: calc(-1 * var(--page-pad-top, 1rem));
}

/* "Behind the navbar": the first-row banner extends up UNDER the navbar (pull past the navbar clearance
   too), and its text is padded down so it clears the bar. Best paired with a transparent navbar - a solid
   bar would simply cover the top of the banner. --loc-navbar-h is published on <body> by each layout. */
.website > .rowcontent:first-child:has(.imgw-fullbleed.imgw-behind-nav) {
    margin-top: calc(-1 * (var(--page-pad-top, 1rem) + var(--loc-navbar-h, 3.25rem)));
}

.imgw-behind-nav.imgw-pos-bg .imgw-caption {
    padding-top: calc(var(--loc-navbar-h, 3.25rem) + 1rem);
}

/* Keep the builder's inline preview navbar above a banner that's pulled up flush/behind it. On the live
   site the real navbar is fixed-top (z-index 1030) so it already wins; in the builder the preview navbar is
   a normal-flow sibling, so without a stacking context the later banner would paint over (hide) it. */
#website-nav {
    position: relative;
    z-index: 3;
}

/* Hover effects */
.imgw-hover-zoom {
    transition: transform 0.25s ease;
}

.imgw-hover-zoom:hover {
    transform: scale(1.05);
}

.imgw-hover-fade {
    transition: opacity 0.25s ease;
}

.imgw-hover-fade:hover {
    opacity: 0.8;
}

/* Click behaviors */
.imgw-lightbox {
    cursor: zoom-in;
}

.imgw-link {
    display: inline-block;
    max-width: 100%;
}

/* Lightbox overlay */
.imgw-lightbox-overlay {
    position: fixed;
    inset: 0;
    z-index: 2000;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(0, 0, 0, 0.85);
    cursor: zoom-out;
}

.imgw-lightbox-overlay img {
    max-width: 92%;
    max-height: 92%;
    box-shadow: 0 4px 30px rgba(0, 0, 0, 0.5);
}

/* Stack image above text on phones for the side-by-side positions */
@media (max-width: 576px) {
    .imgw-pos-left .imgw-media,
    .imgw-pos-right .imgw-media {
        flex-direction: column;
    }

    .imgw-pos-left .imgw-img,
    .imgw-pos-right .imgw-img {
        width: 100% !important;
    }
}

/* Website builder frame: the content pane (.website-builder) reserves a 295px column on its right
   (margin-right: 295px) for the settings toolbar. The toolbar must be taken out of the flex flow and
   pinned into that reserved slot; otherwise it sits as a flex sibling and steals width from the pane,
   which prevents "Max" from filling the available space. */
/* Builder frame: a full-width flex row filling the viewport below the fixed navbar (height set in JS,
   Website.SizeBuilderFrame). The canvas area centers the (max-width-constrained) page canvas in the
   space between the left sidebar and the right toolbar; the toolbar is pinned to the right and can be
   collapsed (Website.ToggleToolBar). Canvas and toolbar scroll independently so both stay usable on a
   tall page. */
#website-builder-wrapper {
    position: relative;
}

/* Fills the gap between the sidebar and toolbar and centers the canvas within it. min-width: 0 lets it
   shrink so the canvas scrolls internally instead of widening the page. */
.builder-canvas-area {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    justify-content: center;
    overflow: hidden;
}

/* The page canvas; max-width is set per responsive preview button (Max/1280/768/400). Scrolls on its
   own (minus its 2px top margin) so the toolbar stays put while editing a tall page. */
.website-builder {
    height: calc(100% - 2px);
    overflow-y: auto;
}

/* Right-hand settings toolbar: fixed-width column pinned to the right, with its own scroll. */
#website-builder-toolbar {
    flex: 0 0 auto;
    max-height: 100%;
    overflow-y: auto;
    overflow-x: hidden; /* fixed-width settings column: never show a horizontal scrollbar */
}

.toolbar-expanded {
    width: 285px;
}

.toolbar-collapsed {
    width: 40px;
}

/* When the bar is collapsed to the 40px rail, only the collapse toggle remains; hide the action icons. */
.toolbar-collapsed .toolbar-action {
    display: none;
}

/* -----------------------------------------
   SECTION HEADING
   Replaces nested "cards within a card". Introduces a sub-section inside a single card with
   a bold title and a brand-coloured divider. It's a flex row, so it can also carry inline
   controls (filter buttons, totals) to the right of the title. Everything is driven by
   --bs-* variables, so it tracks the user's theme and light/dark automatically. Swap the
   border colour to var(--bs-border-color) if you'd prefer a neutral divider over the accent. */
.section-heading {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
    margin: 1.25rem 0 0.75rem;
    padding-bottom: 0.4rem;
    font-weight: 600;
    color: var(--bs-emphasis-color);
    border-bottom: 2px solid var(--bs-primary);
}

/* A section heading that opens a card sits flush under the card header. */
.card-body > .section-heading:first-child {
    margin-top: 0;
}

/* -----------------------------------------
   SELECT2 -> match the themed Bootstrap 5 .form-control
   Select2 4.x ships a Bootstrap-3-era look (28px tall, square corners). These rules make the
   selection box, focus ring, dropdown and search field track .form-control via the theme's
   own --bs-* variables (rounded corners, same border/height/colours). Targets the default
   Select2 theme, so no JS `theme:` option or extra dependency is needed. */
.select2-container--default .select2-selection--single {
    height: calc(1.5em + 0.75rem + 2px); /* match .form-control */
    padding: 0.375rem 0.75rem;
    display: flex;
    align-items: center;
    color: var(--bs-body-color);
    background-color: var(--bs-body-bg);
    border: var(--bs-border-width, 1px) solid var(--bs-border-color);
    border-radius: var(--bs-border-radius);
}
.select2-container--default .select2-selection--single .select2-selection__rendered {
    padding: 0;
    line-height: 1.5;
    color: var(--bs-body-color);
}
.select2-container--default .select2-selection--single .select2-selection__placeholder {
    color: var(--bs-secondary-color);
}
.select2-container--default .select2-selection--single .select2-selection__arrow {
    top: 0;
    right: 0.5rem;
    height: 100%;
}

/* focus / open state — mirror .form-control:focus */
.select2-container--default.select2-container--focus .select2-selection--single,
.select2-container--default.select2-container--open .select2-selection--single,
.select2-container--default.select2-container--focus .select2-selection--multiple {
    border-color: var(--bs-primary);
    box-shadow: 0 0 0 0.25rem rgba(var(--bs-primary-rgb), 0.25);
    outline: 0;
}

/* multi-select box (tags) */
.select2-container--default .select2-selection--multiple {
    /* Grow to fit the tag chips instead of being clamped to the fixed 35px height that the
       generic .select2-selection rule sets for single-selects - otherwise wrapped chips
       overflow the box border. min-height keeps it aligned with a normal input when empty. */
    height: auto;
    min-height: calc(1.5em + 0.75rem + 2px);
    padding: 0.1875rem 0.5rem;
    color: var(--bs-body-color);
    background-color: var(--bs-body-bg);
    border: var(--bs-border-width, 1px) solid var(--bs-border-color);
    border-radius: var(--bs-border-radius);
}
.select2-container--default .select2-selection--multiple .select2-selection__choice {
    border-radius: var(--bs-border-radius-sm);
}

/* dropdown panel, search box and options */
.select2-dropdown {
    color: var(--bs-body-color);
    background-color: var(--bs-body-bg);
    border-color: var(--bs-border-color);
    border-radius: var(--bs-border-radius);
}
.select2-container--default .select2-search--dropdown .select2-search__field {
    color: var(--bs-body-color);
    background-color: var(--bs-body-bg);
    border: var(--bs-border-width, 1px) solid var(--bs-border-color);
    border-radius: var(--bs-border-radius-sm);
}
.select2-container--default .select2-results__option--highlighted[aria-selected] {
    background-color: var(--bs-primary);
    color: #fff;
}

/* -----------------------------------------
   CHECKBOX FIELD (label-on-top)
   The label sits ABOVE the control like every other field, so checkbox fields line up
   with text/number fields in adjacent columns. The checkbox itself lives inside a
   bordered .form-control box of the same height:

       <div class="col-12">
           <label class="control-label">...</label>
           <div class="form-control checkbox-control">
               <input type="checkbox" class="checkbox" />
           </div>
           <p class="form-text">optional helper text</p>
       </div>
   ----------------------------------------- */
/* Compound .form-control.checkbox-control selector (specificity 0,2,0) so display:flex
   wins over Bootstrap/theme's single-class .form-control { display: block }. */
.form-control.checkbox-control {
    display: flex;
    align-items: center;
    justify-content: flex-end; /* checkbox sits at the right-hand end of the box */
    min-height: calc(1.5em + 0.75rem + 2px); /* match .form-control height */
}

/* The checkbox itself: a normal, themed control sitting inside the bordered box.
   (It no longer carries .form-control, so nothing forces appearance:none on it.) */
input[type="checkbox"].checkbox {
    flex: 0 0 auto;
    width: 1.25em;
    height: 1.25em;
    min-width: auto;
    min-height: auto;
    margin: 0;
    padding: 0;
    /* .form-control sets appearance:none, which suppresses the native checkbox glyph and left
       it invisible. Restore native rendering and theme it with the primary colour. */
    -webkit-appearance: auto;
    -moz-appearance: auto;
    appearance: auto;
    box-shadow: none;
    accent-color: var(--bs-primary);
    cursor: pointer;
}

/* -----------------------------------------
   BUTTONS (no global width override)
   ----------------------------------------- */

.btn-fixed {
    max-width: 400px;
}

.btn-full {
    width: 100%;
}

.btn-inline-control {
    margin-top: 25px;
}

/* -----------------------------------------
   BOOKING BUTTONS
   ----------------------------------------- */

.btn-member,
.btn-guest {
    max-width: 300px;
    min-width: 200px;
    margin-top: 2px;
}

@media (max-width: 500px) {
    .btn-member,
    .btn-guest {
        width: 100%;
        max-width: 100%;
    }
}

@media (min-width: 500px) {
    .btn-member,
    .btn-guest {
        max-width: 48%;
        min-width: 48%;
    }
}

/* -----------------------------------------
   SELECT2 (kept, cleaned)
   ----------------------------------------- */

.select2 {
    width: 100%;
    min-width: 200px;
}

.select2-selection {
    height: 35px;
}

.select2-selection__rendered {
    line-height: 32px;
    text-align: left;
}

.select2-selection__placeholder {
    color: var(--bs-secondary-color) !important;
}

/* -----------------------------------------
   CARDS & LAYOUT
   ----------------------------------------- */

.card {
    border-radius: var(--bs-border-radius);
}

.box-shadow {
    box-shadow: 0 0.25rem 0.75rem rgba(0, 0, 0, 0.05);
}

.card-header-primary {
    background-color: var(--bs-primary) !important;
    color: var(--bs-body-color);
}

/* -----------------------------------------
   TABLES
   ----------------------------------------- */

.table-striped tbody tr:nth-of-type(odd) {
    background-color: var(--bs-secondary-bg);
}

/* -----------------------------------------
   BADGES
   ----------------------------------------- */

.badge {
    background-color: var(--bs-primary);
    color: var(--bs-white);
}

/* -----------------------------------------
   SIDEBAR
   ----------------------------------------- */
/* Expanded */
.sidebar-expanded {
    width: 250px;
    min-width: 250px;
    max-width: 250px;
}

/* Collapsed */
.sidebar-collapsed {
    width: 50px;
    min-width: 50px;
    max-width: 50px;
}

/* ---- Syncfusion EJ2 grid integration ---- */

/* The SPA content column (.main-col) is a flex item; flex items won't shrink below their
   content width by default (min-width: auto), so a wide grid widens the whole page.
   min-width: 0 lets it shrink so the grid scrolls horizontally inside itself. */
.main-col {
    min-width: 0;
}

/* EJ2 pager: give the number buttons and the nav arrows a uniform height. The theme
   balances them with padding tuned to a specific font size; the app's base font size
   throws that off, making the number buttons taller than the arrows. */
.e-grid .e-pager .e-numericitem,
.e-grid .e-pager .e-currentitem,
.e-grid .e-pager .e-numericitem.e-currentitem,
.e-grid .e-pager .e-pagercontainer .e-firstpage,
.e-grid .e-pager .e-pagercontainer .e-prevpage,
.e-grid .e-pager .e-pagercontainer .e-nextpage,
.e-grid .e-pager .e-pagercontainer .e-lastpage,
.e-grid .e-pager .e-pagercontainer .e-firstpagedisabled,
.e-grid .e-pager .e-pagercontainer .e-prevpagedisabled,
.e-grid .e-pager .e-pagercontainer .e-nextpagedisabled,
.e-grid .e-pager .e-pagercontainer .e-lastpagedisabled {
    height: 36px;
    line-height: 36px;
    padding-top: 0;
    padding-bottom: 0;
    box-sizing: border-box;
}

/* More compact grid rows (the theme's default cell padding is a bit tall). The td/th
   element selectors give this higher specificity than the theme so it wins regardless
   of stylesheet load order. */
.e-grid td.e-rowcell,
.e-grid th.e-headercell {
    padding-top: 3px;
    padding-bottom: 3px;
}

/* Active | All scope toggle (createListGrid activeToggle) sits in the grid toolbar next to
   New; keep it vertically centred and give it a little breathing room. */
.e-grid .e-toolbar .loc-active-toggle {
    margin: 0 6px;
    vertical-align: middle;
}

/* -----------------------------------------
   ADMIN SHELL - FIXED NAVBAR OFFSET
   The Admin top navbar is position:fixed (out of flow), so the content column must reserve
   space for it. The offset lives in this CSS variable rather than being applied as an inline
   margin from window.onload (the old approach kept the page hidden until the load event and
   produced a visible jump). The default below (~52px: 40px brand logo + the navbar's vertical
   padding) is correct for the common single-row navbar; the layout's DOM-ready script refines
   --loc-navbar-h from the real height before revealing the page, so content still clears the
   bar if the menu wraps to two rows on narrow desktops. Scoped to .loc-admin-shell so it
   doesn't affect the other layouts (which still set their own offset in JS for now).
   ----------------------------------------- */
.loc-admin-shell {
    --loc-navbar-h: 3.25rem;
}

.loc-admin-shell main {
    padding-top: var(--loc-navbar-h);
}

/* The website builder renders its own in-flow navbar inside .website-builder, so its <main> must NOT also
   take the admin shell's fixed-navbar offset above - that added a ~navbar-height gap between the builder's
   nav and the first row. Scoped higher than the rule above so it wins regardless of stylesheet order. */
.loc-admin-shell .website-builder main {
    padding-top: 0;
}

/* -----------------------------------------
   WEB SHELL (MEMBER / VISITOR) - FIXED NAVBAR OFFSET
   These layouts use a website-themed position:fixed navbar whose height varies at runtime
   (Website.NavbarAutoCollapse toggles the expand state to fit the brand + items). The content
   container reserves space for it via --loc-navbar-h, which each layout's DOM-ready script
   sets from the real navbar height and updates on resize. The fallback below (~52px) keeps
   the layout sane before the script runs or if it fails.
   ----------------------------------------- */
.loc-shell-main {
    padding-top: var(--loc-navbar-h, 3.25rem);
}

/* -----------------------------------------
   MODALS
   ----------------------------------------- */
/* Overlay modals opened on top of the base #modal need a higher z-index than Bootstrap's
   default modal (1055) so they stack above it rather than appearing behind. */
.loc-modal-top {
    z-index: 10000;
}

/* Let the modal scroll when its content is taller than the viewport. */
.loc-modal-scroll {
    overflow: auto;
}

/* Modals default to modal-dialog-scrollable (set in the layouts): the header/footer stay pinned and only
   the body scrolls, so Save/Cancel are always reachable. Safety net: modal-dialog-scrollable clips content
   via .modal-content { overflow: hidden }, which would hide overflow in any modal that has NO .modal-body
   to scroll. For those, let the content itself scroll instead of being clipped. (:has is ignored by older
   browsers, which simply fall back to Bootstrap's behaviour.) */
.modal-dialog-scrollable > .modal-content:not(:has(.modal-body)) {
    overflow-y: auto;
}

/* ============================================================================
   Image galleries — replaces the old Unite Gallery (jQuery, 2017) with plain
   CSS layouts + a small home-grown lightbox. Three layouts share one base:
   grid (uniform tiles), masonry (natural aspect ratios), slider (scroll-snap).
   Column count and gap come from CSS vars set inline by the renderer.
   ============================================================================ */
.loc-gallery {
    --loc-gallery-cols: 3;
    --loc-gallery-gap: 0.5rem;
    --loc-gallery-ratio: 4 / 3;
}

.loc-gallery-item {
    position: relative;
    overflow: hidden;
    margin: 0;
    border-radius: var(--bs-border-radius, 0.375rem);
}

.loc-gallery--clickable .loc-gallery-item {
    cursor: pointer;
}

.loc-gallery-item > img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.loc-gallery-item > video {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: contain;
    background: #000;
}

.loc-gallery--masonry .loc-gallery-item > video {
    height: auto;
}

/* Caption ribbon — hidden until hover, or pinned on when "always visible". */
.loc-gallery-caption {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    margin: 0;
    padding: 0.4rem 0.6rem;
    font-size: 0.85rem;
    line-height: 1.25;
    color: #fff;
    background: linear-gradient(to top, rgba(0, 0, 0, 0.72), rgba(0, 0, 0, 0));
    opacity: 0;
    transition: opacity 0.2s ease;
    pointer-events: none;
}

.loc-gallery-item:hover .loc-gallery-caption,
.loc-gallery--captions-on .loc-gallery-caption {
    opacity: 1;
}

/* Subtle zoom on hover for clickable tiles. */
.loc-gallery--clickable .loc-gallery-item > img {
    transition: transform 0.25s ease;
}

.loc-gallery--clickable .loc-gallery-item:hover > img {
    transform: scale(1.04);
}

/* --- Uniform grid ------------------------------------------------------- */
.loc-gallery--grid {
    display: grid;
    grid-template-columns: repeat(var(--loc-gallery-cols), minmax(0, 1fr));
    gap: var(--loc-gallery-gap);
}

.loc-gallery--grid .loc-gallery-item {
    aspect-ratio: var(--loc-gallery-ratio);
}

/* --- Masonry (natural aspect ratios, CSS columns) ----------------------- */
.loc-gallery--masonry {
    column-count: var(--loc-gallery-cols);
    column-gap: var(--loc-gallery-gap);
}

.loc-gallery--masonry .loc-gallery-item {
    break-inside: avoid;
    margin-bottom: var(--loc-gallery-gap);
}

.loc-gallery--masonry .loc-gallery-item > img {
    height: auto;
}

/* --- Slider (native scroll-snap; JS only drives buttons/dots/autoplay) --- */
.loc-gallery-slider {
    position: relative;
}

.loc-gallery--slider {
    display: flex;
    gap: var(--loc-gallery-gap);
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scroll-behavior: smooth;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none; /* Firefox */
}

.loc-gallery--slider::-webkit-scrollbar {
    display: none;
}

.loc-gallery--slider .loc-gallery-item {
    flex: 0 0 calc((100% - (var(--loc-gallery-cols) - 1) * var(--loc-gallery-gap)) / var(--loc-gallery-cols));
    scroll-snap-align: center;
    aspect-ratio: var(--loc-gallery-ratio);
}

.loc-gallery-nav {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    z-index: 2;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 2.4rem;
    height: 2.4rem;
    padding: 0;
    border: none;
    border-radius: 50%;
    color: #fff;
    background: rgba(0, 0, 0, 0.45);
    font-size: 1.5rem;
    line-height: 1;
    cursor: pointer;
    transition: background 0.2s ease;
}

.loc-gallery-nav:hover {
    background: rgba(0, 0, 0, 0.7);
}

.loc-gallery-prev {
    left: 0.5rem;
}

.loc-gallery-next {
    right: 0.5rem;
}

.loc-gallery-dots {
    display: flex;
    justify-content: center;
    gap: 0.35rem;
    margin-top: 0.5rem;
}

.loc-gallery-dot {
    width: 0.55rem;
    height: 0.55rem;
    padding: 0;
    border: none;
    border-radius: 50%;
    background: rgba(0, 0, 0, 0.25);
    cursor: pointer;
    transition: background 0.2s ease;
}

.loc-gallery-dot.is-active {
    background: var(--bs-primary, #0d6efd);
}

/* On phones, grid/masonry collapse toward fewer columns and the slider shows
   one image at a time regardless of the configured count. */
@media (max-width: 575.98px) {
    .loc-gallery--grid,
    .loc-gallery--masonry {
        --loc-gallery-cols: 2;
    }

    .loc-gallery--slider {
        --loc-gallery-cols: 1;
    }
}

/* --- Lightbox (home-grown; opened on click when the gallery is clickable) -- */
.loc-lightbox {
    position: fixed;
    inset: 0;
    z-index: 20000;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(0, 0, 0, 0.9);
    opacity: 0;
    transition: opacity 0.2s ease;
    touch-action: pan-y;
}

.loc-lightbox.is-open {
    opacity: 1;
}

.loc-lightbox-figure {
    margin: 0;
    max-width: 92vw;
    max-height: 92vh;
    display: flex;
    flex-direction: column;
    align-items: center;
}

.loc-lightbox-figure img {
    max-width: 92vw;
    max-height: 84vh;
    object-fit: contain;
    border-radius: 0.25rem;
    box-shadow: 0 0.5rem 2rem rgba(0, 0, 0, 0.5);
}

.loc-lightbox-caption {
    margin-top: 0.6rem;
    max-width: 92vw;
    color: #fff;
    text-align: center;
    font-size: 0.9rem;
}

.loc-lightbox-btn {
    position: absolute;
    display: flex;
    align-items: center;
    justify-content: center;
    border: none;
    color: #fff;
    background: rgba(255, 255, 255, 0.12);
    cursor: pointer;
    transition: background 0.2s ease;
}

.loc-lightbox-btn:hover {
    background: rgba(255, 255, 255, 0.28);
}

.loc-lightbox-nav {
    top: 50%;
    transform: translateY(-50%);
    width: 3rem;
    height: 3rem;
    border-radius: 50%;
    font-size: 2rem;
    line-height: 1;
}

.loc-lightbox-prev {
    left: 1rem;
}

.loc-lightbox-next {
    right: 1rem;
}

.loc-lightbox-close {
    top: 1rem;
    right: 1rem;
    width: 2.6rem;
    height: 2.6rem;
    border-radius: 50%;
    font-size: 1.75rem;
    line-height: 1;
}

.loc-lightbox-counter {
    position: absolute;
    top: 1.2rem;
    left: 1.2rem;
    color: rgba(255, 255, 255, 0.75);
    font-size: 0.85rem;
}

@media (max-width: 575.98px) {
    .loc-lightbox-nav {
        width: 2.4rem;
        height: 2.4rem;
        font-size: 1.5rem;
    }

    .loc-lightbox-prev {
        left: 0.35rem;
    }

    .loc-lightbox-next {
        right: 0.35rem;
    }
}

/* --- Admin gallery management grid (replaces Unite Gallery in image.js) --- */
.loc-admin-gallery {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
    gap: 0.5rem;
    margin-top: 1rem;
}

.loc-admin-gallery .loc-gallery-item {
    aspect-ratio: 1 / 1;
    cursor: pointer;
    border: 1px solid var(--bs-border-color, #dee2e6);
}

.loc-admin-gallery .loc-gallery-item:hover {
    outline: 2px solid var(--bs-primary, #0d6efd);
    outline-offset: -2px;
}

/* --- Weather widget (Open-Meteo) ------------------------------------------ */
.loc-weather {
    width: 100%;
}

.weather-message {
    text-align: center;
    margin: 0.25rem 0 0.5rem;
}

.weather-message-text {
    margin: 0;
    font-size: 1.05rem;
    font-weight: 600;
    color: var(--bs-body-color, #333);
}

.weather-message-date {
    margin: 0.1rem 0 0;
    font-size: 0.72rem;
    color: #888;
}

.weather-body {
    display: flex;
    flex-wrap: wrap;
    gap: 1rem;
    align-items: stretch;
}

.weather-body > .weather-forecast {
    flex: 1 1 280px;
    min-width: 0;
}

.weather-body > .weather-webcam {
    flex: 1 1 280px;
    min-width: 0;
}

.weather-card {
    border-radius: var(--bs-border-radius, 0.75rem);
    overflow: hidden;
    box-shadow: 0 0.4rem 1.2rem rgba(0, 0, 0, 0.12);
    background: var(--bs-body-bg, #fff);
    height: 100%;
}

.weather-loading,
.weather-empty {
    padding: 1.5rem;
    text-align: center;
    color: #6c757d;
    border: 1px dashed #ced4da;
    border-radius: 0.5rem;
}

/* Hero: current conditions on a condition-based gradient. */
.weather-hero {
    padding: 1.25rem 1rem 1.4rem;
    color: #fff;
    text-align: center;
    background: linear-gradient(135deg, #6b7b8c, #9aa7b4);
}

.weather-hero-location {
    font-size: 0.85rem;
    font-weight: 600;
    opacity: 0.9;
    margin-bottom: 0.25rem;
}

.weather-hero-main {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 1rem;
}

.weather-hero-icon {
    font-size: 3.25rem;
    filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.2));
}

.weather-hero-temp {
    font-size: 3.5rem;
    font-weight: 700;
    line-height: 1;
}

.weather-hero-label {
    font-size: 1rem;
    font-weight: 600;
    margin-top: 0.15rem;
}

.weather-hero-meta {
    display: flex;
    justify-content: center;
    flex-wrap: wrap;
    gap: 0.4rem;
    margin-top: 0.7rem;
}

.weather-hero-meta span {
    background: rgba(255, 255, 255, 0.18);
    border-radius: 999px;
    padding: 0.15rem 0.6rem;
    font-size: 0.8rem;
    white-space: nowrap;
}

.weather-hero--clear  { background: linear-gradient(135deg, #2f80ed, #56ccf2); }
.weather-hero--partly { background: linear-gradient(135deg, #4a90d9, #8fc3e8); }
.weather-hero--clouds { background: linear-gradient(135deg, #5c6b7a, #93a2b0); }
.weather-hero--rain   { background: linear-gradient(135deg, #3a6073, #16222a); }
.weather-hero--snow   { background: linear-gradient(135deg, #5b8bb0, #a9cbe3); }
.weather-hero--storm  { background: linear-gradient(135deg, #3d3a5c, #29253f); }

/* Visitor format toggle (segmented pill control). */
.weather-toggle {
    display: flex;
    justify-content: center;
    gap: 0.25rem;
    padding: 0.6rem 0.75rem 0;
}

.weather-toggle-btn {
    border: 1px solid var(--bs-border-color, #dee2e6);
    background: transparent;
    color: #6c757d;
    font-size: 0.75rem;
    font-weight: 600;
    padding: 0.2rem 0.7rem;
    border-radius: 999px;
    cursor: pointer;
    transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}

.weather-toggle-btn:hover {
    background: rgba(0, 0, 0, 0.04);
}

.weather-toggle-btn.is-active {
    background: var(--bs-primary, #0d6efd);
    border-color: var(--bs-primary, #0d6efd);
    color: #fff;
}

/* Week format: each day is a section with its daytime (6am-10pm) hourly breakdown. */
.weather-week {
    padding: 0.25rem 0.5rem 0.5rem;
}

.weather-whday {
    padding: 0.35rem 0;
    border-bottom: 1px solid rgba(0, 0, 0, 0.06);
}

.weather-whday:last-child {
    border-bottom: none;
}

.weather-whday-head {
    font-size: 0.85rem;
    font-weight: 700;
    padding: 0.15rem 0.25rem 0.1rem;
}

.weather-whday-date {
    font-weight: 400;
    color: #8a94a0;
    font-size: 0.75rem;
    margin-left: 0.25rem;
}

/* In the Week view each day's hourly row also fills the full width (equal columns),
   inheriting the base .weather-hour flex sizing. */
.weather-whday .weather-hourly {
    padding: 0.4rem 0.25rem 0.25rem;
}

.weather-icon--clear  { color: #f5a623; }
.weather-icon--partly { color: #5a9bd4; }
.weather-icon--clouds { color: #8a94a0; }
.weather-icon--rain   { color: #4a90d9; }
.weather-icon--snow   { color: #7cc0e8; }
.weather-icon--storm  { color: #7b6fb0; }

/* Hourly format: equal-width columns filling the full width. */
.weather-hourly {
    display: flex;
    gap: 0.35rem;
    padding: 0.6rem 0.75rem 0.75rem;
}

.weather-hour {
    flex: 1 1 0;
    min-width: 0;
    text-align: center;
    padding: 0.35rem 0.15rem;
    border-radius: 0.5rem;
}

.weather-hour:hover {
    background: rgba(0, 0, 0, 0.04);
}

.weather-hour-time {
    font-size: 0.72rem;
    color: #6c757d;
    font-weight: 600;
}

.weather-hour-icon {
    font-size: 1.15rem;
    margin: 0.25rem 0;
}

.weather-hour-temp {
    font-size: 0.95rem;
    font-weight: 700;
}

.weather-hour-wind {
    font-size: 0.68rem;
    color: #7fa8c9;
    margin-top: 0.12rem;
    white-space: nowrap;
}

.weather-hour-wind i {
    font-size: 0.58rem;
}

.weather-hour-rain {
    font-size: 0.7rem;
    color: #8a94a0;
    margin-top: 0.15rem;
    white-space: nowrap;
}

.weather-hour-rain i {
    font-size: 0.6rem;
}

.weather-hour-rain.is-wet {
    color: #4a90d9;
    font-weight: 600;
}

/* Chart format: SVG temperature curve + hourly rain-probability bars. */
.weather-chart-wrap {
    padding: 0.5rem 0.75rem 0.75rem;
}

.weather-chart-legend {
    display: flex;
    gap: 1rem;
    justify-content: center;
    font-size: 0.72rem;
    color: #6c757d;
    margin-bottom: 0.15rem;
}

.weather-chart-legend .temp i {
    color: #f2994a;
}

.weather-chart-legend .rain i {
    color: #4a90d9;
}

.weather-chart {
    width: 100%;
    height: auto;
    display: block;
    overflow: visible;
}

.weather-chart-area {
    fill: rgba(242, 153, 74, 0.18);
}

.weather-chart-line {
    stroke: #f2994a;
    stroke-width: 2.5;
    stroke-linejoin: round;
    stroke-linecap: round;
}

.weather-chart-rain {
    fill: rgba(74, 144, 217, 0.6);
}

.weather-chart-baseline {
    stroke: rgba(0, 0, 0, 0.15);
    stroke-width: 1;
}

.weather-chart-rainlabel {
    fill: #4a90d9;
    font-size: 11px;
    font-weight: 600;
    text-anchor: middle;
}

.weather-chart-xlabel {
    fill: #8a94a0;
    font-size: 13px;
    text-anchor: middle;
}

.weather-chart-tlabel {
    fill: #495057;
    font-size: 13px;
    font-weight: 600;
    text-anchor: middle;
}

/* Webcam cross-fade cycler: all images stacked in one grid cell, opacity fades. */
.weather-webcam-stage {
    display: grid;
    border-radius: var(--bs-border-radius, 0.75rem);
    overflow: hidden;
    box-shadow: 0 0.4rem 1.2rem rgba(0, 0, 0, 0.12);
    height: 100%;
}

.weather-webcam-stage img {
    grid-area: 1 / 1;
    width: 100%;
    height: 100%;
    object-fit: cover;
    opacity: 0;
    transition: opacity 1s ease;
}

.weather-webcam-stage img.is-active {
    opacity: 1;
}

@media (prefers-color-scheme: dark) {
    .weather-whday { border-bottom-color: rgba(255, 255, 255, 0.08); }
    .weather-hour:hover { background: rgba(255, 255, 255, 0.06); }
    .weather-toggle-btn:hover { background: rgba(255, 255, 255, 0.06); }
    .weather-chart-baseline { stroke: rgba(255, 255, 255, 0.18); }
    .weather-chart-xlabel { fill: #adb5bd; }
    .weather-chart-tlabel { fill: #dee2e6; }
}

/* --- Video widget --------------------------------------------------------- */
.vidw-video {
    display: block;
    width: 100%;
    height: auto;
    background: #000;
    border-radius: var(--bs-border-radius, 0.375rem);
}

.vidw-empty {
    padding: 2rem;
    text-align: center;
    color: #6c757d;
    background: #f8f9fa;
    border: 1px dashed #ced4da;
    border-radius: 0.375rem;
}

/* --- Flat selectable image grid ------------------------------------------
   Replaces Unite Gallery on the remaining admin/member/picker screens whose
   markup is just a container of bare <img> children (logo/video pickers,
   Google/YAY image search, member images, copy-move image selection). Direct
   <img> children become responsive square tiles; .loc-selected marks a picked
   tile in multi-select pickers. */
.loc-image-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
    gap: 0.5rem;
    margin: 0.5rem 0;
}

.loc-image-grid img {
    display: block;
    width: 100%;
    aspect-ratio: 1 / 1;
    object-fit: cover;
    cursor: pointer;
    border: 1px solid var(--bs-border-color, #dee2e6);
    border-radius: 0.375rem;
}

.loc-image-grid img:hover {
    outline: 2px solid var(--bs-primary, #0d6efd);
    outline-offset: -2px;
}

.loc-image-grid img.loc-selected {
    outline: 3px solid var(--bs-primary, #0d6efd);
    outline-offset: -3px;
}

/* Sticky action footer: keeps a form's Save/Cancel bar pinned to the bottom of the viewport on long
   forms, so the buttons stay reachable without scrolling. Add the "sticky-actions" class to a .card-footer.
   (If the footer doesn't stick, an ancestor with overflow other than visible is clipping it.) */
.card-footer.sticky-actions {
    position: sticky;
    bottom: 0;
    z-index: 5;
    background-color: var(--bs-card-bg, #fff);
    border-top: 1px solid var(--bs-border-color, #dee2e6);
}

/* Bootbox renders its close button with Bootstrap 4's `.close` class, which Bootstrap 5 dropped - so the
   button gets no positioning. Give it a subtle look and place it top-right in BOTH layouts bootbox produces:
   inside the flex .modal-header when the dialog has a title, and prepended as the first child of .modal-body
   (far left, in front of the message) when it does not - which is the case for bootbox.confirm. */
.bootbox .bootbox-close-button {
    padding: 0;
    border: 0;
    background: transparent;
    font-size: 1.5rem;
    line-height: 1;
    opacity: 0.5;
    cursor: pointer;
}

.bootbox .bootbox-close-button:hover {
    opacity: 0.9;
}

/* Titled dialog: the button is in the flex header - push it to the far right. */
.bootbox .modal-header .bootbox-close-button {
    margin-left: auto;
}

/* Untitled dialog (e.g. bootbox.confirm): the button is the first child of the body. Pin it to the
   top-right of the dialog (the .modal-content is the positioned ancestor) instead of the far left. */
.bootbox .modal-body > .bootbox-close-button {
    position: absolute;
    top: 0.5rem;
    right: 0.75rem;
    z-index: 1;
}

/* Reserve space so a longer, wrapping message never runs under the pinned close button. Targets only the
   message body that directly follows the close button, i.e. the untitled (bootbox.confirm) layout. */
.bootbox .bootbox-close-button + .bootbox-body {
    padding-right: 1.5rem;
}

/* ==========================================================================================
   LoveOurClub custom icons - tennis / pickleball domain icons not available in FontAwesome.
   Rendered like a font icon: <i class="loc-icon loc-tennis-racket"></i>. Each icon is an SVG
   applied as a CSS mask, so it inherits the surrounding text colour (currentColor) and sizes
   to 1em - matching how FontAwesome icons behave inside a button, calendar cell, etc.
   Add a new icon by adding one class + a mask-image, then list it in Scripts/iconpicker.js.
   ========================================================================================== */

.loc-icon {
    display: inline-block;
    width: 1em;
    height: 1em;
    vertical-align: -0.125em;
    background-color: currentColor;
    -webkit-mask-repeat: no-repeat;
    mask-repeat: no-repeat;
    -webkit-mask-position: center;
    mask-position: center;
    -webkit-mask-size: contain;
    mask-size: contain;
}

.loc-icon.loc-tennis-racket {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.5'%3E%3Cellipse cx='12' cy='8' rx='6' ry='7'/%3E%3Cpath d='M12 15 L12 22' stroke-width='2.5' stroke-linecap='round'/%3E%3Cpath d='M6.5 6 H17.5 M6.5 10 H17.5 M9.5 2 V14 M14.5 2 V14' stroke-width='0.9'/%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.5'%3E%3Cellipse cx='12' cy='8' rx='6' ry='7'/%3E%3Cpath d='M12 15 L12 22' stroke-width='2.5' stroke-linecap='round'/%3E%3Cpath d='M6.5 6 H17.5 M6.5 10 H17.5 M9.5 2 V14 M14.5 2 V14' stroke-width='0.9'/%3E%3C/svg%3E");
}

.loc-icon.loc-pickleball-paddle {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23000'%3E%3Crect x='6' y='2' width='12' height='15' rx='6'/%3E%3Crect x='10.5' y='16' width='3' height='6' rx='1'/%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23000'%3E%3Crect x='6' y='2' width='12' height='15' rx='6'/%3E%3Crect x='10.5' y='16' width='3' height='6' rx='1'/%3E%3C/svg%3E");
}

.loc-icon.loc-ball-machine {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23000'%3E%3Crect x='3' y='8' width='15' height='11' rx='2'/%3E%3Ccircle cx='19' cy='6.5' r='2.3'/%3E%3Crect x='5.5' y='19' width='2.5' height='2.5' rx='0.5'/%3E%3Crect x='13' y='19' width='2.5' height='2.5' rx='0.5'/%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23000'%3E%3Crect x='3' y='8' width='15' height='11' rx='2'/%3E%3Ccircle cx='19' cy='6.5' r='2.3'/%3E%3Crect x='5.5' y='19' width='2.5' height='2.5' rx='0.5'/%3E%3Crect x='13' y='19' width='2.5' height='2.5' rx='0.5'/%3E%3C/svg%3E");
}

.loc-icon.loc-singles {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23000'%3E%3Ccircle cx='12' cy='6' r='3.3'/%3E%3Cpath d='M5.5 21 a6.5 6.5 0 0 1 13 0 Z'/%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23000'%3E%3Ccircle cx='12' cy='6' r='3.3'/%3E%3Cpath d='M5.5 21 a6.5 6.5 0 0 1 13 0 Z'/%3E%3C/svg%3E");
}

.loc-icon.loc-doubles {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23000'%3E%3Ccircle cx='8' cy='7' r='2.7'/%3E%3Cpath d='M2.5 20 a5.5 5.5 0 0 1 11 0 Z'/%3E%3Ccircle cx='16' cy='7' r='2.7'/%3E%3Cpath d='M10.5 20 a5.5 5.5 0 0 1 11 0 Z'/%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23000'%3E%3Ccircle cx='8' cy='7' r='2.7'/%3E%3Cpath d='M2.5 20 a5.5 5.5 0 0 1 11 0 Z'/%3E%3Ccircle cx='16' cy='7' r='2.7'/%3E%3Cpath d='M10.5 20 a5.5 5.5 0 0 1 11 0 Z'/%3E%3C/svg%3E");
}

.loc-icon.loc-mixed-doubles {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23000'%3E%3Ccircle cx='8' cy='7' r='2.7'/%3E%3Cpath d='M2.5 20 a5.5 5.5 0 0 1 11 0 Z'/%3E%3Ccircle cx='16' cy='7' r='2.7'/%3E%3Cpath d='M11.5 20 L16 10.5 L20.5 20 Z'/%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23000'%3E%3Ccircle cx='8' cy='7' r='2.7'/%3E%3Cpath d='M2.5 20 a5.5 5.5 0 0 1 11 0 Z'/%3E%3Ccircle cx='16' cy='7' r='2.7'/%3E%3Cpath d='M11.5 20 L16 10.5 L20.5 20 Z'/%3E%3C/svg%3E");
}

.loc-icon.loc-net {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.4' stroke-linecap='round'%3E%3Cpath d='M3 5 V20 M21 5 V20'/%3E%3Crect x='3' y='9' width='18' height='7'/%3E%3Cpath d='M7.5 9 V16 M12 9 V16 M16.5 9 V16 M3 12.5 H21' stroke-width='0.9'/%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.4' stroke-linecap='round'%3E%3Cpath d='M3 5 V20 M21 5 V20'/%3E%3Crect x='3' y='9' width='18' height='7'/%3E%3Cpath d='M7.5 9 V16 M12 9 V16 M16.5 9 V16 M3 12.5 H21' stroke-width='0.9'/%3E%3C/svg%3E");
}

.loc-icon.loc-skill {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23000'%3E%3Crect x='3' y='14' width='3.5' height='7' rx='0.8'/%3E%3Crect x='8.7' y='10' width='3.5' height='11' rx='0.8'/%3E%3Crect x='14.4' y='6' width='3.5' height='15' rx='0.8'/%3E%3Crect x='20.1' y='2' width='3.5' height='19' rx='0.8'/%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23000'%3E%3Crect x='3' y='14' width='3.5' height='7' rx='0.8'/%3E%3Crect x='8.7' y='10' width='3.5' height='11' rx='0.8'/%3E%3Crect x='14.4' y='6' width='3.5' height='15' rx='0.8'/%3E%3Crect x='20.1' y='2' width='3.5' height='19' rx='0.8'/%3E%3C/svg%3E");
}

/* --- Pickleball skill-level badges (1.0-6.0 in 0.5 steps): a ring around the level number. --- */
.loc-icon.loc-skill-1-0 {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.5'%3E%3Ccircle cx='12' cy='12' r='10.5'/%3E%3Ctext x='12' y='12.5' text-anchor='middle' dominant-baseline='central' font-family='Arial,sans-serif' font-size='9' font-weight='700' fill='%23000' stroke='none'%3E1.0%3C/text%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.5'%3E%3Ccircle cx='12' cy='12' r='10.5'/%3E%3Ctext x='12' y='12.5' text-anchor='middle' dominant-baseline='central' font-family='Arial,sans-serif' font-size='9' font-weight='700' fill='%23000' stroke='none'%3E1.0%3C/text%3E%3C/svg%3E");
}
.loc-icon.loc-skill-1-5 {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.5'%3E%3Ccircle cx='12' cy='12' r='10.5'/%3E%3Ctext x='12' y='12.5' text-anchor='middle' dominant-baseline='central' font-family='Arial,sans-serif' font-size='9' font-weight='700' fill='%23000' stroke='none'%3E1.5%3C/text%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.5'%3E%3Ccircle cx='12' cy='12' r='10.5'/%3E%3Ctext x='12' y='12.5' text-anchor='middle' dominant-baseline='central' font-family='Arial,sans-serif' font-size='9' font-weight='700' fill='%23000' stroke='none'%3E1.5%3C/text%3E%3C/svg%3E");
}
.loc-icon.loc-skill-2-0 {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.5'%3E%3Ccircle cx='12' cy='12' r='10.5'/%3E%3Ctext x='12' y='12.5' text-anchor='middle' dominant-baseline='central' font-family='Arial,sans-serif' font-size='9' font-weight='700' fill='%23000' stroke='none'%3E2.0%3C/text%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.5'%3E%3Ccircle cx='12' cy='12' r='10.5'/%3E%3Ctext x='12' y='12.5' text-anchor='middle' dominant-baseline='central' font-family='Arial,sans-serif' font-size='9' font-weight='700' fill='%23000' stroke='none'%3E2.0%3C/text%3E%3C/svg%3E");
}
.loc-icon.loc-skill-2-5 {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.5'%3E%3Ccircle cx='12' cy='12' r='10.5'/%3E%3Ctext x='12' y='12.5' text-anchor='middle' dominant-baseline='central' font-family='Arial,sans-serif' font-size='9' font-weight='700' fill='%23000' stroke='none'%3E2.5%3C/text%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.5'%3E%3Ccircle cx='12' cy='12' r='10.5'/%3E%3Ctext x='12' y='12.5' text-anchor='middle' dominant-baseline='central' font-family='Arial,sans-serif' font-size='9' font-weight='700' fill='%23000' stroke='none'%3E2.5%3C/text%3E%3C/svg%3E");
}
.loc-icon.loc-skill-3-0 {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.5'%3E%3Ccircle cx='12' cy='12' r='10.5'/%3E%3Ctext x='12' y='12.5' text-anchor='middle' dominant-baseline='central' font-family='Arial,sans-serif' font-size='9' font-weight='700' fill='%23000' stroke='none'%3E3.0%3C/text%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.5'%3E%3Ccircle cx='12' cy='12' r='10.5'/%3E%3Ctext x='12' y='12.5' text-anchor='middle' dominant-baseline='central' font-family='Arial,sans-serif' font-size='9' font-weight='700' fill='%23000' stroke='none'%3E3.0%3C/text%3E%3C/svg%3E");
}
.loc-icon.loc-skill-3-5 {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.5'%3E%3Ccircle cx='12' cy='12' r='10.5'/%3E%3Ctext x='12' y='12.5' text-anchor='middle' dominant-baseline='central' font-family='Arial,sans-serif' font-size='9' font-weight='700' fill='%23000' stroke='none'%3E3.5%3C/text%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.5'%3E%3Ccircle cx='12' cy='12' r='10.5'/%3E%3Ctext x='12' y='12.5' text-anchor='middle' dominant-baseline='central' font-family='Arial,sans-serif' font-size='9' font-weight='700' fill='%23000' stroke='none'%3E3.5%3C/text%3E%3C/svg%3E");
}
.loc-icon.loc-skill-4-0 {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.5'%3E%3Ccircle cx='12' cy='12' r='10.5'/%3E%3Ctext x='12' y='12.5' text-anchor='middle' dominant-baseline='central' font-family='Arial,sans-serif' font-size='9' font-weight='700' fill='%23000' stroke='none'%3E4.0%3C/text%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.5'%3E%3Ccircle cx='12' cy='12' r='10.5'/%3E%3Ctext x='12' y='12.5' text-anchor='middle' dominant-baseline='central' font-family='Arial,sans-serif' font-size='9' font-weight='700' fill='%23000' stroke='none'%3E4.0%3C/text%3E%3C/svg%3E");
}
.loc-icon.loc-skill-4-5 {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.5'%3E%3Ccircle cx='12' cy='12' r='10.5'/%3E%3Ctext x='12' y='12.5' text-anchor='middle' dominant-baseline='central' font-family='Arial,sans-serif' font-size='9' font-weight='700' fill='%23000' stroke='none'%3E4.5%3C/text%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.5'%3E%3Ccircle cx='12' cy='12' r='10.5'/%3E%3Ctext x='12' y='12.5' text-anchor='middle' dominant-baseline='central' font-family='Arial,sans-serif' font-size='9' font-weight='700' fill='%23000' stroke='none'%3E4.5%3C/text%3E%3C/svg%3E");
}
.loc-icon.loc-skill-5-0 {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.5'%3E%3Ccircle cx='12' cy='12' r='10.5'/%3E%3Ctext x='12' y='12.5' text-anchor='middle' dominant-baseline='central' font-family='Arial,sans-serif' font-size='9' font-weight='700' fill='%23000' stroke='none'%3E5.0%3C/text%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.5'%3E%3Ccircle cx='12' cy='12' r='10.5'/%3E%3Ctext x='12' y='12.5' text-anchor='middle' dominant-baseline='central' font-family='Arial,sans-serif' font-size='9' font-weight='700' fill='%23000' stroke='none'%3E5.0%3C/text%3E%3C/svg%3E");
}
.loc-icon.loc-skill-5-5 {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.5'%3E%3Ccircle cx='12' cy='12' r='10.5'/%3E%3Ctext x='12' y='12.5' text-anchor='middle' dominant-baseline='central' font-family='Arial,sans-serif' font-size='9' font-weight='700' fill='%23000' stroke='none'%3E5.5%3C/text%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.5'%3E%3Ccircle cx='12' cy='12' r='10.5'/%3E%3Ctext x='12' y='12.5' text-anchor='middle' dominant-baseline='central' font-family='Arial,sans-serif' font-size='9' font-weight='700' fill='%23000' stroke='none'%3E5.5%3C/text%3E%3C/svg%3E");
}
.loc-icon.loc-skill-6-0 {
    -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.5'%3E%3Ccircle cx='12' cy='12' r='10.5'/%3E%3Ctext x='12' y='12.5' text-anchor='middle' dominant-baseline='central' font-family='Arial,sans-serif' font-size='9' font-weight='700' fill='%23000' stroke='none'%3E6.0%3C/text%3E%3C/svg%3E");
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.5'%3E%3Ccircle cx='12' cy='12' r='10.5'/%3E%3Ctext x='12' y='12.5' text-anchor='middle' dominant-baseline='central' font-family='Arial,sans-serif' font-size='9' font-weight='700' fill='%23000' stroke='none'%3E6.0%3C/text%3E%3C/svg%3E");
}

/* =====================================================================================
   Tab Balance widget - balance-due "payment nudge"
   Applied only when a member owes and the club enabled emphasis (see ShowTabBalance).
   ===================================================================================== */
.loc-tab-due {
    background-color: rgba(220, 53, 69, 0.08);
    border: 1px solid rgba(220, 53, 69, 0.45);
    border-left: 4px solid #dc3545;
    border-radius: 0.375rem;
    padding: 1rem;
}

.loc-tab-due-msg {
    color: #dc3545;
    font-weight: 600;
}

.loc-pay-pulse {
    animation: loc-pay-pulse 1.6s ease-in-out infinite;
}

@keyframes loc-pay-pulse {
    0%   { box-shadow: 0 0 0 0 rgba(220, 53, 69, 0.55); }
    70%  { box-shadow: 0 0 0 10px rgba(220, 53, 69, 0); }
    100% { box-shadow: 0 0 0 0 rgba(220, 53, 69, 0); }
}

@media (prefers-reduced-motion: reduce) {
    .loc-pay-pulse { animation: none; }
}

/* =====================================================================================
   My Membership widget - expiring-soon / expired highlight
   Applied only when the membership is within the club's highlight window (see ShowMembershipWidget).
   ===================================================================================== */
.loc-membership-expiring {
    background-color: rgba(255, 193, 7, 0.12);
    border: 1px solid rgba(255, 193, 7, 0.55);
    border-left: 4px solid #ffc107;
    border-radius: 0.375rem;
    padding: 1rem;
}

.loc-membership-expired {
    background-color: rgba(220, 53, 69, 0.08);
    border: 1px solid rgba(220, 53, 69, 0.45);
    border-left: 4px solid #dc3545;
    border-radius: 0.375rem;
    padding: 1rem;
}

/* =====================================================================================
   News widget - unread article list (see ShowNewsWidget)
   ===================================================================================== */
.loc-news-item:last-child {
    border-bottom: 0 !important;
    margin-bottom: 0 !important;
    padding-bottom: 0 !important;
}

.loc-news-excerpt {
    color: #6c757d;
}

/* =====================================================================================
   Template gallery ("Add from template" modal) - cards + layout wireframe preview
   ===================================================================================== */
.loc-tpl-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
    gap: 1rem;
}

.loc-tpl-card {
    border: 1px solid rgba(0, 0, 0, .15);
    border-radius: .5rem;
    padding: .75rem;
    display: flex;
    flex-direction: column;
    gap: .5rem;
}

/* Selectable layout cards in the Add Page dialog. */
.add-page-tpl-card {
    cursor: pointer;
}

.add-page-tpl-card:hover {
    border-color: rgba(13, 110, 253, .5);
}

.add-page-tpl-card.selected {
    border-color: #0d6efd;
    box-shadow: 0 0 0 2px rgba(13, 110, 253, .35);
}

/* Scrollable layout picker area. */
.loc-tpl-scroll {
    max-height: 260px;
    overflow-y: auto;
    padding: .25rem;
    border: 1px solid rgba(0, 0, 0, .1);
    border-radius: .5rem;
}

/* Blank-page card wireframe placeholder. */
.loc-tpl-wire-blank {
    align-items: center;
    justify-content: center;
    border: 1px dashed rgba(0, 0, 0, .25);
    background: repeating-linear-gradient(45deg, #f8f9fa, #f8f9fa 8px, #f1f3f5 8px, #f1f3f5 16px);
}

.loc-tpl-blank-hint {
    color: #6c757d;
    font-size: .85rem;
}

.loc-tpl-wire {
    background: #f8f9fa;
    border-radius: .375rem;
    padding: .5rem;
    display: flex;
    flex-direction: column;
    gap: .35rem;
    min-height: 90px;
}

.loc-tpl-wire-row {
    display: flex;
    gap: .35rem;
}

.loc-tpl-wire-col {
    background: #fff;
    border: 1px solid rgba(0, 0, 0, .15);
    border-radius: .25rem;
    padding: .35rem .25rem;
    font-size: .68rem;
    color: #495057;
    text-align: center;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
}

.loc-tpl-name {
    font-weight: 600;
}

.loc-tpl-badges {
    display: flex;
    gap: .35rem;
    flex-wrap: wrap;
}

.loc-tpl-actions {
    margin-top: auto;
}

/* Icon-only builder toolbox tabs - compact so all four fit one row in the narrow sidebar. */
.website-toolbox-tabs .nav-link {
    padding: .4rem .25rem;
    font-size: 1rem;
    text-align: center;
}

/* =====================================================================================
   Section-template toolbox tiles (draggable) + hover flyout preview
   ===================================================================================== */
/* Tile shows a mini wireframe thumbnail above the name; the full preview lives in the flyout. */
.toolbox-section {
    display: flex;
    flex-direction: column;
    gap: .35rem;
    height: auto;
    padding: 8px;
}

.section-tile-wire {
    display: flex;
    flex-direction: column;
    gap: 2px;
    width: 100%;
}

.section-tile-wire-row {
    display: flex;
    gap: 2px;
}

.section-tile-wire-col {
    flex: 1;
    min-width: 0;
    height: 10px;
    background: #cfe2ff;
    border: 1px solid #9ec5fe;
    border-radius: 2px;
}

/* Full-size preview flown out beside the toolbox on hover (appended to <body>, positioned via JS). */
.section-tpl-flyout {
    position: fixed;
    display: none;
    z-index: 3000;
    width: 260px;
    max-width: 60vw;
    background: #fff;
    border: 1px solid rgba(0, 0, 0, .2);
    border-radius: .5rem;
    box-shadow: 0 .5rem 1rem rgba(0, 0, 0, .15);
    padding: .6rem;
    pointer-events: none;
}

/* =====================================================================================
   Website builder - empty-page drop target (a page with no rows)
   ===================================================================================== */
.website-empty-drop {
    border: 2px dashed rgba(0, 0, 0, .25);
    border-radius: .5rem;
    min-height: 160px;
    display: flex;
    align-items: center;
    justify-content: center;
    text-align: center;
    color: #6c757d;
    margin: 1rem;
    padding: 2rem;
}

.website-empty-drop.ui-state-hover {
    border-color: var(--bs-primary, #0d6efd);
    background: rgba(13, 110, 253, .06);
    color: var(--bs-primary, #0d6efd);
}

.website-empty-drop-inner i {
    font-size: 1.75rem;
    display: block;
}

