@charset "UTF-8";
/* ============================================================================
   BALLERS AMMAN
   One stylesheet, four pages, two directions.

   Tokens are ported verbatim from plan/01-design-tokens.md §1, keeping the same
   names. Contrast ratios in the comments are the verified figures from that
   ledger — do not change a colour without re-measuring.

   Layout uses logical properties throughout (margin-inline-start, inset-inline,
   padding-block) so a single stylesheet serves LTR and RTL. There is no
   direction-specific layout code except where a glyph must physically mirror.
   ========================================================================= */

:root {
  /* ---- Surfaces ---------------------------------------------------------- */
  --color-court: #000000;          /* page canvas — true black, never #0a0a0a */
  --color-deck: #0d0d0d;           /* footer, deep sections */
  --color-slab: #141414;           /* cards, panels, pricing tiers */
  --color-slab-raised: #202020;    /* card hover, nested panels */
  --color-chalk: #f5f5f5;          /* the rare light band — unused in v1 */

  /* ---- Accent ------------------------------------------------------------ */
  --color-green: #d4f55a;          /* Padel Green            17.01:1 on black */
  --color-green-press: #a8c93f;    /* hover / pressed        11.09:1 */
  --color-green-deep: #6e9b2e;     /* active, borders         6.39:1 */
  --color-green-bright: #e4ff7a;   /* focus rings            18.88:1 */

  /* ---- Text -------------------------------------------------------------- */
  --color-ink: #ffffff;            /* headlines              21.00:1 */
  --color-copy: #b8b8b8;           /* body copy              10.59:1 */
  --color-muted: #8a8a8a;          /* captions, metadata      6.08:1 */
  --color-faint: #5e5e5e;          /* decorative only         3.24:1 — sub-AA */

  /* ---- Lines ------------------------------------------------------------- */
  --color-hairline: #2a2a2a;
  --color-hairline-strong: #3c3c3c;

  /* ---- Scrims and vignette ---------------------------------------------- */
  /* Bottom-up, to carry the headline. Plus a short top-down pass so the header
     always has a dark backing: the home frame has a bright white net tape
     across its upper third, and white nav labels on light grey is the one place
     this layout can lose its contrast. DESIGN.md §2 permits exactly this —
     "photographic scrims … to guarantee type legibility". */
  --scrim-hero:
    linear-gradient(
      to bottom,
      rgba(0, 0, 0, 0.88) 0%,
      rgba(0, 0, 0, 0.66) 9%,
      rgba(0, 0, 0, 0.28) 17%,
      transparent 26%
    ),
    linear-gradient(
      to top,
      #000 0%,
      rgba(0, 0, 0, 0.72) 28%,
      rgba(0, 0, 0, 0.25) 62%,
      rgba(0, 0, 0, 0.1) 100%
    );
  --scrim-band: linear-gradient(to top, rgba(0, 0, 0, 0.85), rgba(0, 0, 0, 0.35));
  --vignette: radial-gradient(
    ellipse at center,
    transparent 45%,
    rgba(0, 0, 0, 0.35) 100%
  );

  /* ---- Motion ------------------------------------------------------------ */
  --ease-brand: cubic-bezier(0.16, 1, 0.3, 1);
  --duration-micro: 180ms;
  --duration-standard: 320ms;
  --duration-section: 600ms;

  /* ---- Type families ----------------------------------------------------- */
  /* Fallbacks matter: the client may open this file with no internet, and the
     display typography is the brand. Arial Black is the closest ubiquitous
     heavy grotesk; Tahoma has real Arabic coverage on Windows. */
  --font-display: "Archivo", "Arial Black", "Helvetica Neue", Impact, sans-serif;
  --font-body: "Archivo", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --font-arabic: "Cairo", "Noto Naskh Arabic", "Segoe UI", Tahoma, sans-serif;

  /* ---- Layout ------------------------------------------------------------ */
  --header-height: 72px;
  --sticky-bar-height: 76px;
  --container: 1440px;
  --gutter: 20px;

  /* ---- Display sizes ----------------------------------------------------
     DESIGN.md §8: 120 → 88 → 64 → 44 → 36. Fluid via clamp() rather than
     breakpoint jumps, so there is no reflow at each boundary. Declared as
     custom properties because two things consume them: the type roles, and the
     pill-badge fit calculation. */
  --size-hero: clamp(2.25rem, 9vw, 7.5rem);
  --size-display-2: clamp(2rem, 6vw, 5rem);
  --size-section: clamp(1.75rem, 3vw + 1rem, 3.375rem);
  --size-subsection: clamp(1.5rem, 2vw + 1rem, 2.5rem);
  --size-price: clamp(2.5rem, 1.4vw + 2.2rem, 3.5rem);

  /* Mean advance width per character for the display face, measured from the
     real strings. Used to keep a pill badge from ever wrapping. */
  --pill-advance: 0.83;
  --pill-pad: 1.2;
}

@media (min-width: 640px) {
  :root { --gutter: 24px; }
}
@media (min-width: 1024px) {
  :root { --gutter: 40px; }
}

/* ============================================================================
   Reset
   ========================================================================= */

*,
*::before,
*::after { box-sizing: border-box; }

html {
  background-color: var(--color-court);
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-block-start: var(--header-height);
}

body {
  margin: 0;
  background-color: var(--color-court);
  color: var(--color-copy);
  font-family: var(--font-body);
  font-size: 1rem;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

h1, h2, h3, h4, p, figure, blockquote, dl, dd { margin: 0; }
ul, ol { margin: 0; padding: 0; list-style: none; }
img, svg, picture { display: block; max-width: 100%; }

/* <picture> is a real element in the box tree, so an img with height:100%
   resolves against the <picture>, not against the framed container. Left
   unstyled that silently defeats every object-fit crop on the page — the hero
   photograph renders at its intrinsic ratio and simply stops partway down. */
.hero-media picture,
.band-media picture,
.band picture,
.pkg-banner picture {
  width: 100%;
  height: 100%;
}
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }
a { color: inherit; text-decoration: none; }

/* DESIGN.md §3 — the brand voice is always upright. */
i, em, address, cite { font-style: normal; }

::selection { background-color: var(--color-green); color: var(--color-court); }

/* Focus visibility on a true-black canvas is the hardest a11y problem here.
   The 3px offset is load-bearing: flush against a green pill the ring would
   vanish into the button, so the offset puts it on the canvas behind. */
:focus-visible {
  outline: 2px solid var(--color-green-bright);
  outline-offset: 3px;
  border-radius: inherit;
}

.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* Skip link — first focusable element on every page. */
.skip-link {
  position: absolute;
  inset-inline-start: 1rem;
  inset-block-start: -100px;
  z-index: 100;
  display: inline-flex;
  align-items: center;
  min-height: 48px;
  padding: 0 1.5rem;
  background: var(--color-green);
  color: var(--color-court);
  font-size: 0.9375rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  transition: inset-block-start var(--duration-micro) ease-out;
}
.skip-link:focus { inset-block-start: 1rem; }

/* ============================================================================
   Type roles — DESIGN.md §3
   ========================================================================= */

.t-hero, .t-display-2, .t-section, .t-subsection, .t-feature, .t-card-title, .t-price {
  font-family: var(--font-display);
  text-transform: uppercase;
  color: var(--color-ink);
}

.t-hero {
  font-size: var(--size-hero);
  font-weight: 900;
  line-height: 0.88;
  letter-spacing: -0.02em;
  font-variation-settings: "wdth" 120;
}
.t-display-2 {
  font-size: var(--size-display-2);
  font-weight: 900;
  line-height: 0.92;
  letter-spacing: -0.02em;
  font-variation-settings: "wdth" 120;
}
.t-section {
  font-size: var(--size-section);
  font-weight: 800;
  line-height: 0.95;
  letter-spacing: -0.01em;
  font-variation-settings: "wdth" 118;
}
.t-subsection {
  font-size: var(--size-subsection);
  font-weight: 800;
  line-height: 1;
  letter-spacing: -0.01em;
  font-variation-settings: "wdth" 115;
}
.t-feature {
  font-size: 1.6875rem;
  font-weight: 700;
  line-height: 1.2;
  font-variation-settings: "wdth" 110;
}
.t-card-title {
  font-size: 1.5rem;
  font-weight: 700;
  line-height: 1.25;
  font-variation-settings: "wdth" 110;
}
.t-price {
  font-size: var(--size-price);
  font-weight: 900;
  line-height: 1;
  letter-spacing: -0.01em;
  font-variant-numeric: tabular-nums;
  font-variation-settings: "wdth" 115;
  text-transform: none;
}

.t-price-unit {
  font-size: 1rem;
  font-weight: 600;
  line-height: 1;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-muted);
}
.t-body-lg { font-size: 1.125rem; line-height: 1.55; }
.t-body { font-size: 1rem; line-height: 1.55; }
.t-eyebrow {
  font-size: 0.8125rem;
  font-weight: 600;
  line-height: 1.2;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--color-muted);
}
.t-label {
  font-size: 0.75rem;
  font-weight: 600;
  line-height: 1.4;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}
.t-micro {
  font-size: 0.625rem;
  font-weight: 600;
  line-height: 1.6;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--color-muted);
}

.ink { color: var(--color-ink); }
.green { color: var(--color-green); }
.measure { max-width: 68ch; }

/* ============================================================================
   Arabic — DESIGN.md §3 "Arabic & RTL Typography"

   Scoped with :lang(ar) rather than [lang="ar"] *, because :lang() resolves the
   element's INHERITED language. That is what allows a <span lang="en"> fragment
   inside Arabic copy to stay exempt and keep its Latin tracking.
   ========================================================================= */

:lang(ar) {
  font-family: var(--font-arabic);
  letter-spacing: 0;
  text-transform: none;

  /* Display steps down ~27%: Cairo at the same pixel size reads noticeably
     larger than Archivo, so equal numbers would make Arabic overpower Latin. */
  --size-hero: clamp(1.75rem, 6.6vw, 5.5rem);
  --size-display-2: clamp(1.625rem, 4.8vw, 4rem);
  --size-section: clamp(1.5rem, 2.4vw + 0.8rem, 2.75rem);
  --pill-advance: 0.68;
}

/* Cairo's heaviest weights are lighter than Archivo at wdth 120, so Arabic
   display carries one weight step more. Without this it reads as an
   afterthought, which DESIGN.md §3 explicitly warns against. */
:lang(ar) .t-hero,
:lang(ar) .t-display-2 { font-weight: 1000; line-height: 1.05; }
:lang(ar) .t-section,
:lang(ar) .t-subsection { font-weight: 900; line-height: 1.12; }
:lang(ar) .t-feature,
:lang(ar) .t-card-title { font-weight: 800; line-height: 1.35; }
:lang(ar) .t-price { font-weight: 1000; }
:lang(ar) .t-body,
:lang(ar) .t-body-lg { line-height: 1.8; }
:lang(ar) .measure { max-width: 62ch; }

/* Latin fragments inside Arabic — `250 JOD`, `WhatsApp`, the phone number.
   Isolation is not cosmetic: without it the bidi algorithm reorders
   space-separated Latin runs, and `079 997 7015` renders as `7015 997 079`. */
[dir="rtl"] [lang="en"] {
  unicode-bidi: isolate;
  direction: ltr;
  font-family: var(--font-body);
}

/* Directional glyphs mirror. The shield, the ball and photographs never do. */
[dir="rtl"] .icon-directional { transform: scaleX(-1); }

/* ============================================================================
   Layout
   ========================================================================= */

.container {
  width: 100%;
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.section { padding-block: 56px; }
@media (min-width: 640px) { .section { padding-block: 80px; } }
@media (min-width: 1024px) { .section { padding-block: 128px; } }

.section--slab { background: var(--color-slab); }
.section--deck { background: var(--color-deck); }

/* The measure belongs to prose, not to headings. Capping the whole block at
   68ch of *body* size wraps a 54px section title after three words. */
.section-head .t-eyebrow { margin-block-end: 1rem; }
.section-head p:not(.t-eyebrow) { max-width: 68ch; margin-block-start: 1.25rem; }
:lang(ar) .section-head p:not(.t-eyebrow) { max-width: 62ch; }

/* ============================================================================
   Buttons — DESIGN.md §4

   The asymmetry is intentional: the primary CTA is a pill, the ghost is square.
   Colour is never a prop — a button is one of these three classes, so white
   text on green is not expressible.
   ========================================================================= */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  min-height: 48px;
  font-family: var(--font-body);
  font-size: 0.9375rem;
  font-weight: 700;
  line-height: 1;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  text-align: center;
  /* Named properties, not `all` or `colors`: transitioning outline-color makes
     the focus ring fade in, and a focus indicator must appear at once. */
  transition:
    background-color var(--duration-micro) ease-out,
    border-color var(--duration-micro) ease-out,
    color var(--duration-micro) ease-out;
}
:lang(ar) .btn { letter-spacing: 0; text-transform: none; }

.btn--primary {
  padding: 18px 32px;
  border-radius: 999px;
  background: var(--color-green);
  color: var(--color-court);   /* black on green — the only correct pairing */
}
.btn--primary:hover { background: var(--color-green-press); }
.btn--primary:active { background: var(--color-green-deep); }

.btn--ghost {
  padding: 17px 31px;
  border: 1px solid rgba(255, 255, 255, 0.45);
  border-radius: 0;
  color: var(--color-ink);
}
.btn--ghost:hover {
  border-color: var(--color-ink);
  background: rgba(255, 255, 255, 0.08);
}

.btn--white {
  padding: 18px 32px;
  border-radius: 0;
  background: var(--color-ink);
  color: var(--color-court);
}
.btn--white:hover { background: rgba(255, 255, 255, 0.85); }

.btn--block { display: flex; width: 100%; }

.btn-row {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
}

/* ============================================================================
   Pill badge — DESIGN.md §4, the signature component

   Two things make it read as a stamp rather than a button: each row is fitted
   to its own text width, and the padding is proportional (em) so a 40px badge
   and a 120px badge carry the same weight of white around the letters.

   It must never wrap — a wrapped lozenge is a rounded box, and this system has
   no rounded boxes. But the specified mobile display sizes do not fit every
   string at 375px, where gutters leave 335px (`NOT A COURT RENTAL.` at 32px
   needs 488px), so the role size is a ceiling and the badge steps down only when
   it must. Above mobile the min() always picks the role size and nothing changes.

   The hero pair `WHERE AMMAN` / `PLAYS.` still steps down on phones (32.4px of
   the 36px role at 375px) but holds full size from 768px up. Arabic never steps
   down. The guard stays regardless — `NOT A COURT RENTAL.` overflows widely, and
   it should not depend on one headline surviving client review.

   Both rows of a stack must carry the LONGEST row's --chars, or each row sizes
   itself and the stack loses its single optical size.
   ========================================================================= */

.pill-stack {
  container-type: inline-size;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.08em;
}

.pill {
  display: inline-block;
  width: fit-content;
  white-space: nowrap;
  padding: 0.12em 0.55em;
  border-radius: 999px;
  background: var(--color-ink);
  color: var(--color-court);
  font-family: var(--font-display);
  font-weight: 900;
  line-height: 1.15;
  letter-spacing: -0.01em;
  text-transform: uppercase;
  font-variation-settings: "wdth" 120;
  font-size: min(
    var(--pill-size, var(--size-display-2)),
    calc(100cqi / (var(--chars, 12) * var(--pill-advance) + var(--pill-pad)))
  );
}
.pill--green { background: var(--color-green); }
.pill--hero { --pill-size: var(--size-hero); }
.pill--display { --pill-size: var(--size-display-2); }
.pill--card {
  --pill-size: 1.125rem;
  font-weight: 800;
  font-variation-settings: "wdth" 110;
  letter-spacing: 0.02em;
}

:lang(ar) .pill { font-weight: 1000; letter-spacing: 0; text-transform: none; line-height: 1.35; }

/* A slight inline offset between rows. Logical, so the stack steps away from
   the start edge in either direction. */
.pill-stack .pill-row + .pill-row { margin-inline-start: 0.35em; }
.pill-row { display: block; width: fit-content; }

/* ============================================================================
   Header — DESIGN.md §4 Navigation
   ========================================================================= */

.site-header {
  position: fixed;
  inset-inline: 0;
  inset-block-start: 0;
  z-index: 40;
  height: var(--header-height);
  border-block-end: 1px solid transparent;
  transition:
    background-color var(--duration-standard) ease-out,
    border-color var(--duration-standard) ease-out;
}
.site-header.is-filled {
  background: rgba(0, 0, 0, 0.92);
  border-block-end-color: var(--color-hairline);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
}

.header-inner {
  display: flex;
  align-items: center;
  gap: 1.25rem;
  height: 100%;
}

.brand { display: flex; align-items: center; color: var(--color-ink); }
.brand svg, .brand img { width: 40px; height: auto; }

.header-nav { display: none; }
@media (min-width: 1024px) {
  .header-nav {
    display: flex;
    align-items: center;
    gap: 2rem;
    margin-inline-start: auto;
  }
}
.header-nav a {
  position: relative;
  display: inline-block;
  padding-block: 0.5rem;
  color: var(--color-ink);
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  transition: color var(--duration-micro) ease-out;
}
:lang(ar) .header-nav a { letter-spacing: 0; text-transform: none; font-size: 0.875rem; }
.header-nav a:hover { color: var(--color-green); }
.header-nav a[aria-current="page"]::after {
  content: "";
  position: absolute;
  inset-inline: 0;
  inset-block-end: -1px;
  height: 2px;
  background: var(--color-green);
}

.header-end {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-inline-start: auto;
}
@media (min-width: 1024px) {
  .header-end { margin-inline-start: 0; gap: 1.5rem; }
}
.header-cta { display: none; }
@media (min-width: 1024px) { .header-cta { display: inline-flex; } }

/* Language toggle */
.lang-toggle { display: flex; align-items: center; }
.lang-toggle a,
.lang-toggle span.is-active {
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 44px;
  min-height: 44px;
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.14em;
}
.lang-toggle span.is-active { color: var(--color-ink); }
.lang-toggle a { color: var(--color-muted); transition: color var(--duration-micro) ease-out; }
.lang-toggle a:hover { color: var(--color-ink); }
.lang-toggle .sep { color: var(--color-faint); user-select: none; }
/* `ع` sits small in most Arabic faces; a size nudge puts it optically level
   with `EN` rather than metrically level. */
.lang-toggle [lang="ar"] { font-size: 1.35em; letter-spacing: 0; line-height: 1; }

.nav-toggle {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  color: var(--color-ink);
}
@media (min-width: 1024px) { .nav-toggle { display: none; } }

/* Without JavaScript the overlay cannot open, so the hamburger is hidden and
   the nav links are shown inline instead. The site stays navigable. */
.no-js .nav-toggle { display: none; }
.no-js .header-nav {
  display: flex;
  gap: 1rem;
  margin-inline-start: auto;
}
.no-js .header-nav a { font-size: 0.6875rem; letter-spacing: 0.08em; }

/* ============================================================================
   Mobile menu — full-screen black takeover, not a drawer
   ========================================================================= */

.mobile-menu {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: flex;
  flex-direction: column;
  background: var(--color-court);
  padding-block-end: env(safe-area-inset-bottom);
}
.mobile-menu[hidden] { display: none; }

.mobile-menu-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 1rem var(--gutter);
}
.mobile-menu-head .brand svg { width: 40px; }
.menu-close {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  color: var(--color-ink);
}

.mobile-menu nav {
  display: flex;
  flex: 1;
  flex-direction: column;
  justify-content: center;
  gap: 0.5rem;
  padding-inline: var(--gutter);
}
.mobile-menu nav a {
  padding-block: 0.5rem;
  font-family: var(--font-display);
  font-size: clamp(1.75rem, 8vw, 2rem);
  font-weight: 800;
  letter-spacing: -0.01em;
  text-transform: uppercase;
  color: var(--color-ink);
  font-variation-settings: "wdth" 115;
}
:lang(ar) .mobile-menu nav a { letter-spacing: 0; text-transform: none; font-weight: 900; }

.mobile-menu-foot {
  display: flex;
  flex-direction: column;
  gap: 1.5rem;
  padding: 0 var(--gutter) 2rem;
}
.mobile-menu-foot .lang-toggle a,
.mobile-menu-foot .lang-toggle span.is-active { font-size: 1.125rem; }

/* ============================================================================
   Hero
   ========================================================================= */

.hero {
  position: relative;
  display: flex;
  align-items: flex-end;
  min-height: 100vh;
  min-height: 100dvh;
  padding-block-start: var(--header-height);
  overflow: hidden;
}
.hero--short { min-height: 70vh; min-height: 70dvh; }

.hero-media {
  position: absolute;
  inset: 0;
  z-index: 0;
}
.hero-media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
}

/* Both hero frames are very wide (2.35:1 and 2.16:1) inside a tall hero, so
   `cover` crops away most of their width and, left centred, shows only the
   dark middle of the court.

   The home frame has a floodlight bloom near each edge, so it is symmetrical
   enough to crop toward whichever side the type is NOT on. This is a crop, not
   a mirror: RTL gets the opposite side of the same photograph, never a
   reversed one. */
.hero .hero-media img { object-position: 78% center; }
[dir="rtl"] .hero .hero-media img { object-position: 22% center; }

@media (min-width: 1440px) {
  /* Wider viewports crop less, so the subject drifts back toward centre. */
  .hero .hero-media img { object-position: 68% center; }
  [dir="rtl"] .hero .hero-media img { object-position: 32% center; }
}

/* The coaching frame is NOT symmetrical — the ball sits about a third in, and
   it is the only thing in the shot. So the crop is the same in both directions:
   flipping it would simply lose the subject. Vertical separation does the work
   instead, since the ball sits high and the headline sits low behind the
   scrim. */
.hero--coaching .hero-media img,
[dir="rtl"] .hero--coaching .hero-media img {
  object-position: 34% 32%;
}

/* --- Home hero -------------------------------------------------------------
   Built from two frames because no single home-side asset can carry it.

   `courts` is the base: a night court surface with a lit service line, and the
   only one with usable highlight range (peak 160/255). It is a 4.7:1 strip in
   a 100dvh frame, so it is upscaled — acceptable only because the source is
   already a soft, shallow-focus night frame, which is the brand's own position
   (DESIGN.md §1: "Blur is the atmosphere; type is the only thing in focus").

   `hero-home` is layered over it at low opacity purely for its floodlight
   blooms. It peaks at 69/255 with nothing above half brightness, so it is
   useless as a base but works as a light source. `screen` blending adds its
   glow without darkening the court beneath.

   The crop puts the lit line on the side away from the type, and flips for RTL
   — the frame is a plain court surface with no subject, so mirroring the crop
   costs nothing. */
/* The net frame is portrait (1600×1999) in a landscape hero, so `cover` crops
   hard vertically and the only real decision is which band survives. 56% puts
   the BALLERS net tape across the upper right with the scattered balls above
   it — the two things that make this read as *this* club rather than any court
   — and leaves the headline on the dark court below, where the scrim is
   heaviest.

   Same crop in both directions: this is a photograph with a subject, and a
   photograph does not mirror. */
.hero--home .hero-media img,
[dir="rtl"] .hero--home .hero-media img {
  object-position: 50% 56%;
}

/* Below 1024px the frame is taller than the photograph is, so `cover` crops
   horizontally and the vertical position stops having any effect — the tape
   lands at a fixed height, straight behind the headline, and the wordmark ends
   up sliced in half.
   The net runs diagonally, rising to the right, so moving the crop rightward
   lifts the tape clear of the type. Same crop in both directions. */
@media (max-width: 1023px) {
  .hero--home .hero-media img,
  [dir="rtl"] .hero--home .hero-media img {
    object-position: 82% 56%;
  }
}

.hero-media::after {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--scrim-hero), var(--vignette);
}

.hero-inner {
  position: relative;
  z-index: 1;
  width: 100%;
  padding-block-end: calc(56px + var(--sticky-bar-height));
}
@media (min-width: 640px)  { .hero-inner { padding-block-end: 64px; } }
@media (min-width: 1024px) { .hero-inner { padding-block-end: 80px; } }

.hero-content { max-width: 100%; }
@media (min-width: 1024px) { .hero-content { max-width: 62%; } }

.hero .t-eyebrow { color: var(--color-copy); }
.hero-sub {
  margin-block-start: 1.5rem;
  max-width: 46ch;
  color: var(--color-copy);
}
.hero .btn-row { margin-block-start: 2rem; }
.hero .pill-stack { margin-block-start: 1.25rem; }

/* Hours strip — micro-label band with hairlines, DESIGN.md §4 */
.hours-strip {
  margin-block-start: 2.5rem;
  padding-block: 0.75rem;
  border-block: 1px solid var(--color-hairline);
  text-align: center;
}
@media (min-width: 1024px) { .hours-strip { text-align: start; padding-inline-end: 2rem; } }

/* ============================================================================
   The Club — two columns on desktop, mirrored in RTL by logical order
   ========================================================================= */

.club-grid {
  display: grid;
  gap: 2.5rem;
}
@media (min-width: 1024px) {
  .club-grid {
    grid-template-columns: 5fr 7fr;
    gap: 4rem;
    align-items: start;
  }
}

.band-media { position: relative; overflow: hidden; }
.band-media img { width: 100%; height: 100%; object-fit: cover; }
.band-media::after {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--vignette);
}
/* The club frame is a 5.53:1 cinematic strip whose only subject — a player's
   legs and trainers — sits in the far left 12%. Forced into a portrait column
   it crops to the empty middle of the court and reads as a blank grey box, and
   it would be upscaled 2.7x to get there. A wide box keeps the subject, and
   barely resamples the source. */
.club-grid .band-media { aspect-ratio: 16 / 10; }
/* Same crop in both directions. The subject is at the left of the PHOTOGRAPH,
   and a photograph does not mirror — flipping the crop in RTL would frame the
   empty half of the court instead. */
.club-grid .band-media img { object-position: 8% center; }

.club-body > p + p { margin-block-start: 1.25rem; }
.club-body p { color: var(--color-copy); }
.club-grid .pill-stack { margin-block: 1.25rem 2rem; }

/* Score-style stat row — large tabular figures, tiny labels beneath.
   Figures do not count up: animated counters are decorative motion. */
.stat-row {
  display: grid;
  gap: 1px;
  margin-block-start: 3rem;
  background: var(--color-hairline);
  border: 1px solid var(--color-hairline);
}
@media (min-width: 640px) { .stat-row { grid-template-columns: repeat(3, 1fr); } }

.stat {
  padding: 1.5rem;
  background: var(--color-slab);
}
@media (min-width: 1024px) { .stat { padding: 2rem; } }
.stat-figure {
  font-family: var(--font-display);
  /* "Large tabular figures with tiny uppercase labels beneath" — DESIGN.md §4.
     Capped so the longest string, `8 AM — 12 AM`, still holds one line. */
  font-size: clamp(1.5rem, 2.1vw, 2.125rem);
  font-weight: 900;
  line-height: 1.1;
  letter-spacing: -0.01em;
  text-transform: uppercase;
  font-variant-numeric: tabular-nums;
  font-variation-settings: "wdth" 115;
  color: var(--color-ink);
}
:lang(ar) .stat-figure { letter-spacing: 0; text-transform: none; font-weight: 1000; }
.stat .t-micro { margin-block-start: 0.5rem; }

/* ============================================================================
   Courts & Facilities
   ========================================================================= */

.band {
  position: relative;
  margin-block-end: 3rem;
  overflow: hidden;
  aspect-ratio: 21 / 9;
  max-height: 340px;
}
@media (min-width: 1024px) { .band { aspect-ratio: 4.7 / 1; } }
.band img { width: 100%; height: 100%; object-fit: cover; }
.band::after {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--scrim-band), var(--vignette);
}

.card-grid {
  display: grid;
  gap: 1.5rem;
  margin-block-start: 2.5rem;
}
@media (min-width: 640px)  { .card-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1024px) { .card-grid { grid-template-columns: repeat(3, 1fr); } }

.card {
  padding: 2rem;
  background: var(--color-slab);
  border: 1px solid var(--color-hairline);
  border-radius: 0;              /* only pills and primary CTAs are rounded */
  transition: background-color var(--duration-micro) ease-out;
}
.card:hover { background: var(--color-slab-raised); }
.card p { margin-block-start: 1rem; color: var(--color-copy); }

.section-cta { margin-block-start: 2.5rem; display: flex; justify-content: center; }

/* ============================================================================
   Coaching teaser — a deliberate break in rhythm, narrower than its neighbours
   ========================================================================= */

.teaser { text-align: center; }
/* Wide enough for the display headline to hold one line at 80px; the prose
   inside is capped separately. */
.teaser-inner { max-width: 900px; margin-inline: auto; }
.teaser .t-display-2 { margin-block: 1rem 1.5rem; }
.teaser p { max-width: 54ch; margin-inline: auto; color: var(--color-copy); }
.teaser .btn-row { margin-block-start: 2rem; justify-content: center; }

/* ============================================================================
   FAQ — native <details>, no JavaScript
   ========================================================================= */

.faq { max-width: 800px; margin-inline: auto; }
.faq-list { margin-block-start: 2.5rem; border-block-start: 1px solid var(--color-hairline); }

.faq-item { border-block-end: 1px solid var(--color-hairline); }

.faq-item summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
  padding-block: 1.25rem;
  cursor: pointer;
  list-style: none;
  font-family: var(--font-display);
  font-size: 1.0625rem;
  font-weight: 700;
  line-height: 1.35;
  text-transform: uppercase;
  font-variation-settings: "wdth" 110;
  color: var(--color-ink);
  transition: color var(--duration-micro) ease-out;
}
@media (min-width: 640px) { .faq-item summary { font-size: 1.1875rem; } }
:lang(ar) .faq-item summary { text-transform: none; letter-spacing: 0; font-weight: 800; }
.faq-item summary::-webkit-details-marker { display: none; }
.faq-item summary:hover { color: var(--color-green); }

.faq-icon {
  flex: 0 0 auto;
  width: 14px;
  height: 14px;
  position: relative;
}
.faq-icon::before,
.faq-icon::after {
  content: "";
  position: absolute;
  background: currentColor;
  transition: transform var(--duration-micro) ease-out, opacity var(--duration-micro) ease-out;
}
.faq-icon::before { inset-block-start: 6px; inset-inline: 0; height: 2px; }
.faq-icon::after  { inset-inline-start: 6px; inset-block: 0; width: 2px; }
.faq-item[open] .faq-icon::after { opacity: 0; transform: rotate(90deg); }

.faq-answer {
  padding-block-end: 1.5rem;
  max-width: 68ch;
  color: var(--color-copy);
}
.faq-answer a { color: var(--color-green); text-decoration: underline; text-underline-offset: 3px; }

/* ============================================================================
   Contact strip — type-only address block. No Maps iframe: ~800 KB and it sets
   third-party cookies before consent.
   ========================================================================= */

.contact-grid { display: grid; gap: 2.5rem; }
@media (min-width: 1024px) { .contact-grid { grid-template-columns: 1fr 1fr; gap: 4rem; } }

.address-block {
  position: relative;
  padding: 2rem;
  background: var(--color-slab);
  border: 1px solid var(--color-hairline);
}
@media (min-width: 640px) { .address-block { padding: 2.5rem; } }

.pin {
  width: 28px;
  height: 28px;
  margin-block-end: 1.5rem;
  color: var(--color-green);
}
.address-block address { color: var(--color-copy); font-size: 1.125rem; line-height: 1.7; }
.address-line + .address-line { margin-block-start: 1.25rem; }
.address-block a { color: var(--color-ink); }
.address-block a:hover { color: var(--color-green); }

.contact-detail .t-section { margin-block: 1rem 1.5rem; }
.contact-detail .btn-row { margin-block-start: 2rem; }
.contact-detail p { color: var(--color-copy); }

/* ============================================================================
   Package grid — the commercial core
   ========================================================================= */

.pkg-grid {
  display: grid;
  gap: 1.5rem;
  margin-block-start: 2.5rem;
}
@media (min-width: 640px)  { .pkg-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1280px) { .pkg-grid { grid-template-columns: repeat(4, 1fr); } }

.pkg-card {
  display: flex;
  flex-direction: column;
  background: var(--color-slab);
  border: 1px solid var(--color-hairline);
  border-radius: 0;
  transition: background-color var(--duration-micro) ease-out;
}
.pkg-card:hover { background: var(--color-slab-raised); }

.pkg-banner {
  position: relative;
  height: 120px;
  overflow: hidden;
  border-block-end: 1px solid var(--color-hairline);
}
.pkg-banner img { width: 100%; height: 100%; object-fit: cover; }
.pkg-banner::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(to top, rgba(0, 0, 0, 0.75), rgba(0, 0, 0, 0.25));
}

.pkg-body { display: flex; flex-direction: column; flex: 1; padding: 1.5rem; }
.pkg-body .t-eyebrow { margin-block-start: 0.75rem; }

/* The tier name is a pill badge. `Full Court. Full Progress.` is two rows, so
   the heading is a column with the same slight inline offset as the hero
   stacks. container-type gives the badge a width to fit itself against. */
.pkg-head {
  container-type: inline-size;
  /* `Full Court. Full Progress.` is two pill rows where the others are one.
     Reserving both rows' height keeps the eyebrow, the hairline and the price
     columns on the same line across all four cards — otherwise the fourth card
     sits ~28px lower than its neighbours and the row reads as broken. */
  min-block-size: 3.7rem;
}
.pkg-head h3 {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.08em;
}
.pkg-head [data-second-row] { margin-inline-start: 0.35em; }

.pkg-prices {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1rem;
  margin-block-start: 1.5rem;
  padding-block-start: 1.5rem;
  border-block-start: 1px solid var(--color-hairline);
}
.pkg-price .t-micro { margin-block-end: 0.5rem; }
/* Figure over unit, as in the brand assets and DESIGN.md §4: `250` at price
   scale with `JOD` beneath it, not beside it. */
.pkg-figure {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.25rem;
}
/* The 10-lesson column is always better value per lesson, so it is always the
   green figure. The other stays white. */
.pkg-price--best .t-price { color: var(--color-green); }

.pkg-card .btn { margin-block-start: 1.5rem; }
.pkg-foot { margin-block-start: auto; padding-block-start: 1.5rem; }

.pkg-note {
  margin-block-start: 2rem;
  color: var(--color-muted);
  font-size: 0.9375rem;
  text-align: center;
}

/* ============================================================================
   Footer
   ========================================================================= */

.site-footer { background: var(--color-deck); padding-block: 56px; }
@media (min-width: 640px)  { .site-footer { padding-block: 80px; } }
@media (min-width: 1024px) { .site-footer { padding-block: 96px; } }

.footer-grid { display: grid; gap: 3rem; }
@media (min-width: 1024px) {
  .footer-grid { grid-template-columns: 1fr auto auto; gap: 4rem; }
}
.footer-brand .t-micro { margin-block-start: 1.25rem; }
.footer-col h2 { margin-block-end: 0.75rem; color: var(--color-muted); }
.footer-col address { color: var(--color-copy); }
.footer-col address p + p { margin-block-start: 0.25rem; }

/* Every interactive element ≥48px — DESIGN.md §8. A footer link is a 17px line
   box on its own, which is a miss on a phone; the height comes from the link
   rather than from margins between links, so the target and the visible row
   are the same thing. */
.footer-col a {
  display: inline-flex;
  align-items: center;
  min-height: 48px;
  color: var(--color-copy);
  transition: color var(--duration-micro) ease-out;
}
.footer-col a:hover { color: var(--color-ink); }
.address-block a {
  display: inline-flex;
  align-items: center;
  min-height: 48px;
}

.footer-hours {
  margin-block-start: 3.5rem;
  padding-block: 1rem;
  border-block: 1px solid var(--color-hairline);
  text-align: center;
}

.footer-end {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 1.5rem;
  margin-block-start: 2rem;
}
@media (min-width: 640px) {
  .footer-end { flex-direction: row; align-items: center; justify-content: space-between; }
}
.footer-end .t-micro { color: var(--color-faint); }

/* Clears the sticky bar. A spacer rather than padding, so it adds to the
   footer's own rhythm instead of replacing it, and the deck surface still runs
   behind the bar. */
.sticky-spacer { height: calc(var(--sticky-bar-height) + env(safe-area-inset-bottom)); }
@media (min-width: 1024px) { .sticky-spacer { display: none; } }

/* ============================================================================
   Sticky booking bar — the highest-converting element on the site.
   Never hides on scroll: hide-on-scroll-down costs conversions and shifts
   layout. Because it never hides it needs no scroll state and no JavaScript.
   ========================================================================= */

.sticky-bar {
  position: fixed;
  inset-inline: 0;
  inset-block-end: 0;
  z-index: 30;
  display: flex;
  align-items: center;
  min-height: var(--sticky-bar-height);
  padding: 12px var(--gutter);
  padding-block-end: calc(12px + env(safe-area-inset-bottom));
  background: rgba(0, 0, 0, 0.92);
  border-block-start: 1px solid var(--color-hairline);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
}
@media (min-width: 1024px) { .sticky-bar { display: none; } }

/* ============================================================================
   Scroll reveal — 16px translate-up + fade. Nothing else moves.

   The hidden state is applied only under `.js`, which main.js sets on the root
   element. With JavaScript disabled nothing is ever hidden.
   ========================================================================= */

.js .reveal {
  opacity: 0;
  transform: translateY(16px);
  transition:
    opacity var(--duration-section) var(--ease-brand),
    transform var(--duration-section) var(--ease-brand);
  transition-delay: var(--reveal-delay, 0ms);
}
.js .reveal.is-visible { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
  /* "Content appears immediately" — not "appears quickly once you scroll to
     it". Reduced-motion readers never see the hidden state at all. */
  .js .reveal { opacity: 1; transform: none; }
}

/* Print — the client may well print this for a meeting. */
@media print {
  .site-header, .sticky-bar, .mobile-menu, .skip-link { display: none !important; }
  body { background: #fff; color: #000; }
  .hero { min-height: auto; }
}
