﻿
.demo-bar {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    z-index: 300; /* above .site-header-wrap (z-index:200) so it's never covered */
    display: flex;
    align-items: center;
    justify-content: center;
    flex-wrap: wrap;
    gap: 16px;
    background: rgba(10,10,10,.92);
    border-bottom: 1px solid rgba(255,255,255,.18);
    padding: 8px 14px;
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
    backdrop-filter: blur(6px);
}

.demo-bar-group {
    display: flex;
    align-items: center;
    gap: 8px;
}

.demo-bar label {
    font-size: 10.5px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .08em;
    color: rgba(255,255,255,.55);
    white-space: nowrap;
}

.demo-bar select {
    font-family: inherit;
    font-size: 12.5px;
    font-weight: 600;
    color: #fff;
    background: rgba(255,255,255,.08);
    border: 1px solid rgba(255,255,255,.25);
    border-radius: 4px;
    padding: 5px 8px;
    cursor: pointer;
}

    .demo-bar select:focus {
        outline: 2px solid rgba(255,255,255,.5);
        outline-offset: 1px;
    }
    /* Colour-code each accent option by name in the open dropdown list, so
   "Red" reads in red, "Blue" in blue, etc. — added 2026-08-27. Native
   <option> lists are drawn by the browser/OS on a fixed white background
   regardless of site theme (same fact already documented for .field select
   option in style.css's "Select dropdown ... fixes" section), so these use
   each preset's `deep` shade from demo-accent.js, not its `brand`/`bright`
   shade — brand/bright are tuned to read against the (also fixed) near-black
   demo bar background instead, and several of them (yellow, neon green,
   silver in particular) fall well under WCAG AA contrast against white.
   `deep` was already guaranteed ≥4.5:1 against white for every preset that
   existed before today (it's also used as opaque background behind white
   nav-dropdown text elsewhere in the real site, so the same colour needed to
   work in both directions), and the 3 new presets added today were chosen
   with that same constraint in mind — so reusing `deep` here needed no new
   colour values, just these selectors. Keep this list in sync with the
   ACCENTS object in demo-accent.js if a preset's `deep` value, or the set of
   presets itself, ever changes. The closed select's own text (before you
   open the list) is coloured separately, by JS, using each preset's
   `bright` shade instead — see demo-accent.js's colorSelectText(). */
    .demo-bar select option[value="red"] {
        color: #8f0019;
    }

    .demo-bar select option[value="blue"] {
        color: #00317f;
    }

    .demo-bar select option[value="yellow"] {
        color: #8a6d00;
    }

    .demo-bar select option[value="gold"] {
        color: #6e4f14;
    }

    .demo-bar select option[value="green"] {
        color: #0c5c29;
    }

    .demo-bar select option[value="neon"] {
        color: #125708;
    }

    .demo-bar select option[value="silver"] {
        color: #5c646b;
    }

    .demo-bar select option[value="orange"] {
        color: #8a4000;
    }

    .demo-bar select option[value="purple"] {
        color: #4a1266;
    }

    .demo-bar select option[value="bronze"] {
        color: #623a15;
    }
/* .theme-toggle is a real site component (styled in style.css against the
   theme's own --paper/--line tokens) — but .demo-bar's background is
   deliberately fixed-dark regardless of site theme (same "dev overlay"
   reasoning as everything else in this file), so in light theme --paper
   would otherwise resolve to a dark colour and go near-invisible against
   this bar's dark background. These two rules pin it to fixed light
   colours whenever it's inside .demo-bar specifically, overriding the
   theme-driven values just for this location. */
.demo-bar .theme-toggle {
    color: #fff;
    border-color: rgba(255,255,255,.3);
}

    .demo-bar .theme-toggle:hover {
        color: #fff;
        border-color: #fff;
    }

@media (max-width: 640px) {
    .demo-bar {
        padding: 6px 10px;
        gap: 10px;
    }

        .demo-bar label {
            display: none;
        }
}

@import url('https://fonts.googleapis.com/css2?family=Montserrat:wght@500;600;700;800&family=Open+Sans:wght@400;500;600;700&display=swap');

:root {
       --brand: #07833e; /* the fill: buttons, ticker, badges, calendar days */
    --brand-deep: #04471f; /* shadow / gradient partner, and the nav dropdown ground */
    --brand-rgb: 7,131,62; /* --brand as r,g,b — every low-alpha brand tint tracks this */
    --on-brand: #ffffff; /* text ON a --brand fill. Fixed in both themes. */
    --brand-on-dark: #33cf74; /* accent text on the always-dark hero / CTA / dropdown */
    --brand-on-light: #076c33; /* accent text in light mode and on the white affiliate band */
    /* ---- Neutrals (rarely need to change) ---- */
    --ink: #f7f6f3; /* page background */
    --ink-2: #fbfaf7; /* deepest background (footer, nav drawer) */
    --panel: #ffffff; /* card / panel background */
    --panel-2: #f1efea;
    --line: rgba(10,8,6,.10);
    --line-brand: rgba(var(--brand-rgb),.30);
    --paper: #171512; /* off-white text in the dark file; near-black ink here */
    --grey: #5a564f;
    --grey-dim: #8b877e;
    /* ---- Type (swap per client for a different personality) ----
     "Versatile Premium" pairing — Montserrat covers both display and
     label roles (it has real weights, so headline/eyebrow/nav/button
     share one family instead of two) with Open Sans for body copy,
     the most-used body face on gym/fitness sites today. See
     font-options.html for the full comparison this was chosen from. */
    --f-display: 'Montserrat', 'Arial Narrow', sans-serif; /* big headlines */
    --f-label: 'Montserrat', sans-serif; /* eyebrows, nav, labels, buttons */
    --f-body: 'Open Sans', sans-serif; /* paragraphs */
    /* ---- Layout ---- */
    --maxw: 1240px;
    --pad: clamp(20px, 5vw, 64px);
    --cut: 22px; /* corner-cut size — the signature "strike edge" motif. Set to 0 for square corners. */
    /* ---- Semantic status colours (booking calendar) — deliberately separate from
     --brand so "available/full" stays legible no matter what a client's brand
     colour is. ---- */
    --ok: #22c55e;
    --full: #ef4444;
    /* ---- Themeable surface/border tokens ----
     These exist so components don't hardcode rgba(10,8,6,..) directly.
     The original file's [data-theme="light"] block swapped these in here;
     this fixed-light fork has no such block, so these are just this file's
     only values now (see neon-dark-theme.css for the dark equivalents). */
    --surface-1: rgba(10,8,6,.035); /* input fields, notices */
    --surface-2: rgba(10,8,6,.025); /* subtle fills (acc-items, form-block) */
    --overlay-header: rgba(247,246,243,.86); /* header background once scrolled */
    --overlay-dropdown: rgba(255,255,255,.98); /* nav "More" dropdown */
    --border-soft: rgba(10,8,6,.22); /* outline-button border */
    --checker-a: #efeee9; /* image-placeholder stripe pattern */
    --checker-b: #e6e4dd;
    --label-on-placeholder: rgba(10,8,6,.32);
    /* ---- Fixed "always dark" tokens ----
     The photo hero and CTA band are deliberately dark "spotlight" sections
     in BOTH themes (a photographic hero needs a dark scrim for legible text
     no matter what the rest of the site is doing) — so their text uses these
     fixed tokens instead of the themeable ones above, and never inverts.
     Unchanged from the dark file - these were never part of the light-theme
     override to begin with. */
    --on-dark: #f6f5f2;
    --on-dark-muted: rgba(246,245,242,.82);
    --on-dark-dim: rgba(246,245,242,.55);
}

/* ================================================================
   LIGHT THEME — BAKED INTO :root ABOVE
   This is the fixed-LIGHT fork of site.css (see neon-dark-theme.css
   for the fixed-dark counterpart). The original file toggled theme
   at runtime via data-theme="light" on <html>, with a separate
   [data-theme="light"] block overriding :root's dark defaults; here
   there's only one theme, so those override values were merged
   directly into :root instead, and the runtime mechanism (plus the
   two matching .theme-toggle icon-state overrides further down)
   removed.
   ================================================================ */

*, *::before, *::after {
    box-sizing: border-box;
}

html {
    scroll-behavior: smooth;
}

body {
    margin: 0;
    background: var(--ink);
    color: var(--paper);
    font-family: var(--f-body);
    font-size: 16px;
    line-height: 1.6;
    -webkit-font-smoothing: antialiased;
    overflow-x: hidden;
}

img {
    max-width: 100%;
    display: block;
}

a {
    color: inherit;
    text-decoration: none;
}

ul {
    list-style: none;
    margin: 0;
    padding: 0;
}

h1, h2, h3, h4 {
    font-family: var(--f-display);
    font-weight: 800;
    text-transform: uppercase;
    margin: 0;
    letter-spacing: -.01em;
    line-height: 1.05;
}

p {
    margin: 0 0 1em;
    color: var(--grey);
}

button {
    font-family: inherit;
    cursor: pointer;
}

::selection {
    background: var(--brand);
    color: var(--on-brand);
}

@media (prefers-reduced-motion: reduce) {
    * {
        animation-duration: .001ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: .001ms !important;
        scroll-behavior: auto !important;
    }
}

:focus-visible {
    outline: 2px solid var(--brand-bright);
    outline-offset: 3px;
}

.wrap {
    max-width: var(--maxw);
    margin: 0 auto;
    padding-left: var(--pad);
    padding-right: var(--pad);
}

/* ---------- Corner-cut / clip motif (the "strike edge") ---------- */
.clip {
    clip-path: polygon(var(--cut) 0, 100% 0, 100% calc(100% - var(--cut)), calc(100% - var(--cut)) 100%, 0 100%, 0 var(--cut));
}

.clip-sm {
    --cut: 12px;
}

/* ---------- Eyebrow label ---------- */
.eyebrow {
    font-family: var(--f-label);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .32em;
    font-size: 12.5px;
    color: var(--brand-bright);
    display: inline-flex;
    align-items: center;
    gap: 10px;
    margin-bottom: 16px;
}

    .eyebrow::before {
        content: '';
        width: 26px;
        height: 2px;
        background: var(--brand);
        display: inline-block;
    }

/* ---------- Buttons ----------
   CHAMPIONS ONLY — softened from the template's "strike edge" treatment
   (2026-09-12, Luke: "less aggressive and angular, more neutral and refined").
   Three things were doing the shouting, and all three are dialled back rather
   than removed:
     1. the diagonal corner cut, now a small 8px radius — the cut motif still
        runs on cards, photos and badges, so the page keeps its character while
        the buttons stop being the sharpest thing on screen;
     2. the letter-spacing, .14em -> .10em, which is the single biggest change
        to how forceful the label reads;
     3. the sweeping white gloss on hover, replaced by a quiet lift and a small
        brightness shift.
   To go back to the template look, restore the clip-path, the .14em and the
   ::before sweep. --cut is untouched, so the rest of the site is unaffected. */
.btn {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    font-family: var(--f-label);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .10em;
    font-size: 15px;
    padding: 16px 32px;
    border: 1px solid transparent;
    border-radius: 8px;
    overflow: hidden;
    isolation: isolate;
    transition: transform .25s ease, color .25s ease, border-color .25s ease, background-color .25s ease, box-shadow .25s ease, filter .25s ease;
    background: none;
}

    .btn:hover {
        transform: translateY(-1px);
    }

    .btn:active {
        transform: translateY(0);
    }

.btn-primary {
    background: var(--brand);
    color: var(--on-brand);
    box-shadow: 0 1px 2px rgba(0,0,0,.14);
}
    /* brightness rather than a swap to --brand-bright: in light mode --brand-bright
   is the DEEP gold used for accent text, and filling with it would put dark
   --on-brand text on a dark ground. A small brightness lift is theme-safe and
   only improves the contrast ratio. */
    .btn-primary:hover {
        filter: brightness(1.07);
        box-shadow: 0 6px 18px rgba(var(--brand-rgb),.30);
    }

    .btn-primary span {
        position: relative;
        z-index: 2;
        display: inline-flex;
        align-items: center;
        gap: 10px;
    }

.btn-outline {
    background: transparent;
    color: var(--paper);
    border-color: var(--border-soft);
}

    .btn-outline:hover {
        border-color: var(--brand);
        color: var(--brand-bright);
        background: rgba(var(--brand-rgb),.07);
    }

.btn-block {
    width: 100%;
}

.btn-sm {
    padding: 11px 20px;
    font-size: 13px;
    border-radius: 7px;
}

/* ---------- Header / Nav ---------- */
/* top:55px leaves room for the DEMO ONLY .demo-bar (theme toggle + accent
   picker) fixed above it — see demo-accent.css. Once that bar is deleted for
   a real client handoff, change this back to top:0 (and see the matching
   +55px clearance added to .hero/.page-hero/.main-nav's mobile drawer below,
   which all need reverting too — search this file for "demo-bar" to find
   them all). */
.site-header-wrap {
    position: fixed;
    top: 0px;
    left: 0;
    right: 0;
    z-index: 200;
    display: flex;
    flex-direction: column;
}
/* z-index:2 (a real stacking context, not just z-index:auto) is required here —
   without it the "More" dropdown below (a positioned descendant of .site-header
   with no z-index of its own) can end up compositing BEHIND the ticker strip
   underneath it. The ticker continuously animates a transform (see .ticker-track's
   marquee animation below), which browsers commonly promote to its own GPU
   compositing layer; without an explicit, higher stacking context on the header,
   that animated layer can paint over the dropdown, showing the ticker's scrolling
   text bleeding through the "solid" dropdown background. Pairing this with
   .ticker's own z-index:1 (below) makes the paint order explicit instead of
   relying on default stacking, which is what actually fixes it. */
.site-header {
    position: relative;
    z-index: 2;
    padding: 18px 0;
    transition: background .35s ease, padding .35s ease, border-color .35s ease;
    border-bottom: 1px solid transparent;
}

.site-header-wrap.solid .site-header {
    background: var(--overlay-header);
    backdrop-filter: blur(10px);
    padding: 12px 0;
    border-bottom: 1px solid var(--line);
}

/* Home page only: the header floats transparently over the always-dark
   photo hero before the user scrolls, so its text needs to stay light
   regardless of theme in that moment — once .solid kicks in (opaque bg
   matching the current theme) normal themed colours take back over.
   Scoped to .brand/.nav-toggle (always transparent-over-hero) and,
   ONLY at desktop widths, .main-nav — below 1080px .main-nav becomes an
   off-canvas drawer with its own solid background, so it must keep
   following the normal theme instead of being forced light. */
.site-header-wrap.on-hero:not(.solid) .brand,
.site-header-wrap.on-hero:not(.solid) .nav-toggle {
    --paper: var(--on-dark);
    --grey: var(--on-dark-muted);
    --grey-dim: var(--on-dark-dim);
    --brand-bright: var(--brand-on-dark);
    color: var(--paper);
}

@media (min-width: 1081px) {
    .site-header-wrap.on-hero:not(.solid) .main-nav {
        --paper: var(--on-dark);
        --grey: var(--on-dark-muted);
        --grey-dim: var(--on-dark-dim);
        --brand-bright: var(--brand-on-dark);
        color: var(--paper);
    }
}

/* Dark header (2026-09-21). The master page adds .on-dark to the header wrap on
   every page EXCEPT the home page (which gets .on-hero instead).
   - .on-dark pages: solid near-black bar at every scroll position and screen width.
   - Home page (.on-hero): fully transparent over the hero until the visitor
     scrolls (.solid), then the SAME near-black bar, so the white-text logo.png and
     light menu text stay readable over the light page content below the hero.
   Light menu text comes from re-pointing the text tokens on the header's own
   elements only (same local-custom-property trick as .on-hero:not(.solid) above),
   so nothing else on the page changes theme. On mobile the off-canvas .main-nav
   drawer keeps its own light background and dark text, so .main-nav is only
   re-tokened at desktop widths. The longer selectors out-rank
   .site-header-wrap.solid .site-header (light overlay) further up. */
.site-header-wrap.on-dark .site-header,
.site-header-wrap.on-dark.solid .site-header,
.site-header-wrap.on-hero.solid .site-header {
    background: rgba(10, 10, 10, .94);
    backdrop-filter: blur(10px);
    border-bottom: 1px solid rgba(255, 255, 255, .12);
}

.site-header-wrap.on-dark .brand,
.site-header-wrap.on-dark .nav-toggle,
.site-header-wrap.on-hero.solid .brand,
.site-header-wrap.on-hero.solid .nav-toggle {
    --paper: var(--on-dark);
    --grey: var(--on-dark-muted);
    --grey-dim: var(--on-dark-dim);
    --brand-bright: var(--brand-on-dark);
    color: var(--paper);
}

@media (min-width: 1081px) {
    .site-header-wrap.on-dark .main-nav,
    .site-header-wrap.on-hero.solid .main-nav {
        --paper: var(--on-dark);
        --grey: var(--on-dark-muted);
        --grey-dim: var(--on-dark-dim);
        --brand-bright: var(--brand-on-dark);
        color: var(--paper);
    }
}

/* ---------- Theme toggle (sun/moon), lives in the header next to Contact ---------- */
.theme-toggle {
    position: relative;
    width: 38px;
    height: 38px;
    flex: none;
    border: 1px solid var(--line);
    background: transparent;
    color: var(--paper);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    transition: border-color .2s ease, color .2s ease;
}

    .theme-toggle:hover {
        border-color: var(--brand);
        color: var(--brand-bright);
    }

    .theme-toggle svg {
        width: 16px;
        height: 16px;
        position: absolute;
        transition: opacity .25s ease, transform .35s ease;
    }

    .theme-toggle .i-sun {
        /* Baked-in light-theme state (was the [data-theme="light"] override
         in the original file) - sun shown, moon hidden, unconditionally. */
        opacity: 1;
        transform: rotate(0) scale(1);
    }

    .theme-toggle .i-moon {
        opacity: 0;
        transform: rotate(40deg) scale(.6);
    }

/* [data-theme="light"] .theme-toggle .i-sun / .i-moon overrides removed -
   their values are now the base rules above, unconditionally. */

.site-header .wrap {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 24px;
}

.brand {
    display: flex;
    align-items: center;
    gap: 12px;
}

    .brand img {
        height: 46px;
        width: auto;
        transition: height .3s ease;
    }

.site-header-wrap.solid .brand img {
    height: 38px;
}

.brand-word {
    font-family: var(--f-label);
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
    font-size: 17px;
    line-height: 1.15;
}

    .brand-word small {
        display: block;
        font-family: var(--f-body);
        font-weight: 500;
        letter-spacing: .1em;
        text-transform: uppercase;
        font-size: 10px;
        color: var(--grey-dim);
    }

/* Club logo placeholder box — UNUSED as of 2026-08-26, kept in the stylesheet
   rather than deleted (same "don't delete, might come back" convention as
   .hero-stats/.stat-strip elsewhere in this file) in case a future round ever
   needs a checker-pattern "drop an image here" placeholder again. The header's
   <span class="brand-logo"> was replaced on all 13 pages with a real <img>
   (see .brand img above) pointing at the same placeholder logo used in the
   home page hero's .hero-logo, so this box's markup no longer exists anywhere
   — only its CSS remains, unreferenced. Originally: sat before .brand-word,
   sized/positioned to match where a real <img> logo would go, using the same
   diagonal-stripe --checker-a/b + --label-on-placeholder tokens as every other
   CUSTOMIZABLE IMAGE slot in the template. */
.brand-logo {
    width: 46px;
    height: 46px;
    flex: none;
    display: flex;
    align-items: center;
    justify-content: center;
    background: repeating-linear-gradient(45deg, var(--checker-a) 0 6px, var(--checker-b) 6px 12px);
    border: 1px solid var(--line);
    clip-path: polygon(8px 0, 100% 0, 100% calc(100% - 8px), calc(100% - 8px) 100%, 0 100%, 0 8px);
    color: var(--label-on-placeholder);
    transition: width .3s ease, height .3s ease;
}

    .brand-logo svg {
        width: 20px;
        height: 20px;
    }

.site-header-wrap.solid .brand-logo {
    width: 38px;
    height: 38px;
}

.main-nav {
    display: flex;
    align-items: center;
    gap: 2px;
}

    .main-nav > ul {
        display: flex;
        align-items: center;
        gap: 2px;
    }

    .main-nav a.nav-link {
        font-family: var(--f-label);
        font-weight: 600;
        text-transform: uppercase;
        letter-spacing: .08em;
        font-size: 14px;
        padding: 10px 14px;
        color: var(--paper);
        position: relative;
        display: flex;
        align-items: center;
        gap: 6px;
    }

        .main-nav a.nav-link::after {
            content: '';
            position: absolute;
            left: 14px;
            right: 14px;
            bottom: 5px;
            height: 2px;
            background: var(--brand);
            transform: scaleX(0);
            transform-origin: left;
            transition: transform .25s ease;
        }

        .main-nav a.nav-link:hover::after, .main-nav li.active > a.nav-link::after {
            transform: scaleX(1);
        }

    .main-nav li.active > a.nav-link {
        color: var(--brand-bright);
    }

    .main-nav li {
        position: relative;
    }

.caret {
    width: 9px;
    height: 9px;
    border-right: 2px solid currentColor;
    border-bottom: 2px solid currentColor;
    transform: rotate(45deg) translateY(-2px);
    transition: transform .25s ease;
}

.has-dropdown:hover .caret {
    transform: rotate(225deg) translateY(2px);
}

/* Dropdown background is tied to --brand-deep (not --overlay-dropdown/white) so it
   always carries the current accent colour and always contrasts with the light
   on-dark text below, in either theme, regardless of what's behind it (e.g. the
   transparent nav floating over the home page hero). --brand-deep is the fixed
   "dark shade of the accent" used everywhere reskinning touches, so this reads as
   on-brand for red/blue/green/etc *and* stays dark enough for light text even for
   naturally bright accents like yellow/neon/silver — using --brand directly here
   would break contrast again for those three. */
.dropdown {
    --brand-bright: var(--brand-on-dark);
    position: absolute;
    top: calc(100% + 14px);
    left: 50%;
    transform: translateX(-50%) translateY(6px);
    min-width: 220px;
    background: var(--brand-deep);
    border: 1px solid rgba(0,0,0,.25);
    border-top: 2px solid var(--brand-bright);
    padding: 10px;
    opacity: 0;
    visibility: hidden;
    transition: opacity .2s ease, transform .2s ease, visibility .2s;
    box-shadow: 0 20px 45px rgba(0,0,0,.4);
}

.has-dropdown:hover .dropdown, .has-dropdown:focus-within .dropdown {
    opacity: 1;
    visibility: visible;
    transform: translateX(-50%) translateY(0);
}

.dropdown a {
    display: block;
    padding: 11px 14px;
    font-family: var(--f-body);
    font-size: 14.5px;
    font-weight: 600;
    color: var(--on-dark-muted);
    border-left: 2px solid transparent;
}

    .dropdown a:hover {
        color: var(--on-dark);
        border-left-color: var(--brand-bright);
        background: rgba(0,0,0,.18);
    }

.nav-cta {
    margin-left: 10px;
}

.nav-theme {
    margin-left: 8px;
    display: flex;
    align-items: center;
}

.nav-toggle {
    display: none;
    flex-direction: column;
    gap: 5px;
    background: none;
    border: none;
    padding: 8px;
    z-index: 210;
}

    .nav-toggle span {
        width: 26px;
        height: 2px;
        background: var(--paper);
        transition: transform .3s ease, opacity .3s ease;
    }

    .nav-toggle.open span:nth-child(1) {
        transform: translateY(7px) rotate(45deg);
    }

    .nav-toggle.open span:nth-child(2) {
        opacity: 0;
    }

    .nav-toggle.open span:nth-child(3) {
        transform: translateY(-7px) rotate(-45deg);
    }

/* 2026-08-27: Luke's request (verbatim) — "on desktop can we have the logo and
   club name above the menu options and increase the logo size by 3x on
   desktop. let's spread the menu options out evenly across the page beneath
   the logo and club name but above the ticker." Desktop only — mobile keeps
   its existing centred stacked-brand + off-canvas-drawer layout (the
   max-width:1080px block below) completely untouched. Stacks .brand and
   .main-nav into two centred rows instead of one side-by-side row, triples
   the logo's height (46px base -> 138px; 38px solid-header-scrolled shrink
   size -> 114px, same 46:38 shrink ratio preserved), and makes .main-nav's
   <ul> span the row's full width with justify-content:space-between so every
   item (Home ... More, Contact Us) sits evenly spaced edge-to-edge instead of
   packed together on one side. */
@media (min-width: 1081px) {
    .site-header .wrap {
        flex-direction: column;
        align-items: center;
        justify-content: center;
        gap: 18px;
    }

    .brand img {
        height: 138px;
    }

    .site-header-wrap.solid .brand img {
        height: 114px;
    }

    .main-nav {
        width: 100%;
    }

        .main-nav > ul {
            width: 100%;
            justify-content: space-between;
            gap: 0;
        }

    .nav-cta {
        margin-left: 0;
    }

    .nav-theme {
        margin-left: 0;
    }
}

@media (max-width: 1080px) {
    /* Logo goes centre-top on mobile with the club name stacked underneath it,
     rather than staying inline-left next to the hamburger — there's not
     enough width at this breakpoint for a left-aligned logo+name lockup to
     sit comfortably next to the nav toggle. A 3-column grid (empty spacer /
     brand / toggle) keeps .brand genuinely centred regardless of the
     toggle's width, and lets the row's height grow to fit the now-taller
     stacked logo+name automatically instead of guessing a fixed height. */
    /* 2026-09-19: mobile header is now DARK and the logo sits at the LEFT of the
     screen (previously: light/transparent header with the logo centred). The
     grid drops from 3 columns (spacer / brand / toggle) to 2 (brand / toggle):
     the spacer only existed to keep .brand centred. .brand stays a stacked
     logo-over-club-name lockup, just left-aligned instead of centred, so the
     header's height (and therefore the .hero padding-top clearance values
     further down this file) is unchanged. */
    .site-header .wrap {
        display: grid;
        grid-template-columns: 1fr auto;
    }

    .brand {
        grid-column: 1;
        justify-self: start;
        flex-direction: column;
        align-items: flex-start;
        gap: 6px;
        text-align: left;
    }
        /* Mobile-only logo enlargement (2026-08-26): the header logo is now 2.5x
     larger than its desktop size here — 46px → 115px, and 38px → 95px once
     the header goes solid on scroll — desktop (.brand img above, above
     1080px) is untouched. These two rules must come after the base .brand
     img / .site-header-wrap.solid .brand img declarations earlier in the
     file to win the cascade at this width (identical selector specificity,
     later source order wins). */
        .brand img {
            height: 115px;
        }

    .site-header-wrap.solid .brand img {
        height: 95px;
    }

    /* 2026-09-21: the dark bar + light-on-dark text that used to be forced here for
     EVERY page on mobile (2026-09-19) now applies only to pages the master page
     marks .on-dark (everything except the home page) — see the .on-dark block near
     the top of this file, which covers desktop and mobile in one place. The home
     page's mobile header is transparent over the hero again, like desktop. */
    /* While the drawer is open the toggle (z-index:210) sits ON TOP of the light
     drawer, so its bars must go back to the normal dark themed ink or the X
     becomes invisible. The second selector is (0,4,0), the same specificity as
     the on-hero:not(.solid) rule near the top of this file, and wins it on
     source order — keep this block after that one. */
    .site-header-wrap .nav-toggle.open,
    .site-header-wrap.on-hero .nav-toggle.open,
    .site-header-wrap.on-dark .nav-toggle.open {
        --paper: inherit;
        color: var(--paper);
    }

    .nav-toggle {
        grid-column: 2;
        justify-self: end;
        display: flex;
    }
    /* The stacked logo+name lockup makes the fixed header (+ ticker) taller than
     before, so index.html's hero needs more top clearance to stay uncovered.
     The actual padding-top:250px override for this range lives just after the
     base .hero rule further down the file (search "981–1080px" there) rather
     than here, because a declaration here would tie in specificity with that
     later, unconditional rule and lose the cascade regardless of this media
     query — same reasoning applies to the max-width:980px block below, whose
     own padding-top:250px sits after the base rule for the same reason.
     250px = 195px for the header/ticker stack + 55px for the DEMO ONLY
     .demo-bar now fixed above it (see .site-header-wrap's top:55px above). */
    /* padding-top 183px = 128px original + 55px for the DEMO ONLY .demo-bar now
     fixed above the header (see .site-header-wrap's top:55px above), so the
     drawer's links start below the fixed header+demo-bar stack, not under it. */
    .main-nav {
        position: fixed;
        inset: 0 0 0 auto;
        width: min(360px,88vw);
        height: 100vh;
        background: var(--ink-2);
        border-left: 1px solid var(--line);
        flex-direction: column;
        align-items: stretch;
        justify-content: flex-start;
        padding: 183px 26px 40px;
        gap: 0;
        transform: translateX(100%);
        transition: transform .4s cubic-bezier(.7,0,.2,1);
        overflow-y: auto;
    }

        .main-nav.open {
            transform: translateX(0);
        }

        .main-nav > ul {
            flex-direction: column;
            align-items: stretch;
            gap: 0;
            width: 100%;
        }

        .main-nav a.nav-link {
            padding: 16px 4px;
            font-size: 16px;
            border-bottom: 1px solid var(--line);
            width: 100%;
            justify-content: space-between;
        }
    /* 2026-08-27: mobile menu no longer hides the extra 6 pages behind a "More"
     tap-to-expand step — Luke asked to just show the whole menu instead. The
     "More" trigger link (text + caret) is hidden below, and .dropdown — its
     child, still holding the same 6 links (Reviews/Members Area/Shop/FAQs/
     About Us/Policies) — is shown unconditionally and restyled to read as a
     plain continuation of the flat list (same border-bottom rows, same
     uppercase label typography, same theme-aware --paper text colour) rather
     than the desktop version's separate always-dark floating panel
     (background:var(--brand-deep), border-left accent, fixed --on-dark-muted
     text), which only makes sense as a distinct hover panel on desktop. No
     HTML changes needed on any of the 13 pages — .dropdown's markup already
     held exactly these 6 links, this is a CSS-only re-presentation of it.
     Desktop (above 1080px) is completely untouched — .dropdown's non-mobile
     styling earlier in this file, and the .has-dropdown:hover panel
     mechanism, are unchanged. The .has-dropdown.open/.caret rotate rule just
     below is now inert on mobile (its trigger is hidden so .open can never be
     set here any more) — left in place rather than deleted per this file's
     usual "don't delete, mark unused" convention, since desktop's :hover
     caret-flip mechanism is unrelated and still relies on the base .caret
     rule higher up. */
    .has-dropdown > a.nav-link {
        display: none;
    }

    .dropdown {
        position: static;
        transform: none;
        opacity: 1;
        visibility: visible;
        display: block;
        min-width: 0;
        border: none;
        border-top: none;
        border-left: none;
        background: none;
        margin: 0;
        box-shadow: none;
    }

        .dropdown a {
            font-family: var(--f-label);
            font-weight: 600;
            text-transform: uppercase;
            letter-spacing: .08em;
            font-size: 16px;
            color: var(--paper);
            padding: 16px 4px;
            border-left: none;
            border-bottom: 1px solid var(--line);
        }

            .dropdown a:hover {
                color: var(--brand-bright);
                background: none;
            }
    /* 2026-08-27: .has-dropdown:hover .dropdown / :focus-within (desktop's
     hover-panel positioning rule, defined unscoped near the top of this
     file) was still matching on mobile whenever a tap/hover landed on one
     of the now-always-visible dropdown links, because :hover/:focus-within
     bubble up to the ancestor .has-dropdown <li>. That rule sets
     transform:translateX(-50%) translateY(0) — combined with .dropdown now
     being position:static and full-width on mobile, this shoved the whole
     flat list roughly half its own width to the left the moment a link was
     tapped, making the label unreadable mid-tap. This override matches that
     rule's specificity (0,2,0) and appears later in the cascade, so it wins
     inside this mobile media query and keeps .dropdown untransformed, same
     as the rest of the flat list. Desktop is completely unaffected — this
     lives only inside @media (max-width:1080px). */
    .has-dropdown:hover .dropdown, .has-dropdown:focus-within .dropdown {
        transform: none;
    }

    .has-dropdown.open .dropdown {
        display: block;
    }

    .has-dropdown.open .caret {
        transform: rotate(225deg);
    }

    .nav-cta {
        margin: 24px 0 0;
    }

    .nav-theme {
        margin: 16px 0 0;
        justify-content: center;
    }
}

/* ---------- Marquee ticker ---------- */
/* position:relative + z-index:1 gives the ticker an explicit (lower) place in the
   stacking order relative to .site-header's z-index:2 above — see the comment on
   .site-header for why this pairing is needed (the ticker's own animated
   .ticker-track can otherwise get compositor-promoted and paint over the "More"
   dropdown that overlaps it). */
.ticker {
    position: relative;
    z-index: 1;
    background: var(--brand);
    color: var(--on-brand);
    overflow: hidden;
    white-space: nowrap;
    border-top: 1px solid rgba(0,0,0,.2);
    border-bottom: 1px solid rgba(0,0,0,.2);
}

.ticker-track {
    display: inline-flex;
    align-items: center;
    animation: ticker 26s linear infinite;
}

    .ticker-track span {
        font-family: var(--f-label);
        font-weight: 700;
        text-transform: uppercase;
        letter-spacing: .18em;
        font-size: 14px;
        padding: 14px 28px;
        display: inline-flex;
        align-items: center;
        gap: 16px;
    }

        .ticker-track span::after {
            content: '✕';
            font-size: 12px;
            opacity: .6;
        }

@keyframes ticker {
    from {
        transform: translateX(0);
    }

    to {
        transform: translateX(-50%);
    }
}

/* ---------- Hero (home page) ---------- */
/* The photo hero + CTA band are deliberately "always dark" spotlight
   sections in both themes (see --on-dark* tokens in :root) — this local
   custom-property override means every var(--paper)/var(--grey)/var(--line)
   used by anything nested inside them (headings, .field, .btn-outline...)
   resolves to a dark-appropriate value automatically, in either theme,
   with no extra per-component rules needed. */
.hero, .hero-jump, .cta-band, .enquiry-card {
    --ink: #0a0a0a;
    --paper: var(--on-dark);
    --grey: var(--on-dark-muted);
    --grey-dim: var(--on-dark-dim);
    --line: rgba(255,255,255,.14);
    --surface-1: rgba(255,255,255,.03);
    --border-soft: rgba(255,255,255,.35);
    /* Accent text in here sits on near-black regardless of the site theme,
     so it opts out of :root's darkened --brand-bright (#1a6b0c, baked in
     above from the original [data-theme="light"] override) back to the
     bright shade - this is the one file where this override actually does
     something; it's a no-op in neon-dark-theme.css, kept there for parity. */
    --brand-bright: var(--brand-on-dark);
    color: var(--paper);
}
/* padding-top 205px = 150px original + 55px for the DEMO ONLY .demo-bar now
   fixed above the header (see .site-header-wrap's top:55px above).
   2026-08-27: background:var(--ink) added here (Luke: "meet the team and
   member review within the header area are not visible" in light mode on
   mobile). Root cause: below 980px, .hero-media/.hero-scrim is capped to
   78vh (max 680px, see the max-width:980px block's .hero-media override
   further down) so it stops well short of the hero's full content height —
   the "Book A Trial"/"Meet The Team" buttons and the member-review pull
   quote sit further down, past the photo, in the gap between .hero-media's
   bottom edge and .hero's own bottom edge. That gap was relying on the
   page's background showing through .hero's own (unset, transparent)
   background — fine in dark theme, where the page background is already
   near-black, but in light theme the page background is near-white while
   this text is deliberately pinned to the fixed "always dark" --paper/
   on-dark token (see the .hero,.hero-jump,.cta-band,.enquiry-card block
   below), so the button/quote text, and the outline button's border,
   rendered near-white on a near-white background — invisible. Since --ink
   is already locked to the fixed dark value (#0a0a0a) inside .hero's own
   scope (same block), giving .hero an explicit solid background of its own
   closes that gap with a real dark backdrop in both themes, matching the
   "solid --ink background for the content below" this section's photo
   scrim was already designed to fade into (see the long 2026-08-27 comment
   on .hero-media below) — it just wasn't actually set as a background
   anywhere until now. No visible change on desktop/tablet, where
   .hero-media already stretches to cover .hero's full height. */
.hero {
    position: relative;
    min-height: 100vh;
    display: flex;
    align-items: center;
    padding: 205px 0 90px;
    overflow: hidden;
    background: var(--ink);
}
/* Re-declared here (not left solely in the max-width:1080px block above) so it
   actually wins in the cascade: that block's .hero rule and this one share
   identical specificity, so without this later declaration the earlier,
   unconditional 205px assignment above would win at EVERY width, including
   981–1080px, silently defeating the media query's intent. Bumping the fixed
   header's clearance back up to 297px here is what keeps the headline (and
   the rest of .hero-content) clear of the taller stacked-logo header at that
   breakpoint. 297px = 242px measured header+ticker stack (grew from 195px
   once the mobile-only .brand img logo enlargement below made the header
   taller — see the max-width:1080px block above for that rule) + 55px for
   the DEMO ONLY .demo-bar fixed above it (see .site-header-wrap's top:55px
   above). */
@media (max-width: 1080px) {
    .hero {
        padding-top: 297px;
    }
}
/* 2026-08-27: the desktop header restructure above (logo/club-name row +
   3x-larger logo stacked above a full-width nav row, see the
   min-width:1081px block near .nav-toggle) made the fixed header+ticker
   stack much taller on desktop too — measured via Playwright
   getBoundingClientRect at 1440px: .ticker's bottom edge is now 347.19px
   from the top (was ~205px before this round), so the unconditional 205px
   .hero padding-top above (still needed as-is for the narrow 981–1080px
   tablet gap, which keeps the older single-row/smaller-logo header) no
   longer clears the header on genuine desktop widths. 348px = that measured
   347.19px rounded up, same "measure, then round up slightly" convention
   used for the 297px tablet/mobile value above. */
@media (min-width: 1081px) {
    .hero {
        padding-top: 348px;
    }
}

.hero-media {
    position: absolute;
    inset: 0;
    z-index: 0;
}

.hero-img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: center top;
    display: block;
}

.hero-scrim {
    position: absolute;
    inset: 0;
    background: linear-gradient(100deg, rgba(6,6,6,.78) 0%, rgba(6,6,6,.4) 48%, rgba(6,6,6,.25) 75%), linear-gradient(180deg, rgba(6,6,6,.35) 0%, rgba(6,6,6,.2) 40%, rgba(6,6,6,.55) 78%, var(--ink) 100%);
}
/* No hero photo yet? Drop this modifier on .hero and remove .hero-media —
   gives a premium gradient backdrop until real photography is supplied. */
.hero.hero-noimg {
    background: radial-gradient(ellipse 60% 60% at 75% 10%, rgba(var(--brand-rgb),.16), transparent 60%), var(--ink);
}

    .hero.hero-noimg::before {
        content: '';
        position: absolute;
        inset: -20% -10%;
        z-index: 0;
        pointer-events: none;
        background-image: repeating-linear-gradient(115deg, rgba(var(--brand-rgb),.05) 0 2px, transparent 2px 90px);
    }

.hero-content {
    position: relative;
    z-index: 2;
    width: 100%;
}

.hero .wrap.hero-content {
    display: grid;
    grid-template-columns: 1.15fr .85fr;
    gap: 56px;
    align-items: center;
}
/* Hero logo badge — UNUSED as of 2026-08-26, kept in the stylesheet rather than
   deleted (same "don't delete, might come back" convention as .brand-logo and
   .hero-stats/.stat-strip elsewhere in this file). The <div class="hero-logo">
   markup was removed from index.html's hero — the club logo now appears only
   once on the site, in the header (see .brand img), rather than duplicated in
   the hero. Originally: centred above the headline/enquiry-card row, placed as
   its own full-width grid row (grid-column:1/-1) rather than absolutely
   positioned, so it naturally sat in normal document flow above both columns
   on desktop AND above the stacked columns on mobile once .hero
   .wrap.hero-content collapsed to a single column below 980px — no extra
   breakpoint-specific positioning math needed to keep it clear of the fixed
   header above. If a future round wants a hero badge again, this is a
   ready-made starting point. */
.hero-logo {
    grid-column: 1 / -1;
    display: flex;
    justify-content: center;
}

    .hero-logo img {
        height: 120px;
        width: auto;
        max-width: 70%;
        display: block;
        filter: drop-shadow(0 8px 30px rgba(0,0,0,.55));
    }
/* EthanHarrisHKA's headline ends on "TRANSFORMATION." — fifteen characters in one
   unbreakable word. Two consequences, both handled here:

   1. min-width:0 on the hero's grid children. CSS grid fr tracks are really
      minmax(auto, 1fr), so a word wider than its share doesn't wrap or clip — it
      widens the track and steals the space. At the template's 96px that single
      word took the left column to 917px and squeezed the enquiry card to 194px.
      This makes the tracks able to shrink, so no future long word can collapse
      the form again.
   2. A lower clamp ceiling, so the word actually fits its column at desktop
      rather than merely being allowed to overflow it. If the headline ever
      changes to shorter words, this can go back to the template's 7vw/96px. */
.hero .wrap.hero-content > * {
    min-width: 0;
}

.hero h1 {
    font-size: clamp(40px,4.1vw,59px);
    text-shadow: 0 8px 34px rgba(0,0,0,.55);
}

    .hero h1 .accent {
        color: var(--brand-bright);
    }

.hero-sub {
    font-size: 18px;
    max-width: 520px;
    margin: 22px 0 34px;
    color: var(--paper);
    opacity: .86;
    text-shadow: 0 2px 16px rgba(0,0,0,.5);
}

.hero-actions {
    display: flex;
    gap: 16px;
    flex-wrap: wrap;
}

.hero-stats {
    display: flex;
    gap: 34px;
    margin-top: 48px;
    flex-wrap: wrap;
}

    .hero-stats div b {
        display: block;
        font-family: var(--f-display);
        font-size: 34px;
        color: var(--paper);
        text-shadow: 0 4px 18px rgba(0,0,0,.5);
    }

    .hero-stats div span {
        font-family: var(--f-label);
        text-transform: uppercase;
        letter-spacing: .12em;
        font-size: 12.5px;
        color: var(--grey-dim);
    }

/* Single member review, replacing .hero-stats above in the hero column (kept
   .hero-stats itself in place, unused, in case a future round wants a stat row
   back). Plain text over the photo — same "text + shadow, no card box" treatment
   as .hero-sub — rather than reusing the boxed .testi component, which is built
   for a grid of cards sitting on a plain section background, not floating over
   a photo. Colour tokens (--paper/--grey-dim) resolve via the .hero "always
   dark" override above, same as every other hero text element. */
.hero-review {
    margin-top: 48px;
    max-width: 440px;
}

    .hero-review .stars {
        color: var(--brand-bright);
        letter-spacing: 3px;
        font-size: 16px;
        margin-bottom: 10px;
    }

    .hero-review p {
        font-size: 16px;
        font-style: italic;
        line-height: 1.6;
        color: var(--paper);
        text-shadow: 0 2px 16px rgba(0,0,0,.5);
        margin: 0 0 10px;
    }

    .hero-review cite {
        font-style: normal;
        font-family: var(--f-label);
        text-transform: uppercase;
        letter-spacing: .1em;
        font-size: 12px;
        color: var(--grey-dim);
    }

.hero-jump {
    text-align: center;
    padding: 30px 0;
    background: var(--ink);
    position: relative;
    z-index: 2;
}

.hero-jump-link {
    display: inline-flex;
    flex-direction: column;
    align-items: center;
    gap: 8px;
    font-family: var(--f-label);
    text-transform: uppercase;
    letter-spacing: .16em;
    font-size: 12.5px;
    color: var(--grey);
    transition: color .25s ease;
}

    .hero-jump-link:hover {
        color: var(--brand-bright);
    }

    .hero-jump-link svg {
        width: 18px;
        height: 18px;
        animation: jumpbounce 1.8s ease-in-out infinite;
    }

@keyframes jumpbounce {
    0%,100% {
        transform: translateY(0);
    }

    50% {
        transform: translateY(6px);
    }
}

/* Enquiry card (glass) */
.enquiry-card {
    background: rgba(14,14,14,.68);
    border: 1px solid var(--line);
    border-top: 2px solid var(--brand);
    backdrop-filter: blur(14px);
    padding: 34px;
    clip-path: polygon(28px 0, 100% 0, 100% calc(100% - 28px), calc(100% - 28px) 100%, 0 100%, 0 28px);
}

    .enquiry-card h3 {
        font-size: 26px;
        margin-bottom: 6px;
    }

    .enquiry-card .eyebrow {
        margin-bottom: 10px;
    }

    .enquiry-card p.lead {
        font-size: 14.5px;
        margin-bottom: 22px;
        color: var(--grey);
    }

.field {
    margin-bottom: 16px;
}

    .field label {
        display: block;
        font-family: var(--f-label);
        font-size: 12.5px;
        text-transform: uppercase;
        letter-spacing: .1em;
        color: var(--grey);
        margin-bottom: 7px;
    }

    .field input, .field select, .field textarea {
        width: 100%;
        background: var(--surface-1);
        border: 1px solid var(--line);
        color: var(--paper);
        padding: 13px 14px;
        font-family: var(--f-body);
        font-size: 15px;
        transition: border-color .2s ease, background .2s ease;
    }

        .field input:focus, .field select:focus, .field textarea:focus {
            border-color: var(--brand);
            background: rgba(var(--brand-rgb),.05);
            outline: none;
        }

    .field select {
        appearance: none;
        background-image: linear-gradient(45deg,transparent 50%,var(--grey) 50%),linear-gradient(135deg,var(--grey) 50%,transparent 50%);
        background-position: calc(100% - 20px) center, calc(100% - 15px) center;
        background-size: 5px 5px,5px 5px;
        background-repeat: no-repeat;
    }
        /* The closed <select> box follows the theme (--surface-1/--paper) like any other
   field, but its dropdown list of <option>s is drawn by the OS/browser, not by our
   CSS — it doesn't inherit the site's dark surface the way the closed box does, so
   giving the options the same var(--paper) text colour we use for the closed box
   left later theme/accent combinations with light text on the browser's own white
   option list (white-on-white, unreadable). Options get a fixed, explicit
   background+text colour instead, independent of every other token, so the
   dropdown list is always readable no matter the theme or accent. */
        .field select option {
            background: #ffffff;
            color: #0a0a0a;
        }

.field-note {
    font-size: 12px;
    color: var(--grey-dim);
    margin-top: 16px;
}

/* ---------- Section basics ---------- */
.section {
    padding: 20px 0;
    position: relative;
}

.section-tight {
    padding: 70px 0;
}

.section-head {
    display: flex;
    justify-content: space-between;
    align-items: flex-end;
    gap: 24px;
    margin-bottom: 52px;
    flex-wrap: wrap;
}

    .section-head h2 {
        font-size: clamp(32px,4.4vw,54px);
    }

    .section-head p {
        max-width: 420px;
        margin: 0;
    }

.on-panel {
    background: var(--panel);
}

.on-ink-2 {
    background: var(--ink-2);
}

.divider {
    height: 2px;
    background: linear-gradient(90deg, transparent, var(--brand) 20%, var(--brand) 80%, transparent);
    opacity: .5;
}

/* ---------- Reveal on scroll ---------- */
.reveal {
    opacity: 0;
    transform: translateY(28px);
    transition: opacity .7s ease, transform .7s cubic-bezier(.2,.7,.2,1);
}

    .reveal.in {
        opacity: 1;
        transform: translateY(0);
    }

.reveal-delay-1 {
    transition-delay: .08s;
}

.reveal-delay-2 {
    transition-delay: .16s;
}

.reveal-delay-3 {
    transition-delay: .24s;
}

/* ---------- Grids / Cards ---------- */
.grid-2 {
    display: grid;
    grid-template-columns: repeat(2,1fr);
    gap: 26px;
}

.grid-3 {
    display: grid;
    grid-template-columns: repeat(3,1fr);
    gap: 26px;
}

.grid-4 {
    display: grid;
    grid-template-columns: repeat(4,1fr);
    gap: 22px;
}

.card {
    background: var(--panel);
    border: 1px solid var(--line);
    padding: 32px;
    position: relative;
    overflow: hidden;
    transition: border-color .3s ease, transform .3s ease;
}

    .card:hover {
        transform: translateY(-6px);
        border-color: var(--line-brand);
    }

    .card::after {
        content: '';
        position: absolute;
        left: 0;
        right: 0;
        bottom: 0;
        height: 3px;
        background: var(--brand);
        transform: scaleX(0);
        transform-origin: left;
        transition: transform .35s ease;
    }

    .card:hover::after {
        transform: scaleX(1);
    }

    .card .tag {
        font-family: var(--f-label);
        text-transform: uppercase;
        letter-spacing: .14em;
        font-size: 12px;
        color: var(--brand-bright);
        margin-bottom: 14px;
        display: block;
    }

    .card h3 {
        font-size: 26px;
        margin-bottom: 10px;
    }

    .card .thumb {
        height: 180px;
        margin: -32px -32px 22px;
        position: relative;
        overflow: hidden;
        background: linear-gradient(160deg, rgba(var(--brand-rgb),.28), transparent 60%), repeating-linear-gradient(45deg, var(--checker-a) 0 10px, var(--checker-b) 10px 20px);
        display: flex;
        align-items: center;
        justify-content: center;
    }

        .card .thumb svg {
            width: 64px;
            height: 64px;
            opacity: .85;
        }

        .card .thumb::after {
            content: 'IMAGE PLACEHOLDER';
            position: absolute;
            bottom: 8px;
            right: 10px;
            font-family: var(--f-label);
            font-size: 10px;
            letter-spacing: .14em;
            color: var(--label-on-placeholder);
        }

        .card .thumb.thumb-photo {
            background: #000;
        }

            .card .thumb.thumb-photo::after {
                content: none;
            }

    .card .thumb-img {
        width: 100%;
        height: 100%;
        object-fit: cover;
        display: block;
    }

        .card .thumb-img.top {
            object-position: center top;
        }

.class-card .thumb {
    height: 210px;
}

/* Class cards are no longer a single big link (a "Book This Class" button inside
   the expanded read-more can't legally nest inside an <a>) — each is a plain .card
   div, and only the summary toggle / book button are interactive. Grid items default
   to align-items:stretch, so without this override, opening one card's <details>
   would stretch its two closed siblings to match its new height too (leaving empty
   space in them) — align-items:start lets each card size to its own content. */
/* 2026-09-07 (Luke: "the class cards need to be uniform height"): the row now
   stretches instead of letting each card size to its own content, and each card
   is a flex column with .class-more pushed to the bottom — so with every card
   closed the thumbnails, titles and "Read More" bars all line up across the row
   regardless of how long each card's lead sentence is.
   Opening a card would normally drag every sibling to the open card's height
   (stretch applies to the whole row), leaving three cards mostly empty — so the
   :has() rule below drops the row back to align-items:start the moment any
   <details> is open. Net effect: uniform while closed, each card sizing to its
   own content while one is expanded. Browsers without :has() (pre-2023) just
   keep the stretched behaviour, which still works, only with more whitespace. */
#classes-preview .grid-3,
#classes-preview .grid-4 {
    align-items: stretch;
}

#classes-preview .class-card {
    display: flex;
    flex-direction: column;
}

    #classes-preview .class-card > p {
        margin-bottom: 0;
    }

    #classes-preview .class-card .class-more {
        margin-top: auto;
    }

#classes-preview .grid-3:has(.class-more[open]),
#classes-preview .grid-4:has(.class-more[open]) {
    align-items: start;
}

/* ---------- Class card thumbnail flip ----------
   Opening a card's Read More rotates its photo over to reveal that programme's
   logo. Driven entirely by :has() on the open <details> — no JS, no state to
   keep in sync, and the card works identically if the flip never fires.

   The back face is pinned to a fixed dark ground in BOTH themes rather than
   following --panel-2: these are logo PNGs on transparency, drawn for a dark
   background, and a light-theme tile would swallow them.

   backface-visibility keeps the reverse side hidden mid-rotation. Browsers
   without :has() (pre-2023) simply never flip and keep showing the photo, which
   is why the photo is the FRONT face and not the back.

   prefers-reduced-motion is already handled globally at the top of this file —
   it collapses every transition to ~0s, so the faces swap instantly instead of
   spinning. That's the right behaviour, so there's no extra rule here. */
.thumb-flip {
    display: block;
    perspective: 1100px;
    background: #000;
}

.thumb-flip-inner {
    position: relative;
    width: 100%;
    height: 100%;
    transform-style: preserve-3d;
    transition: transform .7s cubic-bezier(.4,.15,.2,1);
}

.thumb-face {
    position: absolute;
    inset: 0;
    backface-visibility: hidden;
    -webkit-backface-visibility: hidden;
}

.thumb-face-back {
    transform: rotateY(180deg);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 26px;
    background: radial-gradient(ellipse 75% 75% at 50% 50%, rgba(var(--brand-rgb),.16), transparent 72%), #0d0f0c;
}

    .thumb-face-back img {
        width: auto;
        height: auto;
        max-width: 100%;
        max-height: 100%;
        object-fit: contain;
        display: block;
    }

#classes-preview .class-card:has(.class-more[open]) .thumb-flip-inner {
    transform: rotateY(180deg);
}

/* Class thumbnail framing.
   The shared .card .thumb is a fixed 180px tall, which is fine in a 4-up row
   (~1.5:1) but turns into a 3:1 letterbox once the grid drops to two columns
   and then one — wide enough that object-fit:cover was slicing the tops and
   bottoms off people. Below 980px the thumb switches to an aspect ratio so it
   grows with the card instead — 4:3, near enough the shape the photos were
   taken in — and the crop is biased up the image (30% rather than dead centre)
   because heads live in the top half of a training photo.
   Per-card override if one photo still frames badly: add .top to its
   .thumb-img for object-position:center top. */
#classes-preview .card .thumb-img {
    object-position: center 30%;
}

@media (max-width:980px) {
    #classes-preview .card .thumb {
        height: auto;
        aspect-ratio: 4/3;
    }
}

.class-more {
    margin-top: 18px;
    padding-top: 16px;
    border-top: 1px solid var(--line);
}

    .class-more summary {
        list-style: none;
        cursor: pointer;
        display: flex;
        align-items: center;
        gap: 8px;
        font-family: var(--f-label);
        font-weight: 700;
        text-transform: uppercase;
        letter-spacing: .1em;
        font-size: 12.5px;
        color: var(--brand-bright);
    }

        .class-more summary::-webkit-details-marker {
            display: none;
        }

        .class-more summary::after {
            content: '+';
            margin-left: auto;
            font-family: var(--f-body);
            font-size: 19px;
            line-height: 1;
        }

    .class-more[open] summary::after {
        content: '\2013';
    }

.class-more-body {
    padding-top: 16px;
}

    .class-more-body p {
        line-height: 1.7;
        margin-bottom: 22px;
    }

/* ---------- Check list ----------
   Benefit bullets ("what parents notice") inside the home page's class
   read-mores. Ticks use --brand-bright, so they follow the accent and the
   light-theme darkening like every other accent-coloured mark on the site. */
.check-lead {
    font-family: var(--f-label);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .08em;
    font-size: 12.5px;
    color: var(--paper);
    margin-bottom: 12px !important;
}

.check-list {
    margin: 0 0 22px;
    display: grid;
    gap: 10px;
}

    .check-list li {
        position: relative;
        padding-left: 28px;
        color: var(--grey);
        line-height: 1.6;
    }

        .check-list li::before {
            content: '\2713';
            position: absolute;
            left: 0;
            top: 0;
            color: var(--brand-bright);
            font-weight: 700;
            font-size: 15px;
        }

/* ---------- Video embed (click-to-play facade) ----------
   16:9 box carrying the corner-cut motif, so a YouTube video sits in the design
   system rather than looking like a pasted-in widget.

   It is a facade, not a bare <iframe>, for two reasons. Practical: YouTube
   refuses embeds from a page with no http origin, so a plain iframe shows
   "Video unavailable" in a file:// preview — which is exactly how these pages
   get reviewed. Performance: an iframe pulls ~1MB of YouTube script and sets
   cookies on every page load, whether or not anyone watches. The facade is just
   a thumbnail and a button until someone clicks (see main.js), and it clicks
   through to youtube.com when in-page playback isn't possible. */
.video-embed {
    position: relative;
    width: 100%;
    max-width: 900px;
    margin: 0 auto 60px;
    aspect-ratio: 16/9;
    background: #000;
    overflow: hidden;
    clip-path: polygon(var(--cut) 0, 100% 0, 100% calc(100% - var(--cut)), calc(100% - var(--cut)) 100%, 0 100%, 0 var(--cut));
}

    .video-embed iframe {
        position: absolute;
        inset: 0;
        width: 100%;
        height: 100%;
        border: 0;
    }

.video-facade {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    padding: 0;
    border: 0;
    background: none;
    cursor: pointer;
    display: block;
}

    .video-facade img {
        width: 100%;
        height: 100%;
        object-fit: cover;
        display: block;
        transition: transform .6s ease, filter .4s ease;
        filter: brightness(.82);
    }

    .video-facade:hover img, .video-facade:focus-visible img {
        transform: scale(1.04);
        filter: brightness(.7);
    }

    /* Play button — the brand triangle-in-a-disc, using --on-brand for the glyph
   because --brand is a light fill (see the token notes at the top of this file). */
    .video-facade::after {
        content: '';
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%,-50%);
        width: 84px;
        height: 84px;
        border-radius: 50%;
        background: var(--brand);
        box-shadow: 0 10px 40px rgba(0,0,0,.45);
        transition: transform .3s ease;
    }

    .video-facade .play-glyph {
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-42%,-50%);
        z-index: 1;
        width: 0;
        height: 0;
        border-left: 26px solid var(--on-brand);
        border-top: 16px solid transparent;
        border-bottom: 16px solid transparent;
    }

    .video-facade:hover::after, .video-facade:focus-visible::after {
        transform: translate(-50%,-50%) scale(1.08);
    }

@media (max-width:640px) {
    .video-embed {
        margin-bottom: 40px;
    }

    .video-facade::after {
        width: 64px;
        height: 64px;
    }

    .video-facade .play-glyph {
        border-left-width: 20px;
        border-top-width: 12px;
        border-bottom-width: 12px;
    }
}

/* ---------- Challenges section (home page) ----------
   The "problem" beat that sits between the hero and the class cards: two
   audience panels (parents / adults) of pain points, then a reassurance block
   that hands off to the programmes below.

   .pain-list is the counterpart to .check-list — same rhythm, but a neutral
   brand-coloured marker instead of a tick, because these are problems being
   named, not benefits being promised. Ticking a list of worries reads wrong. */
.pain-list {
    margin: 0;
    display: grid;
    gap: 12px;
}

    .pain-list li {
        position: relative;
        padding-left: 28px;
        color: var(--grey);
        line-height: 1.6;
    }

        .pain-list li::before {
            content: '';
            position: absolute;
            left: 2px;
            top: .62em;
            width: 9px;
            height: 9px;
            background: var(--brand);
            clip-path: polygon(3px 0, 100% 0, 100% calc(100% - 3px), calc(100% - 3px) 100%, 0 100%, 0 3px);
        }

.challenge-card p {
    margin-bottom: 22px;
}

/* Reassurance block closing the challenges section — full width, centred, with
   the brand rule above it doing the work instead of another panel/border box. */
.reassure {
    margin-top: 48px;
    text-align: center;
    max-width: 760px;
    margin-left: auto;
    margin-right: auto;
}

    .reassure::before {
        content: '';
        display: block;
        width: 60px;
        height: 3px;
        background: var(--brand);
        margin: 0 auto 26px;
    }

    .reassure h3 {
        font-size: clamp(24px,3vw,34px);
        margin-bottom: 18px;
    }

    .reassure p {
        margin-bottom: 14px;
    }

        .reassure p:last-child {
            margin-bottom: 0;
        }

    .reassure .btn {
        margin-top: 28px;
    }

/* Centred call-to-action closing a section, under a card grid. */
.section-cta {
    margin-top: 52px;
    text-align: center;
}

    .section-cta p {
        max-width: 600px;
        margin: 0 auto 22px;
    }

    .section-cta strong {
        color: var(--paper);
    }

/* The classes section's head carries an intro paragraph as well as the heading.
   .section-head's default flex row puts a sibling <p> in a 420px column beside
   the h2, which is too narrow next to a two-line headline — so here it stacks
   under the heading at a comfortable measure instead. */
#classes-preview .section-head {
    display: block;
}

    #classes-preview .section-head > p {
        max-width: 680px;
        margin-top: 20px;
    }

/* ---------- About teaser portrait ----------
   2026-09-07 (Luke: "remove the picture box"): the about-section image used to
   sit inside a .card > .thumb wrapper, which framed it in a panel with the
   brand-tinted placeholder gradient behind it. .about-photo drops the frame —
   just the image, keeping the corner-cut motif so it still reads as part of the
   design system. */
.about-photo {
    display: block;
    width: 100%;
    height: auto;
    clip-path: polygon(var(--cut) 0, 100% 0, 100% calc(100% - var(--cut)), calc(100% - var(--cut)) 100%, 0 100%, 0 var(--cut));
}

/* ---------- Impact stat strip ---------- */
.stat-strip {
    display: grid;
    grid-template-columns: repeat(4,1fr);
    border-top: 1px solid var(--line);
    border-bottom: 1px solid var(--line);
}

    .stat-strip div {
        padding: 38px 20px;
        text-align: center;
        border-left: 1px solid var(--line);
    }

        .stat-strip div:first-child {
            border-left: none;
        }

    .stat-strip b {
        display: block;
        font-family: var(--f-display);
        font-size: 44px;
        color: var(--brand-bright);
    }

    .stat-strip span {
        font-family: var(--f-label);
        text-transform: uppercase;
        letter-spacing: .12em;
        font-size: 12.5px;
        color: var(--grey);
    }

/* ---------- Testimonials / Reviews ---------- */
.testi {
    background: var(--panel);
    border: 1px solid var(--line);
    padding: 30px;
}

    .testi .stars {
        color: var(--brand-bright);
        letter-spacing: 3px;
        margin-bottom: 14px;
        font-size: 15px;
    }

    .testi p {
        color: var(--paper);
        font-size: 15.5px;
    }

    .testi cite {
        font-style: normal;
        font-family: var(--f-label);
        text-transform: uppercase;
        letter-spacing: .1em;
        font-size: 12.5px;
        color: var(--grey-dim);
    }

.rating-badge {
    display: inline-flex;
    align-items: center;
    gap: 16px;
    background: var(--panel);
    border: 1px solid var(--line);
    padding: 20px 28px;
}

    .rating-badge b {
        font-family: var(--f-display);
        font-size: 40px;
        color: var(--brand-bright);
    }

    .rating-badge .stars {
        color: var(--brand-bright);
        font-size: 18px;
        letter-spacing: 3px;
    }

.rating-summary {
    display: flex;
    flex-wrap: wrap;
    gap: 18px;
    align-items: center;
    margin-bottom: 44px;
}

.rating-source {
    font-family: var(--f-label);
    text-transform: uppercase;
    letter-spacing: .1em;
    font-size: 12.5px;
    color: var(--grey);
    border: 1px solid var(--line);
    padding: 10px 18px;
}

/* ---------- CTA band ---------- */
.cta-band {
    position: relative;
    padding: 90px 0;
    text-align: center;
    overflow: hidden;
    background: linear-gradient(120deg, var(--brand-deep), var(--ink) 55%);
}

    .cta-band::before {
        content: '';
        position: absolute;
        inset: 0;
        background-image: repeating-linear-gradient(115deg, rgba(255,255,255,.04) 0 2px, transparent 2px 60px);
    }

    .cta-band h2 {
        font-size: clamp(30px,5vw,58px);
        margin-bottom: 18px;
        position: relative;
    }

    .cta-band p {
        position: relative;
        max-width: 520px;
        margin: 0 auto 32px;
    }

    .cta-band .hero-actions {
        justify-content: center;
        position: relative;
    }

/* ---------- Locations ---------- */
/* .loc-card.loc-wide — the single-venue variant used on the home page when a
   client trains out of one place (EthanHarrisHKA Martial Arts: Didcot Leisure Centre). The .photo slot
   holds a Google Maps embed instead of a photo, so the map IS the card image.
   Two columns on desktop, stacked below 760px. Drop the modifier and use two or
   three plain .loc-cards in a .grid-2/.grid-3 if a client adds venues. */
.loc-card.loc-wide {
    display: grid;
    grid-template-columns: 1.15fr 1fr;
}

    .loc-card.loc-wide .photo {
        height: 100%;
        min-height: 340px;
        background: var(--panel-2);
    }

        .loc-card.loc-wide .photo iframe {
            width: 100%;
            height: 100%;
            min-height: 340px;
            border: 0;
            display: block;
            filter: none;
        }

    .loc-card.loc-wide .body {
        padding: 34px;
        display: flex;
        flex-direction: column;
        justify-content: center;
    }

    .loc-card.loc-wide address {
        font-size: 16px;
    }

@media (max-width:760px) {
    .loc-card.loc-wide {
        grid-template-columns: 1fr;
    }

        .loc-card.loc-wide .photo, .loc-card.loc-wide .photo iframe {
            min-height: 260px;
        }

        .loc-card.loc-wide .body {
            padding: 24px;
        }
}

.loc-card {
    background: var(--panel);
    border: 1px solid var(--line);
    overflow: hidden;
    transition: border-color .3s ease, transform .3s ease;
}

    .loc-card:hover {
        transform: translateY(-6px);
        border-color: var(--line-brand);
    }

    .loc-card .photo {
        height: 200px;
        overflow: hidden;
        background: #000;
    }

        .loc-card .photo img {
            width: 100%;
            height: 100%;
            object-fit: cover;
            display: block;
            filter: grayscale(1) contrast(1.08) brightness(.92);
            transition: filter .5s ease, transform .5s ease;
        }

    .loc-card:hover .photo img {
        filter: grayscale(.25) contrast(1.08) brightness(1);
        transform: scale(1.05);
    }

    .loc-card .body {
        padding: 22px;
    }

    .loc-card h4 {
        font-family: var(--f-label);
        text-transform: uppercase;
        letter-spacing: .1em;
        font-size: 19px;
        margin-bottom: 10px;
        color: var(--paper);
    }

    .loc-card address {
        font-style: normal;
        font-size: 14px;
        line-height: 1.7;
        color: var(--grey);
        margin: 0 0 18px;
    }

.loc-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    align-items: center;
}

.loc-card .maps-link {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    font-family: var(--f-label);
    text-transform: uppercase;
    letter-spacing: .1em;
    font-size: 12.5px;
    color: var(--brand-bright);
    border: 1px solid var(--line-brand);
    padding: 10px 16px;
    transition: background .2s ease, color .2s ease;
}

    .loc-card .maps-link:hover {
        background: rgba(var(--brand-rgb),.1);
        color: var(--paper);
        border-color: var(--brand);
    }

    .loc-card .maps-link svg {
        width: 14px;
        height: 14px;
    }

/* ---------- Page hero (inner pages) ---------- */
/* padding-top 271px = 216px original + 55px for the DEMO ONLY .demo-bar now
   fixed above the header (see .site-header-wrap's top:55px above). This is
   the desktop/base value — see the max-width:1080px override just below for
   why mobile widths need more. */
.page-hero {
    padding: 271px 0 70px;
    position: relative;
    overflow: hidden;
    background: radial-gradient(ellipse 50% 60% at 85% 0%, rgba(var(--brand-rgb),.14), transparent 60%), var(--ink);
    border-bottom: 1px solid var(--line);
}
/* Below 1080px the header switches to the stacked centre-logo layout (see the
   max-width:1080px block earlier in this file), which — combined with the
   2026-08-26 mobile-only .brand img logo enlargement — makes the fixed
   header+ticker stack taller than the 271px desktop clearance budget covers
   (216px + 55px demo-bar), so the breadcrumb/h1 start getting covered by the
   header without this override. 297px = the same measured header+ticker
   stack + demo-bar total used for .hero's matching max-width:1080px/980px
   overrides above (see those for the full 242px+55px breakdown) — .hero and
   .page-hero sit behind the identical fixed header, so they need identical
   clearance. */
@media (max-width: 1080px) {
    .page-hero {
        padding-top: 197px;
    }
}
/* 2026-08-27: matching .hero's own min-width:1081px override above — the
   restructured desktop header (logo/club-name row + 3x-larger logo stacked
   above a full-width nav row) measures 347.19px to the ticker's bottom edge
   at 1440px, so the unconditional 271px above (still correct for the
   981–1080px tablet gap, which keeps the smaller single-row header) no
   longer clears the header on genuine desktop widths either. Same 348px
   value as .hero's override, since both sit behind the identical fixed
   header+ticker stack. */
@media (min-width: 1081px) {
    .page-hero {
        padding-top: 248px;
    }
}

.page-hero::before {
    content: '';
    position: absolute;
    inset: -20% -10%;
    z-index: 0;
    pointer-events: none;
    background-image: repeating-linear-gradient(115deg, rgba(var(--brand-rgb),.045) 0 2px, transparent 2px 90px);
}

.page-hero .wrap {
    position: relative;
    z-index: 1;
}

.page-hero h1 {
    font-size: clamp(38px,6vw,72px);
}

.page-hero .lead {
    max-width: 600px;
    font-size: 17px;
    margin-top: 16px;
}

.breadcrumb {
    font-family: var(--f-label);
    text-transform: uppercase;
    letter-spacing: .14em;
    font-size: 12.5px;
    color: var(--grey-dim);
    margin-bottom: 18px;
}

    .breadcrumb a:hover {
        color: var(--brand-bright);
    }

    .breadcrumb .sep {
        margin: 0 8px;
        color: var(--line);
    }

/* ---------- Footer ---------- */
.site-footer {
    background: var(--ink-2);
    border-top: 1px solid var(--line);
    padding: 70px 0 26px;
}

.footer-grid {
    display: grid;
    grid-template-columns: 1.4fr 1fr 1fr 1fr;
    gap: 40px;
    margin-bottom: 56px;
}

    .footer-grid img {
        height: 44px;
        margin-bottom: 18px;
    }

    .footer-grid h5 {
        font-family: var(--f-label);
        text-transform: uppercase;
        letter-spacing: .14em;
        font-size: 13px;
        color: var(--grey);
        margin-bottom: 18px;
    }

    .footer-grid li {
        margin-bottom: 10px;
    }

    .footer-grid a {
        color: var(--grey);
        font-size: 14.5px;
    }

        .footer-grid a:hover {
            color: var(--brand-bright);
        }

.footer-social {
    display: flex;
    gap: 12px;
    margin-top: 20px;
}

    .footer-social a {
        width: 38px;
        height: 38px;
        border: 1px solid var(--line);
        display: flex;
        align-items: center;
        justify-content: center;
        transition: border-color .2s, color .2s;
    }

        .footer-social a:hover {
            border-color: var(--brand);
            color: var(--brand-bright);
        }

    .footer-social svg {
        width: 17px;
        height: 17px;
        display: block;
    }

/* ---------- Affiliate / powered-by band ----------
   Sits directly above the footer on every page: EthanHarrisHKA Martial Arts's ICO affiliation, and the
   Admin My Members credit with its contact details. Deliberately quiet — this is
   a credentials strip, not a sales section, so it's a single panel-toned band
   with small logos rather than anything that competes with the CTA above it.

   Logos are hosted externally and their backgrounds aren't known here, so each
   one sits at a fixed height with its own breathing room and the band uses the
   themed --panel; check both themes if either logo is ever swapped. */
/* The band is Admin My Members' own branding, and their logo is supplied as
   dark artwork, so this strip is pinned WHITE in both themes rather than
   following --panel. Same local-token trick .photo-panel uses, inverted: instead
   of forcing the always-dark values it forces the light ones, so every heading,
   paragraph, rule and link nested inside resolves correctly on white without a
   single per-element override.
   --brand-bright matters most here: on this site it's neon green, which is
   invisible on white, so it's pinned to the light-theme deep green (5.8:1+). */
.affiliate-band {
    background: #ffffff;
    --paper: #171512;
    --grey: #5a564f;
    --grey-dim: #8b877e;
    --line: rgba(10,8,6,.12);
    --brand-bright: #1a6b0c;
    color: var(--paper);
    border-top: 1px solid rgba(10,8,6,.12);
    padding: 44px 0;
}

.affiliate-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 48px;
    align-items: center;
}
/* One affiliate instead of two (EthanHarrisHKA Martial Arts: no confirmed ICO affiliation yet, so
   only the powered-by credit is shown). Drop this class when a second block goes
   back in and the two-column rule takes over again. */
.affiliate-grid-single {
    grid-template-columns: 1fr;
}

.affiliate-grid > * + * {
    border-left: 1px solid var(--line);
    padding-left: 48px;
}
/* flex-wrap so an unexpectedly wide logo pushes the text onto its own line
   instead of crushing it into a narrow ragged column. */
.affiliate {
    display: flex;
    align-items: center;
    gap: 22px;
    flex-wrap: wrap;
}

.affiliate-text {
    flex: 1 1 220px;
}

.affiliate-logo {
    flex: none;
    display: block;
}
    /* Height-driven so both logos optically match whatever their native size is;
   max-width stops an unusually wide lockup swallowing the text column. */
    .affiliate-logo img {
        height: 58px;
        width: auto;
        max-width: 190px;
        object-fit: contain;
        display: block;
        transition: opacity .25s ease;
    }

a.affiliate-logo:hover img {
    opacity: .78;
}
/* Double-size variant — the ICO mark is the affiliation being shown off, so it
   carries more weight than the powered-by credit beside it. Height-driven like
   the base rule, with max-width scaled to match so a wide lockup still fits. */
.affiliate-logo.is-large img {
    height: 116px;
    max-width: 380px;
}

.affiliate-label {
    font-family: var(--f-label);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .2em;
    font-size: 11px;
    color: var(--brand-bright);
    margin: 0 0 6px;
}

.affiliate-text p {
    margin: 0;
    font-size: 14px;
    line-height: 1.6;
}

.affiliate-text a {
    color: var(--brand-bright);
}

    .affiliate-text a:hover {
        text-decoration: underline;
    }
/* Flex, so the line breaks BETWEEN the phone and the email rather than through
   the middle of the phone number. */
.affiliate-contact {
    margin-top: 10px !important;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    font-family: var(--f-label);
    font-size: 13px;
    letter-spacing: .02em;
}

    .affiliate-contact a {
        white-space: nowrap;
    }

    .affiliate-contact .sep {
        color: var(--grey-dim);
        margin: 0 10px;
    }

@media (max-width:900px) {
    .affiliate-grid {
        grid-template-columns: 1fr;
        gap: 32px;
    }
        /* Stacked: the divider becomes a rule between the two, not beside them. */
        .affiliate-grid > * + * {
            border-left: none;
            padding-left: 0;
            border-top: 1px solid var(--line);
            padding-top: 32px;
        }
}

@media (max-width:520px) {
    .affiliate {
        flex-direction: column;
        align-items: flex-start;
        gap: 16px;
    }

    .affiliate-logo img {
        height: 48px;
    }

    .affiliate-logo.is-large img {
        height: 88px;
        max-width: 100%;
    }
}

/* ---------- Photo panel ----------
   A full-width section with a photograph behind the text instead of beside it
   (About Us). Built the same way as the home page hero: an absolutely positioned
   image, a scrim over it, and a local override of the colour tokens so
   everything nested inside resolves to its always-dark value in BOTH themes —
   no per-component rules needed, and the light theme can't wash the text out.

   Scrim weight is set so the text clears WCAG AA even over the brightest part a
   photo could have (a pure-white area): at the gradient's lightest point, .68
   black, headings land ~7.3:1 and muted body ~5.6:1. That leaves the photograph
   clearly readable rather than crushing it to a flat dark rectangle. If you swap
   in a much lighter image and it starts to feel busy behind the copy, raise the
   three alpha values together rather than adding a second overlay. */
.photo-panel {
    position: relative;
    overflow: hidden;
    --ink: #0a0a0a;
    --paper: var(--on-dark);
    --grey: var(--on-dark-muted);
    --grey-dim: var(--on-dark-dim);
    --line: rgba(255,255,255,.16);
    --surface-2: rgba(255,255,255,.07);
    --border-soft: rgba(255,255,255,.42);
    --brand-bright: var(--brand-on-dark);
    background: var(--ink);
    color: var(--paper);
}

.photo-panel-media {
    position: absolute;
    inset: 0;
    z-index: 0;
}

    .photo-panel-media img {
        width: 100%;
        height: 100%;
        object-fit: cover;
        object-position: center 30%;
        display: block;
    }

.photo-panel-scrim {
    position: absolute;
    inset: 0;
    background: linear-gradient(100deg, rgba(6,6,6,.90) 0%, rgba(6,6,6,.78) 55%, rgba(6,6,6,.68) 100%), linear-gradient(180deg, rgba(6,6,6,.55) 0%, rgba(6,6,6,0) 22%, rgba(6,6,6,0) 78%, rgba(6,6,6,.55) 100%);
}

.photo-panel-content {
    position: relative;
    z-index: 2;
}

.photo-panel-text {
    max-width: 760px;
}

.photo-panel .photo-credit {
    font-family: var(--f-label);
    text-transform: uppercase;
    letter-spacing: .12em;
    font-size: 12px;
    color: var(--grey-dim);
    border-top: 1px solid var(--line);
    padding-top: 18px;
    margin: 30px 0 0;
}

@media (max-width:760px) {
    /* Tighter left bias on narrow screens — the text spans the full width there,
     so the gradient needs to be even across it rather than lightening at one edge. */
    .photo-panel-scrim {
        background: linear-gradient(180deg, rgba(6,6,6,.86) 0%, rgba(6,6,6,.80) 100%), linear-gradient(180deg, rgba(6,6,6,.4) 0%, rgba(6,6,6,0) 30%);
    }
}

/* ---------- Hero discipline list ----------
   The four things EthanHarrisHKA Martial Arts teaches, sitting under the hero sub-line. Uses the
   brand fist-mark rather than the tick used elsewhere: these are disciplines on
   offer, not benefits being claimed. Lives inside the hero's always-dark scope,
   so it inherits the on-dark tokens automatically. */
.hero-list {
    display: flex;
    flex-wrap: wrap;
    gap: 10px 26px;
    margin: 0 0 20px;
}

    .hero-list li {
        position: relative;
        padding-left: 22px;
        font-family: var(--f-label);
        font-weight: 700;
        text-transform: uppercase;
        letter-spacing: .14em;
        font-size: 13px;
        color: var(--paper);
    }

        .hero-list li::before {
            content: '';
            position: absolute;
            left: 0;
            top: .42em;
            width: 9px;
            height: 9px;
            background: var(--brand);
            clip-path: polygon(3px 0, 100% 0, 100% calc(100% - 3px), calc(100% - 3px) 100%, 0 100%, 0 3px);
        }

@media (max-width:420px) {
    .hero-list {
        gap: 8px 18px;
    }

        .hero-list li {
            font-size: 12px;
        }
}

/* ---------- Social row (hero) ----------
   The same links as the footer, surfaced above the fold. Deliberately built from
   the footer's own icon treatment rather than a new one, so it reads as the same
   control in two places. It sits inside the hero's always-dark scope, so the
   label and borders use the fixed on-dark tokens instead of the themed ones. */
.social-row {
    display: flex;
    align-items: center;
    gap: 14px;
    margin-top: 26px;
}

    .social-row .social-label {
        font-family: var(--f-label);
        font-weight: 700;
        text-transform: uppercase;
        letter-spacing: .22em;
        font-size: 11.5px;
        color: var(--grey);
        margin: 0;
    }

    .social-row .social-links {
        display: flex;
        gap: 10px;
    }

        .social-row .social-links a {
            width: 38px;
            height: 38px;
            border: 1px solid var(--border-soft);
            display: flex;
            align-items: center;
            justify-content: center;
            color: var(--paper);
            transition: border-color .2s, color .2s, background .2s;
        }

            .social-row .social-links a:hover {
                border-color: var(--brand);
                color: var(--brand-bright);
                background: rgba(var(--brand-rgb),.10);
            }

        .social-row .social-links svg {
            width: 17px;
            height: 17px;
            display: block;
        }

@media (max-width:480px) {
    .social-row {
        flex-wrap: wrap;
        gap: 10px;
    }
}

.footer-bottom {
    border-top: 1px solid var(--line);
    padding-top: 24px;
    display: flex;
    justify-content: space-between;
    align-items: center;
    flex-wrap: wrap;
    gap: 14px;
}

    .footer-bottom p {
        margin: 0;
        font-size: 13px;
        color: var(--grey-dim);
    }

.footer-legal {
    display: flex;
    gap: 18px;
    flex-wrap: wrap;
}

    .footer-legal a {
        font-size: 13px;
        color: var(--grey-dim);
    }

        .footer-legal a:hover {
            color: var(--brand-bright);
        }

/* ---------- Utility ---------- */
.text-center {
    text-align: center;
}

.mt-0 {
    margin-top: 0;
}

.pill {
    display: inline-block;
    padding: 6px 14px;
    border: 1px solid var(--line);
    font-family: var(--f-label);
    font-size: 12px;
    text-transform: uppercase;
    letter-spacing: .12em;
    color: var(--grey);
}

    .pill.brand {
        border-color: var(--line-brand);
        color: var(--brand-bright);
    }

/* ---------- Filter chips (Timetable / Gallery / Shop) ---------- */
.filter-bar {
    display: flex;
    gap: 10px;
    margin-bottom: 30px;
    flex-wrap: wrap;
}

.filter-chip {
    font-family: var(--f-label);
    text-transform: uppercase;
    letter-spacing: .1em;
    font-size: 13px;
    padding: 11px 20px;
    border: 1px solid var(--line);
    color: var(--grey);
    background: none;
}

    .filter-chip.active, .filter-chip:hover {
        border-color: var(--brand);
        color: var(--brand-bright);
        background: rgba(var(--brand-rgb),.06);
    }

/* ---------- Schedule table (Timetable) ---------- */
.schedule {
    width: 100%;
    border-collapse: collapse;
    background: var(--panel);
    border: 1px solid var(--line);
}

    .schedule th, .schedule td {
        padding: 16px 18px;
        text-align: left;
        border-bottom: 1px solid var(--line);
        font-size: 14.5px;
    }

    .schedule th {
        font-family: var(--f-label);
        text-transform: uppercase;
        letter-spacing: .1em;
        font-size: 12.5px;
        color: var(--grey);
        background: var(--surface-2);
    }

    .schedule tr:last-child td {
        border-bottom: none;
    }

    .schedule tr:hover td {
        background: rgba(var(--brand-rgb),.05);
    }

    .schedule .class-name {
        color: var(--paper);
        font-weight: 700;
        font-family: var(--f-label);
        letter-spacing: .04em;
        text-transform: uppercase;
        font-size: 14px;
    }

.table-wrap {
    overflow-x: auto;
    border-top: 2px solid var(--brand);
}

/* ---------- Event cards ---------- */
.event-card {
    display: flex;
    gap: 22px;
    background: var(--panel);
    border: 1px solid var(--line);
    padding: 26px;
    align-items: flex-start;
}

    .event-card:hover {
        border-color: var(--line-brand);
    }

.date-badge {
    flex: 0 0 78px;
    text-align: center;
    background: var(--brand);
    color: var(--on-brand);
    padding: 14px 8px;
    clip-path: polygon(10px 0,100% 0,100% 100%,0 100%,0 10px);
}

    .date-badge b {
        display: block;
        font-family: var(--f-display);
        font-size: 26px;
        line-height: 1;
    }

    .date-badge span {
        font-family: var(--f-label);
        font-size: 11px;
        text-transform: uppercase;
        letter-spacing: .1em;
    }

.event-card h3 {
    font-size: 22px;
    margin-bottom: 6px;
}

.event-meta {
    font-family: var(--f-label);
    text-transform: uppercase;
    letter-spacing: .08em;
    font-size: 12px;
    color: var(--grey-dim);
    margin-bottom: 10px;
    display: flex;
    gap: 16px;
    flex-wrap: wrap;
}

/* Event cards get the same "Read More" expand-in-place disclosure as the blog and
   class cards — the short description stays, and a toggle reveals fuller event
   info (what to expect, what to bring, entry details) plus a Reserve CTA. Event
   cards were already plain <div>s (not links), so no structural change was needed
   here the way it was for blog/class cards. Kept as its own .event-more/
   .event-more-body block, mirroring .class-more/.blog-more, for the same reason
   those two are kept separate from each other: independent tuning without risk of
   silently affecting the other card types. Event cards stack in a single column
   (not a grid), so there's no sibling-stretch issue to guard against here. */
.event-more {
    margin-top: 14px;
    padding-top: 14px;
    border-top: 1px solid var(--line);
}

    .event-more summary {
        list-style: none;
        cursor: pointer;
        display: flex;
        align-items: center;
        gap: 8px;
        font-family: var(--f-label);
        font-weight: 700;
        text-transform: uppercase;
        letter-spacing: .1em;
        font-size: 12.5px;
        color: var(--brand-bright);
    }

        .event-more summary::-webkit-details-marker {
            display: none;
        }

        .event-more summary::after {
            content: '+';
            margin-left: auto;
            font-family: var(--f-body);
            font-size: 19px;
            line-height: 1;
        }

    .event-more[open] summary::after {
        content: '\2013';
    }

.event-more-body {
    padding-top: 14px;
}

    .event-more-body p {
        line-height: 1.7;
        margin-bottom: 18px;
    }

        .event-more-body p:last-child {
            margin-bottom: 22px;
        }

/* ---------- Blog cards ---------- */
.blog-card .thumb {
    height: 190px;
}

.blog-meta {
    font-family: var(--f-label);
    text-transform: uppercase;
    letter-spacing: .08em;
    font-size: 11.5px;
    color: var(--grey-dim);
    margin-bottom: 10px;
}

/* Real post titles/excerpts from the CRM won't all be the same length like the
   placeholder text is — without a fixed reserve, a card with a one-line title next
   to one with a two-line title would leave its excerpt, and therefore its "Read
   More" toggle, starting at a different height, so a row of cards would look
   ragged instead of aligned. Clamping both to a fixed number of lines (and
   reserving that many lines' worth of height even when the text is shorter) keeps
   every card's image / title / excerpt / Read More position uniform across a row
   regardless of how long any individual post's title or excerpt actually is. */
.blog-card h3 {
    min-height: 2.1em;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.blog-excerpt {
    min-height: 4.8em;
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

/* Blog cards read in place instead of linking out to a separate article page —
   each post shows its cover image + an excerpt, with a "Read More" toggle that
   expands the same card to reveal the full post text. Same reasoning as the home
   page's class cards (see #classes-preview .grid-3 above): a plain .card/.article
   container, not a link, since the disclosure toggle can't legally nest inside an
   <a>. align-items:start stops CSS Grid's default stretch from padding out the
   still-closed cards with empty space whenever a sibling opens. Kept as its own
   .blog-more/.blog-more-body block (mirroring .class-more 1:1) rather than sharing
   that class, so future tuning of one doesn't silently affect the other. */
#blog-list .grid-3 {
    align-items: start;
}

.blog-more {
    margin-top: 18px;
    padding-top: 16px;
    border-top: 1px solid var(--line);
}

    .blog-more summary {
        list-style: none;
        cursor: pointer;
        display: flex;
        align-items: center;
        gap: 8px;
        font-family: var(--f-label);
        font-weight: 700;
        text-transform: uppercase;
        letter-spacing: .1em;
        font-size: 12.5px;
        color: var(--brand-bright);
    }

        .blog-more summary::-webkit-details-marker {
            display: none;
        }

        .blog-more summary::after {
            content: '+';
            margin-left: auto;
            font-family: var(--f-body);
            font-size: 19px;
            line-height: 1;
        }

    .blog-more[open] summary::after {
        content: '\2013';
    }

.blog-more-body {
    padding-top: 16px;
}

    .blog-more-body p {
        line-height: 1.7;
        margin-bottom: 18px;
    }

        .blog-more-body p:last-child {
            margin-bottom: 0;
        }

/* ---------- Accordion (Policies / FAQs share this pattern) ---------- */
.acc-group {
    margin-bottom: 14px;
}

    .acc-group summary {
        list-style: none;
        cursor: pointer;
        display: flex;
        align-items: center;
        justify-content: space-between;
        gap: 16px;
        background: var(--panel);
        border: 1px solid var(--line);
        border-left: 3px solid var(--brand);
        padding: 20px 24px;
        font-family: var(--f-label);
        text-transform: uppercase;
        letter-spacing: .08em;
        font-size: 15px;
        color: var(--paper);
    }

        .acc-group summary::-webkit-details-marker {
            display: none;
        }

        .acc-group summary::after {
            content: '+';
            font-family: var(--f-body);
            font-size: 22px;
            color: var(--brand-bright);
            flex: none;
        }

    .acc-group[open] summary::after {
        content: '\2013';
    }

.acc-items {
    background: var(--surface-2);
    border: 1px solid var(--line);
    border-top: none;
    padding: 8px 10px;
}

.acc-item {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 16px;
    padding: 14px 16px;
    border-bottom: 1px solid var(--line);
    font-size: 14.5px;
}

    .acc-item:last-child {
        border-bottom: none;
    }

    .acc-item a {
        color: var(--grey);
    }

        .acc-item a:hover {
            color: var(--brand-bright);
        }

    .acc-item .dl {
        font-family: var(--f-label);
        font-size: 11px;
        letter-spacing: .1em;
        text-transform: uppercase;
        color: var(--brand-bright);
        border: 1px solid var(--line-brand);
        padding: 6px 12px;
        white-space: nowrap;
    }
/* FAQ variant: plain answer text instead of a document list.
   Carries .acc-items' surface and border so an open answer reads as attached to
   its question bar rather than floating loose on the page background. */
.faq-answer {
    padding: 18px 24px 22px;
    font-size: 14.5px;
    color: var(--grey);
    line-height: 1.7;
    background: var(--surface-2);
    border: 1px solid var(--line);
    border-top: none;
}

    .faq-answer p {
        margin: 0;
    }

        .faq-answer p + p {
            margin-top: 14px;
        }

/* Label separating the FAQ accordion into audience groups. */
.faq-band {
    margin-top: 46px;
}

    .faq-band:first-of-type {
        margin-top: 0;
    }

/* ---------- Product / shop cards ---------- */
.product-card {
    display: block;
}

    .product-card .thumb {
        height: 200px;
    }

.price-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-top: 14px;
}

.price {
    font-family: var(--f-display);
    font-size: 24px;
    color: var(--brand-bright);
}

/* ---------- Product detail page (product.html) ---------- */
/* The gallery panel reuses .card purely for its placeholder-image / photo
   styling (see .card .thumb above) — it isn't itself a link, so its hover
   affordances (lift + red underline sweep) are switched off below rather
   than duplicating the thumb rules under a brand new class. */
.product-gallery {
    cursor: default;
}

    .product-gallery:hover {
        transform: none;
        border-color: var(--line);
    }

    .product-gallery::after {
        display: none;
    }
    /* Unlike .card's other uses, the gallery panel has nothing below the image —
   so the thumb is pulled flush to all four edges of the card's padding
   instead of leaving .card .thumb's usual 22px gap underneath for a caption/
   title that isn't there. */
    .product-gallery .thumb {
        height: 420px;
        margin: -32px;
    }

.product-info .price {
    font-size: 32px;
    display: block;
    margin: 6px 0 20px;
}

/* ---------- Pricing cards ---------- */
.pricing-card {
    background: var(--panel);
    border: 1px solid var(--line);
    padding: 36px 30px;
    text-align: center;
    position: relative;
}

    .pricing-card.featured {
        border-color: var(--brand);
        transform: scale(1.03);
    }

        .pricing-card.featured::before {
            content: 'Most Popular';
            position: absolute;
            top: -13px;
            left: 50%;
            transform: translateX(-50%);
            background: var(--brand);
            color: var(--on-brand);
            font-family: var(--f-label);
            font-size: 11px;
            letter-spacing: .1em;
            text-transform: uppercase;
            padding: 5px 16px;
        }

    .pricing-card .amount {
        font-family: var(--f-display);
        font-size: 48px;
        color: var(--paper);
        margin: 14px 0 4px;
    }

        .pricing-card .amount span {
            font-family: var(--f-label);
            font-size: 14px;
            color: var(--grey);
            text-transform: none;
            letter-spacing: 0;
        }

    .pricing-card ul {
        text-align: left;
        margin: 26px 0;
    }

    .pricing-card li {
        padding: 10px 0;
        border-bottom: 1px solid var(--line);
        font-size: 14.5px;
        color: var(--grey);
        display: flex;
        gap: 10px;
        align-items: flex-start;
    }

        .pricing-card li::before {
            content: '✕';
            color: var(--brand-bright);
            font-weight: 700;
            transform: rotate(45deg);
        }

/* ---------- Members / login ---------- */
.login-card {
    max-width: 440px;
    margin: 0 auto;
}

.benefits-grid {
    display: grid;
    grid-template-columns: repeat(4,1fr);
    gap: 20px;
}

.benefit {
    display: flex;
    gap: 14px;
    align-items: center;
    padding: 20px 22px;
    background: var(--panel);
    border: 1px solid var(--line);
}

    .benefit svg {
        flex: 0 0 24px;
        width: 24px;
        height: 24px;
        color: var(--brand-bright);
    }

    .benefit h4 {
        font-size: 15px;
        margin: 0;
        letter-spacing: .3px;
    }

    .benefit p {
        font-size: 14px;
        margin: 6px 0 0;
    }

/* Members app — "Setting Up The App" numbered step cards (added 2026-08-25,
   Members Area page). Deliberately its own component rather than reusing .card:
   .card has overflow:hidden (needed for its thumb-image crop + hover underline
   sweep elsewhere), which would clip the .step-num badge poking above the card's
   own top edge. .step-num reuses the same brand-clipped-corner badge treatment as
   .date-badge on the Events page (background:var(--brand); color:var(--on-brand)) for
   visual consistency with that existing numbered/badged pattern. */
.step-card {
    position: relative;
    background: var(--panel);
    border: 1px solid var(--line);
    padding: 32px 26px 26px;
    transition: transform .3s ease, border-color .3s ease;
}

    .step-card:hover {
        transform: translateY(-4px);
        border-color: var(--line-brand);
    }

.step-num {
    position: absolute;
    top: -15px;
    left: 24px;
    width: 34px;
    height: 34px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--brand);
    color: var(--on-brand);
    font-family: var(--f-label);
    font-weight: 700;
    font-size: 13px;
    clip-path: polygon(7px 0,100% 0,100% 100%,0 100%,0 7px);
}

.step-card svg {
    width: 24px;
    height: 24px;
    color: var(--brand-bright);
    margin-bottom: 14px;
}

.step-card h4 {
    font-size: 14.5px;
    text-transform: uppercase;
    letter-spacing: .05em;
    margin-bottom: 8px;
}

.step-card p {
    font-size: 14px;
    color: var(--grey);
    line-height: 1.65;
    margin: 0;
}

/* ---------- Team / coach cards ---------- */
.team-card {
    background: var(--panel);
    border: 1px solid var(--line);
    overflow: hidden;
    transition: border-color .3s ease, transform .3s ease;
}

    .team-card:hover {
        transform: translateY(-6px);
        border-color: var(--line-brand);
    }

    .team-card .photo {
        height: 280px;
        overflow: hidden;
        background: #000;
    }

        .team-card .photo img {
            width: 100%;
            height: 100%;
            object-fit: cover;
            display: block;
            filter: grayscale(.4) contrast(1.05);
            transition: filter .5s ease, transform .5s ease;
        }

    .team-card:hover .photo img {
        filter: grayscale(0) contrast(1.05);
        transform: scale(1.05);
    }

    .team-card .body {
        padding: 22px;
    }

    .team-card h4 {
        font-size: 20px;
        margin-bottom: 4px;
    }

    .team-card .role {
        font-family: var(--f-label);
        text-transform: uppercase;
        letter-spacing: .1em;
        font-size: 12.5px;
        color: var(--brand-bright);
        margin-bottom: 12px;
        display: block;
    }

    .team-card p {
        font-size: 14px;
        margin-bottom: 0;
    }

    .team-card .creds {
        display: flex;
        flex-wrap: wrap;
        gap: 8px;
        margin-top: 14px;
    }

    /* Logo tile instead of a coach headshot.
   The default .photo crops a photograph to fill with object-fit:cover and
   desaturates it — both wrong for a logo, which must sit whole, centred and in
   its real colours. This variant contains it instead, on a themed panel with a
   soft brand glow so the tile reads as designed rather than as a missing image.
   Swap a card back to a real headshot by dropping the .photo-logo class. */
    .team-card .photo.photo-logo {
        display: flex;
        align-items: center;
        justify-content: center;
        padding: 40px;
        background: radial-gradient(ellipse 70% 70% at 50% 45%, rgba(var(--brand-rgb),.13), transparent 70%), var(--panel-2);
    }

        .team-card .photo.photo-logo img {
            width: auto;
            height: auto;
            max-width: 100%;
            max-height: 100%;
            object-fit: contain;
            filter: none;
        }

    .team-card:hover .photo.photo-logo img {
        filter: none;
        transform: scale(1.05);
    }

    .team-card .cred {
        font-family: var(--f-label);
        font-size: 10.5px;
        letter-spacing: .08em;
        text-transform: uppercase;
        color: var(--grey-dim);
        border: 1px solid var(--line);
        padding: 5px 10px;
    }

/* ---------- Gallery grid ---------- */
.gallery-grid {
    display: grid;
    grid-template-columns: repeat(4,1fr);
    gap: 14px;
}

.gallery-tile {
    position: relative;
    aspect-ratio: 1/1;
    overflow: hidden;
    background: #000;
}

    .gallery-tile img {
        width: 100%;
        height: 100%;
        object-fit: cover;
        display: block;
        filter: grayscale(.3) contrast(1.05) brightness(.92);
        transition: filter .4s ease, transform .5s ease;
    }

    .gallery-tile:hover img {
        filter: grayscale(0) contrast(1.05) brightness(1);
        transform: scale(1.06);
    }

    .gallery-tile .cap {
        position: absolute;
        left: 0;
        right: 0;
        bottom: 0;
        padding: 14px 16px;
        background: linear-gradient(0deg, rgba(0,0,0,.82), transparent);
        font-family: var(--f-label);
        text-transform: uppercase;
        letter-spacing: .08em;
        font-size: 11.5px;
        color: var(--on-dark);
        opacity: 0;
        transform: translateY(6px);
        transition: opacity .3s ease, transform .3s ease;
    }

    .gallery-tile:hover .cap {
        opacity: 1;
        transform: translateY(0);
    }

    .gallery-tile.wide {
        grid-column: span 2;
    }

/* ---------- About / founder section ---------- */
.founder-grid {
    display: grid;
    grid-template-columns: .75fr 1.25fr;
    gap: 56px;
    align-items: center;
}

.founder-portrait {
    position: relative;
}

    .founder-portrait img {
        width: 100%;
        height: auto;
        filter: grayscale(.25) contrast(1.05);
    }

    .founder-portrait .tagplate {
        position: absolute;
        left: 16px;
        bottom: 16px;
        background: rgba(8,8,8,.82);
        backdrop-filter: blur(6px);
        border: 1px solid var(--line-brand);
        padding: 10px 16px;
        font-family: var(--f-label);
        text-transform: uppercase;
        letter-spacing: .08em;
        font-size: 12.5px;
        color: var(--on-dark);
    }

blockquote {
    margin: 22px 0;
    padding: 20px 24px;
    border-left: 3px solid var(--brand);
    background: var(--surface-2);
    font-family: var(--f-label);
    font-size: 17px;
    letter-spacing: .01em;
    color: var(--paper);
    font-style: normal;
}

.sig {
    font-family: var(--f-display);
    font-size: 22px;
    margin: 22px 0 0;
    color: var(--paper);
}

.sig-role {
    font-family: var(--f-label);
    text-transform: uppercase;
    letter-spacing: .1em;
    font-size: 12px;
    color: var(--grey-dim);
    margin: 2px 0 0;
}

.creds-row {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    margin-top: 22px;
}

    .creds-row .cred {
        font-family: var(--f-label);
        font-size: 11.5px;
        letter-spacing: .08em;
        text-transform: uppercase;
        color: var(--grey);
        border: 1px solid var(--line);
        padding: 8px 14px;
    }

/* ---------- Generic image placeholder (drop a real <img> in later) ---------- */
.img-placeholder {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    height: 100%;
    position: relative;
    background: linear-gradient(160deg, rgba(var(--brand-rgb),.22), transparent 60%), repeating-linear-gradient(45deg, var(--checker-a) 0 10px, var(--checker-b) 10px 20px);
}

    .img-placeholder::after {
        content: 'IMAGE PLACEHOLDER';
        position: absolute;
        bottom: 8px;
        right: 10px;
        font-family: var(--f-label);
        font-size: 10px;
        letter-spacing: .14em;
        color: var(--label-on-placeholder);
    }

    .img-placeholder svg {
        width: 48px;
        height: 48px;
        opacity: .85;
        color: var(--brand-bright);
    }

/* ---------- Contact / info panels (used on multiple pages) ---------- */
.contact-grid {
    display: grid;
    grid-template-columns: .85fr 1.15fr;
    gap: 40px;
    align-items: start;
}

.contact-info-card {
    background: var(--panel);
    border: 1px solid var(--line);
    padding: 30px;
    margin-bottom: 20px;
}

    .contact-info-card h4 {
        font-size: 17px;
        margin-bottom: 8px;
    }

    .contact-info-card p {
        margin-bottom: 0;
        font-size: 14.5px;
    }

/* ---------- Responsive ---------- */
@media (max-width: 980px) {
    .hero .wrap.hero-content {
        grid-template-columns: 1fr;
    }

    .hero-logo img {
        height: 84px;
    }
    /* UNUSED as of 2026-08-26 — see the .hero-logo comment above .hero-logo{...} further up this file */
    /* padding-top 297px = 242px measured header+ticker stack (see the
     max-width:1080px block's matching comment further up this file for the
     full breakdown) + 55px for the DEMO ONLY .demo-bar now fixed above the
     header (see .site-header-wrap's top:55px above). This is the rule that
     actually wins at typical phone widths (declared later in the file than
     the max-width:1080px block's .hero rule, same specificity), so it must
     match that block's 297px value. */
    .hero {
        padding-top: 297px;
        min-height: auto;
        padding-bottom: 70px;
    }
    /* Below 980px the hero's height is driven by its stacked content (heading, stats,
     the enquiry form) rather than a fixed 100vh, so .hero-media's base rule
     (inset:0, matching the full ~1700px content height) would force object-fit:cover
     to zoom in so far that only ~15% of a 3:2 photo's width stays visible — an
     unusably tight crop found and fixed on 2026-08-24.
     UPDATED 2026-08-27 (Luke: mobile hero should "display as a background in the
     same way as the desktop site" rather than sit above the content as a separate
     banner strip): the 2026-08-24 fix bounded the photo to its own aspect-ratio box
     (zero crop, but only ~260px tall) positioned at the very top of .hero — shorter
     than the 297px fixed header+ticker+demo-bar clearance, so the photo ended up
     entirely hidden behind the header (a real bug, confirmed via Playwright
     screenshot before this change: the mobile hero rendered as solid black with no
     photo visible at all). Replaced that aspect-ratio box with a viewport-relative
     height instead (78vh, clamped 520–680px) — tall enough to (a) clear the header
     with real visible photo underneath it, since .hero-content's text block already
     sits, in normal flow, exactly at the header's bottom edge and is layered above
     .hero-media (z-index 2 vs 0), it now visually overlays the photo the same way
     desktop's headline does; and (b) keep the crop reasonable — at ~650px tall on a
     390px-wide phone, cover crops to ~40% of the photo's width (vs. the ~15% the
     old full-content-height approach produced), a normal hero-image crop ratio, not
     an unusably tight one. The photo still doesn't extend behind the entire
     stacked content (the enquiry-card form, sitting further down, mostly renders on
     the page's plain background rather than the photo) — an actual full-height photo
     is mathematically not viable here (see the math above, ~15% visible even
     centred), so this is a deliberate middle ground: real background-style photo
     behind the headline/subhead/actions like desktop, fading via the existing
     .hero-scrim gradient (already percentage-based within .hero-media, so it
     automatically re-fades at this new height with no separate edit needed) to the
     page's solid --ink background for the content below. .hero-img's
     object-position also changed from "center top" to "center center" per Luke's
     "centring the image" request — center vs top only changes the crop when the box
     is wider/shorter than the 3:2 photo (a desktop-shaped box); on this narrow/tall
     mobile box, height is always the binding dimension so object-position's
     vertical value has no visible effect here, but "center" is kept for
     correctness/consistency with the request rather than left on the old
     desktop-oriented default. */
    .hero-media {
        inset: auto;
        top: 0;
        left: 0;
        right: 0;
        height: 78vh;
        min-height: 520px;
        max-height: 680px;
    }

        .hero-media .hero-img {
            object-position: center center;
        }

    .grid-3, .grid-2, .grid-4 {
        grid-template-columns: 1fr 1fr;
    }

    .gallery-grid {
        grid-template-columns: repeat(2,1fr);
    }

    .gallery-tile.wide {
        grid-column: span 2;
    }

    .stat-strip {
        grid-template-columns: 1fr 1fr;
    }

        .stat-strip div:nth-child(3) {
            border-left: none;
        }

    .footer-grid {
        grid-template-columns: 1fr 1fr;
    }

    .founder-grid {
        grid-template-columns: 1fr;
    }

    .contact-grid {
        grid-template-columns: 1fr;
    }

    .benefits-grid {
        grid-template-columns: 1fr 1fr;
    }
}

@media (max-width: 640px) {
    .grid-3, .grid-2, .grid-4 {
        grid-template-columns: 1fr;
    }

    .gallery-grid {
        grid-template-columns: repeat(2,1fr);
    }

    .gallery-tile.wide {
        grid-column: span 1;
    }

    .stat-strip {
        grid-template-columns: 1fr 1fr;
    }

    .section {
        padding: 76px 0;
    }

    .footer-grid {
        grid-template-columns: 1fr;
    }

    .section-head {
        flex-direction: column;
        align-items: flex-start;
    }

    .pricing-card.featured {
        transform: none;
    }

    .event-card {
        flex-direction: column;
    }

    .benefits-grid {
        grid-template-columns: 1fr;
    }

    .rating-summary {
        flex-direction: column;
        align-items: flex-start;
    }

    .product-gallery .thumb {
        height: 280px;
    }
}

/* ================================================================
   BOOKING CALENDAR (Timetable page)
   A self-contained calendar → class-list → registration-form flow.
   Reuses .field / .btn / .card patterns from the rest of the system
   wherever possible so it doesn't feel like a bolted-on module.
   ================================================================ */

.hidden {
    display: none !important;
}

/* Generic static panel — like .card but without the hover-lift, for
   non-clickable containers (widgets, form wrappers). */
.panel {
    background: var(--panel);
    border: 1px solid var(--line);
    padding: 32px;
}

.panel-tight {
    padding: 22px;
}

@media (max-width: 640px) {
    .panel {
        padding: 22px;
    }
}

/* ---------- Inline notices (disclaimers above the calendar) ---------- */
.notice {
    padding: 14px 18px;
    border-left: 3px solid var(--line);
    background: var(--surface-1);
    font-size: 12.5px;
    color: var(--grey);
    text-align: left;
    line-height: 1.6;
}

    .notice strong {
        color: var(--paper);
    }

    .notice.warn {
        border-left-color: var(--brand);
        background: rgba(var(--brand-rgb),.07);
    }

    .notice + .notice {
        margin-top: 10px;
    }

.notice-icon {
    display: inline-flex;
    vertical-align: -3px;
    margin-right: 6px;
    color: var(--brand-bright);
}

.notice.info .notice-icon {
    color: var(--grey);
}

/* ---------- Calendar (left) + that day's classes (right), desktop only ----------
   Below 900px this collapses to a single column — the calendar can't shrink much
   past ~340px (7 day-circles need room) before it stops being usable next to a
   results column, so it's simplest to stack rather than let both sides get cramped. */
.timetable-layout {
    display: grid;
    grid-template-columns: 380px 1fr;
    gap: 28px;
    align-items: start;
}

@media (max-width: 900px) {
    .timetable-layout {
        grid-template-columns: 1fr;
    }
}

/* ---------- Calendar head / nav ---------- */
.cal-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    padding-bottom: 18px;
    margin-bottom: 22px;
    border-bottom: 1px solid var(--line);
    flex-wrap: wrap;
}

.cal-head-label {
    display: flex;
    align-items: center;
    gap: 10px;
}

    .cal-head-label svg {
        width: 16px;
        height: 16px;
        color: var(--grey);
    }

.cal-head h2 {
    font-size: 15px;
    letter-spacing: .1em;
}

.cal-nav {
    display: flex;
    gap: 6px;
}

.cal-nav-btn {
    width: 34px;
    height: 34px;
    border: 1px solid var(--line);
    background: var(--ink);
    color: var(--grey);
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    transition: border-color .2s ease, color .2s ease;
    padding: 0;
}

    .cal-nav-btn svg {
        width: 12px;
        height: 12px;
    }

    .cal-nav-btn:hover {
        border-color: var(--brand);
        color: var(--brand-bright);
    }

    .cal-nav-btn:disabled {
        opacity: .25;
        pointer-events: none;
    }

/* ---------- Calendar grid ---------- */
.cal-weekdays {
    display: grid;
    grid-template-columns: repeat(7,1fr);
    gap: 6px;
    margin-bottom: 10px;
    text-align: center;
}

    .cal-weekdays span {
        font-family: var(--f-label);
        font-size: 11px;
        letter-spacing: .12em;
        text-transform: uppercase;
        color: var(--grey-dim);
    }

.cal-grid {
    display: grid;
    grid-template-columns: repeat(7,1fr);
    gap: 6px;
    text-align: center;
}

.cal-day {
    background: none;
    border: none;
    padding: 2px 0;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
}

.cal-day-num {
    width: 36px;
    height: 36px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    font-family: var(--f-label);
    font-weight: 700;
    font-size: 13px;
    color: var(--ok);
    transition: background .2s ease, color .2s ease;
}

.cal-day:not(.disabled):hover .cal-day-num {
    background: var(--brand);
    color: var(--on-brand);
}

.cal-day.full .cal-day-num {
    color: var(--full);
}

.cal-day.selected .cal-day-num {
    background: var(--brand);
    color: var(--on-brand);
}

.cal-day.disabled {
    cursor: not-allowed;
    pointer-events: none;
}

    .cal-day.disabled .cal-day-num {
        color: var(--grey-dim);
        opacity: .3;
    }

/* ---------- Legend ---------- */
.cal-legend {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 22px;
    margin-top: 24px;
    padding-top: 18px;
    border-top: 1px solid var(--line);
    font-family: var(--f-label);
    font-size: 11px;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--grey-dim);
}

    .cal-legend .swatch {
        display: inline-flex;
        align-items: center;
        gap: 8px;
    }

    .cal-legend .dot {
        width: 10px;
        height: 10px;
        display: inline-block;
        border-radius: 50%;
    }

        .cal-legend .dot.closed {
            background: none;
            border: 1px solid var(--line);
            border-radius: 2px;
        }

        .cal-legend .dot.ok {
            background: var(--ok);
        }

        .cal-legend .dot.full {
            background: var(--full);
        }

        .cal-legend .dot.sel {
            background: var(--brand);
        }

/* ---------- Empty / prompt state ---------- */
.cal-prompt {
    text-align: center;
    padding: 56px 30px;
}

.cal-prompt-icon {
    width: 44px;
    height: 44px;
    margin: 0 auto 16px;
    border: 1px solid var(--line);
    background: var(--ink);
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--grey-dim);
}

    .cal-prompt-icon svg {
        width: 16px;
        height: 16px;
    }

.cal-prompt h3 {
    font-size: 14px;
    letter-spacing: .08em;
    margin-bottom: 6px;
}

.cal-prompt p {
    font-size: 13px;
    max-width: 320px;
    margin: 0 auto;
}

/* ---------- Class slot cards (results for the selected day) ---------- */
.slot-grid {
    display: grid;
    grid-template-columns: repeat(2,1fr);
    gap: 16px;
}

.slot-card {
    background: var(--ink-2);
    border: 1px solid var(--line);
    padding: 20px;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    gap: 16px;
}

    .slot-card.is-full {
        opacity: .55;
    }

    .slot-card h4 {
        font-size: 16px;
        margin-bottom: 8px;
        letter-spacing: .3px;
    }

    .slot-card.is-full h4 {
        text-decoration: line-through;
        color: var(--grey);
    }

.slot-meta {
    font-family: var(--f-body);
    font-size: 12.5px;
    color: var(--grey);
    display: flex;
    flex-direction: column;
    gap: 5px;
}

    .slot-meta span b {
        color: var(--grey-dim);
        font-weight: 600;
    }

.slot-foot {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    padding-top: 14px;
    border-top: 1px solid var(--line);
}

.slot-status {
    font-family: var(--f-label);
    font-size: 10.5px;
    letter-spacing: .1em;
    text-transform: uppercase;
    padding: 5px 10px;
    border: 1px solid var(--line);
    color: var(--grey);
}

    .slot-status.ok {
        border-color: var(--ok);
        color: var(--ok);
    }

    .slot-status.full {
        border-color: var(--full);
        color: var(--full);
    }

@media (max-width: 640px) {
    .slot-grid {
        grid-template-columns: 1fr;
    }
}

/* ---------- Registration / checkout form ---------- */
.form-block {
    background: var(--surface-2);
    border: 1px solid var(--line);
    padding: 22px;
    margin-bottom: 18px;
}

.form-block-title {
    font-family: var(--f-label);
    text-transform: uppercase;
    letter-spacing: .12em;
    font-size: 12.5px;
    color: var(--paper);
    margin-bottom: 18px;
    display: flex;
    align-items: center;
    gap: 8px;
}

    .form-block-title svg {
        width: 15px;
        height: 15px;
        color: var(--brand-bright);
    }

.field.readonly input {
    color: var(--grey);
    background: var(--surface-1);
}

.field-row {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 16px;
}

@media (max-width: 560px) {
    .field-row {
        grid-template-columns: 1fr;
    }
}

/* ---------- Medical questionnaire accordion ---------- */
.qa-group {
    background: var(--ink-2);
    border: 1px solid var(--line);
    margin-top: 14px;
}

    .qa-group summary {
        list-style: none;
        cursor: pointer;
        padding: 14px 18px;
        font-family: var(--f-label);
        text-transform: uppercase;
        letter-spacing: .08em;
        font-size: 12px;
        color: var(--paper);
        display: flex;
        justify-content: space-between;
        align-items: center;
        gap: 12px;
    }

        .qa-group summary::-webkit-details-marker {
            display: none;
        }

        .qa-group summary svg {
            width: 11px;
            height: 11px;
            color: var(--grey-dim);
            transition: transform .2s ease;
            flex: none;
        }

    .qa-group[open] summary svg {
        transform: rotate(180deg);
    }

.qa-body {
    padding: 4px 18px 18px;
    border-top: 1px solid var(--line);
}

.qa-row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 13px 0;
    border-bottom: 1px solid var(--line);
    font-size: 13px;
}

    .qa-row:last-of-type {
        border-bottom: none;
    }

    .qa-row .qa-text {
        color: var(--grey);
        max-width: 66%;
    }

.qa-choices {
    display: flex;
    gap: 16px;
    flex-shrink: 0;
}

    .qa-choices label {
        display: inline-flex;
        align-items: center;
        gap: 6px;
        font-family: var(--f-label);
        font-size: 11.5px;
        text-transform: uppercase;
        letter-spacing: .06em;
        color: var(--grey);
        cursor: pointer;
    }

    .qa-choices input {
        accent-color: var(--brand);
        width: 15px;
        height: 15px;
    }

.qa-notes {
    margin-top: 14px;
}

    .qa-notes label {
        display: block;
        font-family: var(--f-label);
        font-size: 11px;
        text-transform: uppercase;
        letter-spacing: .1em;
        color: var(--grey);
        margin-bottom: 7px;
    }

    .qa-notes textarea {
        width: 100%;
        background: var(--surface-1);
        border: 1px solid var(--line);
        color: var(--paper);
        padding: 12px 14px;
        font-family: var(--f-body);
        font-size: 13.5px;
        resize: vertical;
    }

        .qa-notes textarea:focus {
            border-color: var(--brand);
            outline: none;
        }

@media (max-width: 560px) {
    .qa-row {
        flex-direction: column;
        align-items: flex-start;
    }

        .qa-row .qa-text {
            max-width: 100%;
        }
}

/* ---------- Dependent child sub-cards ---------- */
.child-card {
    background: var(--panel);
    border: 1px solid var(--line);
    padding: 18px;
    margin-bottom: 14px;
}

.child-card-title {
    font-family: var(--f-label);
    text-transform: uppercase;
    letter-spacing: .1em;
    font-size: 11.5px;
    color: var(--grey);
    border-bottom: 1px solid var(--line);
    padding-bottom: 10px;
    margin-bottom: 14px;
    display: flex;
    align-items: center;
    gap: 7px;
}

    .child-card-title svg {
        width: 13px;
        height: 13px;
        color: var(--grey-dim);
    }

.child-card-remove {
    margin-left: auto;
    width: 22px;
    height: 22px;
    flex: none;
    display: flex;
    align-items: center;
    justify-content: center;
    background: none;
    border: 1px solid var(--line);
    border-radius: 50%;
    color: var(--grey-dim);
    font-size: 15px;
    line-height: 1;
    cursor: pointer;
    transition: border-color .2s ease, color .2s ease;
}

    .child-card-remove:hover {
        border-color: var(--brand);
        color: var(--brand-bright);
    }

/* ---------- Confirmation state ---------- */
.booking-confirm {
    text-align: center;
    padding: 40px 20px;
}

.booking-confirm-icon {
    width: 52px;
    height: 52px;
    margin: 0 auto 18px;
    border: 1px solid var(--ok);
    color: var(--ok);
    display: flex;
    align-items: center;
    justify-content: center;
}

    .booking-confirm-icon svg {
        width: 22px;
        height: 22px;
    }

.booking-confirm h3 {
    font-size: 20px;
    margin-bottom: 10px;
}

.booking-confirm p {
    max-width: 420px;
    margin: 0 auto;
}

/* ================================================================
   EthanHarrisHKA Martial Arts WEBSITE — CLASS-FINDER CHATBOT WIDGET
   ------------------------------------------------------------------
   A lead-qualification chat widget: a few quick questions, then a
   Book Now link or a "call me back" handoff. Opens as a popup
   anchored near the launcher on desktop, full-screen below 480px.

   Deliberately styled off the SITE's own tokens (--brand/--brand-bright/
   --brand-deep, --ink-2/--panel/--paper/--grey/--line, --f-display/
   --f-body) rather than a separate colour system, so re-colouring the
   site for a new client — or picking a different accent via the demo
   picker — re-colours this widget too, with zero widget-specific
   edits. Only exception: --ink-on-accent below, a FIXED dark value
   (not the theme-flipping --ink) used wherever text/an icon sits
   directly on --brand — see the comment on that variable for why.
   ================================================================ */
#dlb-root, #dlb-root * {
    box-sizing: border-box;
}

#dlb-root {
    /* Fixed near-black for text/icons placed directly on --brand. --ink flips to
     near-white in the light theme, which would break contrast on the (always
     mid-to-bright) accent colours — this mirrors the site's own --on-dark
     pattern (a token that deliberately does NOT follow the theme), just the
     dark-on-bright-accent equivalent instead of light-on-dark-photo. */
    --ink-on-accent: #0a0a0a;
    font-family: var(--f-body);
    position: fixed;
    bottom: 20px;
    right: 20px;
    z-index: 9999;
}

/* Launcher */
#dlb-launcher {
    width: 64px;
    height: 64px;
    border-radius: 50%;
    background: var(--brand);
    color: var(--ink-on-accent);
    border: 3px solid var(--ink-2);
    padding: 0;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    box-shadow: 0 8px 24px rgba(0,0,0,.35);
    transition: transform .18s ease, background .2s ease;
}

    #dlb-launcher:hover {
        transform: scale(1.06);
        background: var(--brand-bright);
    }

    #dlb-launcher svg {
        width: 28px;
        height: 28px;
    }

    #dlb-launcher .dlb-pulse {
        position: absolute;
        width: 64px;
        height: 64px;
        border-radius: 50%;
        border: 2px solid var(--brand);
        animation: dlb-ping 2.4s cubic-bezier(0,0,.2,1) infinite;
    }

@keyframes dlb-ping {
    0% {
        transform: scale(1);
        opacity: .6;
    }

    100% {
        transform: scale(1.6);
        opacity: 0;
    }
}

@media (prefers-reduced-motion: reduce) {
    #dlb-launcher .dlb-pulse {
        animation: none;
    }
}

/* Window */
#dlb-window {
    display: none;
    flex-direction: column;
    width: 372px;
    height: 560px;
    max-height: 78vh;
    background: var(--panel);
    border-radius: 4px;
    overflow: hidden;
    box-shadow: 0 20px 60px rgba(0,0,0,.5);
    border: 1px solid var(--line);
    position: absolute;
    bottom: 78px;
    right: 0;
}

    #dlb-window.dlb-open {
        display: flex;
    }

/* Header */
#dlb-header {
    background: var(--ink-2);
    padding: 16px 18px 14px;
    border-bottom: 3px solid var(--brand);
    position: relative;
    flex: none;
}

    #dlb-header .dlb-eyebrow {
        font-family: var(--f-label);
        color: var(--brand-bright);
        font-size: 10px;
        letter-spacing: .14em;
        text-transform: uppercase;
        font-weight: 700;
        margin-bottom: 4px;
    }

    #dlb-header h1 {
        font-size: 20px;
        color: var(--paper);
        line-height: 1.05;
    }

#dlb-close {
    position: absolute;
    top: 14px;
    right: 14px;
    background: none;
    border: none;
    color: var(--grey);
    font-size: 20px;
    line-height: 1;
    padding: 4px;
    transition: color .15s ease;
}

    #dlb-close:hover, #dlb-close:focus-visible {
        color: var(--brand-bright);
    }

/* Progress stripes */
#dlb-progress {
    display: flex;
    gap: 4px;
    margin-top: 12px;
}

.dlb-stripe {
    flex: 1;
    height: 5px;
    background: var(--line);
    border-radius: 2px;
    overflow: hidden;
}

    .dlb-stripe.dlb-filled {
        background: var(--brand);
    }

/* Body */
#dlb-body {
    flex: 1;
    overflow-y: auto;
    padding: 16px;
    display: flex;
    flex-direction: column;
    gap: 10px;
    background: var(--panel);
}

    #dlb-body::-webkit-scrollbar {
        width: 6px;
    }

    #dlb-body::-webkit-scrollbar-thumb {
        background: var(--line);
        border-radius: 3px;
    }

.dlb-msg {
    max-width: 82%;
    padding: 10px 13px;
    border-radius: 12px;
    font-size: 13.5px;
    line-height: 1.45;
    animation: dlb-in .25s ease;
}

@media (prefers-reduced-motion: reduce) {
    .dlb-msg {
        animation: none;
    }
}

@keyframes dlb-in {
    from {
        opacity: 0;
        transform: translateY(6px);
    }

    to {
        opacity: 1;
        transform: translateY(0);
    }
}

.dlb-msg.bot {
    background: var(--surface-2);
    color: var(--paper);
    border: 1px solid var(--line);
    align-self: flex-start;
    border-bottom-left-radius: 3px;
}

.dlb-msg.user {
    background: var(--brand);
    color: var(--ink-on-accent);
    align-self: flex-end;
    border-bottom-right-radius: 3px;
    font-weight: 600;
}

/* Choice chips */
#dlb-choices {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    padding: 2px 16px 12px;
    flex: none;
}

.dlb-chip {
    background: var(--surface-1);
    border: 1.5px solid var(--line);
    color: var(--paper);
    padding: 8px 13px;
    border-radius: 20px;
    font-family: var(--f-body);
    font-size: 13px;
    font-weight: 600;
    cursor: pointer;
    transition: background .15s ease, color .15s ease, border-color .15s ease, transform .1s ease;
}

    .dlb-chip:hover, .dlb-chip:focus-visible {
        background: var(--brand);
        border-color: var(--brand);
        color: var(--ink-on-accent);
        transform: translateY(-1px);
    }

/* CTA link (book now) — reuses the site's own .btn.btn-primary look */
.dlb-cta-wrap {
    padding: 2px 16px 12px;
    flex: none;
}

    .dlb-cta-wrap .btn {
        width: 100%;
    }

/* Input row */
#dlb-inputrow {
    display: flex;
    gap: 8px;
    padding: 12px;
    border-top: 1px solid var(--line);
    background: var(--surface-1);
    flex: none;
}

#dlb-input {
    flex: 1;
    background: var(--panel);
    border: 1px solid var(--line);
    color: var(--paper);
    padding: 10px 12px;
    border-radius: 8px;
    font-size: 13.5px;
    font-family: inherit;
    outline: none;
    transition: border-color .2s ease;
}

    #dlb-input:focus {
        border-color: var(--brand);
    }

#dlb-send {
    background: var(--brand);
    border: none;
    color: var(--ink-on-accent);
    width: 40px;
    padding: 0;
    border-radius: 8px;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    transition: background .15s ease;
}

    #dlb-send:hover {
        background: var(--brand-bright);
    }

    #dlb-send:disabled {
        opacity: .4;
        cursor: not-allowed;
    }

.dlb-typing {
    display: flex;
    gap: 4px;
    padding: 4px 2px;
}

    .dlb-typing span {
        width: 6px;
        height: 6px;
        border-radius: 50%;
        background: var(--grey);
        animation: dlb-bounce 1.1s infinite ease-in-out;
    }

        .dlb-typing span:nth-child(2) {
            animation-delay: .15s;
        }

        .dlb-typing span:nth-child(3) {
            animation-delay: .3s;
        }

@keyframes dlb-bounce {
    0%,60%,100% {
        transform: translateY(0);
    }

    30% {
        transform: translateY(-5px);
    }
}

@media (prefers-reduced-motion: reduce) {
    .dlb-typing span {
        animation: none;
    }
}

/* Full-screen on mobile — the "full screen chat on mobile" half of the brief */
@media (max-width: 480px) {
    #dlb-root {
        bottom: env(safe-area-inset-bottom, 0px);
        right: env(safe-area-inset-right, 0px);
        left: env(safe-area-inset-left, 0px);
    }

    #dlb-launcher {
        position: absolute;
        bottom: 16px;
        right: 16px;
    }

    #dlb-window {
        position: fixed;
        inset: 0;
        width: 100vw;
        height: 100vh;
        max-height: 100vh;
        border-radius: 0;
        border: none;
    }

    #dlb-header {
        padding-top: calc(16px + env(safe-area-inset-top, 0px));
    }

    #dlb-close {
        top: calc(14px + env(safe-area-inset-top, 0px));
        font-size: 26px;
        padding: 8px;
    }

    #dlb-body {
        padding: 14px;
    }

    .dlb-msg {
        max-width: 88%;
        font-size: 15px;
    }

    .dlb-chip {
        font-size: 14px;
        padding: 10px 15px;
    }

    #dlb-inputrow {
        padding: 10px 12px calc(10px + env(safe-area-inset-bottom, 0px));
    }

    #dlb-input {
        font-size: 16px;
        padding: 12px;
    }
    /* 16px stops iOS Safari auto-zoom on focus */
    #dlb-send {
        width: 44px;
    }
}

@media (min-width: 481px) and (max-width: 640px) {
    #dlb-window {
        width: 92vw;
        right: -6px;
    }
}

/* Body scroll lock while full-screen on mobile — see chatbot.js toggleBodyScrollLock() */
body.dlb-scroll-lock {
    overflow: hidden;
}
