/* ==========================================================================
   global-d.css
   Site-wide components introduced by the 2026-07-23 client round.
   Loaded last on every page, after tokens.css, variant-d.css and (on the
   secondary pages) pages-d.css.

   TOKEN NOTE, read before editing:
   Three stylesheets declare custom properties and they overlap.
     tokens.css     the documented set. Defines --ink:#1A1122.
     variant-d.css  REDEFINES --ink to #171219 and owns --soft, --quiet,
                    --focus, --paper, --lavender. Loaded after tokens, so
                    variant-d wins wherever they collide.
     pages-d.css    a parallel --p-* set, and it is NOT loaded by
                    dance-d, music-d or taekwondo-d.
   This file therefore uses only properties guaranteed on every page:
   tokens.css plus variant-d.css. Never reference a --p-* token here.

   Contains:
    1. Floating WhatsApp action  .wa-float
    2. About dropdown in the primary nav  .nav-about
    3. "Times announced soon"  .status-pill / .times-pending
    5. Carousel
    6. Video
    7. Carousel columns
    8. Two spacing corrections
    9. Section heading to its description
   10. Mobile menu
   11. Current page in the navigation  a[aria-current="page"]
   12. Header Contact action, demoted  .header-cta
   13. Department film  .dept-film
   14. Department film in the opening section  .has-film
   15. Single-photograph gallery  .gallery-single
   16. Landscape film  .gallery-film

   There is no 4. It was the header Contact rule, an outline pill that has
   since been replaced by 11, and the numbers below it are load-bearing in
   this comment only.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Floating WhatsApp action
   The primary call to action on every page, per client direction 2026-07-23.

   Uses --wa (#1FAF57), which tokens.css defines as "WhatsApp green,
   deepened for contrast". That token exists for precisely this control.
   To render the action in neutral ink instead, set --wa-bg to var(--ink).
   -------------------------------------------------------------------------- */

:root {
  --wa-bg: var(--wa);
  --wa-fg: #fff;
  --wa-gap: 20px;
}

.wa-float {
  position: fixed;
  right: var(--wa-gap);
  bottom: var(--wa-gap);
  z-index: 60;
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 14px 20px 14px 17px;
  border-radius: 999px;
  background: var(--wa-bg);
  color: var(--wa-fg);
  font-family: var(--f-body);
  font-size: .95rem;
  font-weight: 600;
  letter-spacing: .1px;
  text-decoration: none;
  box-shadow: 0 6px 28px rgba(26, 17, 34, .22);
  transition: filter .18s ease;
}

.wa-float i { font-size: 1.4rem; line-height: 1; }

/* Motion rule: no lift, no scale. Colour feedback only. */
.wa-float:hover,
.wa-float:focus-visible { filter: brightness(.92); }

.wa-float:focus-visible {
  outline: 3px solid var(--focus);
  outline-offset: 3px;
}

/* Below 640px the label is dropped and the action becomes a round mark,
   so it never covers body copy on a narrow screen. */
@media (max-width: 640px) {
  .wa-float {
    padding: 0;
    width: 56px;
    height: 56px;
    justify-content: center;
    gap: 0;
  }
  .wa-float span {
    position: absolute;
    width: 1px; height: 1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
  }
  .wa-float i { font-size: 1.65rem; }
}

/* --------------------------------------------------------------------------
   2. About dropdown in the primary navigation
   Built on <details> so it works with no JavaScript and is keyboard
   operable by default, matching the existing mobile menu pattern.
   Summary matches .desktop-nav a in variant-d.css exactly, so About does
   not read heavier than its siblings.
   -------------------------------------------------------------------------- */

.desktop-nav .nav-about { position: relative; }

.desktop-nav .nav-about > summary {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 9px 14px;
  border-radius: 6px;
  font-size: 13px;
  color: var(--soft);
  cursor: pointer;
  list-style: none;
  user-select: none;
  transition: background .2s ease, color .2s ease;
}

.desktop-nav .nav-about > summary::-webkit-details-marker { display: none; }
.desktop-nav .nav-about > summary::marker { content: ""; }

.desktop-nav .nav-about > summary:hover,
.desktop-nav .nav-about[open] > summary {
  background: #fff;
  color: var(--ink);
}

.desktop-nav .nav-about > summary i {
  font-size: .85em;
  transition: transform .18s ease;
}

.desktop-nav .nav-about[open] > summary i { transform: rotate(180deg); }

.desktop-nav .nav-about > summary:focus-visible {
  outline: 3px solid var(--focus);
  outline-offset: 4px;
}

.desktop-nav .nav-about-panel { display: none; }

.desktop-nav .nav-about[open] .nav-about-panel {
  position: absolute;
  top: calc(100% + 14px);
  left: 50%;
  transform: translateX(-50%);
  z-index: 50;
  display: flex;
  flex-direction: column;
  min-width: 190px;
  padding: 8px;
  border-radius: var(--r-sm);
  background: #fff;
  border: 1px solid var(--line);
  box-shadow: 0 12px 36px rgba(26, 17, 34, .13);
}

.desktop-nav .nav-about-panel a {
  padding: 9px 12px;
  border-radius: 9px;
  white-space: nowrap;
  transition: background-color .15s ease;
}

.desktop-nav .nav-about-panel a:hover,
.desktop-nav .nav-about-panel a:focus-visible { background: var(--paper-soft); }

/* --------------------------------------------------------------------------
   3. "Times announced soon"
   Used where a programme is running but its new term timetable has not been
   published: Tap, Modern, group music classes, Vocal, Drums, Orchestra.

   Design intent: the programme keeps full visual presence. Nothing is dimmed
   to the point of reading as unavailable. Only the schedule is pending.
   -------------------------------------------------------------------------- */

.status-pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 11px 5px 9px;
  border-radius: 999px;
  background: var(--paper-soft);
  border: 1px solid var(--line);
  color: var(--soft);
  font-family: var(--f-body);
  font-size: .78rem;
  font-weight: 600;
  letter-spacing: .1px;
  white-space: nowrap;
}

.status-pill i { font-size: .95rem; line-height: 1; }

/* The block that stands in for a timetable. */
.times-pending {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 14px;
  padding: 24px;
  border-radius: var(--r-md);
  background: var(--paper-soft);
}

.times-pending p {
  margin: 0;
  max-width: 52ch;
  color: var(--soft);
  font-size: 1rem;
  line-height: 1.55;
}

.times-pending .wa-inline {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 11px 18px;
  border-radius: 999px;
  background: var(--wa);
  color: #fff;
  font-family: var(--f-body);
  font-size: .92rem;
  font-weight: 600;
  letter-spacing: .1px;
  text-decoration: none;
  transition: filter .18s ease;
}

.times-pending .wa-inline:hover,
.times-pending .wa-inline:focus-visible { filter: brightness(.92); }

.times-pending .wa-inline i { font-size: 1.15rem; line-height: 1; }

/* --------------------------------------------------------------------------
   Reduced motion
   -------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  .wa-float,
  .header-cta,
  .desktop-nav .nav-about > summary,
  .desktop-nav .nav-about > summary i,
  .desktop-nav .nav-about-panel a,
  .times-pending .wa-inline { transition: none; }
}

/* --------------------------------------------------------------------------
   5. Carousel
   One sliding-image component for the whole site. Client direction
   2026-07-23 asked for sliding pictures across every page.

   Previously this lived in pages-d.css and was hardcoded to the studio
   carousel's element IDs, which meant it could not be used on dance-d,
   music-d or taekwondo-d, none of which load pages-d.css. It now sits here,
   uses only globally available tokens, and js/global-d.js initialises every
   instance on the page automatically.

   Minimum markup: .carousel > .carousel-viewport > .carousel-track >
   .carousel-slide[data-caption]. The bar, dots and captions are optional and
   are filled in by the script.
   -------------------------------------------------------------------------- */

.carousel{margin:0 0 26px}
.carousel-viewport{overflow:hidden;border-radius:18px;background:var(--paper-soft)}
.carousel-track{display:flex;transition:transform .45s cubic-bezier(.2,.75,.2,1)}
.carousel-slide{flex:0 0 100%;min-width:0}
.carousel-slide img{display:block;width:100%;height:clamp(300px,38vw,480px);object-fit:cover}
.carousel-bar{display:flex;align-items:center;justify-content:space-between;gap:24px;margin-top:16px}
.carousel-caption{margin:0;color:var(--soft);font-size:13px}
.carousel-controls{display:flex;align-items:center;gap:8px;flex:0 0 auto}
.carousel-btn{appearance:none;display:inline-flex;align-items:center;justify-content:center;width:40px;height:40px;border:1px solid var(--line);border-radius:8px;background:#fff;color:var(--ink);cursor:pointer;font-size:17px;transition:background .2s ease,border-color .2s ease}
.carousel-btn:hover{background:var(--paper-soft);border-color:var(--ink)}
.carousel-btn:focus-visible{outline:3px solid var(--focus);outline-offset:3px}
.carousel-dots{display:flex;align-items:center;gap:6px;margin:0 4px}
.carousel-dot{appearance:none;width:22px;height:4px;padding:0;border:0;border-radius:2px;background:#DCD5E4;cursor:pointer;transition:background .2s ease}
.carousel-dot[aria-current="true"]{background:var(--ink)}
.carousel-dot:focus-visible{outline:3px solid var(--focus);outline-offset:3px}

@media (max-width:640px){
  .carousel-bar{flex-direction:column;align-items:flex-start;gap:12px}
}

@media (prefers-reduced-motion: reduce){
  .carousel-track{transition:none}
  .carousel-btn,.carousel-dot{transition:none}
}

/* Gallery sections on the department pages.

   These were added without matching the rhythm of the sections around them:
   no vertical margin, a second horizontal padding on top of the one <main>
   already provides, which pushed them 26px out of line with every sibling,
   and a default-size h2 where the neighbouring sections use a display
   heading with supporting copy. This brings them into line. */
.dance-gallery,.t-gallery,.m-gallery{max-width:1120px;margin:clamp(110px,12vw,170px) auto;padding:0}

.gallery-head{display:grid;grid-template-columns:1.15fr .65fr;gap:clamp(40px,7vw,90px);align-items:end;margin-bottom:clamp(30px,3.2vw,46px)}
.gallery-head>div>i{display:block;margin-bottom:16px;font-size:32px;color:var(--quiet)}
.gallery-head h2{max-width:650px;margin:0;font-size:clamp(34px,4vw,51px);line-height:1.2;text-wrap:pretty}
.gallery-head>p{max-width:420px;margin:0 0 7px;color:var(--soft);font-size:15px;line-height:1.6}

@media (max-width:1000px){
  .gallery-head{grid-template-columns:1fr;gap:20px;align-items:start}
}
@media (max-width:680px){
  .dance-gallery,.t-gallery,.m-gallery{margin:96px auto}
  .gallery-head h2{font-size:34px}
  .gallery-head>p{font-size:14px}
}

/* --------------------------------------------------------------------------
   6. Video
   Client direction 2026-08-10: YouTube opens in a modal rather than sending
   the visitor away, and video must not slow the site down. Shubham raised
   the old site's speed problems in the 2026-07-23 meeting.

   Everything here is a "facade": we render a poster image and a play button,
   and load nothing from YouTube until the visitor actually clicks. A normal
   YouTube embed pulls roughly half a megabyte of script per video on page
   load. This pulls a single image, and it is a local one.

   Playback uses youtube-nocookie.com, which sets no tracking cookie until
   play. That matters here because the school's privacy policy is already
   inadequate for UAE PDPL, see AI-HANDOFF section 16b.
   -------------------------------------------------------------------------- */

.video-facade{position:relative;display:block;width:100%;margin:0;padding:0;border:0;border-radius:18px;overflow:hidden;background:var(--paper-soft);cursor:pointer;aspect-ratio:16/9}
.video-facade.is-portrait{aspect-ratio:9/16}
.video-facade img{display:block;width:100%;height:100%;object-fit:cover}
.video-facade iframe{position:absolute;inset:0;width:100%;height:100%;border:0}

/* Play button. Sits on a scrim so it stays legible on any thumbnail. */
.video-facade::after{content:"";position:absolute;inset:0;background:linear-gradient(180deg,rgba(26,17,34,0) 40%,rgba(26,17,34,.35) 100%);pointer-events:none;transition:opacity .2s ease}
.video-facade.is-playing::after{display:none}
.video-play{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);display:inline-flex;align-items:center;justify-content:center;width:66px;height:66px;border-radius:999px;background:rgba(255,255,255,.94);color:var(--ink);pointer-events:none;transition:background-color .2s ease}
.video-play i{font-size:28px;margin-left:3px;line-height:1}
.video-facade:hover .video-play{background:#fff}
.video-facade:focus-visible{outline:3px solid var(--focus);outline-offset:3px}
.video-facade-label{position:absolute;left:16px;right:16px;bottom:14px;color:#fff;font-family:var(--f-body);font-size:13px;font-weight:600;letter-spacing:.1px;text-align:left;pointer-events:none;text-shadow:0 1px 3px rgba(26,17,34,.5)}
.video-facade.is-playing .video-play,
.video-facade.is-playing .video-facade-label{display:none}

/* --- Modal ---------------------------------------------------------------
   Used for videos that live elsewhere on the page, so a visitor is never
   taken off to YouTube. Built on <dialog> for the focus trap and Escape
   handling the browser already provides. */
.video-modal{width:min(92vw,1040px);max-width:none;padding:0;border:0;border-radius:18px;background:#000;overflow:hidden}
.video-modal::backdrop{background:rgba(26,17,34,.72)}
.video-modal-frame{position:relative;width:100%;aspect-ratio:16/9;background:#000}
.video-modal-frame iframe{position:absolute;inset:0;width:100%;height:100%;border:0}
.video-modal-close{position:absolute;top:10px;right:10px;z-index:2;display:inline-flex;align-items:center;justify-content:center;width:40px;height:40px;border:0;border-radius:999px;background:rgba(255,255,255,.92);color:var(--ink);cursor:pointer;font-size:19px}
.video-modal-close:hover{background:#fff}
.video-modal-close:focus-visible{outline:3px solid #fff;outline-offset:2px}

@media (max-width:640px){
  .video-play{width:54px;height:54px}
  .video-play i{font-size:23px}
}

@media (prefers-reduced-motion: reduce){
  .video-facade::after,.video-play,.video-modal-close{transition:none}
}

/* --------------------------------------------------------------------------
   7. Carousel columns
   Client direction 2026-08-10: photo carousels show several pictures at
   once, and each carousel chooses its own column count.

   Set the columns per breakpoint on the element itself:

     <div class="carousel" style="--cols-d:3;--cols-t:2;--cols-m:1">

   --cols-d  desktop, 901px and up
   --cols-t  tablet, 641 to 900px
   --cols-m  mobile, 640px and down

   All three default to 1, so a carousel with no setting behaves exactly as
   it always did: one image at a time. These are plain custom properties, so
   the layout is correct on first paint with no JavaScript involved. The
   script only reads the resulting width to know how far to page.

   Add data-lightbox to let the photographs open large on click.
   -------------------------------------------------------------------------- */

.carousel{--cols-d:1;--cols-t:1;--cols-m:1;--cols:var(--cols-m);--col-gap:12px}
@media (min-width:641px){ .carousel{--cols:var(--cols-t)} }
@media (min-width:901px){ .carousel{--cols:var(--cols-d)} }

.carousel-track{gap:var(--col-gap)}
.carousel-slide{flex:0 0 calc((100% - (var(--cols) - 1) * var(--col-gap)) / var(--cols))}

/* Multi-column carousels are galleries: shorter images, no viewport frame. */
.carousel[data-view="2"] .carousel-viewport,
.carousel[data-view="3"] .carousel-viewport,
.carousel[data-view="4"] .carousel-viewport{background:transparent;border-radius:0}
.carousel[data-view="2"] .carousel-slide img,
.carousel[data-view="3"] .carousel-slide img,
.carousel[data-view="4"] .carousel-slide img{height:clamp(190px,19vw,250px);border-radius:14px}

/* A single caption cannot describe several visible photographs, so it is
   hidden whenever more than one is on screen. data-view is written by the
   script from the measured layout, so this stays correct through a resize.
   Per-image captions still appear in the lightbox at every size. */
.carousel[data-view="2"] .carousel-caption,
.carousel[data-view="3"] .carousel-caption,
.carousel[data-view="4"] .carousel-caption{display:none}
.carousel[data-view="2"] .carousel-bar,
.carousel[data-view="3"] .carousel-bar,
.carousel[data-view="4"] .carousel-bar{justify-content:flex-end}

/* The zoom affordance. A real button, so the lightbox is keyboard reachable. */
.zoom-btn{display:block;width:100%;padding:0;border:0;background:none;cursor:zoom-in;border-radius:14px;overflow:hidden;position:relative}
.zoom-btn:focus-visible{outline:3px solid var(--focus);outline-offset:3px}
.zoom-btn::after{content:"";position:absolute;inset:0;background:rgba(26,17,34,0);transition:background-color .2s ease}
.zoom-btn:hover::after{background:rgba(26,17,34,.12)}

/* --- Lightbox ------------------------------------------------------------ */
.lightbox{width:min(94vw,1180px);max-width:none;max-height:94vh;padding:0;border:0;border-radius:18px;background:transparent;overflow:visible}
.lightbox::backdrop{background:rgba(26,17,34,.86)}
.lightbox-figure{margin:0;display:flex;flex-direction:column;gap:14px}
.lightbox img{display:block;width:100%;max-height:78vh;object-fit:contain;border-radius:14px;background:#000}
.lightbox figcaption{display:flex;align-items:center;justify-content:space-between;gap:20px;color:#fff;font-family:var(--f-body);font-size:13px}
.lightbox-count{flex:0 0 auto;opacity:.72;font-variant-numeric:tabular-nums}
.lightbox-close,.lightbox-nav{position:absolute;z-index:2;display:inline-flex;align-items:center;justify-content:center;width:44px;height:44px;border:0;border-radius:999px;background:rgba(255,255,255,.92);color:var(--ink);cursor:pointer;font-size:19px;transition:background-color .2s ease}
.lightbox-close:hover,.lightbox-nav:hover{background:#fff}
.lightbox-close:focus-visible,.lightbox-nav:focus-visible{outline:3px solid #fff;outline-offset:2px}
.lightbox-close{top:-14px;right:-14px}
.lightbox-nav.is-prev{left:-14px;top:50%;transform:translateY(-50%)}
.lightbox-nav.is-next{right:-14px;top:50%;transform:translateY(-50%)}

@media (max-width:640px){
  .lightbox{width:94vw}
  .lightbox-close{top:8px;right:8px}
  .lightbox-nav.is-prev{left:6px}
  .lightbox-nav.is-next{right:6px}
}

@media (prefers-reduced-motion: reduce){
  .zoom-btn::after,.lightbox-close,.lightbox-nav{transition:none}
}

/* A carousel whose slides all fit has nothing to page to. The script hides
   the controls, and the whole bar when the caption is hidden too, so no
   empty strip is left holding space. */
.carousel-controls[hidden],
.carousel-bar[hidden]{display:none}

/* --------------------------------------------------------------------------
   8. Two spacing corrections
   -------------------------------------------------------------------------- */

/* The "Times announced soon" pill was appended as a fifth child of .m-row,
   which is a four column grid. It therefore landed in column one of an
   implicit new row and was squeezed to 44px while its text needs 179px, so
   the grey background ended well short of the words. Place it under the
   programme name at its natural width instead. */
.m-row .status-pill{grid-column:2 / -1;justify-self:start;margin-top:8px}

/* "Or call 04 344 9776" ran together: at 11px a word space is about 3px, and
   the number is 600 weight against 400 body text, so the two read as one
   word. Give the number a little air. */
.m-trial-action span a,
.cta-action > span a,
.trial-action p a,
.t-trial-action span a,
.dance-trial-action span a{margin-left:.3em}

/* --------------------------------------------------------------------------
   9. Section heading to its description
   The gap ranged from 8px to 22px depending on which stylesheet set it, and
   the music ladder at 8px sat noticeably tighter than its own neighbours.
   One value now, roughly double the old typical.

   Each section head is named explicitly because the page stylesheets pin
   their paragraphs with `p{margin:0}`, which is class specificity and beats
   a bare `h2 + p`. The heading's own bottom margin is zeroed in the same
   rule so the result is exact: margins collapse in a block container but add
   inside a flex one, and several of these are flex.
   -------------------------------------------------------------------------- */

:root{ --head-gap: clamp(24px, 2.4vw, 36px); }

.m-ladder-head h2,
.m-standards-copy h2,
.m-route-side h2,
.standards-copy h2,
.timetable-copy h2,
.h2-faq-wrap h2,
.t-outcomes h2,
.section-head h2,
.h2-head h2,
.ds-section-head h2{ margin-bottom: 0; }

.m-ladder-head h2 + p,
.m-standards-copy h2 + p,
.m-route-side h2 + p,
.standards-copy h2 + p,
.timetable-copy h2 + p,
.h2-faq-wrap h2 + p,
.t-outcomes h2 + p,
.section-head h2 + p,
.h2-head h2 + p,
.ds-section-head h2 + p,
.tt-pending-head h2 + p,
.gallery-head h2 + p{ margin-top: var(--head-gap); }

/* The privacy page is a legal document with thirteen heading and paragraph
   pairs. Doubling every one would balloon the page, so it keeps its own
   tighter rhythm. */
.prose h2{ margin-bottom: 14px; }
.prose h2 + p{ margin-top: 0; }

/* --------------------------------------------------------------------------
   10. Mobile menu
   It was a 210px dropdown pinned to the right of the header, and the About
   destinations sat flat in the list, so the menu ran to eleven items. Client
   direction 2026-08-10: full width, with About as an accordion mirroring the
   desktop dropdown.
   -------------------------------------------------------------------------- */

@media (max-width:1000px){
  /* The panel escapes the 210px box and spans the viewport. Fixed rather than
     absolute so it hangs off the header, not off the 44px kebab button. */
  /* Full height, so the open menu covers the floating WhatsApp action rather
     than leaving two WhatsApp calls to action on screen at once. A column,
     so the action sits at the bottom instead of floating mid-panel. */
  .mobile-menu nav{
    position:fixed;
    left:0; right:0; top:var(--header-h,72px);
    z-index:70;
    width:auto;
    height:calc(100dvh - var(--header-h,72px));
    display:flex; flex-direction:column;
    overflow-y:auto;
    padding:10px 18px calc(18px + env(safe-area-inset-bottom));
    border-radius:0;
    border-top:1px solid var(--line);
    box-shadow:none;
  }

  /* Older engines without dvh fall back to vh. */
  @supports not (height: 100dvh){
    .mobile-menu nav{ height:calc(100vh - var(--header-h,72px)); }
  }

  .mobile-menu nav > a,
  .mobile-menu .m-about > summary,
  .mobile-menu .m-about-panel a{
    display:flex; align-items:center;
    padding:14px 12px;
    border-radius:8px;
    font-size:15px;
  }

  /* About behaves like the desktop dropdown: tap to reveal its children. */
  .mobile-menu .m-about{ border-radius:8px; }
  /* variant-d.css styles `.mobile-menu summary` as the 44x44 kebab button,
     and that descendant selector also catches this one, which is why the
     About row was 44px wide inside a 354px menu. Undo the button sizing. */
  .mobile-menu .m-about > summary{
    width:auto; height:auto; margin-right:0;
    justify-content:space-between;
    cursor:pointer; list-style:none;
    color:var(--ink);
  }
  .mobile-menu .m-about > summary::-webkit-details-marker{ display:none; }
  .mobile-menu .m-about > summary::marker{ content:""; }
  .mobile-menu .m-about > summary i{ font-size:14px; transition:transform .18s ease; }
  .mobile-menu .m-about[open] > summary{ background:var(--paper-soft); }
  .mobile-menu .m-about[open] > summary i{ transform:rotate(180deg); }

  /* A <details> hides its non-summary children, but an explicit display on a
     child overrides that and the panel never collapses. Only lay it out when
     the accordion is actually open. */
  .mobile-menu .m-about-panel{ display:none; }
  .mobile-menu .m-about[open] .m-about-panel{
    display:flex; flex-direction:column;
    margin:2px 0 6px;
    padding-left:10px;
    border-left:2px solid var(--line);
  }
  .mobile-menu .m-about-panel a{ padding-top:12px; padding-bottom:12px; color:var(--soft); }

  /* The WhatsApp action spans the menu rather than sitting as a text link. */
  .mobile-menu nav .mobile-cta{
    justify-content:center; gap:9px;
    margin-top:auto; padding:15px 16px;
    border-radius:999px;
    background:var(--wa); color:#fff;
    font-weight:600; box-shadow:none;
  }
  .mobile-menu nav .mobile-cta i{ font-size:19px; }
}

@media (prefers-reduced-motion: reduce){
  .mobile-menu .m-about > summary i{ transition:none; }
}

/* While the full height menu is open: freeze the page behind it and take the
   floating action out of the way, so there is only ever one WhatsApp call to
   action on screen. */
body.menu-open{ overflow:hidden; }
body.menu-open .wa-float,
body.menu-open .review-fab{ display:none; }

/* Inline emphasis inside body copy. The client bolds phrases in their approved
   text, so those come through as <strong>. Browser default 700 is too heavy
   against Switzer 400 body copy; 600 plus the ink colour reads as deliberate
   emphasis rather than shouting.

   The colour goes through --strong-ink so a reversed surface can opt out. A
   flat color:var(--ink) painted the client's bold phrases near black on the
   dark CTA bands and the taekwondo hero bar, where the copy around them is
   white: the emphasised words simply vanished. Any surface that reverses its
   copy sets --strong-ink:currentColor in the block below, which makes the
   emphasis inherit whatever the copy colour is and leaves weight 600 to do the
   work. If you add a new dark section, add it there too. */
strong{font-weight:600;color:var(--strong-ink,var(--ink))}

/* Reversed surfaces. Every one of these sets color:#fff on its own copy, so
   emphasis inside them must inherit rather than reach for ink. Grouped here
   rather than spread through the department stylesheets so the whole set is
   visible at once. */
.cta-band,                       /* pages-d.css, the shared trial band */
.trial,                          /* variant-d.css, the homepage trial band */
.hero-copy,                      /* variant-d.css, homepage hero above 680px */
.dance-hero-bar, .dance-pathway, .dance-trial,
.m-hero-bar, .m-trial,
.t-hero-bar, .t-trial,
.t-level:nth-child(4), .t-level:nth-child(5),
.h2-step:nth-child(4),
.dept-tile>span,
.video-facade-label,
.lightbox figcaption{ --strong-ink: currentColor; }

/* Base leading for headings. Rules that set their own line-height are all on
   1.2 too (tools/heading_leading.py); this catches the ones that never
   declared one and were inheriting body leading. */
h1,h2,h3{line-height:1.2}

/* Headings use text-wrap:pretty, not balance. Balance equalises line lengths,
   which suited the original three and four word headings but breaks the
   client's longer two sentence ones in odd places: 'From First Steps / to
   Centre Stage.' Pretty only tidies the last line, leaving the rest to wrap
   normally. Browsers without it fall back to normal wrapping. */

/* --------------------------------------------------------------------------
  11. Current page in the navigation
   The site shipped without one. The rule existed in dance-d, music-d and
   taekwondo-d, each scoped to a `.<dept>-page` body class that only three of
   216 pages carried, and nothing ever set the attribute. tools/add_nav_current.py
   sets it now, from each page's own breadcrumb, and this styles it everywhere.

   Two surfaces, so two treatments. Top level links sit on the nav's grey
   field, so current is a white chip, the same shape hover already uses. Panel
   links sit on white, where a white chip would be invisible, so those take the
   soft paper fill instead.
   -------------------------------------------------------------------------- */

.desktop-nav > a[aria-current="page"] {
  background: #fff;
  color: var(--ink);
  font-weight: 600;
  box-shadow: 0 1px 2px rgba(26, 17, 34, .06);
}

.desktop-nav .nav-about-panel a[aria-current="page"] {
  background: var(--paper-soft);
  color: var(--ink);
  font-weight: 600;
}

/* An article or a teacher page is current inside the About panel, which is
   closed by default, so without this the header would show no state at all on
   156 of the pages. :has() carries it; a browser without :has() simply shows
   the state once the panel is open. */
.desktop-nav .nav-about:has(a[aria-current="page"]) > summary {
  background: #fff;
  color: var(--ink);
  font-weight: 600;
  box-shadow: 0 1px 2px rgba(26, 17, 34, .06);
}

.mobile-menu .m-about:has(a[aria-current="page"]) > summary {
  background: #f7f6f8;
  font-weight: 600;
}

/* --------------------------------------------------------------------------
  12. Header Contact action, sized and filled to match the nav
   It stays demoted, per the 2026-07-23 direction that WhatsApp is the only
   primary call to action. What it stopped doing is looking like a stray form
   control parked beside the nav: it was a transparent pill with a 1px
   #EDE9F2 hairline, 44px tall against the nav's 48, on a 8px radius against
   the nav's 9px.

   Same grey field as the nav, same height, same radius, no ring. It now reads
   as the last item in the header group rather than a competing button, and
   hover lifts it to white exactly as the nav links do.
   -------------------------------------------------------------------------- */

.header-cta {
  background: #F7F6F8 !important;
  color: var(--ink) !important;
  padding: 14px 18px;
  border-radius: 9px;
  box-shadow: none;
  transition: background-color .2s ease, box-shadow .2s ease;
}

.header-cta:hover,
.header-cta:focus-visible {
  background: #fff !important;
  box-shadow: 0 1px 2px rgba(26, 17, 34, .06);
}

/* --------------------------------------------------------------------------
   13. Department film
   The client's 2026 clips are 1080x1920, shot vertical for social. Letterboxing
   them into the 16:9 frame the YouTube facades use would waste half the width
   on black, so they get a portrait player set beside the copy rather than
   above it. That also stops a 9:16 video eating a whole phone screen on its
   own.

   preload="none" is on the element, so a visitor who never presses play
   downloads none of it. The poster is a real frame, pulled one second in.
   -------------------------------------------------------------------------- */

/* Contained, not spread. At the section's full 1120px the copy column was a
   1fr against a 274px video, so it took every spare pixel and threw the player
   against the right edge with 400px of nothing between them. The pair is a
   single unit: hold it to a width the two columns actually fill, and centre
   that in the section. */
.dept-film {
  max-width: 780px;
  margin: 0 auto;
  display: grid;
  grid-template-columns: 1fr auto;
  gap: clamp(28px, 4vw, 52px);
  align-items: center;
}

.dept-film-copy h2 {
  margin: 6px 0 0;
  font-size: clamp(26px, 2.6vw, 34px);
  line-height: 1.2;
  text-wrap: pretty;
}

.dept-film-copy p:last-child {
  margin: 14px 0 0;
  max-width: 38ch;
  color: var(--ink-soft);
  font-size: 15.5px;
  line-height: 1.65;
}

.dept-film-player {
  width: clamp(230px, 24vw, 290px);
  aspect-ratio: 9 / 16;
  height: auto;
  border-radius: 16px;
  background: #17121a;
  object-fit: cover;
  box-shadow: 0 1px 2px rgba(26, 17, 34, .05), 0 10px 30px rgba(26, 17, 34, .10);
}

@media (max-width: 760px) {
  /* Copy first, then the film. Stacked, the player takes a comfortable width
     rather than the full column, which a 9:16 video would otherwise fill for
     an entire screen height. */
  .dept-film { grid-template-columns: 1fr; gap: 26px; justify-items: start; }
  .dept-film-player { width: min(280px, 78%); }
}

/* --------------------------------------------------------------------------
   14. Department film in the opening section
   The three department pages each open on a two column block: icon and heading
   on the left, a paragraph on the right. The film goes in that right column and
   the paragraph moves under the heading it belongs to, so the column reads
   heading then the sentence explaining it. Same shape as the Our Centre head.

   Loaded after dance-d, music-d and taekwondo-d, so these override the column
   sizing each of them sets. The paragraph selectors in those files are written
   as `.m-opening > p`, a direct child, and the paragraph is no longer one, so
   its type styles are restated here.
   -------------------------------------------------------------------------- */

.dance-opening.has-film,
.m-opening.has-film,
.t-opening.has-film {
  grid-template-columns: 1.15fr .85fr;
  gap: clamp(36px, 5vw, 64px);
  align-items: center;
}

.has-film > div > p {
  max-width: 52ch;
  margin: 18px 0 0;
  color: var(--soft);
  font-size: 15px;
  line-height: 1.6;
}

.has-film > .dept-film-player { justify-self: center; }

@media (max-width: 860px) {
  .dance-opening.has-film,
  .m-opening.has-film,
  .t-opening.has-film { grid-template-columns: 1fr; gap: 28px; align-items: start; }
  .has-film > .dept-film-player { justify-self: start; width: min(260px, 72%); }
}

/* --------------------------------------------------------------------------
   15. Single-photograph gallery
   Some pages got exactly one photograph in the client's September round.
   A one-slide carousel is a slider with nothing to slide to, so those take a
   plain figure at the same width the carousel would have used.
   -------------------------------------------------------------------------- */

.gallery-single {
  max-width: 1120px;
  margin: 0 auto;
}

.gallery-single img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 16px;
}

/* --------------------------------------------------------------------------
   16. Landscape film
   The September clips are 16:9, unlike the vertical ones from the shoot before,
   so they take the full content width rather than the portrait player in 13.
   preload="none" here too: nothing downloads until somebody presses play.
   -------------------------------------------------------------------------- */

.gallery-film {
  max-width: 1120px;
  margin: 0 auto;
}

.gallery-film video {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 16 / 9;
  border-radius: 16px;
  background: #17121a;
  object-fit: cover;
}
