/* MPL – accessibility layer (WCAG 2.2 AA source remediation).
 *
 * Loaded LAST, after main.css / rtl.css / booking.css / summer.css /
 * site-extra.css, so it can correct the mockup stylesheets without rewriting
 * them. Every rule here exists because a specific success criterion failed at
 * source; each block names the criterion and the defect.
 *
 * Asserted by scripts/verify-a11y-static.mjs (tokens, contrast maths, focus
 * rules, target sizes) and by scripts/browser/a11y.spec.mjs (rendered
 * behaviour). Do not add a rule here without a matching assertion.
 */

/* ═══════════════════════════════════════════════════════════════════════
   1. CONTRAST — 1.4.3 (text) and 1.4.11 (non-text)
   The brand orange #FF6B00 is UNCHANGED: it stays the accent for text on the
   dark surfaces (6.9:1) and for every border, icon and glow. What failed was
   white LABELS on that orange — #FFFFFF on #FF6B00 is 2.9:1, below the 4.5:1
   needed for 14px bold text and below even the 3:1 large-text floor. Filled
   brand controls therefore carry near-black ink (6.9:1) instead of white, so
   the palette itself is preserved and only the label colour moves.
   Exception, per WCAG 1.4.11: the WhatsApp FAB is a brand logotype
   (white glyph on #25D366) and is exempt; it is left exactly as designed.
   ═══════════════════════════════════════════════════════════════════════ */
:root {
  /* ink used on any surface painted with --orange / --orange-light */
  --on-orange: #0A0A0A;
  /* Focus ring: a DUAL-TONE indicator (white core, near-black halo). A single
     white ring is only 2.9:1 against a brand-orange control, so it would fail
     1.4.11 exactly where it is needed most; the near-black halo is 6.9:1
     against that orange and the white core is 19:1 against the dark page, so
     one indicator contrasts on every surface the site uses. */
  --focus-ring: #FFFFFF;
  --focus-halo: #0A0A0A;
}

/* Every rule below remediates ONE white-on-orange combination that
   scripts/css-contrast-inventory.mjs found in main.css / booking.css /
   summer.css. That inventory is re-derived from the built stylesheets on every
   run, so this list cannot silently fall behind the source: a new
   `color: #fff` on a brand-orange surface fails `npm run test:builds` until it
   appears here. The first version of this file listed four selectors by hand
   and missed twenty — including the skip link, the language switcher, the
   programs filter, the offer-banner marquee and eight booking-wizard
   selections, every one of them 2.9:1.

   Selector order below follows the source sheets, so a reviewer can walk the
   inventory output and this block side by side. */

/* — main.css — */
.skip-link,
.btn--primary,
.btn--primary:hover,
.btn--primary:focus,
.btn--ghost:hover,
.btn--ghost:focus-visible,
.lang-switcher__btn.active,
.lang-switcher__btn:hover,
.programs__tab.active,
.program-card__badge,
.offer-banner__item {
  color: var(--on-orange);
}
/* The social glyph is non-text content on an orange chip: 1.4.11 wants 3:1,
   white gives 2.9:1, this gives 6.9:1. */
.footer__social:hover svg { fill: var(--on-orange); }
/* The marquee dismiss painted white on a black-washed orange (4.5:1 only if
   the wash lands exactly right). A white wash + near-black ink is unambiguous
   and keeps the control reading as a button. */
.offer-banner__close {
  color: var(--on-orange);
  background: rgba(255, 255, 255, 0.35);
}
.offer-banner__close:hover { background: rgba(255, 255, 255, 0.55); }

/* — booking.css — */
.step-indicator__item.active .step-num,
.booking-stage .program-card__badge,
.booking-stage .program-card__popular,
.slot-btn.selected,
.date-btn.selected,
.date-btn.selected .date-btn__avail,
.time-btn.selected,
.time-btn.selected .time-btn__spots {
  color: var(--on-orange);
}
/* Selection ticks: non-text content on an orange disc (1.4.11). */
.booking-stage .program-card__check svg,
.booking-stage .coach-card__check svg {
  stroke: var(--on-orange);
}

/* — summer.css — */
.summer-hero__badge,
.program-card__badge--summer,
.btn--outline:hover,
.kids-qty__btn:hover:not(:disabled) {
  color: var(--on-orange);
}

/* The strip repainted dark green (offer-banner, 2026-09-15; main.css
 * --campaign-green) — white ink is 14.7:1 there, so it no longer takes its
 * colour from --on-orange (near-black, which would sit invisibly on a dark
 * surface). See scripts/verify-a11y-static.mjs CONTRAST_PAIRS. */
.summer-strip__link,
.summer-strip__link:visited,
.summer-strip__flag {
  color: var(--white);
}

/* The summer strip close button sits on the (now dark-green) strip; the
 * circle's white tint is raised from .35/.55 to .45/.65 so the on-orange
 * (near-black) icon still clears 4.5:1 against the composited circle. */
.summer-strip__close {
  color: var(--on-orange);
  background: rgba(255, 255, 255, 0.45);
}
.summer-strip__close:hover { background: rgba(255, 255, 255, 0.65); }

/* ═══════════════════════════════════════════════════════════════════════
   2. FOCUS VISIBILITY — 2.4.7 / 2.4.11
   `outline: none` appeared on form inputs (main.css, summer.css) and on the
   booking wizard inputs (booking.css) with only a border-colour change to
   replace it, which disappears entirely in forced-colours mode. Nothing here
   removes an outline; this establishes ONE visible indicator for every
   interactive element on the site, including the ones injected at runtime by
   site-live.js (the consultation modal, generated slides, coach clones).
   ═══════════════════════════════════════════════════════════════════════ */
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
summary:focus-visible,
[tabindex]:focus-visible {
  outline: 3px solid var(--focus-ring);
  outline-offset: 2px;
  box-shadow: 0 0 0 6px var(--focus-halo);
  border-radius: 4px;
}

/* Inputs keep their own rounding so the ring hugs the field. */
.form-field input:focus-visible,
.form-field select:focus-visible,
.summer-form__input:focus-visible,
.form-input:focus-visible {
  outline: 3px solid var(--focus-ring);
  outline-offset: 1px;
  box-shadow: 0 0 0 5px var(--focus-halo);
  border-radius: var(--radius, 8px);
}

/* The skip link is positioned off-screen until focused; keep it visible with
   the same ring rather than the browser default it previously relied on. */
.skip-link:focus-visible {
  outline: 3px solid var(--focus-ring);
  outline-offset: 2px;
}

/* Forced-colours users get the system focus indicator, undiluted. */
@media (forced-colors: active) {
  a:focus-visible,
  button:focus-visible,
  input:focus-visible,
  select:focus-visible,
  textarea:focus-visible,
  [tabindex]:focus-visible {
    outline: 3px solid Highlight;
    box-shadow: none;
  }
}

/* ═══════════════════════════════════════════════════════════════════════
   3. TARGET SIZE — 2.5.8 (minimum)
   The promo dismiss button was 22×22 and the slider pager dots 10×10. The
   visual size is preserved by painting into the content box and growing the
   target with padding.
   ═══════════════════════════════════════════════════════════════════════ */

/* The strip clipped its own overflow, which would also have clipped a larger
   hit area; the link already ellipsises on its own, so clipping moves there. */
.summer-strip { overflow: visible; }
.summer-strip__link { overflow: hidden; }

.summer-strip__close {
  width: 44px;
  height: 44px;
  padding: 11px;
  background-clip: content-box;
  box-sizing: border-box;
}

/* ═══════════════════════════════════════════════════════════════════════
   3b. USE OF COLOUR — 1.4.1
   The active programs filter differed from the inactive ones ONLY by fill
   colour (orange vs transparent). aria-pressed carries the state to assistive
   technology, but a sighted user with a colour-vision deficiency, a monochrome
   display or a forced-colours theme had no cue at all. The inset ring is a
   SHAPE difference and the heavier, underlined label a TYPOGRAPHIC one, so the
   selected filter survives being rendered in greyscale.
   ═══════════════════════════════════════════════════════════════════════ */
.programs__tab.active {
  box-shadow: inset 0 0 0 2px var(--on-orange);
  font-weight: 800;
  text-decoration: underline;
  text-underline-offset: 3px;
}
@media (forced-colors: active) {
  .programs__tab.active { border: 2px solid ButtonText; }
}

.summer-slider__dot {
  width: 24px;
  height: 24px;
  padding: 7px;
  background-clip: content-box;
  /* WCAG 1.4.11 — summer.css paints rgba(255,255,255,.25), which composites to
   * #474747 on --dark #0A0A0A: 2.13:1, under the 3:1 floor for a non-text UI
   * component. These dots are enabled controls, so no "inactive" exemption
   * applies. .45 gives #787878 = 4.48:1. Longhand only, so the shorthand does
   * not reset background-clip above. */
  background-color: rgba(255, 255, 255, 0.45);
  box-sizing: border-box;
}
.summer-slider__dot.active { transform: none; }
.summer-slider__dot.active,
.summer-slider__dot[aria-current='true'] {
  background: var(--orange);
  box-shadow: 0 0 0 2px rgba(255, 107, 0, 0.35);
}

/* ═══════════════════════════════════════════════════════════════════════
   4. PAUSE / STOP CONTROLS — 2.2.2
   The promo slider auto-rotates every 4s and the showcase clips loop forever.
   Both now ship a real control; these rules give them a 44px target and keep
   them legible over the media they sit on.
   ═══════════════════════════════════════════════════════════════════════ */
.summer-slider__dots {
  align-items: center;
}
.summer-slider__motion,
.video-item .motion-toggle {
  width: 44px;
  height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  border: 1px solid rgba(255, 255, 255, 0.35);
  background: rgba(10, 10, 10, 0.72);
  color: #fff;
  font-size: 13px;
  line-height: 1;
  cursor: pointer;
}
.summer-slider__motion:hover,
.video-item .motion-toggle:hover {
  background: rgba(10, 10, 10, 0.9);
  border-color: #fff;
}
.video-item { position: relative; }
.video-item .motion-toggle {
  position: absolute;
  top: 10px;
  inset-inline-end: 10px;
  z-index: 3;
}

/* ═══════════════════════════════════════════════════════════════════════
   5. REDUCED MOTION — 2.3.3
   Nothing in the site honoured prefers-reduced-motion: the count-up, the
   promo fade, the pulsing summer badge, the marquee, every hover lift and
   smooth scrolling all ran regardless. Transitions are shortened rather than
   deleted so state changes stay perceivable.
   ═══════════════════════════════════════════════════════════════════════ */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }

  /* Movement-on-hover is the part that actually causes discomfort. */
  .btn--primary:hover,
  .btn--outline:hover,
  .whatsapp-fab:hover,
  .map-placeholder:hover,
  .summer-slider__dot.active {
    transform: none !important;
  }

  .summer-strip.is-marquee .summer-strip__link,
  .offer-banner__marquee {
    animation: none !important;
    transform: none !important;
  }
}

/* ═══════════════════════════════════════════════════════════════════════
   6. MAP — 4.1.2 (nested interactive content)
   The "open in Google Maps" link used to WRAP the embed. It is now the
   overlay, a sibling of an inert frame. These rules re-point the hover and
   focus states that used to be written as `.map-link:hover .map-placeholder`.
   ═══════════════════════════════════════════════════════════════════════ */
.map-placeholder__frame {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
}
.map-placeholder__frame iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  filter: grayscale(0.8) brightness(0.6) contrast(1.2);
  transition: filter 0.4s ease;
}
a.map-link.map-placeholder__overlay {
  z-index: 2;
  text-decoration: none;
  color: inherit;
  cursor: pointer;
}
.map-placeholder:hover,
.map-placeholder:focus-within {
  border-color: var(--orange);
  transform: translateY(-4px);
  box-shadow: 0 16px 48px rgba(255, 107, 0, 0.2);
}
.map-placeholder:hover .map-placeholder__frame iframe,
.map-placeholder:focus-within .map-placeholder__frame iframe {
  filter: grayscale(0.3) brightness(0.7) contrast(1.1);
}
.map-placeholder:hover .map-placeholder__overlay,
.map-placeholder:focus-within .map-placeholder__overlay {
  background: rgba(10, 10, 10, 0.3);
}

/* ═══════════════════════════════════════════════════════════════════════
   7. (retired) ANALYTICS CONSENT NOTICE
   Removed 2026-09-17: analytics runs cookieless (Consent Mode v2, every
   storage type denied, never updated — public/js/analytics.js), so there is
   no notice, no reopen control and nothing fixed to the bottom of the
   viewport that could obscure focus. verify-a11y-static.mjs asserts the
   notice stays absent.
   ═══════════════════════════════════════════════════════════════════════ */

/* ===== Arabic tracking on the booking wizard =====
   booking.css loads AFTER rtl.css, and `.booking-stage .program-card__name`
   (0,2,0) also outranks the reset there (0,1,0) — so every Arabic string on
   /booking-ar/ kept its Latin letter-spacing, prising apart joined glyphs on
   the one flow that takes money. a11y.css loads last and these selectors carry
   [dir="rtl"] plus the same class chain, so they win on both order AND
   specificity. Covers every tracked selector in booking.css. */
[dir="rtl"] .booking-hero__label,
[dir="rtl"] .booking-hero__title,
[dir="rtl"] .step-label,
[dir="rtl"] .booking-stage .program-card__badge,
[dir="rtl"] .booking-stage .program-card__name,
[dir="rtl"] .booking-stage .program-card__popular,
[dir="rtl"] .section-heading,
[dir="rtl"] .booking-stage .coach-card__avail,
[dir="rtl"] .slot-day-header,
[dir="rtl"] .date-btn__day,
[dir="rtl"] .booking-summary__title,
[dir="rtl"] .booking-summary__key,
[dir="rtl"] .form-label,
[dir="rtl"] .success-title,
[dir="rtl"] .entry-sub-option__name,
[dir="rtl"] .tier-sub-option__name {
  letter-spacing: 0;
}
