/* AUTO-GENERATED by nsop_css_bundle() — do not edit.
   Source: main.css + its @import partials. Edit those instead. */
/* =============================================================================
   NORTH SYDNEY OLYMPIC POOL — MAIN STYLESHEET
   @import manifest, concatenated to main.bundle.css by functions.php.
   NSOP only — legacy NSOP partials (insights / case studies / team /
   flex sections / old chrome) have been removed.
   ============================================================================= */

/* ── Foundation ─────────────────────────────────────────────────────────────*/

/* ── foundation/_fonts.css ── */
/* =============================================================================
   NORTH SYDNEY OLYMPIC POOL — Fonts
   -----------------------------------------------------------------------------
   • MD Nichrome   — display headings (Black / 800). Self-hosted.
   • Archivo Narrow — body copy / big paragraph (Regular / 400). Self-hosted.
   • DM Sans       — medium UI labels. Loaded from Google Fonts in functions.php.
   Add more weights by dropping the woff2 into assets/fonts/ and adding a block.
   ============================================================================= */

/* MD Nichrome — display headings. Black is the only weight supplied; map 700 to
   it too so any "bold" heading still resolves to the brand display face. */
@font-face {
    font-family: 'MD Nichrome';
    src: url('foundation/../../fonts/MDNichrome-Black.woff2') format('woff2');
    /* Single weight supplied — claim the full range so any --fw-* request
       (heading classes ask for 300) still resolves to MD Nichrome instead of
       falling back to Archivo Narrow. */
    font-weight: 100 900;
    font-style: normal;
    font-display: swap;
}

/* Archivo Narrow — body. Regular for copy; Medium/SemiBold/Bold for emphasis. */
@font-face {
    font-family: 'Archivo Narrow';
    src: url('foundation/../../fonts/ArchivoNarrow-Regular.woff2') format('woff2');
    font-weight: 400;
    font-style: normal;
    font-display: swap;
}
@font-face {
    font-family: 'Archivo Narrow';
    src: url('foundation/../../fonts/ArchivoNarrow-Medium.woff2') format('woff2');
    font-weight: 500;
    font-style: normal;
    font-display: swap;
}
@font-face {
    font-family: 'Archivo Narrow';
    src: url('foundation/../../fonts/ArchivoNarrow-SemiBold.woff2') format('woff2');
    font-weight: 600;
    font-style: normal;
    font-display: swap;
}
@font-face {
    font-family: 'Archivo Narrow';
    src: url('foundation/../../fonts/ArchivoNarrow-Bold.woff2') format('woff2');
    font-weight: 700;
    font-style: normal;
    font-display: swap;
}


/* ── foundation/_tokens.css ── */
/* =============================================================================
   NORTH SYDNEY OLYMPIC POOL — Design Tokens (single source of truth)
   -----------------------------------------------------------------------------
   Source: Figma "web" foundation boards
     • Colour      (node 1540-6440)
     • Typography  (node 1540-6533)
     • Shadow      (node 1540-6858)
     • Motion      (docs/motion-data-findings.md — AE ease vocabulary)
   Scaling is viewport-proportional: the container has no max-width, page margin
   and gutter are vw-based, and display type is expressed in vw against the Figma
   1920 canvas — so the whole design scales up/down with the screen. Type carries
   a rem floor via max() so copy stays readable on small screens.
   Never inline a hex/px — always reference a token.
   ============================================================================= */

:root {

    /* ─── Palette ─────────────────────────────────────────────────────────────*/
    --c-black:       #000000;
    --c-white:       #FFFFFF;
    --c-blue:        #0039E6;  /* PRIMARY — CTAs, links, logo wordmark */
    --c-gold:        #EFB621;  /* warm primary accent */
    --c-red:         #E50914;  /* energy / alerts / highlights */
    --c-green:       #005443;  /* deep teal-green */
    --c-teal:        #66E0CB;  /* bright aqua accent */
    --c-sandstone:   #F3D9AF;  /* warm sand — logo on blue, soft surfaces */
    --c-terracotta:  #89351F;  /* earthy clay */
    --c-grey:        #C4C4C4;
    --c-background:  #F9FAFB;  /* page background */

    /* Extended / playful accents */
    --c-loyal:       #FB9A40;  /* warm orange */
    --c-pink:        #FF94CC;  /* intense pink */
    --c-turquoise:   #99EDF0;  /* pretty turquoise */
    --c-sky:         #80D5FF;  /* light sky blue */
    --c-lightning:   #A5B4FF;  /* periwinkle */

    /* Hover / press (derived) */
    --c-blue-hover:  #002BB0;
    --c-blue-press:  #001F80;
    --c-red-hover:   #C40811;
    --c-green-hover: #004537;
    --c-gold-hover:  #D8A417;

    /* Ink aliases — headings / body copy resolve through these */
    --c-charcoal:    var(--c-black);   /* headings / ink */
    --c-body-text:   #1A1A1A;          /* body copy */
    --c-navy:        var(--c-blue);    /* primary alias used across components */
    --c-orange:      var(--c-loyal);

    /* ─── Alpha tints (only the ones actually in use — pruned 2026-07-07) ──────*/
    /* Blue (primary) */
    --c-navy-05:     rgba(0, 57, 230, 0.05);  /* header/mnav pill hover */
    --c-navy-10:     rgba(0, 57, 230, 0.10);  /* = --color-border-subtle */
    --c-navy-30:     rgba(0, 57, 230, 0.30);  /* toggle track, grid borders */
    /* Ink (black) */
    --c-charcoal-03: rgba(0, 0, 0, 0.03);  /* faint hover wash */
    --c-charcoal-10: rgba(0, 0, 0, 0.10);
    --c-charcoal-15: rgba(0, 0, 0, 0.15);  /* hairline dividers */
    --c-charcoal-70: rgba(0, 0, 0, 0.70);  /* secondary text */
    --c-black-60:    rgba(0, 0, 0, 0.60);
    /* White (overlay text on imagery) */
    --c-white-50:    rgba(255, 255, 255, 0.50);
    --c-white-70:    rgba(255, 255, 255, 0.70);

    /* ─── Semantic tokens (the component-facing colour API) ───────────────────*/
    --color-bg-page:              var(--c-background);
    --color-bg-surface:           var(--c-background);
    --color-bg-inverse:           var(--c-blue);
    --color-text-primary:         var(--c-black);
    --color-text-body:            var(--c-body-text);
    --color-text-secondary:       var(--c-charcoal-70);
    --color-text-inverse:         var(--c-white);
    --color-action-primary:       var(--c-blue);
    --color-action-primary-hover: var(--c-blue-hover);
    --color-action-outline:       var(--c-blue);
    --color-accent-green:         var(--c-green);
    --color-accent-orange:        var(--c-loyal);
    --color-accent-lime:          var(--c-gold);
    --color-border-subtle:        var(--c-navy-10);

    /* ─── Colour combinations — approved band + ink pairings ──────────────────
       The palette pairs into a fixed set of BAND (background) + INK (text)
       combinations. Any coloured surface — the footer banner, buttons, section
       bands, cards — MUST use one of these so the text always harmonises with
       its background. Some bands carry more than one valid ink (the consuming
       component picks); the matrix below is the single source of truth.

       RULE (client): gold is INK-ONLY — a text/accent colour, never a band.

         BAND                →  approved INK(s)        used by
         ─────────────────────────────────────────────────────────────────────
         teal                →  green                  banner · buttons
         green               →  teal · white           banner (teal) · buttons (white)
         coral (terracotta)  →  gold · white           banner (gold) · buttons (white)
         sandstone (sand)    →  blue                   banner · cards
         blue                →  white · sandstone       banner (white) · footer legal (sand)
         background          →  blue · green           banner fallback · section headings
         ─────────────────────────────────────────────────────────────────────

       --combo-*-band / --combo-*-ink below encode the pair the ADAPTIVE footer
       banner uses per band (its single chosen ink). main.js reads the page's
       lead hero band and applies the matching pair to --fb-bg / --fb-ink.
       A gold hero collapses to the coral combo (gold can't be a band). */
    --combo-teal-band:  var(--c-teal);        --combo-teal-ink:  var(--c-green);
    --combo-green-band: var(--c-green);       --combo-green-ink: var(--c-teal);
    --combo-coral-band: var(--c-terracotta);  --combo-coral-ink: var(--c-gold);
    --combo-sand-band:  var(--c-sandstone);   --combo-sand-ink:  var(--c-blue);
    --combo-blue-band:  var(--c-blue);        --combo-blue-ink:  var(--c-white);
    --combo-page-band:  var(--c-background);   --combo-page-ink:  var(--c-blue);

    /* ─── Fonts ───────────────────────────────────────────────────────────────
       MD Nichrome (display headings, Black/800) is COMMERCIAL — self-hosted woff2
       in assets/fonts/ (see _fonts.css). Archivo Narrow + DM Sans load from
       Google Fonts (enqueued in functions.php). NSOP has no serif — --f-serif is
       an alias to the body face so any legacy serif reference still resolves. */
    --f-heading: 'MD Nichrome', 'Archivo Narrow', system-ui, sans-serif;
    --f-body:    'Archivo Narrow', system-ui, sans-serif;
    --f-ui:      'DM Sans', system-ui, sans-serif;
    --f-serif:   var(--f-body);

    /* Font weights — every font-weight in the theme resolves through these
       (client 2026-07-09: no literal weights in components). The ONLY exempt
       literals are @font-face range descriptors ("font-weight: 100 900" in
       _fonts.css / _login.css) — descriptors can't read custom properties. */
    --fw-light:    300;
    --fw-regular:  400;
    --fw-medium:   500;
    --fw-semibold: 600;
    --fw-bold:     700;
    --fw-black:    800;   /* MD Nichrome Black — ALL display headings/links */

    /* ─── Type scale — viewport-proportional (Figma 1920 canvas) ──────────────
       px ÷ 1920 × 100 = vw. Body/UI carry a rem floor via max() so copy stays
       readable on small screens. Display HEADINGS scale continuously (below). */

    /* Display headings scale CONTINUOUSLY from the phone anchor (375px frame,
       Figma mobile spec) up to the @1920 target — no frozen floor zone. Form:
       max(rem + vw, vw). The first term is a straight line from the mobile size
       @375 to the desktop size @1920 (gentler slope, so it wins below 1920); the
       second is the pure design-rate vw line that takes over ABOVE 1920 (keeps
       type uncapped past the canvas, same logic as before). Both meet at 1920. */
    --fs-h1:      max(1.9375rem + 8.8026vw, 10.4167vw);  /* 64px @375 → 200px @1920, uncapped */
    --fs-h2:      max(1.6rem + 6.9903vw, 8.3333vw);      /* 52px @375 → 160px @1920, uncapped */
    --fs-h3:      max(1.4375rem + 4.0129vw, 5.2083vw);   /* 38px @375 → 100px @1920, uncapped */
    --fs-h4:      max(0.6125rem + 2.7184vw, 3.2292vw);   /* 20px @375 →  62px @1920, uncapped */
    --fs-h5:      max(1.3556rem + 1.6828vw, 2.8125vw);   /* 28px @375 →  54px @1920, uncapped */
    --fs-link:    max(1.25rem, 1.4583vw);     /*  28px @1920, floor 20px — MD Nichrome links */
    --fs-link-sm: max(1rem, 1.0417vw);        /*  20px @1920, floor 16px */
    --fs-big-p:   max(1.125rem, 1.5625vw);    /*  30px @1920, floor 18px — big paragraph */
    --fs-ui:      max(0.9375rem, 0.9375vw);   /*  18px @1920, floor 15px — DM Sans UI */
    --fs-body:    max(1rem, 1.0417vw);        /*  20px @1920, floor 16px — Archivo Narrow body */
    --fs-cap:     max(0.875rem, 0.8333vw);    /*  16px @1920, floor 14px — cap headings */
    --fs-small:   max(0.9375rem, 0.9375vw);   /*  18px @1920, floor 15px — small body */

    /* Line heights */
    --lh-h1:      0.8;
    --lh-h2:      0.8;
    --lh-h3:      0.8;
    --lh-h4:      0.8;
    --lh-h5:      1;
    --lh-link:    1;
    --lh-link-sm: 1.1;
    --lh-ui:      1.333;   /* 24 / 18 — DM Sans */
    --lh-body:    1.2;     /* Archivo Narrow body (Figma) */
    --lh-cap:     1.5;
    --lh-small:   1.5;

    --ls-cap:     0.0875rem;  /* 1.4px — cap-heading letter-spacing */

    /* ─── Spacing scale (md = base = 16px) ────────────────────────────────────*/
    --sp-3xs: 0.125rem;  /* 2px   */
    --sp-2xs: 0.25rem;   /* 4px   */
    --sp-xs:  0.5rem;    /* 8px   */
    --sp-sm:  0.75rem;   /* 12px  */
    --sp-md:  1rem;      /* 16px  base */
    --sp-lg:  1.5rem;    /* 24px  */
    --sp-xl:  2rem;      /* 32px  */
    --sp-2xl: 3rem;      /* 48px  */
    --sp-3xl: 4rem;      /* 64px  */
    --sp-4xl: 5rem;      /* 80px  */
    --sp-5xl: 6.25rem;   /* 100px */

    /* Fluid spacing — scales between small and large viewports */
    --sp-fluid-sm:    clamp(1rem, 0.879rem + 0.518vw, 1.5rem);     /* 16 → 24 */
    --sp-fluid-lg:    clamp(2rem, 1.757rem + 1.036vw, 3rem);       /* 32 → 48 */
    --sp-fluid-xl-sm: clamp(1.875rem, 1.723rem + 0.647vw, 2.5rem); /* 30 → 40 */
    --sp-fluid-xl:    clamp(2.5rem, 2.136rem + 1.553vw, 4rem);     /* 40 → 64 */
    --sp-fluid-2xl:   clamp(3rem, 2.515rem + 2.071vw, 5rem);       /* 48 → 80 */

    /* Fluid companions to the core scale — same max(rem floor, vw) pattern as
       the type scale (vw = px@1920 ÷ 19.2, floor = 75% of the 1920 value, so
       spacing shrinks in step with the text it separates). Use these for
       STRUCTURAL gaps/padding that should breathe with the viewport (section
       innards, card grids, footer/header rhythm); keep the fixed --sp-* for
       hairline-adjacent details, touch targets, and anything ≤12px.
       Adopted: header rows, footer (2026-07-09); rollout tracked in
       docs/token-scaling-audit.md. */
    --sp-md-f:  max(0.75rem, 0.8333vw);     /*  16px @1920, floor 12px */
    --sp-lg-f:  max(1.125rem, 1.25vw);      /*  24px @1920, floor 18px */
    --sp-xl-f:  max(1.5rem, 1.6667vw);      /*  32px @1920, floor 24px */
    --sp-2xl-f: max(2.25rem, 2.5vw);        /*  48px @1920, floor 36px */
    --sp-3xl-f: max(3rem, 3.3333vw);        /*  64px @1920, floor 48px */
    --sp-4xl-f: max(3.75rem, 4.1667vw);     /*  80px @1920, floor 60px */
    --sp-5xl-f: max(4.6875rem, 5.2083vw);   /* 100px @1920, floor 75px */

    /* Section / nav rhythm */
    /* max(floor, vw) — no upper cap, so section rhythm stays viewport-proportional
       on >1920 screens like the rest of the layout (type, gutter, margin). Floor
       holds ≤960px. 6.25vw = 120px @1920. */
    --sp-section:      max(3.75rem, 6.25vw);    /* 60px floor → 120px @1920 → scales up — section top/bottom */
    --sp-section-half: max(1.875rem, 3.125vw);  /* 30px floor → 60px  @1920 → scales up — heading → next section */
    --sp-nav-h:        clamp(5rem, 6.51vw, 7.8125rem);    /* 80 → 125px — header height (Figma) */

    /* ─── Grid & layout — fluid, no fixed cap ─────────────────────────────────
       The container scales with the viewport instead of capping. Page margin +
       gutter are vw-proportional (Figma 1920: 120px margin, 24px gutter, 12 cols).
       Column count steps 12 → 6 → 4 at the tablet/mobile breakpoints below. */
    --container-max: none;   /* no cap — scale up/down indefinitely */
    --sp-page-x:     6.25vw;  /* 120px @1920 — page margin */
    --gutter:        1.25vw;  /*  24px @1920 — column gutter */
    --grid-cols:     12;

    /* ─── Radius — size-based scale ───────────────────────────────────────────*/
    --r-card: 0.25rem;                 /* 4px  — DEFAULT card / banner / image frame */
    --r-xs:   0.5625rem;               /* 9px  — type-icon tile */
    --r-sm:   0.75rem;                 /* 12px — small icon container */
    --r-md:   1.125rem;                /* 18px — icon bubble, chips */
    --r-lg:   1.25rem;                 /* 20px — flat content card / panel */
    --r-xl:   clamp(1.5rem, 3vw, 3rem);/* 24px → 48px — large containers / buttons */
    --r-pill: 9999px;                  /* full pill */

    /* ─── Shadow ──────────────────────────────────────────────────────────────*/
    --sh-drop: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);        /* Figma SHADOW token */
    --sh-card: 0px 10px 32px rgba(27, 42, 74, 0.10);     /* soft card lift */

    /* ─── Line weight — the single hairline for rules / dividers / underlines ──*/
    --line-w: 1px;

    /* ─── Motion — brand ease vocabulary (extracted from the brand AE files) ───
       Every NSOP animation uses one of these. See docs/motion-data-findings.md. */
    --e-outBack: cubic-bezier(0.34, 1.56, 0.64, 1);  /* ENTRANCE — "come up for air" overshoot */
    --e-inCirc:  cubic-bezier(0.55, 0, 1, 0.45);     /* EXIT — accelerate up & away */
    --e-outCirc: cubic-bezier(0, 0.55, 0.45, 1);     /* image settle */
    --e-inQuint: cubic-bezier(0.64, 0, 0.78, 0);     /* wave scale-collapse */
    --e-inQuad:  cubic-bezier(0.11, 0, 0.5, 0);      /* parallax */
    --e-mask:    cubic-bezier(0.615, 0, 0.367, 1);   /* masked line reveal */
    --e-outQuart:cubic-bezier(0.25, 1, 0.5, 1);      /* logo wave-warp settle */

    /* Motion timing / travel */
    --m-word-dur:     0.7s;    /* H1 word rise */
    --m-word-stagger: 0.06s;   /* per word */
    --m-line-dur:     0.85s;   /* H2/H3 line reveal */
    --m-line-stagger: 0.11s;   /* per line */
    --m-media-dur:    1.1s;    /* image reveal */
    --m-picto-dur:    0.6s;    /* pictogram part pop */
    --m-picto-stagger:0.06s;
    --m-wipe-dur:     1.7s;    /* page-transition wave sweep */

    /* Transitions */
    --transition:        0.25s ease;
    --transition-layout: 0.35s ease; /* dimension changes — height, grid-template-rows */
}

/* =============================================================================
   RESPONSIVE — breakpoint token overrides (768 / 1024)
   Desktop-first: :root above holds Desktop (≥1024px). Everything stays
   vw-proportional (no px) so the design keeps scaling; the column count steps
   down, margin & gutter re-anchor to each breakpoint's design frame, and the
   flat-card radius shrinks on mobile.
   ============================================================================= */

/* Tablet — 768px to 1023px.
   Gutter/margin re-anchored to the ~768 design frame (Figma: 32px margin, 16px
   gutter) so they don't inherit the 1920-anchored desktop vw (which shrinks to a
   cramped ~10px gutter here). Stays vw-proportional — no px. */
@media (max-width: 1023px) {
    :root {
        --grid-cols:  6;
        --sp-page-x:  4.17vw;   /* 32px @768 — page margin */
        --gutter:     2.08vw;   /* 16px @768 — column gutter */
    }
}

/* Mobile — ≤ 767px. Re-anchored to the 375 design frame (Figma: 16px margin,
   8px gutter). vw values ≈ continuous with tablet across the 767/768 boundary. */
@media (max-width: 767px) {
    :root {
        --grid-cols:  4;
        --sp-page-x:  4.27vw;   /* 16px @375 — page margin */
        --gutter:     2.13vw;   /*  8px @375 — column gutter */
        --r-lg:       var(--r-sm);  /* 20px → 12px — image / flat-card surfaces shrink */

        /* Display line-heights loosen on mobile (Figma mobile spec):
           tight 0.8 display leading is too cramped at phone sizes. */
        --lh-h2:      0.9;   /* 90% */
        --lh-h3:      0.9;   /* 90% */
        --lh-h4:      1.2;   /* 120% */
    }
}
        /* single source of truth for all tokens */

/* ── foundation/_reset.css ── */
/* =============================================================================
   NSOP — Reset
   ============================================================================= */

/* ─── Reset ──────────────────────────────────────────────────────────────────*/
*,
*::before,
*::after {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
}

html {
    scroll-behavior: smooth;
    -webkit-text-size-adjust: 100%;
    overscroll-behavior-y: none;   /* stop the scroll bounce/overscroll glow */
    /* Reserve the scrollbar gutter so the vw-based layout doesn't jump right when
       the scrollbar disappears — on nav-drawer/modal scroll-lock (main.js sets
       body overflow:hidden) or navigating to a page short enough to not scroll.
       No effect on overlay-scrollbar systems (macOS/mobile). */
    scrollbar-gutter: stable;
}

body {
    font-family: var(--f-body);
    font-size: 16px;
    color: var(--c-navy);
    background: var(--c-background);
    line-height: 1.5;
    -webkit-font-smoothing: antialiased;
}

/* ─── Homepage ambient gradient background ───────────────────────────────────
   Soft radial blobs at three corners create a warm cream/blush feel.
   All sections are background:transparent so the gradient shows through.  */
.homepage {
    background:
        radial-gradient(ellipse 60% 40% at 8% 18%,  rgba(230,62,98,0.05)   0%, transparent 70%),
        radial-gradient(ellipse 55% 45% at 92% 60%, rgba(245,166,35,0.06)  0%, transparent 65%),
        radial-gradient(ellipse 50% 55% at 15% 85%, rgba(42,191,191,0.04)  0%, transparent 70%),
        radial-gradient(ellipse 70% 50% at 80% 10%, rgba(230,62,98,0.03)  0%, transparent 70%),
        var(--c-background);
    position: relative;
}

img,
svg {
    display: block;
    max-width: 100%;
}

a {
    color: inherit;
    text-decoration: none;
}

ul,
ol {
    list-style: none;
}

button {
    cursor: pointer;
    border: none;
    background: none;
    font-family: inherit;
}

/* ─── Container ──────────────────────────────────────────────────────────────*/
/* Page shell: max-width, page margins, and the responsive grid. The column
   count honours --grid-cols (12 / 6 / 4) so the container's tracks match every
   section's inner grid at each breakpoint — no more a 12-col container wrapping
   a 6-col section. Safe because direct children default to spanning 1/-1 (the
   safety net below); a child only takes a column position when a section sets
   grid-column explicitly, and every such section re-spans it per breakpoint. */
.container {
    width: 100%;
    max-width: var(--container-max);
    margin: 0 auto;
    padding: 0;
    display: grid;
    grid-template-columns: repeat(var(--grid-cols), 1fr);
    column-gap: var(--gutter);
}

/* Zero-specificity safety net — direct children default to full span.
   Any class rule (0-1-0+) overrides this, so sections using specific
   grid-column values don't need to fight it. */
:where(.container) > * {
    grid-column: 1 / -1;
}

@media (max-width: 1760px) {
    .container {
        padding: 0 var(--sp-page-x);
    }
}


/* ── Components ──────────────────────────────────────────────────────────────*/

/* ── components/_typography.css ── */
/* =============================================================================
   NSOP — Typography utility classes
   -----------------------------------------------------------------------------
   Display headings render in MD Nichrome (via --f-heading); body/UI in Archivo
   Narrow / DM Sans. Everything is token-driven — no hardcoded sizes or colours.
   These .t-* helpers back the design-system reference (/foundations/); real
   sections style their own headings.
   ============================================================================= */

.t-hero,
.t-h1 {
    font-family: var(--f-heading);
    font-weight: var(--fw-light);   /* single MD Nichrome weight resolves regardless */
    font-size: var(--fs-h1);
    line-height: var(--lh-h1);
    color: var(--color-text-primary);
}

.t-h2 {
    font-family: var(--f-heading);
    font-weight: var(--fw-light);
    font-size: var(--fs-h2);
    line-height: var(--lh-h2);
    color: var(--color-text-primary);
}

.t-h3 {
    font-family: var(--f-heading);
    font-weight: var(--fw-light);
    font-size: var(--fs-h3);
    line-height: var(--lh-h3);
    color: var(--color-text-primary);
}

.t-h4,
.t-quote {
    font-family: var(--f-heading);
    font-weight: var(--fw-light);
    font-size: var(--fs-h4);
    line-height: var(--lh-h4);
    color: var(--color-text-primary);
}

.t-h5 {
    font-family: var(--f-heading);
    font-weight: var(--fw-light);
    font-size: var(--fs-h5);
    line-height: var(--lh-h5);
    color: var(--color-text-primary);
}

/* Cap heading — uppercase label above a heading */
.t-cap {
    font-family: var(--f-body);
    font-weight: var(--fw-medium);
    font-size: var(--fs-cap);
    line-height: var(--lh-cap);
    letter-spacing: var(--ls-cap);
    text-transform: uppercase;
    color: var(--c-blue);
}

/* Body */
.t-body,
.t-body-xl {
    font-family: var(--f-body);
    font-weight: var(--fw-regular);
    font-size: var(--fs-body);
    line-height: var(--lh-body);
    color: var(--color-text-body);
}

/* Small body */
.t-small {
    font-family: var(--f-body);
    font-weight: var(--fw-regular);
    font-size: var(--fs-small);
    line-height: var(--lh-small);
    color: var(--color-text-body);
}

/* Label — small uppercase UI label */
.t-label {
    font-family: var(--f-body);
    font-weight: var(--fw-medium);
    font-size: var(--fs-cap);
    line-height: 1;
    text-transform: uppercase;
    letter-spacing: var(--ls-cap);
    color: var(--c-charcoal-70);
}

/* <em> inside these utilities = plain italic emphasis (NSOP has no serif). */
.t-hero em, .t-h1 em, .t-h2 em, .t-h3 em, .t-h4 em, .t-h5 em, .t-quote em {
    font-style: italic;
}


/* ── components/_buttons.css ── */
/* =============================================================================
   NORTH SYDNEY OLYMPIC POOL — Buttons & Links
   Source: Figma "Buttons & Links" (node 1547-3491).
   -----------------------------------------------------------------------------
   ACTION BUTTONS — pill, MD Nichrome Black, uppercase, 32px@1920 (--fs-link).
   States are driven by two overlay tokens per variant (--btn-ov-hover /
   --btn-ov-press) applied as an inset box-shadow that tints the fill beneath
   the label. Disabled = 40% opacity. Everything scales with the viewport.
   ============================================================================= */

.btn {
    /* Per-variant tokens (defaults = primary blue) */
    --btn-bg:       var(--c-blue);
    --btn-fg:       var(--c-white);
    --btn-ov-hover: rgba(0, 0, 0, .25);
    --btn-ov-press: rgba(0, 0, 0, .50);

    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--sp-xs);
    min-height: max(3.25rem, 3.125vw);                 /* 60px @1920, floor 52px */
    padding-block: max(.5rem, .4167vw);                /*  8px @1920 */
    padding-inline: max(1.5rem, 2.0833vw);             /* 40px @1920, floor 24px */
    border: 0;
    border-radius: var(--r-pill);
    background: var(--btn-bg);
    color: var(--btn-fg);
    font-family: var(--f-heading);
    font-weight: var(--fw-black);
    font-size: var(--fs-link);                         /* 32px @1920, floor 20px */
    line-height: 1;
    text-transform: uppercase;
    text-align: center;
    text-decoration: none;
    white-space: nowrap;
    cursor: pointer;
    transition: box-shadow var(--transition), color var(--transition), background var(--transition);
}

/* Hover / pressed — tint the fill with the variant's overlay (sits under the
   label because inset box-shadow paints below content). */
.btn:hover  { box-shadow: inset 0 0 0 100vmax var(--btn-ov-hover); }
.btn:active { box-shadow: inset 0 0 0 100vmax var(--btn-ov-press); }
.btn:focus-visible { outline: 3px solid var(--c-blue); outline-offset: 3px; }

/* Disabled */
.btn:disabled,
.btn[aria-disabled="true"],
.btn.is-disabled {
    opacity: .4;
    pointer-events: none;
}

/* ─── Colour variants (exact overlays from Figma) ────────────────────────────*/
.btn--primary    { --btn-bg: var(--c-blue);       --btn-fg: var(--c-white);      --btn-ov-hover: rgba(0,0,0,.25);       --btn-ov-press: rgba(0,0,0,.50); }
.btn--teal       { --btn-bg: var(--c-teal);       --btn-fg: var(--c-green);      --btn-ov-hover: rgba(0,0,0,.15);       --btn-ov-press: rgba(0,0,0,.30); }
.btn--green      { --btn-bg: var(--c-green);      --btn-fg: var(--c-white);      --btn-ov-hover: rgba(255,255,255,.15); --btn-ov-press: rgba(0,0,0,.30); }
.btn--terracotta { --btn-bg: var(--c-terracotta); --btn-fg: var(--c-white);      --btn-ov-hover: rgba(255,255,255,.10); --btn-ov-press: rgba(255,255,255,.40); }
.btn--gold       { --btn-bg: var(--c-gold);       --btn-fg: var(--c-terracotta); --btn-ov-hover: rgba(255,255,255,.10); --btn-ov-press: rgba(255,255,255,.40); }
.btn--white      { --btn-bg: var(--c-white);      --btn-fg: var(--c-blue);       --btn-ov-hover: rgba(243,217,175,.20); --btn-ov-press: rgba(243,217,175,.40); }

/* Outline ("Line") — blue ring, fills blue on hover. */
.btn--outline {
    background: transparent;
    color: var(--c-blue);
    border: 2px solid var(--c-blue);
    padding-block: calc(max(.5rem, .4167vw) - 2px);   /* keep height with the border */
}
.btn--outline:hover  { background: var(--c-blue);       color: var(--c-white); box-shadow: none; }
.btn--outline:active { background: var(--c-blue-press); color: var(--c-white); box-shadow: none; }

/* ─── Size modifier ──────────────────────────────────────────────────────────*/
.btn--sm {
    min-height: max(2.5rem, 2.292vw);                  /* 44px @1920 */
    padding-inline: max(1rem, 1.25vw);                 /* 24px @1920 */
    font-size: var(--fs-link-sm);                      /* 20px @1920, floor 16px */
}

/* ─── Icon inside a button (uses the NSOP arrow svgs, recoloured to the fg) ──*/
.btn__icon { height: 1em; width: auto; flex: none; fill: currentColor; }

/* =============================================================================
   TEXT LINKS — "LEARN MORE →" / "← BACK"  (MD Nichrome, green, arrow icon)
   ============================================================================= */
.link {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-xs);
    font-family: var(--f-heading);
    font-weight: var(--fw-black);
    font-size: var(--fs-link);                         /* 32px @1920 */
    line-height: 1;
    text-transform: uppercase;
    color: var(--c-green);
    text-decoration: none;
    cursor: pointer;
    background: none;
    border: 0;
    transition: gap var(--transition), opacity var(--transition);
}
.link--sm { font-size: var(--fs-link-sm); line-height: 1.1; }      /* 20px → 16px */
.link__icon {
    height: 1em; width: auto; flex: none; fill: currentColor;      /* 32px arrow box @ 32px link */
    transition: transform var(--transition);
}
.link__icon--back { transform: rotate(180deg); }                  /* arrow-slim points right → flip to left */
.link:hover { gap: var(--sp-sm); }                                 /* arrow nudges out */
.link:hover .link__icon--next { transform: translateX(3px); }
.link:hover .link__icon--back { transform: rotate(180deg) translateX(3px); }
.link.is-disabled,
.link[aria-disabled="true"] { opacity: .4; pointer-events: none; }


/* ── components/_back-to-top.css ── */
/* =============================================================================
   NORTH SYDNEY OLYMPIC POOL — Back to Top
   Source: Figma "web" (node 735-6941). Fixed vertical pill, bottom-right of
   the viewport, built as a column (icon over label) rather than a rotated
   box so fixed positioning stays simple. Hidden near the top of the page;
   once scrolled past one screen, main.js reveals it (slide in from the
   right) while scrolling up and hides it again while scrolling down.
   Hidden-start state is gated by html.js-motion (foundation/_tokens.css /
   utilities/_motion.css convention) — no-JS and reduced-motion visitors get
   it fully visible, no animation, always usable.
   ============================================================================= */

.back-to-top {
    position: fixed;
    right: var(--sp-lg);
    bottom: var(--sp-lg);
    z-index: 50;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--sp-3xs);
    padding-block: 0.625rem;   /* 10px */
    padding-inline: var(--sp-2xs);
    background: var(--c-white);
    border: var(--line-w) solid var(--c-blue);
    border-radius: var(--r-pill);
    color: var(--c-blue);
    text-decoration: none;
    cursor: pointer;
    transition: background var(--transition), color var(--transition);
}
/* Same fill-on-interaction treatment as .btn--outline (foundation/_buttons.css).
   :hover is gated to real pointer devices — on touch, a tap matches :hover
   with no pointer-leave to clear it, so without this gate the fill gets
   "stuck" blue after a tap until something else is touched. :active isn't
   gated: it always releases on release/touchend, no stickiness risk. */
@media (hover: hover) and (pointer: fine) {
    .back-to-top:hover { background: var(--c-blue); color: var(--c-white); }
}
.back-to-top:active        { background: var(--c-blue-press); color: var(--c-white); }
.back-to-top:focus-visible { outline: 3px solid var(--c-blue); outline-offset: 3px; }

/* arrow-slim renders pointing right by default — rotate to point up */
.back-to-top__icon { width: 1.5rem; height: 1.5rem; flex: none; transform: rotate(-90deg); }

.back-to-top__label {
    writing-mode: vertical-rl;
    transform: rotate(180deg);   /* read bottom-to-top, under the up arrow */
    font-family: var(--f-heading);
    font-weight: var(--fw-black);
    font-size: 1rem;             /* 16px */
    line-height: 1.1;
    text-transform: uppercase;
    white-space: nowrap;
}

/* ── Reveal on scroll (JS-driven, motion-gated) ─────────────────────────── */
html.js-motion .back-to-top {
    opacity: 0;
    transform: translateX(150%);
    transition: transform 0.5s var(--e-outBack), opacity 0.3s ease,
                background var(--transition), color var(--transition);
    pointer-events: none;
}
html.js-motion .back-to-top.is-visible {
    opacity: 1;
    transform: none;
    pointer-events: auto;
}

@media (max-width: 767px) {
    .back-to-top { right: var(--sp-md); bottom: var(--sp-md); }
}


/* ── components/_ui.css ── */
/* =============================================================================
   NSOP — UI components
   Figma: "Accordeons & listings" (1552-2313), "Mix components" (1552-2504).
   Internal spacing is mostly em-based so each component scales with its
   (viewport-proportional) font size. Colours/radii/shadows are tokens.
   ============================================================================= */

/* ─── Accordion (FAQ) ────────────────────────────────────────────────────────*/
.accordion__item { border-top: 1px solid var(--c-black); }
.accordion__item:last-child { border-bottom: 1px solid var(--c-black); }
.accordion__trigger {
    width: 100%;
    display: flex; align-items: center; justify-content: space-between; gap: var(--sp-lg);
    padding: 1.1em 0.6em;
    background: none; border: 0; cursor: pointer; text-align: left;
    font-family: var(--f-heading); font-weight: var(--fw-black); font-size: var(--fs-link); line-height: 1;
    color: var(--c-green);
}
.accordion__icon { position: relative; width: 1em; height: 1em; flex: none; }
.accordion__icon::before,
.accordion__icon::after { content: ""; position: absolute; background: currentColor; border-radius: 2px; }
.accordion__icon::before { left: 0; right: 0; top: calc(50% - 1px); height: 2px; }            /* horizontal bar */
.accordion__icon::after  { top: 0; bottom: 0; left: calc(50% - 1px); width: 2px; transition: opacity var(--transition); } /* vertical bar (the +) */
.accordion__item.is-open .accordion__icon::after { opacity: 0; }                               /* becomes − */
.accordion__panel { overflow: hidden; max-height: 0; transition: max-height var(--transition-layout); }
.accordion__item.is-open .accordion__panel { max-height: 60rem; }
.accordion__panel-inner { padding: 0 0.6em 1.4em; font-family: var(--f-body); font-size: var(--fs-body); line-height: 1.2; color: var(--c-black); }

/* ─── Listing (arrow-bullet list) ────────────────────────────────────────────*/
.listing { display: flex; flex-direction: column; gap: var(--sp-lg); }
.listing__item {
    display: flex; align-items: flex-start; gap: var(--sp-md);
    font-family: var(--f-body); font-size: var(--fs-big-p); line-height: 1.2; color: var(--c-black);
}
.listing__item::before {                 /* CSS chevron ">" */
    content: ""; flex: none; width: .42em; height: .42em; margin-top: .28em;
    border-right: .12em solid var(--c-blue); border-bottom: .12em solid var(--c-blue);
    transform: rotate(-45deg);
}
.listing--sm { gap: var(--sp-sm); }
.listing--sm .listing__item { font-size: var(--fs-body); }

/* ─── Toggle (two-option pill switch) ────────────────────────────────────────*/
.toggle { display: inline-flex; }
.toggle__btn {
    font-family: var(--f-heading); font-weight: var(--fw-black); font-size: var(--fs-link); line-height: 1; text-transform: uppercase;
    padding: var(--sp-md) var(--sp-xl); border: var(--line-w) solid var(--c-green); background: transparent; color: var(--c-green);
    cursor: pointer; transition: background var(--transition), color var(--transition);
}
.toggle__btn:first-child { border-radius: var(--r-pill) 0 0 var(--r-pill); }
.toggle__btn:last-child  { border-radius: 0 var(--r-pill) var(--r-pill) 0; border-left: 0; }
.toggle__btn.is-active { background: var(--c-green); color: var(--c-white); }

/* ─── Tabs (underline) ───────────────────────────────────────────────────────*/
.tabs { display: flex; flex-wrap: wrap; }
.tab {
    font-family: var(--f-heading); font-weight: var(--fw-black); font-size: var(--fs-link); line-height: 1;
    padding: .5em 1.5em; background: none; border: 0; border-bottom: 1px solid var(--c-green);
    color: var(--c-green); cursor: pointer; transition: background var(--transition), color var(--transition);
}
.tab.is-active { background: var(--c-green); color: var(--c-white); border-bottom: 3px solid var(--c-teal); }

/* ─── Tags / filter chips ────────────────────────────────────────────────────*/
.tag-list { display: flex; gap: var(--sp-sm); flex-wrap: wrap; }
.tag {
    font-family: var(--f-heading); font-weight: var(--fw-black); font-size: var(--fs-link); line-height: 1; text-transform: uppercase;
    padding: .375em .5em; border: 1px solid var(--c-black); background: transparent; color: var(--c-black);
    cursor: pointer; transition: background var(--transition), border-color var(--transition);
}
.tag:hover { background: var(--c-charcoal-03); }
.tag.is-active { background: var(--c-sandstone); border-color: var(--c-sandstone); }

/* Small tag (Figma 1694-4805) — category label chip. Default = sandstone fill;
   --outline = black border, no fill. MD Nichrome 16px, square corners. Not
   interactive (a label, not a filter button). Used on news / what's-on cards. */
.tag-sm {
    display: inline-flex; align-items: center; justify-content: center;
    padding: var(--sp-2xs) var(--sp-xs);
    font-family: var(--f-heading); font-weight: var(--fw-black); font-size: 1rem; line-height: 1.1;
    text-transform: uppercase; color: var(--c-black); background: var(--c-sandstone);
}
.tag-sm--outline { background: transparent; border: 1px solid var(--c-black); }

/* ─── Search bar ─────────────────────────────────────────────────────────────*/
/* Figma 1694-5376 / 1694-6557: white pill, 1px black border, "Search" left, 40px
   blue circular button with a 22px white search icon right. Everything is em-based
   off --fs-body (498px wide, 8/8/8/24 padding, 40px button @ 20px) so the whole
   control scales as one; width caps at 24.9em (498px) and shrinks to 100% on small. */
.search {
    display: flex; align-items: center; justify-content: space-between; gap: var(--sp-sm);
    background: var(--c-white); border: 1px solid var(--c-black); border-radius: var(--r-pill);
    font-size: var(--fs-body); padding: .4em .4em .4em 1.2em;
    width: min(24.9em, 100%);
}
.search__input { flex: 1 1 auto; min-width: 0; border: 0; background: none; outline: none; font-family: var(--f-body); font-size: 1em; line-height: 1.2; color: var(--c-black); }
.search__input::placeholder { color: var(--c-black); opacity: 1; }
.search__btn { flex: none; display: grid; place-items: center; width: 2em; height: 2em; border-radius: var(--r-pill); background: var(--c-blue); color: var(--c-white); border: 0; cursor: pointer; }
.search__btn svg { height: 1.1em; width: auto; }

/* ─── Pagination ─────────────────────────────────────────────────────────────
   Figma "PAGINATION NUM" (1694-7119) + "PAGINATION POINT" (1927-10618). One
   component, sized off a single em unit (--fs-link-sm = 20px @1920) so the whole
   control scales as one and the Figma px ratios hold at any viewport:
     · row gap 20px = 1em        · num/dot boxes 32px = 1.6em
     · nav↔label gap 8px = .4em  · dot diameter 16px = .8em
   `--pg-accent` themes the active colour (blue default; facility-cards → terracotta). */
.pagination {
    --pg-accent: var(--c-blue);
    display: flex; align-items: center; flex-wrap: wrap;
    font-size: var(--fs-link-sm); gap: 1em;                 /* 20px */
}
.pagination[hidden] { display: none; }   /* flex would otherwise beat [hidden] — JS hides it when there's only one page */
.pagination__nav {
    display: inline-flex; align-items: center; gap: .4em;   /* 8px */
    padding: .4em 0;                                        /* 8px block */
    font-family: var(--f-heading); font-weight: var(--fw-black); font-size: 1em; line-height: 1.1;
    text-transform: uppercase; color: var(--pg-accent); background: none; border: 0; cursor: pointer;
    transition: opacity var(--transition);
}
.pagination__nav svg { width: 1.6em; height: 1.6em; }      /* 32px icon box */
.pagination__nav--prev svg { transform: rotate(180deg); }  /* arrow-slim points right → flip to left */
.pagination__nav[disabled], .pagination__nav.is-disabled { opacity: .4; pointer-events: none; }
.pagination__nav:not([disabled]):not(.is-disabled):hover { opacity: .7; }
.pagination__pages { display: flex; gap: .4em; }            /* 8px */
.pagination__num {
    width: 1.6em; height: 1.6em; display: grid; place-items: center;   /* 32px square */
    font-family: var(--f-heading); font-weight: var(--fw-black); font-size: 1em; line-height: 1;
    background: var(--c-white); color: var(--c-black); border: 0; cursor: pointer;
}
.pagination__num.is-active { background: var(--pg-accent); color: var(--c-white); }
/* Dot pagination (carousels) — 16px dots, 16px apart (Figma circle r8 in a 32px box) */
.pagination__dots { display: flex; gap: .8em; align-items: center; font-size: var(--fs-link-sm); }
.pagination__dot {
    width: .8em; height: .8em; padding: 0; border: 0; border-radius: var(--r-pill);
    background: var(--c-navy-30); cursor: pointer; transition: background var(--transition), opacity var(--transition);
}
.pagination__dot.is-active { background: var(--pg-accent, var(--c-blue)); }

/* ─── Pill (stacked icon + label badge, e.g. LEGEND PLUS) ────────────────────*/
/* Figma 1920-13589: gold badge, terracotta star (48px) over MD Nichrome Black
   label (32px), column, gap 4px, padding 8px. em-based off --fs-link (label =
   1em/32px, icon = 1.5em/48px) so the badge scales as one. */
.pill { display: inline-flex; flex-direction: column; align-items: center; justify-content: center; gap: .125em; padding: .25em; background: var(--c-gold); color: var(--c-terracotta); font-size: var(--fs-link); }
.pill__icon { height: 1.5em; width: auto; }
.pill__label { font-family: var(--f-heading); font-weight: var(--fw-black); font-size: 1em; line-height: 1; text-transform: uppercase; }

/* ─── Icon-bullet list (Figma "Listing" 1686-6057) ───────────────────────────*/
/* A recolourable NSOP icon bullet + label. Bullet colour via --list-bullet.
   Default = "big" (36px icon / big-p label); .icon-list--sm = 28px / body.
   Shared by text-media, program-about and any list with icon bullets. */
.icon-list { display: flex; flex-direction: column; gap: var(--sp-md); width: 100%; }
/* Icon centres vertically against the label (icon is taller than the text's
   line box at small viewports — top-aligning left it visually high/low). */
.icon-list__item { display: flex; align-items: center; gap: var(--sp-md); }
.icon-list__icon { flex: none; display: inline-flex; width: clamp(24px, 1.875vw, 36px); color: var(--list-bullet, var(--c-black)); }
.icon-list__icon svg { width: 100%; height: auto; display: block; }
.icon-list__label { font-family: var(--f-body); font-size: var(--fs-big-p); line-height: 1.2; color: var(--c-black); }
.icon-list--sm .icon-list__icon { width: clamp(20px, 1.458vw, 28px); }
.icon-list--sm .icon-list__label { font-size: var(--fs-body); }
         /* accordion, listing, toggle, tabs, tags, search, pagination, pill */

/* ── components/_forms.css ── */
/* =============================================================================
   NSOP — Form components
   Figma: "Mix components" (1552-2504) Forms & Dropdowns.
   White field, grey border, Archivo Narrow; focus → blue border.
   ============================================================================= */

.form { display: flex; flex-direction: column; gap: var(--sp-xl); }
.form__row { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-lg); }
@media (max-width: 767px) { .form__row { grid-template-columns: 1fr; } }

.field { display: flex; flex-direction: column; gap: var(--sp-xs); }
.field__label { font-family: var(--f-body); font-size: var(--fs-body); line-height: 1.2; color: var(--c-black); }

.input, .textarea, .select {
    width: 100%;
    font-family: var(--f-body); font-size: var(--fs-body); line-height: 1.2; color: var(--c-black);
    background: var(--c-white); border: 1px solid var(--c-grey); border-radius: 0;
    padding: .8em;
    transition: border-color var(--transition);
}
.input::placeholder, .textarea::placeholder { color: var(--c-grey); }
.input:focus, .textarea:focus, .select:focus { outline: none; border-color: var(--c-blue); }
.textarea { min-height: 8em; resize: vertical; }

/* Custom select — hide native arrow, draw a blue chevron */
.select {
    appearance: none; -webkit-appearance: none; cursor: pointer; padding-right: 2.75em;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%230039E6' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
    background-repeat: no-repeat; background-position: right .8em center; background-size: 1.25em;
}
.select:invalid, .select option[value=""] { color: var(--c-grey); }

/* Field with a trailing icon (calendar, etc.) */
.field__control { position: relative; display: flex; align-items: center; }
.field__control .input { padding-right: 2.75em; }
.field__control .field__icon { position: absolute; right: .8em; width: 1.25em; height: 1.25em; pointer-events: none; fill: var(--c-black); }
      /* inputs, textarea, select, form layout */

/* ── components/_cards.css ── */
/* =============================================================================
   NSOP — Cards, banners, info blocks & image frames
   Figma: "Info blocks" (1552-2546), "Cards" (1686-2015), "Image" (1694-5475).
   ============================================================================= */

/* ─── Image frames — aspect-ratio containers ─────────────────────────────────*/
.image-frame { position: relative; overflow: hidden; border-radius: var(--r-card); background: var(--c-navy-10); }
.image-frame > img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block; }
.image-frame--16x9 { aspect-ratio: 16 / 9; }
.image-frame--4x3  { aspect-ratio: 4 / 3; }
.image-frame--1x1  { aspect-ratio: 1 / 1; }
.image-frame--3x4  { aspect-ratio: 3 / 4; }
.image-frame--21x9 { aspect-ratio: 21 / 9; }

/* ─── Card stack — full-width cards, one per row ─────────────────────────────*/
.card-stack { display: flex; flex-direction: column; gap: var(--sp-lg); }

/* ─── Banner card (Figma 1686-2025: program headline + brand graphic, full-width row)
   Default = white bg / blue H2 title / black copy. Colour variants set --bc-title + bg.
   Used for NON-swim programs (each program_type/hub gets a colour). Swim programs use
   .classes-card (photo). See inc/taxonomies.php term_hub (swim|gym|kids). */
.banner-card {
    --bc-title: var(--c-blue);
    display: flex; align-items: center; justify-content: space-between; gap: var(--sp-fluid-xl);
    padding: clamp(1.5rem, 2.08vw, 2.5rem) clamp(1.5rem, 6.25vw, 7.5rem);
    border-radius: var(--r-card); background: var(--c-white); color: var(--c-black); overflow: hidden;
}
.banner-card--blue       { --bc-title: var(--c-white);      background: var(--c-blue);       color: var(--c-white); }
.banner-card--teal       { --bc-title: var(--c-green);      background: var(--c-teal);       color: var(--c-green); }
.banner-card--green      { --bc-title: var(--c-white);      background: var(--c-green);      color: var(--c-white); }
.banner-card--gold       { --bc-title: var(--c-terracotta); background: var(--c-gold);       color: var(--c-terracotta); }
.banner-card--terracotta { --bc-title: var(--c-white);      background: var(--c-terracotta); color: var(--c-white); }
.banner-card__legend { display: flex; flex-direction: column; gap: var(--sp-fluid-lg); min-width: 0; }
.banner-card__eyebrow { font-family: var(--f-heading); font-weight: var(--fw-black); font-size: var(--fs-link-sm); line-height: 1.1; color: currentColor; }
.banner-card__title { font-family: var(--f-heading); font-weight: var(--fw-black); font-size: var(--fs-h2); line-height: .8; text-transform: uppercase; color: var(--bc-title); }
.banner-card__body { font-family: var(--f-body); font-size: var(--fs-big-p); line-height: 1.2; color: currentColor; }
.banner-card__graphic { flex: none; width: clamp(140px, 21vw, 402px); height: auto; }

/* ─── Classes card (Figma 1686-2032: headline + PHOTO, full-width row) — swim squads.
   White or teal bg, green H3 title, black copy. Swim school's own style. */
.classes-card {
    display: flex; align-items: center; justify-content: space-between; gap: var(--sp-fluid-2xl);
    padding: clamp(2rem, 3.125vw, 3.75rem) clamp(1.5rem, 6.25vw, 7.5rem);
    border-radius: var(--r-card); background: var(--c-white); color: var(--c-black); overflow: hidden;
}
.classes-card--teal { background: var(--c-teal); }
.classes-card__legend { display: flex; flex-direction: column; gap: var(--sp-lg); min-width: 0; }
.classes-card__eyebrow { font-family: var(--f-heading); font-weight: var(--fw-black); font-size: var(--fs-link-sm); line-height: 1.1; color: var(--c-black); }
.classes-card__title { font-family: var(--f-heading); font-weight: var(--fw-black); font-size: var(--fs-h3); line-height: .8; text-transform: uppercase; color: var(--c-green); }
.classes-card__body { font-family: var(--f-body); font-size: var(--fs-big-p); line-height: 1.2; color: var(--c-black); }
.classes-card__media { flex: none; width: clamp(200px, 17.5vw, 335px); aspect-ratio: 335 / 307; border-radius: var(--r-card); overflow: hidden; }
.classes-card__media img { width: 100%; height: 100%; object-fit: cover; display: block; }
@media (max-width: 767px) {
    .banner-card, .classes-card { flex-direction: column; align-items: flex-start; gap: var(--sp-lg); }
    .classes-card__media { width: 100%; }
    .banner-card__graphic { width: clamp(120px, 40vw, 200px); }
}

/* ─── Category card (Figma 1686-2039: PROGRAM CATEGORY — portrait, image + colour panel)
   Image top (optional LEGEND PLUS corner ribbon when the term is Legend-Plus-only),
   solid coloured panel below with eyebrow + H5 title + hover-revealed description +
   LEARN MORE. Colour per category via --cc-bg / --cc-title / --cc-text. */
.category-card {
    --cc-bg: var(--c-green); --cc-title: var(--c-teal); --cc-text: var(--c-white);
    display: flex; flex-direction: column; border-radius: var(--r-card); overflow: hidden;
    /* Fixed footprint (Figma 1686-2039: 544 × 642): on hover the image shrinks and
       the coloured panel rises to fill the freed space (revealing the description)
       — the card never changes height, so nothing below it shifts. */
    aspect-ratio: 544 / 642;
    background: var(--cc-bg);
    transition: box-shadow var(--transition), background var(--transition);
}
/* Hover: lift + lighten the panel (mix the card colour toward white). */
.category-card:hover, .category-card:focus-within {
    box-shadow: var(--sh-drop);
    background: color-mix(in srgb, var(--cc-bg) 86%, var(--c-white));
}
.category-card--blue       { --cc-bg: var(--c-blue);       --cc-title: var(--c-teal);  --cc-text: var(--c-white); }
.category-card--terracotta { --cc-bg: var(--c-terracotta); --cc-title: var(--c-gold);  --cc-text: var(--c-white); }
.category-card--teal       { --cc-bg: var(--c-teal);       --cc-title: var(--c-green); --cc-text: var(--c-green); }
.category-card--gold       { --cc-bg: var(--c-gold);       --cc-title: var(--c-terracotta); --cc-text: var(--c-terracotta); }
.category-card--green      { --cc-bg: var(--c-green);      --cc-title: var(--c-teal);  --cc-text: var(--c-white); }
.category-card--sandstone  { --cc-bg: var(--c-sandstone);  --cc-title: var(--c-green); --cc-text: var(--c-black); }

/* Image fills the top of the fixed card; on hover its height drops so the panel
   can rise. flex-basis animates → the image shrinks smoothly. */
.category-card__media { position: relative; overflow: hidden; flex: 0 0 59.5%; min-height: 0; transition: flex-basis var(--transition); }  /* 382 / 642 */
.category-card:hover .category-card__media,
.category-card:focus-within .category-card__media { flex-basis: 50.6%; }   /* 325 / 642 */
.category-card__media img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* LEGEND PLUS corner ribbon — reuses the foundation .pill (gold badge: terracotta
   star over MD-Nichrome label, _ui.css), centred on the card's top-right corner
   and rotated 45° so it reads as a solid gold corner banner. The card media's
   overflow:hidden masks the pill to the corner (Figma 1920-13590: pill 287.9 ×
   142.8, transform rotate(45deg), justify-content flex-end, gold #EFB621). */
/* Anchored to the media's TOP edge at its natural 544/382 ratio (not inset:0), so
   the pill's coordinate system stays fixed while the media shrinks on hover — the
   badge doesn't drift. The shrunk media's overflow:hidden clips the excess below. */
.category-card__ribbon { position: absolute; top: 0; left: 0; width: 100%; aspect-ratio: 544 / 382; overflow: hidden; z-index: 3; pointer-events: none; }
.category-card__ribbon .pill {
    position: absolute; top: 11.5%; left: 92%;       /* rotated pill's centre sits near the corner (Figma AABB offsets) */
    width: 53%; aspect-ratio: 287.893 / 142.819;     /* Figma pill footprint (287.9 × 142.8) */
    justify-content: flex-end;                        /* star + label ride the diagonal (bulk of the gold is off-card) */
    gap: .125em; padding: .5em .25em; border-radius: var(--r-card);  /* Figma 16×8, gap 4 (em off --fs-link) */
    transform: translate(-50%, -50%) rotate(45deg);
    /* font-size inherits .pill's var(--fs-link) → 32px label + 48px star, matching Figma */
}
.category-card__ribbon .pill__label { white-space: nowrap; }   /* single-line banner on the diagonal */

.category-card__body { display: flex; flex-direction: column; justify-content: space-between; gap: var(--sp-xl); flex: 1; min-height: 0; padding: clamp(1rem, 1.56vw, 1.875rem) clamp(1.25rem, 3.125vw, 3.75rem); color: var(--cc-text); }
.category-card__eyebrow { font-family: var(--f-body); font-size: var(--fs-body); color: var(--cc-text); }
.category-card__title { font-family: var(--f-heading); font-weight: var(--fw-black); font-size: clamp(2rem, 2.8125vw, 3.375rem); line-height: .85; text-transform: uppercase; color: var(--cc-title); margin-top: var(--sp-2xs); overflow-wrap: anywhere; }
/* description hidden by default, revealed on hover (grid-rows = no layout jank) */
.category-card__desc { display: grid; grid-template-rows: 0fr; opacity: 0; margin-top: 0; transition: grid-template-rows var(--transition), opacity var(--transition), margin-top var(--transition); }
.category-card__desc > span { overflow: hidden; font-family: var(--f-body); font-size: var(--fs-body); line-height: 1.2; color: var(--cc-text); }
.category-card:hover .category-card__desc, .category-card:focus-within .category-card__desc { grid-template-rows: 1fr; opacity: 1; margin-top: var(--sp-xs); }
.category-card__link { display: inline-flex; align-items: center; gap: var(--sp-xs); font-family: var(--f-heading); font-weight: var(--fw-black); font-size: var(--fs-link-sm); line-height: 1.1; text-transform: uppercase; color: var(--cc-title); }
.category-card__link svg { height: 1.4em; width: auto; transition: transform var(--transition); }
.category-card:hover .category-card__link svg { transform: translateX(.3em); }
/* Disabled label (no url — e.g. "Enrolments open soon") — foundation disabled pattern. */
.category-card__link.is-disabled { opacity: .4; pointer-events: none; }
.category-card:hover .category-card__link.is-disabled svg { transform: none; }
/* Tablet/mobile + any touch device (no mouse → no hover): the description is
   ALWAYS revealed. Drop the fixed footprint — natural image aspect, panel hugs
   its (now fully visible) content. */
@media (max-width: 1023px), (hover: none) {
    .category-card { aspect-ratio: auto; }
    .category-card__media,
    .category-card:hover .category-card__media,
    .category-card:focus-within .category-card__media { flex: none; aspect-ratio: 544 / 382; }
    .category-card__desc { grid-template-rows: 1fr; opacity: 1; margin-top: var(--sp-xs); }
}
/* Mobile (1-up, full width): panel hugs content (no row-height stretch to match). */
@media (max-width: 767px) {
    .category-card__body { flex: none; }
}

/* ─── Facility / small category card (Figma 1686-2046) — teal block, INSET image
   (optional) + green H5 title + body + LEARN MORE. Unlike .category-card the image
   sits inside the padded card (not edge-to-edge). Colour via --fc-bg/--fc-title/--fc-text. */
.facility-card {
    --fc-bg: var(--c-teal); --fc-title: var(--c-green); --fc-text: var(--c-black);
    display: flex; flex-direction: column; gap: var(--sp-lg);
    padding: var(--sp-md) var(--sp-md) var(--sp-lg);   /* 16 top · 16 sides · 24 bottom */
    border-radius: var(--r-card); background: var(--fc-bg); color: var(--fc-text);
    transition: box-shadow var(--transition), background var(--transition);
}
/* Hover: lift + lighten the card colour (mix toward white), matching .category-card. */
.facility-card:hover, .facility-card:focus-within {
    box-shadow: var(--sh-drop);
    background: color-mix(in srgb, var(--fc-bg) 86%, var(--c-white));
}
.facility-card--sandstone { --fc-bg: var(--c-sandstone); --fc-title: var(--c-green); }
.facility-card--gold      { --fc-bg: var(--c-gold);      --fc-title: var(--c-terracotta); }
.facility-card--blue      { --fc-bg: var(--c-blue);      --fc-title: var(--c-sandstone); --fc-text: var(--c-white); }
.facility-card--green      { --fc-bg: var(--c-green);      --fc-title: var(--c-teal); --fc-text: var(--c-white); }
.facility-card--terracotta { --fc-bg: var(--c-terracotta); --fc-title: var(--c-gold); --fc-text: var(--c-white); }
.facility-card__media { border-radius: var(--r-card); overflow: hidden; aspect-ratio: 370 / 204; }
.facility-card__media img { width: 100%; height: 100%; object-fit: cover; display: block; }
.facility-card__body { display: flex; flex-direction: column; justify-content: space-between; gap: var(--sp-xl); flex: 1; padding-inline: var(--sp-md); }
.facility-card__text { display: flex; flex-direction: column; gap: var(--sp-2xs); }
.facility-card__eyebrow { font-family: var(--f-body); font-size: var(--fs-body); color: var(--fc-text); }
.facility-card__title { font-family: var(--f-heading); font-weight: var(--fw-black); font-size: clamp(2rem, 2.8125vw, 3.375rem); line-height: .85; text-transform: uppercase; color: var(--fc-title); overflow-wrap: anywhere; }
.facility-card__desc { font-family: var(--f-body); font-size: var(--fs-body); line-height: 1.2; color: var(--fc-text); }
.facility-card__link { display: inline-flex; align-items: center; gap: var(--sp-xs); font-family: var(--f-heading); font-weight: var(--fw-black); font-size: var(--fs-link-sm); line-height: 1.1; text-transform: uppercase; color: var(--fc-title); }
.facility-card__link svg { height: 1.4em; width: auto; transition: transform var(--transition); }
.facility-card:hover .facility-card__link svg { transform: translateX(.3em); }
/* Linkless card (no facility page to point at yet) — Figma 2374-13396: the image
   absorbs ALL the free height (standard 370/204 ratio is its minimum) and the body
   hugs its text, so the text block ends right at the card's bottom padding. The
   title reserves two display lines so a one-line title (Spa & Sauna) doesn't buy
   its card a taller image — text blocks match ⇒ images stay uniform. */
.facility-card--no-link .facility-card__media { flex: 1 0 auto; }
.facility-card--no-link .facility-card__body  { flex: 0 0 auto; }
.facility-card--no-link .facility-card__title { min-height: 1.7em; }   /* 2 lines @ lh .85 */

/* ─── Navigation card / Card Block (Figma 1686-2057) — solid colour block, TEXT-ONLY
   (no image): big H4 title + subtitle + big (32px) LEARN MORE. For nav/section blocks.
   Colour via --nc-bg / --nc-fg. */
.nav-card {
    --nc-bg: var(--c-teal); --nc-fg: var(--c-green);
    display: flex; flex-direction: column; justify-content: space-between; gap: var(--sp-xl);
    padding: clamp(1.25rem, 1.5625vw, 1.875rem) clamp(1.5rem, 3.125vw, 3.75rem);  /* 30 vert · 60 horiz */
    min-height: clamp(220px, 16.5vw, 316px);
    border-radius: var(--r-card); background: var(--nc-bg); color: var(--nc-fg);
    text-decoration: none; transition: box-shadow var(--transition);
}
/* Hover (Figma 1686-2067): drop shadow + subtle darken overlay */
.nav-card:hover, .nav-card:focus-within { box-shadow: var(--sh-drop), inset 0 0 0 100vmax rgba(0,0,0,.08); }
.nav-card--blue      { --nc-bg: var(--c-blue);      --nc-fg: var(--c-white); }
.nav-card--green     { --nc-bg: var(--c-green);     --nc-fg: var(--c-white); }
.nav-card--sandstone { --nc-bg: var(--c-sandstone); --nc-fg: var(--c-green); }
.nav-card--gold      { --nc-bg: var(--c-gold);      --nc-fg: var(--c-terracotta); }
.nav-card__title { font-family: var(--f-heading); font-weight: var(--fw-black); font-size: var(--fs-h4); line-height: .8; text-transform: uppercase; color: var(--nc-fg); }
.nav-card__text  { font-family: var(--f-body); font-size: var(--fs-big-p); line-height: 1.2; color: var(--nc-fg); margin-top: var(--sp-md); }
.nav-card__link  { display: inline-flex; align-items: center; gap: var(--sp-xs); font-family: var(--f-heading); font-weight: var(--fw-black); font-size: var(--fs-link); line-height: 1; text-transform: uppercase; color: var(--nc-fg); text-decoration: none; }
.nav-card__link svg { height: 1em; width: auto; transition: transform var(--transition); }
.nav-card:hover .nav-card__link svg { transform: translateX(.3em); }

/* Icon variant (Figma 1919-10274/75) — horizontal: icon + eyebrow + big link. Blue
   by default; whole block is the link; hover adds a WHITE overlay + shadow (lightens). */
.nav-card--icon {
    --nc-bg: var(--c-blue); --nc-fg: var(--c-white);
    flex-direction: row; align-items: center; justify-content: flex-start; gap: var(--sp-lg);
    min-height: clamp(110px, 8.33vw, 160px);
}
.nav-card--icon:hover, .nav-card--icon:focus-within { box-shadow: var(--sh-drop), inset 0 0 0 100vmax rgba(255,255,255,.1); }
.nav-card__icon { flex: none; display: inline-flex; }
.nav-card__icon svg { width: clamp(48px, 4.17vw, 80px); height: auto; color: var(--nc-fg); }
.nav-card__col { display: flex; flex-direction: column; align-items: flex-start; gap: var(--sp-2xs); }
.nav-card__eyebrow { font-family: var(--f-body); font-size: var(--fs-body); color: var(--nc-fg); }

/* ─── What's On card (Figma 1694-4190) — horizontal news/event: date block + image + info */
.whats-on-card {
    display: flex; align-items: stretch;
    background: var(--c-white); border-radius: var(--r-card); overflow: hidden;
    transition: box-shadow var(--transition);
    /* One grid-column width (12/6/4 per breakpoint) — date + media size off this
       so the card reads as 2 cols (date) · 3 cols (media) · the rest (info). */
    --woc-col: calc((100vw - (2 * var(--sp-page-x)) - ((var(--grid-cols) - 1) * var(--gutter))) / var(--grid-cols));
}
/* .is-active mirrors :hover for touch (≤1023, no hover) — set by
   [data-center-active] in main.js when the row reaches the viewport centre. */
.whats-on-card:hover, .whats-on-card:focus-within, .whats-on-card.is-active { box-shadow: var(--sh-drop); }   /* shadow is part of the hover only */
.whats-on-card[hidden] { display: none; }   /* flex would otherwise beat [hidden] — used by the listing filter/pagination */
.whats-on-card__title a { color: inherit; text-decoration: none; }
.whats-on-card__date {
    flex: none; display: flex; flex-direction: column; justify-content: flex-end;
    width: calc(var(--woc-col) * 2 + var(--gutter)); padding: var(--sp-lg);   /* 2 cols */
    font-family: var(--f-heading); font-weight: var(--fw-black); font-size: clamp(3rem, 5.2vw, 6.25rem); line-height: .8; text-transform: uppercase;
    transition: background var(--transition);
}
.whats-on-card__date .d { display: block; color: var(--c-blue); transition: color var(--transition); }
.whats-on-card__date .m { display: block; color: var(--c-black); transition: color var(--transition); }
/* Hover (Figma 1694-4206): date block turns blue, all text white */
.whats-on-card:hover .whats-on-card__date, .whats-on-card:focus-within .whats-on-card__date, .whats-on-card.is-active .whats-on-card__date { background: var(--c-blue); }
.whats-on-card:hover .whats-on-card__date .d, .whats-on-card:hover .whats-on-card__date .m,
.whats-on-card:focus-within .whats-on-card__date .d, .whats-on-card:focus-within .whats-on-card__date .m,
.whats-on-card.is-active .whats-on-card__date .d, .whats-on-card.is-active .whats-on-card__date .m { color: var(--c-white); }
.whats-on-card__news { display: flex; align-items: center; gap: var(--sp-lg); padding: var(--sp-lg) var(--sp-xl); flex: 1; min-width: 0; }
.whats-on-card__media {
    flex: none;
    align-self: center;            /* keeps its ratio (not stretched to card height) */
    aspect-ratio: 3 / 2;
    width: calc(var(--woc-col) * 3 + var(--gutter) * 2);   /* 3 cols (kept inset by __news padding) */
    border-radius: var(--r-card); overflow: hidden;
}
.whats-on-card__media img { width: 100%; height: 100%; object-fit: cover; display: block; }
.whats-on-card__info { display: flex; flex-direction: column; justify-content: space-between; gap: var(--sp-md); flex: 1; min-width: 0; }
.whats-on-card__title { font-family: var(--f-heading); font-weight: var(--fw-black); font-size: clamp(2rem, 2.8125vw, 3.375rem); line-height: .85; text-transform: uppercase; color: var(--c-blue); margin-top: var(--sp-xs); }
.whats-on-card__excerpt { font-family: var(--f-body); font-size: var(--fs-body); line-height: 1.2; color: var(--c-black); margin-top: var(--sp-xs); }
.whats-on-card__link { display: inline-flex; align-items: center; gap: var(--sp-xs); font-family: var(--f-heading); font-weight: var(--fw-black); font-size: var(--fs-link-sm); line-height: 1.1; text-transform: uppercase; color: var(--c-blue); margin-top: var(--sp-md); }
.whats-on-card__link svg { height: 1.4em; width: auto; transition: transform var(--transition); }
.whats-on-card:hover .whats-on-card__link svg, .whats-on-card.is-active .whats-on-card__link svg { transform: translateX(.3em); }
/* Tablet (6-col grid): 2+3 cols would crush the info column to ~1 col and clip
   the title. Re-balance to date 1.5 · media 1.5 · info 3 so copy gets half. */
@media (min-width: 768px) and (max-width: 1023px) {
    .whats-on-card__date  { width: calc(var(--woc-col) * 1.5 + var(--gutter) * .5); font-size: clamp(2.5rem, 4.4vw, 3.75rem); }
    .whats-on-card__media { width: calc(var(--woc-col) * 1.5 + var(--gutter) * .5); }
}
@media (max-width: 767px) {
    .whats-on-card, .whats-on-card__news { flex-direction: column; align-items: stretch; }
    .whats-on-card__date { width: 100%; }
    .whats-on-card__media { width: 100%; aspect-ratio: 16/9; }
}

/* ─── News card (Figma 1694-5768) — vertical: image top + white body (date + small
   tag, blue 32px title, excerpt, READ MORE). */
.news-card { display: flex; flex-direction: column; background: var(--c-white); border-radius: var(--r-card); overflow: hidden; transition: box-shadow var(--transition); }
.news-card[hidden] { display: none; }   /* flex would otherwise beat [hidden] — used by the listing filter/pagination */
/* .is-active = centre-of-viewport state for touch carousels (no :hover) — set by
   [data-center-active] in main.js; mirrors the :hover lift + arrow nudge. */
.news-card:hover, .news-card:focus-within, .news-card.is-active { box-shadow: var(--sh-drop); }
.news-card__media { display: block; aspect-ratio: 544 / 300; overflow: hidden; }
.news-card__media img { width: 100%; height: 100%; object-fit: cover; display: block; }
.news-card__body { display: flex; flex-direction: column; justify-content: space-between; gap: var(--sp-lg); flex: 1; padding: clamp(1.25rem, 1.5625vw, 1.875rem) clamp(1.25rem, 2.08vw, 2.5rem); }
.news-card__text { display: flex; flex-direction: column; }   /* meta + title + excerpt group (top); READ MORE sits at the bottom via body's space-between */
.news-card__meta { display: flex; align-items: center; gap: var(--sp-md); flex-wrap: wrap; }
.news-card__date { font-family: var(--f-body); font-size: var(--fs-body); color: var(--c-black); transition: color var(--transition); }
.news-card.is-active .news-card__date { color: var(--c-blue); }   /* centre-of-viewport touch state (no :hover) */
.news-card__title { font-family: var(--f-heading); font-weight: var(--fw-black); font-size: var(--fs-link); line-height: 1; text-transform: uppercase; color: var(--c-blue); margin-top: var(--sp-md); }
.news-card__title a { color: inherit; text-decoration: none; }   /* clickable title → event; colour comes from the heading */
.news-card__excerpt { font-family: var(--f-body); font-size: var(--fs-body); line-height: 1.2; color: var(--c-black); margin-top: var(--sp-md); }
.news-card__link { display: inline-flex; align-items: center; gap: var(--sp-xs); font-family: var(--f-heading); font-weight: var(--fw-black); font-size: var(--fs-link-sm); line-height: 1.1; text-transform: uppercase; color: var(--c-blue); }
.news-card__link svg { height: 1.4em; width: auto; transition: transform var(--transition); }
.news-card:hover .news-card__link svg, .news-card.is-active .news-card__link svg { transform: translateX(.3em); }

/* ─── Price block (Figma 1686-8053) — sandstone membership pricing card. Built from
   existing pieces: .btn (Join Legend), a small link (Learn More), diamond-bullet list.
   Hover (Variant2): white 20% overlay + drop shadow. */
.price-block {
    display: flex; flex-direction: column; justify-content: space-between; gap: var(--sp-2xl-f);
    padding: max(1.875rem, 2.08vw) max(2.34375rem, 2.6vw);  /* 40 vert · 50 horiz @1920, 75% floors (--sp-*-f convention) */
    border-radius: var(--r-card); background: var(--c-sandstone); color: var(--c-black);
    transition: box-shadow var(--transition);
}
.price-block:hover, .price-block:focus-within { box-shadow: var(--sh-drop), inset 0 0 0 100vmax rgba(255,255,255,.2); }
.price-block__head { display: flex; flex-direction: column; gap: var(--sp-lg-f); }
.price-block__intro { display: flex; flex-direction: column; gap: var(--sp-xs); text-align: center; }
.price-block__eyebrow { font-family: var(--f-heading); font-weight: var(--fw-black); font-size: var(--fs-link); line-height: 1; text-transform: uppercase; color: var(--c-blue); }
.price-block__tagline { font-family: var(--f-body); font-size: var(--fs-body); line-height: 1.2; color: var(--c-black); }
/* Stacked price — big amount line, small qualifier lines above/below (From / $429,
   $65 / Week). Amount was clamp-capped at 7.5rem; now max() like the rest of the
   type scale (120px @1920, keeps scaling above). */
.price-block__price {
    display: flex; flex-direction: column; align-items: center; gap: var(--sp-xs);
    font-family: var(--f-heading); font-weight: var(--fw-black);
    text-transform: uppercase; color: var(--c-blue); text-align: center; margin: 0;
}
.price-block__price-amount { font-size: max(4rem, 6.25vw); line-height: .8; }
.price-block__price-small  { font-size: var(--fs-link); line-height: 1; }
.price-block__note { font-family: var(--f-body); font-size: var(--fs-body); line-height: 1.2; color: var(--c-black); text-align: center; max-width: 24ch; margin-inline: auto; }
.price-block__divider { border: 0; border-top: 1px solid var(--c-blue); width: 100%; margin: 0; }
/* Feature list — same metrics as the shared .icon-list--sm (28px diamond icon /
   --fs-body label / --sp-md gap) so every diamond-bullet list on the site reads
   identically. Bullet = the real diamond.svg via mask (was a rotated 1em square,
   whose 1.41× diagonal overlapped the gap and never matched the icon set). */
.price-block__list { display: flex; flex-direction: column; gap: var(--sp-md-f); }
.price-block__list li { display: flex; align-items: center; gap: var(--sp-md); font-family: var(--f-body); font-size: var(--fs-body); line-height: 1.2; color: var(--c-black); }
.price-block__list li::before {
    content: ""; flex: none;
    width: clamp(20px, 1.458vw, 28px); height: clamp(20px, 1.458vw, 28px);   /* = .icon-list--sm */
    background: var(--c-blue);
    -webkit-mask: url('components/../../icons/nsop/diamond.svg') center / contain no-repeat;
            mask: url('components/../../icons/nsop/diamond.svg') center / contain no-repeat;
}
.price-block__actions { display: flex; flex-direction: column; align-items: center; gap: var(--sp-sm); }
.price-block__actions .btn { width: 100%; white-space: normal; line-height: 1.1; }  /* full-width pill → let long labels wrap rather than clip */
.price-block__link { display: inline-flex; align-items: center; gap: var(--sp-xs); font-family: var(--f-heading); font-weight: var(--fw-black); font-size: var(--fs-link-sm); line-height: 1.1; text-transform: uppercase; color: var(--c-blue); text-decoration: none; }
.price-block__link svg { height: 1.4em; width: auto; transition: transform var(--transition); }
.price-block:hover .price-block__link svg { transform: translateX(.3em); }

/* Featured / highlighted tier (Figma 1686-8255) — blue fill, inverted palette:
   sandstone price + diamonds + Learn More, white copy, white Join button. Sits a
   touch taller than its neighbours so it "pops" out of a centre-aligned row. */
.price-block--featured {
    background: var(--c-blue); color: var(--c-white);
    padding-block: clamp(2rem, 2.86vw, 3.5rem);   /* ~48px taller total → protrudes */
}
.price-block--featured .price-block__eyebrow,
.price-block--featured .price-block__tagline,
.price-block--featured .price-block__note,
.price-block--featured .price-block__list li { color: var(--c-white); }
.price-block--featured .price-block__price,
.price-block--featured .price-block__link { color: var(--c-sandstone); }
.price-block--featured .price-block__divider { border-top-color: var(--c-sandstone); }
.price-block--featured .price-block__list li::before { background: var(--c-sandstone); }

/* ─── Accessibility card (Figma 1910-10255) — blue feature card: white circle icon
   badge + H5 title + big-p body + FULL DETAILS link. */
.accessibility-card {
    display: flex; flex-direction: column; justify-content: space-between; gap: var(--sp-2xl);
    padding: clamp(1.5rem, 1.5625vw, 1.875rem) clamp(1.5rem, 3.125vw, 3.75rem);  /* 30 vert · 60 horiz */
    border-radius: var(--r-card); background: var(--c-blue); color: var(--c-white);
    transition: box-shadow var(--transition);
}
.accessibility-card:hover, .accessibility-card:focus-within { box-shadow: var(--sh-drop); }
.accessibility-card__top { display: flex; flex-direction: column; align-items: flex-start; gap: var(--sp-fluid-lg); }
.accessibility-card__icon { width: clamp(96px, 7.8vw, 150px); height: auto; }
.accessibility-card__legend { display: flex; flex-direction: column; gap: var(--sp-md); }
.accessibility-card__title { font-family: var(--f-heading); font-weight: var(--fw-black); font-size: clamp(2rem, 2.8125vw, 3.375rem); line-height: .85; text-transform: uppercase; }
.accessibility-card__text { font-family: var(--f-body); font-size: var(--fs-big-p); line-height: 1.2; }
.accessibility-card__link { display: inline-flex; align-items: center; gap: var(--sp-xs); font-family: var(--f-heading); font-weight: var(--fw-black); font-size: var(--fs-link); line-height: 1; text-transform: uppercase; color: var(--c-white); text-decoration: none; }
.accessibility-card__link svg { height: 1em; width: auto; transition: transform var(--transition); }
.accessibility-card:hover .accessibility-card__link svg { transform: translateX(.3em); }

/* ─── Banners: promo (logo/graphic strip) + CTA (photo panel) ─────────────────
   Figma promo 2447-29787 · CTA 2215-17122. ONE model, two ratios:
     • promo — body 8 cols / media 4 cols; media is a CONTAINED graphic, inset to
       match the body padding (both padded equally → title + graphic align).
     • CTA   — body 5 cols / media 7 cols; media is a FULL-BLEED cover photo.
   Both RIDE the .container 12/6/4 grid via subgrid (grid is DevTools-inspectable,
   like every other section — NOT a flex ratio). Height is driven by the BODY
   content: media is absolutely positioned so it never sizes the row. Colour is set
   INLINE by the section (nsop_banner_color_style()): --bnr-bg band · --bnr-ink
   title/body/link. Editor picks background + text (auto|white|blue) + button
   freely; 'auto' text = white on brand bands, blue on sand, terracotta on gold. */

/* Section wrapper — standard section padding-block so it sits in the page rhythm. */
.promo-section { padding-block: var(--sp-section); background: var(--c-background); }

.promo-banner,
.cta-banner {
    --bnr-bg:  var(--c-blue);    /* band colour — overridden inline per instance */
    --bnr-ink: var(--c-white);   /* title/body/link — white by default (Figma)  */
    /* subgrid: reuse the container's 12/6/4 tracks + gutters — NOT a new grid. */
    grid-column: 1 / -1;
    display: grid;
    grid-template-columns: subgrid;
    align-items: stretch;        /* both cells fill the row (body sets the height) */
    border-radius: var(--r-card); overflow: hidden;
    background: var(--bnr-bg); color: var(--bnr-ink);
}
/* Column spans — explicit per item so the tracks are inspectable (12-col). */
.promo-banner__body  { grid-column: 1 / 9;  }   /* 8 of 12 */
.promo-banner__media { grid-column: 9 / -1; }   /* 4 of 12 */
.cta-banner__body    { grid-column: 1 / 6;  }   /* 5 of 12 */
.cta-banner__media   { grid-column: 6 / -1; }   /* 7 of 12 */

/* Body — a padded panel with equal inset on every side, so the title/button
   origin lines up with the top-left corner (shared by both banners). */
.promo-banner__body,
.cta-banner__body {
    display: flex; flex-direction: column; align-items: flex-start;
    gap: var(--sp-fluid-lg); padding: var(--sp-fluid-xl); min-width: 0;   /* copy → button gap (32–48px) */
}
.cta-banner__body { justify-content: space-between; }
/* Title + description grouped so the gap BETWEEN them (16px) is independent of the
   larger gap down to the button/link (the body gap above). */
.promo-banner__copy,
.cta-banner__copy { display: flex; flex-direction: column; align-items: flex-start; gap: var(--sp-md-f); min-width: 0; }
.promo-banner__body .btn,
.cta-banner__body .btn  { align-self: flex-start; }   /* hug content — NOT full width */
.promo-banner__body .link,
.cta-banner__body .link { color: currentColor; }       /* link follows the ink */

/* Shared banner typography — uppercase MD-Nichrome title + big-paragraph copy. */
.promo-banner__title,
.cta-banner__title {
    font-family: var(--f-heading); font-weight: var(--fw-black);
    font-size: var(--fs-h4); line-height: .8; text-transform: uppercase; color: currentColor;
}
.promo-banner__subtitle,
.cta-banner__text {
    margin: 0; font-family: var(--f-body); font-size: var(--fs-big-p);
    line-height: 1.2; color: currentColor;
}

/* Media — the cell stretches to the row (= body) height; the image is absolute so
   it fills the cell without ever dictating the height. */
.promo-banner__media,
.cta-banner__media { position: relative; min-width: 0; }

/* Promo media = contained graphic/logo. Kept absolutely positioned (so it never
   sizes the row — the body copy drives height); inset by --pb-media-pad, HALF the
   body padding by default so the graphic reads larger. Bump the var to shrink it. */
.promo-banner__media { --pb-media-pad: calc(var(--sp-fluid-xl) / 2); }
.promo-banner__media img { position: absolute; inset: var(--pb-media-pad); width: auto; height: auto; max-width: calc(100% - 2 * var(--pb-media-pad)); max-height: calc(100% - 2 * var(--pb-media-pad)); margin: auto; object-fit: contain; display: block; }

/* CTA media = full-bleed cover photo (no padding). */
.cta-banner__media img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block; }

/* Tablet (6-col grid) — keep both side-by-side, re-span to 6 tracks. */
@media (max-width: 1023px) {
    .promo-banner__body  { grid-column: 1 / 5;  }   /* 4 of 6 */
    .promo-banner__media { grid-column: 5 / -1; }   /* 2 of 6 */
    .cta-banner__body    { grid-column: 1 / 4;  }   /* 3 of 6 */
    .cta-banner__media   { grid-column: 4 / -1; }   /* 3 of 6 */
}
/* Mobile (4-col grid) — stack: body then media, each full width. */
@media (max-width: 767px) {
    .promo-banner__body,
    .promo-banner__media,
    .cta-banner__body,
    .cta-banner__media { grid-column: 1 / -1; }
    .promo-banner__media,
    .cta-banner__media { aspect-ratio: 16 / 9; }
}
      /* cards, banners, info blocks, image frames */

/* ── components/_media-grid.css ── */
/* =============================================================================
   NSOP — Media grid (1 / 2 / 3 image arrangements)
   Figma "Content" media (1593-26xx) — shared by text-media, news-content, etc.
   -----------------------------------------------------------------------------
     .media-grid--1  single image (4/3)
     .media-grid--2  two images side-by-side (4/5 each)
     .media-grid--3  one tall image + two stacked beside it (2×2, first spans both)
   Each item is a rounded, cover-cropped frame. Colour/gap are tokens.
   ============================================================================= */

.media-grid { display: grid; gap: var(--sp-md); width: 100%; }
.media-grid__item { border-radius: var(--r-card); overflow: hidden; background: var(--c-navy-10); }
.media-grid__item img { width: 100%; height: 100%; object-fit: cover; display: block; }

.media-grid--1 { grid-template-columns: 1fr; }
.media-grid--1 .media-grid__item { aspect-ratio: 4 / 3; }

.media-grid--2 { grid-template-columns: 1fr 1fr; }
.media-grid--2 .media-grid__item { aspect-ratio: 4 / 5; }

.media-grid--3 { grid-template-columns: 1fr 1fr; grid-auto-rows: 1fr; aspect-ratio: 1 / 1; }
.media-grid--3 .media-grid__item { height: 100%; }
.media-grid--3 .media-grid__item:first-child { grid-row: 1 / 3; }
 /* 1/2/3 image arrangements (text-media, news-content) */

/* ── components/_info-panel.css ── */
/* =============================================================================
   NSOP — Information panel  (Figma 1686-5070 "PROGRAM INFO BLOCK")
   -----------------------------------------------------------------------------
   The "at a glance" block that sits under a program, an event, or on the contact
   page: a coloured title bar + a grid of label/value cells (+ an optional CTA).
   One component, colour-themed per context via CSS custom properties:
     --ip-header  title-bar background
     --ip-cell    cell background
     --ip-label   cell label colour
   Variants:
     (default)          program — green bar / teal cells / green labels
     .info-panel--swim  swim school — blue bar (+ starfish) / sky cells / black labels
     .info-panel--event event detail — blue bar / sandstone cells / blue labels
     .info-panel--contact contact — blue bar / sandstone / blue labels + enquiry links
   Cell dividers are 2px gaps that reveal the page background (--c-background).
   Square outer corners by design (buttons inside stay pills, header image = 4px).
   ============================================================================= */

.info-panel {
    --ip-header: var(--c-green);
    --ip-cell:   var(--c-teal);
    --ip-label:  var(--c-green);
    display: flex; flex-direction: column; gap: 2px;
    background: var(--c-background); width: 100%; overflow: hidden;
}
.info-panel--swim    { --ip-header: var(--c-blue); --ip-cell: var(--c-sky);       --ip-label: var(--c-black); }
.info-panel--event   { --ip-header: var(--c-blue); --ip-cell: var(--c-sandstone); --ip-label: var(--c-blue); }
.info-panel--contact { --ip-header: var(--c-blue); --ip-cell: var(--c-white); --ip-label: var(--c-blue); }

/* ── Title bar ───────────────────────────────────────────────────────────────*/
.info-panel__header {
    display: flex; align-items: center; justify-content: center; gap: var(--sp-lg);
    padding: clamp(1.5rem, 2.08vw, 2.5rem);
    background: var(--ip-header);
}
.info-panel--swim .info-panel__header,
.info-panel--contact .info-panel__header { justify-content: flex-start; }
.info-panel__title {
    font-family: var(--f-heading); font-weight: var(--fw-black); font-size: var(--fs-h5);   /* H5 — 36px @1920, floor 22px */
    line-height: var(--lh-h5); text-transform: uppercase; color: var(--c-white); text-align: center;
}
.info-panel--swim .info-panel__title,
.info-panel--contact .info-panel__title { text-align: left; }
.info-panel__header-graphic { flex: none; width: max(72px, 7.14vw); height: auto; border-radius: var(--r-card); } /* 137px @1920 (Figma 2374-20451) */

/* ── Grid of label / value cells ─────────────────────────────────────────────*/
.info-panel__grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 2px; }
.info-panel__cell {
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap: var(--sp-xs); text-align: center;
    padding: clamp(1.75rem, 3vw, 3.125rem) clamp(1rem, 1.56vw, 1.875rem);
    background: var(--ip-cell);
}
.info-panel__cell--full { grid-column: 1 / -1; }
.info-panel__label { font-family: var(--f-heading); font-weight: var(--fw-black); font-size: var(--fs-link); line-height: 1; text-transform: uppercase; color: var(--ip-label); }
.info-panel__value { font-family: var(--f-body); font-size: var(--fs-body); line-height: 1.2; color: var(--c-black); }

/* ── Contact variant — left-aligned rich-text cells ─────────────────────────*/
.info-panel__cell--text { align-items: flex-start; text-align: left; gap: var(--sp-md);
    padding: clamp(1.5rem, 2.6vw, 3.125rem) clamp(1.5rem, 3.125vw, 3.75rem); }
.info-panel__cell--text p { font-family: var(--f-body); font-size: var(--fs-body); line-height: 1.2; color: var(--c-black); }
.info-panel__cell--text p b, .info-panel__cell--text p strong { font-family: var(--f-heading); font-weight: var(--fw-black); }
.info-panel__enquiry-label { font-family: var(--f-body); font-size: var(--fs-body); color: var(--c-black); }
.info-panel__links { display: flex; flex-direction: column; gap: var(--sp-sm); }
.info-panel__link { display: inline-flex; align-items: center; gap: var(--sp-xs); font-family: var(--f-heading); font-weight: var(--fw-black); font-size: var(--fs-link-sm); line-height: 1.1; text-transform: uppercase; color: var(--c-blue); text-decoration: none; }
.info-panel__link svg { height: 1.4em; width: auto; transition: transform var(--transition); }
.info-panel__link:hover svg { transform: translateX(.3em); }
.info-panel__note { font-family: var(--f-body); font-size: var(--fs-ui); line-height: 1.15; color: var(--c-black); }

@media (max-width: 600px) {
    .info-panel__grid { grid-template-columns: 1fr; }
    .info-panel--swim .info-panel__header,
    .info-panel--contact .info-panel__header { justify-content: center; }
    .info-panel--swim .info-panel__title { text-align: center; }
}
 /* program / event / contact info panel */

/* ── Layout ──────────────────────────────────────────────────────────────────*/

/* ── layout/_header.css ── */
/* =============================================================================
   ⚠️ AUDIT TODO (2026-07-02): the colour-adaptive nav/logo + the L2 "cutout"
   porthole (mask hole in the blue bar) are shipped but not yet audited for
   a11y contrast (e.g. green/blue wordmark over the blue bar edge), Safari mask
   support, and behaviour when there is no lead hero. Revisit in the QA pass.
   -----------------------------------------------------------------------------
   NORTH SYDNEY OLYMPIC POOL — Site header (3 levels + protruding logo)
   -----------------------------------------------------------------------------
   L1  .nsop-notif   Figma 1593-2156  terracotta notification bar (dismissible)
   L2  utility row   Figma 1593-1887  blue, 70px, LISTEN + email | phone…JOIN NOW
   L3  nav row       Figma 1371-2551  blue, 90px, GYM SWIM KIDS | FACILITY…

   The logo is a blue circle (150px) — same method as the footer badge — pinned
   to the horizontal centre, starting at L2's 16px top padding and protruding
   down through the nav; the L2/L3 content groups flank it (justify-between).
   Token-driven. The row heights / L2 padding are rem-FIXED as the ≤1023 base
   (the settled mobile geometry hangs off --hd-l2-h) and go max(rem, vw) fluid
   ≥1024 — see the desktop media block — so the bar thins with the vw type
   scale instead of staying 162px tall while everything in it shrinks.
   ============================================================================= */

:root {
    --hd-nav-h:  5.625rem;   /* 90px  — L3 nav row height */
    /* How far the lead hero slides up behind the header so its background fills
       the porthole cutout. main.js measures the FULL header (L1 notif + L2 + L3)
       and overrides this — covering the strip behind L1 too, so a fast scroll
       direction-flip (header mid transform-transition) never exposes bare page
       background as a gap. This static value is only the pre-JS fallback
       (8.334vw = L2+L3 @1920, 160px floor); pre-JS there's no sticky choreography
       so bar-only coverage is enough. Over-pulling is safe: the surplus hides
       behind the opaque L1/L2 bars and the hero CONTENT never moves
       (margin-top:-pullup / padding-top:+pullup cancel). */
    --hd-pullup: max(10rem, 8.334vw);
    /* Logo diameter rides the grid like the footer badge (Option B): N columns
       wide, one column = (100vw − 2·page-x − (cols−1)·gutter) / cols. 1.5 cols on
       desktop/tablet, 1 col on mobile (≤767) — so it matches --ft-logo at every
       width. Fluid because a column is a vw value. On :root (not .nsop-header):
       the lead hero also reads --hd-logo/--hd-l2-h for its ≤1023 logo-clearance
       padding (the hero is not a header descendant). */
    --hd-col: calc((100vw - (2 * var(--sp-page-x)) - ((var(--grid-cols) - 1) * var(--gutter))) / var(--grid-cols));
    /* 1.25 cols desktop AND tablet (tablet dropped from 1.5 — client 2026-07-09,
       "not this big"); 1 col ≤767 below. Matches --ft-logo in _footer.css. */
    --hd-logo-cols: 1.25;
    --hd-logo: calc(var(--hd-col) * var(--hd-logo-cols) + (var(--hd-logo-cols) - 1) * var(--gutter));
    --hd-l2-h:  4.375rem;    /* 70px  — L2 utility row height (min) */
}

.nsop-header {
    --hd-pad-y: var(--sp-md);/* 16px  — L2 top/bottom padding */
    --hd-fg:    var(--c-black); /* nav + logo colour — overridden per page by main.js from the lead hero */
    /* Sticky: offset up by the notification height (--hd-stick, set by main.js)
       so L1 scrolls above the viewport and L2+L3 stick to the top. */
    position: sticky;
    top: var(--hd-stick, 0px);
    z-index: 100;            /* above page content + the hero sliding up beneath */
    font-family: var(--f-body);
    transition: transform var(--transition);
}
/* Hide on scroll-down / slide back in on scroll-up (main.js toggles .is-hidden). */
.nsop-header.is-hidden { transform: translateY(-100%); }

/* Solid state — once L2+L3 stick to the top (L1 has scrolled away). L2 (utility)
   stays blue and the porthole cutout fills in. BASE (all widths / no-band pages /
   pre-JS): a blue bar with sandstone nav + logo — the safe, legible default that
   mobile keeps. DESKTOP overrides below make L3 + the logo adopt the page's band. */
.nsop-header.scrolled .nsop-header__navlink,
.nsop-header.scrolled .nsop-header__logo { color: var(--c-sandstone); }
.nsop-header.scrolled .nsop-header__bar {
    background: var(--c-blue);
    box-shadow: 0 .25rem .75rem rgba(0, 0, 0, .18);
}
.nsop-header.scrolled .nsop-header__utility::before { -webkit-mask: none; mask: none; }
/* Solid disc behind the wordmark (the logo protrudes below the bar). */
.nsop-header.scrolled .nsop-header__logo { background: var(--c-blue); border-radius: 50%; }

/* Desktop: the sticky L3 (nav row) + the logo disc ADOPT the page's lead-hero
   band colour (--hd-band) with its paired ink (--hd-band-ink) — set by main.js,
   mirroring the footer banner — instead of a fixed blue. So a sandstone-hero page
   gives a sandstone L3 (blue links), a teal-hero page a teal L3 (green links),
   etc. L2 stays blue (bar base). No brand band → WHITE L3 + black text (client
   2026-07-07: blue+sandstone isn't an approved combination; white is fine as
   header chrome — the no-white rule is for section bands/page bg). Mobile is
   untouched (keeps the blue base + white logo ≤1023). */
@media (min-width: 1024px) {
    /* (Top-of-page logo cols now come from the 1.25 :root base above — desktop
       and tablet equal since 2026-07-09; the sticky redeclare below still needs
       its own --hd-logo for the min() bar-height cap.) */

    /* Row heights + L2 padding go FLUID on desktop (client 2026-07-09): same
       max(rem floor, vw) pattern as the type scale, so the bar thins in step
       with its shrinking content instead of holding the fixed 1920 heights
       (72+90 = a 162px bar around 25%-smaller text at 1264 — read as a gap).
       @1920 all three resolve to their old values (90 / 70 / 16), so nothing
       changes at full size; floors keep 1024 comfortable (pill min-height
       2.5rem is the real L2 floor). ≤1023 keeps the rem-fixed base — the
       mobile bar/logo/burger/hero-clearance geometry is all derived from
       --hd-l2-h and is settled. Everything downstream (porthole --hd-hole-cy,
       logo top, sticky min() cap, JS pull-up) is var-driven → recomputes. */
    :root {
        --hd-nav-h: max(4rem, 4.6875vw);      /* 90px @1920, floor 64px */
        --hd-l2-h:  max(3.25rem, 3.646vw);    /* 70px @1920, floor 52px (min-height) */
    }
    .nsop-header { --hd-pad-y: max(0.625rem, 0.8333vw); }   /* 16px @1920, floor 10px */

    /* No bar-level fill on desktop: the base .scrolled rule paints the WHOLE bar
       blue with a background transition, and the L3 band + logo disc sit on top —
       mid-fade the blue blends through (a split-second "default colour" flash on
       stick/unstick). Kill the layer instead: L2 is already blue via its own
       ::before, L3 below gets the band — nothing underneath to flash. */
    .nsop-header.scrolled .nsop-header__bar { background: transparent; }
    .nsop-header.scrolled .nsop-header__nav { background: var(--hd-band, var(--c-white)); }
    .nsop-header.scrolled .nsop-header__navlink,
    .nsop-header.scrolled .nsop-header__logo { color: var(--hd-band-ink, var(--c-black)); }
    .nsop-header.scrolled .nsop-header__logo { background: var(--hd-band, var(--c-white)); }
    /* Sticky logo: NO protrusion below the bar — recentred on the WHOLE bar
       (L2 + L3; top:50% of .nsop-header__bar) and stepped down 1.5 → 1.25 cols
       (~153px @1920 vs the 160px bar) so it sits inside without going small.
       --hd-logo must be REDECLARED here (a custom prop resolves where it's
       declared — :root — so overriding just --hd-logo-cols wouldn't cascade).
       min() caps at the bar height for ultra-wide screens (bar is rem-fixed,
       the logo vw-grows). Move + resize animate via the base .45s --e-outQuart. */
    .nsop-header.scrolled {
        --hd-logo-cols: 1.25;
        --hd-logo: min(calc(var(--hd-col) * var(--hd-logo-cols) + (var(--hd-logo-cols) - 1) * var(--gutter)),
                       calc(var(--hd-l2-h) + var(--hd-nav-h)));
    }
    .nsop-header.scrolled .nsop-header__logo {
        top: 50%;
        transform: translate(-50%, -50%);
    }
}

/* ── L1 · Notification(s) — terracotta, dismissible, rotating when >1 ─────────
   Rides the site 12/6/4 grid (like every band). The message spans the FULL width
   and stays centred; only the controls cell (dots + close) is pinned to the LAST
   column, hard-right. Rotation SLIDES horizontally, and a terracotta gradient at
   each edge dissolves the moving text into the bar (esp. under the controls) so
   it reveals/hides softly instead of a hard clip. */
.nsop-notif {
    position: relative;
    display: grid;
    grid-template-columns: repeat(var(--grid-cols), 1fr);
    column-gap: var(--gutter);
    align-items: center;
    padding-inline: var(--sp-page-x);
    background: var(--c-terracotta); color: var(--c-white);
    overflow: hidden;
}
.nsop-notif[hidden] { display: none; }

/* Message — full width, centred; messages stack in one cell for the slide. */
.nsop-notif__viewport {
    grid-column: 1 / -1;
    grid-row: 1;
    min-width: 0;
    display: grid;
    overflow: hidden;
}
.nsop-notif__inner {
    grid-area: 1 / 1;
    display: flex; flex-wrap: wrap; align-items: center; justify-content: center;
    gap: var(--sp-xs);
    padding-block: var(--sp-md);
    /* Symmetric reserve for the controls (dots + close) so the CENTRED message
       never sits under them at rest — the slide/gradient still handles motion. */
    padding-inline: 5rem;
    min-height: 3.5rem;
}
/* Rotation: messages stack in one grid cell and slide horizontally — the old
   one swipes out to the left (inCirc, accelerate away), the new one slides in
   from the right and settles (outCirc). */
.nsop-notif[data-notif-rotate] .nsop-notif__inner {
    opacity: 0; visibility: hidden; transform: translateX(100%);
    transition: opacity .55s var(--e-outCirc), transform .55s var(--e-outCirc), visibility 0s linear .55s;
}
.nsop-notif[data-notif-rotate] .nsop-notif__inner.is-active {
    opacity: 1; visibility: visible; transform: translateX(0);
    transition: opacity .45s var(--e-outCirc) .1s, transform .55s var(--e-outCirc);
}
.nsop-notif[data-notif-rotate] .nsop-notif__inner.is-leaving {
    opacity: 0; visibility: visible; transform: translateX(-100%);
    transition: opacity .35s var(--e-inCirc), transform .55s var(--e-inCirc);
}
@media (prefers-reduced-motion: reduce) {
    .nsop-notif[data-notif-rotate] .nsop-notif__inner,
    .nsop-notif[data-notif-rotate] .nsop-notif__inner.is-active,
    .nsop-notif[data-notif-rotate] .nsop-notif__inner.is-leaving { transition: none; transform: none; }
}

/* Edge gradients — the moving message fades into the terracotta at both ends;
   the right one is wider so text dissolves before it reaches the dots/close. */
.nsop-notif::before,
.nsop-notif::after {
    content: ""; position: absolute; top: 0; bottom: 0; z-index: 1;
    pointer-events: none;
}
.nsop-notif::before {
    left: 0; width: max(3rem, var(--sp-page-x));
    background: linear-gradient(to right, var(--c-terracotta), transparent);
}
.nsop-notif::after {
    right: 0; width: calc(var(--sp-page-x) + 4rem);
    background: linear-gradient(to left, var(--c-terracotta) 45%, transparent);
}
.nsop-notif__link {
    color: var(--c-white); font-weight: var(--fw-bold); text-decoration: underline;
    text-underline-offset: 2px; white-space: nowrap;
}
.nsop-notif__link:hover { color: var(--c-gold); }
.nsop-notif__msg {
    display: inline-flex; flex-wrap: wrap; align-items: center; justify-content: center;
    gap: var(--sp-xs);
    font-size: var(--fs-body); line-height: 1.2; text-align: center;
}
.nsop-notif__icon { flex: none; display: inline-grid; place-items: center; width: 2rem; height: 2rem; color: var(--c-gold); }
.nsop-notif__icon svg { width: 100%; height: 100%; }
/* Controls cell — last grid column, hard-right (dots then close). Its content
   width can exceed one column; justify-self:end pins the right edge to the last
   column's right edge (= page margin) so the close icon lands there on every
   breakpoint, incl. mobile. */
.nsop-notif__controls {
    grid-column: -2 / -1;
    grid-row: 1;
    justify-self: end;
    position: relative; z-index: 2;   /* above the edge gradient */
    display: flex; align-items: center; gap: var(--sp-md);
}
.nsop-notif__close {
    flex: none;
    display: grid; place-items: center; width: 2rem; height: 2rem;
    background: none; border: 0; cursor: pointer; color: var(--c-white);
}
.nsop-notif__close svg { width: 1.4rem; height: 1.4rem; }
.nsop-notif__close:hover { opacity: .8; }
/* Dot switcher — sits just left of the close button; reuses .pagination__dot,
   themed for the terracotta bar (translucent white → solid gold active). */
.nsop-notif__dots {
    flex: none;
    --pg-accent: var(--c-gold);
}
.nsop-notif__dot { background: rgba(255, 255, 255, .45); }
.nsop-notif__dot:hover { background: rgba(255, 255, 255, .75); }
.nsop-notif__dot.is-active { background: var(--c-gold); }
@media (max-width: 767px) {
    .nsop-notif__dots { display: none; }
    /* Only the close is left on mobile → less clearance + a narrower right fade,
       so the resting message (incl. the "Enrol now" link) stays readable. */
    .nsop-notif__inner { padding-inline: 2.75rem; }
    .nsop-notif::after  { width: calc(var(--sp-page-x) + 2rem); }
    .nsop-notif::before { width: var(--sp-page-x); }
}

/* ── L2 + L3 · The flanking content groups (L2 blue; L3 transparent) ──────────
   The bar itself is transparent — only the L2 utility row carries the blue
   background. L3 (nav) is transparent so the hero behind it shows through. */
.nsop-header__bar { position: relative; transition: background var(--transition), box-shadow var(--transition); }

/* Both rows ride the site 12/6/4 grid (client grid rule) on the 5+2+5 model:
   the two side groups are grid items — left = cols 1–5, right = cols 8–12 —
   and the CENTRE TWO COLUMNS (6–7) are reserved for the protruding logo
   (2 cols + 3 gutters ≈ 1.6× the 1.25-col logo → clearance that scales with
   the grid). Content inside each group is anchored flex from the outer margin
   (client 2026-07-09). */
.nsop-header__utility,
.nsop-header__nav {
    display: grid;
    grid-template-columns: repeat(var(--grid-cols), 1fr);
    column-gap: var(--gutter);
    align-items: center;
    padding-inline: var(--sp-page-x);
}
.nsop-header__utility { position: relative; min-height: var(--hd-l2-h); padding-block: var(--hd-pad-y); color: var(--c-white); }  /* 70px, blue via ::before */
.nsop-header__nav     { min-height: var(--hd-nav-h); }                           /* 90px, transparent */

/* Blue L2 fill as a masked layer: a circular hole is cut where the logo sits,
   so the hero (pulled up behind BOTH rows) shows through — the "cutout"
   porthole. Solid-colour heroes reveal their colour; image heroes reveal the
   continued photo, masking away the blue over that disc. Masking a ::before
   (not the row itself) leaves the utility text/pills unclipped. */
.nsop-header__utility::before {
    content: "";
    position: absolute; inset: 0; z-index: -1;
    background: var(--c-blue);
    --hd-hole-r:  calc(var(--hd-logo) / 2);                     /* logo radius */
    --hd-hole-cy: calc(var(--hd-pad-y) + var(--hd-logo) / 2);   /* logo centre, from the row top */
    -webkit-mask: radial-gradient(circle at 50% var(--hd-hole-cy), transparent 0 var(--hd-hole-r), #000 calc(var(--hd-hole-r) + 1px));
            mask: radial-gradient(circle at 50% var(--hd-hole-cy), transparent 0 var(--hd-hole-r), #000 calc(var(--hd-hole-r) + 1px));
}

/* Content groups either side of the centred logo — grid items on the row grid. */
.nsop-header__side { display: flex; align-items: center; gap: var(--sp-lg); grid-row: 1; min-width: 0; }
/* 5+2+5: left group anchors to col 1's left edge, right group to col 12's right
   edge (same anchors as the hero content and footer bottom row); cols 6–7 stay
   clear for the logo. (On the 6-/4-col grids ≤1023 the left span is re-set to
   1/-1 below; the right group + nav are hidden there.) */
.nsop-header__side--left  { grid-column: 1 / 6;  justify-content: flex-start; }   /* cols 1–5 on 12-col */
.nsop-header__side--right { grid-column: 8 / -1; justify-content: flex-end; }     /* cols 8–12 on 12-col */

/* ── L3 nav: anchored flex, NOT per-column snapping (client 2026-07-09) ────────
   Items are deliberately not snapped to individual tracks: a label wider than
   one column (MEMBERSHIP ≈ 1.5 cols) overflows a fixed track unpredictably —
   centred it spills past the page margin. Instead each side is a flex row
   anchored at its outer margin (left group grows rightward from col 1, right
   group grows leftward from col 12) with ONE consistent, grid-scaled gap
   between items (half a column + a gutter), so the rhythm stays even and wide
   labels simply take the room they need on the logo side, where the reserved
   centre absorbs them. Nav renders ≥1024 only; mega-menu panel is absolute →
   unaffected by the item layout. */
.nsop-header__nav .nsop-header__side { gap: calc(0.5 * var(--hd-col) + var(--gutter)); }
.nsop-header__nav .nsop-nav-item { flex: none; display: flex; align-items: center; }
.nsop-header__nav .nsop-header__navlink { white-space: nowrap; }

/* Utility text + icon links */
.nsop-header__contact { display: inline-flex; align-items: center; gap: var(--sp-xs); color: var(--c-white); text-decoration: none; font-size: var(--fs-body); line-height: 1.2; }
.nsop-header__contact:hover { opacity: .85; }
.nsop-header__ico { flex: none; display: inline-grid; place-items: center; width: 2rem; height: 2rem; }
.nsop-header__ico svg { width: 100%; height: 100%; }
.nsop-header__link { color: var(--c-white); text-decoration: none; font-size: var(--fs-body); line-height: 1.2; padding: var(--sp-md); }
.nsop-header__link:hover { opacity: .85; }
/* Customer portal — MOBILE / TABLET ONLY (≤1023). Hidden on desktop; shown on
   the left of the closed mobile bar (see the ≤1023 block below). */
.nsop-header__link--portal { display: none; }

/* White pill buttons (LISTEN / JOIN NOW): white bg, blue MD Nichrome */
.nsop-header__pill {
    display: inline-flex; align-items: center; justify-content: center; gap: var(--sp-xs);
    padding: var(--sp-xs) var(--sp-xl);
    min-height: 2.5rem;                       /* 40px */
    background: var(--c-white); color: var(--c-blue);
    border: 0; border-radius: var(--r-pill);
    font-family: var(--f-heading); font-weight: var(--fw-black); font-size: var(--fs-link-sm); line-height: 1.1;
    text-transform: uppercase; text-decoration: none; white-space: nowrap; cursor: pointer;
    transition: box-shadow var(--transition);
}
.nsop-header__pill:hover { box-shadow: inset 0 0 0 100vmax var(--c-navy-05); }
.nsop-header__pill svg { width: 1.5rem; height: 1.5rem; }

/* ── Desktop fit ladder (≥1024) — keep L2 clear of the centred logo ────────────
   The reserved centre can't do it alone: columns shrink linearly with vw but the
   utility text has a 1rem floor, so once the floor kicks in (≤1536) fixed-size
   content grows RELATIVE to its shrinking 5-column half until it reaches the
   logo. The grid stays put; the CONTENT adapts in two steps (width budgets in
   desktop-header-logic.md, "Desktop fit ladder").
   L3 nav type scales purely with the viewport instead — NO rem floor (nav only
   renders ≥1024, worst case ~15px @1024): labels + gaps keep the same proportion
   to the grid at every width, so the nav never needs a ladder step. Scoped
   .nsop-header__nav so it beats the base --fs-link rule below (cascade order). */
@media (min-width: 1024px) {
    .nsop-header__nav .nsop-header__navlink { font-size: 1.4583vw; }
}
/* The compact states are MEASURED, not breakpointed (client 2026-07-09): fixed
   media queries were guesses at content widths that change with ACF labels and
   font metrics. main.js measures each L2 side group — natural content width vs
   its 5-col box — and steps ONLY the overflowing side down, re-checked on
   resize + font load (inside rAF, before paint → no flicker):
     .is-compact   — contact text → icon-only (clipped, NOT display:none, so the
                     accessible name survives and the icon always stays), link
                     padding + gaps tighten one step.
     .is-compact-2 — still overflowing → type steps to .875rem and pills slim
                     (pills scale, they are NEVER hidden).
   Scoped ≥1024: the ≤1023 bar has its own design (portal · logo · MENU). */
@media (min-width: 1024px) {
    .nsop-header__side.is-compact .nsop-header__contact span:not(.nsop-header__ico) {
        position: absolute; width: 1px; height: 1px;
        overflow: hidden; clip-path: inset(50%); white-space: nowrap;
    }
    .nsop-header__side.is-compact { gap: var(--sp-md); }
    .nsop-header__side.is-compact .nsop-header__link { padding: var(--sp-xs); }
    .nsop-header__side.is-compact-2 { gap: var(--sp-sm); }
    .nsop-header__side.is-compact-2 .nsop-header__link,
    .nsop-header__side.is-compact-2 .nsop-header__contact { font-size: 0.875rem; }
    .nsop-header__side.is-compact-2 .nsop-header__pill { font-size: 0.875rem; padding-inline: var(--sp-lg); }
}

/* Nav links (L3) — MD Nichrome Black, white, uppercase */
.nsop-header__navlink {
    display: inline-flex; align-items: center;
    font-family: var(--f-heading); font-weight: var(--fw-black); font-size: var(--fs-link); line-height: 1;
    text-transform: uppercase; color: var(--hd-fg); text-decoration: none;
    padding-block: var(--sp-xs);
    transition: opacity var(--transition), color var(--transition);
}
.nsop-header__navlink:hover,
.nsop-header__navlink[aria-current="page"] { opacity: .8; }

/* ── Logo — transparent circle, wordmark recolours per page, pinned centre ───
   No disc fill: the wordmark sits directly over the hero, taking the same
   colour (--hd-fg) as the nav. Inlined SVG so `color` drives its fill. */
.nsop-header__logo {
    position: absolute; left: 50%; top: var(--hd-pad-y); transform: translateX(-50%);
    z-index: 5;
    display: grid; place-items: center;
    width: var(--hd-logo); height: var(--hd-logo);
    color: var(--hd-fg);
    /* Always a circle: the disc bg is only PAINTED in scrolled/open states, but
       the radius must not snap to square while that bg is still fading out. */
    border-radius: 50%;
    /* Background dissolves FAST (.12s) — leaving the scrolled state, the blue
       disc must be gone before the grow-back animation reads; the geometry
       (top/size) then settles on the brand outQuart curve, slightly longer than
       the default so the shrink/grow feels fluid rather than mechanical. */
    transition: color var(--transition), background .12s linear, opacity var(--transition),
                top .45s var(--e-outQuart), width .45s var(--e-outQuart),
                height .45s var(--e-outQuart), transform .45s var(--e-outQuart);
}
.nsop-header__logo-svg { width: 100%; height: auto; display: block; }

/* ── Leading hero overlap ────────────────────────────────────────────────────
   The page's first hero slides up behind BOTH the transparent nav AND the
   masked L2 bar (negative margin) and pads its content back down, so the
   hero's own background colour / image shows through the transparent nav and
   the circular hole in the L2 blue — the logo reads as a cutout of the hero.
   main.js reads that hero's title colour and sets --hd-fg so the nav + logo
   wordmark match it. */
.site-main > .page-hero:first-child {
    position: relative;
    z-index: 1;
    margin-top: calc(-1 * var(--hd-pullup));
    padding-top: var(--hd-pullup);
}

/* ── Responsive ───────────────────────────────────────────────────────────────
   ≤1023 the header collapses to a slim blue L2 strip: centred protruding logo
   + burger only. The utility links/contact/CTA and the whole nav move into the
   full-screen mobile overlay (.nsop-mnav, layout/_mnav.css). */
@media (max-width: 1023px) {
    /* Closed mobile/tablet bar = Customer portal (left) · logo · MENU burger (right).
       Keep the blue bar (backs the logo porthole); show ONLY the portal link on the
       left — Listen / email + the whole right group live in the overlay instead. */
    .nsop-header__utility .nsop-header__side--right { display: none; }
    /* Collapsed bar: the left group (just the portal link now) spans the row. */
    .nsop-header__side--left { grid-column: 1 / -1; }
    .nsop-header__side--left > .nsop-header__pill,
    .nsop-header__side--left > .nsop-header__contact { display: none; }
    .nsop-header__link--portal { display: inline-block; padding: 0; }
    /* Burger sits on the blue L2 bar → ALWAYS white, it never adopts the page's
       hero ink (--hd-fg). Extra .nsop-header ancestor so this beats the later
       _megamenu.css `color: var(--hd-fg)` base rule in the cascade. */
    .nsop-header .nsop-header__burger { color: var(--c-white); }

    /* Logo pushed LOWER on mobile: 75% of the circle protrudes below the bar's
       bottom border (25% stays inside the blue L2). Top-anchored to the L2 height
       so it holds in every state (closed / open / scrolled). Only the wordmark
       COLOUR ever changes (--hd-fg / white) — the background behind it is
       whatever the section underneath provides (porthole cutout, no disc). */
    .nsop-header__logo { top: calc(var(--hd-l2-h) - 0.25 * var(--hd-logo)); }
    /* Porthole hole tracks the moved logo: its centre now sits 0.25·logo BELOW
       the L2 bottom edge (the mask still clips the arc that overlaps the bar). */
    .nsop-header__utility::before { --hd-hole-cy: calc(var(--hd-l2-h) + 0.25 * var(--hd-logo)); }

    /* Sticky reappear (scroll up → solid blue bar): NO push-down — the logo
       shrinks to sit INSIDE the L2 utility strip, white wordmark centred on the
       blue bar. (:not(.is-nav-open): opening the menu restores the big
       straddling logo.) */
    .nsop-header.scrolled:not(.is-nav-open) .nsop-header__logo {
        color: var(--c-white);
        top: 50%;
        transform: translate(-50%, -50%);
        width: calc(var(--hd-l2-h) - var(--sp-md));
        height: calc(var(--hd-l2-h) - var(--sp-md));
    }

    /* Scroll-down hide: safety fade — mid-transition (big logo shrinking while
       the bar slides away) it can still poke below the bar. */
    .nsop-header.is-hidden .nsop-header__logo { opacity: 0; }

    /* Lead hero: reserve room for the protruding logo so hero content (breadcrumb
       / H1) never sits under it. The logo hangs 0.75·logo BELOW the bar, and
       --hd-pullup (measured header height = L1 notif + L2 bar) does NOT include
       that protrusion — so clearance = full header + protrusion + breathing, i.e.
       pullup ADDED to the logo overhang, not max()'d against it. (The old max()
       let a tall notification's pullup win and win the logo clearance away → the
       logo overlapped the hero top; worse on shorter-inner variants like cta.)
       pullup + positive is always ≥ pullup, so the margin/padding pair still
       cancels (content never pulls above the header). */
    .site-main > .page-hero:first-child {
        padding-top: calc(var(--hd-pullup) + 0.75 * var(--hd-logo) + var(--sp-2xl));
    }

    /* ── OPEN state (burger tapped) — ONE header chrome, recoloured ────────────
       Rather than a second white strip + logo in the overlay, the real L2 + L3 +
       protruding logo stay put and flip colour; the accordion drawer (.nsop-mnav)
       drops in below L3. The header pins to the top and the notification hides so
       the white L2 is the topmost row (matches the mobile comp). */
    .nsop-header.is-nav-open {
        position: fixed; top: 0; left: 0; right: 0;
        /* Drawer-scrolled compact sizes — GRID-aligned like every logo size:
           small logo = 0.75 col (the mobile FULL logo is already 1 col, so 1 col
           here would be no shrink at all on phones). */
        --hd-logo-sm:  calc(var(--hd-col) * 0.75);
        --hd-nav-h-sm: calc(var(--hd-logo-sm) / 2 + var(--sp-lg));
    }
    /* Logo wordmark reads white on its blue disc. --hd-fg is set inline per page
       (which beats a stylesheet var override) so set the logo colour directly. */
    .nsop-header.is-nav-open .nsop-header__logo { color: var(--c-white); }
    .nsop-header.is-nav-open .nsop-notif { display: none; }
    /* Bar (L2 + L3 + logo + burger) sits above the drawer backdrop. No shadow —
       the .scrolled drop-shadow reads as a crease across the seamless blue. */
    .nsop-header.is-nav-open .nsop-header__bar { position: relative; z-index: 2; box-shadow: none; }

    /* L2 → white bar; its links (Customer portal) + the burger flip to blue. */
    .nsop-header.is-nav-open .nsop-header__utility::before { background: var(--c-white); -webkit-mask: none; mask: none; }
    .nsop-header.is-nav-open .nsop-header__link--portal { color: var(--c-blue); }
    /* Burger centres on the whole bar (top:50%); once open the bar is L2+L3, so
       keep the blue Close "X" pinned to the white L2 row (its centre) — otherwise
       it lands on the blue L3 band and reads blue-on-blue (invisible). */
    .nsop-header.is-nav-open .nsop-header__burger { color: var(--c-blue); top: calc(var(--hd-l2-h) / 2); }

    /* L3 → shown as a solid blue band (its horizontal nav stays hidden; the band
       just gives the protruding logo its blue backdrop, like the comp). */
    .nsop-header.is-nav-open .nsop-header__nav {
        display: grid; background: var(--c-blue);
        transition: min-height .45s var(--e-outQuart);   /* shrinks with the logo */
    }
    .nsop-header.is-nav-open .nsop-header__nav .nsop-header__side { display: none; }

    /* Logo → solid blue disc straddling the white/blue boundary (white wordmark). */
    .nsop-header.is-nav-open .nsop-header__logo { background: var(--c-blue); border-radius: 50%; }

    /* Drawer scrolled (megamenu.js toggles .is-mnav-scrolled): the big logo eats
       ~20% of the screen, so it shrinks to 0.75 col (grid-aligned like every
       logo size) and recentres 50/50 on the L2 bottom border — half on the white
       strip, half on the blue band. The L3 band shrinks with it (it only needs
       to back the disc's lower half) so the reclaimed space goes to the nav.
       Everything eases on the same outQuart geometry curve; grows back when the
       drawer returns to the top. */
    .nsop-header.is-nav-open.is-mnav-scrolled .nsop-header__logo {
        width: var(--hd-logo-sm);
        height: var(--hd-logo-sm);
        top: calc(var(--hd-l2-h) - var(--hd-logo-sm) / 2);
    }
    .nsop-header.is-nav-open.is-mnav-scrolled .nsop-header__nav { min-height: var(--hd-nav-h-sm); }
}
@media (max-width: 767px) {
    /* Logo drops to a single column on mobile (1.25 cols elsewhere) — matches
       --ft-logo. On :root so the hero's clearance padding sees the same size. */
    :root { --hd-logo-cols: 1; }
}

/* ── Pre-launch header (Header options → Pre-launch → "Pre-launch header") ─────
   One slim L2 bar at EVERY width — header.php renders no L3 nav, mega menu,
   burger or drawer in this mode (one-page pre-launch site, nothing to navigate).
   Geometry = the settled mobile closed-bar treatment promoted to all
   breakpoints: logo 25% inside the bar / 75% protruding into the hero, porthole
   cutout tracking it; sticky = small white logo INSIDE the blue strip. L2 keeps
   portal (icon + label) + email left, phone + JOIN NOW right; ≤1023 the right
   group stays VISIBLE (the full header hides it in favour of the drawer) and
   text links collapse to icons (clip-hidden — accessible names survive). */
.nsop-header--prelaunch .nsop-header__logo { top: calc(var(--hd-l2-h) - 0.25 * var(--hd-logo)); }
.nsop-header--prelaunch .nsop-header__utility::before { --hd-hole-cy: calc(var(--hd-l2-h) + 0.25 * var(--hd-logo)); }
/* The left-group phone duplicate is MOBILE-ONLY (≥1024 the phone sits right). */
.nsop-header--prelaunch .nsop-header__contact--mobile { display: none; }

/* Lead hero clearance at ALL widths (the ≤1023 block already covers the full
   header): the logo hangs 0.75·logo below the bar and --hd-pullup (the measured
   header height) doesn't include that protrusion. */
.nsop-header--prelaunch ~ .site-main > .page-hero:first-child {
    padding-top: calc(var(--hd-pullup) + 0.75 * var(--hd-logo) + var(--sp-2xl));
}

@media (min-width: 1024px) {
    /* Sticky: mirror the mobile treatment — the logo shrinks INSIDE the L2 strip,
       white wordmark on the blue bar. Must out-rank the desktop .scrolled band
       rules (band-coloured disc + 1.25-col size + bar-centred top) — 3 classes
       beat their 2. */
    .nsop-header--prelaunch.scrolled .nsop-header__logo {
        color: var(--c-white);
        background: var(--c-blue);
        top: 50%;
        transform: translate(-50%, -50%);
        width: calc(var(--hd-l2-h) - var(--sp-md));
        height: calc(var(--hd-l2-h) - var(--sp-md));
    }
}

@media (max-width: 1023px) {
    /* The right group (phone + JOIN NOW) stays in the bar — there is no drawer
       to move it to. Anchored to the last two tracks on both the 6- and 4-col
       grids; the left group (portal + email icons) keeps the first two. */
    .nsop-header--prelaunch .nsop-header__utility .nsop-header__side--right { display: flex; }
    .nsop-header--prelaunch .nsop-header__side--left  { grid-column: 1 / 3; }
    .nsop-header--prelaunch .nsop-header__side--right { grid-column: -3 / -1; }
    /* Email + phone stay in the bar too (the full header hides left contacts
       ≤1023) — the phone ICON moves to the left group, JOIN NOW alone right. */
    .nsop-header--prelaunch .nsop-header__side--left > .nsop-header__contact { display: inline-flex; }
    .nsop-header--prelaunch .nsop-header__side--right > .nsop-header__contact { display: none; }
    /* Icons only: clip the link text (same pattern as the desktop .is-compact
       step — the accessible name survives for screen readers). */
    .nsop-header--prelaunch .nsop-header__contact span:not(.nsop-header__ico) {
        position: absolute; width: 1px; height: 1px;
        overflow: hidden; clip-path: inset(50%); white-space: nowrap;
    }
    .nsop-header--prelaunch .nsop-header__side { gap: var(--sp-sm); }
    /* JOIN NOW pill slims a step (mirrors .is-compact-2 sizing). */
    .nsop-header--prelaunch .nsop-header__pill { font-size: 0.875rem; padding-inline: var(--sp-lg); }
}
         /* site header — notification + utility + nav + logo */

/* ── layout/_megamenu.css ── */
/* =============================================================================
   NORTH SYDNEY OLYMPIC POOL — Header mega menu
   -----------------------------------------------------------------------------
   Figma "Mega menu" (1560-1394). ACF-driven (Header options → nav_items), one
   full-width white panel per top-level item. Colour-controlled per item via
   --mm-accent (heading + brand graphic). Rendered by
   template-parts/header/megamenu.php.

   Desktop grid (per spec, on the site 12-col grid):
     [1 empty] [3 intro] [1 gap] [1.5 × N columns] [1 empty]
   ≤1023px the whole nav collapses into a hamburger drawer with the panels as
   stacked accordions.
   ============================================================================= */

/* Nav item wrapper — stays static so each panel's containing block is the
   full-width .nsop-header__bar (→ the dropdown spans edge to edge). */
.nsop-nav-item { position: static; display: inline-flex; }

/* Trigger buttons share .nsop-header__navlink; reset native button chrome. */
/* Reset native button chrome ONLY — do NOT touch `font` (the .nsop-header__navlink
   class supplies MD Nichrome Black / uppercase; `font:inherit` would clobber it). */
button.nsop-header__navlink {
    background: none; border: 0; margin: 0; padding: var(--sp-xs) 0;
    cursor: pointer; color: var(--hd-fg);
}
.nsop-nav-item.is-open > .nsop-header__navlink { opacity: 1; }

/* ── Panel ───────────────────────────────────────────────────────────────────*/
.nsop-megamenu {
    /* one grid column + a 1.5-col list width, in viewport units (desktop grid) */
    --mm-colw:  calc((100vw - 2 * var(--sp-page-x) - 11 * var(--gutter)) / 12);
    --mm-listw: calc(1.5 * var(--mm-colw) + 0.5 * var(--gutter));
    --mm-accent: var(--c-green);

    position: absolute;
    top: calc(100% + var(--sp-xs));
    left: var(--sp-page-x); right: var(--sp-page-x);   /* 12-col content width, not full screen */
    z-index: 30;
    background: var(--c-white);
    color: var(--c-black);
    border-radius: var(--r-card);
    box-shadow: 0 .5rem .75rem rgba(0, 0, 0, .2);

    visibility: hidden; opacity: 0; transform: translateY(-.5rem);
    transition: opacity var(--transition), transform var(--transition), visibility var(--transition);
}
/* Server ships the panel [hidden] for no-JS discoverability; neutralise the
   attribute so visibility (not display) drives show/hide once styled. */
.nsop-megamenu[hidden] { display: block; }

/* Accent per colour choice (top-level control) */
.nsop-megamenu--green      { --mm-accent: var(--c-green); }
.nsop-megamenu--teal       { --mm-accent: var(--c-teal); }
.nsop-megamenu--blue       { --mm-accent: var(--c-blue); }
.nsop-megamenu--terracotta { --mm-accent: var(--c-terracotta); }
.nsop-megamenu--gold       { --mm-accent: var(--c-gold); }
.nsop-megamenu--red        { --mm-accent: var(--c-red); }
.nsop-megamenu--black      { --mm-accent: var(--c-black); }

/* Open — JS-driven (html.js) or hover/focus fallback (no-JS) */
.nsop-nav-item.is-open .nsop-megamenu,
html:not(.js) .nsop-nav-item:hover .nsop-megamenu,
html:not(.js) .nsop-nav-item:focus-within .nsop-megamenu {
    visibility: visible; opacity: 1; transform: none;
}

/* Notch — white door-arch pointing up from the panel to the active nav item.
   Positioned at the active trigger's x via --mm-notch-x (set by megamenu.js;
   falls back to centre for the no-JS :hover path). */
.nsop-megamenu__notch {
    position: absolute;
    bottom: calc(100% - 1px);                 /* sit on the panel's top edge */
    left: var(--mm-notch-x, 50%);
    transform: translateX(-50%);
    width: 0; height: 0;                       /* CSS triangle pointing up */
    border-left: .75rem solid transparent;
    border-right: .75rem solid transparent;
    border-bottom: .625rem solid var(--c-white);
}

/* ── Nav-link states (Figma "Mega menu link" 1558-5948) — underline on
   hover/focus and while the item's panel is open. */
.nsop-header__navlink > span { text-underline-offset: .35em; text-decoration-thickness: .1em; }
.nsop-header__navlink:hover > span,
.nsop-header__navlink:focus-visible > span,
.nsop-nav-item.is-open > .nsop-header__navlink > span { text-decoration: underline; }

/* Inner: site 12-col grid */
.nsop-megamenu__inner {
    display: grid;
    grid-template-columns: repeat(12, 1fr);
    column-gap: var(--gutter);
    align-items: stretch;   /* intro stretches → brand graphic pins to the bottom */
    padding: var(--sp-2xl) 0;   /* panel already inset to content width; cols 1 & 12 stay empty */
}

/* Intro block — cols 2–4 (col 1 empty) */
.nsop-megamenu__intro {
    grid-column: 2 / 5;
    display: flex; flex-direction: column; justify-content: space-between;
    gap: var(--sp-2xl);
    min-height: 100%;
}
.nsop-megamenu__introhead { display: flex; flex-direction: column; gap: var(--sp-md); }
.nsop-megamenu__title {
    margin: 0;
    font-family: var(--f-heading); font-weight: var(--fw-black);
    font-size: var(--fs-h3); line-height: var(--lh-h3, .8);
    text-transform: uppercase; color: var(--mm-accent);
}
/* Title is a link to the item's page — accent underline on hover (matches __link). */
a.nsop-megamenu__title {
    display: inline-block; text-decoration: none;
    transition: color var(--transition);
}
a.nsop-megamenu__title:hover,
a.nsop-megamenu__title:focus-visible {
    text-decoration: underline; text-underline-offset: .12em;
    text-decoration-color: currentColor;
    text-decoration-thickness: .06em;
}
.nsop-megamenu__desc {
    margin: 0;
    font-family: var(--f-body); font-weight: var(--fw-regular);
    font-size: var(--fs-body); line-height: var(--lh-body);
    color: var(--c-black);
}
.nsop-megamenu__icon {
    display: block; width: 7.5rem; height: 7.5rem;   /* 120px @1920 */
    color: var(--mm-accent);                          /* seagull uses currentColor */
    --fill-0: var(--mm-accent);                       /* swim/shell/door use --fill-0 */
}
.nsop-megamenu__icon-svg { width: 100%; height: 100%; display: block; }

/* Columns — cols 6–11 (col 5 is the gap, col 12 empty). A nested 4-track grid
   sizes each column to 1.5 site-cols from the wrapper's OWN width (not 100vw),
   so 4 columns always sit on one row (no sub-pixel/scrollbar wrap). Fewer
   columns fill from the left and leave the trailing tracks empty. */
.nsop-megamenu__cols {
    grid-column: 6 / 12;
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: var(--sp-lg) var(--gutter);
}
.nsop-megamenu__col {
    display: flex; flex-direction: column; gap: var(--sp-md);
    min-width: 0;
}
.nsop-megamenu__colhead {
    margin: 0; padding: var(--sp-xs);
    font-family: var(--f-heading); font-weight: var(--fw-black);
    font-size: var(--fs-link-sm); line-height: 1.1;
    text-transform: uppercase; color: var(--c-black);
}
.nsop-megamenu__list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--sp-xs); }
.nsop-megamenu__link {
    display: inline-block; padding: var(--sp-xs);
    font-family: var(--f-body); font-size: var(--fs-body); line-height: var(--lh-body);
    color: var(--c-black); text-decoration: none;
    transition: color var(--transition);
}
.nsop-megamenu__link:hover,
.nsop-megamenu__link:focus-visible {
    text-decoration: underline; text-underline-offset: .25em;
    text-decoration-color: var(--mm-accent);
    text-decoration-thickness: .1em;
}

/* ── Mobile hamburger ────────────────────────────────────────────────────────*/
.nsop-header__burger {
    display: none;
    position: absolute; right: var(--sp-page-x); top: 50%; transform: translateY(-50%);
    z-index: 40;
    align-items: center; gap: var(--sp-sm);
    height: 2.75rem; padding: 0;
    background: none; border: 0; cursor: pointer; color: var(--hd-fg);
}
/* "MENU" label beside the icon (mobile/tablet only — burger is hidden on desktop). */
.nsop-header__burger-label {
    font-family: var(--f-heading); font-weight: var(--fw-black); font-size: var(--fs-link-sm);
    line-height: 1; text-transform: uppercase; color: currentColor;
}
.nsop-header__burger-box { display: grid; gap: .375rem; width: 1.75rem; }
.nsop-header__burger-box span { display: block; height: .1875rem; background: currentColor; border-radius: 2px; transition: transform var(--transition), opacity var(--transition); }
.nsop-header.is-nav-open .nsop-header__burger-box span:nth-child(1) { transform: translateY(.5625rem) rotate(45deg); }
.nsop-header.is-nav-open .nsop-header__burger-box span:nth-child(2) { opacity: 0; }
.nsop-header.is-nav-open .nsop-header__burger-box span:nth-child(3) { transform: translateY(-.5625rem) rotate(-45deg); }

/* =============================================================================
   ≤1023px — the desktop nav + mega menu step aside for the mobile overlay
   (.nsop-mnav, layout/_mnav.css). The burger toggles it.
   ============================================================================= */
@media (max-width: 1023px) {
    .nsop-header__burger { display: inline-flex; }
    /* Hide the desktop nav row + its mega menus; the mobile overlay takes over. */
    .nsop-header__nav { display: none; }
}
       /* header mega menu (ACF-driven) — desktop */

/* ── layout/_mnav.css ── */
/* =============================================================================
   NORTH SYDNEY OLYMPIC POOL — Mobile menu (full-screen overlay)
   -----------------------------------------------------------------------------
   Figma "HOMEPAGE NSOP mobile" (498-191) + the six accordion states
   (498-5170 … 498-5633). Shown ≤1023px only; the burger toggles it open.

   Data is the SAME nav (nsop_nav_items) + utility ACF as the desktop mega menu
   — editing the menu in the backend updates both. Structure:
     white top strip (utility links + Close) · protruding logo ·
     blue accordion nav (label + caret → white link panels) ·
     foot (Listen / Join Now pills + email + phone).
   ============================================================================= */

/* The drawer is NOT a full-screen overlay: the real header L2 + L3 + logo stay
   put and recolour (see _header.css .is-nav-open). This is only the scrolling
   accordion nav + foot, pinned below L3 (top = --hd-open-top, set by
   megamenu.js) and sitting BEHIND the header bar (z-index below it). */
.nsop-mnav {
    position: fixed;
    top: var(--hd-open-top, 8.75rem); left: 0; right: 0; bottom: 0;
    z-index: 1;                    /* below .nsop-header__bar (z-index 2 when open) */
    display: none;                 /* opened via .nsop-header.is-nav-open (≤1023 only) */
    flex-direction: column;
    background: var(--c-blue);
    color: var(--c-white);
    overflow-x: hidden;            /* never let a long email etc. widen the sheet */
    overflow-y: auto;
    overscroll-behavior: contain;
    -webkit-overflow-scrolling: touch;
    /* Solid blue bleed ABOVE the top edge (hidden behind the opaque bar): while
       the bar + drawer animate their heights in tandem (.is-mnav-scrolled) any
       transient 1-frame mismatch shows blue, never the page behind. */
    box-shadow: 0 -4rem 0 var(--c-blue);
    transition: top .45s var(--e-outQuart);   /* follows the shrinking L3 */
}
/* Drawer scrolled → bar is compact (small logo + shrunk L3); the drawer's top
   rises by the same delta so the reclaimed space goes to the nav. Vars are set
   on .is-nav-open (_header.css) and inherited here. */
.nsop-header.is-nav-open.is-mnav-scrolled .nsop-mnav {
    top: calc(var(--hd-open-top, 8.75rem) - var(--hd-nav-h) + var(--hd-nav-h-sm));
}
.nsop-mnav * { min-width: 0; }     /* allow flex children to shrink below content size */

/* Scroll-fade — a sticky blue→transparent gradient pinned to the drawer's top
   edge, so items MELT into the chrome as they scroll under it instead of
   hard-clipping at the (invisible) blue-on-blue boundary. Zero-height in the
   layout (negative margin swallows it); invisible at rest (blue on blue). */
.nsop-mnav::before {
    content: "";
    position: sticky; top: 0; z-index: 2;
    flex: none;
    height: 2.5rem; margin-bottom: -2.5rem;
    background: linear-gradient(to bottom, var(--c-blue), transparent);
    pointer-events: none;
}

/* ── Accordion nav ────────────────────────────────────────────────────────────*/
.nsop-mnav__nav {
    display: flex; flex-direction: column; gap: var(--sp-2xl);
    padding: var(--sp-xl) var(--sp-page-x) 0;
}
.nsop-mnav__item { display: flex; flex-direction: column; }

/* Top-level row: big white label + caret */
.nsop-mnav__trigger {
    display: flex; align-items: center; justify-content: space-between;
    gap: var(--sp-md);
    width: 100%; padding: var(--sp-sm) 0;
    background: none; border: 0; cursor: pointer; text-align: left;
    color: var(--c-white); text-decoration: none;
    font-family: var(--f-heading); font-weight: var(--fw-black);
    font-size: 2rem; line-height: 1;           /* 32px per spec */
    text-transform: uppercase;
}
.nsop-mnav__trigger--link { cursor: pointer; }
.nsop-mnav__label { min-width: 0; }

/* Caret — CSS triangle, points down (closed) → up (open) */
.nsop-mnav__caret {
    flex: none;
    width: 0; height: 0;
    border-left: .625rem solid transparent;
    border-right: .625rem solid transparent;
    border-top: .75rem solid currentColor;
    transition: transform var(--transition);
}
.nsop-mnav__item.is-open .nsop-mnav__caret { transform: rotate(180deg); }

/* Group heading (white on blue) — only when an item has >1 column */
.nsop-mnav__grouphead {
    margin: var(--sp-md) 0 var(--sp-xs);
    font-family: var(--f-heading); font-weight: var(--fw-black); font-size: var(--fs-link-sm); line-height: 1.1;
    text-transform: uppercase; text-align: center; color: var(--c-white);
}

/* White link panel — a 0fr grid row eased open/closed (accordion). Class-driven
   (.is-open on the item); durations/easings come from _tokens.css so a later
   GSAP pass can lift the same values. */
.nsop-mnav__panel {
    display: grid;
    grid-template-rows: 0fr;
    transition: grid-template-rows var(--transition-layout);
}
.nsop-mnav__panelin {
    display: flex; flex-direction: column;
    min-height: 0; overflow: hidden;   /* the clipped track the row collapses to */
    padding-top: var(--sp-md);         /* panel's old margin-top — inside the clip so closed items reserve nothing */
    visibility: hidden;                /* links unfocusable while closed… */
    transition: visibility 0s linear .35s;  /* …but only hidden AFTER the collapse eases out */
}
.nsop-mnav__item.is-open .nsop-mnav__panel { grid-template-rows: 1fr; }
.nsop-mnav__item.is-open .nsop-mnav__panelin { visibility: visible; transition: none; }
.nsop-mnav__list {
    list-style: none; margin: 0 0 var(--sp-md); padding: var(--sp-xs);
    display: flex; flex-direction: column; gap: var(--sp-xs);
    background: var(--c-white);
}
.nsop-mnav__list:last-child { margin-bottom: 0; }
.nsop-mnav__link {
    display: block; padding: var(--sp-xs) var(--sp-sm);
    font-family: var(--f-heading); font-weight: var(--fw-black); font-size: var(--fs-link-sm); line-height: 1.1;
    text-transform: uppercase; text-align: center; color: var(--c-black); text-decoration: none;
}
.nsop-mnav__link:hover,
.nsop-mnav__link:focus-visible { color: var(--c-blue); text-decoration: underline; text-underline-offset: .2em; }

/* ── Hub link — "View GYM page" (first card of an opened panel) ───────────────
   The trigger tap only expands the accordion, so this is the door to the
   section's main page. White card like the link panels; label + brand
   pictogram + arrow take the item's mega-menu accent (--mn-accent — the same
   per-section colour the desktop mega panel uses for its heading + graphic). */
.nsop-mnav__hub {
    display: flex; align-items: center; justify-content: center; gap: var(--sp-sm);
    margin-bottom: var(--sp-md);
    padding: var(--sp-md) var(--sp-sm);
    background: var(--c-white);
    color: var(--mn-accent, var(--c-blue));
    --fill-0: var(--mn-accent, var(--c-blue));    /* tints the brand graphic */
    font-family: var(--f-heading); font-weight: var(--fw-black); font-size: var(--fs-link-sm); line-height: 1.1;
    text-transform: uppercase; text-align: center; text-decoration: none;
}
.nsop-mnav__hub:hover,
.nsop-mnav__hub:focus-visible { text-decoration: underline; text-underline-offset: .2em; }
.nsop-mnav__hubico { flex: none; display: inline-grid; place-items: center; width: 2rem; height: 2rem; }
.nsop-mnav__hubico svg { width: 100%; height: 100%; }
.nsop-mnav__hubarrow { flex: none; height: 1.1em; width: auto; }
/* Accent map — mirrors .nsop-megamenu--{color} (_megamenu.css); keep in sync. */
.nsop-mnav__hub--green      { --mn-accent: var(--c-green); }
.nsop-mnav__hub--teal       { --mn-accent: var(--c-teal); }
.nsop-mnav__hub--blue       { --mn-accent: var(--c-blue); }
.nsop-mnav__hub--terracotta { --mn-accent: var(--c-terracotta); }
.nsop-mnav__hub--gold       { --mn-accent: var(--c-gold); }
.nsop-mnav__hub--red        { --mn-accent: var(--c-red); }
.nsop-mnav__hub--black      { --mn-accent: var(--c-black); }

/* ── Foot — Listen / Join Now pills + contact ─────────────────────────────────*/
.nsop-mnav__foot {
    display: flex; flex-direction: column; gap: var(--sp-2xl);
    padding: var(--sp-2xl) var(--sp-page-x);
    /* Generous bottom clearance: the contact links otherwise sit hard against
       the viewport edge (thumb-reach + browser chrome / iOS home bar). */
    padding-bottom: calc(var(--sp-2xl) * 2 + env(safe-area-inset-bottom, 0px));
    margin-top: auto;
}
.nsop-mnav__actions { display: flex; gap: var(--sp-md); }
.nsop-mnav__pill {
    flex: 1 1 0; min-width: 0;
    display: inline-flex; align-items: center; justify-content: center; gap: var(--sp-xs);
    min-height: 2.875rem; padding: var(--sp-xs) var(--sp-md);
    background: var(--c-sandstone); color: var(--c-blue);
    border: 0; border-radius: var(--r-pill);
    font-family: var(--f-heading); font-weight: var(--fw-black); font-size: var(--fs-link-sm); line-height: 1.1;
    text-transform: uppercase; text-decoration: none; white-space: nowrap; cursor: pointer;
    transition: box-shadow var(--transition);
}
.nsop-mnav__pill:hover { box-shadow: inset 0 0 0 100vmax var(--c-navy-05); }
.nsop-mnav__pill svg { width: 1.5rem; height: 1.5rem; }

/* Contact — sandstone email + phone stacked under the pills (Figma 498-5720). */
.nsop-mnav__contact {
    display: flex; flex-direction: column; align-items: center; gap: var(--sp-md);
}
.nsop-mnav__contactlink {
    display: inline-flex; align-items: center; gap: var(--sp-sm);
    max-width: 100%;
    color: var(--c-sandstone); text-decoration: none;
    font-family: var(--f-body); font-size: var(--fs-body); line-height: 1.2;
    word-break: break-word;
}
.nsop-mnav__contactlink:hover { text-decoration: underline; text-underline-offset: 2px; }
.nsop-mnav__contactico { flex: none; display: inline-grid; place-items: center; width: 1.75rem; height: 1.75rem; }
.nsop-mnav__contactico svg { width: 100%; height: 100%; }

/* ── Show only ≤1023, when opened — with a staggered entrance ─────────────────
   Keyframes (re)run each time display flips none→flex, so the sequence plays on
   every open: the sheet drops in on the settle curve, then the nav items + foot
   surface one after another on the brand "come up for air" overshoot
   (--e-outBack). `backwards` fill keeps delayed items invisible until their turn.
   A later GSAP pass can replace these 1:1 — same tokens. */
@media (max-width: 1023px) {
    .nsop-header.is-nav-open .nsop-mnav {
        display: flex;
        animation: nsop-mnav-sheet .4s var(--e-outQuart) backwards;
    }
    .nsop-header.is-nav-open .nsop-mnav__item,
    .nsop-header.is-nav-open .nsop-mnav__foot {
        animation: nsop-mnav-rise .55s var(--e-outBack) backwards;
    }
    .nsop-header.is-nav-open .nsop-mnav__item:nth-child(1) { animation-delay: .06s; }
    .nsop-header.is-nav-open .nsop-mnav__item:nth-child(2) { animation-delay: .11s; }
    .nsop-header.is-nav-open .nsop-mnav__item:nth-child(3) { animation-delay: .16s; }
    .nsop-header.is-nav-open .nsop-mnav__item:nth-child(4) { animation-delay: .21s; }
    .nsop-header.is-nav-open .nsop-mnav__item:nth-child(5) { animation-delay: .26s; }
    .nsop-header.is-nav-open .nsop-mnav__item:nth-child(6) { animation-delay: .31s; }
    .nsop-header.is-nav-open .nsop-mnav__item:nth-child(7) { animation-delay: .36s; }
    .nsop-header.is-nav-open .nsop-mnav__item:nth-child(8) { animation-delay: .41s; }
    .nsop-header.is-nav-open .nsop-mnav__foot { animation-delay: .46s; }
}
@keyframes nsop-mnav-sheet { from { opacity: 0; transform: translateY(-.75rem); } }
@keyframes nsop-mnav-rise  { from { opacity: 0; transform: translateY(1.25rem); } }

@media (prefers-reduced-motion: reduce) {
    .nsop-mnav__caret { transition: none; }
    .nsop-mnav__panel { transition: none; }
    .nsop-mnav__panelin { transition: none; }
    .nsop-header.is-nav-open .nsop-mnav,
    .nsop-header.is-nav-open .nsop-mnav__item,
    .nsop-header.is-nav-open .nsop-mnav__foot { animation: none; }
}
           /* mobile menu — full-screen overlay (≤1023) */

/* ── Sections ─────────────────────────────────────────────────────────────────*/

/* ── sections/_hero.css ── */
/* =============================================================================
   NORTH SYDNEY OLYMPIC POOL — Hero (page headers)
   -----------------------------------------------------------------------------
   Four variants, one component (template-parts/sections/hero.php):
     • .page-hero--internal  Figma 1684-1976  breadcrumb → eyebrow → H1(green) → big-p → image
     • .page-hero--section   Figma 1685-1991  H1(green) → big-p → anchor-nav pills → image
     • .page-hero--home      Figma 1685-2726  full-viewport bg media, white H1 + big-p + scroll cue
     • .page-hero--cta       Figma 1694-4762  sandstone tag → H3 → date → primary button → image

   Named `.page-hero` (not `.hero`) on purpose: the legacy NSOP `.hero`
   component (_section-hero_sections.css) still ships and sets a header-offset
   padding + min-height. This NSOP page header is a separate component.

   Everything is token-driven. Gaps/padding follow the theme's viewport-
   proportional model — max(rem floor, vw) so the whole block scales with the
   screen (like the type scale) while staying readable on mobile. px values in
   comments are the Figma 1920 canvas measurements.
   ============================================================================= */

.page-hero {
    /* Local spacing scale — Figma gaps as max(floor, vw) so they scale with the
       viewport exactly like --fs-* / --sp-page-x / --gutter do. */
    --hero-gap-100: max(3rem,    5.2083vw);  /* 100px */
    --hero-gap-60:  max(2rem,    3.125vw);   /*  60px */
    --hero-gap-40:  max(1.5rem,  2.0833vw);  /*  40px */
    --hero-gap-30:  max(1.25rem, 1.5625vw);  /*  30px */
    --hero-gap-25:  max(1rem,    1.3021vw);  /*  25px */
    --hero-gap-24:  var(--gutter);           /*  24px */
    --hero-gap-16:  max(.75rem,  0.8333vw);  /*  16px */
    --hero-pt-180:  max(6rem,    9.375vw);   /* 180px */
    --hero-pb-80:   max(3rem,    4.1667vw);  /*  80px */
    --hero-pt-60:   max(2rem,    3.125vw);   /*  60px */

    --hero-title:   var(--c-black);          /* per-variant override */

    /* Copy width comes from real grid-column spans on .page-hero__text (see the
       shared rules below), not max-width — so the tracks are DevTools-inspectable
       and reflow with the 12/6/4 token. */

    position: relative;
    text-align: center;
}

/* ── Shared inner — the real 12/6/4 grid (inspectable, like .intro-media__inner)
   .page-hero__inner IS .container, so direct children default to grid-column
   1/-1 (the reset safety net) unless a variant re-spans them. row-gap is set
   per variant (the old flex `gap`); column-gap is the token gutter so the tracks
   coincide with every other section. justify-items centres blocks narrower than
   their span (button, scroll cue). */
.page-hero .page-hero__inner {
    display: grid;
    grid-template-columns: repeat(var(--grid-cols), 1fr);
    column-gap: var(--gutter);
    justify-items: center;
}

/* Title + supporting copy group — its OWN matching grid (full width), so the
   title/desc column spans line up with .page-hero__inner's tracks. */
.page-hero__text {
    display: grid;
    grid-template-columns: repeat(var(--grid-cols), 1fr);
    column-gap: var(--gutter);
    width: 100%;
}

/* Copy sits on the __text grid: title/eyebrow group = full 12 cols, desc = 8 cols
   centred, date = 6 cols centred. Stack to full width at ≤1023. */
.page-hero__titlegroup,
.page-hero__text > .page-hero__title { grid-column: 1 / -1; }   /* 12 cols */
.page-hero__desc { grid-column: 3 / 11; }                        /* 8 cols, centred */
.page-hero__date { grid-column: 4 / 10; }                        /* 6 cols, centred */
@media (max-width: 1023px) {
    .page-hero__titlegroup,
    .page-hero__text > .page-hero__title,
    .page-hero__desc,
    .page-hero__date { grid-column: 1 / -1; }
}

/* ── Title / copy primitives ─────────────────────────────────────────────────*/
.page-hero__title {
    margin: 0;
    font-family: var(--f-heading);
    font-weight: var(--fw-black);
    font-size: var(--fs-h1);          /* 200px @1920 */
    line-height: var(--lh-h1);        /* 0.8 */
    text-transform: uppercase;
    color: var(--hero-title);
}
.page-hero__title--h3 {
    font-size: var(--fs-h3);          /* 100px @1920 */
    line-height: var(--lh-h3);        /* 0.8 */
}
/* Mobile: the global --fs-h1 collapses to its 44px floor (its 10.4167vw only
   overtakes ~420px+), leaving the display H1 undersized. Give the hero title its
   own bigger mobile ramp so it stays a display-scale headline. --h3 heroes keep
   their own smaller size. */
@media (max-width: 767px) {
    .page-hero__title:not(.page-hero__title--h3) { font-size: max(3.25rem, 15vw); }
}

.page-hero__eyebrow {
    margin: 0;
    font-family: var(--f-body);
    font-weight: var(--fw-regular);
    font-size: var(--fs-big-p);       /* 30px @1920 */
    line-height: var(--lh-body);      /* 1.2 */
    color: var(--c-black);
}

.page-hero__desc {
    margin: 0;
    font-family: var(--f-body);
    font-weight: var(--fw-regular);
    font-size: var(--fs-big-p);       /* 30px @1920 */
    line-height: var(--lh-body);      /* 1.2 */
    color: var(--hero-desc, var(--c-black));
}

/* Wide media card that closes most hero variants (Figma "Image small card",
   1680×580 @1920 ≈ 2.9:1). object-fit keeps any real photo filling the frame. */
.page-hero__media {
    width: 100%;
    aspect-ratio: 1680 / 580;
    border-radius: var(--r-card);     /* 4px */
    overflow: hidden;
}
.page-hero__media img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

/* ─────────────────────────────────────────────────────────────────────────────
   VARIANT 1 — Internal pages (breadcrumb → eyebrow → H1 → big-p → image)
   ────────────────────────────────────────────────────────────────────────────*/
.page-hero--internal { --hero-title: var(--c-green); }
.page-hero--internal .page-hero__inner { row-gap: var(--hero-gap-60); padding-block: var(--hero-pt-60) 0; }
.page-hero--internal .page-hero__block {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--hero-gap-16);
    width: 100%;
}
.page-hero--internal .page-hero__text { row-gap: var(--hero-gap-40); }
.page-hero--internal .page-hero__titlegroup {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--hero-gap-25);
    width: 100%;
}

/* Breadcrumb (Figma: 20px Archivo Narrow, black; current = green) */
.page-hero__breadcrumb { font-family: var(--f-body); font-size: var(--fs-body); line-height: var(--lh-body); }
.page-hero__breadcrumb ol {
    list-style: none; margin: 0; padding: 0;
    display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 0;
}
.page-hero__breadcrumb li { display: inline-flex; align-items: center; padding: var(--sp-xs); }
.page-hero__breadcrumb a { color: var(--hero-crumb, var(--c-black)); text-decoration: none; }
/* Current page + hover follow the hero heading colour (--hero-title: band ink or
   tt-* tint) so the highlight always matches the H1 below it. */
.page-hero__breadcrumb a:hover { color: var(--hero-title, var(--c-green)); }
.page-hero__breadcrumb [aria-current="page"] { color: var(--hero-title, var(--c-green)); }

/* ─────────────────────────────────────────────────────────────────────────────
   VARIANT 2 — Section / hub pages (H1 → big-p → anchor-nav pills → image)
   ────────────────────────────────────────────────────────────────────────────*/
.page-hero--section { --hero-title: var(--c-green); }
.page-hero--section .page-hero__inner { row-gap: var(--hero-gap-60); padding-block: var(--hero-gap-100); }
.page-hero--section .page-hero__block {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--hero-gap-60);
    width: 100%;
}
.page-hero--section .page-hero__text { row-gap: var(--hero-gap-24); }

/* Anchor nav — jump links styled as the green pill (reuses .btn .btn--green) */
.page-hero__nav {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: var(--hero-gap-16) var(--hero-gap-24);
    width: 100%;
}

/* ── Band colour behind the header (internal / section variants) ──────────────
   `bg_color` sets --ph-band. The band fills up behind the 160px the lead hero
   pulls up under the transparent nav (see _header.css) so the nav + logo
   porthole sit on it; main.js keeps the nav green from the title. Dark bands
   flip the copy to white.
     • SECTION / hub — solid band across the whole hero.
     • INTERNAL / category — the band stops at the wide image's mid-height (top
       half of the image on the band, bottom half on the page background), the
       Figma program-category look. The .page-hero box paints the page bg so the
       sticky footer never shows through the lower (band-less) strip. */
.page-hero--bg-teal      { --ph-band: var(--c-teal); }
.page-hero--bg-white     { --ph-band: var(--c-white); }
.page-hero--bg-sandstone { --ph-band: var(--c-sandstone); }
.page-hero--bg-gold      { --ph-band: var(--c-gold); }
.page-hero--bg-green     { --ph-band: var(--c-green); }
.page-hero--bg-blue      { --ph-band: var(--c-blue); }
.page-hero--bg-terracotta{ --ph-band: var(--c-terracotta); }
/* Brand band → hero heading uses the band's paired ink (the --combo-* matrix),
   so the heading, the transparent L3 nav/logo above it, and the footer banner
   below all share one colour. Mirror of nsop_band_ink() in inc/nav-data.php —
   keep the two in sync. Description stays high-contrast: white on the dark bands
   (green/blue/terracotta), default (dark) ink on the light ones. */
.page-hero--bg-teal       { --hero-title: var(--c-green); }
.page-hero--bg-green      { --hero-title: var(--c-teal);       --hero-desc: var(--c-white); --hero-crumb: var(--c-white); }
.page-hero--bg-blue       { --hero-title: var(--c-white);      --hero-desc: var(--c-white); --hero-crumb: var(--c-white); }
.page-hero--bg-terracotta { --hero-title: var(--c-gold);       --hero-desc: var(--c-white); --hero-crumb: var(--c-white); }
.page-hero--bg-sandstone  { --hero-title: var(--c-blue); }
.page-hero--bg-white      { --hero-title: var(--c-blue); }
.page-hero--bg-gold       { --hero-title: var(--c-terracotta); }
/* Terracotta (Gym) band: gold anchor pills. */
.page-hero--bg-terracotta .page-hero__nav .btn {
    --btn-bg: var(--c-gold); --btn-fg: var(--c-terracotta);
    --btn-ov-hover: rgba(255,255,255,.10); --btn-ov-press: rgba(255,255,255,.40);
}
/* Sandstone (Kids) / White band: solid blue anchor pills. */
.page-hero--section.page-hero--bg-sandstone .page-hero__nav .btn,
.page-hero--section.page-hero--bg-white .page-hero__nav .btn {
    --btn-bg: var(--c-blue); --btn-fg: var(--c-white);
    --btn-ov-hover: rgba(255,255,255,.12); --btn-ov-press: rgba(0,0,0,.20);
}

/* Section / hub AND internal / category: band only reaches the wide image's
   mid-height. --ph-media-half ≈ half the image's height (image ≈ 87.5vw wide,
   aspect 1680/580 → ~30.2vw tall). The image stays full-height in flow; its lower
   half sits on the page background. */
.page-hero--internal[class*="page-hero--bg-"],
.page-hero--section[class*="page-hero--bg-"] {
    --ph-media-half: 15.1vw;
    background: var(--c-background);       /* opaque — hides the fixed footer behind the band-less strip */
}
.page-hero--internal[class*="page-hero--bg-"]::before,
.page-hero--section[class*="page-hero--bg-"]::before {
    content: ""; position: absolute; left: 0; right: 0; top: 0;
    bottom: var(--ph-media-half);
    background: var(--ph-band); z-index: 0;
}
.page-hero--internal .page-hero__inner,
.page-hero--section .page-hero__inner { position: relative; z-index: 1; }
@media (max-width: 767px) {
    /* image aspect switches to 3/2 (taller) → half-height grows */
    .page-hero--internal[class*="page-hero--bg-"],
    .page-hero--section[class*="page-hero--bg-"] { --ph-media-half: 29vw; }
}
/* Section / internal hero with a band but NO wide image → the band fills the
   whole header instead of stopping at the (absent) image's mid-height. */
.page-hero--internal[class*="page-hero--bg-"]:not(:has(.page-hero__media))::before,
.page-hero--section[class*="page-hero--bg-"]:not(:has(.page-hero__media))::before { bottom: 0; }

/* ─────────────────────────────────────────────────────────────────────────────
   VARIANT 3 — Homepage (full-viewport bg image/video, white copy, scroll cue)
   ────────────────────────────────────────────────────────────────────────────*/
.page-hero--home {
    --hero-title: var(--c-white);
    --hero-desc:  var(--c-white);
    min-height: 100svh;
    display: flex;
    color: var(--c-white);
    overflow: hidden;
}
/* Real 12 / 6 / 4 grid (like .intro-media__inner) so the tracks are inspectable
   in DevTools and the copy snaps to columns. flex:1 lets it fill the 100svh
   section; align-content centres the rows vertically. */
.page-hero--home .page-hero__inner {
    display: grid;
    grid-template-columns: repeat(var(--grid-cols), 1fr);
    column-gap: var(--gutter);
    row-gap: var(--hero-gap-100);
    align-content: center;
    justify-items: center;
    flex: 1;
    padding-block: var(--hero-pt-180) var(--hero-pb-80);
    position: relative;
    z-index: 2;
}
/* __text grid + title(8)/desc(6) spans come from the shared rules above. */
.page-hero--home .page-hero__text  { row-gap: var(--hero-gap-24); }

/* Background media layer + legibility scrim */
.page-hero__bg { position: absolute; inset: 0; z-index: 0; }
.page-hero__bg img,
.page-hero__bg video { width: 100%; height: 100%; object-fit: cover; display: block; }
.page-hero--home::after {
    content: "";
    position: absolute; inset: 0; z-index: 1;
    background: linear-gradient(180deg, rgba(0,0,0,.25) 0%, rgba(0,0,0,.15) 40%, rgba(0,0,0,.45) 100%);
    pointer-events: none;
}

/* Scroll cue — animated chevron */
.page-hero__scroll {
    display: inline-flex; flex-direction: column; align-items: center; gap: var(--sp-sm);
    color: var(--c-white);
}
.page-hero__scroll-chevron {
    width: 2.75rem; height: 1.25rem;
    animation: hero-bounce 1.8s ease-in-out infinite;
}
.page-hero__scroll-chevron svg { width: 100%; height: 100%; display: block; }
@keyframes hero-bounce {
    0%, 100% { transform: translateY(0); }
    50%      { transform: translateY(35%); }
}
@media (prefers-reduced-motion: reduce) {
    .page-hero__scroll-chevron { animation: none; }
}

/* ─────────────────────────────────────────────────────────────────────────────
   VARIANT 4 — Internal with call-to-action / program header
                (tag → H3 → date → button → image)
   ────────────────────────────────────────────────────────────────────────────*/
.page-hero--cta { background: var(--c-background); }
.page-hero--cta .page-hero__inner { row-gap: var(--hero-gap-40); padding-block: var(--hero-pt-60) var(--hero-pb-80); }
/* Event / News singles: hero content sits on a white container inset from the page
   gutters (the section band stays --c-background; program-about below reads grey).
   News single goes fully white — see .single-nsop_news .news-content. */
.single-nsop_event .page-hero--cta .page-hero__inner,
.single-nsop_news  .page-hero--cta .page-hero__inner { background: var(--c-white); }
.page-hero--cta .page-hero__block {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--hero-gap-16);
    width: 100%;
}
.page-hero--cta .page-hero__text  { row-gap: var(--hero-gap-30); }
.page-hero__date {
    margin: 0;
    font-family: var(--f-body);
    font-weight: var(--fw-regular);
    font-size: var(--fs-body);        /* 20px @1920 */
    line-height: var(--lh-body);
    text-transform: uppercase;
    color: var(--c-black);
}

/* Sandstone tag chip (Figma 32px "Tag" — bigger than the .tag-sm label chip;
   square corners, MD Nichrome Black). */
.page-hero__tag {
    display: inline-flex; align-items: center; justify-content: center;
    padding: var(--sp-xs) var(--sp-md);
    background: var(--c-sandstone);
    color: var(--c-black);
    font-family: var(--f-heading);
    font-weight: var(--fw-black);
    font-size: var(--fs-link);        /* 32px @1920, floor 20px */
    line-height: 1;
    text-transform: uppercase;
}

/* ─────────────────────────────────────────────────────────────────────────────
   VARIANT 5 — Title only (centred heading + intro, no media)
   Simple page headers (Contact, About intro…). Heading colour = the tint class
   (default blue); the intro stays dark body ink. Sits on the page background.
   ────────────────────────────────────────────────────────────────────────────*/
.page-hero--title { --hero-title: var(--c-blue); background: var(--c-background); }
/* Optional band behind the header (like the section variant) — e.g. What's On =
   sandstone band + blue heading. Dark bands flip title/desc to white via the
   shared .page-hero--bg-* rules above. More specific than the base fill so it wins. */
.page-hero--title[class*="page-hero--bg-"] { background: var(--ph-band); }
/* No media in this variant, so give it generous, symmetric breathing room —
   ~120px top and bottom @1920 (double the base) so the heading isn't cramped
   against the header / the section below. */
.page-hero--title .page-hero__inner { row-gap: var(--hero-gap-40); padding-block: calc(var(--hero-gap-60) * 2); }
.page-hero--title .page-hero__text  { row-gap: var(--hero-gap-30); }

/* Heading tint overrides (title + internal variants — e.g. a program single:
   swim lesson = blue, squad/gym = green). Applied only when `title_color` is set. */
.page-hero--tt-blue       { --hero-title: var(--c-blue); }
.page-hero--tt-green      { --hero-title: var(--c-green); }
.page-hero--tt-teal       { --hero-title: var(--c-teal); }
.page-hero--tt-gold       { --hero-title: var(--c-gold); }
.page-hero--tt-terracotta { --hero-title: var(--c-terracotta); }
.page-hero--tt-red        { --hero-title: var(--c-red); }
.page-hero--tt-black      { --hero-title: var(--c-black); }

/* Program single: subtitle sits under the title (small, dark), then a centred
   square program graphic (the creature icon) instead of the wide media band. */
.page-hero__icon {
    grid-column: 4 / 10;       /* centred area; the graphic below caps to 3 cols */
    display: flex; justify-content: center;
    margin-top: var(--hero-gap-40);
}
@media (max-width: 1023px) { .page-hero__icon { grid-column: 2 / 6; } }   /* centred on 6-col grid */
@media (max-width: 767px)  { .page-hero__icon { grid-column: 1 / -1; } }  /* full on 4-col grid */
.page-hero__icon img {
    /* Icon = 3 grid columns wide (3 tracks + the 2 gutters between them), centred.
       --grid-cols keeps it 3-of-12 / 3-of-6 / 3-of-4 across the breakpoints. */
    --hero-col: calc((100vw - (2 * var(--sp-page-x)) - ((var(--grid-cols) - 1) * var(--gutter))) / var(--grid-cols));
    width: calc(var(--hero-col) * 3 + var(--gutter) * 2);
    max-width: 100%;
    height: auto; display: block;
    aspect-ratio: 1 / 1; object-fit: contain;
}
/* Icon heroes butt the creature graphic against the section below — give the
   inner a section's worth of bottom padding (the internal variant sets it to 0). */
.page-hero--has-icon .page-hero__inner { padding-bottom: var(--sp-section); }

/* ── Responsive — tighten the wide media on small screens so it isn't a sliver */
@media (max-width: 767px) {
    .page-hero__media { aspect-ratio: 3 / 2; }
}
         /* page-header hero — 4 variants */

/* ── sections/_nav-boxes.css ── */
/* =============================================================================
   NORTH SYDNEY OLYMPIC POOL — Navigation boxes section
   Figma "HOMEPAGE NSOP – option 4" / Card Block (1593-2345)
   -----------------------------------------------------------------------------
   A grid of colour-coded link tiles. Each tile fills a solid brand colour and
   pairs it with a brand ink colour (title + subtitle + cue). Whole tile is the
   link. Token-driven; px in comments are the Figma 1920 canvas.
     card 544 × 316 · padding 30 / 60 · gap 24 (gutter) · section pad 100
   ============================================================================= */

.nav-boxes {
    --nb-pad-y: var(--sp-section);
    padding-block: var(--nb-pad-y);
    background: var(--c-background);
}

/* Rides the 12/6/4 token grid (inspectable) — tiles span 4 cols (3-up) on 12,
   3 cols (2-up) on the 6-col tablet, full width (1-up) on the 4-col mobile.
   (Fixed 3-up; the older `columns` arg / --nb-cols is no longer read by CSS.) */
.nav-boxes__grid {
    grid-column: 1 / -1;
    display: grid;
    grid-template-columns: repeat(var(--grid-cols), 1fr);
    gap: var(--gutter);                        /* 24px */
}
.nav-box { grid-column: span 4; }

/* ── Tile — 316px tall, content: title/subtitle top · cue pinned bottom ─────*/
.nav-box {
    display: flex;
    flex-direction: column;
    gap: max(.75rem, .8333vw);                 /* 16px title → subtitle */
    min-height: max(15rem, 16.4583vw);         /* 316px */
    padding: max(1.5rem, 1.5625vw) max(1.75rem, 3.125vw); /* 30 / 60 */
    border-radius: var(--r-card, 4px);
    background: var(--nb-bg);
    color: var(--nb-ink);
    text-decoration: none;
    transition: box-shadow var(--transition), transform var(--transition);
}
.nav-box:hover,
.nav-box:focus-visible { box-shadow: var(--sh-drop); transform: translateY(-2px); }

.nav-box__title {
    font-family: var(--f-heading);
    font-weight: var(--fw-black);
    font-size: var(--fs-h4);                   /* 62px */
    line-height: .8;
    text-transform: uppercase;
    color: var(--nb-ink);
}
.nav-box__subtitle {
    font-family: var(--f-body);
    font-size: var(--fs-big-p);                /* 30px */
    line-height: 1.2;
    color: var(--nb-ink);
}
.nav-box__link {
    margin-top: auto;                          /* pin the cue to the bottom */
    display: inline-flex;
    align-items: center;
    gap: var(--sp-xs);
    font-family: var(--f-heading);
    font-weight: var(--fw-black);
    font-size: var(--fs-link);                 /* 32px */
    line-height: 1;
    text-transform: uppercase;
    color: var(--nb-ink);
}
.nav-box__link svg { height: 1em; width: auto; transition: transform var(--transition); }
.nav-box:hover .nav-box__link svg { transform: translateX(.3em); }

/* ── Colour pairs (bg → ink) — brand tokens only, per Figma ─────────────────*/
.nav-box--teal       { --nb-bg: var(--c-teal);       --nb-ink: var(--c-green); }
.nav-box--terracotta { --nb-bg: var(--c-terracotta); --nb-ink: var(--c-gold); }
.nav-box--sandstone  { --nb-bg: var(--c-sandstone);  --nb-ink: var(--c-blue); }
.nav-box--green      { --nb-bg: var(--c-green);       --nb-ink: var(--c-teal); }
.nav-box--gold       { --nb-bg: var(--c-gold);        --nb-ink: var(--c-terracotta); }
.nav-box--blue       { --nb-bg: var(--c-blue);        --nb-ink: var(--c-sandstone); }

/* ── Responsive — 3 → 2 → 1 tiles, re-spanning on the same 12/6/4 grid ───────*/
@media (max-width: 1023px) {   /* 6-col grid → 2-up */
    .nav-box { grid-column: span 3; }
}
@media (max-width: 767px) {    /* 4-col grid → 1-up */
    .nav-box { grid-column: 1 / -1; min-height: max(12rem, 40vw); }
    /* Full-width tiles on mobile: H4's 20px floor is too weak against the
       18px subtitle. Step the title up to the H3 scale + looser leading. */
    .nav-box__title { font-size: var(--fs-h3); line-height: .9; }
}
    /* homepage quick-links grid — colour-coded link tiles */

/* ── sections/_intro-media.css ── */
/* =============================================================================
   NORTH SYDNEY OLYMPIC POOL — Intro + media section
   Figma 1371-3425 (homepage "The Wonder Pool With a Legendary View")
   -----------------------------------------------------------------------------
   Big blue display heading spanning the top + brand emblem top-right, then a
   left text column (rich body + pill) beside a large image that rises up
   alongside the heading. Token-driven; px in comments are the Figma 1920 canvas.
   ============================================================================= */

.intro-media {
    --im-pad-y: var(--sp-section);
    --im-rise:  max(3.5rem, 6vw);              /* how far the image rises beside the heading */
    position: relative;
    padding-block: var(--im-pad-y);
    background: var(--c-background);
    overflow: clip;
}

/* Own 12-col grid so the spans stay exact regardless of the container reflow.
   Row 1: heading (1–9) · emblem (right ~1.5 cols). Row 2: text (1–4) · media (5–12). */
.intro-media__inner {
    grid-column: 1 / -1;
    display: grid;
    grid-template-columns: repeat(12, 1fr);
    column-gap: var(--gutter);
    row-gap: var(--sp-fluid-lg);
    align-items: start;
}

/* ── Heading — cols 1–9, blue display type ──────────────────────────────────*/
.intro-media__heading {
    grid-column: 1 / 10;                       /* 9 cols */
    grid-row: 1;
    font-family: var(--f-heading);
    font-weight: var(--fw-black);
    font-size: var(--fs-h2);
    line-height: .8;
    text-transform: uppercase;
    color: var(--c-blue);
}

/* ── Emblem — brand seagull, ~1.5 cols in from the right edge, top-aligned ───*/
.intro-media__emblem {
    grid-column: 11 / -1;                      /* right-hand columns */
    grid-row: 1;
    justify-self: end;
    align-self: start;
    width: max(6rem, 9.84vw);                  /* ≈ 1.5 grid columns (189px @1920) */
    color: var(--c-blue);
}
.intro-media__emblem svg,
.intro-media__emblem img { width: 100%; height: auto; display: block; }

/* ── Text column — cols 1–4 ─────────────────────────────────────────────────*/
.intro-media__text {
    grid-column: 1 / 5;                        /* 4 cols */
    grid-row: 2;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--sp-fluid-lg);
}
.intro-media__body { font-family: var(--f-body); font-size: var(--fs-big-p); line-height: 1.2; color: var(--c-black); }
.intro-media__body p + p { margin-top: 1.2em; }

/* ── Media column — cols 5–12, rises up beside the heading ──────────────────*/
.intro-media__media {
    grid-column: 5 / -1;                       /* 8 cols */
    grid-row: 2;
    margin-top: calc(-1 * var(--im-rise));
    border-radius: var(--r-card, 4px);
    overflow: hidden;
}
.intro-media__media img { width: 100%; height: auto; display: block; object-fit: cover; }

/* ── Responsive — single column (heading → emblem → media → text) ───────────*/
@media (max-width: 1023px) {
    .intro-media__inner { grid-template-columns: 1fr; }
    .intro-media__heading { grid-column: 1 / -1; grid-row: auto; order: 1; }
    .intro-media__emblem  { grid-column: 1 / -1; grid-row: auto; order: 2; justify-self: start; width: max(4.5rem, 16vw); }
    .intro-media__media   { grid-column: 1 / -1; grid-row: auto; order: 3; margin-top: 0; }
    .intro-media__text    { grid-column: 1 / -1; grid-row: auto; order: 4; }
}
  /* blue feature intro — display heading + emblem + body + image */

/* ── sections/_whats-on.css ── */
/* =============================================================================
   NORTH SYDNEY OLYMPIC POOL — What's On section
   Figma 1371-4417 (homepage "Check Out What's On")
   -----------------------------------------------------------------------------
   Sticky left column (blue display heading + intro) beside a right column of
   stacked horizontal sandstone cards + a VIEW MORE pill. Token-driven; px in
   comments are the Figma 1920 canvas.
   ============================================================================= */

.whats-on {
    --wo-pad-y: var(--sp-section);
    padding-block: var(--wo-pad-y);
    background: var(--c-background);
}

/* 12-col grid: heading own row (cols 1–5) · lead (cols 1–4) + cards (cols 6–12)
   on the row below. */
.whats-on__inner {
    grid-column: 1 / -1;
    display: grid;
    grid-template-columns: repeat(var(--grid-cols), 1fr);   /* 12 / 6 / 4 — collapses to 1fr at ≤1023 below */
    column-gap: var(--gutter);
    row-gap: var(--sp-fluid-lg);
    align-items: start;
}
/* Left = sticky intro (heading + lead pinned together), cols 1–6. */
.whats-on__intro {
    grid-column: 1 / 7;                        /* 6 cols */
    grid-row: 1;
    position: sticky;
    top: max(6rem, 8vw);                       /* clears the fixed header */
    align-self: start;
    display: flex;
    flex-direction: column;
    gap: var(--sp-fluid-lg);
}
.whats-on__heading {
    font-family: var(--f-heading);
    font-weight: var(--fw-black);
    font-size: var(--fs-h2);
    line-height: .8;
    text-transform: uppercase;
    color: var(--c-blue);
}
.whats-on__lead {
    max-width: 40ch;                           /* ≈ 4 cols */
    font-family: var(--f-body);
    font-size: var(--fs-big-p);
    line-height: 1.2;
    color: var(--c-ink, #1a1a1a);
}

/* ── Right — stacked cards + action (cols 6–12, below the heading) ───────────*/
.whats-on__list {
    grid-column: 7 / -1;
    grid-row: 1;
    margin-top: calc(var(--fs-h2) * 1.6);      /* start below the heading (≈ its 2-line height) */
    display: flex;
    flex-direction: column;
    gap: var(--sp-md);
}

.whats-on__card {
    display: flex;
    align-items: stretch;
    background: var(--c-sandstone);
    border-radius: var(--r-card, 4px);
    overflow: hidden;
    text-decoration: none;
    color: var(--c-black);
    transition: box-shadow var(--transition), transform var(--transition);
}
a.whats-on__card:hover,
a.whats-on__card:focus-visible { box-shadow: var(--sh-drop); transform: translateY(-2px); }

.whats-on__card-media { flex: 0 0 40%; align-self: stretch; overflow: hidden; }
.whats-on__card-media img { width: 100%; height: 100%; object-fit: cover; display: block; }

.whats-on__card-body {
    flex: 1 1 0;
    min-width: 0;
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: var(--sp-lg);
    padding: max(1.5rem, 1.875vw) max(1.75rem, 3.125vw);  /* 30px / 60px */
}
.whats-on__card-text { display: flex; flex-direction: column; gap: var(--sp-sm); }
.whats-on__card-title {
    font-family: var(--f-heading);
    font-weight: var(--fw-black);
    font-size: var(--fs-h5);
    line-height: .85;
    text-transform: uppercase;
    color: var(--c-blue);
}
.whats-on__card-desc { font-family: var(--f-body); font-size: var(--fs-big-p); line-height: 1.2; color: var(--c-black); }
.whats-on__card-link {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-xs);
    font-family: var(--f-heading);
    font-weight: var(--fw-black);
    font-size: var(--fs-link-sm);
    line-height: 1.1;
    text-transform: uppercase;
    color: var(--c-blue);
}
.whats-on__card-link svg { height: 1.4em; width: auto; transition: transform var(--transition); }
.whats-on__card:hover .whats-on__card-link svg { transform: translateX(.3em); }

.whats-on__action { margin-top: var(--sp-lg); }

/* ── Responsive — single column (heading → lead → cards) ────────────────────*/
@media (max-width: 1023px) {
    /* keep the 6/4 grid present (inspectable) — just full-span the children */
    .whats-on__intro { position: static; grid-column: 1 / -1; grid-row: auto; }
    .whats-on__list  { grid-column: 1 / -1; grid-row: auto; margin-top: 0; }
}
@media (max-width: 560px) {
    .whats-on__card { flex-direction: column; }
    .whats-on__card-media { flex-basis: auto; aspect-ratio: 16 / 9; }
}
     /* what's on — sticky heading + stacked event cards */

/* ── sections/_whats-on-listing.css ── */
/* =============================================================================
   NORTH SYDNEY OLYMPIC POOL — What's On listing  (Figma 1694-4267)
   -----------------------------------------------------------------------------
   The News & Events archive body: a filter/search control bar over a stack of
   .whats-on-card rows (the horizontal date-block card — see components/_cards.css),
   closed by pagination. Filter/search/pagination are driven client-side by
   main.js `[data-events-listing]`.

   The card itself (date block · image · tag + blue title + excerpt + LEARN MORE,
   plus its blue-on-hover date block) is the shared .whats-on-card COMPONENT.
   This file only lays out the listing around it. Everything is token-driven.
   ============================================================================= */

.whats-on-listing {
    padding-block: var(--sp-section);
    background: var(--c-background);
}
/* Ride the 12/6/4 token as a REAL grid (client rule) so the tracks are
   DevTools-inspectable — NOT a flex column. Each block spans its columns and
   auto-places on its own row; row-gap keeps the 60px vertical rhythm. */
.whats-on-listing__inner {
    display: grid;
    grid-template-columns: repeat(var(--grid-cols), 1fr);   /* 12 / 6 / 4 — matches .container */
    column-gap: var(--gutter);
    row-gap: max(2rem, 3.125vw);          /* 60px between control bar / list / pagination */
}
.whats-on-listing__controls,
.whats-on-listing__pagination { grid-column: 1 / -1; }   /* full 12 */

/* ── Control bar — filter chips (left) + search (right) ──────────────────────
   Keep both on one row: the chips take the width they need (left), the search
   takes the leftover space (right) and shrinks down to its min — capped at its
   Figma max (24.9em/498px) so it never grows past the component size. Stacks to
   its own column only at the mobile breakpoint below. */
.whats-on-listing__controls {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--sp-lg);
    flex-wrap: nowrap;
}
.whats-on-listing__controls .tag-list { flex: 0 1 auto; min-width: 0; }
.whats-on-listing__controls .search   { flex: 0 1 24.9em; width: auto; min-width: 7em; }

/* ── Article list ────────────────────────────────────────────────────────────
   Default (What's On) = a vertical stack of horizontal .whats-on-card rows.
   `--grid` (News) = a 3-up grid of vertical .news-card (3 → 2 → 1). */
.whats-on-listing__list {
    display: flex;
    flex-direction: column;
    gap: max(1rem, 1.25vw);              /* 24px between rows */
}
.whats-on-listing__list--grid {
    display: grid;
    grid-template-columns: repeat(var(--grid-cols), 1fr);
    gap: var(--gutter);
}
.whats-on-listing__list--grid > .news-card { grid-column: span 4; }   /* 3-up on 12 */

/* List placement on the inner grid. The News grid spans the full 12; the What's
   On row list insets to a centred 10 of 12 columns (2 / 12) — a real grid span,
   NOT a computed max-width, so the tracks stay inspectable. */
.whats-on-listing__list { grid-column: 1 / -1; }
.whats-on-listing__list:not(.whats-on-listing__list--grid) { grid-column: 2 / 12; }   /* 10 cols, centred */
@media (max-width: 1023px) {
    /* On tablet/mobile (6/4-col grid) the page margins already inset — go full width. */
    .whats-on-listing__list:not(.whats-on-listing__list--grid) { grid-column: 1 / -1; }
}
.whats-on-listing__list--grid .whats-on-listing__empty { grid-column: 1 / -1; }
@media (max-width: 1023px) { .whats-on-listing__list--grid > .news-card { grid-column: span 3; } }  /* 2-up on 6 */
@media (max-width: 767px)  { .whats-on-listing__list--grid > .news-card { grid-column: 1 / -1; } }   /* 1-up on 4 */

/* ── Empty state ─────────────────────────────────────────────────────────────*/
.whats-on-listing__empty {
    font-family: var(--f-body); font-size: var(--fs-big-p); color: var(--c-black);
    text-align: center; padding-block: var(--sp-2xl);
}

/* ── Pagination row ──────────────────────────────────────────────────────────*/
.whats-on-listing__pagination { display: flex; justify-content: center; }

/* ── Responsive ──────────────────────────────────────────────────────────────*/
@media (max-width: 560px) {
    .whats-on-listing__controls { flex-direction: column; align-items: stretch; }
    .whats-on-listing__controls .search { flex: none; width: 100%; min-width: 0; }
}
 /* what's on archive — filter/search + date-block article rows + pagination */

/* ── sections/_section-heading.css ── */
/* =============================================================================
   NORTH SYDNEY OLYMPIC POOL — Section heading band
   Figma "Top" (1930-13447)
   -----------------------------------------------------------------------------
   A plain full-width centred divider: a big H2 (colour selectable) + a centred
   big-paragraph intro constrained to a readable measure. Optional coloured
   background band; dark bands flip the text to white. Used to introduce runs of
   content on long pages (Facility: "Our Facilities" / "Amenities" / "Facility
   Hire").

   px in comments are the Figma 1920 canvas measurements.
   ============================================================================= */

.section-heading {
    --sh-title: var(--c-blue);
    --sh-intro: var(--c-black);
    padding-block: var(--sp-section);
}
/* Flush bottom (editor toggle) — drop the bottom padding so the heading sits
   directly on the section below without doubling the gap. */
.section-heading--flush-bottom { padding-bottom: 0; }
/* __inner IS .container → rides the 12/6/4 grid; title spans full, intro sits in
   a centred 10-col band → full width at ≤1023. */
.section-heading__inner {
    row-gap: var(--sp-xl);                 /* 30px */
    text-align: center;
}
.section-heading__eyebrow { grid-column: 1 / -1; }
.section-heading__title { grid-column: 1 / -1; }
.section-heading__intro { grid-column: 2 / 12; }   /* 10 cols, centred */
@media (max-width: 1023px) {
    .section-heading__intro { grid-column: 1 / -1; }
}
/* Optional small uppercase label above the heading (Figma 2243-12146 "LEGENDS PLUS"). */
.section-heading__eyebrow {
    margin: 0;
    font-family: var(--f-body); font-size: var(--fs-big-p);   /* 30px */
    line-height: 1.2; text-transform: uppercase;
    color: var(--sh-intro);
}
.section-heading__title {
    margin: 0;
    font-family: var(--f-heading); font-weight: var(--fw-black);
    font-size: var(--fs-h2);               /* 160px @1920 */
    line-height: var(--lh-h2, 0.8);
    text-transform: uppercase;
    color: var(--sh-title);
}
/* Size follows the chosen heading level (editor "Heading size"). */
h1.section-heading__title { font-size: var(--fs-h1); }
h3.section-heading__title { font-size: var(--fs-h3); }
.section-heading__intro {
    margin: 0;
    font-family: var(--f-body); font-size: var(--fs-big-p);   /* 30px */
    line-height: 1.2; color: var(--sh-intro);
}

/* ── Heading colour ─────────────────────────────────────────────────────────*/
.section-heading--tt-blue       { --sh-title: var(--c-blue); }
.section-heading--tt-green      { --sh-title: var(--c-green); }
.section-heading--tt-teal       { --sh-title: var(--c-teal); }
.section-heading--tt-gold       { --sh-title: var(--c-gold); }
.section-heading--tt-terracotta { --sh-title: var(--c-terracotta); }
.section-heading--tt-red        { --sh-title: var(--c-red); }
.section-heading--tt-black      { --sh-title: var(--c-black); }
.section-heading--tt-white      { --sh-title: var(--c-white); }

/* ── Background band (dark bands after, so they win the text colour) ─────────*/
.section-heading--bg-teal       { background: var(--c-teal); }
.section-heading--bg-sandstone  { background: var(--c-sandstone); }
.section-heading--bg-gold       { background: var(--c-gold); }
.section-heading--bg-green      { background: var(--c-green); }
.section-heading--bg-blue       { background: var(--c-blue); }
.section-heading--bg-terracotta { background: var(--c-terracotta); }
.section-heading--bg-green,
.section-heading--bg-blue,
.section-heading--bg-terracotta { --sh-title: var(--c-white); --sh-intro: var(--c-white); }
 /* section heading band — centred H2 + intro divider */

/* ── sections/_facility-cards.css ── */
/* =============================================================================
   NORTH SYDNEY OLYMPIC POOL — Facility cards section
   Figma "Card sections" (1686-5525)
   -----------------------------------------------------------------------------
   Full-width section that arranges .facility-card components (components/_cards.css)
   as a horizontal, snap-scrolling carousel:

     centred H3 heading + big-paragraph intro
       → track of teal facility cards (4 across @1920, peeks 1–2 on smaller screens)
       → PREV · dots · NEXT pagination  (reuses the [data-carousel] engine in main.js)
       → centred CTA button

   Sits on top of the swim / gym / kids hub pages to showcase that area's
   facilities. Spacing/type/colour are all tokens; the px in comments are the
   Figma 1920 canvas measurements. Cards themselves live in _cards.css.
   ============================================================================= */

.facility-cards {
    --fc-pad-y: var(--sp-section);
    --fc-gap-30: max(1.25rem, 1.5625vw);   /*  30px — head: title ↔ intro          */
    padding-block: var(--fc-pad-y);
    background: var(--c-background);
    text-align: center;
}

/* ── Background band variants (editor-controlled via the `background` arg) ─────
   Tint the whole section. Light bands (teal/sandstone/gold) keep the green
   heading + black intro; dark bands (green/blue/terracotta) flip both to white.
   Used e.g. on the Gym hub — terracotta band behind gold facility cards. */
.facility-cards--bg-teal      { background: var(--c-teal); }
.facility-cards--bg-sandstone { background: var(--c-sandstone); }
.facility-cards--bg-gold      { background: var(--c-gold); }
.facility-cards--bg-green      { background: var(--c-green); }
.facility-cards--bg-blue       { background: var(--c-blue); }
.facility-cards--bg-terracotta { background: var(--c-terracotta); }
.facility-cards--bg-green .facility-cards__title,
.facility-cards--bg-blue .facility-cards__title,
.facility-cards--bg-terracotta .facility-cards__title,
.facility-cards--bg-green .facility-cards__intro,
.facility-cards--bg-blue .facility-cards__intro,
.facility-cards--bg-terracotta .facility-cards__intro { color: var(--c-white); }

/* Inner = the .container 12-col grid (repeat(--grid-cols,1fr), see _reset.css).
   The three blocks (head / carousel / CTA) are grid rows that each span the full
   12 columns (1 / -1, the container's default child span) so they line up with
   /foundations/ and every other section on the shared grid. Only the row rhythm
   and the CTA's horizontal centring are set here. */
.facility-cards__inner {
    row-gap: var(--sp-fluid-2xl);          /* ~60px between head, carousel, CTA */
}
/* Grid items are blockified, so the inline-flex .btn would stretch full-width —
   hug + centre it instead. */
.facility-cards__inner > .btn { justify-self: center; }

/* ── Head — green H3 + big-paragraph intro (spans all 12 cols) ───────────────*/
.facility-cards__head {
    grid-column: 2 / 12;          /* centred, 10 of 12 columns */
    display: flex;
    flex-direction: column;
    gap: var(--fc-gap-30);
}
@media (max-width: 1023px) {
    .facility-cards__head { grid-column: 1 / -1; }
}
.facility-cards__title {
    font-family: var(--f-heading); font-weight: var(--fw-black);
    font-size: var(--fs-h3); line-height: .8; text-transform: uppercase;
    color: var(--c-green);
}
/* Optional title colour override (passed via the `class` arg). */
.facility-cards--title-terracotta .facility-cards__title { color: var(--c-terracotta); }
.facility-cards--title-blue .facility-cards__title { color: var(--c-blue); }
.facility-cards__intro {
    font-family: var(--f-body);
    font-size: var(--fs-big-p); line-height: 1.2;
    color: var(--c-black);
}

/* ── Carousel — track + pagination (spans all 12 cols) ───────────────────────*/
.facility-cards__carousel {
    grid-column: 1 / -1;
    min-width: 0;                          /* let the inner scroll track shrink, not overflow the grid */
    display: flex; flex-direction: column; align-items: center;
    gap: var(--sp-lg);
}

/* Horizontal snap-scroll track. --fcard-per = cards visible per view; fractional
   values on smaller screens let the next card peek in to hint the scroll. */
.facility-cards__track {
    --fcard-per: 4;
    display: flex;
    gap: var(--gutter);                    /* 24px column gutter */
    width: 100%;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scrollbar-width: none;                 /* Firefox — hide the bar */
    -ms-overflow-style: none;
    /* Bleed the track to the section edges only on scroll so peeking cards don't
       clip against the page margin — kept simple: track lives inside .container. */
}
.facility-cards__track::-webkit-scrollbar { display: none; }

.facility-cards__track > .facility-card {
    flex: 0 0 calc((100% - (var(--fcard-per) - 1) * var(--gutter)) / var(--fcard-per));
    min-width: 0;                          /* flex min-width:auto would let a long unbreakable
                                              word grow the card past its basis → track overflows
                                              and the last card clips off-screen */
    scroll-snap-align: start;
    text-align: left;                      /* cards read left-aligned inside the centred section */
    min-height: max(24rem, 27.3958vw);     /* 526px — Figma card height (2374-13396); linkless
                                              cards grow their image to fill (--no-link, _cards.css) */
}

/* ── Pagination — PREV · dots · NEXT ─────────────────────────────────────────
   Reuses the shared .pagination component (components/_ui.css) so the Figma
   arrow / sizing / spacing stay in one place. Only the accent colour differs:
   this carousel themes PREV/NEXT + the active dot terracotta (Figma
   "PAGINATION POINT", 1927-10618). */
.pagination--facility { --pg-accent: var(--c-terracotta); }
/* Blue-titled sections (memberships benefits, 2374-13396) theme the pagination to match. */
.facility-cards--title-blue .pagination--facility { --pg-accent: var(--c-blue); }

/* ── Responsive — fewer cards per view, peek the next one ─────────────────────
   ≤1023 the track also BLEEDS to the viewport edges: negative margins pull it
   under the .container page margin so scrolling cards run edge-to-edge instead
   of clipping at the margin. Matching padding + scroll-padding keep the resting
   / snapped cards aligned with the shared grid (border-box: the content box —
   which the card % widths resolve against — stays the container width). */
@media (max-width: 1023px) {           /* tablet */
    .facility-cards__track {
        --fcard-per: 2.2;
        width: calc(100% + 2 * var(--sp-page-x));
        margin-inline: calc(-1 * var(--sp-page-x));
        padding-inline: var(--sp-page-x);
        scroll-padding-inline: var(--sp-page-x);
    }
}
@media (max-width: 767px) {            /* mobile */
    .facility-cards__track { --fcard-per: 1.15; }
    /* Swipe IS the affordance on phones (peeking card hints it) — drop the
       PREV · dots · NEXT chrome. */
    .facility-cards__nav { display: none; }
}
 /* facility carousel — heading + cards + pagination + CTA */

/* ── sections/_program-category.css ── */
/* =============================================================================
   NORTH SYDNEY OLYMPIC POOL — Program category section (tabbed)
   Figma "Card sections / program category" (1686-5527)
   -----------------------------------------------------------------------------
   A hub-page module (e.g. Swim → "Swimming Lessons") that presents a program
   area's categories as .category-card components (components/_cards.css), split
   by an age-group TAB toggle:

     header row (on the 12-col grid):
       • left  (cols 1–5)   green H3 title + big-paragraph subtitle
       • right (cols 9–12)  "Choose your age group:" + .toggle tab switch + note
     panels (full 12 cols): a 3-up row of .category-card, swapped per tab.
     Grid reflows 12 → 6 → 4; header stacks full-width ≤1023.

   Tabs are driven by the generic [data-tabs] engine in assets/js/main.js
   (buttons [data-tab-btn], panels [data-tab-panel], per-tab notes [data-tab-note]).
   The age-group switch reuses the .toggle component (_ui.css). Everything is
   token-driven; px in comments are the Figma 1920 canvas.
   ============================================================================= */

.program-cat {
    padding-block: var(--sp-section);      /* 120px @1920 — shared section padding token */
    background: var(--c-background);
    color: var(--c-black);
}

/* ── Background band variants (editor-controlled via the `background` arg) ─────
   Tint the whole section. Light bands keep the green title + black copy; dark
   bands (green/blue/terracotta) flip title/subtitle/prompt/note to white. Used
   e.g. on the Gym hub — terracotta band behind gold category cards. */
.program-cat--bg-teal      { background: var(--c-teal); }
.program-cat--bg-sandstone { background: var(--c-sandstone); }
.program-cat--bg-gold      { background: var(--c-gold); }
.program-cat--bg-green      { background: var(--c-green); }
.program-cat--bg-blue       { background: var(--c-blue); }
.program-cat--bg-terracotta { background: var(--c-terracotta); }
.program-cat--bg-green,
.program-cat--bg-blue,
.program-cat--bg-terracotta { color: var(--c-white); }
.program-cat--bg-green .program-cat__title,
.program-cat--bg-blue .program-cat__title,
.program-cat--bg-terracotta .program-cat__title,
.program-cat--bg-green .program-cat__sub,
.program-cat--bg-blue .program-cat__sub,
.program-cat--bg-terracotta .program-cat__sub,
.program-cat--bg-green .program-cat__prompt,
.program-cat--bg-blue .program-cat__prompt,
.program-cat--bg-terracotta .program-cat__prompt,
.program-cat--bg-green .program-cat__note,
.program-cat--bg-blue .program-cat__note,
.program-cat--bg-terracotta .program-cat__note { color: var(--c-white); }

/* Inner = the .container 12-col grid. Header intro/controls share row 1, the
   card panels take row 2 full width. Bottom-align the header row so the title
   baseline sits level with the toggle (Figma). */
.program-cat__inner {
    align-items: end;
    row-gap: var(--sp-fluid-2xl);          /* ~60px header → cards */
}

/* ── Header — left intro ─────────────────────────────────────────────────────*/
.program-cat__intro {
    grid-column: 1 / 6;                    /* first 5 cols */
    display: flex; flex-direction: column; gap: var(--sp-lg);
}
.program-cat__title {
    font-family: var(--f-heading); font-weight: var(--fw-black);
    font-size: var(--fs-h3); line-height: .8; text-transform: uppercase;
    color: var(--c-green);
}
.program-cat__sub {
    font-family: var(--f-body);
    font-size: var(--fs-big-p); line-height: 1.2;
    color: var(--c-black);
}

/* ── Header — right controls (prompt + toggle + note) ────────────────────────*/
.program-cat__controls {
    grid-column: 9 / -1;                   /* last 4 cols */
    display: flex; flex-direction: column; gap: var(--sp-lg);
}
.program-cat__prompt {
    font-family: var(--f-body);
    font-size: var(--fs-big-p); line-height: 1.2;
    color: var(--c-black);
}
/* Toggle fills the 4-col controls width; the two tabs split it evenly. */
.program-cat__controls .toggle { align-self: stretch; display: flex; }
.program-cat__controls .toggle__btn { flex: 1; text-align: center; }
.program-cat__note {
    font-family: var(--f-body);
    font-size: var(--fs-body); line-height: 1.2;
    color: var(--c-black);
}
.program-cat__note[hidden] { display: none; }

/* ── Optional decorative brand graphic (single-group layout) ─────────────────
   Replaces the toggle controls: sits in the last 4 cols, right-aligned, and its
   height matches the intro block (grid row stretch → the SVG fills that height).
   The brand graphic is colourless (fill=var(--fill-0,currentColor)) — tint green
   by default; white on dark bands (like the title). */
.program-cat__graphic {
    grid-column: 9 / -1;
    grid-row: 1;                      /* share the header row with the intro (else it wraps below) */
    align-self: stretch;             /* → its height tracks the intro block */
    justify-self: end;
    min-height: 0;
    display: flex;
    align-items: flex-start;          /* top-align with the intro (Figma) */
    justify-content: flex-end;
    color: var(--c-green);
    --fill-0: var(--c-green);
}
.program-cat__graphic-svg {
    height: 100%;
    width: auto;
    max-width: 100%;
    aspect-ratio: 1 / 1;
    object-fit: contain;
    display: block;
}
.program-cat--bg-green .program-cat__graphic,
.program-cat--bg-blue .program-cat__graphic,
.program-cat--bg-terracotta .program-cat__graphic { color: var(--c-white); --fill-0: var(--c-white); }

/* ── Centred heading arrangement (align=center) — title + sub centred, full width */
.program-cat--center .program-cat__intro {
    grid-column: 4 / 10;          /* centred, 6 of 12 columns */
    align-items: center;
    text-align: center;
}
@media (max-width: 1023px) {
    .program-cat--center .program-cat__intro { grid-column: 1 / -1; }
}
.program-cat--center .program-cat__controls { display: none; }   /* no toggle in the centred single-group layout */
.program-cat--center .program-cat__title { color: var(--c-terracotta); }   /* coral heading (Figma) */

/* ── Footnote — centred note below the grid (Legends Plus explainer) ──────────*/
.program-cat__footnote {
    grid-column: 1 / -1;
    text-align: center;
    max-width: 70ch;
    margin-inline: auto;
    font-family: var(--f-body);
    font-size: var(--fs-big-p); line-height: 1.2;
    color: var(--c-black);
}
.program-cat__footnote strong { font-weight: var(--fw-bold); color: var(--c-terracotta); }
.program-cat--bg-green .program-cat__footnote,
.program-cat--bg-blue .program-cat__footnote,
.program-cat--bg-terracotta .program-cat__footnote { color: var(--c-white); }

/* ── Panels — a 3-up row of category cards, one panel per tab ────────────────*/
.program-cat__panels { grid-column: 1 / -1; min-width: 0; }
.program-cat__panel[hidden] { display: none; }
.program-cat__grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: var(--gutter);
}

/* ── Carousel arrangement (layout=carousel) ──────────────────────────────────
   Editor-selected alternative to the grid: each panel becomes a horizontal
   snap-scroll track with PREV · dots · NEXT, reusing the shared [data-carousel]
   engine (main.js) + .pagination component — same recipe as facility-cards.
   --pcard-per = cards visible per view; the fractional values on tablet/mobile
   let the next card peek in to hint the scroll. */
.program-cat__carousel {
    min-width: 0;                          /* let the scroll track shrink, not overflow the grid */
    display: flex; flex-direction: column; align-items: center;
    gap: var(--sp-lg);
}
.program-cat__track {
    --pcard-per: 3;
    display: flex;
    gap: var(--gutter);
    width: 100%;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scrollbar-width: none;                 /* Firefox — hide the bar */
    -ms-overflow-style: none;
}
.program-cat__track::-webkit-scrollbar { display: none; }
.program-cat__track > .category-card {
    flex: 0 0 calc((100% - (var(--pcard-per) - 1) * var(--gutter)) / var(--pcard-per));
    scroll-snap-align: start;
}
/* Terracotta pagination accent (as facility-cards); dark bands flip it white,
   and lift the idle dots off the band for contrast. */
.program-cat--bg-green .program-cat__nav,
.program-cat--bg-blue .program-cat__nav,
.program-cat--bg-terracotta .program-cat__nav { --pg-accent: var(--c-white); }
.program-cat--bg-green .program-cat__nav .pagination__dot:not(.is-active),
.program-cat--bg-blue .program-cat__nav .pagination__dot:not(.is-active),
.program-cat--bg-terracotta .program-cat__nav .pagination__dot:not(.is-active) { background: var(--c-white-50); }

/* ── Responsive — stack the header, reflow the cards ─────────────────────────*/
@media (max-width: 1023px) {           /* tablet */
    .program-cat__intro,
    .program-cat__controls { grid-column: 1 / -1; }
    .program-cat__graphic { display: none; }   /* decorative — drop it when the header stacks */
    .program-cat__grid { grid-template-columns: repeat(2, 1fr); }
    /* Bleed the carousel track to the viewport edges (as facility-cards):
       cards scroll under the page margin; padding + scroll-padding keep the
       resting / snapped cards aligned with the shared grid. */
    .program-cat__track {
        --pcard-per: 2.2;
        width: calc(100% + 2 * var(--sp-page-x));
        margin-inline: calc(-1 * var(--sp-page-x));
        padding-inline: var(--sp-page-x);
        scroll-padding-inline: var(--sp-page-x);
    }
}
@media (max-width: 767px) {            /* mobile */
    .program-cat__grid { grid-template-columns: 1fr; }
    .program-cat__track { --pcard-per: 1.15; }
    /* Swipe IS the affordance on phones (as facility-cards) — drop the nav. */
    .program-cat__nav { display: none; }
}
 /* tabbed program categories — header + toggle + card grid */

/* ── sections/_program-list.css ── */
/* =============================================================================
   NORTH SYDNEY OLYMPIC POOL — Program list section ("Programs in this category")
   Figma "Card sections / class section" (1686-5875)
   -----------------------------------------------------------------------------
   The class/program list on a program-category (taxonomy) single page, e.g.
   Swim → Infants → Seashells / Sea Urchins / Sea Stars:

     small MD-Nichrome section label ("PROGRAMS IN THIS CATEGORY")
       → a stack of full-width white program cards, each:
           left  → age eyebrow · huge blue H2 title · big-paragraph description
           right → a program graphic / photo (rounded)
       → "← BACK TO …" link

   The whole card is a link when a url is given. Everything is token-driven; px in
   comments are the Figma 1920 canvas measurements. Rides the .container 12-col
   grid (each block spans 1 / -1).
   ============================================================================= */

.program-list {
    --pl-pad-y: var(--sp-section);
    padding-block: var(--pl-pad-y);
    background: var(--c-background);
    color: var(--c-black);
}
.program-list__inner { row-gap: var(--sp-fluid-2xl); }   /* ~60px title → list → back */

/* ── Section label ───────────────────────────────────────────────────────────*/
.program-list__title {
    grid-column: 1 / -1;
    font-family: var(--f-heading); font-weight: var(--fw-black);
    font-size: var(--fs-link); line-height: 1; text-transform: uppercase;
    color: var(--c-black);
}

/* ── Card stack ──────────────────────────────────────────────────────────────*/
.program-list__items {
    grid-column: 1 / -1;
    display: flex; flex-direction: column; gap: var(--sp-md);   /* 16px between cards */
}

/* Card rides a 12-col grid: 1 empty col each side (content cols 2–11), the
   legend spans 6 cols and the media the last ~3 — matches the .container 12/6/4. */
.program-item {
    display: grid;
    grid-template-columns: repeat(var(--grid-cols), 1fr);   /* 12 / 6 / 4 — matches .container */
    column-gap: var(--gutter);
    align-items: center;
    padding-block: clamp(1.5rem, 2.08vw, 2.5rem);   /* 40 — inset comes from the empty cols */
    border-radius: var(--r-card); background: var(--c-white); color: var(--c-black);
    text-decoration: none; transition: box-shadow var(--transition);
}
a.program-item:hover, a.program-item:focus-within { box-shadow: var(--sh-drop); }

.program-item__legend { grid-column: 2 / 8; display: flex; flex-direction: column; gap: clamp(1.5rem, 2.08vw, 2.5rem); min-width: 0; }
.program-item__head { display: flex; flex-direction: column; gap: var(--sp-md); }
.program-item__eyebrow { font-family: var(--f-heading); font-weight: var(--fw-black); font-size: var(--fs-link-sm); line-height: 1.1; color: var(--c-black); }
.program-item__title { font-family: var(--f-heading); font-weight: var(--fw-black); font-size: var(--fs-h3); line-height: .8; text-transform: uppercase; color: var(--pl-title, var(--c-blue)); }
/* Accent (per category): blue default (swim lessons) · green (squads/gym) · etc. */
.program-list--green      { --pl-title: var(--c-green); }
.program-list--teal       { --pl-title: var(--c-teal); }
.program-list--gold       { --pl-title: var(--c-gold); }
.program-list--terracotta { --pl-title: var(--c-terracotta); }
.program-item__desc { font-family: var(--f-body); font-size: var(--fs-big-p); line-height: 1.2; color: var(--c-black); }

.program-item__media { grid-column: 9 / 12; width: 100%; aspect-ratio: 402 / 367; border-radius: var(--r-card); overflow: hidden; }
.program-item__media img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* Creature icons: show the whole shape, don't crop the edges. */
.program-item__media--icon { overflow: visible; }
.program-item__media--icon img { object-fit: contain; }

/* ── Back link ───────────────────────────────────────────────────────────────*/
.program-list__back-wrap { grid-column: 1 / -1; }
.program-list__back {
    display: inline-flex; align-items: center; gap: var(--sp-xs);
    font-family: var(--f-heading); font-weight: var(--fw-black); font-size: var(--fs-link); line-height: 1;
    text-transform: uppercase; color: var(--c-black); text-decoration: none;
}
.program-list__back svg { height: 1em; width: auto; transform: rotate(180deg); transition: transform var(--transition); }  /* arrow-next → points left */
.program-list__back:hover svg { transform: rotate(180deg) translateX(.3em); }   /* rotated space → moves left */

/* ── Responsive — 6-col (tablet) then stacked (mobile) ───────────────────────*/
@media (max-width: 1023px) {   /* grid auto-steps to 6 cols via --grid-cols */
    .program-item { padding-inline: clamp(1.5rem, 3vw, 2.5rem); }
    .program-item__legend { grid-column: 1 / 4; }
    .program-item__media  { grid-column: 4 / 7; }
    /* Icons read big at 3 cols — pull them to 2 cols (photos keep the full 3). */
    .program-item__media.program-item__media--icon { grid-column: 5 / 7; }
}
@media (max-width: 767px) {    /* stack */
    .program-item { display: flex; flex-direction: column; align-items: flex-start; gap: var(--sp-lg); }
    .program-item__media { width: 100%; aspect-ratio: 16 / 9; }
    /* Icons don't need the full stacked width — sit them ~2 cols wide, centred. */
    .program-item__media.program-item__media--icon {
        align-self: center; width: 40%; max-width: 180px; aspect-ratio: 1 / 1;
    }
}
   /* program list — "programs in this category" stacked cards */

/* ── sections/_skills.css ── */
/* =============================================================================
   NORTH SYDNEY OLYMPIC POOL — Skills / "What will you learn" section
   Figma "Top" (2066-12707)
   -----------------------------------------------------------------------------
   Optional band on a program-category page: centred H4 heading + big-paragraph
   intro → a centred row of skill markers. Each marker = a teal circle holding a
   green functional icon, with a green MD-Nichrome label beneath. px in comments
   are the Figma 1920 canvas.
   ============================================================================= */

.skills {
    --skills-circle: max(6.25rem, 7.8125vw);   /* 150px — icon disc */
    /* Marker colour = an approved band+ink combination (--combo-* in _tokens.css):
       the disc is the band, the icon is the ink. Default teal; override per
       instance with a .skills--combo-* class (What's Included = sand). */
    --skills-band: var(--combo-teal-band);
    --skills-ink:  var(--combo-teal-ink);
    padding-block: var(--sp-section);
    background: var(--c-background);
    color: var(--c-black);
}

/* Colour combinations — same band+ink pairings shown on /foundations/. */
.skills--combo-teal  { --skills-band: var(--combo-teal-band);  --skills-ink: var(--combo-teal-ink); }
.skills--combo-green { --skills-band: var(--combo-green-band); --skills-ink: var(--combo-green-ink); }
.skills--combo-coral { --skills-band: var(--combo-coral-band); --skills-ink: var(--combo-coral-ink); }
.skills--combo-sand  { --skills-band: var(--combo-sand-band);  --skills-ink: var(--combo-sand-ink); }
.skills--combo-blue  { --skills-band: var(--combo-blue-band);  --skills-ink: var(--combo-blue-ink); }
.skills--combo-page  { --skills-band: var(--combo-page-band);  --skills-ink: var(--combo-page-ink); }

/* __inner IS .container → rides the 12/6/4 grid. Head sits in a centred 8-col
   band; the marker row spans full width (markers stay a centred flex cluster). */
.skills__inner {
    row-gap: var(--sp-fluid-2xl);              /* 80px head → grid */
}
.skills__head { grid-column: 3 / 11; }         /* 8 cols, centred */
.skills__grid { grid-column: 1 / -1; }
@media (max-width: 1023px) {
    .skills__head { grid-column: 1 / -1; }
}

/* ── Head ─────────────────────────────────────────────────────────────────────*/
.skills__head {
    display: flex; flex-direction: column; align-items: center; gap: var(--sp-lg);
    text-align: center;
}
.skills__title {
    font-family: var(--f-heading); font-weight: var(--fw-black);
    font-size: var(--fs-h4); line-height: .8; text-transform: uppercase;
    color: var(--c-black);
}
.skills__intro {
    font-family: var(--f-body); font-size: var(--fs-big-p); line-height: 1.2;
    color: var(--c-black);
}

/* ── Grid of skill markers ────────────────────────────────────────────────────*/
.skills__grid {
    list-style: none; margin: 0; padding: 0;
    display: flex; flex-wrap: wrap; justify-content: center;
    gap: var(--hero-gap-40, max(1.5rem, 2.0833vw));   /* 40px */
    width: 100%;
}
.skills__item {
    display: flex; flex-direction: column; align-items: center; gap: var(--sp-lg);
    width: max(9rem, 10.4167vw);               /* 200px */
    text-align: center;
}
.skills__icon {
    display: inline-flex; align-items: center; justify-content: center;
    width: var(--skills-circle); height: var(--skills-circle);
    border-radius: 50%;
    background: var(--skills-band);            /* combo band */
    color: var(--skills-ink);                  /* combo ink — nsop_icon → currentColor */
}
.skills__icon svg { width: 60%; height: 60%; display: block; }
.skills__label {
    font-family: var(--f-heading); font-weight: var(--fw-black);
    font-size: var(--fs-link); line-height: 1; text-transform: uppercase;
    color: var(--c-black);                     /* labels stay dark */
}

/* ── Responsive ───────────────────────────────────────────────────────────────*/
@media (max-width: 767px) {
    .skills__item { width: max(7rem, 40vw); }
}
         /* skills — "what will you learn" teal-circle icon markers */

/* ── sections/_program-about.css ── */
/* =============================================================================
   NORTH SYDNEY OLYMPIC POOL — Program about + sidebar
   Figma "Text with listing + info block" (1686-5280)
   -----------------------------------------------------------------------------
   The body of a single program page (e.g. Swim → Infants → Sea Stars):

     left  → blue H4 heading · description · "What you will learn:" sub-heading ·
             icon-bullet list (.icon-list) · ENROL button · "← Back to …" link
     right → the .info-panel component (--swim: blue header + starfish + sky cells)

   Two columns, equal height (the back link sits level with the panel's bottom).
   Reuses .icon-list (_ui.css), .info-panel (_info-panel.css) and .btn. px in
   comments are the Figma 1920 canvas.
   ============================================================================= */

.program-about {
    --pa-pad-y: var(--sp-section);
    padding-block: var(--pa-pad-y);
    background: var(--c-background);
    color: var(--c-black);
}

/* __inner IS .container → rides the 12/6/4 grid: text 7 cols (1–7), panel 4 cols
   (9–12), col 8 is the gap. align-items:stretch (grid default) keeps equal height. */
.program-about__inner {
    align-items: stretch;
}

/* ── Left — text column (back link pinned to the bottom) ─────────────────────*/
.program-about__text { grid-column: 1 / 8; min-width: 0; display: flex; flex-direction: column; justify-content: space-between; gap: var(--sp-fluid-xl); }
.program-about__body { display: flex; flex-direction: column; align-items: flex-start; gap: var(--sp-fluid-lg); }   /* ~40px */
.program-about__head { display: flex; flex-direction: column; gap: var(--sp-fluid-lg); width: 100%; }
.program-about__heading { font-family: var(--f-heading); font-weight: var(--fw-black); font-size: var(--fs-h4); line-height: .8; text-transform: uppercase; color: var(--c-blue); }
/* Accent (per program/category): blue default (swim lessons) · green (squads/gym). */
.program-about--green  .program-about__heading { color: var(--c-green); }
.program-about--teal   .program-about__heading { color: var(--c-teal); }
.program-about--gold   .program-about__heading { color: var(--c-gold); }
.program-about--terracotta .program-about__heading { color: var(--c-terracotta); }
.program-about__desc { font-family: var(--f-body); font-size: var(--fs-big-p); line-height: 1.2; color: var(--c-black); }
/* Rich WYSIWYG body (e.g. an event/article) — space stacked paragraphs & lists. */
.program-about__rich > * { margin: 0; }
.program-about__rich > * + * { margin-top: var(--sp-md); }
.program-about__rich :where(h2, h3, h4) { font-family: var(--f-heading); font-weight: var(--fw-black); text-transform: uppercase; color: var(--c-blue); line-height: .9; }
.program-about__rich :where(ul, ol) { padding-left: 1.2em; }
.program-about__rich a { color: var(--c-blue); text-decoration: underline; }

.program-about__learn { display: flex; flex-direction: column; gap: var(--sp-fluid-lg); width: 100%; }   /* sub-heading → list, ~30px */
.program-about__subheading { font-family: var(--f-heading); font-weight: var(--fw-black); font-size: var(--fs-link); line-height: 1; color: var(--c-black); }

/* Back link — MD-Nichrome, arrow-next rotated to point left. */
.program-about__back { display: inline-flex; align-items: center; gap: var(--sp-xs); font-family: var(--f-heading); font-weight: var(--fw-black); font-size: var(--fs-link-sm); line-height: 1.1; text-transform: uppercase; color: var(--c-black); text-decoration: none; }
.program-about__back svg { height: 1em; width: auto; transform: rotate(180deg); transition: transform var(--transition); }
.program-about__back:hover svg { transform: rotate(180deg) translateX(.3em); }

/* ── Right — info-panel sidebar ──────────────────────────────────────────────*/
.program-about__aside { grid-column: 9 / -1; }

/* ── Responsive — stack, panel below the text (grid stays present) ────────────*/
@media (max-width: 1023px) {
    .program-about__inner { row-gap: var(--sp-fluid-xl); }
    .program-about__text,
    .program-about__aside { grid-column: 1 / -1; }
    .program-about__aside { max-width: 544px; }
}
  /* program about + info-panel sidebar (single program body) */

/* ── sections/_contact-form.css ── */
/* =============================================================================
   NORTH SYDNEY OLYMPIC POOL — Contact form + info
   Figma "Form with info" (1698-6296)
   -----------------------------------------------------------------------------
   The contact-page body: a two-column split (equal height) —
     left  → the .form component (interest select · name · phone/email · message
             · SUBMIT, pinned to the bottom)
     right → the .info-panel component (--contact: blue header + sandstone cells:
             hours/phone/email/address rich text + a "Specific Enquiries" link list)

   Pure assembly of existing components (_forms.css + _info-panel.css + .btn); this
   partial only lays out the two columns. px in comments are the Figma 1920 canvas.
   ============================================================================= */

.contact-form {
    --cf-pad-y: var(--sp-section);
    padding-block: var(--cf-pad-y);
    background: var(--c-background);
    color: var(--c-black);
}

/* __inner IS .container → rides the 12/6/4 grid: form 7 cols (1–7), panel 4 cols
   (9–12), col 8 is the gap. align-items:stretch (grid default) keeps equal height. */
.contact-form__inner {
    align-items: stretch;
}

/* Form column — fields group at the top, SUBMIT pinned to the bottom so it sits
   level with the info-panel's base (matches the Figma). */
.contact-form__form { grid-column: 1 / 8; min-width: 0; display: flex; flex-direction: column; justify-content: space-between; gap: var(--sp-fluid-lg); }
.contact-form__form .btn { align-self: flex-start; }   /* hug, don't stretch */

.contact-form__aside { grid-column: 9 / -1; }

/* ── Responsive — stack, panel below the form (grid stays present) ────────────*/
@media (max-width: 1023px) {
    .contact-form__inner { row-gap: var(--sp-fluid-xl); }
    .contact-form__form,
    .contact-form__aside { grid-column: 1 / -1; }
    .contact-form__aside { max-width: 544px; }
}
   /* contact form + info-panel (--contact) two-column body */

/* ── sections/_form-embed.css ── */
/* =============================================================================
   NORTH SYDNEY OLYMPIC POOL — Form embed
   Figma "Register for updates" (2550-20125)
   -----------------------------------------------------------------------------
   A colour band (--bnr-bg/--bnr-ink from nsop_banner_color_style, inline) with
   a third-party form iframe in a white card beside a display heading + copy.
   Rides the container 12/6/4 grid: card 1–6 · copy 8–12, vertically centred.
   ≤1023 both re-span 1/-1 and the copy moves above the card. Iframe heights
   are editor-set inline (--fe-h desktop · --fe-h-m ≤767) — cross-origin forms
   can't be measured, so the whole form must fit without an inner scrollbar.
   ============================================================================= */

.form-embed {
    padding-block: var(--sp-section);
    background: var(--bnr-bg, var(--c-blue));
    color: var(--bnr-ink, var(--c-white));
}

.form-embed__inner { align-items: center; }

/* The white form card — the iframe is the card. Hosted CM forms centre a fixed
   ~660px-max box in the iframe (vertically AND horizontally), so the card HUGS
   that width instead of stretching with the fluid grid — no dead side space on
   wide screens; the editor-set height (content + small buffer) keeps the even
   gap vertical. scrolling="no" on the iframe kills the inner scrollbar. */
.form-embed__card { grid-column: 1 / 7; justify-self: start; width: min(100%, 720px); min-width: 0; background: var(--c-white); border-radius: var(--r-xs); overflow: hidden; }
.form-embed__frame { display: block; width: 100%; height: var(--fe-h, 690px); border: 0; }

.form-embed__copy { grid-column: 8 / -1; min-width: 0; display: flex; flex-direction: column; gap: var(--sp-md-f); }
.form-embed__title { font-family: var(--f-heading); font-weight: var(--fw-black); font-size: var(--fs-h3); line-height: .8; text-transform: uppercase; overflow-wrap: anywhere; }
.form-embed__text { font-family: var(--f-body); font-size: var(--fs-big-p); line-height: 1.2; }

/* ── Responsive — stack, heading above the form (grid stays present) ─────────*/
@media (max-width: 1023px) {
    .form-embed__inner { row-gap: var(--sp-fluid-xl); }
    .form-embed__card,
    .form-embed__copy { grid-column: 1 / -1; }
    .form-embed__copy { order: -1; }
}

@media (max-width: 767px) {
    .form-embed__frame { height: var(--fe-h-m, 820px); }
}
     /* form embed — third-party sign-up form card + heading (colour band) */

/* ── sections/_text-media.css ── */
/* =============================================================================
   NORTH SYDNEY OLYMPIC POOL — Text + media block (flexible content section)
   Figma "Content" arrangements (1593-2643 / 1593-2645 / 1593-2690 / 1686-5247)
   -----------------------------------------------------------------------------
   ONE section, many arrangements. A two-column split: a text column and a media
   column, vertically centred, that the editor arranges:

     • media LEFT or RIGHT               (.text-media--media-right)
     • media = 1, 2 or 3 images          (.text-media__grid--1 / --2 / --3)

   Text column (all optional except heading) stacks:
     badge (.tag-sm) → green heading → description → small text → icon-bullet list
       (bullet = any recolourable NSOP icon, colour via --tm-bullet) → 1–2 buttons.

   Everything is token-driven; px in comments are the Figma 1920 canvas. Reuses
   .tag-sm (_ui.css), the icon set (nsop_icon → currentColor) and .btn (_buttons).
   ============================================================================= */

.text-media {
    --tm-pad-y: var(--sp-section);
    --tm-bg:   var(--c-background);        /* section band (drives the button label) */
    --tm-head: var(--c-green);             /* heading colour (drives the button fill) */
    padding-block: var(--tm-pad-y);
    background: var(--tm-bg);
    color: var(--c-black);
}

/* ── Background band variants (editor-controlled via the `background` arg) ─────
   Tint the whole section. Light bands (teal/sandstone/gold) keep the default
   green heading + black copy — matches Figma's teal "Casual Swim" band. Dark
   bands (green/blue/terracotta) flip the heading + copy to white for contrast.
   Consecutive same-colour sections read as one continuous band (e.g. the swim
   page's teal Casual Swim + Lane Availability pair). */
.text-media--bg-teal      { --tm-bg: var(--c-teal); }
.text-media--bg-sandstone { --tm-bg: var(--c-sandstone); }
.text-media--bg-gold      { --tm-bg: var(--c-gold); }
.text-media--bg-green      { --tm-bg: var(--c-green); }
.text-media--bg-blue       { --tm-bg: var(--c-blue); }
.text-media--bg-terracotta { --tm-bg: var(--c-terracotta); }

/* Dark bands: heading (--tm-head) + body flip to white. */
.text-media--bg-green,
.text-media--bg-blue,
.text-media--bg-terracotta { --tm-head: var(--c-white); color: var(--c-white, #fff); }
.text-media--bg-green .text-media__desc,
.text-media--bg-blue .text-media__desc,
.text-media--bg-terracotta .text-media__desc,
.text-media--bg-green .text-media__small,
.text-media--bg-blue .text-media__small,
.text-media--bg-terracotta .text-media__small,
.text-media--bg-green .text-media__subheading,
.text-media--bg-blue .text-media__subheading,
.text-media--bg-terracotta .text-media__subheading { color: var(--c-white, #fff); }

/* Optional ink overrides (passed via `class`) — win over band flips (declared
   after, equal specificity). `--head-terracotta` recolours only the heading
   (e.g. Timetable coral heading on white); `--ink-gold` recolours the whole
   text block gold (e.g. Personal Training / Teen Gym on the terracotta band). */
.text-media--head-terracotta { --tm-head: var(--c-terracotta); }
.text-media--head-gold { --tm-head: var(--c-gold); }
.text-media--head-blue { --tm-head: var(--c-blue); }   /* e.g. Kids splash/crèche/birthday blocks */
.text-media--head-black { --tm-head: var(--c-black); } /* e.g. migrated Pricing blocks */
.text-media--ink-gold { --tm-head: var(--c-gold); }   /* gold heading … */
.text-media--ink-gold .text-media__desc,
.text-media--ink-gold .text-media__small,
.text-media--ink-gold .icon-list__label { color: var(--c-white); }     /* … white body */

/* Two-column split — 12-col grid: media 6 cols, text 5 cols, 1 empty col between
   them as spacing (media-left: 1–6 · [7] · 8–12; media-right: 1–5 · [6] · 7–12). */
.text-media__inner {
    grid-column: 1 / -1;
    display: grid;
    grid-template-columns: repeat(var(--grid-cols), 1fr);   /* 12 / 6 / 4 — matches .container */
    column-gap: var(--gutter);
    align-items: center;
    min-width: 0;
}
/* Both columns share row 1 — grid-row is explicit so the text (media is first in
   the DOM) can't get auto-placed onto a second row when it sits left of the media. */
.text-media__media { grid-column: 1 / 7; grid-row: 1; min-width: 0; }   /* 6 cols */
.text-media__text  { grid-column: 8 / -1; grid-row: 1; min-width: 0; }  /* 5 cols, col 7 empty */
.text-media--media-right .text-media__media { grid-column: 7 / -1; }  /* 6 cols right */
.text-media--media-right .text-media__text  { grid-column: 1 / 6; }   /* 5 cols left, col 6 empty */

/* Content width — set automatically by image count (text-media.php): a single
   image → --width-10 (this rule); 2–3 images → full 12 (the .text-media__inner
   rule above). --width-10 insets the block to a centred 10 of 12 cols (one empty
   col each side). Desktop only — on the 6/4-col grid (≤1023) it stays full-width.
   The inner keeps its own 12/6/4 repeat, so media/text proportions are unchanged,
   just narrower. */
@media (min-width: 1024px) {
    .text-media--width-10 .text-media__inner { grid-column: 2 / 12; }   /* 10 of 12, centred */
}

/* Full-height / square media (media_fill toggle) — the media column becomes a
   1:1 square that fills the row; images cover it (so they read tall, not short).
   The text column stays vertically centred against it (inner align-items:center). */
.text-media--media-fill .text-media__media { align-self: stretch; }
.text-media--media-fill .media-grid { aspect-ratio: 1 / 1; height: 100%; }
.text-media--media-fill .media-grid__item { aspect-ratio: auto; height: 100%; }
/* Stacked media (media_stack) — two images one above the other, not side-by-side. */
.text-media--media-stack .media-grid--2 { grid-template-columns: 1fr; grid-template-rows: 2fr 3fr; }   /* top 40% · bottom 60% */
.text-media--media-stack .media-grid--2 .media-grid__item { aspect-ratio: auto; }

/* Match media height to text (media_height 'match') — the media is a SQUARE at
   minimum, and stretches taller when the text column outgrows it. Never squat:
   an invisible 1:1 spacer (::before, stacked in the same grid cell) forces the
   row to at least the media width, so a short text column yields a square while
   a long one stretches the images to the full row height (incl. buttons).
   Side-by-side breakpoints only: on the ≤767 stack the media has no row height
   to fill, so it keeps its default ratio. */
@media (min-width: 768px) {
    /* Height = max(square, text): the ::before spacer (in flow, width = column)
       sets the square MINIMUM; the media-grid is position:absolute so the
       image's natural height can't drive the row (in-flow/grid variants let the
       intrinsic image size win — it overflowed the column or grew the row). */
    .text-media--media-match .text-media__media { align-self: stretch; position: relative; }
    .text-media--media-match .text-media__media::before { content: ''; display: block; aspect-ratio: 1 / 1; }
    .text-media--media-match .text-media__media > .media-grid { position: absolute; inset: 0; height: 100%; }
    /* Every arrangement drops its fixed aspect ratio and covers the row height. */
    .text-media--media-match .media-grid--2,
    .text-media--media-match .media-grid--3 { aspect-ratio: auto; grid-auto-rows: 1fr; }
    .text-media--media-match .media-grid__item { aspect-ratio: auto; height: 100%; }
}

/* ── Media column — 1 / 2 / 3 image arrangements via the shared .media-grid ──*/

/* ── Text column ─────────────────────────────────────────────────────────────*/
/* Text stack — fluid structural gap (--sp-*-f, token audit phase 2): identical
   @1920, tightens proportionally below so the gap tracks the shrinking type. */
.text-media__text { display: flex; flex-direction: column; align-items: flex-start; gap: var(--sp-lg-f); }
.text-media__heading { font-family: var(--f-heading); font-weight: var(--fw-black); font-size: var(--tm-fs-head, var(--fs-h3)); line-height: .8; text-transform: uppercase; color: var(--tm-head); }
/* Heading size override (editor "Heading size" select) — visual only, tag stays h2. */
.text-media--size-h1 { --tm-fs-head: var(--fs-h1); }
.text-media--size-h2 { --tm-fs-head: var(--fs-h2); }
.text-media--size-h4 { --tm-fs-head: var(--fs-h4); }
.text-media--size-h5 { --tm-fs-head: var(--fs-h5); }
/* Bold note tucked under the heading (e.g. a price / billing line). Pulls back
   half the stack gap (SAME token as the flex gap above, or the offset drifts) so
   it reads as a subtitle, not a paragraph. */
.text-media__subheading { margin-top: calc(var(--sp-lg-f) * -0.5); font-family: var(--f-heading); font-weight: var(--fw-black); font-size: var(--fs-big-p); line-height: 1.1; color: var(--c-black); }
.text-media__desc { font-family: var(--f-body); font-size: var(--fs-big-p); line-height: 1.2; color: var(--c-black); }
.text-media__small { font-family: var(--f-body); font-size: var(--fs-body); line-height: 1.2; color: var(--c-black); }

/* Icon-bullet list — the shared .icon-list component (_ui.css); bullet colour is
   set inline via --list-bullet from the list.color arg. Labels drop to --fs-body
   here (vs the component default --fs-big-p) so they read like .text-media__small. */
.text-media .icon-list__label { font-size: var(--fs-body); }

/* Numbered list variation (list.style = 'number') — MD Nichrome steps, e.g. the
   Birthday "How it works" flow. Figma: 32px MD Nichrome Black, decimal markers. */
.text-media__ol {
    margin: 0; padding-inline-start: 1.6em; list-style: decimal;
    display: flex; flex-direction: column; gap: var(--sp-md-f);
    font-family: var(--f-heading); font-weight: var(--fw-black);
    font-size: var(--fs-link);        /* 32px, floor 20px */
    line-height: 1; text-transform: uppercase; color: var(--c-black);
}
.text-media__ol li { padding-inline-start: .4em; }
/* Dark bands flip the list to white with the rest of the copy. */
.text-media--bg-green .text-media__ol,
.text-media--bg-blue .text-media__ol,
.text-media--bg-terracotta .text-media__ol { color: var(--c-white); }

/* Price rows variation (list.style = 'price') — hairline-ruled label/note/price
   rows; absorbs the old pricing-media section (docs/text-media-unification.md).
   Visuals mirror _pricing-media.css: display label + body note below, right-
   aligned display price; accent via --tm-price (list.color, default blue). */
.text-media__prices {
    --tm-price: var(--c-blue);
    align-self: stretch;                     /* rules run the full text column */
    list-style: none; margin: 0; padding: 0;
}
.text-media__price-row {
    display: flex; align-items: center; justify-content: space-between;
    gap: var(--gutter);
    padding-block: max(1rem, 1.25vw);        /* 24px */
    border-bottom: 1px solid var(--c-black);
}
.text-media__price-row:last-child { border-bottom: 0; }
.text-media__price-text {
    display: flex; flex-direction: column; gap: max(.5rem, 1.0417vw);   /* 20px */
}
.text-media__price-label {
    font-family: var(--f-heading); font-weight: var(--fw-black);
    font-size: max(1.75rem, 2.8125vw);       /* 54px */
    line-height: 0.85; text-transform: uppercase; color: var(--tm-price);
}
.text-media__price-note {
    font-family: var(--f-body); font-weight: var(--fw-regular);
    font-size: var(--fs-big-p);              /* 30px */
    line-height: 1.2; color: var(--c-black);
}
.text-media__price {
    flex-shrink: 0;
    font-family: var(--f-heading); font-weight: var(--fw-black);
    font-size: var(--fs-h4);                 /* 62px */
    line-height: 0.8; color: var(--tm-price); white-space: nowrap;
}
/* Dark bands flip the rules + notes with the rest of the copy. */
.text-media--bg-green .text-media__price-row,
.text-media--bg-blue .text-media__price-row,
.text-media--bg-terracotta .text-media__price-row { border-bottom-color: var(--c-white); }
.text-media--bg-green .text-media__price-note,
.text-media--bg-blue .text-media__price-note,
.text-media--bg-terracotta .text-media__price-note { color: var(--c-white); }

/* Info-card media (media_type = 'card') — the shared .info-card primitive
   (_booking-info.css). The card rides the site grid at 4 COLS (matching
   booking-info's 546px card @1920) instead of the images' 6; the text column
   widens to 7 so the split mirrors booking-info's text/card proportions. */
.text-media__media > .info-card { width: 100%; }
@media (min-width: 1024px) {
    .text-media--media-card .text-media__media { grid-column: 1 / 5; }   /* 4 cols */
    .text-media--media-card .text-media__text  { grid-column: 6 / -1; }  /* 7 cols, col 5 empty */
    .text-media--media-card.text-media--media-right .text-media__media { grid-column: 9 / -1; } /* 4 cols right */
    .text-media--media-card.text-media--media-right .text-media__text  { grid-column: 1 / 8; }  /* 7 cols, col 8 empty */
}

/* Buttons — 1 or 2, extra run-up above them. */
.text-media__actions { display: flex; flex-wrap: wrap; gap: var(--sp-md); margin-top: var(--sp-2xl-f); }
/* Button fill = heading colour (--tm-head); label = white for legibility on the
   saturated fill (e.g. green pill → white text). On dark bands --tm-head flips to
   white, so the label drops back to the band colour to stay readable. */
.text-media__actions .btn { --btn-bg: var(--tm-head); --btn-fg: var(--c-white); }
.text-media--bg-green .text-media__actions .btn,
.text-media--bg-blue .text-media__actions .btn,
.text-media--bg-terracotta .text-media__actions .btn { --btn-fg: var(--tm-bg); }

/* ── Tablet — grid steps to 6 cols; keep a 3/3 side-by-side split ────────────*/
@media (max-width: 1023px) and (min-width: 768px) {
    .text-media__media { grid-column: 1 / 4; }   /* 3 of 6 cols */
    .text-media__text  { grid-column: 4 / -1; }  /* 3 of 6 cols */
    .text-media--media-right .text-media__media { grid-column: 4 / -1; }
    .text-media--media-right .text-media__text  { grid-column: 1 / 4; }
}

/* ── Responsive — stack media above text ─────────────────────────────────────*/
@media (max-width: 767px) {
    /* keep the 4-col grid present (inspectable) — just full-span the children */
    .text-media__inner { row-gap: var(--sp-2xl-f); align-items: stretch; }
    .text-media__media,
    .text-media__text,
    .text-media--media-right .text-media__media,
    .text-media--media-right .text-media__text { grid-column: 1 / -1; }
    .text-media__media { grid-row: 1; }   /* media above text */
    .text-media__text  { grid-row: 2; }
}
     /* text + media block — flexible content (1–3 imgs, list, buttons) */

/* ── sections/_news-content.css ── */
/* =============================================================================
   NORTH SYDNEY OLYMPIC POOL — News content (article body blocks)
   Figma "just text" (1694-7217) + media / buttons / links / back variants
   -----------------------------------------------------------------------------
   The body of a news / article single: a NARROW, centred column the editor fills
   with a stack of blocks, in any order:

     text · heading · icon-bullet list (configurable bullet shape + colour) ·
     images (1/2/3 via .media-grid) · buttons (1–2) · links · back-to-news link

   Each block owns its internal spacing; the column sets the rhythm between them.
   Reuses .icon-list (_ui.css), .media-grid (_media-grid.css) and .btn. Token-
   driven; px in comments are the Figma 1920 canvas.
   ============================================================================= */

.news-content {
    --nc-pad-y: var(--sp-section);
    padding-block: var(--nc-pad-y);
    background: var(--c-background);
    color: var(--c-black);
}

/* News single = all white (hero inner white in _hero.css; article body white here). */
.single-nsop_news .news-content { background: var(--c-white); }

/* Readable article column = a centred 6-col band of the container's 12/6/4 grid
   (~828px @1920) → full width at ≤1023. Blocks stack as a flex column inside. */
.news-content__inner {
    grid-column: 4 / 10;
    display: flex; flex-direction: column; align-items: stretch;
    gap: var(--sp-fluid-lg);               /* ~40px baseline rhythm between blocks */
}
@media (max-width: 1023px) {
    .news-content__inner { grid-column: 1 / -1; }
}

/* Editor-set column width (Text content section → "Column width"). Centred bands
   of the 12-col grid; --w-narrow (6 cols) is the default above. All collapse to
   full width ≤1023 via the rule above. */
.news-content--w-medium .news-content__inner { grid-column: 3 / 11; }   /* 8 cols */
.news-content--w-wide   .news-content__inner { grid-column: 2 / 12; }   /* 10 cols */
.news-content--w-full   .news-content__inner { grid-column: 1 / -1; }   /* 12 cols */

/* ── Blocks ──────────────────────────────────────────────────────────────────*/
.news-content__heading { font-family: var(--f-heading); font-weight: var(--fw-black); font-size: var(--fs-link); line-height: 1; color: var(--c-black); }

.news-content__text { font-family: var(--f-body); font-size: var(--fs-big-p); line-height: 1.2; color: var(--c-black); }
.news-content__text > * + * { margin-top: var(--sp-md); }   /* 16px between paragraphs */
.news-content__text a { color: var(--c-blue); text-decoration: underline; }
.news-content__text strong, .news-content__text b { font-weight: var(--fw-bold); }

/* Section rhythm for headings within the rich text (Terms / Privacy / policies):
   extra air ABOVE a heading so each section reads as its own block, and a tighter
   gap BELOW so the heading hugs the paragraph it introduces. Overrides the flat
   `* + *` 16px rhythm above. First heading has no run-up (it opens the column). */
.news-content__text > * + :is(h2, h3, h4) { margin-top: var(--sp-2xl-f); }   /* ~48px above */
.news-content__text > :is(h2, h3, h4) + * { margin-top: var(--sp-sm); }      /* ~12px below */
.news-content__text :is(h2, h3, h4) { line-height: 1.1; }

/* Buttons row (1–2) — a little extra run-up (Figma 60px group gap). */
.news-content__buttons { display: flex; flex-wrap: wrap; gap: var(--sp-lg); margin-top: var(--sp-md); }

/* Links block — its own "Links" heading + underlined links. */
.news-content__links { display: flex; flex-direction: column; align-items: flex-start; gap: var(--sp-fluid-lg); margin-top: var(--sp-xl); }
.news-content__link { font-family: var(--f-body); font-size: var(--fs-big-p); line-height: 1.2; color: var(--c-black); text-decoration: underline; text-underline-offset: .12em; word-break: break-word; transition: color var(--transition); }
.news-content__link:hover { color: var(--c-blue); }

/* Back-to-news link — arrow-slim rotated to point left. */
.news-content__back { align-self: flex-start; display: inline-flex; align-items: center; gap: var(--sp-xs); margin-top: var(--sp-lg); font-family: var(--f-heading); font-weight: var(--fw-black); font-size: var(--fs-link-sm); line-height: 1.1; text-transform: uppercase; color: var(--c-black); text-decoration: none; }
.news-content__back svg { height: 1em; width: auto; transform: rotate(180deg); transition: transform var(--transition); }
.news-content__back:hover svg { transform: rotate(180deg) translateX(.3em); }
   /* news content — narrow article column of stacked blocks */

/* ── sections/_more-events.css ── */
/* =============================================================================
   NORTH SYDNEY OLYMPIC POOL — More events section
   Figma "Card sections / more events" (1694-5891)
   -----------------------------------------------------------------------------
   Full-width "related articles" block that closes an event / news single:

     left-aligned green H4 title ("MORE EVENTS")
       → a row of vertical .news-card components (components/_cards.css)

   Three cards across on desktop (they fit the row exactly, so no scrollbar);
   on tablet / mobile the row becomes a horizontal snap-scroll track that peeks
   the next card — the same idiom as facility-cards, minus the pagination chrome
   (this is a short, fixed related set). Spacing/type/colour are all tokens; the
   px in comments are the Figma 1920 canvas measurements.
   ============================================================================= */

.more-events {
    --me-pad-y: var(--sp-section);
    padding-block: var(--me-pad-y);
    background: var(--c-background);
}

/* Inner = the .container 12-col grid. Head + track are rows spanning all 12
   columns so they align with every other section on the shared grid. */
.more-events__inner {
    row-gap: var(--sp-fluid-2xl);      /* ~50px between title and cards */
}

/* ── Head — left-aligned green H4 title (spans all 12 cols) ───────────────────*/
.more-events__head { grid-column: 1 / -1; }
.more-events__title {
    font-family: var(--f-heading); font-weight: var(--fw-black);
    font-size: var(--fs-h4); line-height: .8; text-transform: uppercase;
    color: var(--c-blue);
}

/* ── Track — a row of news cards (spans all 12 cols) ──────────────────────────*/
.more-events__track {
    /* Desktop per-view comes from the template's inline --me-lg (default 3). Read
       it via a fallback var — NOT an inline --me-per — so the tablet/mobile media
       queries below (plain --me-per) can still win; an inline custom property
       would override every stylesheet rule and freeze the carousel at 3-up. */
    --me-per: var(--me-lg, 3);         /* cards visible per view */
    grid-column: 1 / -1;
    min-width: 0;                      /* let the track scroll, not overflow the grid */
    display: flex;
    gap: var(--gutter);                /* 24px column gutter */
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scrollbar-width: none;             /* Firefox — hide the bar */
    -ms-overflow-style: none;
}
.more-events__track::-webkit-scrollbar { display: none; }

.more-events__track > .news-card {
    flex: 0 0 calc((100% - (var(--me-per) - 1) * var(--gutter)) / var(--me-per));
    scroll-snap-align: start;
}

/* ── Responsive — fewer cards per view, peek the next one ─────────────────────
   ≤1023 the track bleeds to the viewport edges (as facility-cards): cards
   scroll under the .container page margin; padding + scroll-padding keep the
   resting / snapped cards aligned with the shared grid. */
@media (max-width: 1023px) {           /* tablet */
    .more-events__track {
        --me-per: 2.2;
        margin-inline: calc(-1 * var(--sp-page-x));
        padding-inline: var(--sp-page-x);
        scroll-padding-inline: var(--sp-page-x);
    }
}
@media (max-width: 767px) {            /* mobile — centred snap carousel */
    .more-events__track {
        --me-per: 1.3;                 /* one card centred, both neighbours peek */
        scroll-padding-inline: 0;      /* centre snap doesn't want the start inset */
    }
    .more-events__track > .news-card { scroll-snap-align: center; }
}
  /* more events — related news cards closing an event/news single */

/* ── sections/_faq.css ── */
/* =============================================================================
   NORTH SYDNEY OLYMPIC POOL — FAQ section
   Figma "FAQ" (1686-7052)
   -----------------------------------------------------------------------------
   A full-width, colour-schemed section that pairs a big display heading with the
   shared .accordion component (components/_ui.css — the Figma "Listing FAQ"):

     [ display heading ]        [ accordion of question / answer items ]
                     … fan scallop line pattern (accent) …

   COLOUR SCHEME: one `.faq--x` modifier sets a trio of custom properties —
   --faq-bg (surface), --faq-accent (heading / questions / +− icon / fans) and
   --faq-ink (answer body + hairlines). Everything below reads those, so picking
   a surface colour re-pairs the whole section. Add a scheme = add one block.

   px in comments are the Figma 1920 canvas; sizes are token / vw-proportional.
   ============================================================================= */

.faq {
    /* Default pairing = teal surface + green accent (straight from Figma). */
    --faq-bg:     var(--c-teal);
    --faq-accent: var(--c-green);
    --faq-ink:    var(--c-black);
    --faq-line:   var(--c-black);

    --faq-pad-y: var(--sp-section);
    --faq-gap:    max(2.5rem, 6.25vw);   /* 120px — row gap above the fan pattern */

    padding-block: var(--faq-pad-y);
    background: var(--faq-bg);
}

/* ── Colour schemes (surface → matched accent + ink) ─────────────────────────*/
.faq--teal      { --faq-bg: var(--c-teal);      --faq-accent: var(--c-green);  --faq-ink: var(--c-black); --faq-line: var(--c-black); }
.faq--green     { --faq-bg: var(--c-green);     --faq-accent: var(--c-teal);   --faq-ink: var(--c-white); --faq-line: var(--c-black); }
.faq--blue      { --faq-bg: var(--c-blue);      --faq-accent: var(--c-sandstone); --faq-ink: var(--c-white); --faq-line: var(--c-black); }
.faq--sandstone { --faq-bg: var(--c-sandstone); --faq-accent: var(--c-green);  --faq-ink: var(--c-black); --faq-line: var(--c-black); }
.faq--sand      { --faq-bg: var(--c-sandstone); --faq-accent: var(--c-blue);   --faq-ink: var(--c-black); --faq-line: var(--c-black); }
.faq--gold      { --faq-bg: var(--c-gold);      --faq-accent: var(--c-terracotta); --faq-ink: var(--c-black); --faq-line: var(--c-black); }
/* List variation: page background, blue heading, dark body, no fan pattern. */
.faq--list      { --faq-bg: var(--c-background); --faq-accent: var(--c-blue);   --faq-ink: var(--c-black); --faq-line: var(--c-black); }

/* ── Inner — .container: stacks the heading+accordion block, then the pattern. */
.faq__inner {
    row-gap: var(--faq-gap);
}

/* Heading (cols 1–4) + accordion (cols 6–12) share their OWN 12/6/4 grid so the
   sticky heading's containing block ends with the accordion — it never sticks
   over the fan pattern (a sibling of this wrapper). Empty col 5 = the ~120px gap. */
.faq__cols {
    grid-column: 1 / -1;
    display: grid;
    grid-template-columns: repeat(var(--grid-cols), 1fr);
    column-gap: var(--gutter);
    row-gap: var(--faq-gap);
    align-items: start;
}

/* ── Heading — display, uppercase, accent colour ─────────────────────────────*/
.faq__title {
    grid-column: 1 / 5;
    grid-row: 1;
    align-self: start;
    position: sticky;
    top: max(6rem, 8vw);              /* stays pinned as the accordion scrolls (clears the header) */
    margin: 0;
    font-family: var(--f-heading);
    font-weight: var(--fw-black);
    font-size: var(--fs-h3);          /* 100px @1920, floors 32px */
    line-height: var(--lh-h3);        /* 0.8 */
    text-transform: uppercase;
    color: var(--faq-accent);
}

/* ── Accordion list — recolour the shared component to the scheme ────────────*/
.faq__list {
    grid-column: 6 / -1;
    grid-row: 1;
    align-self: start;
}
.faq .accordion__item      { border-top-color: var(--faq-line); }
.faq .accordion__item:last-child { border-bottom-color: var(--faq-line); }
.faq .accordion__trigger   { color: var(--faq-accent); }   /* question + the +− icon (currentColor) */
.faq .accordion__panel-inner { color: var(--faq-ink); }
.faq .accordion__panel-inner :where(p, li) { margin: 0; }
.faq .accordion__panel-inner p + p { margin-top: var(--sp-sm); }

/* ── List variation — always-open static list (no accordion), sticky heading ──
   Each item = optional title (H5 54px) + body (big-p). Numbered mode prefixes a
   decimal marker (block <li>, NOT flex, so the marker renders). A <strong> in the
   body renders as a big MD-Nichrome line (e.g. the same-day phone number). */
.faq--list { --faq-title-fs: max(1.75rem, 2.8125vw); }   /* 54px */

/* List mode: 10-col inset (cols 2–11). Heading cols 2–5, content cols 7–11. */
.faq--list .faq__title        { grid-column: 2 / 6; grid-row: 1; }   /* 4 cols, starts col 2 */
.faq--list .faq__list--static { grid-column: 7 / 12; grid-row: 1; }  /* 5 cols, starts col 7 */

.faq__list--static { align-self: start; list-style: none; margin: 0; padding: 0; }
.faq__list--static > li + li { margin-top: max(2.5rem, 4.1667vw); }   /* 80px between items */
.faq__list--numbered { list-style: decimal; padding-inline-start: 1.6em; }
.faq__list-item { color: var(--faq-ink); }               /* also colours the decimal marker */
/* Numbered marker matches the item title exactly (MD Nichrome, not body font). */
.faq__list--numbered .faq__list-item {
    font-family: var(--f-heading); font-weight: var(--fw-black);
    font-size: var(--faq-title-fs); line-height: 0.85;
}
.faq__list-q {
    margin: 0;
    font-family: var(--f-heading); font-weight: var(--fw-black);
    font-size: var(--faq-title-fs); line-height: 0.85;
    text-transform: uppercase; color: var(--faq-ink);
}
.faq__list-a {
    margin-top: max(.75rem, 1.0417vw);                   /* 20px title → body */
    font-family: var(--f-body); font-weight: var(--fw-regular); font-size: var(--fs-big-p); line-height: 1.2; color: var(--faq-ink);
}
.faq__list-a p { margin: 0; }
.faq__list-a p + p { margin-top: var(--sp-md); }
.faq__list-a strong {                                    /* highlight line, e.g. a phone number */
    display: block; margin-top: max(.5rem, .8333vw);
    font-family: var(--f-heading); font-weight: var(--fw-black);
    font-size: var(--faq-title-fs); line-height: 0.85;
}
@media (max-width: 1023px) {
    /* Selectors must MATCH the desktop rules' specificity (.faq--list .faq__…) —
       a bare .faq__list--static loses to the (0,2,0) desktop span, leaving the
       list on cols 7–12 at mobile and crushing the title into implicit tracks. */
    .faq--list .faq__title,
    .faq--list .faq__list--static { grid-column: 1 / -1; grid-row: auto; }
}

/* ── Tables variation (display = 'tables') — price tables, absorbs the old
   pricing-split section (docs/text-media-unification.md). Sticky head (title +
   intro pinned together) left cols 1–5, .pricing-table__* stacks right cols 7–12.
   WHITE band = client-directed exception to the no-white-band rule (Legends
   pricing — see CHANGELOG 2026-07-08 / CLAUDE.md Gotchas); declared after the
   schemes so it wins the --faq-bg pairing. */
.faq--tables {
    --faq-bg:     var(--c-white);
    --faq-accent: var(--c-blue);
    --faq-ink:    var(--c-black);
    --faq-tables-gap: max(2.5rem, 5.2083vw);   /* 100px between stacked tables */
    /* Pricing-table tokens live on .pricing-table; re-declare for the reused
       .pricing-table__* rows/bands sitting under .faq (same as old .pricing-split). */
    --pt-fs:    max(1.75rem, 2.8125vw);   /* 54px — band + row text */
    --pt-pad-y: max(1.25rem, 2.0833vw);   /* 40px — band + row padding */
    --pt-ink:   var(--c-white);           /* band ink (white on blue) */
    --pt-price: var(--c-blue);            /* blue prices (labels stay black) */
}
.faq--tables .faq__head {
    grid-column: 1 / 6;
    grid-row: 1;
    align-self: start;
    position: sticky;
    top: max(6rem, 8vw);
    display: flex;
    flex-direction: column;
    gap: var(--sp-md);
}
.faq--tables .faq__title { position: static; grid-column: auto; }   /* the wrapper sticks, not the title */
.faq__intro {
    margin: 0;
    font-family: var(--f-body);
    font-size: var(--fs-big-p);
    line-height: 1.2;
    color: var(--faq-ink);
}
.faq__tables {
    grid-column: 7 / -1;
    grid-row: 1;
    align-self: start;
    display: flex;
    flex-direction: column;
    gap: var(--faq-tables-gap);
}
@media (max-width: 1023px) {
    .faq--tables .faq__head,
    .faq__tables { grid-column: 1 / -1; grid-row: auto; }
    .faq--tables .faq__head { position: static; margin-bottom: max(2rem, 4vw); }
}

/* ── Sticky-heading opt-out (editor "Sticky heading" toggle off) ─────────────
   Declared after every sticky rule so it wins at equal-or-higher specificity. */
.faq--head-static .faq__title,
.faq--head-static .faq__head { position: static; }

/* ── Fan scallop line pattern — the `fan` brand graphic tiled across the full
   width as a mask, recoloured to the accent. mask-repeat:round rescales the tile
   so a WHOLE number of scallops fits edge-to-edge (no half fans clipped L/R). */
.faq__pattern {
    grid-column: 1 / -1;
    --faq-fan-w: max(2.5rem, 4.1667vw);              /* 80px @1920 — ideal scallop width */
    height: calc(var(--faq-fan-w) * 100.018 / 132.877);  /* fan.svg aspect */
    background-color: var(--faq-accent);
    /* path is relative to THIS partial (assets/css/sections/) — the bundler
       re-prefixes it with `sections/` so it resolves from the bundle root. */
    -webkit-mask-image: url('sections/../../images/graphics/fan.svg');
            mask-image: url('sections/../../images/graphics/fan.svg');
    -webkit-mask-size: var(--faq-fan-w) 100%;
            mask-size: var(--faq-fan-w) 100%;
    -webkit-mask-repeat: round no-repeat;
            mask-repeat: round no-repeat;
    -webkit-mask-position: center;
            mask-position: center;
}

/* ── Reflow: stack heading over accordion on tablet / mobile ─────────────────*/
@media (max-width: 1023px) {
    .faq__title,
    .faq__list { grid-column: 1 / -1; grid-row: auto; }
    .faq__title { position: static; }   /* stacked — no sticky */
    .faq__inner,
    .faq__cols { row-gap: max(2rem, 4vw); }
    .faq__title { margin-bottom: max(1rem, 2vw); }
}
          /* FAQ — display heading + accordion listing (colour-schemed) */

/* ── sections/_memberships.css ── */
/* =============================================================================
   NORTH SYDNEY OLYMPIC POOL — Memberships section
   Figma "MEMBERSHIP BLOCK" (1686-8957)
   -----------------------------------------------------------------------------
   Full-width section presenting a caller-chosen set of membership tiers as a
   3-up row of the .price-block component (components/_cards.css):

     centred blue H3 heading + big-paragraph intro
       → row of .price-block cards (the `featured` one is blue + popped taller)
       → centred "VIEW ALL MEMBERSHIPS" button

   Which tiers appear / which is featured is driven entirely by the template-part
   args, so the same section serves the Memberships hub and a filtered subset on
   the Swim / Gym hubs. px in comments are the Figma 1920 canvas measurements.
   ============================================================================= */

.memberships {
    --mb-pad-y: var(--sp-section);
    --mb-gap:   max(2.5rem, 4.1667vw); /* 80px — head ↔ cards ↔ CTA         */
    padding-block: var(--mb-pad-y);
    background: var(--c-background);
}

/* Inner rides the .container 12-col grid; head / cards / CTA each span all 12
   cols on their own row (the container's default child span). */
.memberships__inner {
    row-gap: var(--mb-gap);
    justify-items: center;
}

/* ── Head — centred blue H3 + big-paragraph intro ────────────────────────────*/
.memberships__head {
    grid-column: 3 / 11;   /* 8 cols, centred */
    display: flex; flex-direction: column; align-items: center; gap: var(--sp-2xl); /* 40px */
    text-align: center;
}
@media (max-width: 1023px) { .memberships__head { grid-column: 1 / -1; } }
.memberships__title {
    margin: 0;
    font-family: var(--f-heading); font-weight: var(--fw-black);
    font-size: var(--fs-h3);            /* 100px @1920, floors 32px */
    line-height: var(--lh-h3);          /* 0.8 */
    text-transform: uppercase;
    color: var(--c-blue);
}
.memberships__intro {
    margin: 0;
    font-family: var(--f-body); font-size: var(--fs-big-p); line-height: 1.2;
    color: var(--c-black);
}

/* ── Cards — 3-up on the 12/6/4 grid (each tier = 4 cols); featured pops taller ─*/
.memberships__grid {
    grid-column: 1 / -1;
    display: grid;
    grid-template-columns: repeat(var(--grid-cols), 1fr);
    align-items: center;                 /* featured card is taller → pops out */
    gap: var(--gutter);                  /* 24px */
    width: 100%;
}
.memberships__grid > * { grid-column: span 4; }

/* ── VIEW ALL button — centred (grid child, so hug it) ───────────────────────*/
.memberships__cta { grid-column: 1 / -1; }

/* ── Reflow ──────────────────────────────────────────────────────────────────
   Tablet (6-col grid): keep 3-up — each tier spans 2 cols.
   Mobile (4-col grid): stack — each tier spans the full width. */
@media (max-width: 1023px) {
    .memberships__grid > * { grid-column: span 2; }
    .memberships__inner { --mb-gap: max(2rem, 4vw); }
}
@media (max-width: 767px) {
    .memberships__grid > * { grid-column: 1 / -1; }   /* full 4-col width — stretch (default) */
}
  /* memberships — 3-up price-block tiers (one featured/blue) */

/* ── sections/_membership-plans.css ── */
/* =============================================================================
   NORTH SYDNEY OLYMPIC POOL — Membership plans
   Figma "Frame 21330" (2243-12442)
   -----------------------------------------------------------------------------
   Sandstone band presenting the membership tiers as detailed plan cards:

     centred blue H2 title + big-paragraph intro
       → row of 2 large "featured" cards (white + image + 160px price)
       → stacked full-width horizontal compact cards (solid colour: accent
         heading + white JOIN on the left, plan details on the right —
         Figma 2243-17543 / 2374-26138)

   The whole plans area rides a centred 10-of-12 column band (Figma 1396/1680).
   CPT-driven (see inc/page-sections.php → membership_plans). Token-driven;
   px in comments = Figma 1920 canvas.
   ============================================================================= */

.membership-plans {
    --mp-pad-y: var(--sp-section);
    --mp-gap:     max(2.5rem, 4.1667vw); /*  80px — head ↔ featured ↔ rows */
    --mp-card-gap: var(--gutter);        /*  24px — between cards in a row */
    padding-block: var(--mp-pad-y);
    background: var(--c-sandstone);
}

/* Inner = .container 12/6/4 grid; head in a centred 8-col band, featured + rows
   ride a centred 10-col band (Figma content width 1396 of 1680). */
.membership-plans__inner { row-gap: var(--mp-gap); }
.membership-plans__featured,
.membership-plans__rows { grid-column: 2 / 12; }   /* 10 cols, centred */
.membership-plans__head { grid-column: 3 / 11; }   /* 8 cols, centred */
@media (max-width: 1023px) {
    .membership-plans__head,
    .membership-plans__featured,
    .membership-plans__rows { grid-column: 1 / -1; }
}

/* ── Head ─────────────────────────────────────────────────────────────────── */
.membership-plans__head {
    display: flex; flex-direction: column; align-items: center;
    gap: var(--sp-2xl);                  /* 40px */
    text-align: center;
}
.membership-plans__title {
    font-family: var(--f-heading); font-weight: var(--fw-black);
    font-size: var(--fs-h2); line-height: .8; text-transform: uppercase;
    color: var(--c-blue);
}
.membership-plans__intro {
    font-family: var(--f-body); font-size: var(--fs-big-p); line-height: 1.2;
    color: var(--c-black);
}

/* ── Featured row — two big white cards, each 5 of the 10-col band ───────────
   Nested repeat(10) tracks align with the outer 12-col grid (same 1fr + gutter). */
.membership-plans__featured {
    display: grid;
    grid-template-columns: repeat(10, 1fr);
    column-gap: var(--gutter);
    row-gap: var(--mp-card-gap);
    align-items: stretch;
}
.membership-plans__featured > * { grid-column: span 5; }
@media (max-width: 1023px) {
    .membership-plans__featured { grid-template-columns: repeat(var(--grid-cols), 1fr); }
    .membership-plans__featured > * { grid-column: 1 / -1; }
}

/* ── Compact rows — stacked full-width horizontal cards ─────────────────────── */
.membership-plans__rows {
    display: flex; flex-direction: column;
    gap: var(--sp-xl);                   /* 30px between cards (Figma 2326-12285) */
}

/* ── Plan card ────────────────────────────────────────────────────────────── */
.plan-card {
    --plan-bg:     var(--c-white);
    --plan-ink:    var(--c-black);
    --plan-label:  var(--c-black);
    --plan-price:  var(--c-blue);
    --plan-accent: var(--c-blue);
    --plan-rule:   rgba(0, 0, 0, .15);
    display: flex; flex-direction: column; align-items: center;
    gap: var(--sp-2xl);                  /* 24–40px */
    padding: var(--sp-2xl) max(1.5rem, 3.125vw);  /* 40px block / 50px inline (Figma) */
    border-radius: var(--r-xs);          /* 4px */
    background: var(--plan-bg);
    color: var(--plan-ink);
    text-align: center;
}

.plan-card__label {
    font-family: var(--f-heading); font-weight: var(--fw-black);
    font-size: var(--fs-link); line-height: 1; text-transform: uppercase;
    color: var(--plan-label);
}
.plan-card__price-block { display: flex; flex-direction: column; align-items: center; gap: var(--sp-lg); }
.plan-card__price {
    font-family: var(--f-heading); font-weight: var(--fw-black);
    line-height: .8; text-transform: uppercase;
    color: var(--plan-price);
}
.plan-card__note {
    max-width: 28ch;
    font-family: var(--f-body); font-size: var(--fs-body); line-height: 1.2;
    color: var(--plan-ink);
}

.plan-card__media {
    width: 100%; aspect-ratio: 586 / 306; overflow: hidden;
    border-radius: var(--r-xs);
}
.plan-card__media img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* Body fills remaining height so the button pins to the bottom (cards align). */
.plan-card__body {
    display: flex; flex-direction: column; align-items: stretch;
    gap: var(--sp-2xl);                  /* 40px — list ↔ button (Figma) */
    width: 100%;
    flex: 1 0 auto; justify-content: space-between;
    text-align: left;
}
.plan-card__divider { width: 100%; height: 0; border: 0; border-top: 1px solid var(--plan-rule); margin: 0 0 var(--sp-xl); }
.plan-card__list { display: flex; flex-direction: column; gap: var(--sp-lg); width: 100%; }
.plan-card__list li {
    position: relative; padding-left: 1.6em;
    font-family: var(--f-body); line-height: 1.2;
    color: var(--plan-ink);
}
.plan-card__list li::before {
    content: ""; position: absolute; left: 0; top: .18em;
    width: .62em; height: .62em; transform: rotate(45deg);
    background: var(--plan-accent);
}
.plan-card--featured .plan-card__cta.btn { width: 100%; }

/* Featured cards — big blue price + image; list text is the big paragraph size. */
.plan-card--featured .plan-card__price { font-size: var(--fs-h2); }
.plan-card--featured .plan-card__list li { font-size: var(--fs-big-p); }

/* ── Compact cards — full-width HORIZONTAL colour card (Figma 2243-17543) ─────
   Left "lead" column: big accent heading (top) + white JOIN button (bottom).
   Right "detail" column: label → price → note → divider → features.
   --plan-head = the heading accent per colour variant. */
.plan-card--compact {
    --plan-ink:    var(--c-white);
    --plan-label:  var(--c-white);
    --plan-price:  var(--c-white);
    --plan-accent: var(--c-white);
    --plan-head:   var(--c-gold);
    --plan-rule:   rgba(255, 255, 255, .3);
    flex-direction: row; align-items: stretch; justify-content: space-between;
    gap: var(--gutter);
    padding: var(--sp-2xl) max(1.5rem, 3.125vw);   /* 40px block / 60px inline */
    text-align: left;
}
.plan-card__lead {
    display: flex; flex-direction: column; align-items: flex-start;
    justify-content: space-between;                 /* heading top, JOIN bottom */
    gap: var(--sp-2xl);
    flex: 0 1 37.9%;                                /* 529 / 1396 */
}
.plan-card__heading {
    font-family: var(--f-heading); font-weight: var(--fw-black);
    font-size: var(--fs-h4); line-height: .8; text-transform: uppercase;  /* 62px */
    color: var(--plan-head);
}
.plan-card__detail {
    display: flex; flex-direction: column; align-items: stretch;
    gap: var(--sp-lg);                              /* 24px rhythm */
    flex: 0 1 46.4%;                                /* 647 / 1396 */
}
.plan-card--compact .plan-card__price-block { align-items: flex-start; text-align: left; }
.plan-card--compact .plan-card__note { max-width: none; }
.plan-card--compact .plan-card__divider { margin: 0; }
.plan-card--compact .plan-card__price { font-size: var(--fs-h4); }
.plan-card--compact .plan-card__list { gap: var(--sp-md); }        /* 16px */
.plan-card--compact .plan-card__list li { font-size: var(--fs-body); }
/* White JOIN button takes the card colour as its label ink (Figma). */
.plan-card--compact .plan-card__cta.btn { --btn-fg: var(--plan-bg); }

.plan-card--terracotta { --plan-bg: var(--c-terracotta); --plan-head: var(--c-gold); }
.plan-card--green      { --plan-bg: var(--c-green);      --plan-head: var(--c-teal); }
.plan-card--blue       { --plan-bg: var(--c-blue);       --plan-head: var(--c-sandstone); }
.plan-card--gold       { --plan-bg: var(--c-gold);  --plan-head: var(--c-terracotta); --plan-ink: var(--c-terracotta); --plan-label: var(--c-terracotta); --plan-price: var(--c-terracotta); --plan-accent: var(--c-terracotta); --plan-rule: rgba(137,53,31,.3); }
.plan-card--teal       { --plan-bg: var(--c-teal);  --plan-head: var(--c-green); --plan-ink: var(--c-green); --plan-label: var(--c-green); --plan-price: var(--c-green); --plan-accent: var(--c-green); --plan-rule: rgba(0,84,67,.3); }
.plan-card--sandstone  { --plan-bg: #efe0c6; --plan-head: var(--c-blue); --plan-ink: var(--c-black); --plan-label: var(--c-black); --plan-price: var(--c-blue); --plan-accent: var(--c-blue); --plan-rule: rgba(0,0,0,.15); }

/* ── Responsive — compact card stacks: heading → details → JOIN ─────────────── */
@media (max-width: 1023px) {
    .plan-card--compact { flex-direction: column; align-items: stretch; }
    .plan-card--compact .plan-card__lead { display: contents; }
    .plan-card--compact .plan-card__heading { order: -1; }
    .plan-card--compact .plan-card__cta.btn { order: 10; }
}
 /* membership plans — sandstone band: featured cards + aside/compact-card rows (CPT-driven) */

/* ── sections/_member-support.css ── */
/* =============================================================================
   NORTH SYDNEY OLYMPIC POOL — Member support ("Complementary Member Support")
   Figma "Text block" (1930-14122)
   -----------------------------------------------------------------------------
   A tinted band listing what's included with a membership:

     centred H3 heading + big-paragraph intro
       → a row of solid-colour support cards (icon + H5 title + body)
       → an optional full-width feature banner (H4 + LEARN MORE + image)

   Two editor "controls" drive the colour:
     • .member-support--bg-{colour}   the section band
     • .member-support__card--{colour} the support cards
   (The feature banner is the shared .promo-banner component — see _cards.css.)
   Light bands keep the terracotta heading + black intro; dark bands flip to
   white for contrast. Everything is token-driven; px in comments = Figma 1920.
   ============================================================================= */

.member-support {
    --ms-pad-y: var(--sp-section);
    --ms-gap:   max(2rem, 3.125vw);        /*  60px — head ↔ cards ↔ banner */
    --ms-title: var(--c-terracotta);       /* heading colour (editor control) */
    padding-block: var(--ms-pad-y);
    text-align: center;
}

/* ── Band colour variants (control 1) ────────────────────────────────────────*/
.member-support--bg-gold       { background: var(--c-gold); }
.member-support--bg-teal       { background: var(--c-teal); }
.member-support--bg-sandstone  { background: var(--c-sandstone); }
.member-support--bg-green      { background: var(--c-green); }
.member-support--bg-blue       { background: var(--c-blue); }
.member-support--bg-terracotta { background: var(--c-terracotta); }

/* Inner = the .container 12/6/4 grid; head, cards + banner all span the full 12/6/4.
   (The feature banner is the shared .promo-banner component — styled in _cards.css.) */
.member-support__inner { row-gap: var(--ms-gap); }
.member-support__head,
.member-support__cards { grid-column: 1 / -1; }

/* ── Head — terracotta H3 + black big-paragraph intro ────────────────────────*/
.member-support__head { display: flex; flex-direction: column; gap: var(--sp-lg); align-items: center; }
.member-support__title {
    font-family: var(--f-heading); font-weight: var(--fw-black);
    font-size: var(--fs-h3); line-height: .8; text-transform: uppercase;
    color: var(--ms-title);
}
/* Heading colour override (editor control; dark-band flip below still wins). */
.member-support--head-blue       { --ms-title: var(--c-blue); }
.member-support--head-green      { --ms-title: var(--c-green); }
.member-support--head-teal       { --ms-title: var(--c-teal); }
.member-support--head-gold       { --ms-title: var(--c-gold); }
.member-support--head-terracotta { --ms-title: var(--c-terracotta); }
.member-support--head-black      { --ms-title: var(--c-black); }
.member-support--head-white      { --ms-title: var(--c-white); }
.member-support__intro {
    font-family: var(--f-body); font-size: var(--fs-big-p); line-height: 1.2;
    color: var(--c-black);
}
/* Dark bands: flip heading + intro to white. */
.member-support--bg-green .member-support__title,
.member-support--bg-blue .member-support__title,
.member-support--bg-terracotta .member-support__title { color: var(--c-white); }
.member-support--bg-green .member-support__intro,
.member-support--bg-blue .member-support__intro,
.member-support--bg-terracotta .member-support__intro { color: var(--c-white); }

/* ── Support cards (control 2) — icon + H5 + body ────────────────────────────*/
/* Cards span the full 12/6/4 grid; each card = 4 cols (3-up) → 3 cols (2-up) → full. */
.member-support__cards {
    display: grid;
    grid-template-columns: repeat(var(--grid-cols), 1fr);
    gap: var(--gutter);                    /* 24px */
    text-align: left;
}
.member-support__card { grid-column: span 4; }
.member-support__card {
    --ms-card-bg:  var(--c-terracotta);
    --ms-card-ink: var(--c-white);
    display: flex; flex-direction: column; align-items: flex-start;
    gap: var(--sp-md);                     /* 16px between icon/title/body */
    padding: max(1.5rem, 3.125vw) max(1.5rem, 3.125vw);  /* 60px inline / ~30px block below via title spacing */
    padding-block: max(1.25rem, 1.5625vw); /* 30px */
    border-radius: var(--r-card);
    background: var(--ms-card-bg);
    color: var(--ms-card-ink);
}
.member-support__card--terracotta { --ms-card-bg: var(--c-terracotta); --ms-card-ink: var(--c-white); }
.member-support__card--green      { --ms-card-bg: var(--c-green);      --ms-card-ink: var(--c-white); }
.member-support__card--blue       { --ms-card-bg: var(--c-blue);       --ms-card-ink: var(--c-white); }
.member-support__card--teal       { --ms-card-bg: var(--c-teal);       --ms-card-ink: var(--c-green); }
.member-support__card--gold       { --ms-card-bg: var(--c-gold);       --ms-card-ink: var(--c-terracotta); }
.member-support__card--sandstone  { --ms-card-bg: var(--c-sandstone);  --ms-card-ink: var(--c-black); }

.member-support__icon {
    display: grid; place-items: center;
    width: max(3rem, 4.1667vw); height: max(3rem, 4.1667vw);  /* 80px */
    color: var(--ms-card-ink);
}
.member-support__icon svg { width: 100%; height: 100%; }
/* Icon, title and body are one 16px-gap stack (Figma TEXT BLOCK gap-16); the
   card's flex `gap: --sp-md` already spaces them — no extra icon margin. */
.member-support__card-title {
    font-family: var(--f-heading); font-weight: var(--fw-black);
    font-size: var(--fs-h5); line-height: .85; text-transform: uppercase;
    color: var(--ms-card-ink);
}
.member-support__card-desc {
    font-family: var(--f-body); font-size: var(--fs-body); line-height: 1.2;
    color: var(--ms-card-ink);
}

/* ── Feature banner ───────────────────────────────────────────────────────────
   Now the shared .promo-banner component (see _cards.css) — no bespoke banner
   layout/colour here. Colour comes from nsop_banner_color_style() inline. */

/* ── Responsive ──────────────────────────────────────────────────────────────*/
@media (max-width: 1023px) {
    .member-support__card { grid-column: span 3; }   /* 2-up on the 6-col grid */
}
@media (max-width: 767px) {
    .member-support__card { grid-column: 1 / -1; }    /* 1-up on the 4-col grid */
}
 /* member support — tinted band: heading + support cards + feature banner */

/* ── sections/_transport.css ── */
/* =============================================================================
   NORTH SYDNEY OLYMPIC POOL — Transport options (tabbed) section
   Figma "Tab with image" (1758-9784)
   -----------------------------------------------------------------------------
   Two-column split on the .container grid: a tabbed text block (blue H3 → .tabs
   row → per-tab title + .icon-list) on the left, one image filling the column
   height on the right. Tabs reuse the [data-tabs] engine + the .tab underline
   component (_ui.css). The "Visit Us → Transport Options" module.

   px in comments are the Figma 1920 canvas measurements.
   ============================================================================= */

.transport {
    --tr-pad-y: var(--sp-section);
    --tr-stack-gap:  max(2rem, 3.125vw);      /*  60px — heading ↔ tab-nav          */
    --tr-panel-gap:  max(1.25rem, 1.5625vw);  /*  30px — tabs ↔ panel, title ↔ list */
    padding-block: var(--tr-pad-y);
    background: var(--c-background);
}

/* Inner rides the .container 12-col grid; text block + image sit on one row and
   stretch to equal height (grid default), so the image matches the text height. */
.transport__inner { align-items: start; }

.transport__main  { grid-column: 1 / 8; align-self: stretch; }
.transport__media { grid-column: 8 / -1; }
.transport--media-left .transport__main  { grid-column: 6 / -1; }
.transport--media-left .transport__media { grid-column: 1 / 6; grid-row: 1; }

/* ── Text block — heading + tab nav ──────────────────────────────────────────*/
.transport__main {
    display: flex; flex-direction: column; justify-content: space-between;
    gap: var(--tr-stack-gap);
}
.transport__title {
    margin: 0;
    font-family: var(--f-heading); font-weight: var(--fw-black);
    font-size: var(--fs-h3);          /* 100px @1920, floors 32px */
    line-height: var(--lh-h3);        /* 0.8 */
    text-transform: uppercase;
    color: var(--c-black);
}

.transport__nav { display: flex; flex-direction: column; gap: var(--tr-panel-gap); }
/* Keep the tab row on ONE line (shared .tabs wraps by default → FERRY dropped to
   a 2nd line on narrow screens). Never wrap; scroll horizontally if it overflows. */
.transport .tabs {
    flex-wrap: nowrap;
    overflow-x: auto;
    scrollbar-width: none;                     /* Firefox — hide the scrollbar */
}
.transport .tabs::-webkit-scrollbar { display: none; }   /* WebKit — hide the scrollbar */
.transport .tab { flex: 0 0 auto; white-space: nowrap; }  /* don't shrink / break labels */
/* Toggle: sand band + blue ink (idle underline blue, active = sand fill + blue). */
.transport .tab {
    text-transform: uppercase;                 /* CAR · TRAIN · BUS · FERRY */
    color: var(--c-blue); border-bottom-color: var(--c-blue);
}
.transport .tab.is-active {
    background: var(--c-sandstone); color: var(--c-blue); border-bottom-color: var(--c-blue);
}

.transport__panel { display: flex; flex-direction: column; gap: var(--tr-panel-gap); }
.transport__panel[hidden] { display: none; }   /* author display:flex would otherwise beat [hidden] */
.transport__panel-title {
    margin: 0;
    font-family: var(--f-heading); font-weight: var(--fw-black);
    font-size: max(1.75rem, 2.8125vw);   /* 54px @1920, floors 28px */
    line-height: 0.85;
    text-transform: uppercase;
    color: var(--c-black);
}

/* ── Image — 5-col square (1:1); one per tab, swaps with the active tab.
      The square image sets the row height, keeping the section compact. ───────*/
.transport__media {
    align-self: start;
    aspect-ratio: 1 / 1;
    border-radius: var(--r-card); overflow: hidden;
    background: var(--c-navy-10);
}
.transport__media-img { display: block; width: 100%; height: 100%; object-fit: cover; }
.transport__media-img[hidden] { display: none; }

/* ── Reflow: stack (text then image) on tablet / mobile ──────────────────────*/
@media (max-width: 1023px) {
    .transport__main,
    .transport--media-left .transport__main  { grid-column: 1 / -1; grid-row: auto; }
    .transport__media,
    .transport--media-left .transport__media { grid-column: 1 / -1; grid-row: auto; }
    .transport__media { aspect-ratio: 4 / 3; }
    .transport__inner { row-gap: var(--tr-stack-gap); }
    .transport { --tr-stack-gap: max(2rem, 5vw); }
}
@media (max-width: 767px) {
    /* Tighter horizontal padding helps all four tabs sit on one line at phone
       widths; the nowrap + overflow-x scroll above still covers any overflow. */
    .transport .tab { padding-inline: 0.9em; }
}
    /* transport options — tabbed text block + image (Visit Us) */

/* ── sections/_find-us.css ── */
/* =============================================================================
   NORTH SYDNEY OLYMPIC POOL — Find us here section
   Figma "Text block" (1830-12047)
   -----------------------------------------------------------------------------
   Two stacked rows on the .container grid (children span 1 / -1):
     1. top   → blue H3 + address listing (left) beside a map (right).
     2. hours → a row of opening-hours blocks (blue title header + day/time cells).
   The map/intro stack at ≤1023; the hours row reflows 4 → 2 → 1 columns.

   px in comments are the Figma 1920 canvas measurements.
   ============================================================================= */

.find-us {
    padding-block: var(--sp-section);
    background: var(--c-background);
}
.find-us__inner { row-gap: max(2.5rem, 5.2083vw); align-items: start; }   /* 100px between rows */
.find-us__top,
.find-us__hours { grid-column: 1 / -1; }

/* ── Top: intro + map ────────────────────────────────────────────────────────*/
.find-us__top {
    display: flex;
    gap: max(2rem, 3.125vw);              /* ~60px */
    align-items: stretch;
}
.find-us__intro {
    flex: 1 1 0; min-width: 0;
    display: flex; flex-direction: column; justify-content: flex-start;
    gap: max(1rem, 1.5625vw);             /* 30px heading ↔ address */
}
.find-us__title {
    margin: 0;
    font-family: var(--f-heading); font-weight: var(--fw-black);
    font-size: var(--fs-h3);              /* 100px @1920 */
    line-height: var(--lh-h3);            /* 0.8 */
    text-transform: uppercase;
    color: var(--c-blue);
}
.find-us__address { display: flex; flex-direction: column; gap: var(--sp-md); }   /* 16px */
.find-us__address-label {
    margin: 0;
    font-family: var(--f-heading); font-weight: var(--fw-black);
    font-size: var(--fs-link);            /* 32px @1920 */
    line-height: 1; text-transform: uppercase;
    color: var(--c-black);
}
.find-us__address-line {
    margin: 0;
    font-family: var(--f-body); font-size: var(--fs-big-p);   /* 30px */
    line-height: 1.2; color: var(--c-black);
}
.find-us__map {
    flex: 2 1 0; min-width: 0;
    border-radius: var(--r-card); overflow: hidden;
    aspect-ratio: 1111 / 478;
    background: var(--c-navy-10);
}
.find-us__map iframe,
.find-us__map img { display: block; width: 100%; height: 100%; border: 0; object-fit: cover; }

/* ── Hours: opening-hours blocks ─────────────────────────────────────────────*/
.find-us__hours {
    display: grid;
    grid-template-columns: repeat(var(--hours-cols, 4), minmax(0, 1fr));
    gap: var(--gutter);
}
.hours-block {
    display: flex; flex-direction: column;
    /* Per-block colour theme (Figma 1830-12060): header band + accent title + day label. */
    --hb-band: var(--c-blue);
    --hb-title: var(--c-white);
    --hb-day: var(--c-blue);
}
.hours-block--green      { --hb-band: var(--c-green);      --hb-title: var(--c-teal);      --hb-day: var(--c-green); }
.hours-block--terracotta { --hb-band: var(--c-terracotta); --hb-title: var(--c-gold);      --hb-day: var(--c-terracotta); }
.hours-block--blue       { --hb-band: var(--c-blue);       --hb-title: var(--c-sandstone); --hb-day: var(--c-blue); }
.hours-block--teal       { --hb-band: var(--c-teal);       --hb-title: var(--c-green);     --hb-day: var(--c-green); }
.hours-block__title {
    background: var(--hb-band); color: var(--hb-title);
    font-family: var(--f-heading); font-weight: var(--fw-black);
    font-size: max(1.75rem, 2.8125vw);    /* 54px @1920 */
    line-height: 0.85; text-transform: uppercase; text-align: center;
    padding: max(1rem, 1.5625vw) var(--sp-md);   /* 30px */
    border-bottom: 1px solid var(--c-white);
}
.hours-block__row {
    background: var(--c-white);
    border-bottom: 2px solid var(--c-background);
    padding: max(.9rem, 1.25vw);          /* 24px */
    display: flex; flex-direction: column; align-items: center; gap: var(--sp-xs);
    text-align: center;
}
.hours-block__day {
    margin: 0;
    font-family: var(--f-heading); font-weight: var(--fw-black);
    font-size: var(--fs-link);            /* 32px @1920 */
    line-height: 1; text-transform: uppercase;
    color: var(--hb-day);
}
.hours-block__time {
    margin: 0;
    font-family: var(--f-body); font-size: var(--fs-body);   /* 20px */
    line-height: 1.2; color: var(--c-black);
}

/* ── Reflow ──────────────────────────────────────────────────────────────────*/
@media (max-width: 1023px) {
    .find-us__top { flex-direction: column; }
    /* Stacked: reset the row's flex-basis:0 so aspect-ratio sets the height
       (in a content-height column container flex-grow has no space to fill). */
    .find-us__map { flex: 0 0 auto; width: 100%; aspect-ratio: 16 / 9; }
    .find-us__hours { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 560px) {
    .find-us__hours { grid-template-columns: 1fr; }
}
      /* find us here — heading + address + map + opening-hours blocks (Visit Us) */

/* ── sections/_entry-fees.css ── */
/* =============================================================================
   NORTH SYDNEY OLYMPIC POOL — Casual entry fees section
   Figma "Text block" (1844-12641)
   -----------------------------------------------------------------------------
   Centred colour band (default blue): white H3 + intro → a row of white fee
   cards (brand graphic → coloured H4 → copy → coloured "VIEW … →" link) → a
   centred white primary link. Cards reflow 2 → 1 column at ≤767.

   px in comments are the Figma 1920 canvas measurements.
   ============================================================================= */

.entry-fees {
    --ef-ink: var(--c-white);
    padding-block: var(--sp-section);
}
.entry-fees--bg-blue       { background: var(--c-blue);       --ef-ink: var(--c-white); }
.entry-fees--bg-teal       { background: var(--c-teal);       --ef-ink: var(--c-green); }
.entry-fees--bg-green      { background: var(--c-green);      --ef-ink: var(--c-white); }
.entry-fees--bg-terracotta { background: var(--c-terracotta); --ef-ink: var(--c-white); }
.entry-fees--bg-gold       { background: var(--c-gold);       --ef-ink: var(--c-terracotta); }
.entry-fees--bg-sandstone  { background: var(--c-sandstone);  --ef-ink: var(--c-blue); }

.entry-fees__inner { row-gap: max(2rem, 3.125vw); justify-items: center; }   /* 60px */
.entry-fees__cta { grid-column: 1 / -1; }
.entry-fees__cards { grid-column: 2 / 12; }   /* 10 cols, centred */
.entry-fees__head { grid-column: 3 / 11; }   /* 8 cols, centred */

.entry-fees__head {
    display: flex; flex-direction: column; align-items: center; gap: var(--sp-lg);
    text-align: center;
}
.entry-fees__title {
    margin: 0;
    font-family: var(--f-heading); font-weight: var(--fw-black);
    font-size: var(--fs-h3);              /* 100px @1920 */
    line-height: var(--lh-h3);            /* 0.8 */
    text-transform: uppercase; color: var(--ef-ink);
}
.entry-fees__intro {
    margin: 0;
    font-family: var(--f-body); font-size: var(--fs-big-p);   /* 30px */
    line-height: 1.2; color: var(--ef-ink);
}

.entry-fees__cards {
    display: grid; grid-template-columns: repeat(var(--grid-cols), 1fr);
    gap: var(--gutter); width: 100%;
}
.entry-fee-card { grid-column: span 6; }   /* 2-up on the 12-col grid */
.entry-fee-card {
    --efc-accent: var(--c-green);
    background: var(--c-white); border-radius: var(--r-card);
    padding: max(1.5rem, 1.5625vw) max(1.5rem, 3.125vw);   /* 30px / 60px */
    display: flex; flex-direction: column; gap: var(--sp-md);
    min-height: max(16rem, 20.8333vw);    /* 400px */
}
.entry-fee-card--green      { --efc-accent: var(--c-green); }
.entry-fee-card--terracotta { --efc-accent: var(--c-terracotta); }
.entry-fee-card--teal       { --efc-accent: var(--c-teal); }
.entry-fee-card--blue       { --efc-accent: var(--c-blue); }
.entry-fee-card--gold       { --efc-accent: var(--c-gold); }
.entry-fee-card__graphic {
    display: inline-flex; color: var(--efc-accent);
    height: calc(var(--fs-h4) * 1.5);   /* 1.5× the card title (H4) text height */
    margin-bottom: var(--sp-xs);
}
.entry-fee-card__graphic svg { height: 100%; width: auto; display: block; }
.entry-fee-card__title {
    margin: 0;
    font-family: var(--f-heading); font-weight: var(--fw-black);
    font-size: var(--fs-h4);              /* 62px @1920 */
    line-height: 0.8; text-transform: uppercase; color: var(--efc-accent);
}
.entry-fee-card__desc {
    margin: 0;
    font-family: var(--f-body); font-size: var(--fs-big-p);   /* 30px */
    line-height: 1.2; color: var(--c-black);
}
.entry-fee-card__link { margin-top: auto; color: var(--efc-accent); }

.entry-fees__cta { color: var(--ef-ink); }

@media (max-width: 1023px) {
    .entry-fees__head,
    .entry-fees__cards { grid-column: 1 / -1; }   /* grid reflows to 6/4 cols — span full */
}
@media (max-width: 1023px) {
    .entry-fee-card { grid-column: span 3; }   /* 2-up on the 6-col grid */
}
@media (max-width: 767px) {
    .entry-fee-card { grid-column: 1 / -1; min-height: 0; }   /* 1-up on the 4-col grid */
}
   /* casual entry fees — blue band: heading + fee cards + pricing link (Visit Us) */

/* ── sections/_pricing-table.css ── */
/* =============================================================================
   NORTH SYDNEY OLYMPIC POOL — Pricing table section
   Figma "Casual Entry" pricing (2439-36522)
   -----------------------------------------------------------------------------
   A single price list: a full-width coloured header band + a stack of rows
   (label [+ small note]  …  price) split by hairline rules, last row none.

   The editor adds one section per list and picks the band colour on each, so a
   page can stack several (Aquatic Centre / Visit Pass / Gym Only). The block is
   centred and inset from the page edge (Figma 262px @1920): it spans 10 of the
   12 grid columns (2 / 12), which — with the 120px page padding + 24px gutter —
   lands exactly on the Figma inset. Reflows to full width at ≤1023.

   Type follows the theme's viewport-proportional model — max(rem floor, vw) so
   the list scales with the screen like --fs-*. px in comments = Figma 1920 canvas.
   ============================================================================= */

.pricing-table {
    /* Row/heading text is Figma "H5" 54px — between the theme --fs-h5 (36) and
       --fs-h4 (62), so it gets its own local token on the same vw model. */
    --pt-fs:    max(1.75rem, 2.8125vw);   /* 54px */
    --pt-pad-y: max(1.25rem, 2.0833vw);   /* 40px — band + row vertical padding */
    --pt-ink:   var(--c-white);           /* band ink, per colour below */
    --pt-price: var(--c-black);           /* price ink (override per section, e.g. blue) */

    padding-block: max(1.5rem, 2.6042vw); /* 50px → stacked tables sit 100px apart (Figma gap-100) */
}

/* Centred, inset table — 10 of 12 cols (2 / 12) = the Figma 262px page inset. */
.pricing-table .container {
    display: grid;
    grid-template-columns: repeat(var(--grid-cols), 1fr);
    column-gap: var(--gutter);
}
.pricing-table__inner { grid-column: 2 / 12; }

/* ── Header band ──────────────────────────────────────────────────────────────*/
.pricing-table__head {
    display: flex;
    align-items: center;
    justify-content: center;
    padding-block: var(--pt-pad-y);
    background: var(--c-green);           /* per-colour override below */
    border-bottom: 1px solid var(--c-white);
    text-align: center;
}
.pricing-table__head--stack { flex-direction: column; gap: max(.25rem, .4167vw); }   /* title + subtitle */
.pricing-table__title {
    margin: 0;
    font-family: var(--f-heading);
    font-weight: var(--fw-black);
    font-size: var(--pt-fs);
    line-height: 0.85;
    text-transform: uppercase;
    color: var(--pt-ink);
}
/* Small band subtitle under the title, e.g. "Billed fortnightly". */
.pricing-table__subtitle {
    margin: 0;
    font-family: var(--f-body);
    font-size: var(--fs-body);
    line-height: 1.2;
    color: var(--pt-ink);
}

/* ── Band colours + legible ink (mirrors the entry-fees / --combo pairings) ───*/
.pricing-table--green      .pricing-table__head { background: var(--c-green); }
.pricing-table--blue       .pricing-table__head { background: var(--c-blue); }
.pricing-table--terracotta .pricing-table__head { background: var(--c-terracotta); }
.pricing-table--teal       .pricing-table__head { background: var(--c-teal); }
.pricing-table--gold       .pricing-table__head { background: var(--c-gold); }
.pricing-table--sandstone  .pricing-table__head { background: var(--c-sandstone); }

.pricing-table--teal      { --pt-ink: var(--c-green); }
.pricing-table--gold      { --pt-ink: var(--c-terracotta); }
.pricing-table--sandstone { --pt-ink: var(--c-blue); }
/* green / blue / terracotta keep the default white ink */

/* ── Rows ─────────────────────────────────────────────────────────────────────*/
.pricing-table__rows {
    list-style: none;
    margin: 0;
    padding: 0;
}
.pricing-table__row {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--gutter);
    padding-block: var(--pt-pad-y);
    border-bottom: 1px solid var(--c-black);
}
.pricing-table__row--last { border-bottom: 0; }

.pricing-table__label {
    display: inline-flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: max(0.5rem, 1.0417vw);           /* 20px between label + note */
    font-family: var(--f-heading);
    font-weight: var(--fw-black);
    font-size: var(--fs-h5);              /* token-aligned, one notch under the band title (--pt-fs) */
    line-height: 0.85;
    text-transform: uppercase;
    color: var(--c-black);
}
/* Stacked label — item title on its own line, note beneath (e.g. Reformer Pilates /
   Single Class). Default is inline (label + note on one baseline). */
.pricing-table__label--stack { flex-direction: column; align-items: flex-start; gap: max(.25rem, .4167vw); }
.pricing-table__note {
    font-family: var(--f-body);
    font-weight: var(--fw-regular);
    font-size: var(--fs-big-p);           /* 30px */
    line-height: 1.2;
    text-transform: none;
    color: var(--c-black);
}
.pricing-table__price {
    flex-shrink: 0;
    font-family: var(--f-heading);
    font-weight: var(--fw-black);
    font-size: var(--fs-h5);              /* token-aligned, one notch under the band title (--pt-fs) */
    line-height: 0.85;
    color: var(--pt-price);
    white-space: nowrap;
}

/* ── Responsive — the inset relaxes to the page gutter on the 6/4-col grid ─────*/
@media (max-width: 1023px) {
    .pricing-table__inner { grid-column: 1 / -1; }
}
 /* pricing table — coloured header band + label/note/price rows (Casual Entry) */

/* ── sections/_pricing-split.css ── */
/* =============================================================================
   NORTH SYDNEY OLYMPIC POOL — Pricing split section
   Figma "Legends — Pricing" (2447-30669)
   -----------------------------------------------------------------------------
   The FAQ "list" layout re-purposed for pricing: a big sticky display heading +
   supporting line on the LEFT, one or more price tables stacked on the RIGHT.

     [ PRICING ]              [ Direct Debit band + rows ]
     [ small line ]           [ Upfront band + rows ]

   Reuses the .pricing-table__* visual classes (band, rows, label, price) from
   _pricing-table.css so the tables match the standalone pricing_table section.
   Prices here are blue (--pt-price) rather than black, per Figma. Reflows to a
   single stacked column at ≤1023, like faq--list.
   ============================================================================= */

.pricing-split {
    --ps-pad-y: var(--sp-section);
    --ps-gap:   max(2.5rem, 5.2083vw); /* 100px — gap between stacked tables    */
    padding-block: var(--ps-pad-y);
    background: var(--c-white); /* client-directed white band (Legends pricing) — see CHANGELOG; exception to no-white-band rule */
    /* Pricing-table tokens live on .pricing-table; re-declare them here since the
       reused .pricing-table__* rows/bands sit under .pricing-split, not .pricing-table. */
    --pt-fs:    max(1.75rem, 2.8125vw);   /* 54px — band + row text */
    --pt-pad-y: max(1.25rem, 2.0833vw);   /* 40px — band + row padding */
    --pt-ink:   var(--c-white);           /* band ink (white on blue) */
    --pt-price: var(--c-blue);            /* blue prices (labels stay black) */
}

/* Own 12/6/4 grid so the sticky heading's containing block ends with the tables
   column — mirrors faq--list. Full width: heading cols 1–5, tables cols 7–12 (6). */
.pricing-split__inner {
    grid-column: 1 / -1;
    display: grid;
    grid-template-columns: repeat(var(--grid-cols), 1fr);
    column-gap: var(--gutter);
    align-items: start;
}

.pricing-split__head {
    grid-column: 1 / 6;
    grid-row: 1;
    align-self: start;
    position: sticky;
    top: max(6rem, 8vw);
    display: flex;
    flex-direction: column;
    gap: var(--sp-md);
}
.pricing-split__title {
    margin: 0;
    font-family: var(--f-heading);
    font-weight: var(--fw-black);
    font-size: var(--fs-h3);           /* 100px @1920, floors 32px */
    line-height: 0.8;
    text-transform: uppercase;
    color: var(--c-blue);
}
.pricing-split__intro {
    margin: 0;
    font-family: var(--f-body);
    font-size: var(--fs-big-p);
    line-height: 1.2;
    color: var(--c-black);
}

/* Tables column — full right half (6 cols, 7 / -1); stack with a 100px gap. */
.pricing-split__tables {
    grid-column: 7 / -1;
    grid-row: 1;
    display: flex;
    flex-direction: column;
    gap: var(--ps-gap);
}

/* ── Reflow: stack heading over the tables on tablet / mobile ────────────────*/
@media (max-width: 1023px) {
    .pricing-split__head,
    .pricing-split__tables { grid-column: 1 / -1; grid-row: auto; }
    .pricing-split__head { position: static; margin-bottom: max(2rem, 4vw); }
}
 /* pricing split — sticky heading left + stacked price tables right (Legends) */

/* ── sections/_pricing-addon.css ── */
/* =============================================================================
   NORTH SYDNEY OLYMPIC POOL — Pricing add-on section
   Figma "Legends — Class Add-on Cost" (2447-30981)
   -----------------------------------------------------------------------------
   A centred, inset block: gold pill eyebrow → terracotta display heading →
   centred intro → a stack of label/price rows (stacked title + note on the left,
   accent price on the right) → an optional footnote + blue arrow link.

   Reuses the .pricing-table__* row classes (_pricing-table.css). The accent
   (heading + price) is set by a --pa-accent → --pt-price hand-off so both track
   the chosen colour. Centred + inset to 10 of 12 cols (2 / 12), like the standalone
   pricing_table. Reflows to full width at ≤1023.
   ============================================================================= */

.pricing-addon {
    --pa-accent: var(--c-terracotta);
    --pa-pad-y: var(--sp-section);
    padding-block: var(--pa-pad-y);
    background: var(--c-background);
    /* Reused .pricing-table__* row tokens (declared on .pricing-table normally). */
    --pt-fs:    max(1.75rem, 2.8125vw);   /* 54px — row text */
    --pt-pad-y: max(1.25rem, 2.0833vw);   /* 40px — row padding */
    --pt-price: var(--pa-accent);         /* price ink follows the accent */
}

.pricing-addon--terracotta { --pa-accent: var(--c-terracotta); }
.pricing-addon--green      { --pa-accent: var(--c-green); }
.pricing-addon--blue       { --pa-accent: var(--c-blue); }
.pricing-addon--teal       { --pa-accent: var(--c-teal); }

/* Centred, inset — 8 of 12 cols (3 / 11), riding the 12/6/4 grid token. */
.pricing-addon__inner {
    display: grid;
    grid-template-columns: repeat(var(--grid-cols), 1fr);
    column-gap: var(--gutter);
}
.pricing-addon__head,
.pricing-addon__rows,
.pricing-addon__cta { grid-column: 3 / 11; }

/* ── Head (centred) ─────────────────────────────────────────────────────────*/
.pricing-addon__head {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: var(--sp-md);
    margin-bottom: max(2.5rem, 5.2083vw);   /* 100px → heading block to first row */
}
.pricing-addon__eyebrow {
    display: inline-flex; align-items: center;
    padding: var(--sp-2xs) var(--sp-xs);
    font-family: var(--f-heading); font-weight: var(--fw-black); font-size: 1rem; line-height: 1.1;
    text-transform: uppercase; color: var(--c-black); background: var(--c-gold);
}
.pricing-addon__title {
    margin: 0;
    font-family: var(--f-heading); font-weight: var(--fw-black);
    font-size: var(--fs-h3);            /* 100px @1920, floors 32px */
    line-height: 0.85;
    text-transform: uppercase; color: var(--pa-accent);
}
.pricing-addon__intro {
    margin: 0;
    max-width: 46ch;
    font-family: var(--f-body); font-size: var(--fs-big-p); line-height: 1.2; color: var(--c-black);
}

/* Rows keep bottom hairlines on every row (including the last), per Figma. */
.pricing-addon__rows .pricing-table__row { border-bottom: 1px solid var(--c-black); }

/* ── Footer note + link (centred) ───────────────────────────────────────────*/
.pricing-addon__cta {
    display: flex; flex-wrap: wrap; align-items: center; justify-content: center;
    gap: var(--sp-sm);
    margin: 0;
    margin-top: max(2rem, 3.125vw);     /* 60px */
    text-align: center;
}
.pricing-addon__footnote {
    font-family: var(--f-body); font-size: var(--fs-body); line-height: 1.2; color: var(--c-black);
}
.pricing-addon__link { color: var(--c-blue); }

/* ── Responsive — inset relaxes to the page gutter ──────────────────────────*/
@media (max-width: 1023px) {
    .pricing-addon__head,
    .pricing-addon__rows,
    .pricing-addon__cta { grid-column: 1 / -1; }
}
 /* pricing add-on — centred pill + heading + rows + link (Legends) */

/* ── sections/_pricing-media.css ── */
/* =============================================================================
   NORTH SYDNEY OLYMPIC POOL — Pricing + media section
   Figma "Frame 21366" (2431-21253) — the Crèche pricing module
   -----------------------------------------------------------------------------
   A text/media split (like text-media) where the text column is a price list:
   a big display heading then rows of coloured title + note-below and a right-
   aligned coloured price, split by hairline rules (last row none). Media = one
   tall image. Editor flips the image left/right; --pm-accent / --pm-head set
   the row + heading colours (inline, from tokens — same pattern as text-media).
   Stacks ≤1023. px in comments = Figma 1920 canvas.
   ============================================================================= */

.pricing-media {
    --pm-fs-title: max(1.75rem, 2.8125vw);   /* 54px row title */
    --pm-accent:   var(--c-blue);
    --pm-head:     var(--c-black);
    padding-block: var(--sp-section);
}
.pricing-media__inner {
    display: flex;
    align-items: center;
    gap: max(2.5rem, 8.59375vw);             /* 165px */
}
.pricing-media--media-right .pricing-media__media { order: 2; }

.pricing-media__media {
    flex: 0 0 max(16rem, 35.625vw);          /* 684px */
    aspect-ratio: 684 / 700;
    border-radius: var(--r-card);
    overflow: hidden;
}
.pricing-media__media img {
    display: block; width: 100%; height: 100%; object-fit: cover;
}

.pricing-media__text { flex: 1 1 auto; }
.pricing-media__heading {
    margin: 0 0 max(2.5rem, 7.13542vw) 0;    /* ~137px gap to the list (Figma) */
    font-family: var(--f-heading); font-weight: var(--fw-black);
    font-size: var(--fs-h3);                 /* 100px */
    line-height: 0.8; text-transform: uppercase; color: var(--pm-head);
}

.pricing-media__rows { list-style: none; margin: 0; padding: 0; }
.pricing-media__row {
    display: flex; align-items: center; justify-content: space-between;
    gap: var(--gutter);
    padding-block: max(1rem, 1.25vw);        /* 24px */
    border-bottom: 1px solid var(--c-black);
}
.pricing-media__row--last { border-bottom: 0; }

.pricing-media__rowtext {
    display: flex; flex-direction: column; gap: max(.5rem, 1.0417vw);   /* 20px */
}
.pricing-media__label {
    font-family: var(--f-heading); font-weight: var(--fw-black);
    font-size: var(--pm-fs-title);
    line-height: 0.85; text-transform: uppercase; color: var(--pm-accent);
}
.pricing-media__note {
    font-family: var(--f-body); font-weight: var(--fw-regular);
    font-size: var(--fs-big-p);              /* 30px */
    line-height: 1.2; color: var(--c-black);
}
.pricing-media__price {
    flex-shrink: 0;
    font-family: var(--f-heading); font-weight: var(--fw-black);
    font-size: var(--fs-h4);                 /* 62px */
    line-height: 0.8; color: var(--pm-accent); white-space: nowrap;
}

@media (max-width: 1023px) {
    .pricing-media__inner { flex-direction: column; align-items: stretch; gap: max(2rem, 4vw); }
    .pricing-media--media-right .pricing-media__media { order: 0; }
    .pricing-media__media { flex-basis: auto; aspect-ratio: 3 / 2; }
}
 /* pricing + media — image beside a blue price list (Crèche) */

/* ── sections/_booking-info.css ── */
/* =============================================================================
   NORTH SYDNEY OLYMPIC POOL — Booking info section
   Figma "Text block" (2431-20920) — the Crèche "How to book / What to bring"
   -----------------------------------------------------------------------------
   Tinted band split into two columns: LEFT a stack of text blocks (blue H4 +
   numbered/icon list + pill buttons + footnote); RIGHT a "Sessions & Hours"
   info card (colour header + white rows split by hairline rules). Stacks ≤1023.

   Type/space follow the theme's viewport-proportional model — max(rem, vw).
   px in comments = Figma 1920 canvas.
   ============================================================================= */

.booking-info {
    --bi-ink:   var(--c-black);
    --bi-head:  var(--c-blue);
    padding-block: var(--sp-section);
}
.booking-info--bg-sandstone  { background: var(--c-sandstone); }
.booking-info--bg-gold       { background: var(--c-gold); }
.booking-info--bg-teal       { background: var(--c-teal); }
.booking-info--bg-green      { background: var(--c-green);      --bi-ink: var(--c-white); --bi-head: var(--c-gold); }
.booking-info--bg-blue       { background: var(--c-blue);       --bi-ink: var(--c-white); --bi-head: var(--c-gold); }
.booking-info--bg-terracotta { background: var(--c-terracotta); --bi-ink: var(--c-white); --bi-head: var(--c-gold); }

/* Real 12/6/4 grid (client grid rule): text blocks cols 1–8 (7), info card cols
   9–12 (4, matching text-media's card mode + the ~546px Figma card), col 8 empty
   (≈ the old 166px flex gap). ≤1023 stacks — both full-span rows, so the card is
   FULL WIDTH on mobile (the old column-flex left it shrink-wrapped). */
.booking-info__inner {
    grid-column: 1 / -1;
    display: grid;
    grid-template-columns: repeat(var(--grid-cols), 1fr);   /* 12 / 6 / 4 — matches .container */
    column-gap: var(--gutter);
    align-items: stretch;
    min-width: 0;
}
.booking-info__blocks { grid-column: 1 / 8; grid-row: 1; min-width: 0; }   /* 7 cols */
.booking-info__card   { grid-column: 9 / -1; grid-row: 1; min-width: 0; }  /* 4 cols, col 8 empty */
@media (max-width: 1023px) {
    .booking-info__inner { row-gap: max(2.5rem, 5.2083vw); }
    .booking-info__blocks,
    .booking-info__card { grid-column: 1 / -1; }
    .booking-info__blocks { grid-row: 1; }
    .booking-info__card   { grid-row: 2; }
}

/* ── LEFT — text blocks ───────────────────────────────────────────────────────*/
.booking-info__blocks {
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    gap: max(2.5rem, 4.1667vw);               /* 80px between blocks */
}
.booking-info__block {
    display: flex;
    flex-direction: column;
    gap: max(1.25rem, 2.0833vw);              /* 40px */
}
.booking-info__heading {
    margin: 0;
    font-family: var(--f-heading); font-weight: var(--fw-black);
    font-size: var(--fs-h4);                  /* 62px */
    line-height: 0.8; text-transform: uppercase;
    color: var(--bi-head);
}
.booking-info__ol {
    margin: 0; padding-inline-start: 1.5em;
    list-style: decimal;
    font-family: var(--f-body); font-size: var(--fs-big-p);            /* 30px */
    line-height: 1.2; color: var(--bi-ink);
}
.booking-info__ol li { padding-inline-start: .5em; margin-bottom: max(.5rem, .8333vw); }   /* 16px */
.booking-info__ol li:last-child { margin-bottom: 0; }
.booking-info__actions {
    display: flex; flex-wrap: wrap; gap: max(1rem, 2.0833vw);          /* 40px */
    margin-top: max(.5rem, .8333vw);
}
.booking-info__footnote {
    margin: 0;
    font-family: var(--f-heading); font-weight: var(--fw-black);
    font-size: var(--fs-link);                /* 32px, floor 20px */
    line-height: 1; color: var(--bi-ink);
}

/* ── RIGHT — Sessions & Hours info card ──────────────────────────────────────
   Reusable "info-card" primitive: a solid header band + white rows. Named
   generically so other sections can drop it in. */
.info-card {
    --ic-accent: var(--c-blue);
    align-self: start;                        /* top-aligned in its grid track */
    background: var(--c-white);
    border-radius: var(--r-card);
    overflow: hidden;
}
.info-card--green      { --ic-accent: var(--c-green); }
.info-card--teal       { --ic-accent: var(--c-teal); }
.info-card--terracotta { --ic-accent: var(--c-terracotta); }
.info-card--gold       { --ic-accent: var(--c-gold); }
.info-card--blue       { --ic-accent: var(--c-blue); }
.info-card__head {
    padding: max(1.5rem, 2.0833vw) var(--sp-lg);
    background: var(--ic-accent);
    color: var(--c-white);
    font-family: var(--f-heading); font-weight: var(--fw-black);
    font-size: var(--fs-h4);                  /* was --fs-link */
    line-height: 1; text-transform: uppercase; text-align: center;
}
.info-card__row {
    display: flex; flex-direction: column; gap: var(--sp-xs);
    padding: max(1.75rem, 2.6042vw) var(--sp-lg);   /* 50px / 24px */
    text-align: center;
    border-bottom: 2px solid var(--c-sandstone);
}
.info-card__row:last-child { border-bottom: 0; }
.info-card__title {
    margin: 0;
    font-family: var(--f-heading); font-weight: var(--fw-black);
    font-size: var(--fs-link);                /* 32px */
    line-height: 1; text-transform: uppercase; color: var(--ic-accent);
}
.info-card__text {
    font-family: var(--f-body); font-weight: var(--fw-regular);
    font-size: var(--fs-body);                /* 20px */
    line-height: 1.2; color: var(--c-black);
}
  /* booking info — text blocks + Sessions & Hours info card (Crèche) */

/* ── sections/_testimonials.css ── */
/* =============================================================================
   NORTH SYDNEY OLYMPIC POOL — Testimonials section
   Figma "Frame 21367" (2437-34170) — the Crèche testimonials strip
   -----------------------------------------------------------------------------
   A snap-scrolling carousel of white quote cards (blue quote-mark → quote →
   optional author) on the page background (or a tinted band). 3 per view on
   desktop, 2.2 / 1.15 peek on tablet / mobile (system carousel-track rules —
   see facility-cards). Shared [data-carousel] engine + .pagination--facility
   nav in main.js; autoplays via data-carousel-auto.
   px in comments = Figma 1920 canvas.
   ============================================================================= */

.testimonials {
    --tm-accent: var(--c-blue);
    padding-block: var(--sp-section);
}
.testimonials--bg-sandstone  { background: var(--c-sandstone); }
.testimonials--bg-teal       { background: var(--c-teal); }
.testimonials--bg-gold       { background: var(--c-gold); }
.testimonials--bg-green      { background: var(--c-green); }
.testimonials--bg-blue       { background: var(--c-blue); }
.testimonials--bg-terracotta { background: var(--c-terracotta); }

/* ── Carousel — snap track + PREV · dots · NEXT (shared engine) ──────────────*/
.testimonials__carousel {
    grid-column: 1 / -1;
    min-width: 0;                             /* let the scroll track shrink, not overflow the grid */
    display: flex; flex-direction: column; align-items: center;
    gap: var(--sp-lg);
}

/* Horizontal snap-scroll track. --tm-per = cards visible per view; fractional
   values on smaller screens let the next card peek in to hint the scroll. */
.testimonials__track {
    --tm-per: 3;
    list-style: none; margin: 0; padding: 0;
    display: flex;
    gap: var(--gutter);                       /* 24px */
    width: 100%;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scrollbar-width: none;                    /* Firefox — hide the bar */
    -ms-overflow-style: none;
}
.testimonials__track::-webkit-scrollbar { display: none; }

.testimonials__card {
    flex: 0 0 calc((100% - (var(--tm-per) - 1) * var(--gutter)) / var(--tm-per));
    min-width: 0;                             /* long unbreakable words must not grow the card past its basis */
    scroll-snap-align: start;
    display: flex; flex-direction: column;
    gap: max(1.25rem, 2.0833vw);              /* 40px */
    padding: max(2rem, 4.1667vw) max(1.5rem, 3.125vw);   /* 80px / 60px */
    background: var(--c-white);
    border-radius: var(--r-card);
    text-align: left;
}
.testimonials__mark {
    font-family: var(--f-heading); font-weight: var(--fw-black);
    font-size: max(6rem, 9vw); line-height: 0.8;
    /* MD Nichrome's “ ink ends ≈.3em below the box top — clamp the empty
       descent so the flex gap measures from the glyph (Figma: 52px @1920) */
    height: .3em; overflow: visible;
    color: var(--tm-accent); flex-shrink: 0;
}
.testimonials__quote {
    margin: 0;
    font-family: var(--f-body); font-weight: var(--fw-regular);
    font-size: var(--fs-big-p);               /* 30px */
    line-height: 1.2; color: var(--c-black);
}
.testimonials__author {
    margin: 0;
    font-family: var(--f-heading); font-weight: var(--fw-black);
    font-size: var(--fs-body); line-height: 1; color: var(--tm-accent);
}

/* Pagination follows the quote-mark accent; dark bands flip it white so the
   PREV/NEXT + active dot stay visible on the band. */
.testimonials .pagination--facility { --pg-accent: var(--tm-accent); }
.testimonials--bg-green .pagination--facility,
.testimonials--bg-blue .pagination--facility,
.testimonials--bg-terracotta .pagination--facility { --pg-accent: var(--c-white); }

/* ── Responsive — fewer cards per view, peek the next one ─────────────────────
   ≤1023 the track BLEEDS to the viewport edges (system carousel-track rule —
   see facility-cards for the mechanics): negative margins pull it under the
   .container page margin; matching padding + scroll-padding keep resting cards
   grid-aligned. */
@media (max-width: 1023px) {           /* tablet */
    .testimonials__track {
        --tm-per: 2.2;
        width: calc(100% + 2 * var(--sp-page-x));
        margin-inline: calc(-1 * var(--sp-page-x));
        padding-inline: var(--sp-page-x);
        scroll-padding-inline: var(--sp-page-x);
    }
}
@media (max-width: 767px) {            /* mobile */
    .testimonials__track { --tm-per: 1.15; }
    /* Swipe IS the affordance on phones — drop the PREV · dots · NEXT chrome. */
    .testimonials__nav { display: none; }
}
  /* testimonials — row of white quote cards (Crèche) */

/* ── sections/_condition-of-entry.css ── */
/* =============================================================================
   NORTH SYDNEY OLYMPIC POOL — Condition of entry section
   Figma "Text block" (1871-21353)
   -----------------------------------------------------------------------------
   Two-column split on the .container grid: a text column (blue H3 + intro +
   .icon-list of conditions, wave bullets) beside an "accessibility" banner card
   (coloured panel: two-tone accessibility mark + H5 + body + white link pinned
   to the bottom). Stacks at ≤1023.

   px in comments are the Figma 1920 canvas measurements.
   ============================================================================= */

.condition-entry {
    --ce-title: var(--c-blue);
    --ce-ink: var(--c-black);
    padding-block: var(--sp-section);
    background: var(--c-background);
}
.condition-entry__inner { align-items: stretch; row-gap: max(2.5rem, 4vw); }
.condition-entry__text { grid-column: 1 / 8; }
.condition-entry .access-card { grid-column: 9 / -1; }

/* ── Background band (dark bands flip heading/intro/footnote to white) ────────*/
.condition-entry--bg-teal       { background: var(--c-teal); }
.condition-entry--bg-sandstone  { background: var(--c-sandstone); }
.condition-entry--bg-gold       { background: var(--c-gold); }
.condition-entry--bg-green      { background: var(--c-green); }
.condition-entry--bg-blue       { background: var(--c-blue); }
.condition-entry--bg-terracotta { background: var(--c-terracotta); }
.condition-entry--bg-green,
.condition-entry--bg-blue,
.condition-entry--bg-terracotta { --ce-title: var(--c-white); --ce-ink: var(--c-white); }

/* ── Text column ─────────────────────────────────────────────────────────────*/
.condition-entry__text {
    display: flex; flex-direction: column;
    gap: max(2rem, 4.1667vw);             /* 80px head ↔ list */
}
.condition-entry__head { display: flex; flex-direction: column; gap: var(--sp-lg); }   /* 24px */
.condition-entry__title {
    margin: 0;
    font-family: var(--f-heading); font-weight: var(--fw-black);
    font-size: var(--fs-h3);              /* 100px @1920 */
    line-height: var(--lh-h3);            /* 0.8 */
    text-transform: uppercase; color: var(--ce-title);
}
.condition-entry__intro {
    margin: 0;
    font-family: var(--f-body); font-size: var(--fs-big-p);   /* 30px */
    line-height: 1.2; color: var(--ce-ink);
}
.condition-entry__note {
    margin: 0;
    font-family: var(--f-body); font-size: var(--fs-body);    /* 20px */
    line-height: 1.2; color: var(--ce-ink);
}
.condition-entry__note a { color: inherit; text-decoration: underline; }
/* List bullet labels follow the section ink (white on dark bands); the bullet
   itself is set inline via --list-bullet (auto or the chosen keyword). */
.condition-entry .icon-list__label { color: var(--ce-ink); }
.condition-entry__actions { display: flex; flex-wrap: wrap; gap: var(--sp-lg); }

/* ── Accessibility banner card ───────────────────────────────────────────────*/
.access-card {
    border-radius: var(--r-card);
    padding: max(1.75rem, 3.125vw);       /* 60px */
    display: flex; flex-direction: column; justify-content: space-between;
    gap: max(1.5rem, 2.0833vw);           /* 40px */
}
/* No bottom-pinned link ⇒ card hugs its content and tops-aligns in the row
   (not stretched to the text column's full height — matches the Figma "Banner").
   It also sticks on scroll: its containing block is the grid row (as tall as the
   text column), so position:sticky only engages once .condition-entry__text is
   taller than the card — otherwise it just sits normally. top clears the header. */
.access-card--hug {
    align-self: start;
    position: sticky;
    top: max(6rem, 8vw);
}
.access-card--blue       { background: var(--c-blue);       color: var(--c-white); }
.access-card--green      { background: var(--c-green);      color: var(--c-white); }
.access-card--teal       { background: var(--c-teal);       color: var(--c-green); }
.access-card--terracotta { background: var(--c-terracotta); color: var(--c-white); }
.access-card--gold       { background: var(--c-gold);       color: var(--c-terracotta); }
.access-card--white      { background: var(--c-white);      color: var(--c-black); }
.access-card__top { display: flex; flex-direction: column; gap: max(1.5rem, 2.0833vw); }   /* 40px */
.access-card__icon { display: inline-flex; width: max(5rem, 7.8125vw); }   /* 150px */
.access-card__icon img,
.access-card__icon svg { width: 100%; height: auto; display: block; }
/* Two-tone accessibility mark — recolourable circle + figure (see the inlined
   images/graphics SVG). Default = Figma: blue circle, white figure (reads on the
   white / light cards). On the blue card, invert so the circle stays visible.
   Override --acc-bg / --acc-fg per card variant to assign other colours. */
.access-card__icon { --acc-bg: var(--c-blue); --acc-fg: var(--c-white); }
.access-card--blue .access-card__icon { --acc-bg: var(--c-white); --acc-fg: var(--c-blue); }
.access-card__text { display: flex; flex-direction: column; gap: var(--sp-lg); }   /* 24px */
.access-card__title {
    margin: 0;
    font-family: var(--f-heading); font-weight: var(--fw-black);
    font-size: max(1.75rem, 2.8125vw);    /* 54px @1920 */
    line-height: 0.85; text-transform: uppercase; color: currentColor;
}
.access-card__body {
    margin: 0;
    font-family: var(--f-body); font-size: var(--fs-big-p);   /* 30px */
    line-height: 1.2; color: currentColor;
}
.access-card__link { color: currentColor; }

/* ── Reflow ──────────────────────────────────────────────────────────────────*/
@media (max-width: 1023px) {
    .condition-entry__text,
    .condition-entry .access-card { grid-column: 1 / -1; }
    .condition-entry__text { gap: max(1.5rem, 3vw); }
    /* Stacked full-width — no sticky. */
    .access-card--hug { position: static; }
}
 /* condition of entry — icon-list + accessibility banner card (Visit Us) */

/* ── sections/_links.css ── */
/* =============================================================================
   NORTH SYDNEY OLYMPIC POOL — Links section
   Figma "LINKS" (1919-10587)
   -----------------------------------------------------------------------------
   A full-width band of horizontal .nav-card--icon blocks (components/_cards.css)
   — a quick-links / "plan your visit" row that sits near the bottom of a page:

     [ icon · eyebrow + big link → ]   ×N   (blue blocks, one row)

   Three across @1920 (each 544px on the 1680px content row); reflows to two on
   tablet, one on mobile. Spacing/colour live on the .nav-card--icon component;
   this file only sets the section rhythm and the responsive grid.
   ============================================================================= */

.links {
    --links-pad-y: var(--sp-section);
    padding-block: var(--links-pad-y);
    background: var(--c-background);
}

/* Cards ride the 12/6/4 token grid: each spans 4 cols (3-up) → 3 cols (2-up) →
   full (1-up). Grid stays present at every breakpoint (inspectable). */
.links__grid {
    grid-column: 1 / -1;
    display: grid;
    grid-template-columns: repeat(var(--grid-cols), 1fr);
    gap: var(--gutter);                      /* 24px */
}
.links__grid > * { grid-column: span 4; }

/* ── Responsive — fewer cards per row as the viewport narrows ─────────────────*/
@media (max-width: 1023px) {                 /* 6-col grid → 2-up */
    .links__grid > * { grid-column: span 3; }
}
@media (max-width: 767px) {                  /* 4-col grid → 1-up */
    .links__grid > * { grid-column: 1 / -1; }
}
        /* links — row of icon nav-cards ("plan your visit" quick links) */

/* ── sections/_cta.css ── */
/* =============================================================================
   NORTH SYDNEY OLYMPIC POOL — Call to action section
   Figma "CALL TO ACTION" (text 1686-10979 · feature 1844-12781)
   -----------------------------------------------------------------------------
   One section, two variants:

     .cta-block--text     teal band · giant green display heading with photo
                          strips set inline between the words · green pill button
                          bottom-aligned to its right.
     .cta-block--feature  full-bleed background photo + dark overlay · centred
                          seagull emblem → white H1 → big paragraph → blue pill.

   px in comments are the Figma 1920 canvas measurements. Internal spacing is
   token / em-based so the whole block scales with the viewport. Distinct from
   the smaller card-level .cta-banner / .promo-banner in components/_cards.css.
   ============================================================================= */

.cta-block {
    --cta-pad-y: var(--sp-section);
    position: relative;
    overflow: hidden;
}

/* ── TEXT variant — teal band, inline-photo heading + pill ───────────────────*/
.cta-block--text {
    --cta-bg:  var(--c-teal);   /* band background (overridden per --bg-* below) */
    --cta-ink: var(--c-green);  /* display heading colour                        */
    background: var(--cta-bg);
    padding-block: var(--cta-pad-y);
}

/* Background colour variants (caller picks via `bg`). Ink stays green unless the
   band itself is green, in which case flip the heading to teal for contrast. */
.cta-block--bg-teal       { --cta-bg: var(--c-teal); }
.cta-block--bg-blue       { --cta-bg: var(--c-blue);       --cta-ink: var(--c-teal); }
.cta-block--bg-gold       { --cta-bg: var(--c-gold);       --cta-ink: var(--c-green); }
.cta-block--bg-sandstone  { --cta-bg: var(--c-sandstone);  --cta-ink: var(--c-green); }
.cta-block--bg-terracotta { --cta-bg: var(--c-terracotta); --cta-ink: var(--c-gold); }
.cta-block--bg-green      { --cta-bg: var(--c-green);      --cta-ink: var(--c-teal); }

/* Rides the .container 12-col grid (from _reset.css). Each heading LINE is its
   own grid row: normal lines span all 12 columns, and the LAST line yields its
   right-hand 2 columns to the button (which sits on that same row, bottom-right). */
.cta-block__inner {
    align-items: end;
    row-gap: max(1.5rem, 2.0833vw); /* 40px between lines / stacked rows */
}

/* Heading is display:contents so its lines become direct grid items of the
   .container grid. The <h*> generates no box but still cascades its type down. */
.cta-block__heading {
    display: contents;
    font-family: var(--f-heading);
    font-weight: var(--fw-black);
    font-size: var(--fs-h2);   /* 160px @1920, floors 36px */
    line-height: var(--lh-h2); /* 0.8 */
    text-transform: uppercase;
    color: var(--cta-ink);
}
.cta-block__line {
    grid-column: 1 / -1; /* normal line: full 12 columns */
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.125em; /* 20px between words / strips @160px */
}
/* When a button is present, the last line makes room for it in the right 2 cols. */
.cta-block--has-action .cta-block__line:last-child { grid-column: 1 / 11; }
/* Trim each word's box to the cap-height (as Figma does) so an inline strip,
   which stretches to the line's cross-size, matches the visible letter height
   exactly. Falls back to the 0.8em line box where text-box-trim is unsupported. */
.cta-block__word {
    white-space: nowrap;
    text-box: trim-both cap alphabetic;
}

/* Inline photo strip — matches the height of the text on its line. The <img>
   is taken out of flow (absolute) so the strip has no intrinsic height of its
   own; align-self:stretch then sizes it to the line's cross-axis = the text. */
.cta-block__strip {
    position: relative;
    align-self: stretch;
    flex: 0 0 auto;
    width: 1.65em;      /* 264px @160px */
    overflow: hidden;
}
.cta-block__strip img {
    position: absolute;
    inset: 0;
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

/* Button — last 2 columns, pinned bottom-right. */
.cta-block__action {
    grid-column: 11 / -1;
    justify-self: end;
    align-self: end;
}
/* Pill fill = display heading colour (--cta-ink; green on the teal band); label
   = white for legibility on the saturated fill (green/teal). Exception: the
   terracotta band's fill is gold, which pairs with terracotta — see below. */
.cta-block--text .cta-block__action .btn {
    --btn-bg: var(--cta-ink);
    --btn-fg: var(--c-white);
}
.cta-block--text.cta-block--bg-terracotta .cta-block__action .btn { --btn-fg: var(--c-terracotta); }

/* ── FEATURE variant — full-bleed photo, centred emblem + H1 + paragraph ─────*/
.cta-block--feature {
    --cta-overlay: 0.3;
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: max(34rem, 43.4375vw); /* 834px @1920 */
    padding-block: var(--cta-pad-y);
    color: var(--c-white);
    text-align: center;
}
/* Solid-background feature: a colour combination instead of a photo (no overlay,
   shorter band). Heading = combo ink, body ink legible per band. Editor picks the
   combination (same --combo-* pairings as /foundations/). */
.cta-block--solid {
    min-height: 0;
    color: var(--cta-body, var(--c-black));
}
.cta-block--solid .cta-block__title { color: var(--cta-title, currentColor); }
.cta-block--combo-sand  { background: var(--combo-sand-band);  --cta-title: var(--combo-sand-ink);  --cta-body: var(--c-black); }
.cta-block--combo-teal  { background: var(--combo-teal-band);  --cta-title: var(--combo-teal-ink);  --cta-body: var(--c-black); }
.cta-block--combo-page  { background: var(--combo-page-band);  --cta-title: var(--combo-page-ink);  --cta-body: var(--c-black); }
.cta-block--combo-green { background: var(--combo-green-band); --cta-title: var(--combo-green-ink); --cta-body: var(--c-white); }
.cta-block--combo-coral { background: var(--combo-coral-band); --cta-title: var(--combo-coral-ink); --cta-body: var(--c-white); }
.cta-block--combo-blue  { background: var(--combo-blue-band);  --cta-title: var(--combo-blue-ink);  --cta-body: var(--c-white); }
.cta-block--combo-gold  { background: var(--c-gold);           --cta-title: var(--c-terracotta);    --cta-body: var(--c-black); }

.cta-block__bg,
.cta-block__overlay {
    position: absolute;
    inset: 0;
    pointer-events: none;
}
.cta-block__bg img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}
.cta-block__overlay { background: rgba(0, 0, 0, var(--cta-overlay)); }

/* .cta-block__content carries .container (12-col grid). Content sits on the grid:
   textgroup = 10 cols (centred) @desktop → full width at 6/4-col reflow. */
.cta-block__content {
    position: relative;   /* lift above bg + overlay */
    z-index: 1;
    row-gap: max(1.5rem, 2.0833vw); /* 40px — textgroup ↔ button */
    align-content: center;
    justify-items: center;
}
.cta-block__textgroup {
    grid-column: 2 / 12;  /* 10 of 12 cols, centred */
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: max(1.5rem, 2.0833vw); /* 40px — titlebox ↔ paragraph */
}
/* Feature variant: the text group becomes its own full-width 12-col grid so the
   titlebox and paragraph ride real page columns (client grid rule) — titlebox
   spans 10 cols, only the paragraph narrows to 6, both centred. */
.cta-block--feature .cta-block__textgroup {
    grid-column: 1 / -1;
    justify-self: stretch;             /* beat .cta-block__content justify-items:center */
    display: grid;
    grid-template-columns: repeat(var(--grid-cols), 1fr);
    column-gap: var(--gutter);         /* row-gap kept from the base .textgroup gap */
    align-items: start;
}
.cta-block--feature .cta-block__titlebox { grid-column: 2 / 12; }   /* 10 of 12 cols */
.cta-block--feature .cta-block__desc     { grid-column: 4 / 10; }   /*  6 of 12 cols */
.cta-block--feature .cta-block__content > .btn { grid-column: 1 / -1; justify-self: center; }
/* Emblem sits directly on top of the title (Figma: no gap). */
.cta-block__titlebox {
    display: flex;
    flex-direction: column;
    align-items: center;
}
.cta-block__emblem {
    width: max(5rem, 7.8125vw); /* 150px @1920, scales with viewport */
    height: auto;
    color: var(--c-white);
    --fill-0: currentColor;      /* fill-token graphics (e.g. shell) follow the white colour too */
}
.cta-block__title {
    margin: 0;
    font-family: var(--f-heading);
    font-weight: var(--fw-black);
    font-size: var(--fs-h2);   /* 160px @1920 */
    line-height: var(--lh-h1); /* 0.8 */
    text-transform: uppercase;
    color: inherit;
}
.cta-block__desc {
    margin: 0;
    font-family: var(--f-body);
    font-size: var(--fs-big-p); /* 30px @1920, floors 18px */
    line-height: 1.2;
    color: inherit;
}

/* ── Reflow ──────────────────────────────────────────────────────────────────*/
@media (max-width: 1023px) {
    /* Text band: the last line reclaims full width and the button drops below it
       (left-aligned) on the reflowed 6-then-4-col grid. */
    .cta-block--has-action .cta-block__line:last-child,
    .cta-block__action { grid-column: 1 / -1; }
    .cta-block__action { justify-self: start; align-self: start; }
    /* feature: text group + its titlebox/paragraph reclaim full width on the
       6/4-col grid (the 10-/6-col spans would clamp too narrow otherwise). */
    .cta-block--feature .cta-block__textgroup,
    .cta-block--feature .cta-block__titlebox,
    .cta-block--feature .cta-block__desc { grid-column: 1 / -1; }
}
          /* call to action — inline-photo text band + full-bleed feature */

/* ── sections/_quiz.css ── */
/* =============================================================================
   NORTH SYDNEY OLYMPIC POOL — Level Quiz
   Source: Figma "Quiz cards" (nodes 1918-8950 / 1918-8080).
   -----------------------------------------------------------------------------
   A white card centred on the page background. Three JS-rendered states
   (assets/js/lts-quiz.js): question, question + media, and reveal (result).
   Everything is token-driven and vw-proportional to the 1920 canvas, matching
   the rest of the theme's fluid scaling.
   ============================================================================= */

/* The whole page sits on teal (hero + card + help), opaque so it covers the
   fixed footer behind .site-main. The shared Hero (internal variant) is
   rendered above .quiz-page and inherits this background. */
.quiz-main {
    background: var(--c-teal);
}

.quiz-page {
    padding-block: max(2rem, 4.1667vw) max(2.5rem, 5.2083vw);   /* 80px → 100px */
}

/* __inner IS .container → rides the 12/6/4 grid. Card sits in a centred 8-col
   band (= its old 1112px measure); the help line spans full width. */
.quiz-page__inner {
    row-gap: max(1.75rem, 2.6042vw);           /* 50px @1920 */
    justify-items: center;
}
.quiz-card    { grid-column: 3 / 11; }         /* 8 cols, centred */
@media (max-width: 1023px) { .quiz-card { grid-column: 1 / -1; } }

/* ─── Card shell ─────────────────────────────────────────────────────────────*/
.quiz-card {
    width: 100%;
    background: var(--c-white);
    border-radius: 4px;
    padding: max(2rem, 4.1667vw);              /* 80px @1920, floor 32px */
    box-shadow: var(--sh-drop);
}
.quiz-card__noscript {
    font-family: var(--f-body);
    color: var(--c-black);
}

.quiz-card__inner {
    display: flex;
    flex-direction: column;
    gap: max(2rem, 4.1667vw);                  /* 80px @1920 — prev ↔ body */
}
.quiz__body {
    display: flex;
    flex-direction: column;
    gap: max(1.5rem, 3.125vw);                 /* 60px @1920 */
}

/* ─── "Previous question" link ───────────────────────────────────────────────*/
.quiz__prev {
    align-self: flex-start;
    background: none;
    border: 0;
    padding: 0;
    color: var(--c-black);                     /* Figma: black, not the link green */
    cursor: pointer;
}
.quiz__prev:hover { color: var(--c-green); }

/* ─── Progress head ──────────────────────────────────────────────────────────*/
.quiz__head {
    display: flex;
    flex-direction: column;
    gap: max(1rem, 1.5625vw);                  /* 30px @1920 */
}
.quiz__step {
    font-family: var(--f-body);
    font-size: var(--fs-big-p);                /* 30px @1920 */
    color: var(--c-black);
}
.quiz__bar {
    height: 8px;
    border-radius: 100px;
    background: var(--c-grey);                 /* #C4C4C4 track */
    overflow: hidden;
}
.quiz__bar-fill {
    display: block;
    height: 100%;
    border-radius: 100px;
    background: var(--c-green);
    transition: width .3s ease;
}

/* ─── Question ───────────────────────────────────────────────────────────────*/
.quiz__question {
    font-family: var(--f-heading);
    font-weight: var(--fw-black);
    font-size: max(2rem, 2.8125vw);            /* 54px @1920, floor 32px */
    line-height: .85;
    color: var(--c-black);
}

/* ─── Media (image / video) ──────────────────────────────────────────────────*/
.quiz__media {
    width: 100%;
    height: max(16rem, 26.0417vw);             /* 500px @1920, floor 256px */
    border-radius: 4px;
    overflow: hidden;
    background: var(--c-background);
}
.quiz__media img,
.quiz__media video,
.quiz__media iframe {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
    border: 0;
}

/* ─── Answers ────────────────────────────────────────────────────────────────*/
.quiz__answers {
    display: flex;
    flex-wrap: wrap;
    gap: max(1rem, 1.25vw);                    /* 24px @1920 */
}
.quiz__btn { min-width: max(13rem, 13.5417vw); }   /* 260px @1920, floor 208px */

/* ─── Reveal (result) ────────────────────────────────────────────────────────*/
.quiz__reveal {
    align-items: center;
    text-align: center;
    gap: max(1.5rem, 3.125vw);                 /* 60px @1920 */
}
/* "Big card image" — its own full-width band, creature centred (50% larger than Figma 300px). */
.quiz__reveal-graphic {
    align-self: stretch;                       /* ignore the centred column → full width */
    width: 100%;
    height: max(16.5rem, 23.4375vw);           /* 450px @1920, floor 264px */
    border-radius: 4px;
    overflow: hidden;
}
.quiz__reveal-graphic img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: contain;
}
.quiz__reveal-title {
    font-family: var(--f-heading);
    font-weight: var(--fw-black);
    font-size: var(--fs-h4);                   /* 62px @1920 */
    line-height: .8;
    color: var(--c-black);
}
.quiz__reveal-body {
    font-family: var(--f-body);
    font-size: var(--fs-big-p);                /* 30px @1920 */
    color: var(--c-black);
    max-width: 40rem;
}
.quiz__reveal-links {
    display: flex;
    flex-wrap: wrap;
    gap: max(.75rem, 1.25vw);
    justify-content: center;
}

/* CTA + "Start again" cluster (Figma gap-16) */
.quiz__reveal-cta { align-self: center; }
.quiz__restart {
    background: none;
    border: 0;
    padding: var(--sp-xs);
    font-family: var(--f-body);
    font-size: var(--fs-link-sm);              /* 20px @1920 */
    color: var(--c-black);
    text-decoration: underline;
    text-underline-offset: 3px;
    cursor: pointer;
}
.quiz__restart:hover { color: var(--c-green); }

/* ─── Help row ("Not sure?  TALK TO OUR TEAM →") ─────────────────────────────*/
.quiz-page__help {
    display: flex;
    align-items: center;
    gap: max(.75rem, .8333vw);                 /* 16px @1920 */
    flex-wrap: wrap;
    justify-content: center;
    margin: 0;
}
.quiz-page__help-label {
    font-family: var(--f-body);
    font-size: var(--fs-link-sm);              /* 20px @1920 */
    color: var(--c-black);
}
/* The "Talk to our team" link is the design-system SMALL LINK: black + MD
   Nichrome (override the green .link component here). */
.quiz-page__help .link {
    color: var(--c-black);
    font-size: var(--fs-link-sm);
}
.quiz-page__help .link:hover { color: var(--c-green); }

/* ─── Responsive ─────────────────────────────────────────────────────────────*/
@media (max-width: 640px) {
    .quiz__answers { flex-direction: column; }
    .quiz__btn { width: 100%; }
}
         /* level quiz — client-driven state-machine card (single-nsop_quiz) */

/* ── sections/_spacing.css ── */
/* =============================================================================
   NORTH SYDNEY OLYMPIC POOL — Spacing (blank vertical spacer)
   -----------------------------------------------------------------------------
   A content-less section that just adds height, so an editor can open up the
   rhythm between two sections without introducing a coloured band. Height is a
   multiple of the shared --sp-section token, so it scales with the viewport like
   every section's own top/bottom padding (see foundation/_tokens.css).
     • --single  1× --sp-section  (one section's worth of padding)
     • --double  2× --sp-section
   Presentational only (rendered aria-hidden); sits on the page background.
   ============================================================================= */
.spacing { display: block; width: 100%; }
.spacing--single { height: var(--sp-section); }
.spacing--double { height: calc(var(--sp-section) * 2); }
      /* spacing — blank vertical spacer (1× / 2× --sp-section) */

/* ── sections/_footer.css ── */
/* =============================================================================
   NORTH SYDNEY OLYMPIC POOL — Footer (three stacked sections)
   -----------------------------------------------------------------------------
   The site footer is composed of three independent sections (each its own
   template-part in template-parts/sections/), stacked in footer.php:
     1. .footer-insta   Figma 1686-7126  full-bleed Instagram photo strip + IG badge
     2. .footer-banner  Figma 1686-7360  teal "JOIN OUR COMMUNITY" band + socials
     3. .footer-main    Figma 1686-7159  blue link columns + logo + legal + acknowledgment

   Token-driven throughout. Vertical rhythm uses max(rem, vw) locals so the
   footer scales with the viewport like the type scale; page margin is the
   global --sp-page-x. px values in comments are the Figma 1920 measurements.
   ============================================================================= */

.site-footer { display: block; }

/* ─────────────────────────────────────────────────────────────────────────────
   1 · INSTAGRAM STRIP — full-bleed row of square photos + centred IG badge
   ────────────────────────────────────────────────────────────────────────────*/
.footer-insta { position: relative; display: block; }
.footer-insta__grid { display: flex; }
/* Desktop: unbox the track/set wrappers so .footer-insta__item flows straight
   into the .footer-insta__grid flex row; the duplicate set is unused here. */
.footer-insta__track,
.footer-insta__set { display: contents; }
.footer-insta__set--dup { display: none; }
.footer-insta__item {
    flex: 1 1 0;
    min-width: 0;
    aspect-ratio: 1 / 1;
    overflow: hidden;
    display: block;
}
.footer-insta__item img {
    width: 100%; height: 100%;
    object-fit: cover; display: block;
    transition: transform var(--transition), filter var(--transition);
}
.footer-insta__item:hover img { transform: scale(1.05); filter: brightness(.9); }

/* Desktop/tablet carousel — added (via .footer-insta--carousel, PHP) when there
   are MORE than 6 photos, so the extra tiles scroll instead of shrinking the row.
   Same infinite-loop mechanic as the ≤767 mobile strip (real set + duplicate,
   track animates to -50%), just showing 6 tiles per view. Scoped ≥768 so it never
   collides with the mobile rules below, which govern the strip on their own. */
@media (min-width: 768px) {
    .footer-insta--carousel .footer-insta__grid { overflow: hidden; }
    .footer-insta--carousel .footer-insta__track {
        display: flex;
        width: max-content;
        animation: nsop-insta-scroll 32s linear infinite;
    }
    .footer-insta--carousel .footer-insta__set { display: flex; flex: 0 0 auto; }
    .footer-insta--carousel .footer-insta__set--dup { display: flex; }
    .footer-insta--carousel .footer-insta__item { flex: 0 0 calc(100% / 6); }  /* 6 per view */
    .footer-insta--carousel .footer-insta__grid:hover .footer-insta__track,
    .footer-insta--carousel .footer-insta__track:focus-within { animation-play-state: paused; }
}
@media (min-width: 768px) and (prefers-reduced-motion: reduce) {
    .footer-insta--carousel .footer-insta__grid { overflow-x: auto; }
    .footer-insta--carousel .footer-insta__track { animation: none; }
    .footer-insta--carousel .footer-insta__set--dup { display: none; }
}

/* Centred white circle Instagram button, overlapping the strip */
.footer-insta__badge {
    position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
    z-index: 2;
    display: grid; place-items: center;
    width: max(4.5rem, 6.25vw); height: max(4.5rem, 6.25vw);  /* 120px @1920 */
    background: var(--c-white);
    border-radius: var(--r-pill);
    color: var(--c-blue);
    box-shadow: var(--sh-drop);
    transition: transform var(--transition);
}
.footer-insta__badge:hover { transform: translate(-50%, -50%) scale(1.06); }
.footer-insta__badge svg { width: 45%; height: auto; }

/* ─────────────────────────────────────────────────────────────────────────────
   2 · BANNER — teal band, green H4, social icons right (Figma 1686-7360)
   ────────────────────────────────────────────────────────────────────────────*/
.footer-banner {
    /* Figma 1686-7360: padding 100 (block) / 120 (inline).
       Inline (120px @1920) = the page-margin token --sp-page-x, applied by
       .container below. Block (100px @1920) scales with the viewport like the
       type scale — max(rem floor, vw) — matching the hero's 100px step. */
    --fb-pad-y: var(--sp-section);
    /* Adaptive colour (like the header's --hd-fg): main.js mirrors the page's
       first hero band and pairs it with that band's approved ink from the
       foundation combination matrix (--combo-* in _tokens.css), setting --fb-bg
       / --fb-ink. gold is ink-only → a gold hero collapses to the coral combo
       (terracotta band + gold text); no hero → the teal/green default below. */
    background: var(--fb-bg, var(--combo-teal-band));
    padding-block: var(--fb-pad-y);
}
/* Ride the shared .container grid (repeat(--grid-cols,1fr)) instead of flex, so
   the title/socials sit on real 12/6/4 tracks that align with every section
   above. Title takes the left 8 cols, socials the right 4 (end-justified). */
.footer-banner .container {
    align-items: center;
    row-gap: var(--sp-xl-f);          /* fluid — scales with the type (2026-07-09) */
    padding-inline: var(--sp-page-x);  /* 120px @1920 — explicit page-margin token */
}
.footer-banner__title {
    grid-column: 1 / 9;
    margin: 0;
    font-family: var(--f-heading);
    font-weight: var(--fw-black);
    font-size: var(--fs-h4);          /* 62px @1920 */
    line-height: var(--lh-h4);        /* 0.8 */
    text-transform: uppercase;
    color: var(--fb-ink, var(--combo-teal-ink));
}
.footer-banner__socials {
    grid-column: 9 / -1;
    display: flex; align-items: center; justify-content: flex-end; gap: var(--sp-lg-f);
}
.footer-banner__social {
    display: grid; place-items: center;
    width: max(2.5rem, 3.125vw); height: max(2.5rem, 3.125vw);  /* 60px */
    color: var(--fb-ink, var(--combo-teal-ink));
    transition: transform var(--transition), opacity var(--transition);
}
.footer-banner__social:hover { transform: translateY(-2px); opacity: .8; }
.footer-banner__social svg { width: 100%; height: 100%; }

/* ─────────────────────────────────────────────────────────────────────────────
   3 · FOOTER MAIN — blue link columns, logo, legal, acknowledgment (1686-7159)
   ────────────────────────────────────────────────────────────────────────────*/
.footer-main {
    /* Self-contained tokens (footer-main also renders outside .site-footer, e.g.
       on the /sections/ reference page) so none of these resolve to empty. */
    /* One grid column width (12/6/4 per breakpoint), same formula as .container's
       own tracks: (100vw - 2 margins - (cols-1) gutters) / cols. So it steps with
       --grid-cols at 1024/768 and scales continuously with vw inside each range. */
    --ft-col: calc((100vw - (2 * var(--sp-page-x)) - ((var(--grid-cols) - 1) * var(--gutter))) / var(--grid-cols));
    /* Logo diameter in columns: 1.25 cols on desktop AND tablet (tablet dropped
       from 1.5 — client 2026-07-09), 1 col on mobile (overridden ≤767). Matches
       the header --hd-logo. Width of N spanned cols = N·col + (N−1)·gutter. */
    --ft-logo-cols: 1.25;
    --ft-logo: calc(var(--ft-col) * var(--ft-logo-cols) + (var(--ft-logo-cols) - 1) * var(--gutter));
    --ft-pad-y: var(--sp-section);
    color: var(--c-white);
    position: relative;
    /* Fraction of the logo that protrudes above the footer (overlapping the
       section above): 50% on desktop, 25% on tablet + mobile (overridden ≤1023).
       The pull-up and the logobar gradient below both derive from this one value
       so the transparent top slice always equals the protruding slice → the seam
       lands exactly on the circle at every breakpoint. */
    --ft-protrude: 0.5;
    margin-top: calc(var(--ft-logo) * var(--ft-protrude) * -1);
}
/* The base .container is a 12-col grid; the footer lays out its own blocks, so
   force normal flow here (0,2,0 beats .container regardless of @import order). */
.footer-main .container { display: block; }

/* Part 1 — logo bar. Height = logo diameter; the top --ft-protrude slice is
   transparent (over the section above), the rest is blue (blends into the body
   below) — same fraction as .footer-main's pull-up so the seam sits on the
   circle. Blue stop = (1 − protrude): 50% desktop, 75% tablet + mobile. */
.footer-main__logobar {
    height: var(--ft-logo);
    display: grid;
    grid-template-columns: repeat(var(--grid-cols), 1fr);   /* ride the 12/6/4 token */
    column-gap: var(--gutter);
    padding-inline: var(--sp-page-x);                       /* tracks align with the nav/bottom */
    place-items: center;
    background: linear-gradient(to top,
        var(--c-blue) calc((1 - var(--ft-protrude)) * 100%),
        transparent  calc((1 - var(--ft-protrude)) * 100%));
}
/* The circle itself — a blue disc with the white wordmark inset. Diameter =
   --ft-logo (1.5 cols desktop/tablet, 1 col mobile). It isn't snapped to a track,
   so it spans the full row and is centred (justify-self) at that fixed width. */
.footer-main__logo {
    grid-column: 1 / -1;
    justify-self: center;
    display: grid;
    place-items: center;
    width: var(--ft-logo);
    height: var(--ft-logo);
    background: var(--c-blue);
    border-radius: var(--r-pill);
    color: var(--c-sandstone);   /* wordmark ink (inline SVG, currentColor) */
}
.footer-main__logo svg { width: 100%; height: auto; display: block; }

/* Parts 2 & 3 — blue body holding the nav + divider + copyright. The body is
   full-width; cols/divider/bottom carry their own inset (page-margin token). */
.footer-main__body { background: var(--c-blue); }

.footer-main__cols {
    display: grid;
    grid-template-columns: repeat(var(--grid-cols), 1fr);   /* ride the 12/6/4 token */
    column-gap: var(--gutter);
    row-gap: var(--sp-2xl-f);                    /* fluid — scales with the type (2026-07-09) */
    padding: var(--ft-pad-y) var(--sp-page-x);   /* nav: normal padding, inset to page margin */
}
/* Each nav column spans 2 grid tracks, so the six columns lay out 6-up on the
   12-col grid, 3-up at 6 cols (≤1023) and 2-up at 4 cols (≤767) — automatically,
   with no per-breakpoint template swap. */
.footer-col { grid-column: span 2; }
/* Per-column heading + its own underline (spans that column only, not a
   continuous rule). Hairline width via the --line-w token. */
.footer-col__title {
    margin: 0 0 var(--sp-md-f);      /* fluid; the sp-sm underline inset stays fixed (≤12px detail) */
    padding-bottom: var(--sp-sm);
    border-bottom: var(--line-w) solid var(--c-sandstone);
    font-family: var(--f-heading);
    font-weight: var(--fw-black);
    font-size: var(--fs-link);        /* 32px @1920, floor 20px */
    line-height: 1;
    text-transform: uppercase;
    color: var(--c-sandstone);
}
.footer-col__list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--sp-xs); }
.footer-col__list a {
    font-family: var(--f-body);
    font-weight: var(--fw-regular);   /* Figma: Archivo Narrow Regular, 400 */
    font-size: max(1rem, 0.9375vw);   /* 18px @1920, floor 16px */
    line-height: 1.2;
    text-transform: uppercase;
    color: var(--c-sandstone);
    text-decoration: none;
    transition: opacity var(--transition);
}
.footer-col__list a:hover { opacity: .7; text-decoration: underline; }

/* Full-width rule between nav and copyright — same hairline as the column
   underlines. Zero margin: the nav's bottom padding + copyright's top padding
   provide the space, so both blocks keep their normal top/bottom padding. */
.footer-main__divider {
    height: 0;
    border-top: var(--line-w) solid var(--c-white);
    margin: 0 var(--sp-page-x);   /* inset to the page margin, matching cols/bottom */
}

/* Part 3 — copyright · Terms · Privacy · Acknowledgment, laid out on the 12-col
   grid and spread across the full width (4 / 2 / 2 / 4 = 12). Normal top +
   bottom padding, inset to the page margin. Stacks down on smaller screens. */
.footer-main__bottom {
    display: grid;
    grid-template-columns: repeat(var(--grid-cols), 1fr);   /* ride the 12/6/4 token */
    column-gap: var(--gutter);
    row-gap: var(--sp-lg-f);          /* fluid — scales with the type (2026-07-09) */
    align-items: start;
    padding: var(--ft-pad-y) var(--sp-page-x);
    font-family: var(--f-body);
    font-size: var(--fs-body);        /* 20px @1920 — Figma body */
    line-height: 1.2;
    color: var(--c-sandstone);        /* Warm sand — logo on blue, soft surfaces */
}
.footer-main__copy  { grid-column: 1 / 4; margin: 0; }
/* Desktop: unbox the wrapper so the two links become direct items on
   .footer-main__bottom's own 12-col grid, each pinned to its own column
   (client spec: Terms of use → cols 4–5, Privacy Policy → cols 6–7). */
.footer-main__legal { display: contents; }
.footer-main__legal-link { color: var(--c-sandstone); text-decoration: none; text-transform: uppercase; }
.footer-main__legal-link:hover { opacity: .7; text-decoration: underline; }
.footer-main__legal-link:nth-of-type(1) { grid-column: 4 / 6; }
.footer-main__legal-link:nth-of-type(2) { grid-column: 6 / 8; }
.footer-ack              { grid-column: 9 / -1; }   /* right-aligned, ~half width */
.footer-ack__title {
    margin: 0 0 var(--sp-sm);
    font-family: var(--f-body);
    font-weight: var(--fw-regular);
    text-transform: uppercase;
}
.footer-ack__body { margin: 0; }

/* ── Responsive ───────────────────────────────────────────────────────────── */
@media (max-width: 1023px) {
    /* Tablet + mobile: only a quarter of the logo protrudes (half on desktop). */
    .footer-main { --ft-protrude: 0.25; }

    /* --grid-cols is now 6; both footer grids ride it. Nav .footer-col span-2 →
       3-up automatically (no template swap). Banner: title left, socials right. */
    .footer-banner__title    { grid-column: 1 / 5; }
    .footer-banner__socials  { grid-column: 5 / -1; }

    /* Bottom row on the 6-col grid: copy left, legal right, acknowledgment
       full-width below. */
    .footer-main__copy { grid-column: 1 / 4; }
    /* The two links become one flex row again (per-column 4/6 pinning only makes
       sense against the 12-col desktop track). */
    .footer-main__legal {
        display: flex; gap: var(--gutter); flex-wrap: wrap;
        grid-column: 4 / -1; justify-content: flex-end;
    }
    .footer-main__legal-link:nth-of-type(1),
    .footer-main__legal-link:nth-of-type(2) { grid-column: auto; }
    .footer-ack { grid-column: 1 / -1; }
}
@media (max-width: 767px) {
    /* Instagram strip → infinite auto-scrolling carousel. The track holds the
       real set + an identical duplicate back-to-back; animating to -50% loops
       seamlessly since what's on screen at the jump is pixel-identical. The
       badge stays centred (absolute on .footer-insta), outside the track. */
    .footer-insta__grid { overflow: hidden; }
    .footer-insta__track {
        display: flex;
        width: max-content;
        animation: nsop-insta-scroll 32s linear infinite;
    }
    .footer-insta__set {
        display: flex;
        flex: 0 0 auto;
    }
    .footer-insta__set--dup { display: flex; }
    .footer-insta__item { flex: 0 0 42vw; }
    .footer-insta__grid:hover .footer-insta__track,
    .footer-insta__track:focus-within { animation-play-state: paused; }

    /* Logo shrinks to a single column on mobile (1.25 cols elsewhere).
       (Protrusion is already 0.25 from the ≤1023 rule above.) */
    .footer-main { --ft-logo-cols: 1; }
    /* --grid-cols is now 4. Nav .footer-col span-2 → 2-up automatically. Banner
       sits side-by-side on the 4-col grid: text 2 cols left, socials 2 cols right. */
    .footer-banner__title    { grid-column: 1 / 3; font-size: var(--fs-h4); }
    .footer-banner__socials  { grid-column: 3 / -1; justify-content: flex-end; }
    /* Bottom info block: children re-span 1/-1 on the 4-col grid (never a
       1fr template — keeps the tracks inspectable). Reflows to: legal links
       (spread) → acknowledgment → copyright last. Order only — DOM stays
       copy/legal/ack for source clarity. */
    .footer-main__copy,
    .footer-main__legal,
    .footer-ack { grid-column: 1 / -1; }
    .footer-main__legal { order: 1; justify-content: space-between; }
    .footer-ack          { order: 2; }
    .footer-main__copy   { order: 3; }
}
@keyframes nsop-insta-scroll {
    from { transform: translateX(0); }
    to   { transform: translateX(-50%); }
}
@media (max-width: 767px) and (prefers-reduced-motion: reduce) {
    .footer-insta__grid { overflow-x: auto; }
    .footer-insta__track { animation: none; width: auto; }
    .footer-insta__set--dup { display: none; }
}
       /* footer — instagram + banner + main */

/* ── Utilities (always last) ────────────────────────────────────────────────*/

/* ── utilities/_grid.css ── */
/* =============================================================================
   NSOP — Utility: 12-Column Grid
   File: assets/css/utilities/_grid.css
   Imported in main.css before _animations.css.

   WHY THIS EXISTS
   ───────────────
   Early sections used `max-width: %` or `flex: 0 0 XX%` to constrain content
   width. Percentages don't account for column gutters, so elements from
   different sections don't visually align even when they "should" be at the
   same column position. A shared 12-column grid fixes this: column 8 in
   text_d is always the same x-position as column 8 in text_e.

   GRID MATH (at max container width: 1760px, gutter: 20px)
   ──────────────────────────────────────────────────────────
   Each 1fr  = (1760 − 11 × 20) / 12 = 128.33px
    2 cols   =  276px   (icon / small element)
    4 cols   =  573px   (text_e body column — Figma spec 574px ✓)
    5 cols   =  701px
    7 cols   = 1018px   (text_b / text_c heading / statement area)
    8 cols   = 1167px   (text_d statement — Figma ~1084px, grid-snapped)
   12 cols   = 1760px   (full container width)

   WHEN TO USE .grid-12
   ─────────────────────
   Add the class to any wrapper div where children need to snap to named
   column positions:

     <div class="text-x__inner grid-12">
         <div class="text-x__heading">...</div>   <!-- CSS: grid-column: 1 / -1  -->
         <div class="text-x__body">...</div>       <!-- CSS: grid-column: 1 / 9   -->
     </div>

   When the grid wrapper IS the .container (no inner div), apply the grid via
   a scoped CSS rule in the section file instead of adding a class to .container:

     .text-d .container {
         display: grid;
         grid-template-columns: repeat(12, 1fr);
         column-gap: var(--gutter);
     }

   WHEN NOT TO USE IT
   ───────────────────
   Simple 2-element proportional splits (e.g. text_f at 49.4%/flex:1) don't
   benefit from named column placement — flex is simpler and equally valid.
   Only reach for the 12-col grid when you need to position 3+ elements OR
   constrain one element to a specific column count.

   SECTIONS CURRENTLY USING THE 12-COL GRID
   ──────────────────────────────────────────
   text_a__bottom   — repeat(12, 1fr) inline (pre-dates this utility)
   text_d .container — repeat(12, 1fr) inline; statement → cols 1–8
   text_e__bottom   — repeat(12, 1fr) inline; columns → cols 1–8, icon → 9–13

   REFACTOR CANDIDATES (next time those files are touched)
   ────────────────────────────────────────────────────────
   (None outstanding here. text_b was retired → migrated into text_compose
   2026-06-03; text_c moved to --grid-cols, cols 1–8 / 9–13, the same day.)

   Do NOT retrofit hero, services, insights, or media_blocks — they have
   bespoke grids tied to their card/image layouts and don't share column
   positions with the text sections.
   ============================================================================= */

.grid-12 {
    display: grid;
    grid-template-columns: repeat(12, 1fr);
    column-gap: var(--gutter);
}


/* ── utilities/_heading-cascade.css ── */
/* =============================================================================
   NSOP — Utility: Heading Cascade (2nd-line column offset)
   Reusable across heading sections. Replaces the old per-section offset hacks
   (text_a / sec-heading / text_g margin-left, hero em{display:block}).

   Behaviour: ONLY the 2nd line of a heading indents — its start snaps to a grid
   column chosen via data-offset="2|3|4". The 1st line and every line from the
   3rd on stay anchored at column 1. No line is forced to break: line breaks come
   only from the editor (separate <p> lines, or <br> the template splits).

   Requirements:
     • The heading wrapper's PARENT is a 12-col grid (.container or a section grid).
     • The wrapper is placed on that grid with `grid-column` (any span starting at
       col 1) and carries the .heading-cascade class + data-offset.
     • Each heading line is a block-level child (a <p>, or a line <span>).

   How it snaps: the wrapper is a `subgrid`, so its own column lines === the parent
   grid's columns. data-offset="3" → the 2nd line starts at the parent's column 3.
   ============================================================================= */

.heading-cascade {
    display: grid;
    grid-template-columns: subgrid;
}

.heading-cascade > * {
    grid-column: 1 / -1;
    margin-block: 0;
}

/* Only the 2nd line is nudged — snapped to the chosen column. */
.heading-cascade[data-offset="2"] > :nth-child(2) { grid-column: 2 / -1; }
.heading-cascade[data-offset="3"] > :nth-child(2) { grid-column: 3 / -1; }
.heading-cascade[data-offset="4"] > :nth-child(2) { grid-column: 4 / -1; }

/* Fallback for browsers without subgrid (pre-2023): approximate the column
   indent as a percentage of the heading's own width. Not column-exact, but the
   cascade reads the same. Assumes a heading roughly 7 columns wide. */
@supports not (grid-template-columns: subgrid) {
    .heading-cascade        { display: block; }
    .heading-cascade > *    { display: block; }
    .heading-cascade[data-offset="2"] > :nth-child(2) { margin-left: 8.5%; }
    .heading-cascade[data-offset="3"] > :nth-child(2) { margin-left: 17%; }
    .heading-cascade[data-offset="4"] > :nth-child(2) { margin-left: 25.5%; }
}

/* Reset all offsets on tablet / mobile — too few columns for the indent to read well. */
@media (max-width: 1023px) {
    .heading-cascade[data-offset="2"] > :nth-child(2),
    .heading-cascade[data-offset="3"] > :nth-child(2),
    .heading-cascade[data-offset="4"] > :nth-child(2) { grid-column: 1 / -1; }

    @supports not (grid-template-columns: subgrid) {
        .heading-cascade[data-offset="2"] > :nth-child(2),
        .heading-cascade[data-offset="3"] > :nth-child(2),
        .heading-cascade[data-offset="4"] > :nth-child(2) { margin-left: 0; }
    }
}


/* ── utilities/_motion.css ── */
/* =============================================================================
   NSOP — Motion (brand animation system)
   Rebuilt from the brand After Effects files (see docs/motion-data-findings.md).
   Eases live in foundation/_tokens.css (--e-outBack "come up for air", --e-mask, …).

   GATING: every hidden-start state is scoped to `html.js-motion`, which an inline
   script in header.php sets BEFORE paint — only when JS is on AND the user has
   not requested reduced motion. So no-JS, reduced-motion, and SEO/crawlers all
   get the fully-rendered content with zero flash and no LCP penalty.

   Families:
     1. .nsop-h-entrance   — H1 words rise + overshoot (outBack)      [JS-wrapped]
     2. .nsop-reveal-lines — H2/H3 lines rise from behind a clip mask [JS-wrapped]
     3. .nsop-media        — image/video settle up (outCirc)
     4. .nsop-pictogram    — SVG parts pop in (outBack), staggered
     5. .nsop-wipe         — wave page-transition overlay
   Elements get `.is-in` when they scroll into view (added by main.js).
   ============================================================================= */

/* ── 1. HEADING ENTRANCE — H1 word rise + outBack (§7.4 Typography Standard) ── */
html.js-motion .nsop-h-entrance .nsop-word {
    display: inline-block;
    opacity: 0;
    transform: translateY(0.5em);
    transition:
        transform var(--m-word-dur) var(--e-outBack),
        opacity   var(--m-word-dur) ease-out;
    will-change: transform, opacity;
}
html.js-motion .nsop-h-entrance.is-in .nsop-word { opacity: 1; transform: none; }

/* ── 2. MASKED LINE REVEAL — H2/H3 lines rise behind a clip (§7.4 / TEXT IN) ── */
html.js-motion .nsop-reveal-lines .nsop-line-mask {
    display: block;
    /* Clip VERTICALLY only (the rise animation) — horizontal stays visible so a
       line mid-resize (or in a squeezed column) overflows readably instead of
       slicing glyphs. visible+clip is the one legal mixed overflow pair. */
    overflow-x: visible;
    overflow-y: clip;
    /* Display headings run line-height 0.8, so glyphs overflow the line box:
       accented caps (È/É — Crèche, Café) rise ~0.2em above it, descenders and
       commas hang ~0.15em below. Pad the clip window past both edges (negative
       margins cancel the layout shift) so nothing is shaved at rest. */
    padding-top: 0.25em;
    margin-top: -0.25em;
    padding-bottom: 0.18em;
    margin-bottom: -0.18em;
}
html.js-motion .nsop-reveal-lines .nsop-line {
    display: block;
    /* 160% (not 100%) so the hidden line — accents included — clears the clip
       window's padded bottom edge above. */
    transform: translateY(160%);
    transition: transform var(--m-line-dur) var(--e-mask);
    will-change: transform;
}
html.js-motion .nsop-reveal-lines.is-in .nsop-line { transform: none; }

/* ── 3. IMAGE / MEDIA REVEAL — brand WAVE uncover (§7.5) ────────────────────── */
/* main.js wraps each content image/video in .nsop-media-wave and injects a wave
   overlay (.nsop-media-wave__wave). The wave (coloured with the section heading's
   colour, --wave-c) sits over the image, then sweeps up to uncover it; the image
   settles up from a soft blur beneath. */
html.js-motion .nsop-media-wave {
    position: relative;
    display: block;
    overflow: hidden;
    width: 100%;
    height: 100%;
}
html.js-motion .nsop-media-wave > img,
html.js-motion .nsop-media-wave > video {
    display: block;
    transform: scale(1.06);
    filter: blur(6px);
    transition:
        transform var(--m-media-dur) var(--e-outCirc),
        filter    var(--m-media-dur) ease-out;
    will-change: transform, filter;
}
html.js-motion .nsop-media-wave.is-in > img,
html.js-motion .nsop-media-wave.is-in > video { transform: none; filter: none; }

html.js-motion .nsop-media-wave__wave {
    position: absolute;
    left: 0; top: 0;
    width: 100%;
    height: 132%;
    color: var(--wave-c, var(--c-blue));
    transform: translateY(-16%);              /* covering */
    pointer-events: none;
    will-change: transform;
}
html.js-motion .nsop-media-wave__wave svg { display: block; width: 100%; height: 100%; }
html.js-motion .nsop-media-wave__wave svg path { fill: currentColor; }
html.js-motion .nsop-media-wave.is-in .nsop-media-wave__wave {
    animation: nsop-media-uncover var(--m-media-dur) var(--e-mask) forwards;
}
@keyframes nsop-media-uncover { from { transform: translateY(-16%); } to { transform: translateY(-142%); } }

/* ── 4. PICTOGRAMS — parts pop in with overshoot (§7.6) ─────────────────────── */
/* Marker `.nsop-pictogram` is auto-added by nsop_icon() to pictogram graphics.
   CONTENT pictograms (in .site-main) hide then pop on scroll-in. */
html.js-motion .site-main .nsop-pictogram path {
    transform: scale(0);
    transform-origin: center;
    transform-box: fill-box;
    transition: transform var(--m-picto-dur) var(--e-outBack);
    will-change: transform;
}
html.js-motion .site-main .nsop-pictogram.is-in path { transform: scale(1); }

/* MEGA-MENU pictograms are always visible (never hidden — a dropdown may never
   trigger a scroll observer); they pop each time their panel opens. */
html.js-motion .nsop-nav-item.is-open .nsop-pictogram path,
html.js-motion li.is-open .nsop-pictogram path {
    transform-box: fill-box;
    transform-origin: center;
    animation: nsop-picto-pop var(--m-picto-dur) var(--e-outBack) both;
}
@keyframes nsop-picto-pop { from { transform: scale(0); } to { transform: scale(1); } }

/* ── 5. PAGE TRANSITION — wave wipe overlay (§7.5) ──────────────────────────── */
/* Cross-document View Transitions bridge the inter-document gap: the browser
   HOLDS the old page's last painted frame (our green cover) until the new
   document's first paint, so there's no blank/white frame between documents —
   the one thing a JS overlay alone can't fix (there's a moment where neither
   document paints). We suppress VT's default root cross-fade so it competes with
   nothing — the wave below stays the only visible motion; VT just bridges.
   Progressive enhancement: unsupported browsers ignore @view-transition and fall
   back to the pre-paint cover + native paint-holding. */
@view-transition { navigation: auto; }
::view-transition-old(root),
::view-transition-new(root) { animation: none; }
@media (prefers-reduced-motion: reduce) {
    @view-transition { navigation: none; }
}

/* Injected into <body> by main.js. Colour = current page's hero heading colour
   (--wipe-color, set by JS). The wave is a tall both-edges shape: it rises up to
   cover (leading wavy edge) on click, then continues up to reveal (trailing wavy
   edge) on the next page's load. */
/* A solid fill (always covers to the very bottom — no gap) + a wave CREST on top
   (leading edge as it rises to cover) + a wave TROUGH below (trailing edge as it
   lifts to reveal). All one translating unit, all the heading colour. */
.nsop-wipe {
    position: fixed;
    left: 0; top: 0;
    width: 100%;
    height: 100vh;
    z-index: 100000;
    pointer-events: none;
    color: var(--wipe-color, var(--c-blue));
    /* parked fully below the viewport — +16vh so the crest (which sits ABOVE the
       fill) is also off-screen and never peeks at the bottom of the page. */
    transform: translateY(calc(100% + 16vh));
    will-change: transform;
}
.nsop-wipe__fill  { position: absolute; left: 0; top: 0; width: 100%; height: 100%; background: currentColor; }
.nsop-wipe__crest { position: absolute; left: 0; bottom: 100%; width: 100%; height: 14vh; }  /* above the fill */
.nsop-wipe__trough{ position: absolute; left: 0; top: 100%;    width: 100%; height: 14vh; }  /* below the fill */
.nsop-wipe__crest svg, .nsop-wipe__trough svg { display: block; width: 100%; height: 100%; }
.nsop-wipe__crest svg path, .nsop-wipe__trough svg path { fill: currentColor; }

/* Phase A — cover: rises from the very bottom up over the current page. At
   translateY(0) the solid fill covers the whole viewport (crest off the top). */
.nsop-wipe.is-covering { animation: nsop-wipe-cover 0.55s var(--e-inQuint) forwards; }
@keyframes nsop-wipe-cover { from { transform: translateY(calc(100% + 16vh)); } to { transform: translateY(0); } }

/* Phase B — reveal: continues up and off, the trailing wave trough uncovering
   the new page. */
.nsop-wipe.is-revealing { animation: nsop-wipe-reveal 0.8s var(--e-outCirc) forwards; }
@keyframes nsop-wipe-reveal { from { transform: translateY(0); } to { transform: translateY(-130%); } }

/* Pre-paint cover: arriving via a transition, the header inline script adds
   `html.nsop-entering` so the incoming page is covered from the first frame (no
   flash) until main.js swaps to the reveal phase.
   The .nsop-wipe overlay itself lives at the END of <body> (footer.php), so on a
   fresh navigation the browser paints the top of the page (white bg) before it
   parses down to the overlay — a split-second flash. Paint a full-screen cover on
   <html> (which exists from the first byte, with --wipe-color already set inline)
   so there's no gap; main.js hands off to the reveal wave and drops nsop-entering
   in the same frame the wave is at translateY(0), so the swap is seamless. */
html.nsop-entering::before {
    content: "";
    position: fixed;
    inset: 0;
    background: var(--wipe-color, var(--c-blue));
    z-index: 100001;              /* above .nsop-wipe (100000) */
    pointer-events: none;
}
html.nsop-entering .nsop-wipe--enter { transform: translateY(0); animation: none; }

/* ── Reduced motion / no-JS: everything static (handled by the js-motion gate,
   but this is a belt-and-braces reset if the class is ever present). ────────── */
@media (prefers-reduced-motion: reduce) {
    html.js-motion .nsop-word,
    html.js-motion .nsop-line,
    html.js-motion .nsop-media-wave > img,
    html.js-motion .nsop-media-wave > video,
    html.js-motion .nsop-pictogram path {
        transition: none !important;
        transform: none !important;
        opacity: 1 !important;
        filter: none !important;
    }
    .nsop-wipe, .nsop-media-wave__wave { display: none !important; }
}
        /* brand motion system (js-motion gated) */

/* ── utilities/_layout.css ── */
/* =============================================================================
   NSOP — Fluid container (overrides the base .container)
   -----------------------------------------------------------------------------
   The container has no max-width (--container-max: none): it is always
   full-width with vw-proportional page margins, so the design fills and scales
   up/down with the viewport (big screen = a scaled-up small-laptop view).
   Imported last in main.css so it wins over foundation/_reset.css.
   ============================================================================= */

.container {
    max-width: none;                    /* no cap — scale indefinitely */
    padding-inline: var(--sp-page-x);   /* vw-proportional page margin, always on */
}

/* Opt-in readability cap for long-form text blocks (e.g. policy pages) where an
   unbounded measure would hurt legibility. Add to a wrapper, not the .container. */
.measure-readable {
    max-width: 75ch;
    margin-inline: auto;
}
        /* fluid container — overrides .container, must be last */
